Commit graph

1293 commits

Author SHA1 Message Date
Christian Klotz
8efd314fa3
docs(ai,coding-agent): generate models.json reference from schemas (#11038)
* docs(ai,coding-agent): generate models.json reference from schemas

Add npm run generate:references, which renders docs/models-configuration.md
from the models.json TypeBox schemas, and describe provider and model fields
in those schemas. Overrides get their own descriptions without defaults, and
compat sections cover the Responses API aliases.

closes #10790

* Modify changelog

* docs(ai,coding-agent): use shared thinkingLevelMap and promptCache schemas

Replace the per-use schema helpers with fixed schemas whose descriptions
hold for both models and modelOverrides entries.
2026-10-16 21:53:00 +01:00
Carlos Villela
95364a54ef
feat(coding-agent): default NVIDIA to Nemotron 3.5 Super VL (#10910)
* feat(coding-agent): default NVIDIA to Nemotron 3.5 Super VL

Co-authored-by: prademacher-nvidia <235594174+prademacher-nvidia@users.noreply.github.com>

* docs(coding-agent): changelog for NVIDIA default model change

* fix(ai): run NVIDIA E2E tests against Nemotron 3.5 Super VL

---------

Co-authored-by: prademacher-nvidia <235594174+prademacher-nvidia@users.noreply.github.com>
2026-10-16 22:26:37 +02:00
David Brailovsky
6fcb48670f
fix(coding-agent): remove fixed output limits from summary requests (#11036)
Compaction summaries were limited to 0.8 * compaction.reserveTokens (13107 by default), turn-prefix summaries to 0.5 * reserveTokens, and branch summaries to a hardcoded 4096. On providers where reasoning shares the output limit (OpenAI Responses, adaptive Anthropic), high thinking levels used most of that limit and compaction failed with "generation hit the token cap", even though the model allows far more output.

Tying the limit to reserveTokens assumed the summary request is as large as the full context, so its output had to fit in the reserved space. It is usually much smaller: recent messages kept by keepRecentTokens are not sent, a split turn goes to a separate request, tool results are truncated, and tool definitions and the normal system prompt are not included. Manual compaction can also run long before the context is full. The provider layer already sizes output from the actual request, using the model's output limit reduced to fit the remaining context, as for normal turns.

Summary requests now set no maxTokens and rely on that. compaction.reserveTokens only controls when compaction starts.

generateSummary() and generateSummaryWithUsage() now ignore the reserveTokens parameter.

closes #9512, closes #9075, closes #10908
2026-10-16 13:53:16 +02:00
David Brailovsky
90d863f7c1 fix(coding-agent): use mimo-v2.6-pro as Xiaomi default model
The generated Xiaomi catalogs no longer include mimo-v2.5-pro.
2026-10-16 12:51:37 +02:00
David Brailovsky
9fe3f37162 fix(coding-agent): keep empty quoted prompt template arguments
Empty quoted arguments ("" or '') were dropped, shifting later positional
arguments and preventing positional defaults from applying.

closes #10867
2026-10-14 15:35:39 +02:00
Ramiz Wachtler
910149912c
fix(coding-agent): normalize read line-range labels (#10938)
- share range formatting across the TUI, exports, and examples
- add regression coverage without changing execution arguments
- fixes #9887
2026-10-14 15:20:04 +02:00
Christian Klotz
d7f7e0dfee
fix(coding-agent): resolve model references through one provider selection policy (#10913)
* fix(coding-agent): resolve model references through one provider selection policy

Model references from --model, --models/enabledModels, /model, and auth credential printing now share one resolver. It collects every candidate before choosing a provider, so catalog order never decides, a :<thinking> suffix cannot change the provider, and an ambiguous exact match no longer falls through to a fuzzy match.

provider/id still prefers the named provider's exact or fuzzy match. A gateway exposing provider/id as a raw model id is used when the named provider has no match, or lacks credentials while the gateway has them. Several gateways without a unique authenticated one are reported as ambiguous.

fixes #10160

* docs(coding-agent): shorten model selection notes in CLI reference

* docs(coding-agent): condense #10160 changelog entry

* fix(coding-agent): move model reference resolution into model-resolver

* fix(coding-agent): warn when a model scope pattern matches several providers

* docs(coding-agent): trim model resolver comments to the reasons

* fix(coding-agent): build custom model ids from the resolver's not-found target
2026-10-14 11:00:21 +01:00
David Brailovsky
6f2f164ab7
fix(coding-agent): restore active tools on session resume (#10887)
The SDK always passed initial tools, so the constructor never restored the
loadout recorded in the transcript, and resumed sessions dropped tools activated
during the session. Sessions that use the default tools now restore the recorded
loadout, with --tools +name/-name entries applied to it.

fixes #10785
2026-10-13 15:55:12 +02:00
Vegard Stikbakke
cea257439d feat(coding-agent): configure session share destination
closes #10870
2026-10-13 15:41:13 +02:00
David Brailovsky
e6fb2581df fix(coding-agent): retry transient Windows EPERM when acquiring auth lock
A just-removed auth.json.lock directory can stay delete-pending on Windows
while another process holds a handle, making mkdir fail with EPERM. Retry
this briefly (capped separately from ELOCKED) so real permission errors
still fail fast.

fixes #10801
2026-10-12 16:14:55 +02:00
Armin Ronacher
014873d7d5 feat(coding-agent): show elapsed and total time on codemode rows
The codemode row shows "Elapsed" while the script runs and "Took" once
it finishes, like bash rows. The timer logic moves from the bash renderer
to render-utils, and scripts send an initial update so the timer starts
before the first nested call.

closes #10708
2026-10-12 15:29:18 +02:00
David Brailovsky
6a51a39d42 fix(coding-agent): expand ~ in resource setting patterns
Entries like !~/skills/pdf, +~/x and -~/x in the extensions, skills,
prompts, and themes settings were compared with a literal ~ and never
matched.

fixes #10765
2026-10-12 14:03:34 +02:00
David Brailovsky
ee409a85f6
feat(ai,coding-agent): list only the OpenRouter models a key may use (#10672)
On each OpenRouter refresh, combine the catalog (built-in models plus a newer pi.dev catalog) with GET /models/user for the user's key: keep only the listed chat models and take their context size, max output and prices from it. Image and classifier models are kept. The combined list is saved and replaces the OpenRouter catalog, including offline.

- ai: add personalizeOpenRouterCatalog and RefreshModelsContext.baseUrl, so the request follows a base URL configured in models.json (regional endpoints)
- ai: share OpenRouter price conversion with the generator; negative prices (router models such as openrouter/auto) become 0
- coding-agent: add withPersonalizedCatalog next to withRemoteCatalog
- docs: OpenRouter section in providers.md

fixes #10353
2026-10-12 10:17:40 +02:00
David Brailovsky
a447ba11f3
fix(coding-agent): emit before_agent_start for runs started by custom messages (#10739)
Runs started by pi.sendMessage(..., { triggerTurn: true }) skipped before_agent_start. After their first tool call, the next-turn refresh fell back to the base prompt options and patched away the sections handlers had added, changing the system prompt mid-run and breaking the provider prompt cache.

These runs now go through the same setup as prompt(): compaction check, before_agent_start, tool loadout, nextTurn messages, handler messages, and the system patch. BeforeAgentStartEvent is a union on messageType ("user" or "custom"); custom events carry the starting message.

The session counts as busy from the start of setup, so messages sent while handlers run go into the starting run instead of starting a second one, and an abort requested meanwhile aborts the run once it starts.

closes #10267, closes #5581, closes #10639, closes #10289
partly fixes #10606
2026-10-12 09:53:24 +02:00
Armin Ronacher
24382bedd0 refactor(codemode,coding-agent): decouple MCP from codemode
Tools that reach other tools declare it with reachesTools(input); MCP uses it to wait for the servers a call needs and to decide which codemode or tool_search tool to activate, instead of parsing codemode scripts and comparing parameter schemas. Namespaces get aliases, replacing codemode's MCP-specific __ suffix rule.

pi-codemode no longer knows MCP: MCP_TYPESCRIPT_PREAMBLE and mcpStructuredContentSchema() are removed, and the MCP result schema describes itself, with the server's local $refs relocated so they resolve as before.
2026-10-12 09:19:30 +02:00
Mario Zechner
15e7bdc14c fix(coding-agent,durable): omit thinking from compaction summaries
Replayed thinking is often not part of the live context (for example,
radius drops it, and Anthropic drops blocks that do not match their
request), but serializeConversation included all of it. A Pi Mobile
session at ~996K of 1M context tokens produced 1.38M-token summarization
requests that failed on every attempt. Providers only return summaries of
the reasoning anyway; visible text, tool calls, and tool results record
what happened.
2026-10-11 15:45:13 +00:00
David Brailovsky
f1b2e77f5b fix(coding-agent): load symlinked AGENTS.md in nested git worktrees
The nested worktree dedup compared the context file's realpath with the
main repo's file, so a worktree AGENTS.md symlinked to the main repo's
copy was skipped along with it. Compare the walked directory's realpath
plus the file name instead.

fixes #10681
2026-10-09 09:40:08 +02:00
Christian Klotz
7f9e1198f2
feat(coding-agent): publish configuration schemas (#9880)
* feat(coding-agent): publish configuration schemas

* fix(coding-agent): preserve config schema metadata

* fix(coding-agent): align schemas with public contracts

* fix(ai): place compatibility schema with providers

* fix(ai,coding-agent): align configuration schema contracts

* fix(ai): reuse session affinity schema

* docs(coding-agent): document strict theme validation

* fix(ai,coding-agent): align runtime and generated schemas

* fix(ai,coding-agent): centralize configuration schema contracts

* fix(ai,coding-agent): preserve schema validation contracts

* fix(coding-agent): validate keybinding schema grammar

* fix(ai,coding-agent): refine configuration schemas

* fix(ai,tui,coding-agent): align schemas with runtime behavior

* fix(tui): normalize shifted symbol keybindings

* fix(ai): preserve compatibility auto-detection
2026-10-08 10:01:17 +02:00
Mario Zechner
503c605528 feat(tui,coding-agent): report program status via OSC 7501
Report idle, working, blocked, done, and error to terminals that support
the Program Status Protocol. ProcessTerminal sends the support query with
the keyboard query and reports only after the terminal answers before DA1;
PI_PROGRAM_STATUS=1|0 overrides detection. Interactive mode reports runs,
compaction, extension dialogs, and logins. agent_settled now carries
aborted so cancelled runs report idle.

closes #10607
2026-10-07 19:05:41 +00:00
David Brailovsky
27c7b6ff48 fix(coding-agent): strip ANSI sequences split across user bash output chunks
closes #10504
2026-10-07 15:02:59 +02:00
Armin Ronacher
ce8972a0e9 feat(ai,coding-agent): add OpenAI Decisions classifier and classifier images
Adds the openai-decisions classifier API with gpt-6-luna on the openai provider. bool questions map to predicates with the criteria in the instructions, refusals fail the result, and gateway timeouts (504) are not retried. The model needs an API key and is hidden from availability while openai uses Sign in with ChatGPT.

Adds optional images to ClassifierContext. Models without image input and APIs that cannot send images return an error result. Codemode's models.classify() accepts images.

Moves the shared classifier HTTP code out of system-one-shared.ts into classifier-shared.ts.
2026-10-07 08:27:56 +02:00
Mario Zechner
36a686ee8d feat: record response, tool execution, and durable task times
pi-ai's AssistantMessageEventStream sets AssistantMessage.durationMs with a
monotonic clock for every API implementation. The agent loop and the durable
tool task set ToolResultMessage.durationMs around execute(). Durable task
records carry startedAt/endedAt stamped by the Session. The coding agent's bash
renderer shows Took from the recorded duration, also after a reload.

closes #10549
2026-10-06 19:28:54 +02:00
Ramiz Wachtler
18336987ad
fix(coding-agent): apply outputPad to all transcript blocks (#10557) 2026-10-06 17:27:55 +02:00
Armin Ronacher
ddaa0a0341 feat(coding-agent): accept +name/-name entries in --tools
A --tools list of only +name/-name entries changes the default tool
selection like the defaultTools setting, e.g. pi -t +codemode. Mixed
lists and patterns in modifiers are rejected, and /reload keeps tools
removed with -name removed.
2026-10-06 13:51:04 +02:00
Armin Ronacher
c30840c2eb fix(coding-agent): keep hidden tools out of prompt rules and skills hint
Rules and the tool list follow the declared tools (active minus
hiddenDeclarations). The skills hint names no tool when the reader is
hidden. Codemode shows each tool's prompt guidelines with its
declaration, via the new ToolLoadout.getPromptGuidelines().

closes #10343
2026-10-05 18:50:17 +02:00
Armin Ronacher
04b97ef000 fix(coding-agent): keep MCP tools with --tools, add tool patterns and --no-mcp
--tools no longer removes MCP tools unless an entry starts with mcp__, so
pi --tools codemode can reach MCP servers. Unnamed MCP tools are never
declared directly; only tool_search can load them. --no-tools still
removes everything.

--tools and --exclude-tools accept * patterns, for example
--tools read,codemode,'mcp__radius__*'. --no-mcp disables the built-in
MCP support for one run.
2026-10-05 17:21:55 +02:00
Armin Ronacher
021eae60a7 fix(coding-agent): resolve codemode read calls on images to image blocks
read declares an output schema: text for text files, and an image block
with its note for images, which codemode's image() shows.

closes #10251
2026-10-05 16:58:05 +02:00
Justin Santer
a37306d437
feat(ai): support Azure Foundry Chat Completions deployments (#9714)
* feat(ai): support Azure Foundry Chat Completions deployments

The Azure provider only implemented the Responses API, so Foundry
deployments that speak Chat Completions could not be used. On Chat
Completions the deepseek/deepseek-v4-pro model sends `thinking` and
`prompt_cache_key`, both of which Azure rejects with 400.

The provider now dispatches openai-completions alongside
azure-openai-responses. A stream wrapper resolves the Azure endpoint
onto the model first, since the shared openai-completions
implementation reads it off the model.

The request-shape differences are catalog compat rather than api code:
reasoning_effort instead of DeepSeek's thinking field, no prompt cache
parameters, reasoning_content kept on assistant turns so the prefix
Foundry cached stays byte-identical, and effort clamped to the
low/medium/high the deployment accepts.

The provider is renamed from azure-openai-responses to azure, since it
now serves more than the Responses API. The azure-openai-responses api
id is unchanged. Breaking: auth.json and models.json entries keyed on
azure-openai-responses must move to azure, and existing sessions see a
different provider on their next turn.

closes #9645

* feat(ai): apply the Azure deployment name map to Chat Completions

The Responses path already sent the deployment name from
AZURE_OPENAI_DEPLOYMENT_NAME_MAP. The Chat Completions path sent the
catalog model id, so any deployment not named after the model 404'd.

The Azure provider now swaps the deployment name into the request via
onPayload before dispatch, then runs the caller's own onPayload on it.
model.id stays the catalog id. The map helpers move to
azure-openai-config.ts so the provider can share them without
importing the SDK.

* docs(ai,coding-agent): add changelog entries for the Azure provider rename

Breaking: the azure-openai-responses provider is now azure. Users rename
the key in auth.json, models.json, and settings.json; SDK users switch to
getModel("azure", ...) and providers/azure.

Also note Azure Foundry Chat Completions support (DeepSeek V4 Pro).

---------

Co-authored-by: David Brailovsky <davidbrai@gmail.com>
2026-10-05 09:46:48 +02:00
Armin Ronacher
d677d0ee71 feat(coding-agent): save codemode image() output to temp files
image() output is also written to a temp file and the result names the
path before each image, so later turns can reference generated images.
Output files are now created through one helper (still tmpdir()) and
are readable only by the user.

closes #10310
2026-10-04 23:32:43 +02:00
Duncan Ogilvie
76dfb88f63
feat(ai): add per-thinking-level sampling parameters (#9776) 2026-10-04 01:29:01 +02:00
Armin Ronacher
49b9df4895 fix(coding-agent): default NVIDIA to Nemotron 3 Ultra
NVIDIA no longer serves nvidia/nemotron-3-super-120b-a12b, so the default model and the NVIDIA e2e test now use nvidia/nemotron-3-ultra-550b-a55b.
2026-10-03 14:14:51 +02:00
Armin Ronacher
11449730c8 fix(coding-agent): render MCP tool calls before their server connects
Add pi.registerToolRenderer((toolName, next) => renderers), which chooses the
renderers for calls to any tool, including tools that are not registered.
Resolvers run in extension load order; next() returns what the remaining
resolvers, then the registered tool, would use. Interactive mode and HTML
export both resolve through it.

The MCP extension uses it to render every mcp__<server>__<tool> call with the
MCP renderers, so calls in a resumed session no longer render fully expanded
before their server connects, or for good if it never does.

closes #10285
2026-10-03 13:54:18 +02:00
Armin Ronacher
1499466d85 feat(coding-agent): opt-in MCP OAuth client ID metadata documents
Adds oauth.clientRegistration: "cimd", which identifies pi with its Client ID Metadata Document on pi.dev instead of dynamic client registration, matching Codex: a shared document when the authorization server sends iss, otherwise a document and callback path specific to the MCP server. Authorization responses are only accepted on the exact redirect URI. Dynamic client registration stays the default.

closes #10302
2026-10-02 16:02:43 +02:00
Armin Ronacher
6f1072cc08 feat(coding-agent): shrink codemode prompt and guide scripts back from errors
Move the codemode script reference, including the models API, into
docs/codemode.md and keep only one line per global in the tool
description. Declared tools get a one-line note on how scripts call them,
and the codemode system prompt guidance and MCP server section are shorter.
With the default tools a GPT-5.6 request drops from about 5,300 to 3,300
tokens.

Errors now point the way back: unknown tools and models members name close
matches, models.classify() and models.generateImages() validate their
arguments, unknown or mistyped models point to getAvailableOfType(),
store() overflow explains the store, and unshown generated images get a note.
2026-10-01 18:27:23 +02:00
Armin Ronacher
88ff80b986 feat(coding-agent): make fullscreen the default TUI mode 2026-10-01 17:26:35 +02:00
Armin Ronacher
aab34df655 feat(coding-agent): add models.generateImages() to codemode
Scripts run image models with the session's credentials, like
models.classify(). Results are base64 image blocks that image() attaches
to the codemode result; usage counts toward the session cost.
2026-10-01 16:50:29 +02:00
Armin Ronacher
ed8b3bcc19 feat(coding-agent): offer Radius sign-in and MCP setup in /login
The top-level /login menu offers Sign in with Radius with its status,
with an animated shimmer on the Radius row and a short Radius intro.
After a Radius sign-in it offers to configure the Radius MCP server in
the global mcp.json with auth.provider and reloads. Cancelling a login
returns to the menu it was started from. OAuth sign-ins without a
subscription are labeled as accounts.

Co-authored-by: niloc <5925270+colindaymond@users.noreply.github.com>
2026-10-01 15:12:24 +02:00
Armin Ronacher
f29ea3deb2 feat(coding-agent): add header-only quietStartup mode
quietStartup: "header" keeps the startup header with version and key hints
but hides the model scope line and loaded-resource listing.
2026-10-01 14:42:02 +02:00
Armin Ronacher
c662ec7e37 fix(coding-agent): restore MCP tools loaded by tool_search on resume and reload
The session restored its tool loadout before MCP servers reconnected, so deferred tools that tool_search had loaded were dropped. Restored tools that are not registered yet now stay pending and are activated when they register, until a setActiveTools() call deactivates a tool or the next prompt starts.
2026-10-01 13:35:33 +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
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
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
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
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