Merge origin/main into model runtime changes

This commit is contained in:
Mario Zechner
2026-07-15 13:00:45 +02:00
26 changed files with 244 additions and 163 deletions
+15 -15
View File
@@ -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",
+2
View File
@@ -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)).
+2 -2
View File
@@ -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"
+23 -7
View File
@@ -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
+1 -1
View File
@@ -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",
@@ -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,
+57 -75
View File
@@ -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,
@@ -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<Uint8Array>({
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;
+36 -12
View File
@@ -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<void>` 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
@@ -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"
}
@@ -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'",
@@ -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'",
@@ -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"
}
@@ -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'",
@@ -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"
}
@@ -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'",
@@ -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"
},
@@ -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'",
+15 -15
View File
@@ -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",
@@ -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",
+12 -12
View File
@@ -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",
+4 -4
View File
@@ -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",
+2
View File
@@ -2,6 +2,8 @@
## [Unreleased]
## [0.80.7] - 2026-07-14
## [0.80.6] - 2026-07-09
## [0.80.5] - 2026-07-09
+2 -2
View File
@@ -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"
+6
View File
@@ -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
+1 -1
View File
@@ -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",