mixdog 0.9.147 → 0.9.149
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/package.json +23 -3
- package/scripts/build-voice-runtime-unix.sh +101 -0
- package/scripts/embedding-quality-probe.mjs +96 -0
- package/scripts/generate-voice-runtime-manifest.mjs +300 -0
- package/scripts/generate-voice-runtime-manifest.test.mjs +135 -0
- package/scripts/native-binary-arch.mjs +30 -13
- package/scripts/native-binary-arch.test.mjs +40 -4
- package/scripts/plan-voice-runtime-release.mjs +73 -0
- package/scripts/prepare-native-assets.mjs +50 -9
- package/scripts/prune-embedding-runtime.mjs +3 -3
- package/scripts/sync-voice-runtime-manifest.mjs +46 -0
- package/scripts/verify-release-assets.mjs +106 -6
- package/scripts/verify-voice-runtime-release.mjs +89 -0
- package/scripts/voice-runtime-config.json +52 -0
- package/src/app.mjs +42 -5
- package/src/headless-exec.mjs +58 -32
- package/src/headless-exec.test.mjs +74 -13
- package/src/rules/lead/01-general.md +2 -0
- package/src/rules/shared/10-tool-workflow.md +7 -4
- package/src/rules/shared/30-exploration.md +5 -1
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +28 -9
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +6 -1
- package/src/runtime/agent/orchestrator/config.mjs +53 -18
- package/src/runtime/agent/orchestrator/mcp/cancellation.test.mjs +139 -0
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +34 -5
- package/src/runtime/agent/orchestrator/mcp/client.mjs +94 -10
- package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +5 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +98 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.test.mjs +90 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-leaked-toolcall.mjs +67 -16
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +4 -82
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +0 -5
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +62 -121
- package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +48 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.test.mjs +215 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +44 -48
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +54 -31
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +56 -2
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +34 -2
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +61 -1
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +6 -1
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +61 -15
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +120 -1
- package/src/runtime/agent/orchestrator/providers/lib/env-utils.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/lib/stream-outcome.mjs +0 -3
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +187 -84
- package/src/runtime/agent/orchestrator/providers/openai-codex-identity.test.mjs +32 -9
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +78 -33
- package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +21 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +36 -36
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +16 -6
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +50 -213
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +135 -126
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +20 -11
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +112 -36
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +220 -50
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +112 -9
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +11 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +130 -60
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +28 -10
- package/src/runtime/agent/orchestrator/providers/registry.mjs +122 -95
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +69 -3
- package/src/runtime/agent/orchestrator/providers/tool-stream-state.mjs +4 -22
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +7 -14
- package/src/runtime/agent/orchestrator/session/compact-policy.test.mjs +128 -0
- package/src/runtime/agent/orchestrator/session/context-compaction-policy.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +27 -48
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +19 -14
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +9 -43
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +43 -5
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +15 -2
- package/src/runtime/agent/orchestrator/session/manager/pending-messages-persistence.test.mjs +325 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +599 -195
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +22 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +9 -2
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +26 -16
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +23 -11
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +118 -3
- package/src/runtime/agent/orchestrator/session/store-summary-reader.test.mjs +332 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +38 -1
- package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +27 -6
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +12 -20
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +291 -128
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +46 -9
- package/src/runtime/agent/orchestrator/tools/builtin/edit-encoding-eol.test.mjs +224 -0
- package/src/runtime/agent/orchestrator/tools/builtin/edit-sequential-occupation.test.mjs +53 -3
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +255 -25
- package/src/runtime/agent/orchestrator/tools/builtin/find-search-budget.test.mjs +87 -0
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +132 -9
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.test.mjs +10 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-pattern-fanout.mjs +29 -3
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool-integrity.test.mjs +14 -0
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +180 -31
- package/src/runtime/agent/orchestrator/tools/builtin/local-search-telemetry.mjs +4 -1
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +32 -5
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-health.test.mjs +5 -2
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-runner.mjs +10 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +38 -10
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +12 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +31 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +11 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-windows.mjs +22 -4
- package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +6 -8
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +25 -24
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +152 -133
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +114 -42
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +129 -15
- package/src/runtime/agent/orchestrator/tools/code-graph/loose-file-target.test.mjs +72 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +7 -8
- package/src/runtime/agent/orchestrator/tools/code-graph/search-references.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +201 -19
- package/src/runtime/agent/orchestrator/tools/code-graph/span.mjs +26 -3
- package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +10 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/symbol-search-scope.test.mjs +55 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +115 -25
- package/src/runtime/agent/orchestrator/tools/code-graph/text-span-mask.test.mjs +268 -0
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +296 -46
- package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.test.mjs +104 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +136 -0
- package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +127 -38
- package/src/runtime/agent/orchestrator/tools/patch/engine-contract-gate.test.mjs +661 -0
- package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +350 -9
- package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +418 -44
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +27 -3
- package/src/runtime/agent/orchestrator/tools/patch/patch-codec-eol.test.mjs +552 -0
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +65 -15
- package/src/runtime/agent/orchestrator/tools/patch-manifest.json +11 -11
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +284 -109
- package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +51 -21
- package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +44 -27
- package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +11 -11
- package/src/runtime/attachments/store.mjs +11 -3
- package/src/runtime/channels/data/voice-runtime-manifest.json +46 -70
- package/src/runtime/channels/lib/event-queue.mjs +51 -41
- package/src/runtime/channels/lib/scheduler.mjs +23 -28
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +6 -17
- package/src/runtime/channels/lib/voice-runtime-fetcher.test.mjs +17 -0
- package/src/runtime/channels/lib/webhook.mjs +39 -20
- package/src/runtime/channels/lib/whisper-server.mjs +46 -1
- package/src/runtime/channels/lib/worker-main.mjs +3 -1
- package/src/runtime/media/adapters/gemini-video.mjs +20 -4
- package/src/runtime/media/jobs.mjs +13 -0
- package/src/runtime/media/renditions.mjs +7 -1
- package/src/runtime/media/store.mjs +42 -22
- package/src/runtime/memory/index.mjs +4 -9
- package/src/runtime/memory/lib/agent-ipc.mjs +1 -6
- package/src/runtime/memory/lib/archive-security.test.mjs +21 -1
- package/src/runtime/memory/lib/core-memory-store.mjs +28 -50
- package/src/runtime/memory/lib/embedding-model-config.mjs +37 -1
- package/src/runtime/memory/lib/embedding-model-config.test.mjs +33 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +34 -12
- package/src/runtime/memory/lib/embedding-worker.mjs +37 -5
- package/src/runtime/memory/lib/ko-morph.mjs +46 -15
- package/src/runtime/memory/lib/memory-action-handlers.mjs +18 -1
- package/src/runtime/memory/lib/memory-cycle1.mjs +1 -18
- package/src/runtime/memory/lib/memory-cycle2-gate.mjs +1 -18
- package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +98 -45
- package/src/runtime/memory/lib/memory-cycle2-shared.mjs +71 -0
- package/src/runtime/memory/lib/memory-cycle2-shared.test.mjs +78 -0
- package/src/runtime/memory/lib/memory-cycle2.mjs +37 -3
- package/src/runtime/memory/lib/memory-cycle3.mjs +1 -1
- package/src/runtime/memory/lib/memory-embedding-migration.test.mjs +50 -0
- package/src/runtime/memory/lib/memory-recall-store.mjs +9 -24
- package/src/runtime/memory/lib/memory.mjs +50 -12
- package/src/runtime/memory/lib/pg/process.mjs +1 -10
- package/src/runtime/memory/lib/pg/supervisor.mjs +1 -9
- package/src/runtime/memory/lib/query-handlers.mjs +2 -4
- package/src/runtime/memory/lib/session-ingest-runtime.mjs +2 -2
- package/src/runtime/shared/background-tasks.mjs +15 -0
- package/src/runtime/shared/background-tasks.test.mjs +78 -0
- package/src/runtime/shared/child-guardian.mjs +2 -10
- package/src/runtime/shared/pid-liveness.mjs +27 -0
- package/src/runtime/shared/pristine-execution-contract.json +0 -1
- package/src/runtime/shared/runtime-root.mjs +1 -11
- package/src/runtime/shared/service-discovery.mjs +1 -17
- package/src/runtime/shared/singleton-owner.mjs +1 -11
- package/src/runtime/shared/staged-update.mjs +2 -12
- package/src/runtime/shared/tool-status.mjs +5 -1
- package/src/runtime/shared/tool-surface.mjs +15 -7
- package/src/runtime/shared/turn-snapshot-store.mjs +168 -0
- package/src/runtime/shared/turn-snapshot.mjs +137 -13
- package/src/runtime/shared/turn-worktree-snapshot.mjs +110 -18
- package/src/runtime/shared/webhook-session-run.mjs +16 -2
- package/src/runtime/web-search/lib/http-fetch.mjs +34 -4
- package/src/runtime/web-search/lib/state.mjs +15 -15
- package/src/runtime/web-search/lib/web-tools.mjs +46 -5
- package/src/session-runtime/context-status.mjs +4 -12
- package/src/session-runtime/runtime-core.mjs +20 -1
- package/src/session-runtime/session-lifecycle.mjs +9 -0
- package/src/standalone/agent-dispatch-broker.mjs +33 -2
- package/src/standalone/agent-tool/job-task-reconcile.mjs +78 -0
- package/src/standalone/agent-tool/notify.mjs +3 -1
- package/src/standalone/agent-tool/spawn-flow.mjs +52 -70
- package/src/standalone/agent-tool/tag-registry.mjs +116 -33
- package/src/standalone/agent-tool/tool-def.mjs +2 -2
- package/src/standalone/agent-tool/worker-index.mjs +8 -11
- package/src/standalone/agent-tool/worker-rows.mjs +4 -1
- package/src/standalone/agent-tool.mjs +20 -55
- package/src/standalone/agent-watchdog-registry.mjs +28 -4
- package/src/standalone/channel-client.mjs +47 -15
- package/src/standalone/channel-transport.mjs +44 -25
- package/src/standalone/daemon.mjs +31 -2
- package/src/standalone/hook-bus/config.mjs +25 -9
- package/src/standalone/hook-bus/handlers.mjs +16 -52
- package/src/standalone/hook-bus.mjs +29 -23
- package/src/standalone/memory-runtime-proxy.mjs +1 -16
- package/src/standalone/session-client.mjs +86 -23
- package/src/standalone/session-protocol.mjs +0 -2
- package/src/standalone/session-runtime-host-health.test.mjs +5 -4
- package/src/standalone/session-runtime-host.mjs +101 -6
- package/src/standalone/session-runtime-record.mjs +1 -5
- package/src/standalone/session-runtime-worker.mjs +52 -57
- package/src/standalone/session-service.mjs +4 -1
- package/src/standalone/session-transport.mjs +56 -25
- package/src/tui/App.jsx +40 -49
- package/src/tui/app/app-view.jsx +14 -21
- package/src/tui/app/core-memory-picker.mjs +29 -16
- package/src/tui/app/create-app-pickers.mjs +15 -36
- package/src/tui/app/extension-pickers.mjs +60 -49
- package/src/tui/app/maintenance-pickers.mjs +100 -57
- package/src/tui/app/message-selector.mjs +6 -5
- package/src/tui/app/model-picker.mjs +30 -13
- package/src/tui/app/onboarding-steps.mjs +21 -12
- package/src/tui/app/panel-epoch.mjs +56 -0
- package/src/tui/app/panel-epoch.test.mjs +1009 -0
- package/src/tui/app/panel-surface.mjs +98 -0
- package/src/tui/app/project-picker.mjs +30 -29
- package/src/tui/app/prompt-submit.mjs +192 -97
- package/src/tui/app/prompt-submit.test.mjs +206 -0
- package/src/tui/app/provider-setup-picker.mjs +74 -43
- package/src/tui/app/resume-picker.mjs +11 -8
- package/src/tui/app/route-pickers.mjs +45 -28
- package/src/tui/app/settings-picker.mjs +69 -18
- package/src/tui/app/shell-layout.mjs +1 -3
- package/src/tui/app/slash-commands.mjs +0 -2
- package/src/tui/app/slash-dispatch.mjs +4 -2
- package/src/tui/app/text-entry-policy.mjs +25 -0
- package/src/tui/app/theme-effort-pickers.mjs +11 -16
- package/src/tui/app/usage-context-panels.mjs +21 -25
- package/src/tui/app/use-global-key-input.mjs +3 -2
- package/src/tui/app/use-prompt-draft-flow.mjs +6 -18
- package/src/tui/app/use-prompt-handlers.mjs +3 -2
- package/src/tui/app/use-welcome-prompt-hint.mjs +17 -3
- package/src/tui/components/Picker.jsx +1 -1
- package/src/tui/components/TextEntryPanel.jsx +7 -2
- package/src/tui/dist/index.mjs +652 -561
- package/src/tui/lib/voice-setup.mjs +1 -2
- package/src/tui/session/agent-job-feed.mjs +73 -11
- package/src/tui/session/session-api-ext.mjs +5 -6
- package/src/tui/session/session-api.mjs +1 -0
- package/src/tui/session/tool-approval.mjs +15 -5
- package/src/tui/session/tui-steering-persist.mjs +33 -19
- package/src/tui/session/tui-steering-persist.test.mjs +104 -0
- package/src/tui/session-local.mjs +0 -22
- package/scripts/.tmp-coverage-report.mjs +0 -96
- package/src/runtime/agent/orchestrator/tools/builtin/shell-monitor.mjs +0 -57
- package/src/runtime/agent/orchestrator/tools/builtin/shell-monitor.test.mjs +0 -57
|
@@ -8,7 +8,10 @@ import {
|
|
|
8
8
|
mintUuidV7,
|
|
9
9
|
} from '../session/manager/session-id.mjs';
|
|
10
10
|
import { buildStableProviderPromptCacheKey } from '../agent-runtime/cache-strategy.mjs';
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
_codexWsCompatibilityHeaders,
|
|
13
|
+
_withCodexWsClientMetadata,
|
|
14
|
+
} from './openai-codex-metadata.mjs';
|
|
12
15
|
import { codexOriginator, codexUserAgent } from './codex-client-meta.mjs';
|
|
13
16
|
|
|
14
17
|
test('Codex wire identity is a real time-based UUIDv7 and remains session-stable', () => {
|
|
@@ -26,14 +29,7 @@ test('Codex wire identity is a real time-based UUIDv7 and remains session-stable
|
|
|
26
29
|
assert.equal(ensureCodexWireSessionId(session), sessionId);
|
|
27
30
|
});
|
|
28
31
|
|
|
29
|
-
test('Codex cache key and every wire session identity use the same UUIDv7', (
|
|
30
|
-
const previousParity = process.env.MIXDOG_OAI_CODEX_WIRE_PARITY;
|
|
31
|
-
process.env.MIXDOG_OAI_CODEX_WIRE_PARITY = '1';
|
|
32
|
-
t.after(() => {
|
|
33
|
-
if (previousParity == null) delete process.env.MIXDOG_OAI_CODEX_WIRE_PARITY;
|
|
34
|
-
else process.env.MIXDOG_OAI_CODEX_WIRE_PARITY = previousParity;
|
|
35
|
-
});
|
|
36
|
-
|
|
32
|
+
test('Codex cache key and every wire session identity use the same UUIDv7', () => {
|
|
37
33
|
const sessionId = mintUuidV7();
|
|
38
34
|
const turnStartedAtUnixMs = Date.now();
|
|
39
35
|
const turnId = mintUuidV7(turnStartedAtUnixMs);
|
|
@@ -80,11 +76,38 @@ test('Codex cache key and every wire session identity use the same UUIDv7', (t)
|
|
|
80
76
|
assert.equal(turnMetadata.session_id, sessionId);
|
|
81
77
|
assert.equal(turnMetadata.thread_id, sessionId);
|
|
82
78
|
assert.equal(turnMetadata.turn_id, turnId);
|
|
79
|
+
assert.match(turnMetadata.installation_id, /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/);
|
|
83
80
|
assert.equal(turnMetadata.agent_name, '/root');
|
|
84
81
|
assert.equal(turnMetadata.sandbox, 'none');
|
|
85
82
|
assert.equal(turnMetadata.sandbox_mode, 'danger-full-access');
|
|
86
83
|
assert.equal(turnMetadata.auto_review_enabled, false);
|
|
84
|
+
assert.equal(turnMetadata.node_repl_auto_review_required, false);
|
|
85
|
+
assert.equal(turnMetadata.node_repl_disabled, false);
|
|
87
86
|
assert.equal(turnMetadata.turn_started_at_unix_ms, turnStartedAtUnixMs);
|
|
87
|
+
|
|
88
|
+
const prewarmHeaders = _codexWsCompatibilityHeaders({
|
|
89
|
+
cacheKey: promptCacheKey,
|
|
90
|
+
poolKey: session.id,
|
|
91
|
+
model: 'gpt-5.6-sol',
|
|
92
|
+
handshake: true,
|
|
93
|
+
useResponsesLite: true,
|
|
94
|
+
sendOpts: {
|
|
95
|
+
codexSessionId: sessionId,
|
|
96
|
+
codexThreadId: sessionId,
|
|
97
|
+
requestKind: 'prewarm',
|
|
98
|
+
session,
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
assert.equal(prewarmHeaders['session-id'], sessionId);
|
|
102
|
+
assert.equal(prewarmHeaders['thread-id'], sessionId);
|
|
103
|
+
assert.equal(prewarmHeaders['x-client-request-id'], sessionId);
|
|
104
|
+
assert.equal('x-codex-installation-id' in prewarmHeaders, false);
|
|
105
|
+
assert.equal('x-openai-internal-codex-responses-lite' in prewarmHeaders, false);
|
|
106
|
+
const prewarmMetadata = JSON.parse(prewarmHeaders['x-codex-turn-metadata']);
|
|
107
|
+
assert.equal(prewarmMetadata.request_kind, 'prewarm');
|
|
108
|
+
assert.equal(prewarmMetadata.turn_id, '');
|
|
109
|
+
assert.equal(prewarmMetadata.installation_id, turnMetadata.installation_id);
|
|
110
|
+
assert.equal('turn_started_at_unix_ms' in prewarmMetadata, false);
|
|
88
111
|
});
|
|
89
112
|
|
|
90
113
|
// A compaction summary is a request of the same session: same thread identity,
|
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
// installation/session/thread/turn identity block that rides every frame, its
|
|
3
3
|
// handshake-header projection, and the per-turn x-codex-turn-state guard.
|
|
4
4
|
// Extracted from openai-oauth-ws.mjs, which now owns transport flow only.
|
|
5
|
-
import { createHash } from 'crypto';
|
|
5
|
+
import { createHash, randomUUID } from 'crypto';
|
|
6
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
7
|
+
import { join } from 'path';
|
|
8
|
+
import { getPluginData } from '../config.mjs';
|
|
9
|
+
|
|
10
|
+
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
|
+
let _installationId = null;
|
|
6
12
|
|
|
7
13
|
function _cleanMetaString(value) {
|
|
8
14
|
return typeof value === 'string' ? value.trim() : '';
|
|
@@ -49,8 +55,38 @@ function _codexRequestKind(sendOpts, sessionId) {
|
|
|
49
55
|
}
|
|
50
56
|
|
|
51
57
|
function _codexInstallationId(sendOpts) {
|
|
52
|
-
|
|
53
|
-
|
|
58
|
+
const explicit = _cleanMetaString(
|
|
59
|
+
sendOpts?.installationId
|
|
60
|
+
|| sendOpts?.codexInstallationId
|
|
61
|
+
|| process.env.MIXDOG_CODEX_INSTALLATION_ID,
|
|
62
|
+
).toLowerCase();
|
|
63
|
+
if (UUID_RE.test(explicit)) return explicit;
|
|
64
|
+
if (_installationId) return _installationId;
|
|
65
|
+
const dir = getPluginData();
|
|
66
|
+
const file = join(dir, 'installation_id');
|
|
67
|
+
try {
|
|
68
|
+
const existing = existsSync(file) ? readFileSync(file, 'utf8').trim().toLowerCase() : '';
|
|
69
|
+
if (UUID_RE.test(existing)) {
|
|
70
|
+
_installationId = existing;
|
|
71
|
+
return _installationId;
|
|
72
|
+
}
|
|
73
|
+
} catch {}
|
|
74
|
+
const generated = randomUUID();
|
|
75
|
+
try {
|
|
76
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
77
|
+
try {
|
|
78
|
+
writeFileSync(file, generated, { encoding: 'utf8', flag: 'wx', mode: 0o644 });
|
|
79
|
+
} catch {
|
|
80
|
+
const winner = readFileSync(file, 'utf8').trim().toLowerCase();
|
|
81
|
+
if (UUID_RE.test(winner)) {
|
|
82
|
+
_installationId = winner;
|
|
83
|
+
return _installationId;
|
|
84
|
+
}
|
|
85
|
+
writeFileSync(file, generated, { encoding: 'utf8', mode: 0o644 });
|
|
86
|
+
}
|
|
87
|
+
} catch {}
|
|
88
|
+
_installationId = generated;
|
|
89
|
+
return _installationId;
|
|
54
90
|
}
|
|
55
91
|
|
|
56
92
|
// The identity block is rebuilt per request: never cached on the pooled
|
|
@@ -75,51 +111,42 @@ function _codexMetadataBase(entry, { poolKey, cacheKey, sendOpts, handshake = fa
|
|
|
75
111
|
)
|
|
76
112
|
|| rawSessionId;
|
|
77
113
|
const rawInstallationId = _codexInstallationId(sendOpts);
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
const installationId = wireParity ? _codexUuidV7(rawInstallationId) : rawInstallationId;
|
|
114
|
+
const sessionId = _codexUuidV7(rawSessionId);
|
|
115
|
+
const threadId = _codexUuidV7(rawThreadId);
|
|
116
|
+
const installationId = rawInstallationId;
|
|
82
117
|
const startedAt = Number.isFinite(Number(sendOpts?.turnStartedAtUnixMs))
|
|
83
118
|
? Math.floor(Number(sendOpts.turnStartedAtUnixMs))
|
|
84
119
|
: _sessionStartedAtUnixMs(rawSessionId);
|
|
85
120
|
const requestKind = _codexRequestKind(sendOpts, rawSessionId);
|
|
86
121
|
// The reference client opens the WS with a prewarm (empty turn_id) BEFORE
|
|
87
|
-
// the real turn
|
|
88
|
-
//
|
|
89
|
-
// presenting the handshake as a live turn. Parity off is unchanged.
|
|
122
|
+
// the real turn, so the handshake is always identified as a prewarm rather
|
|
123
|
+
// than as a live turn.
|
|
90
124
|
const isPrewarm = requestKind === 'prewarm' || handshake === true;
|
|
91
125
|
const rawExplicitTurnId = _cleanMetaString(sendOpts?.turnId || sendOpts?.codexTurnId || sendOpts?.session?.turnId);
|
|
92
126
|
const explicitWindowId = _cleanMetaString(sendOpts?.windowId || sendOpts?.codexWindowId || sendOpts?.session?.windowId);
|
|
93
|
-
const turnId =
|
|
127
|
+
const turnId = isPrewarm
|
|
94
128
|
? ''
|
|
95
|
-
:
|
|
96
|
-
|
|
97
|
-
: (rawExplicitTurnId || sessionId);
|
|
98
|
-
const effectiveRequestKind = wireParity && isPrewarm ? 'prewarm' : requestKind;
|
|
129
|
+
: _codexUuidV7(rawExplicitTurnId || `${rawSessionId}:turn`);
|
|
130
|
+
const effectiveRequestKind = isPrewarm ? 'prewarm' : requestKind;
|
|
99
131
|
// Window id is `<thread-id>:<auto-compact window number>`, and that counter
|
|
100
132
|
// starts at 0: a thread that never auto-compacted reports generation 0 and
|
|
101
|
-
// only advances when a new context window opens.
|
|
102
|
-
|
|
103
|
-
const windowId = explicitWindowId || `${threadId}:${wireParity ? 0 : 1}`;
|
|
133
|
+
// only advances when a new context window opens.
|
|
134
|
+
const windowId = explicitWindowId || `${threadId}:0`;
|
|
104
135
|
const turnMetadata = {
|
|
105
136
|
installation_id: installationId,
|
|
106
137
|
session_id: sessionId,
|
|
107
138
|
thread_id: threadId,
|
|
139
|
+
agent_name: '/root',
|
|
108
140
|
turn_id: turnId,
|
|
109
141
|
window_id: windowId,
|
|
110
142
|
request_kind: effectiveRequestKind,
|
|
111
|
-
// Turn-metadata fields the reference client fills on every request.
|
|
112
|
-
// They were behind a probe knob after a 2026-07-04 A/B showed no
|
|
113
|
-
// isolated effect; they are unconditional now because a partial blob is
|
|
114
|
-
// a shape no real client sends. Absolute agent path, not a bare name;
|
|
115
|
-
// the sandbox pair reports this runtime honestly (tools run with full
|
|
116
|
-
// host access, so there is no sandbox to declare).
|
|
117
|
-
agent_name: '/root',
|
|
118
143
|
thread_source: 'user',
|
|
119
144
|
sandbox: 'none',
|
|
120
145
|
sandbox_mode: 'danger-full-access',
|
|
121
146
|
auto_review_enabled: false,
|
|
122
|
-
|
|
147
|
+
node_repl_auto_review_required: false,
|
|
148
|
+
node_repl_disabled: false,
|
|
149
|
+
...(!isPrewarm ? { turn_started_at_unix_ms: startedAt } : {}),
|
|
123
150
|
};
|
|
124
151
|
return {
|
|
125
152
|
'x-codex-installation-id': installationId,
|
|
@@ -144,16 +171,18 @@ export function _metadataTrace(metadata) {
|
|
|
144
171
|
};
|
|
145
172
|
}
|
|
146
173
|
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
// all of them on every request, and a 2026-07-04 A/B measured the blob alone
|
|
150
|
-
// lifting prefix-cache hits.
|
|
174
|
+
// The WebSocket handshake carries compatibility identity and routing fields.
|
|
175
|
+
// Installation and Responses Lite data stay in per-request client_metadata.
|
|
151
176
|
export function _codexWsCompatibilityHeaders(context = {}) {
|
|
152
177
|
const metadata = _codexMetadataBase(null, context);
|
|
153
178
|
const headers = {};
|
|
179
|
+
if (metadata.session_id) headers['session-id'] = metadata.session_id;
|
|
180
|
+
if (metadata.thread_id) {
|
|
181
|
+
headers['thread-id'] = metadata.thread_id;
|
|
182
|
+
headers['x-client-request-id'] = metadata.thread_id;
|
|
183
|
+
}
|
|
154
184
|
if (metadata['x-codex-window-id']) headers['x-codex-window-id'] = metadata['x-codex-window-id'];
|
|
155
185
|
if (metadata['x-codex-turn-metadata']) headers['x-codex-turn-metadata'] = metadata['x-codex-turn-metadata'];
|
|
156
|
-
if (metadata['x-codex-installation-id']) headers['x-codex-installation-id'] = metadata['x-codex-installation-id'];
|
|
157
186
|
// Routing hint. The reference client attaches this to EVERY request whose
|
|
158
187
|
// auth is the ChatGPT backend — no flag, no mode, and with `model=` alone
|
|
159
188
|
// when no service tier is selected. It is how the backend lands the request
|
|
@@ -177,9 +206,14 @@ export function _codexWsCompatibilityHeaders(context = {}) {
|
|
|
177
206
|
export function _withCodexWsClientMetadata(frame, entry, enabled, context = {}) {
|
|
178
207
|
if (!enabled || !frame || typeof frame !== 'object') return frame;
|
|
179
208
|
const base = _codexMetadataBase(entry, context);
|
|
209
|
+
const requestKind = _codexRequestKind(context?.sendOpts, context?.poolKey || '');
|
|
210
|
+
const isPrewarmRequest = requestKind === 'prewarm';
|
|
180
211
|
const metadata = {
|
|
181
212
|
...base,
|
|
182
213
|
...(frame.client_metadata && typeof frame.client_metadata === 'object' ? frame.client_metadata : {}),
|
|
214
|
+
...(context?.useResponsesLite === true
|
|
215
|
+
? { ws_request_header_x_openai_internal_codex_responses_lite: 'true' }
|
|
216
|
+
: {}),
|
|
183
217
|
'x-codex-ws-stream-request-start-ms': String(Date.now()),
|
|
184
218
|
};
|
|
185
219
|
if (entry && typeof entry === 'object') {
|
|
@@ -192,10 +226,21 @@ export function _withCodexWsClientMetadata(frame, entry, enabled, context = {})
|
|
|
192
226
|
if (entry.turnStateTurnId == null) {
|
|
193
227
|
entry.turnStateTurnId = base.turn_id;
|
|
194
228
|
} else if (entry.turnStateTurnId !== base.turn_id) {
|
|
195
|
-
|
|
196
|
-
|
|
229
|
+
// Codex startup prewarm owns the handshake turn-state until
|
|
230
|
+
// the first real turn consumes that prewarmed client session.
|
|
231
|
+
// Adopt it once across prewarm→turn; ordinary turn changes
|
|
232
|
+
// still retire the old token.
|
|
233
|
+
if (entry.turnStateFromPrewarm === true && !isPrewarmRequest) {
|
|
234
|
+
entry.turnStateTurnId = base.turn_id;
|
|
235
|
+
} else {
|
|
236
|
+
entry.turnState = null;
|
|
237
|
+
entry.turnStateTurnId = null;
|
|
238
|
+
}
|
|
197
239
|
}
|
|
198
240
|
}
|
|
241
|
+
if (!isPrewarmRequest && entry.turnStateFromPrewarm === true) {
|
|
242
|
+
entry.turnStateFromPrewarm = false;
|
|
243
|
+
}
|
|
199
244
|
entry.currentTurnId = base.turn_id;
|
|
200
245
|
}
|
|
201
246
|
if (entry?.turnState) metadata['x-codex-turn-state'] = String(entry.turnState);
|
|
@@ -7,6 +7,23 @@
|
|
|
7
7
|
* _displayCodexModel for existing importers.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
const CODEX_RESPONSES_LITE_CAPABILITY = Object.freeze({
|
|
11
|
+
'gpt-5.6-sol': true,
|
|
12
|
+
'gpt-5.6-terra': true,
|
|
13
|
+
'gpt-5.6-luna': true,
|
|
14
|
+
'gpt-5.5': false,
|
|
15
|
+
'gpt-5.4': false,
|
|
16
|
+
'gpt-5.4-mini': false,
|
|
17
|
+
'gpt-5.2': false,
|
|
18
|
+
'codex-auto-review': false,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export function _codexUsesResponsesLite(id, modelInfo = null) {
|
|
22
|
+
const explicit = modelInfo?.useResponsesLite ?? modelInfo?.use_responses_lite;
|
|
23
|
+
if (typeof explicit === 'boolean') return explicit;
|
|
24
|
+
return CODEX_RESPONSES_LITE_CAPABILITY[String(id || '').trim()] === true;
|
|
25
|
+
}
|
|
26
|
+
|
|
10
27
|
// OAuth catalog returns dated ids (gpt-5.4-mini-2026-03-17). Strip the trailing
|
|
11
28
|
// -YYYY-MM-DD to get the version alias (gpt-5.4-mini). Unknown shapes pass
|
|
12
29
|
// through unchanged.
|
|
@@ -82,6 +99,10 @@ export function _normalizeCodexModel(m) {
|
|
|
82
99
|
latest: false,
|
|
83
100
|
description: m?.description || '',
|
|
84
101
|
reasoningLevels: (m?.supported_reasoning_levels || []).map(r => r.effort),
|
|
102
|
+
supportVerbosity: m?.support_verbosity === true,
|
|
103
|
+
defaultVerbosity: m?.default_verbosity || null,
|
|
104
|
+
useResponsesLite: m?.use_responses_lite === true,
|
|
105
|
+
supportsReasoningSummaries: m?.supports_reasoning_summaries === true,
|
|
85
106
|
serviceTiers,
|
|
86
107
|
defaultServiceTier: m?.default_service_tier || null,
|
|
87
108
|
additionalSpeedTiers,
|
|
@@ -152,11 +152,16 @@ function mergeToolCallDelta(accByIndex, deltaCalls, bucketState) {
|
|
|
152
152
|
} else if (tc.function?.name) {
|
|
153
153
|
const anonId = ++bucketState._nextAnonId;
|
|
154
154
|
key = `anon:${anonId}`;
|
|
155
|
-
bucketState._lastAnonKey = key;
|
|
156
155
|
} else {
|
|
157
156
|
key = bucketState._lastAnonKey;
|
|
158
157
|
if (!key) continue;
|
|
159
158
|
}
|
|
159
|
+
// Whatever bucket this chunk resolved to becomes the continuation
|
|
160
|
+
// target for later argument-only chunks (no index, no id, no name).
|
|
161
|
+
// Only the anonymous branch used to record it, so a provider that
|
|
162
|
+
// identifies a tool call by id alone and then streams bare argument
|
|
163
|
+
// deltas had every one of those deltas silently discarded.
|
|
164
|
+
bucketState._lastAnonKey = key;
|
|
160
165
|
let prev = accByIndex.get(key);
|
|
161
166
|
if (!prev) {
|
|
162
167
|
prev = {
|
|
@@ -210,7 +215,7 @@ function emitCompatToolCallOnce(state, call, onToolCall) {
|
|
|
210
215
|
// Fix 2: cross-path name+args dedupe. A synthesized text-leaked call and an
|
|
211
216
|
// identical native tool_call must fire onToolCall exactly once. state._toolDedupe
|
|
212
217
|
// is created per stream; when absent (older callers) behavior is unchanged.
|
|
213
|
-
if (state._toolDedupe && !state._toolDedupe.shouldDispatch(call.name, call.arguments)) {
|
|
218
|
+
if (state._toolDedupe && !state._toolDedupe.shouldDispatch(call.name, call.arguments, call.id)) {
|
|
214
219
|
// Still mark the id as emitted so later id-frames for the same native
|
|
215
220
|
// call don't retry, but do NOT invoke onToolCall (already dispatched).
|
|
216
221
|
state.emittedToolCallKeys.add(key);
|
|
@@ -556,6 +561,33 @@ export async function consumeCompatChatCompletionStream(stream, {
|
|
|
556
561
|
};
|
|
557
562
|
}
|
|
558
563
|
|
|
564
|
+
// Reconcile a COMPLETED function_call item into state.toolCalls: fill in the
|
|
565
|
+
// id/name a streamed call may still be missing, or adopt the item as a new
|
|
566
|
+
// call. `response.output_item.done` and the `response.completed` sweep see the
|
|
567
|
+
// same item shape and must land on the same single emit, so both route here.
|
|
568
|
+
// Returns the item id the done-branch still needs for its pendingCalls /
|
|
569
|
+
// tool-tracker bookkeeping.
|
|
570
|
+
function reconcileCompatFunctionCallItem(state, item, label, onToolCall) {
|
|
571
|
+
const itemId = item.id || '';
|
|
572
|
+
const tc = state.toolCalls.find(t => t._pendingItemId === itemId)
|
|
573
|
+
|| (item.call_id ? state.toolCalls.find(t => t.id === item.call_id) : null);
|
|
574
|
+
if (tc) {
|
|
575
|
+
if (!tc.id && item.call_id) tc.id = item.call_id;
|
|
576
|
+
if (!tc.name && item.name) tc.name = item.name;
|
|
577
|
+
if (tc.id && tc.name) delete tc._pendingItemId;
|
|
578
|
+
emitCompatToolCallOnce(state, tc, onToolCall);
|
|
579
|
+
} else if (item.call_id && item.name) {
|
|
580
|
+
const call = {
|
|
581
|
+
id: item.call_id,
|
|
582
|
+
name: item.name,
|
|
583
|
+
arguments: parseCompletedToolCallArgumentsJson(item.arguments, label, { id: item.call_id, name: item.name, finishReason: 'done' }),
|
|
584
|
+
};
|
|
585
|
+
state.toolCalls.push(call);
|
|
586
|
+
emitCompatToolCallOnce(state, call, onToolCall);
|
|
587
|
+
}
|
|
588
|
+
return itemId;
|
|
589
|
+
}
|
|
590
|
+
|
|
559
591
|
function handleCompatResponsesStreamEvent(event, state, { label, parseResponsesToolCalls, responseOutputText, onStreamDelta, onToolCall, onTextDelta, relayLeakText }) {
|
|
560
592
|
if (!event || typeof event.type !== 'string') return;
|
|
561
593
|
const pushToolSearchCall = (item) => {
|
|
@@ -671,23 +703,7 @@ function handleCompatResponsesStreamEvent(event, state, { label, parseResponsesT
|
|
|
671
703
|
case 'response.output_item.done': {
|
|
672
704
|
const item = event.item || {};
|
|
673
705
|
if (item.type === 'function_call') {
|
|
674
|
-
const itemId = item
|
|
675
|
-
const tc = state.toolCalls.find(t => t._pendingItemId === itemId)
|
|
676
|
-
|| (item.call_id ? state.toolCalls.find(t => t.id === item.call_id) : null);
|
|
677
|
-
if (tc) {
|
|
678
|
-
if (!tc.id && item.call_id) tc.id = item.call_id;
|
|
679
|
-
if (!tc.name && item.name) tc.name = item.name;
|
|
680
|
-
if (tc.id && tc.name) delete tc._pendingItemId;
|
|
681
|
-
emitCompatToolCallOnce(state, tc, onToolCall);
|
|
682
|
-
} else if (item.call_id && item.name) {
|
|
683
|
-
const call = {
|
|
684
|
-
id: item.call_id,
|
|
685
|
-
name: item.name,
|
|
686
|
-
arguments: parseCompletedToolCallArgumentsJson(item.arguments, label, { id: item.call_id, name: item.name, finishReason: 'done' }),
|
|
687
|
-
};
|
|
688
|
-
state.toolCalls.push(call);
|
|
689
|
-
emitCompatToolCallOnce(state, call, onToolCall);
|
|
690
|
-
}
|
|
706
|
+
const itemId = reconcileCompatFunctionCallItem(state, item, label, onToolCall);
|
|
691
707
|
// Drop the resolved function item from pendingCalls before
|
|
692
708
|
// recomputing toolInFlight — otherwise a completed call keeps
|
|
693
709
|
// pendingCalls.size > 0 and the latch never clears, so a later
|
|
@@ -732,23 +748,7 @@ function handleCompatResponsesStreamEvent(event, state, { label, parseResponsesT
|
|
|
732
748
|
}
|
|
733
749
|
for (const item of resp.output || []) {
|
|
734
750
|
if (item?.type === 'function_call') {
|
|
735
|
-
|
|
736
|
-
const tc = state.toolCalls.find(t => t._pendingItemId === itemId)
|
|
737
|
-
|| (item.call_id ? state.toolCalls.find(t => t.id === item.call_id) : null);
|
|
738
|
-
if (tc) {
|
|
739
|
-
if (!tc.id && item.call_id) tc.id = item.call_id;
|
|
740
|
-
if (!tc.name && item.name) tc.name = item.name;
|
|
741
|
-
if (tc.id && tc.name) delete tc._pendingItemId;
|
|
742
|
-
emitCompatToolCallOnce(state, tc, onToolCall);
|
|
743
|
-
} else if (item.call_id && item.name) {
|
|
744
|
-
const call = {
|
|
745
|
-
id: item.call_id,
|
|
746
|
-
name: item.name,
|
|
747
|
-
arguments: parseCompletedToolCallArgumentsJson(item.arguments, label, { id: item.call_id, name: item.name, finishReason: 'done' }),
|
|
748
|
-
};
|
|
749
|
-
state.toolCalls.push(call);
|
|
750
|
-
emitCompatToolCallOnce(state, call, onToolCall);
|
|
751
|
-
}
|
|
751
|
+
reconcileCompatFunctionCallItem(state, item, label, onToolCall);
|
|
752
752
|
try { onStreamDelta?.('tool'); } catch {}
|
|
753
753
|
reportedBundleProgress = true;
|
|
754
754
|
} else if (item?.type === 'tool_search_call') {
|
|
@@ -44,13 +44,15 @@ export function toOpenAIMessages(messages, providerName, options = {}) {
|
|
|
44
44
|
// strict providers (xai) reject unknown roles/types and would 400 the
|
|
45
45
|
// request. Documented in v0.1.160 (GPT reasoning replay).
|
|
46
46
|
//
|
|
47
|
-
// DeepSeek thinking models
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
//
|
|
47
|
+
// DeepSeek splits by model: thinking-mode models with tools REQUIRE the
|
|
48
|
+
// prior turn's `reasoning_content` echoed back (400 without it), while
|
|
49
|
+
// `deepseek-reasoner` REJECTS it with a 400. The caller decides per model
|
|
50
|
+
// through options.replaysReasoningContent — see
|
|
51
|
+
// deepseekReplaysReasoningContent below. xAI reasoning models preserve
|
|
52
|
+
// their official multi-turn shape and cache prefix stability when prior
|
|
53
|
+
// assistant reasoning_content is replayed; reasoning_effort itself remains
|
|
54
|
+
// caller/user-selected.
|
|
52
55
|
const replaysReasoningContent = options.replaysReasoningContent === true
|
|
53
|
-
|| providerName === 'deepseek'
|
|
54
56
|
|| providerName === 'xai';
|
|
55
57
|
const out = [];
|
|
56
58
|
const pendingToolMedia = [];
|
|
@@ -94,6 +96,14 @@ export function toOpenAIMessages(messages, providerName, options = {}) {
|
|
|
94
96
|
return out;
|
|
95
97
|
}
|
|
96
98
|
|
|
99
|
+
// deepseek-reasoner returns 400 when `reasoning_content` appears in the input
|
|
100
|
+
// messages; every other DeepSeek thinking model needs it back once tools are in
|
|
101
|
+
// play. Unknown DeepSeek ids default to replaying: a missing echo breaks the
|
|
102
|
+
// tool loop, while a stray field on a non-thinking model is ignored.
|
|
103
|
+
export function deepseekReplaysReasoningContent(model) {
|
|
104
|
+
return !/reasoner/.test(String(model || '').trim().toLowerCase());
|
|
105
|
+
}
|
|
106
|
+
|
|
97
107
|
export function toOpenAITools(tools) {
|
|
98
108
|
return tools.map((t) => ({
|
|
99
109
|
type: 'function',
|