mixdog 0.9.151 → 0.9.153
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSES/browser-import-NOTICE.txt +11 -0
- package/NOTICE.md +11 -0
- package/README.md +108 -68
- package/package.json +17 -4
- package/scripts/computer-task-cost-report.mjs +144 -0
- package/scripts/run-office-live-tests.mjs +32 -0
- package/scripts/tool-stress.mjs +0 -2
- package/src/agents/front-worker/AGENT.md +13 -0
- package/src/agents/front-worker/agent.json +6 -0
- package/src/agents/heavy-worker/AGENT.md +10 -11
- package/src/agents/heavy-worker/agent.json +1 -1
- package/src/agents/maintainer/AGENT.md +0 -2
- package/src/agents/reviewer/AGENT.md +9 -13
- package/src/agents/reviewer/agent.json +1 -1
- package/src/agents/security/AGENT.md +14 -0
- package/src/agents/security/agent.json +6 -0
- package/src/agents/worker/AGENT.md +8 -8
- package/src/agents/worker/agent.json +1 -1
- package/src/agents/writer/AGENT.md +14 -0
- package/src/agents/writer/agent.json +6 -0
- package/src/defaults/skills/setup/SKILL.md +18 -27
- package/src/headless-exec.mjs +3 -10
- package/src/headless-exec.test.mjs +2 -7
- package/src/rules/agent/00-common.md +4 -7
- package/src/rules/lead/01-general.md +0 -3
- package/src/rules/shared/10-tool-workflow.md +10 -2
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +183 -26
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.test.mjs +378 -0
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +4 -0
- package/src/runtime/agent/orchestrator/cache-break-trace.mjs +109 -0
- package/src/runtime/agent/orchestrator/cache-break-trace.test.mjs +115 -0
- package/src/runtime/agent/orchestrator/config.mjs +13 -68
- package/src/runtime/agent/orchestrator/context/collect-skills.test.mjs +153 -0
- package/src/runtime/agent/orchestrator/context/collect.mjs +49 -45
- package/src/runtime/agent/orchestrator/mcp/client.mjs +242 -15
- package/src/runtime/agent/orchestrator/mcp/features.test.mjs +66 -0
- package/src/runtime/agent/orchestrator/mcp/security.test.mjs +36 -20
- package/src/runtime/agent/orchestrator/providers/admission-scheduler-metrics.test.mjs +47 -0
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +16 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +54 -33
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +3 -8
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +19 -3
- package/src/runtime/agent/orchestrator/providers/lib/provider-replay.mjs +50 -0
- package/src/runtime/agent/orchestrator/providers/lib/sse-framing.mjs +93 -0
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +30 -9
- package/src/runtime/agent/orchestrator/providers/media-parity.test.mjs +59 -0
- package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +3 -3
- package/src/runtime/agent/orchestrator/providers/openai-codex-identity.test.mjs +71 -0
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +18 -26
- package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +25 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +35 -4
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +47 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +103 -12
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +13 -0
- package/src/runtime/agent/orchestrator/providers/openai-turn-state.mjs +68 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta-parity.test.mjs +122 -6
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +36 -11
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +144 -93
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +18 -13
- package/src/runtime/agent/orchestrator/providers/provider-replay.test.mjs +288 -0
- package/src/runtime/agent/orchestrator/providers/sse-framing.test.mjs +719 -0
- package/src/runtime/agent/orchestrator/providers/stream-json-pool.mjs +399 -39
- package/src/runtime/agent/orchestrator/providers/stream-json-worker.mjs +26 -0
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +86 -7
- package/src/runtime/agent/orchestrator/session/agent-loop.test.mjs +222 -0
- package/src/runtime/agent/orchestrator/session/browser-snapshot-supersession.mjs +61 -0
- package/src/runtime/agent/orchestrator/session/browser-snapshot-supersession.test.mjs +83 -0
- package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +26 -2
- package/src/runtime/agent/orchestrator/session/compact-policy.test.mjs +112 -0
- package/src/runtime/agent/orchestrator/session/compaction-read-reset.test.mjs +192 -0
- package/src/runtime/agent/orchestrator/session/context-usage-restart.test.mjs +72 -0
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +100 -15
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +17 -1
- package/src/runtime/agent/orchestrator/session/eager-dispatch.test.mjs +74 -0
- package/src/runtime/agent/orchestrator/session/image-strip-recovery.mjs +12 -8
- package/src/runtime/agent/orchestrator/session/image-strip-recovery.test.mjs +20 -1
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +110 -2
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +3 -16
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.test.mjs +28 -0
- package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +111 -39
- package/src/runtime/agent/orchestrator/session/manager/ask-session.test.mjs +46 -0
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +30 -6
- package/src/runtime/agent/orchestrator/session/manager/message-sanitize.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +27 -3
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +26 -54
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.test.mjs +63 -1
- package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -110
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +580 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.test.mjs +593 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +119 -190
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +115 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +43 -8
- package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +129 -12
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +9 -2
- package/src/runtime/agent/orchestrator/session/store/listing.mjs +8 -1
- package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +15 -1
- package/src/runtime/agent/orchestrator/session/store-live-publication.test.mjs +83 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +36 -2
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +157 -30
- package/src/runtime/agent/orchestrator/session/store-summary-reader.test.mjs +64 -0
- package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +57 -0
- package/src/runtime/agent/orchestrator/session/store-summary-visibility.test.mjs +219 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +26 -2
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +22 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool-cwd-env.test.mjs +14 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +19 -10
- package/src/runtime/agent/orchestrator/tools/builtin/find-search-budget.test.mjs +30 -14
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +15 -4
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +73 -15
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.test.mjs +76 -2
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +24 -683
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +64 -72
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-runner.mjs +2 -5
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-transport.mjs +75 -0
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-transport.test.mjs +24 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +6 -6
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +12 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +4 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +24 -5
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.test.mjs +44 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +12 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +35 -21
- package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +28 -13
- package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.test.mjs +54 -0
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +11 -11
- package/src/runtime/agent/orchestrator/tools/patch-manifest.json +11 -11
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +12 -0
- package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +11 -11
- package/src/runtime/attachments/pdf-extract.mjs +3 -0
- package/src/runtime/attachments/pdfjs-runtime.mjs +13 -0
- package/src/runtime/bridge-clients.test.mjs +827 -0
- package/src/runtime/browser-bridge/action-schema.mjs +251 -0
- package/src/runtime/browser-bridge/client.mjs +152 -0
- package/src/runtime/browser-bridge/tool-defs.mjs +159 -0
- package/src/runtime/computer-bridge/action-schema.mjs +653 -0
- package/src/runtime/computer-bridge/client.mjs +231 -0
- package/src/runtime/computer-bridge/tool-defs.mjs +33 -0
- package/src/runtime/media/store.mjs +18 -8
- package/src/runtime/media/store.test.mjs +14 -0
- package/src/runtime/memory/index.mjs +1 -1
- package/src/runtime/memory/lib/transcript-ingest.mjs +8 -6
- package/src/runtime/memory/lib/transcript-ingest.test.mjs +52 -0
- package/src/runtime/office/assurance-benchmark.mjs +358 -0
- package/src/runtime/office/assurance.mjs +833 -0
- package/src/runtime/office/benchmark.mjs +496 -0
- package/src/runtime/office/capabilities.mjs +551 -0
- package/src/runtime/office/com-adapter.mjs +283 -0
- package/src/runtime/office/content-model.mjs +183 -0
- package/src/runtime/office/contract-benchmark.mjs +105 -0
- package/src/runtime/office/design-library.mjs +1562 -0
- package/src/runtime/office/design-system.mjs +1966 -0
- package/src/runtime/office/index.mjs +2413 -0
- package/src/runtime/office/journal.mjs +82 -0
- package/src/runtime/office/office-assurance.test.mjs +371 -0
- package/src/runtime/office/office-com-host.ps1 +3781 -0
- package/src/runtime/office/office-com-session-host.ps1 +855 -0
- package/src/runtime/office/office-live-runtime.test.mjs +819 -0
- package/src/runtime/office/office-runtime.test.mjs +2070 -0
- package/src/runtime/office/ooxml-validator.mjs +271 -0
- package/src/runtime/office/pagination.mjs +132 -0
- package/src/runtime/office/pdf-adapter.mjs +591 -0
- package/src/runtime/office/pdf-analysis.mjs +372 -0
- package/src/runtime/office/pdf-render.mjs +167 -0
- package/src/runtime/office/pdf-security.mjs +63 -0
- package/src/runtime/office/polish-benchmark.mjs +190 -0
- package/src/runtime/office/portable-ooxml.mjs +1867 -0
- package/src/runtime/office/quality-live-benchmark.mjs +486 -0
- package/src/runtime/office/quality-pipeline.mjs +136 -0
- package/src/runtime/office/tabular.mjs +302 -0
- package/src/runtime/office/templates/mixdog-executive.pptx +0 -0
- package/src/runtime/office/templates/mixdog-executive.pptx.mixdog.json +190 -0
- package/src/runtime/office/tool-defs.mjs +113 -0
- package/src/runtime/office/visual-diff.mjs +89 -0
- package/src/runtime/office/xlsx-assertions.mjs +172 -0
- package/src/runtime/office/xlsx-contract.mjs +147 -0
- package/src/runtime/shared/agent-route-config.mjs +9 -0
- package/src/runtime/shared/child-spawn-gate.mjs +17 -0
- package/src/runtime/shared/child-spawn-remote.mjs +69 -7
- package/src/runtime/shared/child-spawn-remote.test.mjs +124 -0
- package/src/runtime/shared/pristine-execution-contract.json +2 -1
- package/src/runtime/shared/provider-api-key.mjs +1 -0
- package/src/runtime/shared/session-runtime-health.mjs +91 -0
- package/src/runtime/shared/session-runtime-health.test.mjs +53 -0
- package/src/runtime/shared/skill-document.mjs +86 -0
- package/src/runtime/shared/skill-document.test.mjs +81 -0
- package/src/runtime/shared/tool-execution-contract.mjs +16 -0
- package/src/runtime/shared/tool-surface.mjs +27 -0
- package/src/runtime/shared/turn-snapshot-store.mjs +1 -0
- package/src/runtime/shared/turn-snapshot.mjs +32 -9
- package/src/runtime/shared/user-cwd.mjs +33 -14
- package/src/runtime/shared/user-cwd.test.mjs +43 -0
- package/src/session-runtime/agent-disable.test.mjs +20 -1
- package/src/session-runtime/context-status.mjs +9 -3
- package/src/session-runtime/cwd-plugins.mjs +26 -26
- package/src/session-runtime/cwd-plugins.test.mjs +75 -0
- package/src/session-runtime/cwd-tool-routing.test.mjs +5 -0
- package/src/session-runtime/deferred-tool-delta.mjs +104 -0
- package/src/session-runtime/deferred-tool-delta.test.mjs +40 -0
- package/src/session-runtime/global-extensions.mjs +26 -0
- package/src/session-runtime/global-extensions.test.mjs +28 -0
- package/src/session-runtime/global-settings-session-identity.test.mjs +76 -0
- package/src/session-runtime/goal-runtime.mjs +1141 -0
- package/src/session-runtime/goal-runtime.test.mjs +645 -0
- package/src/session-runtime/lifecycle-api.mjs +58 -11
- package/src/session-runtime/lifecycle-api.test.mjs +183 -0
- package/src/session-runtime/mcp-glue.mjs +49 -47
- package/src/session-runtime/plugin-mcp-standard.test.mjs +177 -0
- package/src/session-runtime/plugin-mcp.mjs +96 -22
- package/src/session-runtime/prewarm.mjs +1 -10
- package/src/session-runtime/provider-request-snapshot.mjs +33 -9
- package/src/session-runtime/provider-request-snapshot.test.mjs +27 -5
- package/src/session-runtime/resource-api-global.test.mjs +109 -0
- package/src/session-runtime/resource-api.mjs +168 -116
- package/src/session-runtime/runtime-core.mjs +208 -29
- package/src/session-runtime/runtime-tunables.mjs +6 -8
- package/src/session-runtime/session-lifecycle.mjs +34 -12
- package/src/session-runtime/session-title.mjs +2 -2
- package/src/session-runtime/session-turn-api.mjs +37 -25
- package/src/session-runtime/skills-api.mjs +79 -25
- package/src/session-runtime/skills-api.test.mjs +99 -0
- package/src/session-runtime/tool-catalog-data.mjs +1 -1
- package/src/session-runtime/tool-catalog-schema.mjs +0 -5
- package/src/session-runtime/tool-catalog.mjs +42 -112
- package/src/session-runtime/tool-defs.mjs +6 -1
- package/src/session-runtime/tool-policy-surface.test.mjs +93 -17
- package/src/session-runtime/tool-surface.mjs +30 -8
- package/src/session-runtime/workflow-agents-api.mjs +8 -25
- package/src/session-runtime/workflow.mjs +8 -6
- package/src/standalone/agent-dispatch-broker.mjs +5 -9
- package/src/standalone/agent-tool/helpers.mjs +2 -2
- package/src/standalone/agent-tool/job-views.mjs +3 -1
- package/src/standalone/agent-tool/notify.mjs +11 -9
- package/src/standalone/agent-tool/notify.test.mjs +37 -0
- package/src/standalone/agent-tool/render.mjs +3 -0
- package/src/standalone/agent-tool/spawn-flow.mjs +61 -16
- package/src/standalone/agent-tool/spawn-flow.test.mjs +41 -0
- package/src/standalone/agent-tool/tool-def.mjs +1 -1
- package/src/standalone/agent-tool/worker-index.mjs +123 -0
- package/src/standalone/agent-tool/worker-index.test.mjs +132 -0
- package/src/standalone/agent-tool/worker-rows.mjs +2 -1
- package/src/standalone/agent-tool.mjs +57 -10
- package/src/standalone/daemon.mjs +113 -15
- package/src/standalone/hook-bus/config.mjs +1 -0
- package/src/standalone/plugin-admin.mjs +17 -0
- package/src/standalone/plugin-admin.test.mjs +7 -0
- package/src/standalone/provider-admin.mjs +1 -0
- package/src/standalone/session-protocol.mjs +5 -0
- package/src/standalone/session-runtime-agent-control-client.mjs +133 -0
- package/src/standalone/session-runtime-agent-control-client.test.mjs +71 -0
- package/src/standalone/session-runtime-dispatch-cancel.test.mjs +139 -0
- package/src/standalone/session-runtime-host-factory.mjs +17 -0
- package/src/standalone/session-runtime-host-factory.test.mjs +31 -0
- package/src/standalone/session-runtime-host-health.test.mjs +5 -0
- package/src/standalone/session-runtime-host.mjs +709 -58
- package/src/standalone/session-runtime-inline-host.mjs +258 -0
- package/src/standalone/session-runtime-inline-host.test.mjs +385 -0
- package/src/standalone/session-runtime-provider-cooldown.mjs +78 -0
- package/src/standalone/session-runtime-provider-cooldown.test.mjs +80 -0
- package/src/standalone/session-runtime-shard-host.test.mjs +642 -0
- package/src/standalone/session-runtime-shard-router.mjs +149 -0
- package/src/standalone/session-runtime-shard-router.test.mjs +101 -0
- package/src/standalone/session-runtime-worker.mjs +302 -26
- package/src/standalone/session-service-agent-tree.test.mjs +984 -0
- package/src/standalone/session-service-goal-recovery.test.mjs +177 -0
- package/src/standalone/session-service.mjs +711 -11
- package/src/tui/app/app-view.jsx +1 -0
- package/src/tui/app/core-memory-picker.mjs +2 -0
- package/src/tui/app/extension-pickers.mjs +1 -1
- package/src/tui/app/maintenance-pickers.mjs +3 -3
- package/src/tui/app/model-options.mjs +2 -0
- package/src/tui/app/model-picker.mjs +14 -4
- package/src/tui/app/panel-handoff.test.mjs +311 -0
- package/src/tui/app/project-picker.mjs +1 -0
- package/src/tui/app/route-pickers.mjs +21 -6
- package/src/tui/app/settings-picker.mjs +26 -3
- package/src/tui/app/slash-commands.mjs +1 -0
- package/src/tui/app/slash-dispatch.mjs +73 -22
- package/src/tui/app/theme-effort-pickers.mjs +7 -2
- package/src/tui/components/Picker.jsx +10 -1
- package/src/tui/dist/index.mjs +187 -45
- package/src/tui/lib/voice-setup.mjs +4 -1
- package/src/tui/session/agent-message-source.test.mjs +37 -0
- package/src/tui/session/completion-card-restore.test.mjs +50 -0
- package/src/tui/session/context-state.mjs +3 -13
- package/src/tui/session/goal-continuation.mjs +141 -0
- package/src/tui/session/goal-continuation.test.mjs +203 -0
- package/src/tui/session/queue-helpers.mjs +5 -2
- package/src/tui/session/session-action-surface.test.mjs +190 -0
- package/src/tui/session/session-api-ext.mjs +48 -8
- package/src/tui/session/session-api.mjs +73 -1
- package/src/tui/session/session-flow.mjs +31 -1
- package/src/tui/session/turn.mjs +88 -15
- package/src/tui/session-local.mjs +39 -3
- package/src/vendor/statusline/src/gateway/route-meta.mjs +31 -0
- package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +0 -301
|
@@ -13,6 +13,12 @@ import {
|
|
|
13
13
|
_withCodexWsClientMetadata,
|
|
14
14
|
} from './openai-codex-metadata.mjs';
|
|
15
15
|
import { codexOriginator, codexUserAgent } from './codex-client-meta.mjs';
|
|
16
|
+
import { _captureTurnStateFromEvent } from './openai-ws-stream.mjs';
|
|
17
|
+
import { _buildOpenAIHttpFallbackHeaders } from './openai-oauth-http-sse.mjs';
|
|
18
|
+
import {
|
|
19
|
+
_clearCodexTurnStatesForTest,
|
|
20
|
+
retireCodexTurnStateOwner,
|
|
21
|
+
} from './openai-turn-state.mjs';
|
|
16
22
|
|
|
17
23
|
test('Codex wire identity is a real time-based UUIDv7 and remains session-stable', () => {
|
|
18
24
|
const now = Date.now();
|
|
@@ -151,3 +157,68 @@ test('compaction shares the session identity and cache slot with its turns', ()
|
|
|
151
157
|
assert.equal(turnMetadata.session_id, turn.codexSessionId);
|
|
152
158
|
assert.equal(turnMetadata.thread_id, turn.codexThreadId);
|
|
153
159
|
});
|
|
160
|
+
|
|
161
|
+
test('Codex turn state follows the logical turn across WS reconnect and HTTP fallback', (t) => {
|
|
162
|
+
_clearCodexTurnStatesForTest();
|
|
163
|
+
t.after(_clearCodexTurnStatesForTest);
|
|
164
|
+
const poolKey = 'turn-state-parity-session';
|
|
165
|
+
const cacheKey = mintUuidV7();
|
|
166
|
+
const turnId = mintUuidV7();
|
|
167
|
+
const nextTurnId = mintUuidV7();
|
|
168
|
+
const context = {
|
|
169
|
+
poolKey,
|
|
170
|
+
cacheKey,
|
|
171
|
+
sendOpts: { turnId },
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const firstEntry = {};
|
|
175
|
+
const firstFrame = _withCodexWsClientMetadata({}, firstEntry, true, context);
|
|
176
|
+
assert.equal(firstFrame.client_metadata['x-codex-turn-state'], undefined);
|
|
177
|
+
|
|
178
|
+
_captureTurnStateFromEvent(firstEntry, {
|
|
179
|
+
type: 'response.metadata',
|
|
180
|
+
headers: { 'x-codex-turn-state': 'ts-first' },
|
|
181
|
+
});
|
|
182
|
+
_captureTurnStateFromEvent(firstEntry, {
|
|
183
|
+
type: 'response.metadata',
|
|
184
|
+
headers: { 'x-codex-turn-state': 'ts-later' },
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const siblingEntry = {};
|
|
188
|
+
const siblingFrame = _withCodexWsClientMetadata({}, siblingEntry, true, context);
|
|
189
|
+
assert.equal(siblingFrame.client_metadata['x-codex-turn-state'], undefined);
|
|
190
|
+
|
|
191
|
+
const httpHeaders = _buildOpenAIHttpFallbackHeaders({
|
|
192
|
+
auth: { type: 'openai-oauth', access_token: 'token', account_id: 'account' },
|
|
193
|
+
cacheKey,
|
|
194
|
+
poolKey,
|
|
195
|
+
turnId,
|
|
196
|
+
});
|
|
197
|
+
assert.equal(httpHeaders['x-codex-turn-state'], 'ts-first');
|
|
198
|
+
|
|
199
|
+
retireCodexTurnStateOwner(poolKey, firstEntry);
|
|
200
|
+
const reconnectEntry = {};
|
|
201
|
+
const reconnectFrame = _withCodexWsClientMetadata({}, reconnectEntry, true, context);
|
|
202
|
+
assert.equal(reconnectFrame.client_metadata['x-codex-turn-state'], 'ts-first');
|
|
203
|
+
|
|
204
|
+
const nextTurnFrame = _withCodexWsClientMetadata({}, reconnectEntry, true, {
|
|
205
|
+
...context,
|
|
206
|
+
sendOpts: { turnId: nextTurnId },
|
|
207
|
+
});
|
|
208
|
+
assert.equal(nextTurnFrame.client_metadata['x-codex-turn-state'], undefined);
|
|
209
|
+
const nextTurnHttpHeaders = _buildOpenAIHttpFallbackHeaders({
|
|
210
|
+
auth: { type: 'openai-oauth', access_token: 'token', account_id: 'account' },
|
|
211
|
+
cacheKey,
|
|
212
|
+
poolKey,
|
|
213
|
+
turnId: nextTurnId,
|
|
214
|
+
});
|
|
215
|
+
assert.equal(nextTurnHttpHeaders['x-codex-turn-state'], undefined);
|
|
216
|
+
|
|
217
|
+
const directHeaders = _buildOpenAIHttpFallbackHeaders({
|
|
218
|
+
auth: { type: 'openai-direct', apiKey: 'key' },
|
|
219
|
+
cacheKey,
|
|
220
|
+
poolKey,
|
|
221
|
+
turnId,
|
|
222
|
+
});
|
|
223
|
+
assert.equal(directHeaders['x-codex-turn-state'], undefined);
|
|
224
|
+
});
|
|
@@ -6,6 +6,7 @@ import { createHash, randomUUID } from 'crypto';
|
|
|
6
6
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
7
7
|
import { join } from 'path';
|
|
8
8
|
import { getPluginData } from '../config.mjs';
|
|
9
|
+
import { activateCodexTurnState } from './openai-turn-state.mjs';
|
|
9
10
|
|
|
10
11
|
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
11
12
|
let _installationId = null;
|
|
@@ -206,39 +207,30 @@ export function _codexWsCompatibilityHeaders(context = {}) {
|
|
|
206
207
|
export function _withCodexWsClientMetadata(frame, entry, enabled, context = {}) {
|
|
207
208
|
if (!enabled || !frame || typeof frame !== 'object') return frame;
|
|
208
209
|
const base = _codexMetadataBase(entry, context);
|
|
209
|
-
const
|
|
210
|
-
|
|
210
|
+
const explicitLogicalTurnId = _cleanMetaString(
|
|
211
|
+
context?.sendOpts?.turnId
|
|
212
|
+
|| context?.sendOpts?.codexTurnId
|
|
213
|
+
|| context?.sendOpts?.session?.turnId,
|
|
214
|
+
);
|
|
215
|
+
const logicalTurnId = explicitLogicalTurnId
|
|
216
|
+
? _codexUuidV7(explicitLogicalTurnId)
|
|
217
|
+
: base.turn_id;
|
|
218
|
+
const turnStateScope = _cleanMetaString(context?.poolKey);
|
|
211
219
|
const metadata = {
|
|
212
220
|
...base,
|
|
213
221
|
...(frame.client_metadata && typeof frame.client_metadata === 'object' ? frame.client_metadata : {}),
|
|
214
222
|
'x-codex-ws-stream-request-start-ms': String(Date.now()),
|
|
215
223
|
};
|
|
216
224
|
if (entry && typeof entry === 'object') {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
if (entry.turnState) {
|
|
223
|
-
if (entry.turnStateTurnId == null) {
|
|
224
|
-
entry.turnStateTurnId = base.turn_id;
|
|
225
|
-
} else if (entry.turnStateTurnId !== base.turn_id) {
|
|
226
|
-
// Codex startup prewarm owns the handshake turn-state until
|
|
227
|
-
// the first real turn consumes that prewarmed client session.
|
|
228
|
-
// Adopt it once across prewarm→turn; ordinary turn changes
|
|
229
|
-
// still retire the old token.
|
|
230
|
-
if (entry.turnStateFromPrewarm === true && !isPrewarmRequest) {
|
|
231
|
-
entry.turnStateTurnId = base.turn_id;
|
|
232
|
-
} else {
|
|
233
|
-
entry.turnState = null;
|
|
234
|
-
entry.turnStateTurnId = null;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
if (!isPrewarmRequest && entry.turnStateFromPrewarm === true) {
|
|
239
|
-
entry.turnStateFromPrewarm = false;
|
|
225
|
+
const priorTurnId = entry.turnStateTurnId;
|
|
226
|
+
if (turnStateScope && logicalTurnId) {
|
|
227
|
+
entry.turnState = activateCodexTurnState(turnStateScope, logicalTurnId, entry);
|
|
228
|
+
} else if (priorTurnId != null && priorTurnId !== logicalTurnId) {
|
|
229
|
+
entry.turnState = null;
|
|
240
230
|
}
|
|
241
|
-
entry.
|
|
231
|
+
entry.turnStateScope = turnStateScope || null;
|
|
232
|
+
entry.turnStateTurnId = logicalTurnId || null;
|
|
233
|
+
entry.currentTurnId = logicalTurnId || null;
|
|
242
234
|
}
|
|
243
235
|
if (entry?.turnState) metadata['x-codex-turn-state'] = String(entry.turnState);
|
|
244
236
|
return { ...frame, client_metadata: metadata };
|
|
@@ -14,6 +14,14 @@ export const OPENAI_COMPAT_PRESETS = {
|
|
|
14
14
|
baseURL: 'https://opencode.ai/zen/go/v1',
|
|
15
15
|
defaultModel: 'glm-5.2',
|
|
16
16
|
},
|
|
17
|
+
openrouter: {
|
|
18
|
+
baseURL: 'https://openrouter.ai/api/v1',
|
|
19
|
+
defaultModel: 'openrouter/auto',
|
|
20
|
+
extraHeaders: {
|
|
21
|
+
'HTTP-Referer': 'https://github.com/tribgames/mixdog',
|
|
22
|
+
'X-OpenRouter-Title': 'mixdog',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
17
25
|
ollama: {
|
|
18
26
|
baseURL: 'http://localhost:11434/v1',
|
|
19
27
|
defaultModel: 'llama3.3:latest',
|
|
@@ -296,6 +296,7 @@ export async function consumeCompatChatCompletionStream(stream, {
|
|
|
296
296
|
let sawFirstEvent = false;
|
|
297
297
|
let content = '';
|
|
298
298
|
let reasoningContent = '';
|
|
299
|
+
const reasoningDetails = [];
|
|
299
300
|
// Invariant flag for the gateway live-text relay: set once a non-empty
|
|
300
301
|
// text chunk has been forwarded to the client. A failure after this point
|
|
301
302
|
// must be treated as permanent — the rendered text cannot be withdrawn and
|
|
@@ -435,6 +436,10 @@ export async function consumeCompatChatCompletionStream(stream, {
|
|
|
435
436
|
// use reasoning, and some local compatibility shims expose
|
|
436
437
|
// thinking. They are aliases, never concatenate multiple aliases
|
|
437
438
|
// from the same chunk.
|
|
439
|
+
if (Array.isArray(choice?.delta?.reasoning_details) && choice.delta.reasoning_details.length) {
|
|
440
|
+
reasoningDetails.push(...choice.delta.reasoning_details);
|
|
441
|
+
reportProgress('reasoning');
|
|
442
|
+
}
|
|
438
443
|
const reasoningDelta = typeof choice?.delta?.reasoning_content === 'string'
|
|
439
444
|
? choice.delta.reasoning_content
|
|
440
445
|
: typeof choice?.delta?.reasoning === 'string'
|
|
@@ -513,6 +518,7 @@ export async function consumeCompatChatCompletionStream(stream, {
|
|
|
513
518
|
const message = {
|
|
514
519
|
content: content || null,
|
|
515
520
|
...(reasoningContent ? { reasoning_content: reasoningContent } : {}),
|
|
521
|
+
...(reasoningDetails.length ? { reasoning_details: reasoningDetails } : {}),
|
|
516
522
|
};
|
|
517
523
|
const rawToolCalls = [...toolAcc.values()]
|
|
518
524
|
.sort((a, b) => a._order - b._order)
|
|
@@ -557,6 +563,7 @@ export async function consumeCompatChatCompletionStream(stream, {
|
|
|
557
563
|
toolCalls,
|
|
558
564
|
stopReason,
|
|
559
565
|
reasoningContent: reasoningContent || null,
|
|
566
|
+
reasoningDetails: reasoningDetails.length ? reasoningDetails : null,
|
|
560
567
|
rawUsage,
|
|
561
568
|
};
|
|
562
569
|
}
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
import {
|
|
21
21
|
customToolCallFromResponseItem,
|
|
22
22
|
} from './custom-tool-wire.mjs';
|
|
23
|
+
import { providerReplayItems } from './lib/provider-replay.mjs';
|
|
23
24
|
|
|
24
25
|
export function positiveTokenInt(value) {
|
|
25
26
|
const n = Number(value);
|
|
@@ -56,6 +57,12 @@ export function toOpenAIMessages(messages, providerName, options = {}) {
|
|
|
56
57
|
|| providerName === 'xai';
|
|
57
58
|
const out = [];
|
|
58
59
|
const pendingToolMedia = [];
|
|
60
|
+
const openRouterReasoningDetails = (message) => {
|
|
61
|
+
if (providerName !== 'openrouter') return null;
|
|
62
|
+
const metadata = message?.providerMetadata?.openrouter;
|
|
63
|
+
const details = metadata?.reasoning_details ?? metadata?.reasoningDetails;
|
|
64
|
+
return Array.isArray(details) && details.length ? details : null;
|
|
65
|
+
};
|
|
59
66
|
const flushToolMedia = () => {
|
|
60
67
|
if (!pendingToolMedia.length) return;
|
|
61
68
|
out.push({ role: 'user', content: pendingToolMedia.splice(0) });
|
|
@@ -83,11 +90,20 @@ export function toOpenAIMessages(messages, providerName, options = {}) {
|
|
|
83
90
|
})),
|
|
84
91
|
};
|
|
85
92
|
if (replaysReasoningContent && m.reasoningContent) msg.reasoning_content = m.reasoningContent;
|
|
93
|
+
const reasoningDetails = openRouterReasoningDetails(m);
|
|
94
|
+
if (reasoningDetails) msg.reasoning_details = reasoningDetails;
|
|
86
95
|
out.push(msg);
|
|
87
96
|
continue;
|
|
88
97
|
}
|
|
89
|
-
|
|
90
|
-
|
|
98
|
+
const reasoningDetails = m.role === 'assistant' ? openRouterReasoningDetails(m) : null;
|
|
99
|
+
if (m.role === 'assistant' && ((replaysReasoningContent && m.reasoningContent) || reasoningDetails)) {
|
|
100
|
+
const msg = {
|
|
101
|
+
role: m.role,
|
|
102
|
+
content: normalizeContentForOpenAIChat(m.content, { role: 'assistant' }),
|
|
103
|
+
};
|
|
104
|
+
if (replaysReasoningContent && m.reasoningContent) msg.reasoning_content = m.reasoningContent;
|
|
105
|
+
if (reasoningDetails) msg.reasoning_details = reasoningDetails;
|
|
106
|
+
out.push(msg);
|
|
91
107
|
continue;
|
|
92
108
|
}
|
|
93
109
|
out.push({ role: m.role, content: normalizeContentForOpenAIChat(m.content, { role: m.role }) });
|
|
@@ -392,6 +408,13 @@ export function toXaiResponsesInput(messages, providerState, options = {}) {
|
|
|
392
408
|
const m = messages[messageIndex];
|
|
393
409
|
if (!includeSystem && m.role === 'system') continue;
|
|
394
410
|
if (m.role !== 'tool') flushToolMedia();
|
|
411
|
+
const orderedReplay = m.role === 'assistant'
|
|
412
|
+
? providerReplayItems(m, 'xai-responses')
|
|
413
|
+
: undefined;
|
|
414
|
+
if (orderedReplay?.length) {
|
|
415
|
+
input.push(...orderedReplay);
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
395
418
|
const reasoningItems = reasoningByMessageIndex.get(messageIndex);
|
|
396
419
|
if (reasoningItems) input.push(...reasoningItems);
|
|
397
420
|
if (dropToolHistory && m.role === 'tool') continue;
|
|
@@ -64,6 +64,7 @@ import {
|
|
|
64
64
|
writeXaiResponsesCacheTrace,
|
|
65
65
|
} from './openai-compat-xai.mjs';
|
|
66
66
|
import { envFlag as _envFlag } from './lib/env-utils.mjs';
|
|
67
|
+
import { createProviderReplay } from './lib/provider-replay.mjs';
|
|
67
68
|
|
|
68
69
|
const requireOpenAI = createRequire(import.meta.url);
|
|
69
70
|
let _OpenAI = null;
|
|
@@ -168,10 +169,33 @@ function normalizeReasoningEffort(value, allowed) {
|
|
|
168
169
|
return allowed.includes(effort) ? effort : null;
|
|
169
170
|
}
|
|
170
171
|
|
|
172
|
+
export function compatReportedCostUsd(providerName, usage) {
|
|
173
|
+
if (providerName === 'openrouter') {
|
|
174
|
+
const cost = Number(usage?.cost);
|
|
175
|
+
return Number.isFinite(cost) && cost >= 0 ? cost : undefined;
|
|
176
|
+
}
|
|
177
|
+
if (providerName === 'xai') {
|
|
178
|
+
const ticks = Number(usage?.cost_in_usd_ticks);
|
|
179
|
+
return Number.isFinite(ticks) && ticks >= 0
|
|
180
|
+
? Number((ticks * 1e-10).toFixed(8))
|
|
181
|
+
: undefined;
|
|
182
|
+
}
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
|
|
171
186
|
// Keep provider extensions isolated: fields accepted by one OpenAI-compatible
|
|
172
187
|
// backend are frequently rejected by another even when the core Chat schema is
|
|
173
188
|
// shared.
|
|
174
189
|
export function applyCompatProviderChatOptions(params, providerName, opts = {}, config = {}, modelInfo = null) {
|
|
190
|
+
if (providerName === 'openrouter') {
|
|
191
|
+
const effort = normalizeReasoningEffort(
|
|
192
|
+
opts.openRouterReasoningEffort ?? opts.effort ?? config?.reasoningEffort,
|
|
193
|
+
['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'],
|
|
194
|
+
);
|
|
195
|
+
if (effort === 'none') params.reasoning = { enabled: false };
|
|
196
|
+
else if (effort) params.reasoning = { enabled: true, effort };
|
|
197
|
+
return params;
|
|
198
|
+
}
|
|
175
199
|
if (providerName === 'xai') {
|
|
176
200
|
const reasoningEffort = normalizeXaiReasoningEffort(opts.xaiReasoningEffort
|
|
177
201
|
?? opts.effort
|
|
@@ -594,6 +618,9 @@ export class OpenAICompatProvider {
|
|
|
594
618
|
const reasoningContent = (capturesReasoningContent && typeof assembled.reasoningContent === 'string')
|
|
595
619
|
? assembled.reasoningContent
|
|
596
620
|
: null;
|
|
621
|
+
const reasoningDetails = this.name === 'openrouter' && Array.isArray(choice?.message?.reasoning_details)
|
|
622
|
+
? choice.message.reasoning_details
|
|
623
|
+
: null;
|
|
597
624
|
return {
|
|
598
625
|
content: assembled.content || '',
|
|
599
626
|
// Streamed chunks can omit `model`; fall back to the requested
|
|
@@ -609,6 +636,9 @@ export class OpenAICompatProvider {
|
|
|
609
636
|
// instead of silently treating a truncated answer as complete.
|
|
610
637
|
...(stopReason === 'length' && (assembled.content || '').length > 0 ? { truncated: true } : {}),
|
|
611
638
|
...(reasoningContent ? { reasoningContent } : {}),
|
|
639
|
+
...(reasoningDetails?.length ? {
|
|
640
|
+
providerMetadata: { openrouter: { reasoning_details: reasoningDetails } },
|
|
641
|
+
} : {}),
|
|
612
642
|
usage: response.usage ? (() => {
|
|
613
643
|
const input = response.usage.prompt_tokens ?? response.usage.input_tokens ?? 0;
|
|
614
644
|
const cached = extractCompatCachedTokens(response.usage);
|
|
@@ -616,10 +646,7 @@ export class OpenAICompatProvider {
|
|
|
616
646
|
// (1 tick = $1e-10, per docs.x.ai). Surface it as costUsd so the
|
|
617
647
|
// session manager skips the catalog-rate fallback and records the
|
|
618
648
|
// provider-billed value verbatim.
|
|
619
|
-
const
|
|
620
|
-
const costUsd = typeof ticks === 'number' && ticks >= 0
|
|
621
|
-
? Number((ticks * 1e-10).toFixed(8))
|
|
622
|
-
: undefined;
|
|
649
|
+
const costUsd = compatReportedCostUsd(this.name, response.usage);
|
|
623
650
|
return {
|
|
624
651
|
inputTokens: input,
|
|
625
652
|
outputTokens: response.usage.completion_tokens ?? response.usage.output_tokens ?? 0,
|
|
@@ -884,6 +911,7 @@ export class OpenAICompatProvider {
|
|
|
884
911
|
// any rejection as a provider-side drop.)
|
|
885
912
|
const nextPreviousResponseId = response.id;
|
|
886
913
|
const encryptedReasoningItems = encryptedXaiReasoningItems(response.output);
|
|
914
|
+
const providerReplay = createProviderReplay('xai-responses', response.output);
|
|
887
915
|
const encryptedReasoningHistory = [
|
|
888
916
|
...(Array.isArray(opts.providerState?.xaiResponses?.encryptedReasoningHistory)
|
|
889
917
|
? opts.providerState.xaiResponses.encryptedReasoningHistory
|
|
@@ -904,6 +932,7 @@ export class OpenAICompatProvider {
|
|
|
904
932
|
...(streamed.stopReason === 'length' && (streamed.content || '').length > 0 ? { truncated: true } : {}),
|
|
905
933
|
citations: searchSources.citations.length ? searchSources.citations : undefined,
|
|
906
934
|
webSearchCalls: searchSources.webSearchCalls.length ? searchSources.webSearchCalls : undefined,
|
|
935
|
+
providerReplay,
|
|
907
936
|
providerState: {
|
|
908
937
|
...(opts.providerState || {}),
|
|
909
938
|
xaiResponses: {
|
|
@@ -1022,6 +1051,7 @@ export class OpenAICompatProvider {
|
|
|
1022
1051
|
// Same rationale as the HTTP path above: `length` stop keeps the chain.
|
|
1023
1052
|
const nextPreviousResponseId = responseId;
|
|
1024
1053
|
const encryptedReasoningItems = encryptedXaiReasoningItems(result.responseItems);
|
|
1054
|
+
const providerReplay = createProviderReplay('xai-responses', result.responseItems);
|
|
1025
1055
|
const encryptedReasoningHistory = [
|
|
1026
1056
|
...(Array.isArray(opts.providerState?.xaiResponses?.encryptedReasoningHistory)
|
|
1027
1057
|
? opts.providerState.xaiResponses.encryptedReasoningHistory
|
|
@@ -1080,6 +1110,7 @@ export class OpenAICompatProvider {
|
|
|
1080
1110
|
// P1 audit fix: same truncated signal as the HTTP path (see
|
|
1081
1111
|
// _doSendXaiResponses above) for the WebSocket transport.
|
|
1082
1112
|
...(result.stopReason === 'length' && (result.content || '').length > 0 ? { truncated: true } : {}),
|
|
1113
|
+
providerReplay,
|
|
1083
1114
|
providerState: {
|
|
1084
1115
|
...(opts.providerState || {}),
|
|
1085
1116
|
xaiResponses: {
|
|
@@ -38,8 +38,13 @@ import { createLeakGuard, createToolCallDedupe, dedupeToolCallList } from './ant
|
|
|
38
38
|
import { customToolCallFromResponseItem } from './custom-tool-wire.mjs';
|
|
39
39
|
import { CODEX_OAUTH_ORIGINATOR, CODEX_RESPONSES_URL, _displayCodexModel } from './openai-oauth.mjs';
|
|
40
40
|
import { createActiveToolItemTracker } from './tool-stream-state.mjs';
|
|
41
|
+
import { createProviderReplay } from './lib/provider-replay.mjs';
|
|
41
42
|
import { parseProviderJsonBatch } from './stream-json-pool.mjs';
|
|
42
43
|
import { envFlag as _envFlag } from './lib/env-utils.mjs';
|
|
44
|
+
import {
|
|
45
|
+
activateCodexTurnState,
|
|
46
|
+
captureCodexTurnState,
|
|
47
|
+
} from './openai-turn-state.mjs';
|
|
43
48
|
export { envPositiveInt as _envPositiveInt } from './lib/env-utils.mjs';
|
|
44
49
|
export { _envFlag };
|
|
45
50
|
|
|
@@ -163,7 +168,13 @@ function _pushOutputTextAnnotations(part, citations, citationKeys) {
|
|
|
163
168
|
}
|
|
164
169
|
}
|
|
165
170
|
|
|
166
|
-
function _buildOpenAIHttpFallbackHeaders({
|
|
171
|
+
export function _buildOpenAIHttpFallbackHeaders({
|
|
172
|
+
auth,
|
|
173
|
+
cacheKey,
|
|
174
|
+
statelessConversation = false,
|
|
175
|
+
poolKey = null,
|
|
176
|
+
turnId = null,
|
|
177
|
+
}) {
|
|
167
178
|
if (auth?.type === 'openai-direct') {
|
|
168
179
|
// Public API-key auth: Bearer <OPENAI_API_KEY>, no chatgpt-account-id /
|
|
169
180
|
// originator (mirrors openai-ws-pool _buildHandshakeHeaders' direct
|
|
@@ -194,6 +205,8 @@ function _buildOpenAIHttpFallbackHeaders({ auth, cacheKey, statelessConversation
|
|
|
194
205
|
headers['session-id'] = sid;
|
|
195
206
|
headers['thread-id'] = sid;
|
|
196
207
|
}
|
|
208
|
+
const turnState = activateCodexTurnState(poolKey, turnId);
|
|
209
|
+
if (turnState) headers['x-codex-turn-state'] = turnState;
|
|
197
210
|
return headers;
|
|
198
211
|
}
|
|
199
212
|
|
|
@@ -250,7 +263,14 @@ export async function sendViaHttpSse({
|
|
|
250
263
|
const totalTimeout = createPassthroughSignal(externalSignal);
|
|
251
264
|
const statelessConversation = opts?.statelessConversation === true
|
|
252
265
|
|| _envFlag('MIXDOG_OAI_STATELESS_HTTP', false);
|
|
253
|
-
const
|
|
266
|
+
const turnId = opts?.turnId || opts?.codexTurnId || opts?.session?.turnId || null;
|
|
267
|
+
const headers = _buildOpenAIHttpFallbackHeaders({
|
|
268
|
+
auth,
|
|
269
|
+
cacheKey,
|
|
270
|
+
statelessConversation,
|
|
271
|
+
poolKey,
|
|
272
|
+
turnId,
|
|
273
|
+
});
|
|
254
274
|
const fetchStartedAt = Date.now();
|
|
255
275
|
const responsesUrl = auth?.type === 'openai-direct'
|
|
256
276
|
? OPENAI_DIRECT_RESPONSES_URL
|
|
@@ -379,6 +399,10 @@ export async function sendViaHttpSse({
|
|
|
379
399
|
totalTimeout.cleanup();
|
|
380
400
|
throw err;
|
|
381
401
|
}
|
|
402
|
+
if (auth?.type !== 'openai-direct') {
|
|
403
|
+
const responseTurnState = response.headers?.get?.('x-codex-turn-state');
|
|
404
|
+
if (responseTurnState) captureCodexTurnState(poolKey, turnId, responseTurnState);
|
|
405
|
+
}
|
|
382
406
|
if (!response.body) {
|
|
383
407
|
totalTimeout.cleanup();
|
|
384
408
|
throw Object.assign(new Error('OpenAI OAuth HTTP fallback returned no response body'), { initialResponseError: true });
|
|
@@ -504,6 +528,8 @@ export async function sendViaHttpSse({
|
|
|
504
528
|
const clearActiveToolItem = _toolTracker.clear;
|
|
505
529
|
let _toolInFlight = false;
|
|
506
530
|
const reasoningItems = [];
|
|
531
|
+
const responseItems = [];
|
|
532
|
+
const responseItemKeys = new Set();
|
|
507
533
|
const citations = [];
|
|
508
534
|
const citationKeys = new Set();
|
|
509
535
|
const webSearchCalls = [];
|
|
@@ -663,6 +689,16 @@ export async function sendViaHttpSse({
|
|
|
663
689
|
});
|
|
664
690
|
}
|
|
665
691
|
};
|
|
692
|
+
const pushResponseItem = (item) => {
|
|
693
|
+
if (!item || typeof item !== 'object') return;
|
|
694
|
+
let fallbackKey = '';
|
|
695
|
+
try { fallbackKey = JSON.stringify(item); } catch {}
|
|
696
|
+
const key = `${item.type || 'unknown'}:${item.id || item.call_id || fallbackKey}`;
|
|
697
|
+
if (responseItemKeys.has(key)) return;
|
|
698
|
+
responseItemKeys.add(key);
|
|
699
|
+
try { responseItems.push(structuredClone(item)); }
|
|
700
|
+
catch { responseItems.push({ ...item }); }
|
|
701
|
+
};
|
|
666
702
|
const pushToolSearchCall = (item) => {
|
|
667
703
|
if (!item || item.type !== 'tool_search_call') return;
|
|
668
704
|
const callId = item.call_id || item.id || '';
|
|
@@ -800,6 +836,7 @@ export async function sendViaHttpSse({
|
|
|
800
836
|
break;
|
|
801
837
|
case 'response.output_item.done': {
|
|
802
838
|
const item = event.item || {};
|
|
839
|
+
pushResponseItem(item);
|
|
803
840
|
pushReasoningItem(item);
|
|
804
841
|
pushWebSearchCall(item);
|
|
805
842
|
if (item.type === 'function_call') {
|
|
@@ -852,6 +889,7 @@ export async function sendViaHttpSse({
|
|
|
852
889
|
}
|
|
853
890
|
let reportedBundleProgress = false;
|
|
854
891
|
for (const item of resp.output || []) {
|
|
892
|
+
pushResponseItem(item);
|
|
855
893
|
if (item.type === 'message') {
|
|
856
894
|
for (const part of item.content || []) {
|
|
857
895
|
if (!content && part.type === 'output_text') {
|
|
@@ -1060,6 +1098,11 @@ export async function sendViaHttpSse({
|
|
|
1060
1098
|
// trailing text is never lost (streamed-text path).
|
|
1061
1099
|
flushLeak();
|
|
1062
1100
|
} catch (err) {
|
|
1101
|
+
if (err && !err.partialProviderReplay) {
|
|
1102
|
+
try {
|
|
1103
|
+
err.partialProviderReplay = createProviderReplay('openai-responses', responseItems);
|
|
1104
|
+
} catch {}
|
|
1105
|
+
}
|
|
1063
1106
|
// Live-text invariant: once a non-empty chunk has been relayed it
|
|
1064
1107
|
// cannot be withdrawn — flag the error so no upstream layer retries.
|
|
1065
1108
|
if (emittedText && err) { try { err.liveTextEmitted = true; err.unsafeToRetry = true; } catch {} }
|
|
@@ -1100,6 +1143,7 @@ export async function sendViaHttpSse({
|
|
|
1100
1143
|
try {
|
|
1101
1144
|
err.partialContent = content;
|
|
1102
1145
|
err.partialToolCalls = toolCalls.length ? toolCalls.slice() : undefined;
|
|
1146
|
+
err.partialProviderReplay = createProviderReplay('openai-responses', responseItems);
|
|
1103
1147
|
err.partialModel = model || undefined;
|
|
1104
1148
|
err.pendingToolUse = pendingCalls.size > 0 || activeToolItems.size > 0 || _toolInFlight === true;
|
|
1105
1149
|
} catch { /* best-effort enrichment */ }
|
|
@@ -1141,6 +1185,7 @@ export async function sendViaHttpSse({
|
|
|
1141
1185
|
content,
|
|
1142
1186
|
model: liveModel,
|
|
1143
1187
|
reasoningItems: reasoningItems.length ? reasoningItems : undefined,
|
|
1188
|
+
providerReplay: createProviderReplay('openai-responses', responseItems),
|
|
1144
1189
|
toolCalls: _returnedToolCalls,
|
|
1145
1190
|
citations: citations.length ? citations : undefined,
|
|
1146
1191
|
webSearchCalls: webSearchCalls.length ? webSearchCalls : undefined,
|