Commit Graph

109 Commits

Author SHA1 Message Date
metaphorics 3802d2dd80 chore(ts): enforce noImplicitOverride 2026-08-05 02:49:01 +09:00
roboomp a3d1f35099 fix(openai): preserved Codex native image results
- Normalized result-bearing Codex image items on terminal output events and emitted standard image content.

- Preserved result-bearing image calls during full Responses history replay despite stale provider status.

- Added stream and replay regressions for the Codex path.

Fixes #7445
2026-08-03 02:41:03 +00:00
Christian Stewart 9d69db481a feat(coding-agent): add OpenAI service tier override
The OpenAI service tier could only be chosen through the `tier.openai`
setting, or for a resumed session through whatever tier that session
recorded. Wanting flex or priority for a single run meant editing
settings and putting them back afterwards, while `bench` already took a
`--service-tier` flag that the session CLI did not offer.

Add `--service-tier` to the root command. The flag wins over the
configured setting and over a resumed session's recorded tier, leaves
the Anthropic and Google entries untouched, and records the resulting
map so a later resume keeps it. `none` removes the OpenAI entry, which
omits `service_tier` from the request.

Signed-off-by: Christian Stewart <christian@aperture.us>
2026-08-02 05:07:33 -07:00
roboomp a598d67d75 fix(ai): preserved codex websocket chaining for normalized ids
- Stored replay-sanitized Codex response items as the append baseline.

- Disabled append state for responses without replayable output and covered oversized call IDs.

Fixes #7279
2026-08-01 16:01:21 +00:00
roboomp eb5bfbfb11 fix(ai): honored disabled Codex cache retention
Routed Codex prompt cache identity through the shared retention-aware resolver while preserving transport session identity.

Covered explicit and environment-derived opt-outs, option precedence, direct body construction, and transport headers.

Fixes #7219
2026-08-01 03:45:49 +00:00
can1357 47d3317d32 feat(ai): reserved code_mode_tool_names and preserve encrypted_function_args
- Reserve the `code_mode_tool_names` metadata key to prevent caller-supplied client extra collisions.
- Preserve the `encrypted_function_args` plaintext-collaboration marker on replayed function calls.
2026-07-30 00:00:37 +02:00
can1357 eab5b50834 feat(ai): added parentTurnId support and capture turn-state refreshes in Codex
- Added first-class `parentTurnId` stream option and reserved metadata key for nested Codex requests.
- Captured `x-codex-turn-state` refreshes from `response.metadata` event headers in WebSocket and streaming sessions.
2026-07-29 23:33:29 +02:00
metaphorics 4d334592c1 perf(ai): compress Codex SSE request bodies with zstd
(cherry picked from commit 0b830d33eb9dcf6290db0f45cd1cd0995dbd7fe0)
2026-07-29 23:08:48 +02:00
Jeff Scott Ward 050388b486 fix(advisor): bound Codex SSE retries 2026-07-24 15:24:14 -04:00
usr-bin-roygbiv b9504f65e7 feat: add native Codex computer use 2026-07-24 01:40:04 +00:00
can1357 8ff821515d fix(ai): honor NO_PROXY ports for secure websockets 2026-07-16 03:41:17 +02:00
can1357 a17db4bea8 merged PR #5510: fix(ai): honor proxies for Codex WebSockets
# Conflicts:
#	packages/ai/test/openai-codex-stream.test.ts
2026-07-16 03:41:16 +02:00
can1357 3fbb1cd386 Merge PR #5477: fix(ai): retry Codex pre-response watchdog timeouts (@roboomp) 2026-07-14 22:58:47 +02:00
roboomp f029e536ba fix(ai): honored proxies for codex websockets
Passed provider-specific PI_PROXY settings and standard HTTPS/ALL proxy variables to Bun WebSocket connections while preserving NO_PROXY bypasses.

