The shared formatToolResultText helper emitted its trim() result instead
of using it as an emptiness predicate only, so native Mistral and Ollama
requests silently stripped leading indentation and trailing
whitespace from durable tool output (#127587). Chat Completions already
emits the original sanitized text and uses trim solely to detect blank
content; align the shared formatter with that contract. Blank output
keeps the placeholder fallback, error prefix, and omitted-media suffix.
Closes#127587
AI-assisted (Claude); shared + Mistral + Ollama boundary regression
tests fail pre-fix and pass post-fix.
Co-authored-by: Parker Fawcett <Parkerscottfawcett@gmail.com>
* perf(ai): refresh streamed tool-call argument previews on a length schedule
Every input_json_delta re-parsed the entire accumulated argument buffer
(quote scan, strict parse attempt, repair scan, partial parse), making
assembly quadratic in argument size. A 128KB tool call spent ~1.2s of CPU
on re-parsing alone while blocking token delivery; previews are
preview-only by contract since the terminal parse re-reads the full
buffer authoritatively at content_block_stop.
Refresh previews on a geometric length checkpoint instead: bounded
staleness, linear total work. Applied across every accumulating
packages/ai transport/provider surface sharing the invariant.
(hook bypassed per run-node-tool.sh contract: no local node_modules in
this worktree and pnpm install is out of scope; oxfmt --check green on
all staged files via sibling checkout binary.)
* perf(agents): throttle proxied tool argument previews
* fix(agents): preserve terminal-only proxy tool calls
Preserve opaque source strings across tool-result replay while retaining masking for direct .env reads, registered or recognizable secrets, structured sensitive fields, and payment data.
Responses replay parsed persisted thinking signatures without validating their JSON shape, so corrupt or unrelated values could prevent every later turn in a session.
Parse signatures in the shared replay owner and accept only reasoning records. Cover malformed syntax, null, arrays, and wrong item types through both provider- and transport-style converters.
The default OpenAI Responses compact_threshold was 70% of contextWindow alone; for gpt-5.6-sol (1.05M window, 272k active budget) that resolved to 735,000, above the ~252k prompt budget the runtime admits, so provider compaction never fired before local overflow handling. Threshold now uses 0.7 x min(contextTokens, contextWindow) (190,400 for Sol) on both the payload-policy and host-preflight paths; explicit responsesCompactThreshold still wins.
Classify text interrupted by resumed reasoning at the OpenAI-completions producer boundary, so channels deliver only the confirmed final answer.
Defer phase-ambiguous replies until terminal classification while preserving live partial delivery for ordinary completions.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* refactor(ai): give transport streams an honest writer type
* test(ai): use canonical transport stream fixtures
* fix(ai): preserve partial-less stream deltas
* fix(ai): preserve provider terminal error message in stream transports
The managed OpenAI Responses transport (and the mistral/google-shared
providers) threw a literal "An unknown error occurred" on terminal
error stop reasons, discarding the provider's terminal fact (for example
"Provider incomplete_reason: content_filter"). The catch-side
projectProviderError() then overwrote output.errorMessage with the
generic string, so users saw an unknown error and failover classified
the deterministic failure as a transient timeout, rotating models and
re-sending the same filtered prompt.
Align all three sites with the canonical siblings
(openai-responses-shared.ts, transport-stream-shared.ts) by preserving
output.errorMessage when present.
* test(ai): await the transport stream factory before result()
* fix(ai): narrow the repair to the managed OpenAI transport
ClawSweeper correctly noted the mistral and google-shared edits were
no-ops: streamMistral never assigns output.errorMessage and the Google
path throws its own constructed terminal error before this fallback.
Revert both to keep the PR scoped to the proven managed-transport
repair.
* fix(ai): recover rejected WebSocket compaction
Native OpenAI WebSocket turns now rebuild full history over SSE when a replayed encrypted checkpoint is explicitly rejected, then suppress that checkpoint on later turns.
* ci: refresh merge check
* fix(ai): managed OpenAI transport understates gpt-5.5 priority pricing by 20%
The managed Responses transport carried its own copy of the service-tier
pricing table in openai-responses-debug.ts (flat 2x for priority). The
canonical helper applyResponsesServiceTierPricing in
openai-responses-shared.ts was updated to 2.5x for gpt-5.5 priority
(#117298) but the transport copy was never touched, so UI cost for
managed-transport fast-mode turns understated the real spend.
Delete the duplicated table and delegate the transport's pricingOptions
to the canonical model-aware helper. Azure intentionally remains
tier-unpriced (it sets no pricingOptions).
* test(ai): pin managed-transport gpt-5.5 priority pricing at the transport boundary
ClawSweeper correctly flagged that the helper-only test also passes on
unfixed main. Add a mocked managed-transport run with a priority
response and nonzero model cost asserting the final usage cost is 2.5x
(fails at 24 vs 30 on the pre-fix flat table).
Treat <internal> blocks as private reasoning in the shared parser and remove Telegram raw-reasoning fallbacks. This keeps model reflections out of user-visible replies while preserving surrounding answer text.
Closes#122623
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Co-authored-by: WangYan <wang.yan29@xydigit.com>
* feat(ai): continue stateful OpenAI SSE turns
Use the prior OpenAI Responses ID for native stateful HTTP/SSE turns, retry missing server state with full history in the same turn, and keep stateless/custom routes unchanged.
Co-authored-by: Markus Hartung <mail@hartmark.se>
* test(ai): assert Responses retry attempt metadata
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>