Commit graph

1170 commits

Author SHA1 Message Date
Petr Houška
c8ec752cf9 fix(coding-agent): skip fd/rg downloads on unsupported architectures
Only x64 and arm64 map to prebuilt release archives. ARM32 and ia32 previously
fell back to x86-64 binaries; now pi warns and recommends the system package manager.

fixes #11209
2026-10-23 19:48:59 +02:00
Lincoln
6dfb546785
fix(coding-agent): start when a configured package fails to install (#11304)
fix(coding-agent): start when a configured package fails to install

A package in settings.json that could not be installed (registry
unreachable, package missing, failing git prepare step) crashed startup
with an uncaught rejection and a raw Node stack.

Resolving packages now catches the install failure, skips that package
the same way offline mode does, and reports it as an extension warning:

  Warning: Extension package "npm:foo": failed to install (...).
  Run "pi remove npm:foo" to remove it from settings.json.

Project packages point at `pi remove <source> --local`. `-e` sources
say to check the source instead. Pi tries the install again on the next
start or /reload.

--help and --list-models now print runtime diagnostics, so the warning
shows there too. pi config prints it as well. pi install and
pi update --extensions still fail with a non-zero exit.

closes #11088
2026-10-23 12:27:45 +02:00
Petr Houška
8c03fef4d3 fix(tui,coding-agent): rank contiguous fuzzy matches and search session fields separately
fuzzyMatch scored only the greedy leftmost alignment, so a query could be
scattered over an earlier unrelated part of the text (opus via "openrouter",
astra via "radius radius/gpt") and the real match ranked last. It now also
scores every contiguous occurrence and keeps the best alignment.

/resume matched one concatenated id/name/messages/cwd string. Scattered
matches in megabytes of message text or in UUIDs were noise, and the
position penalty buried real hits deep in a transcript. Fields are now
matched separately: name and cwd fuzzy, id and messages exact only, with no
position penalty. Ranking is name text, then id/message/cwd text, then
scattered name/cwd matches. Lowercased message text is cached per session.

closes #11220
2026-10-22 21:39:17 +02:00
Petr Houška
7151099d02 feat(coding-agent): confirm device-code browser and clipboard actions
Knowing how annoying re-logins in corporate environments can be, I think
we can open the browser and copy the code to the clipboard (what the user
asks for) without forcing it upon users (which I assume was the reason
it was removed in 8f0e9251b9).

This change adds optional browser opening and code copying during
device-code login after an additional confirmation (usually Enter).
It should work for all providers, with an optional opt-out controlled
by the provider author, not user settings.

Fixes #9282.
2026-10-22 21:38:58 +02:00
muyiyr
c60de42e98 fix(coding-agent): preserve pi.exec spawn errors
Fixes #11085
2026-10-22 21:14:23 +02:00
Petr Houška
1c720d2850 fix(coding-agent): render HTML export for sessions deeper than the call stack
Replace recursive tree walks in the export template (sortChildren, mapNodes,
markActive) with iterative traversals, and build getPath with push + reverse.

closes #11225
2026-10-22 20:51:38 +02:00
Ville Penttinen
64627838b2
feat(coding-agent): add messageId and timestamp to markdown transformer context
* feat(coding-agent): add messageId and timestamp to markdown transformer context

* fix(coding-agent): update compaction render test for messageMeta argument

---------

Co-authored-by: Petr Houška <houskape@gmail.com>
2026-10-22 20:49:38 +02:00
Petr Houška
9359adf0c6 fix(coding-agent): render system messages in HTML export
Render the leading system message as the system prompt and tool list,
and later system messages as named section and tool updates. The header
prompt/tools from agent state remain as a fallback for sessions without
system entries. CLI --export now shows the prompt and tools too (#3464).

closes #11261
2026-10-22 20:37:03 +02:00
Petr Houška
27cc6bfc0c fix(coding-agent): stop macOS shell groups before killing them
Reduce the race where killing a foreground child wakes its shell before the shell is signalled. Keep Linux and Windows termination unchanged and preserve kill fallbacks when stopping fails.

closes #11252
2026-10-22 20:22:20 +02:00
Vegard Stikbakke
cae8d69e57
fix(ai): use OpenRouter-reported total cost (#10286)
Use authoritative OpenRouter billing for Chat Completions and Anthropic Messages while retaining catalog component estimates and fallback behavior.

Fixes #9980
2026-10-22 11:01:39 +02:00
Vegard Stikbakke
7c22a93d0e
feat(ai): add totalFromProvider flag to usage cost (#11178)
Add Usage.cost.totalFromProvider to record whether cost.total is the
billed cost reported by the provider or an estimate from catalog rates.
Catalog-derived totals set it to false; a missing value also means
false. combineUsage marks a sum as provider-reported only when both
parts are.
2026-10-22 09:02:01 +02:00
Armin Ronacher
7f225f25d8 feat(ai,coding-agent): image input for System One classifiers
Jev (TypeSafe, Workers AI), Clef (Workers AI), and OpenRouter decision
models now accept ClassifierContext.images. Each service takes its own
wire form: TypeSafe assets with the opt-in header, Clef images data URLs,
or OpenRouter image_url parts in the state. A new SystemOneCompat
(imageInput, sendImageOptInHeader) selects the form; catalog entries set
it explicitly and models.json provider compat now applies to classifiers.

Adds Clef Omni and Jev 1.14 on Workers AI and fixes Clef Flash and
Workers AI Jev catalog pricing.
2026-10-21 23:53:47 +02:00
Petr Houška
02726086d1 fix(coding-agent): recovery omits tool results with the truncated tool call
Pre-prompt recovery of a recoverable length stop omitted the assistant
message but not the tool results that answered its calls, because only
the end-of-run caller passed them. The orphaned results were persisted
and providers rejected every later request.

_omitRecoveryAttempt now finds the matching tool results in the
projected context itself, so every caller omits the pair together.

closes #11227
2026-10-21 22:44:44 +02:00
Petr Houška
8c4e873899 fix(coding-agent): grep tool ignores ripgrep config via --no-config
The built-in grep tool spawned rg with the inherited environment, so
RIPGREP_CONFIG_PATH (e.g. a config containing --fixed-strings) silently
changed tool semantics: literal: false searches became literal and the
agent got incomplete results with no error.

Pass --no-config so the tool contract is deterministic. Users who want
custom rg behavior can use the bash tool or wrap grep in an extension.

closes #11203
2026-10-21 22:19:03 +02:00
David Brailovsky
bd3c9b8237 fix(coding-agent): activate extension tools registered after the branch recorded its loadout
Resume and /tree restored exactly the tools the branch recorded, so extension
tools registered later stayed inactive. Registered extension tools that the
branch never added or removed are now activated unless they use
defaultActive: false. The whole branch is searched, so tools removed before a
compaction stay inactive. Also fixes the /tree case from #11075.

closes #11062
2026-10-21 16:39:13 +02:00
Mario Zechner
04a93bad8f fix(ai,agent,coding-agent,durable): client identity follow-ups
- ClientAttribution is { name, url, categories? } with required name and url, so
  OpenRouter always gets an HTTP-Referer. identity.ts maps the fields to each
  provider's headers; NVIDIA gets the name with its first letter upper-cased.
  attribution: null turns it off. PI_ATTRIBUTION is pi's, including the
  cli-agent category; agent-core, durable, and the coding agent use it.
- Categories are a string array, joined for OpenRouter.
- withClientIdentity() is a typed wrapper instead of a Proxy and keeps a
  MutableModels mutable. Durable no longer caches wrappers in a WeakMap.
- The Codex originator stays pi; login agentName no longer follows attribution.
- Models and the coding agent's ModelRuntime add x-opencode-session for custom
  providers pointing at OpenCode, replacing the coding agent's transformHeaders.
2026-10-21 11:18:16 +00:00
Armin Ronacher
adc5fa9f80 feat(ai,agent,coding-agent): move client identity and provider attribution into pi-ai
pi-ai gets a ClientIdentity request option and createModels() default that choose the User-Agent (detailed with version, short, or custom) and provider attribution headers for OpenRouter, NVIDIA NIM, and OpenCode. Attribution is off by default in pi-ai and on by default in pi-agent-core and pi-durable (HarnessOptions.identity). pi-coding-agent sets its identity from the telemetry setting instead of adding headers itself.
2026-10-21 11:17:02 +00:00
David Brailovsky
adfc14461a fix(coding-agent): apply /compact instructions to split-turn prefix summary
closes #11058
2026-10-21 12:42:17 +02:00
Mario Zechner
bdd9f0399d fix(coding-agent): accept mcp.json files with a UTF-8 BOM
closes #11191
2026-10-21 00:14:21 +02:00
Petr Houška
22dc6c26f3 fix(coding-agent): expose @earendil-works/pi-ai/models in the extension loader
Extensions importing the public /models subpath (e.g. clampThinkingLevel)
failed with "Cannot find module" because the loader aliased/virtualized
only the pi-ai root, /compat, /oauth, and /providers/all entrypoints.
Add /models to the jiti aliases and the embedded virtual module map,
plus a regression test importing it without a local pi-ai install.

Closes #11156

Co-authored-by: Dante-dan <dantedan@users.noreply.github.com>
2026-10-20 21:47:52 +02:00
Mario Zechner
885a564b3b fix(coding-agent): queue codemode scripts at the worker limit
Scripts wait in arrival order for a free worker instead of failing
immediately. The wait counts toward timeout_ms, honours abort, and is
capped at 60 seconds. PI_CODEMODE_MAX_WORKERS raises the process-wide
limit of two workers for hosts running many sessions in one process.

closes #11184
2026-10-20 20:50:27 +02:00
Mario Zechner
f8ab362cca fix(coding-agent): keep clipboard helpers out of pi's process group so Ctrl+Z does not stop them
closes #11179
2026-10-20 20:49:48 +02:00
Mario Zechner
38847563f4 fix(coding-agent): stack concurrent extension dialogs instead of replacing them
A second select/confirm/input/editor dialog or inline custom() component
replaced the visible one and left its promise pending forever. Dialogs in
the editor slot now form a stack: closing the visible dialog shows the
previous one again, and dialogs opened from inside a custom component work.

closes #11166
2026-10-20 20:45:12 +02:00
Lucas Meijer
fdce48eb40
fix(ai): drop Codex models rejected for ChatGPT accounts (#11173)
The openai-codex provider authenticates with a ChatGPT account, and the
Codex backend rejects gpt-5.5 and gpt-5.3-codex-spark for those accounts
("not supported when using Codex with a ChatGPT account"). Remove them
from the catalog so model pickers stop offering models that always fail.

Codex e2e tests that used openai-codex/gpt-5.5 now use gpt-6.1-sol, the
openai-codex default. The context overflow test uses gpt-5.6-sol to keep
its prompt smaller.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 15:55:48 +02:00
Ramiz Wachtler
26293e74f6
fix(coding-agent): render CJK emphasis in HTML export (#11168) 2026-10-20 13:20:37 +02:00
Armin Ronacher
ea25697e91 fix(coding-agent): accept managed install markers with a UTF-8 BOM
Windows PowerShell 5.1 adds a BOM when it rewrites managed-install.json, which made pi update fail with "Managed install marker is missing or invalid".
2026-10-20 10:29:22 +02:00
Petr Houška
73f8de80bc fix(ai): recover from Copilot request-size overflow
Copilot rejects request bodies over its byte-size limit with HTTP 413 and a generic
'failed to parse request' body, so the existing token-count heuristics never matched.
Treat any HTTP 413 as request-size overflow regardless of provider or body text, so
the agent compacts and retries instead of surfacing a raw API error.

Validated against the live Copilot API (40MB image payload): main classifies the 413
as a plain error, this branch detects it as overflow.
2026-10-19 22:46:26 +02:00
Petr Houška
61060ddf8c fix(coding-agent): resolve Windows shells from installation directories
Use installation environment variables for PowerShell discovery and legacy WSL launcher detection.
2026-10-19 21:55:12 +02:00
Petr Houška
28bea006be fix(coding-agent): accept Windows Store shell aliases
Node's existsSync() can reject runnable Store aliases because its extra
Windows-only stat check fails with EACCES (nodejs/node#36790). Use
access(F_OK) for shell validation on all platforms instead, matching the
check harness-v2's async refactor settled on (617d8b317, now pathExists
in packages/durable/src/env/node.ts). On Unix this is a no-op: existsSync
is already access(F_OK) there, so shell search order and behavior stay
unchanged; on Windows runnable aliases now pass validation.
2026-10-19 21:24:10 +02:00
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
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
Colin Mason
a4f67eb65e
fix(coding-agent): close own custom ui overlay (#10999)
done() from ctx.ui.custom({ overlay: true }) closed the overlay with
ui.hideOverlay(), which removes the topmost overlay instead of the one
that called done(). With a shell overlay open under a dialog overlay
from another extension, the shell's exit removed the dialog: the
finished shell overlay stayed on screen ignoring input and the dialog's
promise never resolved. Hide the overlay through its own handle.

closes #10648
2026-10-15 20:50:03 +02:00
David Brailovsky
dfb03c3283 fix(coding-agent): use claude-sonnet-4.5 in model registry tests
anthropic/claude-sonnet-4 is no longer in the OpenRouter catalog.
2026-10-15 15:27:42 +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
Armin Ronacher
3daa20280f fix(coding-agent): keep codemode cancellation prompt and bounded
Refs #10748
2026-10-13 18:17:31 +02: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
3e477eab5f feat(coding-agent): add PI_CLIPBOARD_OSC52 to force OSC 52 copies
Sends copied text to the terminal with OSC 52 after the local clipboard
write, as over SSH, for remote clients without SSH variables such as
multiplexer attaches and remote IDE daemons.

closes #10826, closes #10835, closes #10114
2026-10-12 18:07:27 +02:00
Armin Ronacher
b6d505cd1f fix(codemode): reject // @options: lines that are not the first line
A misplaced options line was ignored, so its timeout_ms never applied and
the script ran without a deadline. parseCodemodeSource now throws
CodemodeSourceError before the script runs.

fixes #10631
2026-10-12 17:55:33 +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
David Brailovsky
441f5767c4 fix(coding-agent): warn and exit non-zero in print mode on truncated response
Print mode now writes a warning to stderr and exits 1 when the final
response stopped at the model's output token limit. The partial text
is still written to stdout.

fixes #10799
2026-10-12 16:06:42 +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
Armin Ronacher
67996ab75c fix(mcp,coding-agent): accept any JSON value as tool structuredContent
MCP 2026-07-28 allows structuredContent to be any JSON value, including
arrays and null. callTool() rejected non-object values, failing the whole
tool call. CallToolResult.structuredContent is now unknown, and MCP tools
without an output schema declare structuredContent as unknown to codemode.

refs #10416
2026-10-12 14:16:35 +02:00
Armin Ronacher
f4cca2dc22 fix(coding-agent): stop listing MCP resources when connecting
Servers with resources registered no tools until resources/list and
resources/templates/list finished, so a slow listing (a large drive)
kept their tools out of the first prompt. The lists only fed counts in
/mcp and pi mcp list; both now show that a server offers resources.
The resource tools still list and read resources on demand.

fixes #10526
2026-10-12 14:15:21 +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
Mario Zechner
7472cda0d6 feat(coding-agent): remove the experimental server stack and the client, protocol, and server packages
Deletes packages/client, packages/protocol (CBOR codec), packages/server, coding-agent's
src/experimental (except source-resolver.ts, which source runs still preload), src/cli/experimental,
src/client, the example plugin, and their tests. coding-agent no longer depends on @earendil-works/chord.
The installer lock drops esbuild, so its platform-package sanity check goes too.
2026-10-12 10:41:59 +00: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
Armin Ronacher
f11e50f72e fix(coding-agent): make codemode output joining linear
joinAdjacentText checked endsWith on the growing joined string, which
makes V8 flatten the concatenation on every item. Collect each text run
in an array, check the separator against the last non-empty part, and
join once. Same fix in the durable code mode copy.

closes #10678
2026-10-12 10:03:56 +02:00