Images produced by tools (extensions, MCP bridges, screenshot tools) went into
session history at full resolution because processImage was only wired to the
read tool and @file CLI attachments. Providers validate every image in the
request, so one oversized image poisons the whole conversation: Anthropic drops
its per-image cap from 8000px to 2000px once a request carries many images, and
every later turn re-sends the same payload. Switching models does not help.
Normalize tool result images in AgentSession.afterToolCall, after the extension
tool_result hook so extension-injected images are covered too. Honors
images.autoResize, and keeps the original block when processing fails so an
unavailable image backend does not delete tool output.
Refs #5369
Assisted-By: devx/86bf3b09-9aba-4d03-8154-50fca3ffc9b5
Extensions have no way to read the session's scoped model set (the models
resolved from --models / enabledModels against the available catalogue --
the same list /scoped-models shows). The only model surfaces on
ExtensionContext are ctx.model (active) and ctx.modelRegistry.getAvailable()
(the whole catalogue, unfiltered), so an extension that wants a scoped
model picker must either enumerate everything or re-implement pi's scope
resolution (minimatch on provider/modelId / bare modelId + enabledModels +
--models) from disk -- duplicating core logic.
Add ctx.scopedModels: readonly ScopedModel[] to ExtensionContext, mirroring
how ctx.model is exposed (field -> bindCore -> lazy getter in createContext()).
Empty when no scoping is configured (all available models usable). Each entry
is { model, thinkingLevel? }.
- types.ts: ExtensionContext.scopedModels + ExtensionContextActions.getScopedModels
- runner.ts: field, bindCore wiring, lazy scopedModels getter
- agent-session.ts: provide getScopedModels: () => this._scopedModels
- test: assert ctx.scopedModels reflects the action (default [] + live ref)
- docs/extensions.md: document the new field
Co-authored-by: ngSoftware <alessandro@pungitore.ch>
The OpenRouter PKCE flow only completed through the loopback callback
server, so remote/headless sessions (e.g. pi over SSH) could never
finish login: the browser runs on another machine and cannot reach
127.0.0.1 on the host running pi.
Race the callback server against a manual_code prompt, matching the
existing Anthropic and OpenAI Codex flows. Users can paste the final
redirect URL (or the bare authorization code) and the flow exchanges
it with the same PKCE verifier. A claimed callback keeps priority so
a pasted code cannot interrupt an in-flight exchange.
The callback server object follows the OAuthServerInfo shape from the
OpenAI Codex flow: waitForCredential() resolves null when cancelWait()
hands the login over to manual entry, and close() is pure cleanup that
never settles the wait.
Refs #7078
Add the constrained sampling API and provider plumbing for OpenAI and Anthropic tool calls, including grammar sampling variants and model capability metadata.
Replace OpenAI and Anthropic SDK retries with local request retries that
preserve configured retry counts, enforce maxRetryDelayMs, and make retry
backoff interruptible through AbortSignal.
Alternatives considered: Racing SDK requests against AbortSignal would make
cancellation observable but would not let Pi enforce maxRetryDelayMs before
the SDK enters its retry sleep. Patching private SDK internals would be brittle,
while disabling provider retries entirely would ignore explicitly configured
maxRetries.
Also, align the custom OpenAI Codex retry loop with the documented
maxRetryDelayMs behavior. Oversized server-requested delays now fail immediately
instead of being clamped, allowing the visible, abortable agent-level retry
policy to handle the failure.
Fixes#6911
This PR:
- Adds retainedTail to compaction entries in the new agent harness so we don't have to walk up the tree for the 2000 tokens before compaction,
- Changes getPathToRoot to getPathToRootOrCompaction to only load until last compaction, as unnecessary to access all nodes where it is called,
- Adds a SQLite storage backend, in a separate packages/session-backend-sqlite, with a migration system and schemas as per on-site discussions: sessions to match session header messages (except for metadata, which I couldn't understand what it's used for or where it gets written, so I omitted it), session_entries for shared entry types as columns plus payload as a json for what remains, session_sequences to represent the append-only, serialized nature of the jsonl files, branch_entries to attribute nodes to branches (relationship one-to-many), and session_materialized with the session info (see /session in TUI) to act as a "cache" or quick-access for costs, message count, token info, labels, session name, and model-thinking-level config (e.g. for fast resume).
- This is compatible with the new agent harness Session abstraction.
Add Alibaba Cloud Model Studio Token Plan subscription service as two
built-in API-key providers: qwen-token-plan (international, Singapore)
and qwen-token-plan-cn (China, Beijing).
Each provider exposes 15 text-generation models (Qwen, DeepSeek, GLM,
Kimi, MiniMax) via the OpenAI-compatible endpoint with DashScope
enable_thinking support. Model metadata is sourced from models.dev;
qwen3.8-max-preview is hardcoded until models.dev includes it.
Also fixes kimi-coding test references (k2p7 -> kimi-for-coding) after
models.dev catalog update picked up by generate-models.
Closes#6850