@oh-my-pi/pi-ai
Fixed
- Fixed Ollama/llama.cpp chat payloads serializing user-attributed mid-conversation developer messages (auto-learn capture nudge, advisor cards, file-mention companions) as
systemturns; they now serialize asuserso llama.cpp can reuse the warm prompt prefix instead of forcing full re-processing. Agent-owned developer reminders (attribution: "agent"— empty/unexpected-stop retries, checkpoint rewind warning, todo reminders) keep theirsystempriority. (#3456) - Fixed prior-turn reasoning being lost on cross-API provider switches: when a session moved from an Anthropic-compatible 3p endpoint to an OpenAI-compatible one (Z.AI Anthropic → Z.AI OpenAI, Kimi Anthropic → Kimi OpenAI, DeepSeek, OpenCode-hosted reasoning models, or any custom
models.yamlswitch that crosses API types), the cross-API path oftransformMessagestext-demoted every priorthinkingblock, so the next request shipped the reasoning chain as plain conversationcontentinstead of structuredreasoning_content— losing it as reasoning context and re-billing it.convertMessagesnow threads the request-time resolved compat intotransformMessages, which preserves the prior reasoning as a native, signature-strippedthinkingblock whenever that resolved target acceptsreasoning_contentas a continuation hint (requiresReasoningContentForToolCalls— including thewhenThinkingpolicy OpenCode reactivates for thinking-on requests, #1071/#1484 — orthinkingFormat: "zai"); theopenai-completionsencoder surfaces those blocks viareasoningContentField, with a new branch for Z.AI-format hosts (Z.AI, Zhipu, Moonshot Kimi, Xiaomi MiMo) that accept but don't require the field. Targets that can't replay unsigned reasoning (encrypted reasoning blobs, signed thought parts, non-reasoning models, thinking-disabled OpenCode) still text-demote so the reasoning survives as conversation context. (#3437, #3439 by @roboomp; #3433, #3434) - Fixed Bedrock cross-region inference profiles routing to
us-east-1regardless of their geo prefix: a profile such aseu.anthropic.claude-…(orapac./au./jp.) sent to the hardcodedus-east-1endpoint returned HTTP 400The provided model identifier is invalid.streamBedrocknow derives the runtime region from the profile's geo prefix — honoring an ambientAWS_REGION/AWS_DEFAULT_REGIONonly when it can serve that geo and falling back to the geo's default region otherwise — while explicit per-request and ARN-embedded regions still win and region-agnosticglobal.profiles stay unchanged. - Fixed malformed tool calls (empty
name) wedging entire sessions in HTTP 400 loops: when a model occasionally emits{ "name": "", "arguments": "{}" }(observed: GLM-5.2 + thinking on long turns), the agent rejected the call at execution time withTool not found, but the malformed block plus its errortoolResultstayed in conversation history and every subsequent request 400'd ontool_use.name/tool_calls[i].function.namevalidation until the user ran/clear.transformMessages— the canonical sanitize boundary every provider passes through — now dropstoolCallblocks with empty/whitespacename, pairs them with theirtoolResultmessages only inside the same assistant→tool-result window (per-id FIFO queue cleared at non-result boundaries, so stale malformed calls without a result cannot consume later valid duplicate-id outputs), and drops the assistant turn when it has no replayable content left. Defensive (provider-agnostic, fires regardless of model), idempotent (no-op on a clean history), and self-healing (one round-trip after the fix lands sanitizes an already-poisoned session). (#3458)
@oh-my-pi/pi-coding-agent
Fixed
- Fixed
omp install <plugin>failing extension validation in compiled-binary mode withCannot find module '@(scope)/pi-ai/oauth' from '<plugin>/src/oauth.ts'(and any other non-wildcard pi-* subpath import like@oh-my-pi/pi-coding-agent/tools). The bundled-registry override map seeded by__buildLegacyPiPackageRootOverridesonly covered the bare package roots, sorewriteLegacyPiImportsrewrote@(scope)/pi-ai/oauthto@oh-my-pi/pi-ai/oauth, fell through toBun.resolveSync(which bunfs can't satisfy on Bun 1.3.14+), then left the original specifier alone — at which point Bun's native resolver failed because most plugins declare@(scope)/pi-aias apeerDependencyonly and never materialize a real install. The newscripts/generate-legacy-pi-bundled-registry.tsreads every bundled pi-* package's non-wildcardexportsfield and emits both the heavylegacy-pi-bundled-registry.ts(static imports + map) and a lightlegacy-pi-bundled-keys.ts(statically imported bylegacy-pi-compat.tsto seed the override map without the cascade throughlegacy-pi-coding-agent-shim → ../index → export/html/...).scripts/build-binary.tsnow runs the generator beforebun build --compile. (#3442) - Fixed
skill://tool resolution losing loaded session skills when a tool runs outside the session-initialization module state. Internal URL resolution now prefers the caller'ssession.skillssnapshot before falling back to the process-global skill list, soread skill://<name>works across tool execution boundaries. (#3436) - Fixed
@imagementions on OpenAI Codex Responses (chatgpt.comgpt-5.5and siblings) failing withCodex error event: [OneOfParam] [input[N].content[…]] [invalid_enum_value] Invalid value: 'input_image'. Supported values are: 'input_text'..convertToLlmforfileMentionalways emitted adeveloper-role message, so the auto-attached image landed in a Responses content array that the Codex backend (and OpenAI Responses generally) only allows to carryinput_text. #3421's previous fix only stopped the Codex Responses Lite header from going out on image-bearing turns; the full transport kept rejecting the same payload.convertToLlmnow splits a mixed-contentfileMentioninto two messages — text-only files stay ondeveloper(so the auto-read context keeps instruction priority), while image-bearing files ride onuser(the only Responses content slot that acceptsinput_image). (#3443) - Fixed
local://binary attachments being decoded withBun.file().text()before read-tool file safeguards could reject or stream them.read local://...now routes file-backed resources through the normal filesystem reader, the protocol handler refuses known binary/container resources without materializing their bytes, and the streaming reader's NUL-byte refusal now also covers binary blobs whose first newline lies beyond the byte budget (videos, archives) — those previously bypassed the per-line scan and surfaced as decoded mojibake. (#3448)
@oh-my-pi/pi-tui
Fixed
- Fixed bordered
Editorrendering 1–2 cells past the terminal width when the end-of-line cursor glyph landed past a wide trailing grapheme (CJK comma,, emoji, etc.), wrapping the bottom-right corner (╯) to its own row. The right chrome (padding +─+ corner) now shrinks by the exact cursor overflow cell count instead of a 1-cell boolean, so the box stays insidewidthfor anypaddingX(#3431).
What's Changed
- fix(ai): preserve cross-api reasoning replay by @roboomp in #3437
- fix(ai): preserve 3p thinking blocks across cross-API switches by @roboomp in #3439
- fix(tui): shrink bordered Editor right chrome by cursor overflow cells by @roboomp in #3432
- fix(agent): preserve skill URL session context by @roboomp in #3438
- fix(coding-agent): route image-bearing @ mentions as user-role messages by @roboomp in #3445
- fix(plugins): route bundled pi-* subpath imports through the virtual registry by @roboomp in #3446
- fix(coding-agent): refuse local binary attachment text reads by @roboomp in #3450
- fix(ai): preserve Ollama cache for capture turns by @roboomp in #3457
- fix(ai): drop malformed (empty-name) tool calls in transformMessages by @roboomp in #3459
Full Changelog: v16.1.18...v16.1.19