202 Commits

Author SHA1 Message Date
Peter Steinberger 5eebaf9e5c refactor(ai): internalize ChatGPT SSE protocol (#122930) 2026-08-12 19:31:00 -07:00
Peter Steinberger 2335332a5b refactor(ai): remove Azure provider testing export (#122819) 2026-08-12 14:16:26 -07:00
Peter Steinberger 45a59030db fix(ai): recover missing OpenAI WebSocket response state (#122727)
* fix(ai): recover rejected WebSocket continuations

* fix(ai): keep WebSocket server error internal
2026-08-12 10:34:09 -07:00
Markus Hartung 4e12d0556b feat(ai): continue stateful OpenAI SSE turns (#122194)
* 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>
2026-08-12 09:25:51 -07:00
Peter Steinberger 2cb9a75648 improve(gateway): compose live session stress probes (#122519)
* test(gateway): compose live session stress probes

Amp-Thread-ID: https://ampcode.com/threads/T-019feaaa-c7ed-769e-9f29-a3612bec72e7

* fix(ai): resume after Responses compaction checkpoints

Amp-Thread-ID: https://ampcode.com/threads/T-019feaaa-c7ed-769e-9f29-a3612bec72e7

* test(gateway): compose multi-session subagent probes

Amp-Thread-ID: https://ampcode.com/threads/T-019feaaa-c7ed-769e-9f29-a3612bec72e7

* fix(test): invalidate inlined schema transforms

Amp-Thread-ID: https://ampcode.com/threads/T-019feaaa-c7ed-769e-9f29-a3612bec72e7

* test(ai): cover empty compaction owners

Amp-Thread-ID: https://ampcode.com/threads/T-019feaaa-c7ed-769e-9f29-a3612bec72e7

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-08-12 06:22:08 -07:00
Peter Steinberger b080dd1e76 refactor: consolidate coercion contracts (#122458)
* refactor: consolidate coercion contracts

Centralize exact string, record, numeric, date, Boolean, argument, and structured-error coercions while preserving call-site semantics.

Migrate canonical-name collisions and deprecated internal SDK bypasses, deleting 55 net production/tooling lines. Expand declaration ownership enforcement to 101 allowed helpers and add a narrow export-completeness audit.

* fix: preserve standalone script coercions

Keep copied Control UI tooling self-contained and retain the trusted release harness module-relative source seam when the harness runs against an old target cwd.
2026-08-11 23:26:37 -07:00
Peter Steinberger 0c8c8d95c7 fix(ai): restore cached OpenAI continuation (#122483) 2026-08-11 23:24:57 -07:00
Peter Steinberger e30df72045 fix(worker): keep source bundles npm-installable (#122430) 2026-08-11 21:50:56 -07:00
Peter Steinberger 964c8c84c1 refactor: consolidate coercion ownership (#122299)
* 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.
2026-08-11 17:14:53 -07:00
Peter Steinberger 087fb56f77 feat(moonshot): add native K3 video input (#122337) 2026-08-11 16:49:42 -07:00
Peter Steinberger 7eed2c3f21 feat(google): add current-turn native video input (#122074)
* feat(agents): add current-turn Gemini video handoff

* test(google): add live native video regression

* build(ai): emit provider types entrypoint

* fix(google): preserve video shedding on retry
2026-08-11 12:58:32 -07:00
tharuntejmeta a57e8c70f5 feat(meta): add Muse Spark 1.2 models (#120373)
* feat(meta): add Muse Spark 1.2 models

* fix(meta): verify Muse Spark 1.2 catalog metadata

* fix(meta): verify Muse Spark 1.2 contracts

* docs(meta): quote discounted services terms

* fix(meta): preserve replay fields for simple completions

* test(meta): align stream host adapter types

* fix(meta): apply catalog cap for zero max tokens

* fix(meta): preserve omitted output cap

* fix(meta): scope responses stream wrapper

* fix(ai): preserve source API for stream wrappers

* fix(ai): distinguish hook and dispatch APIs

* test(ai): adapt plugin streams synchronously

* chore(plugin-sdk): refresh API baseline

* chore(plugin-sdk): refresh sharded API baseline

---------

Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
2026-08-11 11:26:58 -07:00
Peter Steinberger cad77fb39c refactor: consolidate remaining coercion helpers (#122020) 2026-08-11 10:22:01 -07:00
Peter Steinberger 7fb18bf2cf test(ai): remove stale completions compat bridge (#122154) 2026-08-11 10:10:39 -07:00
Peter Steinberger fe4cff7a6b refactor(ai): split completions transport into concept modules (#122122)
* refactor(ai): split completions transport into concept modules

* refactor(ai): delete duplicated transport helpers

* chore(lint): ratchet max-lines baseline after transport split

* test(scripts): update prefix expansion expectation
2026-08-11 09:47:52 -07:00
Peter Steinberger 903af8bef5 fix(ai): couple Responses hooks to stream lifecycle (#121163) 2026-08-11 09:03:07 -07:00
Peter Steinberger 226c699a23 feat(ai): add provider video input contract (#121887)
* feat(llm): add user video input contract

* fix(ai): preserve structured tool results

* refactor(ai): isolate provider video input types

* style(ai): format provider transform imports

* chore(ai): register provider type entrypoint
2026-08-11 03:08:27 -07:00
Peter Steinberger fa03d9b913 refactor: consolidate coercion helpers (#121366)
* refactor: consolidate coercion helpers

* fix: remove duplicate coercion imports

* fix: preserve serialized coercion guard

* chore: ratchet coercion helper carve-outs

* fix(test): keep gauntlet subprocess startup lean

* fix: preserve imported session timestamp semantics

* fix: preserve catalog timestamp string semantics

* chore: align plugin SDK surface ratchet

* fix: preserve trajectory and SDK string contracts

* fix(test): preserve QA record assertion semantics

* fix: complete standalone record guard rename

* refactor(cron): use canonical string coercion

* fix(acpx): preserve Pi timestamp parsing

* test(channels): adapt custody test harnesses

* test(telegram): classify media harness as test support

* test(acpx): split timestamp contract coverage

* test(channels): support generated custody contracts

* chore: ban the full coercion helper name set

Extends the declaration guard to all eleven consolidated helper names and
renames the cron schedule-identity readNumber wrapper to readScheduleInteger
so the banned generic name cannot regrow.

* fix(scripts): repair release-validation guard drift and lint cause

Restores the renamed isJsonRecord guard in assertTrustedWorkflowHarness after
main added isRecord call sites in parallel, and attaches the caught YAML error
as the thrown error cause (preserve-caught-error was red on main).

* fix: preserve Claude timestamp string semantics

* fix: preserve persisted timestamp string semantics

* fix: preserve date-first timestamp contracts

* fix(openai): harden delegation failure formatting

* chore: close coercion helper guard gaps

* test(openai): model non-error delegation rejection

* chore: refresh plugin SDK API contract

* fix(tasks): use canonical string field reader

* fix(ai): use canonical provider error field coercion

* fix(browser): migrate native bootstrap coercion

* docs(plugin-sdk): clarify text record export compatibility

* fix(gateway): normalize approval execution identity

* test(outbound): isolate message action poll harness
2026-08-11 00:02:18 -07:00
Peter Steinberger 90ddeb4b40 refactor(agents): absorb overflow, retry, and matcher duplicates into the failover substrate (#121817)
* refactor(ai): centralize context overflow matching

* refactor(agents): add retry evidence and guarded status facets

* refactor(agents): absorb assistant retry and key matchers

* chore(plugin-sdk): refresh failover closure hashes

* fix(agents): consume retry evidence at altitude zero

* test(agents): narrow retry corpus provider fixtures

* test(agents): keep retry corpus sorting immutable
2026-08-10 22:07:21 -07:00
Peter Steinberger 00fb85e48f fix(openai): preserve hosted search in Code Mode (#121812)
Keep provider-hosted web_search alongside Code Mode's constrained function surface when OpenAI policy authorizes it. Enforce the same authorization at Responses transport egress.

Refs #121803.
2026-08-10 19:59:51 -07:00
Peter Steinberger 8aa0376f27 refactor(agents): simplify turn latency runtime ownership (#121779)
Amp-Thread-ID: https://ampcode.com/threads/T-019fe95b-d75c-70fc-82b6-4825ca874826

Co-authored-by: Amp <amp@ampcode.com>
2026-08-10 18:58:36 -07:00
Peter Steinberger 58a538767c fix(security): centralize provider diagnostic redaction (#121599)
* fix(security): centralize provider diagnostic redaction

* fix(workers): redact finishing diagnostics

* fix(security): fail closed on malformed diagnostics

* fix(security): redact media wrapper diagnostics

* fix(security): normalize diagnostic field redaction

* fix(security): redact diagnostic media URIs

* fix(ai): preserve diagnostic compatibility in error projection

* refactor(ai): simplify diagnostic error handling

* fix(security): redact credential query diagnostics

* fix(security): redact diagnostic media arrays

* fix(security): redact diagnostic credential headers

* test: align shared expectations with current runtime contracts

* test(ui): align managed media and picker expectations

* fix(security): redact plural media diagnostics

* fix(ai): preserve bracketed provider errors

* fix(security): cover generic diagnostic credentials

* fix(security): redact prefixed diagnostic JSON

* fix(security): redact embedded diagnostic JSON

* test(agents): align cache trace media redaction

* fix(security): redact cookie diagnostics

* refactor(ai): isolate diagnostic host policy

* refactor(ai): narrow diagnostic helper exports

* fix(security): bound diagnostic descriptor reads

* fix(security): bound diagnostic graph traversal
2026-08-10 18:53:45 -07:00
Peter Steinberger ba58803997 fix(models): repair local model no-auth and overflow handling (#121790)
Preserve the internal null Authorization marker when resolving local no-auth provider headers, avoid classifying LM Studio prompt-template guidance as context overflow, and rebuild ai/llm-core package sources during pnpm dev/watch.
2026-08-10 18:52:00 -07:00
Peter Steinberger aa25f88fe3 test(ai): remove schema cache reset seam (#121769) 2026-08-10 17:20:10 -07:00
Peter Steinberger f09a33ce41 Optimize OpenAI turn latency and simplify reuse (#121687)
Amp-Thread-ID: https://ampcode.com/threads/T-019fe95b-d75c-70fc-82b6-4825ca874826

Co-authored-by: Amp <amp@ampcode.com>
2026-08-10 16:23:06 -07:00
Peter Steinberger 92e522cade fix(openai): bound streamed tool arguments (#117055) 2026-08-09 10:02:23 -07:00
Peter Steinberger 4af090365c fix(openai): preserve failed Responses terminal usage (#115175)
* fix(openai): preserve failed Responses usage

* test(ci): include failed SSE prefix sibling
2026-08-09 09:59:21 -07:00
Peter Steinberger 9bbbeb0489 fix(openai): preserve Chat response hook lifecycle (#117056) 2026-08-09 09:18:16 -07:00
Peter Steinberger c70aee247e refactor(scripts): migrate JavaScript tools to TypeScript (#121005)
* refactor(scripts): migrate JavaScript tools to TypeScript

* fix(ci): keep changed-scope preflight zero-install

* fix(ci): preserve zero-install script owners

* fix(ci): complete script migration follow-through

* fix(release): keep stable closeout zero-install

* fix(scripts): preserve standalone execution boundaries

* fix(scripts): repair standalone loader boundaries

* fix(scripts): normalize gateway observation ids

* fix(scripts): keep Docker packager standalone

* test(scripts): preserve rebase cleanup helpers

* test(sessions): use tracked temp directory
2026-08-09 07:21:35 -07:00
Peter Steinberger 2941ff5e44 fix(ai): preserve Responses stream cancellation (#113801) 2026-08-09 03:54:02 -07:00
Peter Steinberger 993a415d24 fix(ai): fence Responses replay metadata (#120777) 2026-08-08 17:35:34 -07:00
Peter Steinberger 56cdad5055 fix(ai): invalidate stale compaction replay (#120786) 2026-08-08 17:29:17 -07:00
Peter Steinberger 257ac20fe5 fix(ai): preserve Responses history after compaction (#120729) 2026-08-08 15:59:04 -07:00
Peter Steinberger 5ebbc3c003 fix(agents): keep stalled turns visible after Responses streams settle (#120426)
* fix(agents): keep stalled turns visible after Responses streams settle

A bare-continue turn in live QA (goal-followthrough-live, gpt-5.4 via
openai-responses) completed its SSE requests and then produced no terminal
result, delivery, timeout, or error for 6+ minutes until SIGTERM. Root cause:
turn liveness is enforced only while awaiting provider stream events (llm-idle
watchdog); queued subscription handlers are fire-and-forget during the turn and
finalize joined them unbounded and un-abortable, backed only by the 48h default
run budget. One hung delivery handler silently dead-ended the whole turn.

- Bound the pending-events join in attempt-stream-finalize with a 120s liveness
  deadline plus the run-abort signal; on expiry, warn with the runId and proceed
  to settlement so the run always yields a visible terminal outcome.
- Responses transports now report every SSE event via notifyLlmRequestActivity
  (parity with completions/anthropic), so bookkeeping-only events keep the idle
  watchdog quiet instead of counting as network silence.

* fix(agents): bound the settlement block-reply flush with the shared liveness join

ClawSweeper P1 on #120426: after the finalize-phase join times out, settlement
still awaited onBlockReplyFlush on the same wedged delivery chain (unbounded on
the supported blockReplyTimeoutMs: 0 path). Generalize the bounded join into
joinWithRunLivenessDeadline in run/abortable.ts (owner of abort/liveness
racing) and use it for both the pending-events join and the settle flush;
timeout and abort resolve with a recorded warning so the turn always reaches a
visible terminal outcome. New coverage: helper tests (hang, abort, rejection)
and a real-settle-path regression holding the flush past the deadline.
2026-08-08 12:34:23 -07:00
Peter Steinberger 47f78a32eb fix(ai): preserve long Responses sessions after server compaction (#120457)
* fix(ai): preserve Responses server compaction state

Persist opaque Responses compaction items as fenced provider replay state so long stateless sessions can resume authoritative compressed history without exposing it in display or diagnostics. Carry state through worker transcripts and prune replay prefixes without splitting tool pairs.

Release note: Preserve long OpenAI Responses sessions across server-side compaction and worker restarts.

Related: #95788

* test(ai): align long-context fixtures with CI contracts

Make tool-result fixtures type-complete, use the canonical model selector helper, remove unused test-helper exports, and route the paid long-context live probe through the dedicated Gateway profile shard.

* test(ai): type mocked Responses terminal events

Give the mock SSE event collection an explicit open event shape so terminal response events coexist with output-item events under the root test typecheck.

* fix(ai): suppress rejected compaction replay

Persist a route-fenced suppression tombstone when encrypted-content recovery rejects a compaction item, so later turns do not retry the same opaque state. Preserve the tombstone through transcript redaction and cover successful fallback followed by the next turn.

* fix(ai): keep compaction suppression transport-private

Keep the suppression contract local to its sole Responses transport owner and make the regression fixture satisfy root type and lint checks without widening the Plugin SDK surface.

* refactor(ai): remove compaction suppression re-export

* fix(ai): scope compaction suppression to replay route

Keep foreign-route rejection tombstones from hiding the newest compatible Responses compaction while preserving same-route suppression.

* fix(ai): harden Responses replay recovery

Stage encrypted replay recovery so compaction is only suppressed after an attributable rejection. Preserve terminal ordering and keep provider replay within worker frame budgets without truncating opaque state.

* refactor(ai): centralize Responses output indexes

Keep normalized output identity tracking in the stream-slot owner, move response failure state to its diagnostic owner, and remove the obsolete replay clone export so exact-head static gates remain shrink-only.

* fix(ai): retain idless terminal tool identity

Use the canonical empty identity only when a provider supplies neither call nor item id, preventing terminal recovery from duplicating a done-only tool call while preserving stronger identities when available.

* fix(sessions): hide provider replay from public events

* fix(ai): stage encrypted replay recovery

* fix(ai): keep replay attempt kind internal

* fix(ai): route Azure through replay recovery

Use the shared encrypted-content retry owner for Azure Responses so compaction suppression and prompt-observer variants stay coherent across transports.

* fix(ai): harden replay persistence boundaries

Fence Azure replay by the resolved request endpoint, drop invalid replay during transcript sanitization, and surface worker-launch replay omissions through the existing redacted diagnostic path.
2026-08-08 11:55:26 -07:00
Peter Steinberger 40385bb5c1 test(e2e): isolate shared build artifacts (#120628) 2026-08-08 09:21:50 -07:00
Peter Steinberger 48639663b0 chore(release): prepare 2026.8.1 (#120375) 2026-08-07 18:44:12 -07:00
Peter Steinberger 5a795f4dda fix(qa): require a fresh reply and real tool use after switching models (#119662)
* fix(qa): require a fresh reply after switching models

* fix(qa): prove successful tool use after model switching

* fix(qa): wait for the new persisted model-switch tool result

* fix(qa): authenticate canonical model-switch attempt evidence

* fix(ai): preserve effective response model evidence

Punchcard-Session: golden-valley-workshop-br

* fix(agent): publish run-owned terminal receipts

Punchcard-Session: golden-valley-workshop-br

* fix(qa): require run-owned model-switch evidence

Punchcard-Session: golden-valley-workshop-br

* fix(agent): record explicit tool completion outcomes

Punchcard-Session: golden-valley-workshop-br

* fix(agent): exclude unavailable approvals from receipts

Punchcard-Session: golden-valley-workshop-br

* fix(agent): derive receipt visibility from terminal reply

Punchcard-Session: golden-valley-workshop-br

* fix(qa): bind model-switch continuity to terminal reply

Punchcard-Session: golden-valley-workshop-br

* fix(qa): project Crabline Telegram visible text

Punchcard-Session: golden-valley-workshop-br

* fix(qa): record run-owned delivery evidence

Punchcard-Session: golden-valley-workshop-br

* fix(qa): bind primary model-switch delivery

Punchcard-Session: golden-valley-workshop-br

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-08-08 03:05:32 +08:00
Peter Steinberger 74500f334e fix(ai): truncated Anthropic streams error; proxies exempt from message_stop contract (#120030)
* fix(ai): enforce message_stop only for direct Anthropic models

The Anthropic SSE transport threw 'stream ended before message_stop' only when
a refusal buffer happened to be non-empty, so a truncated first-party stream
could pass silently while compatible proxy providers that legitimately omit
message_stop failed intermittently. The invariant now keys off the transport
contract owner: direct Anthropic models always require message_stop; proxy
providers are exempt.

* test(ai): cover proxy streams ending without message_stop

ClawSweeper P1: the proxy exemption had no focused test, so the lenient
branch could regress silently. A non-anthropic provider through a custom
endpoint now proves stopReason=stop with no error when the stream ends
without message_stop.
2026-08-07 01:49:46 -07:00
metaforismo 2e0fe80c80 fix(venice): replay Gemini tool signatures by turn occurrence (#119783)
* fix(venice): replay Gemini tool-call signatures

* fix(venice): preserve Gemini signatures in transcripts

* fix(venice): handle mixed Gemini tool history

* fix(venice): downgrade unsigned Gemini tool history

* fix(venice): scope Gemini tool replay by turn

* fix(venice): narrow replay occurrence guards

---------

Co-authored-by: Wen-Yong Lim <cheng@Wen-4-Mac-mini.local>
Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
2026-08-06 20:27:16 -07:00
Peter Steinberger c663c39763 refactor(test): table-drive exact-duplicate test blocks, batch 2 (#120071)
* refactor(test): table-drive tooling test cases

* refactor(test): table-drive agent test cases

* refactor(test): table-drive core test cases

* refactor(test): table-drive plugin test cases

* refactor(test): table-drive package test cases

* chore(test): prune max-lines baseline

* fix(test): preserve table row literal types
2026-08-06 17:00:28 -07:00
大村愛弥 793f602f80 fix: remove bodyless 400/413 from overflow patterns to prevent false compaction (#119596)
* fix: remove bodyless 400/413 from overflow patterns to prevent false compaction

PR #67024 fixed the failover classification path (errors.ts) to not
classify bodyless 400/422 as 'format' errors. However, the compaction
trigger path (isContextOverflow in overflow.ts) still has the pattern
/^4(?:00|13)\s*(?:status code)?\s*\(no body\)/i in OVERFLOW_PATTERNS.

This means a bodyless 400 from any provider triggers compaction via
checkCompaction() -> isContextOverflow(), even though PR #67024
ensured the failover reason is null (not 'format'). The two paths are
independent: failover classification and compaction triggering use
separate functions.

A bodyless 400 cannot be a context overflow — real overflow errors
from all major providers include a descriptive body. A bare 400 with
no body is a transient/malformed error that should surface to the
user, not trigger a compaction loop.

Remove the Cerebras-specific pattern from OVERFLOW_PATTERNS. If
Cerebras returns bodyless 400/413 for actual overflow, it should be
handled with a more specific pattern or NON_OVERFLOW_PATTERNS exclusion.

AI-assisted.

* fix(ai): avoid compacting on bodyless 400 errors

---------

Co-authored-by: lykeion-dev <lykeion-dev@users.noreply.github.com>
Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
2026-08-05 20:53:02 -07:00
Vincent Koc a54bec799c fix(agents): observe native provider prompt egress (#119219)
* fix(agents): observe final provider prompt egress

* fix(agents): observe native provider prompt egress

* test(agents): type native prompt observer models
2026-08-04 22:46:07 +08:00
Vincent Koc 1fb4f3c709 merge: sync llama.cpp transport fix with main
* 'main' of https://github.com/openclaw/openclaw:
  test(qa): cover sandboxed exec behavior (#119053)
  test(qa): prove shared-channel memory recall (#119111)
  fix(telegram): keep request deadlines through response bodies
  test(qa): cover gateway plugin approvals (#119128)
  fix(ai): keep OpenAI tool call id truncation UTF-16 safe (#110471)
  fix: preserve live updater failure diagnostics (#119096)
  fix: recover new-session models through Gateway startup (#119120)
  test(qa): cover instruction profile artifacts (#119078)
  fix(telegram): record automatic delivery message ids
  test(qa): cover memory promotion safety (#119093)
  test(qa): prove overflow compaction pruning (#119033)
  fix(tool-search): preserve deferred MCP failures (#118363)
  fix(macos): keep setup activation within app checks
  test(setup): type provider kind fixture
  fix(setup): complete prepared model activation
  fix(protocol): regenerate Swift wizard models
  fix(ollama): activate the model selected during setup
  fix(setup): preserve the prepared model handoff
2026-08-04 14:51:35 +08:00
pick-cat 01e7fca716 fix(ai): keep OpenAI tool call id truncation UTF-16 safe (#110471) 2026-08-04 14:03:44 +08:00
Vincent Koc 9c854cb1a0 fix(ai): preserve Google simple completion sanitation 2026-08-04 13:58:58 +08:00
Vincent Koc 9501a8264b fix(ai): prefer provider-owned completion streams 2026-08-04 11:11:55 +08:00
zengLingbiao 780d6bf7b8 fix(ai): reject binary Codex websocket frames (#111138)
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-08-04 02:11:08 +08:00
Peter Steinberger 1140e56a37 test(ai): deduplicate legacy function-call fixtures (#118445) 2026-08-02 21:24:46 -07:00
Peter Steinberger 30c79e4db1 fix(inference): prevent lost cancellation, stuck compaction, and runaway tools (#118146)
* fix(inference): preserve cancellations, compaction, and tool-loop safety

* fix(inference): satisfy Codex and mock-provider type checks

* fix(codex): secure tool-free recovery and restricted turns

* fix(codex): satisfy host-prompt provenance lint
2026-08-02 14:42:01 -07:00