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>
* refactor: consolidate coercion ownership
Centralize four canonical coercion helpers, migrate exact core and plugin duplicates through narrow Plugin SDK facades, and enforce declaration and plugin-normalization ownership boundaries.
The sweep adds eight focused SDK exports while deleting more production and tooling code than it adds. User-visible behavior is unchanged except for safer equivalent object and UI parsing at existing boundaries.
* fix: guard integer option ownership
Register resolveIntegerOption with the canonical function owner and extend the declaration-guard fixture so future local duplicates fail validation.
* fix: keep integer helpers on numeric facade
Remove the unshipped duplicate string-coerce exports and route every affected plugin consumer through the existing number-runtime contract.
* fix: point numeric coercion to number runtime
Make boundary and declaration diagnostics recommend the canonical numeric facade, with failing-before coverage for both guidance paths.