diff --git a/package-lock.json b/package-lock.json index 1b9b01b3..c57a391e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5115,10 +5115,10 @@ }, "packages/agent": { "name": "@earendil-works/pi-agent-core", - "version": "0.80.6", + "version": "0.80.7", "license": "MIT", "dependencies": { - "@earendil-works/pi-ai": "^0.80.6", + "@earendil-works/pi-ai": "^0.80.7", "ignore": "7.0.5", "typebox": "1.1.38", "yaml": "2.9.0" @@ -5467,7 +5467,7 @@ }, "packages/ai": { "name": "@earendil-works/pi-ai", - "version": "0.80.6", + "version": "0.80.7", "license": "MIT", "dependencies": { "@anthropic-ai/sdk": "0.91.1", @@ -5773,12 +5773,12 @@ }, "packages/coding-agent": { "name": "@earendil-works/pi-coding-agent", - "version": "0.80.6", + "version": "0.80.7", "license": "MIT", "dependencies": { - "@earendil-works/pi-agent-core": "^0.80.6", - "@earendil-works/pi-ai": "^0.80.6", - "@earendil-works/pi-tui": "^0.80.6", + "@earendil-works/pi-agent-core": "^0.80.7", + "@earendil-works/pi-ai": "^0.80.7", + "@earendil-works/pi-tui": "^0.80.7", "@silvia-odwyer/photon-node": "0.3.4", "chalk": "5.6.2", "cross-spawn": "7.0.6", @@ -5819,32 +5819,32 @@ }, "packages/coding-agent/examples/extensions/custom-provider-anthropic": { "name": "pi-extension-custom-provider-anthropic", - "version": "0.80.6", + "version": "0.80.7", "dependencies": { "@anthropic-ai/sdk": "0.52.0" } }, "packages/coding-agent/examples/extensions/custom-provider-gitlab-duo": { "name": "pi-extension-custom-provider-gitlab-duo", - "version": "0.80.6" + "version": "0.80.7" }, "packages/coding-agent/examples/extensions/gondolin": { "name": "pi-extension-gondolin", - "version": "0.80.6", + "version": "0.80.7", "dependencies": { "@earendil-works/gondolin": "0.12.0" } }, "packages/coding-agent/examples/extensions/sandbox": { "name": "pi-extension-sandbox", - "version": "1.10.6", + "version": "1.10.7", "dependencies": { "@anthropic-ai/sandbox-runtime": "0.0.26" } }, "packages/coding-agent/examples/extensions/with-deps": { "name": "pi-extension-with-deps", - "version": "0.80.6", + "version": "0.80.7", "dependencies": { "ms": "2.1.3" }, @@ -6140,10 +6140,10 @@ }, "packages/orchestrator": { "name": "@earendil-works/pi-orchestrator", - "version": "0.80.6", + "version": "0.80.7", "license": "MIT", "dependencies": { - "@earendil-works/pi-coding-agent": "^0.80.6" + "@earendil-works/pi-coding-agent": "^0.80.7" }, "devDependencies": { "shx": "0.4.0" @@ -6154,7 +6154,7 @@ }, "packages/tui": { "name": "@earendil-works/pi-tui", - "version": "0.80.6", + "version": "0.80.7", "license": "MIT", "dependencies": { "get-east-asian-width": "1.6.0", diff --git a/packages/agent/CHANGELOG.md b/packages/agent/CHANGELOG.md index 391ec8fc..e09fcda0 100644 --- a/packages/agent/CHANGELOG.md +++ b/packages/agent/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased] +## [0.80.7] - 2026-07-14 + ### Added - Added `AgentToolResult.addedToolNames` propagation to `ToolResultMessage` so tools introduced by a result can be loaded from that transcript point onward ([#6474](https://github.com/earendil-works/pi-mono/pull/6474)). diff --git a/packages/agent/package.json b/packages/agent/package.json index d0f9d5af..1279d714 100644 --- a/packages/agent/package.json +++ b/packages/agent/package.json @@ -1,6 +1,6 @@ { "name": "@earendil-works/pi-agent-core", - "version": "0.80.6", + "version": "0.80.7", "description": "General-purpose agent with transport abstraction, state management, and attachment support", "type": "module", "main": "./dist/index.js", @@ -29,7 +29,7 @@ "prepublishOnly": "npm run clean && npm run build" }, "dependencies": { - "@earendil-works/pi-ai": "^0.80.6", + "@earendil-works/pi-ai": "^0.80.7", "ignore": "7.0.5", "typebox": "1.1.38", "yaml": "2.9.0" diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index eee024f8..02d58490 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -9,7 +9,6 @@ - Renamed the canonical login interaction interface from `AuthLoginCallbacks` to `AuthInteraction`; it exposes the provider-neutral `prompt()`/`notify()` protocol used by API-key and OAuth flows. - Changed the `Models` request contract: `getAuth(model)` now includes model headers, while `getAuth(providerId)` remains provider-scoped, and Models stream options may include `transformHeaders`. Custom `Models` implementations must execute the transform after merging auth/model and explicit headers, then remove it before provider dispatch. - Changed dynamic model refresh to `Models.refresh(options)`, which refreshes every configured dynamic provider and returns per-provider errors/cancellation state. `Provider.refreshModels(context)` now receives the effective credential, scoped model storage, network policy, and abort signal. -- Removed the `OpenAIResponsesCompat.sendSessionIdHeader` flag. Session-affinity behavior is now controlled by `compat.sessionAffinityFormat` (`"openai"`, `"openai-nosession"`, or `"openrouter"`). Replace `sendSessionIdHeader: false` with `sessionAffinityFormat: "openai-nosession"` ([#6366](https://github.com/earendil-works/pi/issues/6366)). ### Added @@ -18,10 +17,6 @@ - Added neutral auth-flow information/link events and provider-owned Amazon Bedrock and Google Vertex AI credential selection flows. - Added `ModelsStore` with an in-memory default for restoring and persisting dynamic provider catalogs. - Added the dynamic Radius `pi-messages` gateway provider with OAuth and credential-specific catalog refresh. -- Added cache-friendly dynamic tool loading. `ToolResultMessage.addedToolNames` marks where tools from `Context.tools` became available; Anthropic and OpenAI Responses use native deferred loading so late tools stay out of the cached prefix, while other providers continue using `Context.tools` normally ([#6474](https://github.com/earendil-works/pi-mono/pull/6474)). -- Added native `xhigh` and `max` thinking levels for Claude Fable 5 across all generated provider catalogs ([#6490](https://github.com/earendil-works/pi-mono/pull/6490) by [@davidbrai](https://github.com/davidbrai)). -- Added `toolChoice` support to OpenAI Codex Responses, including `"required"` to force a tool call. -- Added `toolChoice` support to OpenAI Responses, including required and named tool selection. ### Changed @@ -31,10 +26,31 @@ - Fixed Cloudflare Workers AI and AI Gateway streams to materialize account and gateway endpoint placeholders after auth resolution, including compat streaming with custom model objects. - Fixed lazy provider streams to preserve their final assistant message when forwarding an inner stream. + +## [0.80.7] - 2026-07-14 + +### Breaking Changes + +- Removed the `OpenAIResponsesCompat.sendSessionIdHeader` flag. Session-affinity behavior is now controlled by `compat.sessionAffinityFormat` (`"openai"`, `"openai-nosession"`, or `"openrouter"`). Replace `sendSessionIdHeader: false` with `sessionAffinityFormat: "openai-nosession"` ([#6496](https://github.com/earendil-works/pi-mono/pull/6496) by [@petrroll](https://github.com/petrroll)). + +### Added + +- Added cache-friendly dynamic tool loading. `ToolResultMessage.addedToolNames` marks where tools from `Context.tools` became available; Anthropic and OpenAI Responses use native deferred loading so late tools stay out of the cached prefix, while other providers continue using `Context.tools` normally ([#6474](https://github.com/earendil-works/pi-mono/pull/6474)). +- Added native `xhigh` and `max` thinking levels for Claude Fable 5 across all generated provider catalogs ([#6490](https://github.com/earendil-works/pi-mono/pull/6490) by [@davidbrai](https://github.com/davidbrai)). +- Added `toolChoice` support to OpenAI and Codex Responses, including required and named tool selection ([#6588](https://github.com/earendil-works/pi-mono/pull/6588) by [@xl0](https://github.com/xl0)). + +### Fixed + - Fixed OpenRouter model context windows to use the top provider's actual context length ([#6481](https://github.com/earendil-works/pi-mono/pull/6481) by [@davidbrai](https://github.com/davidbrai)). -- Fixed the GitHub Copilot `mai-code-1-flash-picker` model to route through the `/responses` endpoint. +- Fixed the GitHub Copilot `mai-code-1-flash-picker` model to route through the `/responses` endpoint ([#6544](https://github.com/earendil-works/pi-mono/pull/6544) by [@petrroll](https://github.com/petrroll)). - Fixed Amazon Bedrock requests to use the generic `apiKey` stream option as a Bedrock bearer token. -- Fixed OpenRouter OpenAI-compatible session IDs to use the `x-session-id` header instead of OpenAI-specific session-affinity fields ([#6366](https://github.com/earendil-works/pi/issues/6366)). +- Fixed OpenRouter OpenAI-compatible session IDs to use the `x-session-id` header instead of OpenAI-specific session-affinity fields ([#6496](https://github.com/earendil-works/pi-mono/pull/6496) by [@petrroll](https://github.com/petrroll)). +- Fixed Amazon Bedrock ambient AWS credentials to keep using SigV4 authentication, including for custom model IDs ([#6532](https://github.com/earendil-works/pi-mono/pull/6532) by [@ribelo](https://github.com/ribelo)). +- Fixed Cloudflare Workers AI and AI Gateway authentication to use ambient account and gateway IDs when stored credentials contain only an API key ([#6292](https://github.com/earendil-works/pi-mono/pull/6292) by [@markphelps](https://github.com/markphelps)). +- Fixed Amazon Bedrock errors to report unhandled provider stop reasons instead of only `An unknown error occurred` ([#6598](https://github.com/earendil-works/pi-mono/pull/6598) by [@davidbrai](https://github.com/davidbrai)). +- Fixed Azure OpenAI Responses reasoning replay when `encrypted_content` appears only in the terminal response event ([#6608](https://github.com/earendil-works/pi-mono/pull/6608) by [@davidbrai](https://github.com/davidbrai)). +- Fixed Anthropic-compatible proxies that omit `usage` from `message_delta` events ([#6611](https://github.com/earendil-works/pi-mono/pull/6611) by [@davidbrai](https://github.com/davidbrai)). +- Fixed OpenCode OpenAI Responses models to omit the unsupported `session-id` header while preserving other cache-affinity data ([#6645](https://github.com/earendil-works/pi-mono/pull/6645) by [@davidbrai](https://github.com/davidbrai)). ## [0.80.6] - 2026-07-09 diff --git a/packages/ai/package.json b/packages/ai/package.json index ce4613c1..d0edb56b 100644 --- a/packages/ai/package.json +++ b/packages/ai/package.json @@ -1,6 +1,6 @@ { "name": "@earendil-works/pi-ai", - "version": "0.80.6", + "version": "0.80.7", "description": "Unified LLM API with automatic model discovery and provider configuration", "type": "module", "main": "./dist/index.js", diff --git a/packages/ai/src/api/openai-codex-responses.ts b/packages/ai/src/api/openai-codex-responses.ts index fc57ec33..de0d1792 100644 --- a/packages/ai/src/api/openai-codex-responses.ts +++ b/packages/ai/src/api/openai-codex-responses.ts @@ -258,8 +258,9 @@ export const stream: StreamFunction<"openai-codex-responses", OpenAICodexRespons if (nextBody !== undefined) { body = nextBody as RequestBody; } - const websocketRequestId = options?.sessionId || createCodexRequestId(); - const sseHeaders = buildSSEHeaders(model.headers, options?.headers, accountId, apiKey, options?.sessionId); + const codexSessionId = clampOpenAIPromptCacheKey(options?.sessionId); + const websocketRequestId = codexSessionId || createCodexRequestId(); + const sseHeaders = buildSSEHeaders(model.headers, options?.headers, accountId, apiKey, codexSessionId); const websocketHeaders = buildWebSocketHeaders( model.headers, options?.headers, diff --git a/packages/ai/src/providers/openrouter.models.ts b/packages/ai/src/providers/openrouter.models.ts index d157f6fb..e18a1af2 100644 --- a/packages/ai/src/providers/openrouter.models.ts +++ b/packages/ai/src/providers/openrouter.models.ts @@ -462,24 +462,6 @@ export const OPENROUTER_MODELS = { contextWindow: 262144, maxTokens: 80000, } satisfies Model<"openai-completions">, - "arcee-ai/trinity-mini": { - id: "arcee-ai/trinity-mini", - name: "Arcee AI: Trinity Mini", - api: "openai-completions", - provider: "openrouter", - baseUrl: "https://openrouter.ai/api/v1", - compat: {"supportsDeveloperRole":false,"thinkingFormat":"openrouter"}, - reasoning: true, - input: ["text"], - cost: { - input: 0.045, - output: 0.15, - cacheRead: 0, - cacheWrite: 0, - }, - contextWindow: 131072, - maxTokens: 131072, - } satisfies Model<"openai-completions">, "arcee-ai/virtuoso-large": { id: "arcee-ai/virtuoso-large", name: "Arcee AI: Virtuoso Large", @@ -688,8 +670,8 @@ export const OPENROUTER_MODELS = { reasoning: true, input: ["text"], cost: { - input: 0.21, - output: 0.79, + input: 0.25, + output: 0.95, cacheRead: 0.13, cacheWrite: 0, }, @@ -1122,13 +1104,13 @@ export const OPENROUTER_MODELS = { reasoning: true, input: ["text", "image"], cost: { - input: 0.12, + input: 0.06, output: 0.35, - cacheRead: 0.09, + cacheRead: 0, cacheWrite: 0, }, contextWindow: 262144, - maxTokens: 262144, + maxTokens: 8192, } satisfies Model<"openai-completions">, "google/gemma-4-31b-it:free": { id: "google/gemma-4-31b-it:free", @@ -1146,7 +1128,7 @@ export const OPENROUTER_MODELS = { cacheWrite: 0, }, contextWindow: 262144, - maxTokens: 8192, + maxTokens: 32768, } satisfies Model<"openai-completions">, "ibm-granite/granite-4.1-8b": { id: "ibm-granite/granite-4.1-8b", @@ -1239,6 +1221,24 @@ export const OPENROUTER_MODELS = { contextWindow: 262144, maxTokens: 65536, } satisfies Model<"openai-completions">, + "kwaipilot/kat-coder-air-v2.5": { + id: "kwaipilot/kat-coder-air-v2.5", + name: "Kwaipilot: KAT-Coder-Air V2.5", + api: "openai-completions", + provider: "openrouter", + baseUrl: "https://openrouter.ai/api/v1", + compat: {"supportsDeveloperRole":false,"thinkingFormat":"openrouter"}, + reasoning: false, + input: ["text"], + cost: { + input: 0.15, + output: 0.6, + cacheRead: 0.03, + cacheWrite: 0, + }, + contextWindow: 256000, + maxTokens: 80000, + } satisfies Model<"openai-completions">, "kwaipilot/kat-coder-pro-v2": { id: "kwaipilot/kat-coder-pro-v2", name: "Kwaipilot: KAT-Coder-Pro V2", @@ -1257,23 +1257,23 @@ export const OPENROUTER_MODELS = { contextWindow: 256000, maxTokens: 80000, } satisfies Model<"openai-completions">, - "liquid/lfm-2.5-1.2b-thinking:free": { - id: "liquid/lfm-2.5-1.2b-thinking:free", - name: "LiquidAI: LFM2.5-1.2B-Thinking (free)", + "kwaipilot/kat-coder-pro-v2.5": { + id: "kwaipilot/kat-coder-pro-v2.5", + name: "Kwaipilot: KAT-Coder-Pro V2.5", api: "openai-completions", provider: "openrouter", baseUrl: "https://openrouter.ai/api/v1", compat: {"supportsDeveloperRole":false,"thinkingFormat":"openrouter"}, - reasoning: true, + reasoning: false, input: ["text"], cost: { - input: 0, - output: 0, - cacheRead: 0, + input: 0.74, + output: 2.96, + cacheRead: 0.15, cacheWrite: 0, }, - contextWindow: 32768, - maxTokens: 4096, + contextWindow: 256000, + maxTokens: 80000, } satisfies Model<"openai-completions">, "meta-llama/llama-3.1-70b-instruct": { id: "meta-llama/llama-3.1-70b-instruct", @@ -1357,8 +1357,8 @@ export const OPENROUTER_MODELS = { reasoning: false, input: ["text", "image"], cost: { - input: 0.15, - output: 0.6, + input: 0.2, + output: 0.8, cacheRead: 0, cacheWrite: 0, }, @@ -1866,7 +1866,7 @@ export const OPENROUTER_MODELS = { cacheRead: 0.07, cacheWrite: 0, }, - contextWindow: 256000, + contextWindow: 262144, maxTokens: 4096, } satisfies Model<"openai-completions">, "moonshotai/kimi-k2.6": { @@ -1897,9 +1897,9 @@ export const OPENROUTER_MODELS = { reasoning: true, input: ["text", "image"], cost: { - input: 0.72, + input: 0.719, output: 3.49, - cacheRead: 0.159, + cacheRead: 0.149, cacheWrite: 0, }, contextWindow: 262144, @@ -2457,11 +2457,11 @@ export const OPENROUTER_MODELS = { cost: { input: 0.05, output: 0.4, - cacheRead: 0.01, + cacheRead: 0.005, cacheWrite: 0, }, contextWindow: 400000, - maxTokens: 4096, + maxTokens: 128000, } satisfies Model<"openai-completions">, "openai/gpt-5-pro": { id: "openai/gpt-5-pro", @@ -2493,7 +2493,7 @@ export const OPENROUTER_MODELS = { cost: { input: 1.25, output: 10, - cacheRead: 0.13, + cacheRead: 0.125, cacheWrite: 0, }, contextWindow: 400000, @@ -2977,26 +2977,8 @@ export const OPENROUTER_MODELS = { reasoning: true, input: ["text"], cost: { - input: 0.036, - output: 0.18, - cacheRead: 0, - cacheWrite: 0, - }, - contextWindow: 131072, - maxTokens: 4096, - } satisfies Model<"openai-completions">, - "openai/gpt-oss-120b:free": { - id: "openai/gpt-oss-120b:free", - name: "OpenAI: gpt-oss-120b (free)", - api: "openai-completions", - provider: "openrouter", - baseUrl: "https://openrouter.ai/api/v1", - compat: {"thinkingFormat":"openrouter"}, - reasoning: true, - input: ["text"], - cost: { - input: 0, - output: 0, + input: 0.03, + output: 0.15, cacheRead: 0, cacheWrite: 0, }, @@ -3482,7 +3464,7 @@ export const OPENROUTER_MODELS = { input: ["text"], cost: { input: 0.09, - output: 0.1, + output: 0.55, cacheRead: 0, cacheWrite: 0, }, @@ -4075,13 +4057,13 @@ export const OPENROUTER_MODELS = { reasoning: true, input: ["text", "image"], cost: { - input: 0.285, + input: 0.289, output: 2.4, - cacheRead: 0.15, + cacheRead: 0, cacheWrite: 0, }, - contextWindow: 262140, - maxTokens: 262140, + contextWindow: 131072, + maxTokens: 131072, } satisfies Model<"openai-completions">, "qwen/qwen3.6-35b-a3b": { id: "qwen/qwen3.6-35b-a3b", @@ -4476,7 +4458,7 @@ export const OPENROUTER_MODELS = { cacheRead: 0.028, cacheWrite: 0, }, - contextWindow: 32000, + contextWindow: 262144, maxTokens: 4096, } satisfies Model<"openai-completions">, "xiaomi/mimo-v2.5-pro": { @@ -4562,12 +4544,12 @@ export const OPENROUTER_MODELS = { input: ["text"], cost: { input: 0.43, - output: 1.74, + output: 1.75, cacheRead: 0.08, cacheWrite: 0, }, - contextWindow: 202752, - maxTokens: 131072, + contextWindow: 198000, + maxTokens: 16384, } satisfies Model<"openai-completions">, "z-ai/glm-4.6v": { id: "z-ai/glm-4.6v", @@ -4638,8 +4620,8 @@ export const OPENROUTER_MODELS = { cacheRead: 0.119, cacheWrite: 0, }, - contextWindow: 202752, - maxTokens: 4096, + contextWindow: 198000, + maxTokens: 128000, } satisfies Model<"openai-completions">, "z-ai/glm-5-turbo": { id: "z-ai/glm-5-turbo", @@ -4688,9 +4670,9 @@ export const OPENROUTER_MODELS = { thinkingLevelMap: {"xhigh":"xhigh"}, input: ["text"], cost: { - input: 0.84, - output: 2.64, - cacheRead: 0.156, + input: 0.924, + output: 2.904, + cacheRead: 0.1716, cacheWrite: 0, }, contextWindow: 1024000, diff --git a/packages/ai/test/openai-codex-stream.test.ts b/packages/ai/test/openai-codex-stream.test.ts index fc47572a..793ccc20 100644 --- a/packages/ai/test/openai-codex-stream.test.ts +++ b/packages/ai/test/openai-codex-stream.test.ts @@ -640,6 +640,54 @@ describe("openai-codex streaming", () => { expect(capturedPayload?.prompt_cache_key).toBe("x".repeat(64)); }); + it("clamps Codex session-id header to 64 characters", async () => { + const token = mockToken(); + const sessionId = "x".repeat(67); + let capturedHeaders: Headers | undefined; + const encoder = new TextEncoder(); + vi.stubGlobal( + "fetch", + vi.fn(async (_input: string | URL, init?: RequestInit) => { + capturedHeaders = init?.headers instanceof Headers ? init.headers : undefined; + return new Response( + new ReadableStream({ + start(controller) { + controller.enqueue(encoder.encode(buildSSEPayload({ status: "completed" }))); + controller.close(); + }, + }), + { status: 200, headers: { "content-type": "text/event-stream" } }, + ); + }), + ); + + const model: Model<"openai-codex-responses"> = { + id: "gpt-5.1-codex", + name: "GPT-5.1 Codex", + api: "openai-codex-responses", + provider: "openai-codex", + baseUrl: "https://chatgpt.com/backend-api", + reasoning: true, + input: ["text"], + cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + contextWindow: 400000, + maxTokens: 128000, + }; + const context: Context = { + systemPrompt: "You are a helpful assistant.", + messages: [{ role: "user", content: "Say hello", timestamp: Date.now() }], + }; + + await streamOpenAICodexResponses(model, context, { + apiKey: token, + transport: "sse", + sessionId, + }).result(); + + expect(capturedHeaders?.get("session-id")).toBe("x".repeat(64)); + expect(capturedHeaders?.get("x-client-request-id")).toBe("x".repeat(64)); + }); + it("preserves gpt-5.5 xhigh reasoning effort from simple options", async () => { const tempDir = mkdtempSync(join(tmpdir(), "pi-codex-stream-")); process.env.PI_CODING_AGENT_DIR = tempDir; diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index b4f5dcf4..584d82e3 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -9,22 +9,13 @@ - Replaced SDK request-auth assembly through `ModelRegistry.getApiKeyAndHeaders()` with `ModelRuntime.getAuth()`. Passing a provider ID returns provider-scoped auth; passing a model also resolves built-in, `models.json`, and extension model headers. - Changed extension-facing `ModelRegistry.refresh()` from synchronous `void` to `Promise` because `models.json` loading is asynchronous. Extensions must await it before making synchronous registry reads. - Moved canonical dynamic catalog refresh to async `ModelRuntime.refresh()`/pi-ai `Models.refresh()`. Legacy extension OAuth `modifyModels` remains supported as a synchronous compatibility projection after credential initialization. -- Removed the `openai-responses` `compat.sendSessionIdHeader` flag from `models.json`. Session-affinity behavior is now controlled by `compat.sessionAffinityFormat` (`"openai"`, `"openai-nosession"`, or `"openrouter"`). Replace `sendSessionIdHeader: false` with `sessionAffinityFormat: "openai-nosession"` ([#6366](https://github.com/earendil-works/pi/issues/6366)). - -### New Features - -- **Cache-friendly dynamic tool loading** - Extensions can add tools during execution while supported Anthropic and OpenAI Responses models preserve prompt-cache prefixes. See [Dynamic Tool Loading](docs/extensions.md#dynamic-tool-loading). -- **Message copy shortcut** - `Ctrl+X` copies the last assistant message in the transcript or the selected message in `/tree`, making older and branched messages directly copyable. See [Display and Message Queue](docs/keybindings.md#display-and-message-queue). -- **Fable 5 `xhigh` and `max` thinking** - Native `xhigh` and `max` thinking levels are available across generated provider catalogs. See [Model Options](docs/usage.md#model-options). ### Added - Added `ModelRuntime` as the canonical async SDK and internal model/auth facade while preserving the synchronous extension-facing `ModelRegistry` API. `ModelRuntime.create()` accepts any pi-ai `CredentialStore` through its `credentials` option. - Added provider-owned `/login` discovery directly from registered pi-ai providers, including ambient auth status and informational links. - Added file-backed dynamic catalogs in `models-store.json`, per-provider pi.dev catalog overlays, and Radius gateway support including offline migration from legacy credential-cached catalogs. -- Added cache-friendly dynamic tool loading for extension tools activated by tool results. Supported Anthropic and OpenAI Responses models load definitions where they become available, preserving the cached prompt prefix. See [Dynamic Tool Loading](docs/extensions.md#dynamic-tool-loading) ([#6474](https://github.com/earendil-works/pi-mono/pull/6474)). -- Added inherited native `xhigh` and `max` thinking levels for Claude Fable 5 across all generated provider catalogs ([#6490](https://github.com/earendil-works/pi-mono/pull/6490) by [@davidbrai](https://github.com/davidbrai)). -- Added `Ctrl+X` to copy the last assistant message, or the selected message in `/tree`. +- Added extension provider `refreshModels(context)` support for dynamic model discovery with optional provider-controlled persistence. ### Changed @@ -35,11 +26,44 @@ ### Fixed - Fixed configured-provider catalog refresh to parse pi.dev's model-ID keyed responses, throttle checks to once per four hours, send the versioned pi user agent, treat unimplemented routes as unavailable overlays, and show concise refresh status in `/model`. +- Fixed adjacent assistant thinking blocks to render as one thinking section. + +## [0.80.7] - 2026-07-14 + +### Breaking Changes + +- Removed the `openai-responses` `compat.sendSessionIdHeader` flag from `models.json`. Session-affinity behavior is now controlled by `compat.sessionAffinityFormat` (`"openai"`, `"openai-nosession"`, or `"openrouter"`). Replace `sendSessionIdHeader: false` with `sessionAffinityFormat: "openai-nosession"` ([#6496](https://github.com/earendil-works/pi-mono/pull/6496) by [@petrroll](https://github.com/petrroll)). + +### New Features + +- **Cache-friendly dynamic tool loading** - Extensions can add tools during execution while supported Anthropic and OpenAI Responses models preserve prompt-cache prefixes. See [Dynamic Tool Loading](docs/extensions.md#dynamic-tool-loading). +- **Message copy shortcut** - `Ctrl+X` copies the last assistant message in the transcript or the selected message in `/tree`, making older and branched messages directly copyable. See [Display and Message Queue](docs/keybindings.md#display-and-message-queue). +- **Fable 5 `xhigh` and `max` thinking** - Native `xhigh` and `max` thinking levels are available across generated provider catalogs. See [Model Options](docs/usage.md#model-options). + +### Added + +- Added cache-friendly dynamic tool loading for extension tools activated by tool results. Supported Anthropic and OpenAI Responses models load definitions where they become available, preserving the cached prompt prefix. See [Dynamic Tool Loading](docs/extensions.md#dynamic-tool-loading) ([#6474](https://github.com/earendil-works/pi-mono/pull/6474)). +- Added inherited native `xhigh` and `max` thinking levels for Claude Fable 5 across all generated provider catalogs ([#6490](https://github.com/earendil-works/pi-mono/pull/6490) by [@davidbrai](https://github.com/davidbrai)). +- Added `Ctrl+X` to copy the last assistant message, or the selected message in `/tree`. +- Added inherited `toolChoice` support for OpenAI and Codex Responses, including required and named tool selection ([#6588](https://github.com/earendil-works/pi-mono/pull/6588) by [@xl0](https://github.com/xl0)). + +### Fixed + - Fixed inherited OpenRouter model context windows to use the top provider's actual context length ([#6481](https://github.com/earendil-works/pi-mono/pull/6481) by [@davidbrai](https://github.com/davidbrai)). -- Fixed inherited OpenRouter OpenAI-compatible session IDs to use the `x-session-id` header instead of OpenAI-specific session-affinity fields ([#6366](https://github.com/earendil-works/pi/issues/6366)). +- Fixed inherited OpenRouter OpenAI-compatible session IDs to use the `x-session-id` header instead of OpenAI-specific session-affinity fields ([#6496](https://github.com/earendil-works/pi-mono/pull/6496) by [@petrroll](https://github.com/petrroll)). - Fixed `Ctrl+V` to paste clipboard text when the pasteboard does not contain an image. - Fixed `/login amazon-bedrock` to prompt for and save a Bedrock API key instead of only displaying ambient AWS credential setup instructions. -- Fixed adjacent assistant thinking blocks to render as one thinking section. +- Fixed inherited Amazon Bedrock ambient AWS credentials to keep using SigV4 authentication, including for custom model IDs ([#6532](https://github.com/earendil-works/pi-mono/pull/6532) by [@ribelo](https://github.com/ribelo)). +- Fixed inherited Cloudflare Workers AI and AI Gateway authentication to use ambient account and gateway IDs when stored credentials contain only an API key ([#6292](https://github.com/earendil-works/pi-mono/pull/6292) by [@markphelps](https://github.com/markphelps)). +- Fixed inherited legacy terminal decoding for Alt+symbol key combinations such as `Alt+,` and `Alt+.` ([#6523](https://github.com/earendil-works/pi-mono/pull/6523) by [@ribelo](https://github.com/ribelo)). +- Fixed the GitHub Copilot `mai-code-1-flash-picker` model to route through the `/responses` endpoint ([#6544](https://github.com/earendil-works/pi-mono/pull/6544) by [@petrroll](https://github.com/petrroll)). +- Fixed branch summaries to work with providers that use ambient authentication instead of API keys ([#6595](https://github.com/earendil-works/pi-mono/pull/6595) by [@davidbrai](https://github.com/davidbrai)). +- Fixed inherited Amazon Bedrock errors to report unhandled provider stop reasons instead of only `An unknown error occurred` ([#6598](https://github.com/earendil-works/pi-mono/pull/6598) by [@davidbrai](https://github.com/davidbrai)). +- Fixed npm package removal when installed packages have conflicting peer dependencies ([#6604](https://github.com/earendil-works/pi-mono/pull/6604) by [@davidbrai](https://github.com/davidbrai)). +- Fixed inherited Azure OpenAI Responses reasoning replay when `encrypted_content` appears only in the terminal response event ([#6608](https://github.com/earendil-works/pi-mono/pull/6608) by [@davidbrai](https://github.com/davidbrai)). +- Fixed inherited Anthropic-compatible proxies that omit `usage` from `message_delta` events ([#6611](https://github.com/earendil-works/pi-mono/pull/6611) by [@davidbrai](https://github.com/davidbrai)). +- Fixed inherited OpenCode OpenAI Responses models to omit the unsupported `session-id` header while preserving other cache-affinity data ([#6645](https://github.com/earendil-works/pi-mono/pull/6645) by [@davidbrai](https://github.com/davidbrai)). +- Fixed system prompt cache invalidation across dates by removing the current date from the default prompt ([#6621](https://github.com/earendil-works/pi/issues/6621)). ## [0.80.6] - 2026-07-09 diff --git a/packages/coding-agent/examples/extensions/custom-provider-anthropic/package-lock.json b/packages/coding-agent/examples/extensions/custom-provider-anthropic/package-lock.json index 7c01a92d..efc92273 100644 --- a/packages/coding-agent/examples/extensions/custom-provider-anthropic/package-lock.json +++ b/packages/coding-agent/examples/extensions/custom-provider-anthropic/package-lock.json @@ -1,12 +1,12 @@ { "name": "pi-extension-custom-provider", - "version": "0.80.6", + "version": "0.80.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pi-extension-custom-provider", - "version": "0.80.6", + "version": "0.80.7", "dependencies": { "@anthropic-ai/sdk": "^0.52.0" } diff --git a/packages/coding-agent/examples/extensions/custom-provider-anthropic/package.json b/packages/coding-agent/examples/extensions/custom-provider-anthropic/package.json index 7e6c7873..14ad1405 100644 --- a/packages/coding-agent/examples/extensions/custom-provider-anthropic/package.json +++ b/packages/coding-agent/examples/extensions/custom-provider-anthropic/package.json @@ -1,7 +1,7 @@ { "name": "pi-extension-custom-provider-anthropic", "private": true, - "version": "0.80.6", + "version": "0.80.7", "type": "module", "scripts": { "clean": "echo 'nothing to clean'", diff --git a/packages/coding-agent/examples/extensions/custom-provider-gitlab-duo/package.json b/packages/coding-agent/examples/extensions/custom-provider-gitlab-duo/package.json index 8d62dd7f..42101f1e 100644 --- a/packages/coding-agent/examples/extensions/custom-provider-gitlab-duo/package.json +++ b/packages/coding-agent/examples/extensions/custom-provider-gitlab-duo/package.json @@ -1,7 +1,7 @@ { "name": "pi-extension-custom-provider-gitlab-duo", "private": true, - "version": "0.80.6", + "version": "0.80.7", "type": "module", "scripts": { "clean": "echo 'nothing to clean'", diff --git a/packages/coding-agent/examples/extensions/gondolin/package-lock.json b/packages/coding-agent/examples/extensions/gondolin/package-lock.json index 454fa63d..dac0d6e9 100644 --- a/packages/coding-agent/examples/extensions/gondolin/package-lock.json +++ b/packages/coding-agent/examples/extensions/gondolin/package-lock.json @@ -1,12 +1,12 @@ { "name": "pi-extension-gondolin", - "version": "0.80.6", + "version": "0.80.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pi-extension-gondolin", - "version": "0.80.6", + "version": "0.80.7", "dependencies": { "@earendil-works/gondolin": "0.12.0" } diff --git a/packages/coding-agent/examples/extensions/gondolin/package.json b/packages/coding-agent/examples/extensions/gondolin/package.json index fe329ba6..c54e563e 100644 --- a/packages/coding-agent/examples/extensions/gondolin/package.json +++ b/packages/coding-agent/examples/extensions/gondolin/package.json @@ -1,7 +1,7 @@ { "name": "pi-extension-gondolin", "private": true, - "version": "0.80.6", + "version": "0.80.7", "type": "module", "scripts": { "clean": "echo 'nothing to clean'", diff --git a/packages/coding-agent/examples/extensions/sandbox/package-lock.json b/packages/coding-agent/examples/extensions/sandbox/package-lock.json index e0c46cdd..f35689c6 100644 --- a/packages/coding-agent/examples/extensions/sandbox/package-lock.json +++ b/packages/coding-agent/examples/extensions/sandbox/package-lock.json @@ -1,12 +1,12 @@ { "name": "pi-extension-sandbox", - "version": "1.10.6", + "version": "1.10.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pi-extension-sandbox", - "version": "1.10.6", + "version": "1.10.7", "dependencies": { "@anthropic-ai/sandbox-runtime": "^0.0.26" } diff --git a/packages/coding-agent/examples/extensions/sandbox/package.json b/packages/coding-agent/examples/extensions/sandbox/package.json index 4402a001..4ffb2caf 100644 --- a/packages/coding-agent/examples/extensions/sandbox/package.json +++ b/packages/coding-agent/examples/extensions/sandbox/package.json @@ -1,7 +1,7 @@ { "name": "pi-extension-sandbox", "private": true, - "version": "1.10.6", + "version": "1.10.7", "type": "module", "scripts": { "clean": "echo 'nothing to clean'", diff --git a/packages/coding-agent/examples/extensions/with-deps/package-lock.json b/packages/coding-agent/examples/extensions/with-deps/package-lock.json index 54eaccd3..3599384e 100644 --- a/packages/coding-agent/examples/extensions/with-deps/package-lock.json +++ b/packages/coding-agent/examples/extensions/with-deps/package-lock.json @@ -1,12 +1,12 @@ { "name": "pi-extension-with-deps", - "version": "0.80.6", + "version": "0.80.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pi-extension-with-deps", - "version": "0.80.6", + "version": "0.80.7", "dependencies": { "ms": "^2.1.3" }, diff --git a/packages/coding-agent/examples/extensions/with-deps/package.json b/packages/coding-agent/examples/extensions/with-deps/package.json index 87bb49f3..fb40ffe1 100644 --- a/packages/coding-agent/examples/extensions/with-deps/package.json +++ b/packages/coding-agent/examples/extensions/with-deps/package.json @@ -1,7 +1,7 @@ { "name": "pi-extension-with-deps", "private": true, - "version": "0.80.6", + "version": "0.80.7", "type": "module", "scripts": { "clean": "echo 'nothing to clean'", diff --git a/packages/coding-agent/install-lock/package-lock.json b/packages/coding-agent/install-lock/package-lock.json index 4ddf19bb..7cc30d87 100644 --- a/packages/coding-agent/install-lock/package-lock.json +++ b/packages/coding-agent/install-lock/package-lock.json @@ -1,14 +1,14 @@ { "name": "@earendil-works/pi-coding-agent-install", - "version": "0.80.6", + "version": "0.80.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@earendil-works/pi-coding-agent-install", - "version": "0.80.6", + "version": "0.80.7", "dependencies": { - "@earendil-works/pi-coding-agent": "0.80.6" + "@earendil-works/pi-coding-agent": "0.80.7" }, "engines": { "node": ">=22.19.0" @@ -450,11 +450,11 @@ } }, "node_modules/@earendil-works/pi-agent-core": { - "version": "0.80.6", - "resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.80.6.tgz", + "version": "0.80.7", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.80.7.tgz", "license": "MIT", "dependencies": { - "@earendil-works/pi-ai": "^0.80.6", + "@earendil-works/pi-ai": "^0.80.7", "ignore": "7.0.5", "typebox": "1.1.38", "yaml": "2.9.0" @@ -464,8 +464,8 @@ } }, "node_modules/@earendil-works/pi-ai": { - "version": "0.80.6", - "resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.80.6.tgz", + "version": "0.80.7", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.80.7.tgz", "license": "MIT", "dependencies": { "@anthropic-ai/sdk": "0.91.1", @@ -488,13 +488,13 @@ } }, "node_modules/@earendil-works/pi-coding-agent": { - "version": "0.80.6", - "resolved": "https://registry.npmjs.org/@earendil-works/pi-coding-agent/-/pi-coding-agent-0.80.6.tgz", + "version": "0.80.7", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-coding-agent/-/pi-coding-agent-0.80.7.tgz", "license": "MIT", "dependencies": { - "@earendil-works/pi-agent-core": "^0.80.6", - "@earendil-works/pi-ai": "^0.80.6", - "@earendil-works/pi-tui": "^0.80.6", + "@earendil-works/pi-agent-core": "^0.80.7", + "@earendil-works/pi-ai": "^0.80.7", + "@earendil-works/pi-tui": "^0.80.7", "@silvia-odwyer/photon-node": "0.3.4", "chalk": "5.6.2", "cross-spawn": "7.0.6", @@ -522,8 +522,8 @@ } }, "node_modules/@earendil-works/pi-tui": { - "version": "0.80.6", - "resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.80.6.tgz", + "version": "0.80.7", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.80.7.tgz", "license": "MIT", "dependencies": { "get-east-asian-width": "1.6.0", diff --git a/packages/coding-agent/install-lock/package.json b/packages/coding-agent/install-lock/package.json index ba122ec4..9d749d79 100644 --- a/packages/coding-agent/install-lock/package.json +++ b/packages/coding-agent/install-lock/package.json @@ -1,10 +1,10 @@ { "name": "@earendil-works/pi-coding-agent-install", - "version": "0.80.6", + "version": "0.80.7", "private": true, "description": "Lockfile root used by the Pi installer and updater.", "dependencies": { - "@earendil-works/pi-coding-agent": "0.80.6" + "@earendil-works/pi-coding-agent": "0.80.7" }, "overrides": { "rimraf": "6.1.2", diff --git a/packages/coding-agent/npm-shrinkwrap.json b/packages/coding-agent/npm-shrinkwrap.json index 6674bbbd..bcbab041 100644 --- a/packages/coding-agent/npm-shrinkwrap.json +++ b/packages/coding-agent/npm-shrinkwrap.json @@ -1,17 +1,17 @@ { "name": "@earendil-works/pi-coding-agent", - "version": "0.80.6", + "version": "0.80.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@earendil-works/pi-coding-agent", - "version": "0.80.6", + "version": "0.80.7", "license": "MIT", "dependencies": { - "@earendil-works/pi-agent-core": "^0.80.6", - "@earendil-works/pi-ai": "^0.80.6", - "@earendil-works/pi-tui": "^0.80.6", + "@earendil-works/pi-agent-core": "^0.80.7", + "@earendil-works/pi-ai": "^0.80.7", + "@earendil-works/pi-tui": "^0.80.7", "@silvia-odwyer/photon-node": "0.3.4", "chalk": "5.6.2", "cross-spawn": "7.0.6", @@ -474,11 +474,11 @@ } }, "node_modules/@earendil-works/pi-agent-core": { - "version": "0.80.6", - "resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.80.6.tgz", + "version": "0.80.7", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.80.7.tgz", "license": "MIT", "dependencies": { - "@earendil-works/pi-ai": "^0.80.6", + "@earendil-works/pi-ai": "^0.80.7", "ignore": "7.0.5", "typebox": "1.1.38", "yaml": "2.9.0" @@ -488,8 +488,8 @@ } }, "node_modules/@earendil-works/pi-ai": { - "version": "0.80.6", - "resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.80.6.tgz", + "version": "0.80.7", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.80.7.tgz", "license": "MIT", "dependencies": { "@anthropic-ai/sdk": "0.91.1", @@ -512,8 +512,8 @@ } }, "node_modules/@earendil-works/pi-tui": { - "version": "0.80.6", - "resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.80.6.tgz", + "version": "0.80.7", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.80.7.tgz", "license": "MIT", "dependencies": { "get-east-asian-width": "1.6.0", diff --git a/packages/coding-agent/package.json b/packages/coding-agent/package.json index bce2edab..aed830a9 100644 --- a/packages/coding-agent/package.json +++ b/packages/coding-agent/package.json @@ -1,6 +1,6 @@ { "name": "@earendil-works/pi-coding-agent", - "version": "0.80.6", + "version": "0.80.7", "description": "Coding agent CLI with read, bash, edit, write tools and session management", "type": "module", "piConfig": { @@ -39,9 +39,9 @@ "prepublishOnly": "npm run clean && npm run build && npm run shrinkwrap" }, "dependencies": { - "@earendil-works/pi-agent-core": "^0.80.6", - "@earendil-works/pi-ai": "^0.80.6", - "@earendil-works/pi-tui": "^0.80.6", + "@earendil-works/pi-agent-core": "^0.80.7", + "@earendil-works/pi-ai": "^0.80.7", + "@earendil-works/pi-tui": "^0.80.7", "@silvia-odwyer/photon-node": "0.3.4", "chalk": "5.6.2", "cross-spawn": "7.0.6", diff --git a/packages/orchestrator/CHANGELOG.md b/packages/orchestrator/CHANGELOG.md index f4bcedff..36dbea1f 100644 --- a/packages/orchestrator/CHANGELOG.md +++ b/packages/orchestrator/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased] +## [0.80.7] - 2026-07-14 + ## [0.80.6] - 2026-07-09 ## [0.80.5] - 2026-07-09 diff --git a/packages/orchestrator/package.json b/packages/orchestrator/package.json index 6e9aa1dd..646bcee1 100644 --- a/packages/orchestrator/package.json +++ b/packages/orchestrator/package.json @@ -1,6 +1,6 @@ { "name": "@earendil-works/pi-orchestrator", - "version": "0.80.6", + "version": "0.80.7", "description": "experimental orchestrator package for pi", "type": "module", "main": "./dist/index.js", @@ -37,7 +37,7 @@ "node": ">=22.19.0" }, "dependencies": { - "@earendil-works/pi-coding-agent": "^0.80.6" + "@earendil-works/pi-coding-agent": "^0.80.7" }, "devDependencies": { "shx": "0.4.0" diff --git a/packages/tui/CHANGELOG.md b/packages/tui/CHANGELOG.md index c88cb18b..f2ef581f 100644 --- a/packages/tui/CHANGELOG.md +++ b/packages/tui/CHANGELOG.md @@ -2,6 +2,12 @@ ## [Unreleased] +## [0.80.7] - 2026-07-14 + +### Fixed + +- Fixed legacy terminal decoding for Alt+symbol key combinations such as `Alt+,` and `Alt+.` ([#6523](https://github.com/earendil-works/pi-mono/pull/6523) by [@ribelo](https://github.com/ribelo)). + ## [0.80.6] - 2026-07-09 ## [0.80.5] - 2026-07-09 diff --git a/packages/tui/package.json b/packages/tui/package.json index 27d790aa..87935c04 100644 --- a/packages/tui/package.json +++ b/packages/tui/package.json @@ -1,6 +1,6 @@ { "name": "@earendil-works/pi-tui", - "version": "0.80.6", + "version": "0.80.7", "description": "Terminal User Interface library with differential rendering for efficient text-based applications", "type": "module", "main": "dist/index.js",