Fixes #5384
2026-07-14 19:50:39 +00:00
roboomp c49c693b73 fix(ai): retried codex pre-response watchdog timeouts
Gave each Codex SSE transport attempt an independent pre-response watchdog while reserving the retry-loop signal for caller cancellation.

Added provider-level coverage for retry recovery and explicit abort behavior.

Fixes #5329
2026-07-14 18:26:35 +00:00
roboomp e5f6119a4a fix(ai): preserved streamed responses text
Kept message text accumulated from Responses/Codex streaming deltas when output_item.done carries empty content.

Fixes #5146
2026-07-11 05:21:25 +00:00
can1357 2dafa7ac79 feat: further codex metadata 2026-07-10 11:35:09 +02:00
can1357 396e91e101 fix(ai): preserved streamed responses thinking on empty done summary
Codex #handleOutputItemDone unconditionally rebuilt block.thinking from
item.summary, clobbering already-streamed reasoning with "" when the
done event carries no summary (GPT-5.x Codex renders <!-- --> in TUI).
The generic processResponsesStream had the same clobber, and the codex
handler also dropped response.reasoning_text.delta events entirely.

Added shared finalizeReasoningThinking(): prefer done-item summary,
then reasoning_text content, then the streamed accumulation; wired
response.reasoning_text.delta into the codex processor.

Adopted from PR #4935 minus unrelated prompt churn.

Fixes #4918
2026-07-09 18:27:20 +02:00
can1357 68da3dca8a test: aligned merged regression tests with current main contracts
- handoff veto mock returns a promise and threshold expectation includes onSwitchCancelled
- codex websocket stale-anchor stats assertion tolerates lastTurn debug payload
2026-07-08 15:43:56 +02:00
can1357 48155c0fbe merge PR #4625: fix(ai): recognize proxy stale-anchor codes for codex websocket previous_response chain 2026-07-08 15:19:34 +02:00
roboomp ea4e913301 fix(ai): recorded codex compact usage diagnostics
Added Codex turn diagnostics that pair WebSocket/SSE request shape with raw provider usage and displayed usage buckets, including delta-chain state for previous_response_id requests.

Covered the compact/resume WebSocket delta path where raw usage lacks orchestration fields but reports a persistent uncached suffix.

Refs #4707
2026-07-06 14:34:17 +00:00
roboomp fc71df400f fix(ai): recognized proxy stale-anchor codes as codex previous_response chain expiry
`isCodexStalePreviousResponseError` short-circuited for `CodexProviderStreamError`
by comparing `error.code` only to `previous_response_not_found`, so a proxy code
such as `codex_previous_response_stale` never reached the message-based
fallback. WebSocket continuations that hit a stale upstream response anchor
surfaced the terminal error to the user instead of retrying with full context.

Codex WebSocket continuations now treat both the OpenAI-standard
`previous_response_not_found` and the proxy `codex_previous_response_stale`
code as the same recovery class, and every `Error` — not just plain ones —
falls through to the existing `previous[ _]?response` / `expired|stale|...`
message check.

Fixes #4624
2026-07-05 18:15:15 +00:00
can1357 a868a7d2d5 Merge PR #4471: fix(ai): separate Codex orchestration usage (@roboomp) 2026-07-05 13:03:08 +02:00
roboomp f6ec7a613e fix(ai): allowed opaque codex provider keys
Made Codex account ids optional for openai-codex-responses custom providers, omitting chatgpt-account-id when opaque API keys cannot provide a ChatGPT account claim.

Added SSE and websocket regression coverage for custom Codex proxy API keys.

Fixes #4526
2026-07-04 15:44:49 +00:00
roboomp a52ed682c7 fix(ai): separated codex orchestration usage
- Added a Usage.orchestration sidecar for provider-side service tokens so Responses/Codex totals and costs stay accurate without inflating visible prompt input/cache buckets.
- Updated Codex/WebSocket usage, session/status aggregates, and usage reporting to preserve orchestration-aware totals.
- Added regressions for OpenAI Responses accounting, Codex WebSocket terminal usage, cost calculation, and session aggregation.

