- Enabled recursive parsing in `tryParseJsonForTypes` to coerce double-encoded JSON strings.
- Updated `coerceArgsFromIssues` to parse object/array JSON strings before singleton-array fallback.
- Prevented malformed container strings from being wrapped into arrays so validation returns array errors directly.
- Added ZAI GLM-5.2 reasoning-effort mapping, translating minimal to none and xhigh to max.
- Enabled ZAI and zhipu GLM-5.2 completion requests to send reasoning_effort and tool_stream.
- Added provider token clamping so GLM-5.2 completion requests use capped max_tokens.
- Updated catalog policies to route GLM-5.2 max-token and reasoning support through ZAI/zhipu hosts.
- Removed synthetic HF model entries and aligned GLM-5.2 catalog specs with real providers.
Fixes#2833
Stopped google-gemini-cli and google-antigravity requests from sending explicit AUTO toolConfig entries for toolChoice auto, matching the shared Google provider behavior.
Added regression coverage for both Gemini CLI provider identities.
Fixes#2830
- Replaced `process.chdir(tempDir)` plus `PI_REQ_DEBUG=1` auto-naming with explicit `setNextRequestDebugPath` targets, removing the `previousCwd` save/restore and the `debugFiles` directory-scan helper.
- The PI_REQ_DEBUG recording assertions now read each request/response from the path they set, so the test no longer mutates `process.cwd()` or the global debug env flag.
Rewrote unsupported lookaround patternProperties keys to a supported catch-all pattern instead of dropping their value schemas, preserving dynamic-key tool arguments when additionalProperties is false.
Extended sanitizer and Codex conversion regression coverage for the closed dynamic-key case.
Fixes#2784
- Added LaTeX math and Mermaid allowances in terminal and final-chat prompts.
- Added inline math tokenization in TUI for $, $$, \(\), and \[\].
- Added LaTeX-to-Unicode conversion helpers and exports for math rendering.
- Fixed inline math detection to skip escaped dollars and currency-like spans.
- Tracked whether a Responses stream event carries an identifier (`output_index` or `item_id`) in `processResponsesStream` and dropped keyed argument deltas whose item already closed instead of routing them to another open call.
- Restricted the `lastOpenItem` singleton fallback to fully identifierless mock/proxy events so real parallel tool calls keep their own argument streams.
- Added a regression test asserting stale keyed deltas after item close are dropped rather than appended to a sibling call.
- Recorded the fix in the ai changelog.
- Re-exported `renderDelimitedThinking` from `./dialect/rendering` through the `@oh-my-pi/pi-ai/dialect` barrel, keeping the remaining `rendering` primitives dialect-internal.
- Documented in `dialect/index.ts` why only this one `rendering` symbol is re-exported (the legacy markdown `/dump` reuses its `<thinking>` envelope unwrap).
- Added the `### Added` changelog entry recording the new export.
Converted schema nodes emptied by OpenAI Responses lookaround stripping to boolean true so pattern-only nodes keep the existing empty-schema semantics.
Extended sanitizer and Codex regression coverage for pattern-only property and propertyNames schemas.
Fixes#2784
Removed JSON Schema pattern values containing regex lookaround from OpenAI Responses/Codex tool schemas so incompatible MCP tools do not poison the request.
Added schema-normalization and Codex conversion regression coverage for Figma-style fileKey patterns.
Fixes#2784
Recognized the empty Ollama finish_reason:length guidance as context overflow so coding-agent promotion and compaction recovery still run after surfacing the actionable error.
Added overflow utility coverage for the Ollama prompt-filled-context wording.
Stopped serializing explicit AUTO toolConfig for Google Gemini toolChoice auto so Gemini defaults apply without triggering upstream planning JSON leaks.\n\nAdded a regression test for auto toolChoice while preserving explicit ANY and named-tool routing.\n\nFixes #2776
Scoped empty finish_reason:length error conversion to Ollama so other OpenAI-compatible providers keep the length stop used by coding-agent incomplete-output recovery.
Added regression coverage for empty non-Ollama length completions.
Mapped empty Ollama OpenAI-compatible finish_reason:length completions to a provider error with actionable num_ctx guidance instead of a silent length stop.
Added regression coverage for the empty length stream path and recorded the package-local checks.
Fixes#2774
Preserve signed thinking bytes when unwrapping Anthropic thinking envelopes. Residual over the already-landed core (commit 7936ea2ac3) that fixes a still-live signed-whitespace P1 in main (issue #2695).
Unwrap literal <thinking> envelopes in the render-layer raw dumps (issue #2700). Includes review test 222562ecb2 (render-layer regression coverage). Orthogonal to #2698 (provider-source layer).
Route prefixed Responses tool-call deltas by call_id alias (issue #2715). Includes review fix f6ab97843c: fall through to the prefixed alias when a delta's output_index was never registered (llama.cpp/Ollama streams).
Adds render-layer regression coverage in packages/ai, where the #2702 fix lives. Asserts the anthropic dialect unwraps a single literal <thinking> envelope (no nesting), unwraps sibling envelopes independently (no malformed close/open boundary), and that a <thinking> envelope is not mistaken for the qwen3 <think> delimiter (prefix safety). The PR's existing test lives only in packages/coding-agent and cannot exercise the fix under the shared workspace node_modules symlink.
Addresses review feedback on #2702.
Spec-shaped Responses argument deltas always carry output_index, but llama.cpp/Ollama omit it on output_item.added (issue #2015), so the index is never registered. The early return trusted the stale index and dropped to lastOpenItem before consulting the prefixed fc_<call_id> alias map, folding every parallel delta into the most-recently-added call and leaving earlier ast_grep calls with {}. Try the output-index map first, then fall through to the alias/exact lookup. Adds a regression test for the unregistered-index shape.
Addresses review feedback on #2719.
Tracked whether Anthropic thinking-envelope normalization actually stripped a wrapper before mutating thinking bytes or clearing signatures.
Added coverage for signed thinking with surrounding whitespace to preserve byte-for-byte replay.
Fixes#2695
Used the shared Codex originator constant for browser OAuth URLs so login credentials match the headers sent by OMP Codex requests.
Added a regression test covering the browser-login URL originator.
Fixes#2696
Kept synthesized fc_<call_id> aliases in a separate lookup map so real call_id keys like fc_x cannot overwrite aliases for call_id x.
Extended the parallel ast_grep regression to cover x/fc_x call-id collisions under prefixed delta routing.
Fixes#2715
Always register the synthesized fc_<call_id> lookup key for Responses tool calls, even when the call_id already starts with fc_.
Extended the parallel ast_grep regression to cover call_id values with an existing fc_ prefix.
Fixes#2715
Registered OpenAI Responses function-call stream items under both their bare call_id and synthesized fc_<call_id> key so Ollama/local parallel tool deltas no longer fall back to the most recent call.
Added a regression covering parallel ast_grep calls whose argument deltas use prefixed item ids.
Fixes#2715
One MCP tool whose input schema can't be emitted as a valid strict tool schema
for the active provider made the whole request 400, so the assistant couldn't
respond at all (#2652). `convertTools` now validates each tool's emitted
parameter schema for enum/const-vs-type contradictions that pass structural
JSON-Schema validation but the provider rejects (a non-null enum on a
type:"null" node; an enum on an array node), and drops just the offending tool
with a `logger.warn` naming the tool + schema path, keeping the rest of the
request valid.
- New `findStrictToolSchemaViolation` in utils/schema: a semantic enum/const-vs-
type checker. The existing `isValidJsonSchema` is structural-only and accepts
these contradictions, which is exactly why they reach the provider.
- Tests: the three reported shapes (nullable-enum, enum-on-array, anyOf/const),
nested-path reporting, valid combinations incl. nullable unions, and the
convertTools quarantine (bad tool dropped, others survive).
Parsed literal thinking envelopes independently before transcript rendering so interleaved thinking blocks do not collapse into one malformed wrapper. Added advisor raw dump regression coverage for sibling literal thinking blocks.\n\nFixes #2700
Cleared Anthropic thinking signatures when literal thinking-envelope normalization changes provider bytes, preventing same-model replay from pairing stale signatures with rewritten text.
Extended the wrapped-thinking regression test to verify replay demotes the rewritten block instead of sending an invalid signed thinking block.
Fixes#2695
Normalized Anthropic thinking deltas that arrive wrapped in literal thinking tags before finalizing the parsed thinking block.
Added a stream regression test covering nested provider thinking wrappers so advisor raw dumps do not render duplicated tags.
Fixes#2695