Commit graph

6004 commits

Author SHA1 Message Date
Christian Klotz
e3c9214d4b
docs(coding-agent): improve MCP server guide 2026-09-30 00:40:41 +01:00
Armin Ronacher
f4c7624c40 fix(coding-agent): mark current MCP exposure with a check like other pickers 2026-09-29 08:12:41 +02:00
Armin Ronacher
83f0c5033b Merge remote-tracking branch 'origin/main' into codemode-and-mcp 2026-09-29 08:12:12 +02:00
Armin Ronacher
28fd590868 fix(ai,coding-agent): replace removed Together Kimi K2.6 with Kimi K3
Together no longer lists Kimi K2.6, which broke type checks against the hydrated catalog. Tests use Kimi K3 and the Together default model now points at it.
2026-09-29 08:11:56 +02:00
Armin Ronacher
1ef250772e feat(coding-agent): split MCP deferred exposure into tool_search and codemode modes
deferred MCP servers now activate tool_search instead of codemode, so their tools load as declared tools without codemode. The previous behavior is available as codemode-deferred. The unreachable-tools warning now accepts an active tool_search as reaching undeclared MCP tools.
2026-09-29 08:03:12 +02:00
Armin Ronacher
a1fa315f8f feat(coding-agent): add MCP resources, per-tool exposure, and output limits
Servers with resources are reached through Codex's list_mcp_resources, list_mcp_resource_templates, and read_mcp_resource tools; MCP App resources and icons are left out. toolExposure sets the exposure of single tools by name or pattern. Tool annotations are passed on to ToolDefinition and ToolInfo for permission extensions. MCP text over 20KB is cut in the middle like in Codex and saved to a temp file. OAuth takes scope and a Codex-style callbackUrl, and stdio servers expand ~ in command, args, and cwd. Also fixes the !command header example in the MCP docs.
2026-09-29 07:49:19 +02:00
Armin Ronacher
761545d4b3 feat(mcp): list and read resources
McpClient lists resources and resource templates, all pages or one page at a time, and reads resources. The OAuth callback server can name another host in its redirect URL than it listens on, and its default path is /callback.
2026-09-29 07:49:19 +02:00
Armin Ronacher
715f2eccac feat(coding-agent): use -l/--local for project servers in pi mcp add/remove
Replaces --project to match pi install and pi remove.
2026-09-29 01:24:27 +02:00
Armin Ronacher
e78aece136 feat(coding-agent): add pi mcp add/remove and log server messages to mcp.log
pi mcp add writes stdio or HTTP server entries to the global or project mcp.json, pi mcp remove deletes them. Log messages servers send with notifications/message are appended to mcp.log in the agent directory, rotated at 5 MB.
2026-09-29 01:03:19 +02:00
Mario Zechner
cb7969d212 feat(durable): add durable task runtime
Adds defineTask, registry-resolved phase handlers, and a scheduler that
decides every task transition in one callback on the Session line:
reservation with migration, dependencies, precedence rules in a step
before each phase, handover to replaced definitions, direct-task abort
(mark, signal, join, fresh abort invocation), orphaning of blocked tasks,
open reconciliation, and close that joins invocations without writing
outcomes. runtime.commit() callbacks return the typed next state; Tx no
longer exposes setTask. Adds Harness.resume, getTask, waitForTask,
abortTask, and task-aware waitForIdle; RegistryReader.subscribe wakes
the scheduler.
2026-09-28 23:55:24 +02:00
Armin Ronacher
0cc77a1c10 Merge branch 'main' into codemode-and-mcp
# Conflicts:
#	packages/coding-agent/docs/extensions.md
#	packages/coding-agent/src/core/agent-session.ts
#	packages/coding-agent/src/core/extensions/loader.ts
#	packages/coding-agent/src/core/extensions/types.ts
#	packages/coding-agent/src/core/model-registry.ts
#	packages/coding-agent/src/index.ts
2026-09-28 23:54:27 +02:00
Armin Ronacher
540e174c72
feat(coding-agent): Virtual models (#10035)
This adds experimental support for virtual models. A virtual model is a catalog entry that an extension registers with pi.registerVirtualModel(). It does not talk to a provider itself; for every request it picks a physical model and thinking level. The motivation is to make routing policies pluggable: plan on a strong model and implement on a cheap one, pick a model with a classifier, or move to a larger window when the context grows. Today this needs model switching by hand or hacks in prepareRequest.

The selection stays virtual: model_change records it, resume restores it, and each response records the physical model and thinking level that produced it. Router state can be stored on the session branch, so it follows /tree and forks and survives compaction. Context limits, compaction and image sizing use the physical model a request was routed to. examples/extensions/jev-router.ts shows a full router that uses the Jev classifier to pick Sol or Terra for planning and hands off to Luna after the first edit. docs/virtual-models.md describes the API.
2026-09-28 23:30:45 +02:00
David Brailovsky
1b2aa0ca0e fix(ai): reject unfinished Responses tool calls instead of running them
The agent runs every tool call in the final assistant message, including
calls whose output_item.done never arrived. Those can carry cut-off or
mixed-up arguments. With llama.cpp, which omits output_index, two parallel
calls became three (echo a, echo a, echo b), two of them with the same id.

processResponsesStream now fails the stream when a completed response
still has an unfinished tool call.

fixes #9974
2026-09-28 23:19:38 +02:00
Christian Klotz
fd889a2741
fix(coding-agent,tui): paste Finder file paths instead of icons (#10136)
Read Finder file URLs before icon image data on macOS. Quote paths in
bash mode and reject terminal control characters before rendering.

Fixes #9999

Co-authored-by: 1dustycy <onedustycy@gmail.com>
2026-09-28 20:59:29 +01:00
Mario Zechner
3883fcb1f3 feat(durable): add openable Harness with registry and conversation config
Implements Pico5 Package 13: Harness.open over a Session with an application-owned
registry (tools, tool wrappers, hooks, tasks, system prompt sections; batched
publication, stable keyed order), lazy root creation with init, atomic
create/fork with init, conversation-bound commits, fork-aware entries, model
context derivation, and the built-in ConversationConfig document.

Fixes cached documents skipping migration when accessed with another definition
version. Rewrites the Pico5 spec and handoff to the registry/system-prompt
design and removes the superseded live-registries proposal.
2026-09-28 21:57:41 +02:00
Armin Ronacher
c90d9ea586 feat(ai,coding-agent): add Claude Sonnet 5.5 support 2026-09-28 20:46:38 +02:00
Mario Zechner
11894012dd feat(durable): expose deltas since base to checkpoint predicates
Storage reports replayed deltas after the selected base; Session tracks the
count across adopted writes so checkpoint predicates can bound replay.
Also adds internal reserved-root creation and conversation-bound commit
defaults for the upcoming Harness.
2026-09-28 17:21:20 +02:00
Mario Zechner
cd5ff11259 docs: reorder durable harness milestones 2026-09-28 16:47:23 +02:00
Mario Zechner
35180b9df8 feat(durable): add document states and buffered watches 2026-09-28 16:36:31 +02:00
David Brailovsky
c1449660c8 fix(ai): allow empty thinking signatures for OpenCode qwen3.8-flash
fixes #10047
2026-09-28 14:55:08 +02:00
David Brailovsky
dc84c1ac0a fix(ai): send requested thinking level to Mistral reasoning models
Mistral models with effort levels now use reasoning_effort based on
their thinking level map from models.dev instead of a hardcoded id list.
GLM 5.3 no longer gets prompt_mode, GLM 5.2 can use max, and off sends
the model's off value when it has one.

fixes #9678
2026-09-28 14:33:10 +02:00
Armin Ronacher
04efdfc380
feat(ai): Discount jev (#10119)
Add the llama-cpp-classify classifier API. Each question becomes one chat prompt with single-token answer labels; llama-server's pre-sampling next-token log-probabilities give the softmax over those labels. Missing labels are retried with deeper readouts and then reported as errors.
2026-09-28 14:19:07 +02:00
Armin Ronacher
2e0ca71816 Merge remote-tracking branch 'origin/main' into codemode-and-mcp 2026-09-28 12:09:06 +02:00
Armin Ronacher
e1787702d3 fix(coding-agent): default OpenCode Go to Kimi K3 after Kimi K2.6 removal 2026-09-28 12:08:56 +02:00
Armin Ronacher
57f221eddd Merge remote-tracking branch 'origin/main' into codemode-and-mcp 2026-09-28 12:01:12 +02:00
Armin Ronacher
ebced83431 fix(ai): update tests for removed OpenCode Go Kimi K2.6
models.dev dropped Kimi K2.6 from OpenCode Go, which broke type checks
against the regenerated catalog. Use OpenCode Go Kimi K3 for
provider-level tests and OpenCode Zen Kimi K2.6 for thinking format tests.
2026-09-28 12:01:02 +02:00
Armin Ronacher
c95a4cc282 test(codemode,coding-agent): trim duplicated codemode and MCP tests
Test each behavior at one layer, share the UI context and tool result helpers in the suite harness, loosen assertions on prompt text, and drop the /mcp manager UI test.
2026-09-28 01:17:22 +02:00
Armin Ronacher
fd7798bae2 Merge branch 'main' into codemode-and-mcp 2026-09-28 00:22:58 +02:00
Armin Ronacher
6f7551516b fix(ai,coding-agent): update Fireworks tests and default for removed models
models.dev dropped Kimi K2.6, GLM 5.2, and the dated DeepSeek V4 Fireworks
models, which broke type checks against the regenerated catalog.
2026-09-28 00:22:39 +02:00
Armin Ronacher
237a4e80f1 feat(mcp,agent,codemode): expose toLlmContent and document agent-core usage
pi-mcp exports toLlmContent(), which converts a CallToolResult to pi-ai-shaped text and image content. The coding agent's MCP adapter uses it.

A typechecked example in packages/agent/examples/mcp-codemode shows a plain Agent with MCP tools and a codemode tool whose nested calls go through runToolCall() and the agent's hooks. The pi-mcp, pi-codemode, and pi-agent-core READMEs describe the same wiring.
2026-09-28 00:10:50 +02:00
Armin Ronacher
a6bc4036d7 feat(coding-agent): let extensions register MCP servers
pi.registerMcpServer(name, config) adds a server for the session with the mcp.json config shape; pi.unregisterMcpServer() removes it and pi.getMcpServers() lists registrations. Servers registered while loading connect on session_start, later ones right away. A server in mcp.json with the same name takes precedence and /mcp shows the override. Changes to registered servers in /mcp apply to the session only.

The mcp_servers_change event lets any MCP extension connect registered servers; when none handles it, registrations are reported as extension errors.
2026-09-27 23:50:53 +02:00
Armin Ronacher
e94c9763db feat(codemode,coding-agent): rename the exec tool back to codemode
The tool is named codemode again and scripts configure it with a first-line // @options: {...} instead of the // @exec: pragma. yield_time_ms is gone; max_output_tokens and timeout_ms remain. Comments, docs, and tests no longer describe the tool in terms of another agent.
2026-09-27 23:22:48 +02:00
Armin Ronacher
74393661e9 fix(coding-agent): let extensions replace built-in MCP, codemode, and tool search
Built-in extensions marked replaceable are left out when another extension registers the same tool, command, or flag name, so third-party MCP extensions such as pi-mcp-adapter take over /mcp instead of both connecting the same servers.

MCP only activates the codemode exec tool, not another extension's tool named exec, and the first prompt waits at most 10 seconds for startup connections.
2026-09-27 22:41:51 +02:00
Armin Ronacher
779f67895c feat(coding-agent): add pi mcp list, login, and logout commands
pi mcp list connects to every enabled server and reports its state, tools, and errors, exiting with 1 when anything fails, so agents can verify an mcp.json they wrote. pi mcp login runs the OAuth sign-in through the browser, and pi mcp logout deletes stored credentials. Running sessions reconnect servers waiting for a sign-in at the next turn when their credentials changed.

The system prompt points MCP questions to docs/mcp.md, which now covers setting up servers: which file to edit, rules that are easy to get wrong, converting entries from other clients, and verifying with pi mcp list.
2026-09-27 22:01:25 +02:00
Armin Ronacher
4951dcc376 feat(coding-agent): open an MCP server manager from /mcp
/mcp in the TUI lists every configured server with its state, tool count, exposure, and scope, servers that need attention first, and updates while they connect. Selecting a server shows its command or URL, config file, and full error, and offers the actions for its state: sign in (with a paste field for the redirect URL), tools, reconnect, sign out, exposure, and enable or disable. Exposure and enabled are saved to the mcp.json that defines the server.

Startup problems are reported once in the transcript, pointing to /mcp. Outside the TUI, /mcp prints the status, and /mcp login, logout, and the new reconnect subcommand stay available.
2026-09-27 21:40:00 +02:00
Armin Ronacher
2498ca492e refactor(agent,coding-agent): isolate codemode, tool search, and MCP from the core
The agent loop is back to main's tool execution: it only exports runToolCall(), honors isError results, and passes structuredContent through afterToolCall. Nested calls (ctx.executeTool, ids, events with parentToolCallId, the nestedCalls record) live in coding-agent and start on the first call.

AgentSession no longer knows exec or tool_search. Tools adjust the declared loadout through a generic prepareLoadout hook, and codemode and tool_search use it like any other tool.

exec and tool_search move to built-in extensions under src/extensions/ and register inactive (defaultActive: false). The CLI loads them with MCP; SDK sessions add createCodemodeExtension(), createToolSearchExtension(), and createMcpExtension(). Extensions gain pi.getSettings() and model catalog and classifier access on ModelRegistry.
2026-09-27 21:15:56 +02:00
Armin Ronacher
377cef09de fix(agent,coding-agent): simplify tool result contracts from the codemode review
- structuredContent after tool_result/afterToolCall: providing it replaces it; replacing content without it drops it. No more key-presence checks.
- Tools run outside a session get a ToolContext (loop services plus optional extension fields) instead of a context typed as a full ExtensionToolContext.
- Document that nested calls get synthesized <parent>/<n> tool call ids that never appear in the transcript.
- The exec description no longer mentions yield_time_ms, which is accepted and ignored.
- The sandbox abort test waits for the tool call instead of a fixed delay.
2026-09-27 19:31:57 +02:00
Armin Ronacher
42933fdb50 feat(ai,agent,coding-agent): emit events for nested tool calls and record them
Calls a tool makes through executeTool (for example from exec scripts) now emit tool_execution_start/update/end with parentToolCallId, for extensions and telemetry. Interactive mode keeps showing them inside the parent's row, and Agent.pendingToolCalls only tracks model-issued calls.

The model-issued call's tool result message carries nestedCalls, a bounded record like Codex's ExecutedToolCalls: name, arguments, status, duration, and error, never results. Arguments over 8 KiB per call or 32 KiB in total are omitted, at most 256 calls are kept, and complete is false when anything was lost or still running. Compaction and branch summaries count files touched by nested read/edit/write calls, and HTML exports list nested calls.
2026-09-27 19:14:50 +02:00
Armin Ronacher
188d3a4bd0 feat(coding-agent): add codemode.mode to present tools like Codex's tool modes
While exec is active, codemode.mode on (default) appends the exec declaration to declared tools that scripts can call and lists only non-direct tools in the exec description. codemode.mode only lists every callable tool in the exec description and hides active direct tools from requests. The hiding is a request projection, so the transcript still declares the active set and /tree and resume keep it.

The exec listing depends on exposure, not on the active set, so tool_search loads do not redeclare exec.
2026-09-27 19:07:25 +02:00
Armin Ronacher
fe07d21dde feat(coding-agent): add tool discovery for exec and a tool_search tool
- The exec description spends at most codemode.inlineBudget (default 3000) estimated tokens on tool declarations, filled round-robin across namespaces, cheapest first. Every namespace is listed with its tool count, and the listing says COMPLETE or PARTIAL.
- Scripts find omitted and deferred tools with searchTools(query, { limit, namespace }) and describeTool(name).
- tool_search, an optional built-in modeled on Codex, searches codemode and deferred tools and declares the matches for the next model call through the active tool set, so loads are recorded on the branch.
- Both use a BM25 ranker over Codex's search text (name, description, schema properties, namespace) behind a ToolRanker interface.
2026-09-27 18:48:47 +02:00
Armin Ronacher
3de4babe50 feat(codemode,coding-agent): make codemode a Codex-compatible exec tool
The codemode tool is now exec and follows the exec tool of OpenAI Codex, so scripts written for Codex run unchanged:

- // @exec: pragma with yield_time_ms, max_output_tokens (default 10000 tokens) and the pi addition timeout_ms; Codex's grammar and error messages
- text(), image() (data URLs, { image_url }, MCP ImageContent), exit(), ALL_TOOLS, tools under normalized identifiers; console and return values append text
- Results start with Script completed/failed and the wall time; failed scripts return an error result that keeps partial output and appends Script error
- Output over the token budget keeps its start and end like Codex; the full text is spilled to a temp file
- MCP tools resolve to their CallToolResult (isError resolves) and are declared as CallToolResult<T>; bash resolves to { output, exit_code, wall_time_seconds }, also for non-zero exits
- The description uses Codex's layout: helper list, deferred-tool guidance, shared MCP types, one section per tool grouped by namespace (MCP servers, with their instructions)
2026-09-27 18:00:33 +02:00
Armin Ronacher
f2270cdb63 feat(agent): let tools return error results without throwing
AgentToolResult.isError marks a result as failed while keeping details and structuredContent, so partial output and structured failures (such as MCP isError results) reach the UI and nested callers.
2026-09-27 18:00:25 +02:00
Armin Ronacher
4ccdc212e7 feat(agent,coding-agent): replace nestedOnly with tool exposure
AgentTool.nestedOnly is replaced by AgentContext.nestedTools, the tools callable through executeTool. Tool definitions declare an exposure (direct, model-only, codemode, deferred, hidden). The active set is now the declared set; codemode and deferred tools are callable from codemode whenever registered, so tree navigation, resume and fork cannot drop them.

MCP servers accept deferred and hidden exposure, withdraw tools by re-registering them as hidden, and mcp.json gains autoEnableCodemode.
2026-09-27 17:38:48 +02:00
Armin Ronacher
be49a2509d fix(mcp,coding-agent): bound SSE event data and report codemode spill errors
The SSE parser only limited the partial line, so a stream of short data: lines without a blank line could grow without bound. The event data size is now checked as lines arrive.

When saving a truncated codemode return value to a temp file fails, the truncation notice now names the error.
2026-09-27 17:38:40 +02:00
Armin Ronacher
d20d3ada42 fix(coding-agent): keep codemode MCP tools on tree navigation, cap codemode memory
Restoring tools from the transcript dropped nestedOnly tools because they are never declared to the model, so /tree navigation turned off codemode-exposed MCP tools. Active nestedOnly tools are now kept.

Codemode scripts now run with a 256 MiB QuickJS memory limit instead of growing up to the 4 GiB wasm32 ceiling inside pi's process.
2026-09-27 13:59:40 +02:00
Armin Ronacher
423b99797e fix(coding-agent): validate MCP server URLs and re-prompt sign-in on repeated 401
An invalid url made the OAuth store throw while creating connections, which
failed MCP startup for every server. OAuth servers that still answer 401
after a refresh now show as needing sign-in instead of failing each call.
2026-09-27 12:44:42 +02:00
Armin Ronacher
0ea585d6ca fix(codemode): fail stalled scripts and expand local schema references
- A script awaiting a promise nothing can settle (no pending host call,
  no timers in the VM) now fails instead of hanging until aborted, which
  matters because pi runs scripts without a default deadline
- Declarations resolve #/$defs and #/definitions references, which MCP
  servers built on pydantic or zod emit for nested arguments
2026-09-27 12:43:25 +02:00
Armin Ronacher
b9bbc35844 fix(coding-agent): make MCP connections and OAuth refresh reliable
- Share one OAuth refresh between concurrent requests and skip it when the
  token was already replaced, so rotating refresh tokens do not sign the
  user out; refresh tokens before they expire
- Treat insufficient_scope as needs-sign-in and request the new scope on
  /mcp login instead of refreshing
- Only list tools for servers that declare the tools capability
- Retry HTTP connects that fail transiently; show dropped connections as
  disconnected
- Deactivate tools a server withdraws on list_changed and restore them
- Keep sanitized tool names unique; default missing input properties
2026-09-27 12:41:07 +02:00
Armin Ronacher
0d8db59207 fix(mcp): harden streamable HTTP, stdio shutdown, and OAuth refresh
- Accept servers negotiating 2024-11-05 through 2025-11-25; request 2025-11-25
- Default missing tools/call content, never cancel initialize, add onClose
- Open the GET stream only after notifications/initialized, reconnect it
  with backoff, and send Last-Event-ID only when resuming
- Resume response streams the server closed before answering; fail the
  request instead of hanging when a stream ends without a response
- Reject 202 for requests, ignore bodies for notifications, include the
  response body in HTTP errors
- Hand 401 and insufficient_scope 403 to the auth provider with the
  rejected token; share one refresh between concurrent 401s so rotating
  refresh tokens are not burned; skip refresh for step-up scope
- Track token expiry, normalize issuer trailing slashes
- Shut stdio servers down per spec (stdin, SIGTERM, SIGKILL) across their
  process group
2026-09-27 12:37:01 +02:00
Armin Ronacher
6e6c5a9fe3 Merge branch 'main' into codemode-and-mcp
# Conflicts:
#	packages/coding-agent/install-lock/package-lock.json
#	packages/coding-agent/npm-shrinkwrap.json
2026-09-27 12:26:43 +02:00