Fixes #4469
2026-07-03 16:44:12 +00:00
can1357 2863a9c4e7 feat(ai): enabled textVerbosity option for openai api stream requests
- Added textVerbosity option to OpenAIResponsesOptions and SimpleStreamOptions.
- Updated stream mapping logic to propagate verbosity setting to the API request body.
- Implemented endpoint validation to ensure verbosity settings are only applied to official OpenAI endpoints.
- Added comprehensive test coverage for request payload inspection and stream event handling.
2026-06-27 13:05:56 +02:00
can1357 f018c5ce81 feat(ai): updated default reasoning and text verbosity settings
- Default the reasoning context to all_turns in the OpenAI Codex request transformer.
- Increase the default text verbosity for Codex requests to medium.
- Set a detailed reasoning summary for AI streams by default.
- Remove outdated testing logic for low verbosity defaults.
2026-06-27 12:43:23 +02:00
can1357 174d5ca171 refactor(ai): restructured ai configuration and purged legacy logic
- Migrated configuration constants to use dynamic environment variable lookups.
- Removed unused helper functions and associated internal logic.
- Deleted comprehensive test suite for decommissioned WebSocket transport mechanisms.
2026-06-27 12:35:41 +02:00
can1357 39baa044ef test(ai): aligned openai test suites with hardening requirements
- Adjusted `openai-codex-stream` tests to dynamically resolve queue capacity, ensuring reliable overflow-triggered SSE fallback testing.
- Added validation in `openai-responses-delta-input` to verify that changes to top-level request options correctly break response streaming chains.
- Cleaned up redundant environment variable cleanup logic in test teardown hooks.
- Refined serialization in `openai-first-event` error testing to ensure stable comparisons of response content.
2026-06-27 12:26:23 +02:00
can1357 357c29224d feat: implemented symbol-based streaming state for isolated metadata
- Migrated internal streaming state from string-based properties to symbol-keyed properties for improved data isolation and safety.
- Replaced the deprecated `stripVariant` utility with centralized `clearStreamingPartialJson` and symbol-specific helper methods across all provider implementations.
- Implemented `stripStreamingBlockSymbols` and updated deep equality checks to ensure metadata does not interfere with content comparisons.
- Standardized streaming metadata access through a new `block-symbols` utility module.
2026-06-27 12:07:08 +02:00
can1357 7afd288422 feat(ai): consolidated error transport patterns and clarify stream classification
- Centralized transient transport error patterns to enable consistent reuse across error handling modules.
- Refactored `isOpaqueStatusBody` for improved accessibility in classification logic.
- Updated retryable error detection to include the consolidated transport pattern and additional provider-specific error criteria.
2026-06-27 10:55:23 +02:00
can1357 2eabc28830 test(ai): updated property absence assertions in stream tests
- Replaced `in` operator checks with `toBeUndefined()` assertions to improve type safety with casting.
2026-06-27 10:47:36 +02:00
can1357 a70f3f0614 fix(ai/providers): prevented cross-turn frame and tool result misattribution
- Implement ID-based guards for Codex WebSocket frames to reject stale or unauthorized interleaved frames from previous turns.
- Check sequence numbers within Codex responses to detect and handle out-of-order frame delivery.
- Restrict tool result consumption to occurrences appearing after the associated tool call, preventing the reuse of orphaned results from earlier conversation turns.
2026-06-21 08:30:37 +02:00
roboomp f6c4d6fb62 fix(ai): stripped unsupported sampling keys from openai-codex-responses payloads
The Codex Responses backend (ChatGPT-subscription `/backend-api/codex/responses`)
returns 400 `{"detail":"Unsupported parameter: temperature"}` for every sampling
control, but `buildTransformedCodexRequestBody` forwarded `temperature`, `top_p`,
`top_k`, `min_p`, `presence_penalty`, and `repetition_penalty` straight through
whenever the caller's `StreamOptions` carried them — so any non-default sampling
setting failed every turn.

