Commit Graph
6657 Commits
Author SHA1 Message Date
Armin Ronacher a4715ec9bf test(coding-agent): run the official MCP client conformance suite in CI
Runs the pinned @modelcontextprotocol/conformance client scenarios for 2025-03-26, 2025-06-18, and 2025-11-25 against pi's MCP connection and OAuth sign-in, and fails on regressions against a committed check-level baseline.
2026-10-01 10:43:44 +02:00
Armin Ronacher e529a82c98 fix(mcp): keep granted scopes on step-up authorization
A step-up sign-in requested only the scopes of the insufficient_scope challenge, so the new token lost the scopes granted before and other requests asked for sign-in again. Tokens now record their granted scope and step-up requests the union (SEP-2350).
2026-10-01 10:43:44 +02:00
David Brailovsky 0c453048bd fix(coding-agent): require --model when --provider is given
--provider without --model was ignored and the default model from
another provider ran instead. It now fails with an error. Also fixes
the outdated "(default: google)" in the --help text.

closes #10236
2026-10-01 10:25:16 +02:00
Mario Zechner 70c036211d feat(coding-agent): show the durable TUI's task panel by default 2026-10-01 10:07:19 +02:00
David Brailovsky 41169ba2af fix(coding-agent): make /mcp login sign-in URL clickable in the TUI
fixes #10186
2026-10-01 09:55:24 +02:00
Mario Zechner 5609b0d6c0 feat(coding-agent): experimental TUI coding agent on pi-durable
A small local agent in src/experimental/durable: pi's model runtime, settings,
system prompt, theme, and interactive components over a durable Harness with
SQLite storage. Streaming, tools, steer and follow-up, abort, model and
thinking selection, compaction, --continue with recovery of interrupted turns,
a subagent tool with /agents to switch to and talk to subagents, and a live
/tasks panel from the task graph view. The tsconfig path for
@earendil-works/pi-durable/* resolves subpaths to source.
2026-10-01 09:53:21 +02:00
Mario Zechner 49683a3647 feat(durable): lifecycle conformance and task graph view (Packages 22, 23)
Package 22: runtime.now() and report() throw after the invocation ended; a
migration-only commit is published; a failed Harness.open closes without the
caller's context and rethrows the open error; ConversationWatch alias. Tests
for close joining non-cooperative code, cancelled close, queued operations at
the seal, progress calls and viewers on a paused Harness, the Chord guide, and
the spec's usage examples.

Package 23: Harness.taskGraph() and watchTaskGraph() mount every live task with
its owner edge, committed status, flags, and owned conversations, advanced from
commit publications. Example 24 prints the checkout's tree.
2026-10-01 09:53:21 +02:00
Mario Zechner 5b5ccddfac docs(durable): settle lifecycle wording and specify the task graph view (Packages 22, 23)
Close ends states and watches at its seal, joins non-cooperative code, and a
cancelled close cancels only its wait. Conversation.abort() starts scheduling.
New section 9.5 specifies Harness.taskGraph() and watchTaskGraph(). The Chord
guide uses real imports and documents shutdown order.
2026-10-01 09:53:21 +02:00
Armin Ronacher 8ce69e9d2b fix(mcp): treat empty and null optional OAuth fields as absent
Empty or null optional fields in OAuth token and registration responses
(scope, refresh_token, id_token, client_secret) failed sign-in, and
expires_in: null marked tokens as expired. Also fall back to the server
origin when resource metadata has invalid URLs, skip empty scopes when
selecting the requested scope, and end pagination at an empty or null
nextCursor.

closes #10266
2026-10-01 02:05:35 +02:00
Mario Zechner b56702ad34 feat(durable): extensions and per-conversation agents (Package 21)
- Registry of named extensions (tools, sections, hooks, wraps, tasks) with install/uninstall;
  defineExtension, defineTool, section, hook, wrapTool, wrapSection
- pi.agent document (model, thinking level, extensions, tools filter, instructions, cwd),
  configure(), Conversation.agent()/configure(), agent option on root/createConversation/fork,
  task-owned conversations copy their owner's agent
- Harness-wide HarnessSettings read at every use; env function built per use
- Hooks and the agent resolved per task phase; tool calls resolved with the tools filter applied
- ToolRegistration<TParameters, TDetails> types execute() args from parameters
- HarnessOptions.conversationCreated; Tx.submissionByRequest() and Tx.createSubmission()
- FileSystem.id; edit/write serialize per file system id and canonical path
- CodingTools extension (read, write, edit, bash)
- Examples 06-31 on the new API, README and CHANGELOG
2026-10-01 01:28:22 +02:00
Mario Zechner 4bae867759 docs(durable): specify extensions and per-conversation agents (Package 21)
Extensions installed by name, the rewindable pi.agent document with configure(),
Harness-wide live settings, env built per use, typed tool args with defineTool(),
HarnessOptions.conversationCreated, Tx submission methods, FileSystem.id for
edit/write serialization, and tool resolution with the tools filter applied.
2026-10-01 01:28:22 +02:00
Armin Ronacher 17f3dccbef fix(tui): preserve ANSI order at slice boundaries
Fixes color bleeding after mouse selection and search highlights in
fullscreen mode when a styled token ends at the highlight boundary.

closes #10169
2026-10-01 00:05:28 +02:00
Armin Ronacher d850edee9c feat(coding-agent): add MCP oauth.authServerMetadataUrl and check RFC 9207 iss
The configured metadata document replaces discovery and is trusted as
configured. Authorization codes are only exchanged when the response's
iss parameter names the flow's authorization server.

closes #10172
2026-09-30 23:56:10 +02:00
Lucas Meijer 7a11fe1c72 feat(ai): add copy code login method to Anthropic OAuth (#10194)
Claude Code's OAuth client also accepts https://platform.claude.com/oauth/code/callback
as redirect_uri. That page shows the authorization code to copy, which works when
the browser runs on another machine than pi, where the localhost callback cannot load.
Anthropic login now asks for a method like OpenAI Codex login: browser (default)
or copy code (headless).
2026-09-30 23:17:13 +02:00
xu0o0 65117e31f2 fix(tui): complete slash commands after leading whitespace (#10218) 2026-09-30 23:13:01 +02:00
Armin Ronacher b35af04f46 feat(coding-agent,tui): add a hidden easter egg to the header logo
Adds TuiAltScreen.getScreenLines(), which returns the lines of the last rendered frame.
2026-09-30 22:57:55 +02:00
Mario Zechner d4d74eb19b Merge PR #10232 follow-up a0feabda7 (already included in ed391c4f0) 2026-09-30 22:32:47 +02:00
Mario Zechner ed391c4f0a fix(durable): harden async SQLite adapter queue and close
- drop AsyncLocalStorage misuse guards from the Node adapter
- run calls immediately when the queue is idle; transactions publish their barrier before the callback starts
- SqliteStorage.close() waits for admitted multi-query reads and shares one close promise
2026-09-30 22:32:34 +02:00
Christian Klotz a0feabda7c refactor(durable): drop AsyncLocalStorage misuse detection from Node SQLite adapter 2026-09-30 20:38:41 +01:00
Mario Zechner 8f89293a26 Merge PR #10232: feat(durable): make SQLite storage asynchronous 2026-09-30 21:36:10 +02:00
Armin Ronacher 955cc6665e Add [Unreleased] section for next cycle 2026-09-30 21:12:42 +02:00
Armin Ronacher 005af57d88 Release v0.99.2 v0.99.2 2026-09-30 21:12:28 +02:00
Christian Klotz 77ac62f22a refactor(durable): simplify Node SQLite queue and bindings 2026-09-30 20:10:39 +01:00
Armin Ronacher 002c183e18 docs(ai,coding-agent): audit unreleased changelog entries
Add missing entries, contributor attribution, cross-package duplicates, and a New Features section.
2026-09-30 21:07:03 +02:00
Phil Freo a9424cd43d feat(ai): Anthropic workload identity federation (#10242)
Adds Anthropic workload identity federation from the SDK env vars
(ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
ANTHROPIC_IDENTITY_TOKEN_FILE, optional ANTHROPIC_SERVICE_ACCOUNT_ID and
ANTHROPIC_WORKSPACE_ID). Keys and ANTHROPIC_AUTH_TOKEN keep precedence.

The federation client is reused across requests so the SDK's token cache
avoids a token exchange per request, and the SDK's own credential chain is
disabled so pi's auth resolver stays the only source of credentials.

closes #10177
2026-09-30 20:58:37 +02:00
Christian Klotz cd0ba2fabc feat(durable): execute SQLite queries by SQL text and cache statements per connection
Replace prepare/SqliteStatement with run/get/all(sql, ...params) on the database and transaction handles. The Node adapter caches prepared statements per connection, so transactions reuse them instead of preparing again on every commit.

Read documents in one transaction so a concurrent commit cannot replace the base between the record and revision queries.
2026-09-30 19:49:55 +01:00
Armin Ronacher 91f9f3b5df feat(coding-agent): let MCP servers authenticate with a provider login
HTTP MCP servers can set "auth": { "provider": "<provider>" } to send the provider's current /login token as the bearer token instead of using MCP OAuth. The token is read on every request, so provider refreshes apply and nothing is copied to mcp-auth.json. Only allowed in the global mcp.json and from extensions, and requires https except on loopback hosts.
2026-09-30 20:41:58 +02:00
Armin Ronacher b29db895c5 fix(coding-agent): align MCP tool names with codemode identifiers
MCP tool and namespace names now replace - with _ like Codex, so the
pi tool name is also the codemode identifier. Tools of a server whose
names collide all get a hash suffix, and server names that differ only
in - and _ are rejected.

closes #10239
2026-09-30 18:40:06 +02:00
Mario Zechner ed0d6b91b6 feat(durable): compaction and overflow (Package 20)
Manual compact(), background and blocking threshold compaction, and overflow
compaction with one retry. Summaries are headed pi.compaction entries placed
through the inbox, or appended by a compaction the generation waits on; the
stale rule decides between concurrent summaries.
2026-09-30 18:23:25 +02:00
Mario Zechner b72cf98ec7 docs(durable): specify compaction and overflow (Package 20) 2026-09-30 18:23:25 +02:00
Armin Ronacher db6cc71dc7 feat(coding-agent): enable tools newly added to defaultTools on reload
When the session's initial tools come from defaultTools, /reload activates
names added to the resolved selection. Removals do not deactivate tools, and
explicit --tools/--no-tools/--no-builtin-tools keep overriding the setting.

closes #10245
2026-09-30 17:55:25 +02:00
Armin Ronacher 028c0ec56e fix(coding-agent): do not list codemode-hidden tools in the system prompt
In codemode.mode "only", tools whose declarations codemode hides were still
listed in the <tools> section. Drop their snippets so the list matches the
declared tools.

closes #10192
2026-09-30 17:46:43 +02:00
Armin Ronacher 0582d9c11d fix(coding-agent): limit codemode and MCP result previews to wrapped lines
Collapsed previews counted logical lines, so one long JSON line filled the
screen. Share a VisualLinePreview component with the bash renderer.
2026-09-30 17:25:07 +02:00
Armin Ronacher e029c3ed0a feat(coding-agent): stop waiting for MCP servers on the first prompt
The first prompt waits only for servers with direct tools. Other servers
connect in the background; codemode scripts, tool_search, and the
resource tools wait for the servers they need. codemode and tool_search
are activated from the config.

Tool declarations no longer depend on connected servers: the codemode
description leaves out deferred tools, and the tool_search description
no longer lists sources. Servers are listed in an mcp_servers system
prompt section instead, set in before_agent_start from the config and
connected state, so changes are appended to the conversation.

describeNamespace() and searchTools() accept mcp__dev-radius,
mcp__dev_radius, dev-radius, and dev_radius.

closes #10212
2026-09-30 17:21:05 +02:00
David Brailovsky 2bbfcca437 fix(ai): use exponential backoff when Retry-After is unparseable
closes #9571
2026-09-30 15:31:30 +02:00
David Brailovsky 295cc72b03 fix(ai): send Anthropic tools non-strict when schema has rejected keywords
Anthropic strict tool use rejects keywords like minimum/maximum with a 400
for the whole request, so one bounded-integer tool broke every turn.

resolveJsonSchemaStrictSampling() now takes an optional per-provider
keyword check. With Anthropic's check, "prefer" tools that hit it fall
back to non-strict. Other providers are unchanged.

fixes #9953
2026-09-30 15:20:17 +02:00
Armin Ronacher 7ef68d4f2f fix(mcp): call fetch without a receiver in Streamable HTTP transport
Cloudflare Workers reject the platform fetch when it is invoked as a
method of the transport or of UnauthorizedContext.

closes #10188
2026-09-30 15:03:55 +02:00
David Brailovsky dc83372f8f fix(coding-agent): validate extension command registration
Reject extension commands without a non-empty string name or a handler
at registration, instead of letting them crash the editor when typing /.

fixes #10054
2026-09-30 15:02:08 +02:00
Armin Ronacher c34f2d6ad5 fix(coding-agent): merge remote catalog models in linear time
mergeModels ran a findIndex per remote model, so every model lookup for a
provider with a refreshed pi.dev catalog was quadratic in catalog size.
2026-09-30 14:33:58 +02:00
Armin Ronacher a0660b174e fix(coding-agent): resolve branch model selection with one catalog lookup
getBranchSelection looked up the model catalog once per assistant message,
which made prompt submission scale with session length. Walk the branch
backward instead: only the last model_change can hold against later
responses, so at most that model needs a lookup.

closes #10198
2026-09-30 14:20:03 +02:00
Mario Zechner 37c9d0d200 fix(durable): harden the persistent subagent example
The subagent tool no longer offers wait, is not rerun after a crash (a repeated stop could stop newer work), reports each answer once even when several messages end in it, checks registry names as own properties, and its scenes cannot hang polling.
2026-09-30 14:01:47 +02:00
Armin Ronacher 7c9fe66452 feat(coding-agent): allow a custom OAuth client name for MCP servers
Adds oauth.clientName (and pi mcp add --oauth-client-name) to set the
client_name sent during dynamic client registration. Defaults to pi.

closes #10226
2026-09-30 13:59:24 +02:00
Armin Ronacher 1c7e7df765 feat(coding-agent): list MCP servers instead of their tools in codemode
MCP codemode exposure no longer lists tools, tool counts, or server
instructions in the codemode description. Servers are listed by name and
an optional mcp.json description; scripts find tools with searchTools()
and read instructions with describeNamespace(). codemode-deferred is an
alias for codemode.

refs #10212
2026-09-30 13:54:02 +02:00
Mario Zechner 03180653c6 feat(durable): structured concurrency: task ownership, waiting, completing holds, bottom-up abort (Package 19)
Tasks name their owner (conversation or task); a task waits on other tasks with a waiting state (failFast or allSettled) and runtime.outcomes(); a task that finishes while owned work is live holds completing until it drains; abort handlers run bottom-up; only live owners cascade. The generation owns its tool tasks and waits for them in a tools phase, replacing pi.post-tools and after. Adds Conversation.abort({ background: true }), example 24 (checkout with payments), and reworks example 23 into persistent subagents.
2026-09-30 13:50:29 +02:00
Mario Zechner 96377f5c2a docs(durable): specify structured concurrency (Package 19) 2026-09-30 13:50:29 +02:00
Armin Ronacher 4a42f8fafa fix(coding-agent): load codemode worker in Windows binary
closes #10204
2026-09-30 13:48:04 +02:00
Christian Klotz fd3af5ee2b feat(durable): pass a transaction handle to SQLite transaction callbacks 2026-09-30 11:39:02 +01:00
Christian Klotz f3e68e8eaf feat(durable): make SQLite storage asynchronous 2026-09-30 11:10:50 +01:00
Armin Ronacher d2931ad3d5 fix(coding-agent): validate codemode image() base64 and detect image type
image() now rejects malformed base64 and data without a PNG, JPEG, GIF,
or WebP signature, and derives the MIME type from the signature. Invalid
image blocks were persisted and made every later provider request fail.

closes #10215
2026-09-30 12:10:30 +02:00
David Brailovsky 3dd803d7e7 fix(ai): detect Z.AI CN endpoint context overflow errors
The CN endpoint returns code 1261 with "Prompt exceeds max length"
instead of "Prompt too long", which isContextOverflow() did not match.

fixes #10208
2026-09-30 10:51:10 +02:00