- Provider drops the full sampling set (matching codex-rs, which sends none).
- `RequestBody` no longer types fields it never populates for codex.
- Auth-gateway defensive strip in `buildStreamOptions` and the pi-native handler
  widened from `{temperature, topP}` to the same set plus
  `stopSequences`/`frequencyPenalty`.
- Regression test pins the captured body to omit every key even when the caller
  sets all of them.

Fixes #3117
2026-06-20 09:48:58 +00:00
can1357 291b3c74c2 feat: enhanced model reasoning, schema normalization, and loop guarding
- Integrated comprehensive loop guard support for DeepSeek and assistant prose patterns, including configurable stream checks.
- Implemented Moonshot Flavored JSON Schema (MFJS) normalization for improved tool compatibility and enum type inference.
- Added support for Ollama reasoning effort backfilling and Grok-specific service tier cost tracking across providers.
- Expanded model catalog with new entries and unified compatibility logic for improved OpenRouter API integration.
2026-06-18 04:51:43 +02:00
DarkPhilosophy 1b58c6c7f1 Merge remote-tracking branch 'can1357/main' into fix/provider-onpayload-replacements 2026-06-15 14:01:41 +03:00
roboomp e114f3b1b2 style: bun run fix 2026-06-15 06:29:00 +00:00
roboomp da94f27edd fix(ai): tracked unkeyed current open item via currentEntry
The keyed maps only see items whose `output_item.added` carries `item.id`
or `output_index`. A fully keyless add never reached either map, and the
unkeyed fallback was scanning those maps instead of the actual current
item — so `function_call_arguments.delta` / `output_item.done` for a
keyless tool call landed on null and the stored block kept `{}`. Mixed
streams also picked an older `output_index` entry before a later
id-only current item for the same reason.

`CodexStreamRuntime.currentEntry` now always points at the most recently
added `output_item.added` (whether or not it has keys). `openItemForEvent`
returns `currentEntry` when both `item_id` and `output_index` are absent,
and `closeCodexOpenItem` clears `currentEntry` (alongside the legacy
`currentItem` / `currentBlock` mirrors) when its item closes. The keyed
maps are unchanged so deliberate drop-on-mismatch for keyed events still
holds.

Regression tests cover the fully keyless function-call stream and the
mixed id-only vs `output_index`-only ordering. Existing reasoning/message
flow keeps singleton semantics through the same fallback.

Fixes #2619
2026-06-15 06:28:35 +00:00
roboomp 5f3d8643d5 fix(ai): finalized idless codex calls by output_index
Codex Responses function/custom tool call items can omit `id` while still
carrying `output_index` on `output_item.added` and `output_item.done`.
The first pass only keyed open items by `item.id`, so idless done events
could not find the stored block and the authoritative final arguments were
not copied into `output.content`.

Track open items by both `item.id` and `output_index`. Event lookup now
uses `item_id` first, then `output_index`, and only falls back to the
singleton-current path when neither key is present. Closing an item removes
both keys, so stale keyed deltas remain dropped instead of leaking into a
sibling.

Added a regression covering idless function and custom tool calls finalized
only by `output_item.done`, including out-of-order completion and per-call
`contentIndex`.

Fixes #2619
2026-06-15 06:14:02 +00:00
roboomp cf71cfa832 style: bun run fix 2026-06-15 05:55:43 +00:00
roboomp cdfc1cce3e fix(ai): routed codex responses arg deltas by item_id
The Codex Responses stream runtime tracked a singleton
`currentItem`/`currentBlock`. With more than one tool call open
concurrently every `response.function_call_arguments.delta` was
appended to whichever item was added most recently, and the next
`response.output_item.done` for the earlier call overwrote the
sibling's stored arguments. On the agent loop's `task` tool this
surfaced as `tasks: Invalid input: expected array, received undefined`.

Open items are now tracked in a `Map<string, CodexOpenItem>` keyed by
`item.id`, each entry carrying its own `block` and `contentIndex`.
`response.function_call_arguments.{delta,done}`,
`response.custom_tool_call_input.{delta,done}`, and
`response.output_item.done` route through `openItemForEvent` and
operate on the matching entry's block; the legacy singleton-current
fallback only kicks in when an event omits `item_id`. A delta whose
keyed item already closed is dropped instead of leaking into a
sibling, and `toolcall_delta` / `toolcall_end` stream events emit the
right `contentIndex` for each call. Recovery sites converge on a new
`resetCodexStreamAccumulators` helper that clears the open-items map
in lockstep with `currentItem`/`currentBlock`/`nativeOutputItems`.

Regression test (`packages/ai/test/openai-codex-stream.test.ts`)
interleaves two function-call argument streams plus a stale
post-close delta and asserts per-call argument integrity and
per-call stream `contentIndex`.

Fixes #2619
2026-06-15 05:55:24 +00:00
DarkPhilosophy 86f560f061 fix: keep codex websocket append baseline 2026-06-14 23:58:02 +03:00
DarkPhilosophy 1521275538 fix: apply codex websocket payload replacements 2026-06-14 23:47:51 +03:00
DarkPhilosophy 45af89e1b7 test(ai): avoid leaking fetch stubs 2026-06-13 20:36:34 +03:00
DarkPhilosophy 9da623e2a4 Merge remote-tracking branch 'can1357/main' into fix/provider-onpayload-replacements 2026-06-12 19:02:36 +03:00
can1357 7119153077 fix(ai): removed Codex SSE stateful chaining and enforced turn-scoped state
- Removed stateful SSE chain controls from Codex provider options.
- Changed SSE transport to send full request bodies without `previous_response_id` deltas.
- Updated stale-chain recovery to treat `unsupported` as stale and recover via websocket.
- Scoped `x-codex-turn-state` to in-turn follow-ups and cleared turn state otherwise.
2026-06-12 11:12:27 +02:00
can1357 344ac680df feat(ai): added stateful SSE turn chaining to the Codex provider 2026-06-12 02:33:46 +02:00
can1357 ad276e931c feat(ai): added Codex Lite options and improved response stream resilience
- Added `responsesLite`, `reasoningContext`, `clientMetadata`, and `onModerationMetadata` options.
- Changed Lite request transformation to default `reasoning.context` to `all_turns`.
- Changed request shaping to strip image `detail` fields and force `parallel_tool_calls` off in Lite mode.
- Fixed streaming behavior by excluding `client_metadata` from websocket append diffs and swallowing moderation metadata errors.
2026-06-12 02:33:45 +02:00
can1357 eb966cc6dc fix: handled non-terminal pause_turn stops by resampling interrupted turns
- Mapped Codex `end_turn:false` terminal events to `pause_turn` stop details in response stream parsing.
- Updated `agent-loop` to re-sample `pause_turn` turns, reset on tool calls, and cap continuations at 8.
- Added coverage for pause-turn mapping and continuation-capping in agent and AI stream tests.
2026-06-12 02:33:45 +02:00
can1357 ae415199dc feat: added build-time compatibility in ModelSpec/buildModel pipeline
- Centralized catalog and registry handling on `ModelSpec` and `buildModel`, resolving compatibility at model build time.
- Removed runtime compatibility detectors and switched provider request flows to direct `model.compat` reads.
- Added compat fields (`supportsReasoningParams`, `alwaysSendMaxTokens`, `strictResponsesPairing`, `whenThinking`).
- Persisted explicit compatibility overrides through `compatConfig` in discovery and cache merge paths.
2026-06-10 06:20:51 +02:00