mixdog 0.9.63 → 0.9.64
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/README.md +3 -0
- package/package.json +9 -2
- package/scripts/code-graph-description-contract.mjs +3 -3
- package/scripts/verify-release-assets.mjs +2 -2
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +11 -14
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +6 -6
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -2
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +1 -0
- package/src/runtime/agent/orchestrator/config.mjs +19 -124
- package/src/runtime/agent/orchestrator/context/collect.mjs +6 -6
- package/src/runtime/agent/orchestrator/dispatch-persist.mjs +2 -2
- package/src/runtime/agent/orchestrator/internal-agents.mjs +2 -2
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +1 -1
- package/src/runtime/agent/orchestrator/mcp/client.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +333 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +3 -277
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +6 -6
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +196 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +460 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +14 -593
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +5 -280
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +357 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-headers.mjs +216 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +2 -188
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/provider-catalog-cache.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/registry.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/compact/budget.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/compact/file-reattach.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +4 -4
- package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +17 -0
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +18 -26
- package/src/runtime/agent/orchestrator/session/loop/termination.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/delivered-completions.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/live-state.mjs +49 -0
- package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +49 -0
- package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +260 -0
- package/src/runtime/agent/orchestrator/session/store/serialize.mjs +72 -0
- package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +163 -0
- package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/store.mjs +9 -561
- package/src/runtime/agent/orchestrator/session/tool-envelope.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +2 -2
- package/src/runtime/agent/orchestrator/stall-policy.mjs +11 -11
- package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/bash-session.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +2 -154
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/cwd-utils.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/fs-reachability.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/glob-walk.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/path-locks.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/path-utils.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-args.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +2 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-image-resize.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-open.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-spawn.mjs +519 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +5 -449
- package/src/runtime/agent/orchestrator/tools/builtin/snapshot-helpers.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +212 -0
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +1 -7
- package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +9 -36
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +15 -3
- package/src/runtime/agent/orchestrator/tools/code-graph/search-references.mjs +429 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +2 -395
- package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/trusted-roots.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-state.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/mutation-planner.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/next-call-utils.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +7 -7
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +72 -9
- package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/patch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/result-compression.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +2 -444
- package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +505 -0
- package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +1 -1
- package/src/runtime/channels/lib/backend-dispatch.mjs +20 -5
- package/src/runtime/channels/lib/scheduler.mjs +1 -1
- package/src/runtime/channels/lib/telegram-format.mjs +1 -1
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +4 -4
- package/src/runtime/channels/tool-defs.mjs +2 -3
- package/src/runtime/memory/index.mjs +1 -5
- package/src/runtime/memory/lib/core-memory-candidates.mjs +357 -0
- package/src/runtime/memory/lib/core-memory-store.mjs +7 -357
- package/src/runtime/memory/lib/cycle-signatures.mjs +1 -1
- package/src/runtime/memory/lib/embedding-model-config.mjs +1 -1
- package/src/runtime/memory/lib/embedding-provider.mjs +1 -5
- package/src/runtime/memory/lib/embedding-worker.mjs +1 -5
- package/src/runtime/memory/lib/ko-morph.mjs +2 -2
- package/src/runtime/memory/lib/memory-config-flags.mjs +2 -5
- package/src/runtime/memory/lib/memory-cycle-requests.mjs +3 -7
- package/src/runtime/memory/lib/memory-cycle1.mjs +4 -8
- package/src/runtime/memory/lib/memory-cycle2-gate.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2-shared.mjs +2 -5
- package/src/runtime/memory/lib/memory-cycle3.mjs +1 -5
- package/src/runtime/memory/lib/memory-embed.mjs +2 -6
- package/src/runtime/memory/lib/memory-log.mjs +8 -0
- package/src/runtime/memory/lib/memory-ops-policy.mjs +4 -8
- package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +1 -1
- package/src/runtime/memory/lib/memory-recall-store.mjs +2 -193
- package/src/runtime/memory/lib/memory-score.mjs +1 -1
- package/src/runtime/memory/lib/memory-text-utils.mjs +2 -2
- package/src/runtime/memory/lib/memory.mjs +2 -6
- package/src/runtime/memory/lib/pg/adapter.mjs +2 -6
- package/src/runtime/memory/lib/pg/process.mjs +1 -5
- package/src/runtime/memory/lib/pg/supervisor.mjs +1 -5
- package/src/runtime/memory/lib/recall-format.mjs +2 -2
- package/src/runtime/memory/lib/recall-scoring.mjs +195 -0
- package/src/runtime/memory/lib/runtime-fetcher.mjs +1 -5
- package/src/runtime/memory/lib/trace-store.mjs +2 -6
- package/src/runtime/search/lib/http-fetch.mjs +6 -6
- package/src/runtime/search/lib/web-tools.mjs +2 -2
- package/src/runtime/shared/buffered-appender.mjs +1 -1
- package/src/runtime/shared/child-guardian.mjs +1 -1
- package/src/runtime/shared/child-spawn-gate.mjs +1 -1
- package/src/runtime/shared/config.mjs +4 -4
- package/src/runtime/shared/launcher-control.mjs +9 -10
- package/src/runtime/shared/llm/index.mjs +5 -20
- package/src/runtime/shared/markdown-frontmatter.mjs +1 -1
- package/src/runtime/shared/memory-snapshot.mjs +4 -4
- package/src/runtime/shared/pristine-execution.mjs +1 -1
- package/src/runtime/shared/process-lifecycle.mjs +0 -1
- package/src/runtime/shared/process-shutdown.mjs +1 -1
- package/src/runtime/shared/resource-admission.mjs +2 -2
- package/src/runtime/shared/schedule-session-run.mjs +1 -1
- package/src/runtime/shared/schedules-db.mjs +1 -1
- package/src/runtime/shared/service-discovery.mjs +2 -2
- package/src/runtime/shared/staged-update.mjs +6 -6
- package/src/runtime/shared/tool-execution-contract.mjs +1 -1
- package/src/runtime/shared/tool-primitives.mjs +1 -1
- package/src/runtime/shared/tool-surface.mjs +2 -2
- package/src/runtime/shared/update-checker.mjs +1 -1
- package/src/runtime/shared/user-cwd.mjs +3 -3
- package/src/runtime/shared/user-data-guard.mjs +4 -4
- package/src/runtime/shared/workspace-router.mjs +5 -5
- package/src/session-runtime/config-helpers.mjs +2 -3
- package/src/session-runtime/config-lifecycle.mjs +1 -1
- package/src/session-runtime/hitch-profile.mjs +1 -1
- package/src/session-runtime/lifecycle-api.mjs +6 -4
- package/src/session-runtime/model-recency.mjs +5 -5
- package/src/session-runtime/plugin-mcp.mjs +1 -1
- package/src/session-runtime/provider-request-snapshot.mjs +338 -0
- package/src/session-runtime/session-text.mjs +4 -4
- package/src/session-runtime/tool-catalog-schema.mjs +197 -0
- package/src/session-runtime/tool-catalog.mjs +6 -483
- package/src/session-runtime/tool-defs.mjs +1 -1
- package/src/standalone/agent-task-status.mjs +1 -1
- package/src/standalone/agent-tool/helpers.mjs +2 -2
- package/src/standalone/channel-admin.mjs +4 -4
- package/src/standalone/explore-tool.mjs +3 -3
- package/src/standalone/hook-bus/config.mjs +1 -1
- package/src/standalone/hook-bus/constants.mjs +1 -1
- package/src/standalone/hook-bus/rules.mjs +1 -1
- package/src/standalone/projects.mjs +1 -1
- package/src/standalone/provider-admin.mjs +2 -2
- package/src/tui/app/app-format.mjs +2 -2
- package/src/tui/app/clipboard.mjs +3 -3
- package/src/tui/app/input-parsers.mjs +1 -1
- package/src/tui/app/text-layout.mjs +1 -1
- package/src/tui/app/transcript-row-estimate.mjs +360 -0
- package/src/tui/app/transcript-window.mjs +5 -347
- package/src/tui/app/use-mouse-input.mjs +1 -1
- package/src/tui/app/use-prompt-handlers.mjs +1 -1
- package/src/tui/components/tool-execution/surface-detail.mjs +9 -9
- package/src/tui/components/tool-execution/text-format.mjs +2 -2
- package/src/tui/components/tool-output-format.mjs +7 -7
- package/src/tui/display-width.mjs +4 -4
- package/src/tui/dist/index.mjs +63 -97
- package/src/tui/engine/agent-envelope.mjs +5 -5
- package/src/tui/engine/notification-plan.mjs +1 -1
- package/src/tui/engine/queue-helpers.mjs +3 -3
- package/src/tui/engine/render-timing.mjs +4 -5
- package/src/tui/engine/session-api-ext.mjs +3 -3
- package/src/tui/engine/tool-result-status.mjs +5 -5
- package/src/tui/engine/tool-result-text.mjs +1 -1
- package/src/tui/engine/transcript-spill.mjs +585 -0
- package/src/tui/engine/tui-steering-persist.mjs +1 -1
- package/src/tui/engine.mjs +2 -474
- package/src/tui/lib/voice-setup.mjs +1 -1
- package/src/tui/markdown/format-token.mjs +1 -1
- package/src/tui/markdown/render-ansi.mjs +1 -1
- package/src/tui/markdown/table-layout.mjs +4 -4
- package/src/tui/paste-attachments.mjs +1 -1
- package/src/tui/prompt-history-store.mjs +3 -3
- package/src/tui/statusline-ansi-bridge.mjs +2 -2
- package/src/tui/theme.mjs +1 -1
- package/src/tui/transcript-tool-failures.mjs +2 -2
- package/src/ui/ansi.mjs +0 -9
- package/src/ui/statusline-format.mjs +2 -4
- package/scripts/_bench-cwc.json +0 -20
- package/scripts/_jitter-fuzz.jsx +0 -42
- package/scripts/_jitter-fuzz2.jsx +0 -30
- package/scripts/_jitter-probe.jsx +0 -35
- package/scripts/_jp2.jsx +0 -16
- package/scripts/_smoke_wd.mjs +0 -7
- package/scripts/abort-recovery-test.mjs +0 -175
- package/scripts/agent-dispatch-abort-compose-test.mjs +0 -31
- package/scripts/agent-live-arg-guard-smoke.mjs +0 -20
- package/scripts/agent-live-path-suffix-smoke.mjs +0 -34
- package/scripts/agent-live-toolcall-args-smoke.mjs +0 -45
- package/scripts/agent-loop-policy-test.mjs +0 -37
- package/scripts/agent-model-liveness-test.mjs +0 -763
- package/scripts/agent-parallel-smoke.mjs +0 -435
- package/scripts/agent-route-batch-test.mjs +0 -40
- package/scripts/agent-tag-reuse-smoke.mjs +0 -441
- package/scripts/agent-terminal-reap-test.mjs +0 -252
- package/scripts/agent-trace-io-test.mjs +0 -133
- package/scripts/ansi-color-capability-test.mjs +0 -90
- package/scripts/anthropic-admission-retry-integration-test.mjs +0 -119
- package/scripts/anthropic-maxtokens-test.mjs +0 -119
- package/scripts/anthropic-oauth-refresh-race-test.mjs +0 -397
- package/scripts/anthropic-transport-policy-test.mjs +0 -726
- package/scripts/apply-patch-edit-smoke.mjs +0 -71
- package/scripts/arg-guard-test.mjs +0 -93
- package/scripts/async-notify-settlement-test.mjs +0 -99
- package/scripts/atomic-lock-tryonce-test.mjs +0 -125
- package/scripts/background-task-meta-smoke.mjs +0 -38
- package/scripts/bench-run.mjs +0 -508
- package/scripts/boot-smoke.mjs +0 -137
- package/scripts/build-runtime-windows.ps1 +0 -242
- package/scripts/channel-daemon-smoke.mjs +0 -1103
- package/scripts/code-graph-aggregate-cwd-test.mjs +0 -158
- package/scripts/code-graph-disk-hit-test.mjs +0 -290
- package/scripts/code-graph-dispatch-test.mjs +0 -96
- package/scripts/code-graph-root-federation-test.mjs +0 -273
- package/scripts/compact-active-turn-test.mjs +0 -68
- package/scripts/compact-file-reattach-test.mjs +0 -88
- package/scripts/compact-pressure-test.mjs +0 -788
- package/scripts/compact-prior-context-flatten-test.mjs +0 -252
- package/scripts/compact-recall-digest-test.mjs +0 -57
- package/scripts/compact-smoke.mjs +0 -1017
- package/scripts/compact-trigger-migration-smoke.mjs +0 -261
- package/scripts/compacted-placeholder-scrub-test.mjs +0 -63
- package/scripts/context-mcp-metering-test.mjs +0 -1406
- package/scripts/debounced-skills-async-save-test.mjs +0 -57
- package/scripts/deferred-tool-loading-test.mjs +0 -250
- package/scripts/desktop-session-bridge-test.mjs +0 -1013
- package/scripts/dispatch-persist-recovery-test.mjs +0 -141
- package/scripts/embedding-worker-exit-test.mjs +0 -76
- package/scripts/execution-completion-dedup-test.mjs +0 -205
- package/scripts/execution-pending-resume-kick-test.mjs +0 -151
- package/scripts/execution-resume-esc-integration-test.mjs +0 -176
- package/scripts/explore-bench-tmp.mjs +0 -36
- package/scripts/explore-bench.mjs +0 -248
- package/scripts/explore-prompt-policy-test.mjs +0 -256
- package/scripts/explore-timeout-cancel-test.mjs +0 -345
- package/scripts/find-fuzzy-hidden-test.mjs +0 -267
- package/scripts/forwarder-rebind-tail-test.mjs +0 -67
- package/scripts/freevar-smoke.mjs +0 -98
- package/scripts/gemini-provider-test.mjs +0 -1448
- package/scripts/generate-oc-icons.mjs +0 -11
- package/scripts/grok-oauth-refresh-race-test.mjs +0 -273
- package/scripts/headless-pristine-execution-test.mjs +0 -614
- package/scripts/hook-bus-test.mjs +0 -552
- package/scripts/ingest-pure-conversation-smoke.mjs +0 -175
- package/scripts/internal-comms-bench-test.mjs +0 -226
- package/scripts/internal-comms-bench.mjs +0 -853
- package/scripts/internal-comms-smoke.mjs +0 -277
- package/scripts/internal-tools-normalization-test.mjs +0 -62
- package/scripts/interrupted-turn-history-test.mjs +0 -399
- package/scripts/lead-workflow-smoke.mjs +0 -592
- package/scripts/lifecycle-api-test.mjs +0 -137
- package/scripts/live-share-test.mjs +0 -148
- package/scripts/live-worker-smoke.mjs +0 -333
- package/scripts/log-writer-guard-smoke.mjs +0 -131
- package/scripts/maintenance-default-routes-test.mjs +0 -164
- package/scripts/max-output-recovery-persist-test.mjs +0 -81
- package/scripts/max-output-recovery-test.mjs +0 -368
- package/scripts/mcp-client-normalization-test.mjs +0 -45
- package/scripts/mcp-grace-deferred-test.mjs +0 -225
- package/scripts/memory-core-input-test.mjs +0 -167
- package/scripts/memory-cycle-routing-test.mjs +0 -111
- package/scripts/memory-meta-concurrency-test.mjs +0 -20
- package/scripts/memory-pg-recovery-test.mjs +0 -59
- package/scripts/memory-rule-contract-test.mjs +0 -93
- package/scripts/model-list-sanitize-test.mjs +0 -37
- package/scripts/mouse-tracking-restore-smoke.mjs +0 -107
- package/scripts/native-edit-wire-test.mjs +0 -152
- package/scripts/notify-completion-mirror-test.mjs +0 -73
- package/scripts/openai-oauth-refresh-race-test.mjs +0 -120
- package/scripts/openai-oauth-ws-1006-retry-test.mjs +0 -954
- package/scripts/openai-ws-early-settle-test.mjs +0 -216
- package/scripts/output-style-bench.mjs +0 -292
- package/scripts/output-style-smoke.mjs +0 -145
- package/scripts/parent-abort-link-test.mjs +0 -90
- package/scripts/patch-binary-cache-test.mjs +0 -181
- package/scripts/path-suffix-test.mjs +0 -57
- package/scripts/pending-completion-drop-test.mjs +0 -239
- package/scripts/pending-messages-lock-nonblocking-test.mjs +0 -62
- package/scripts/pretool-ask-runtime-test.mjs +0 -54
- package/scripts/process-lifecycle-test.mjs +0 -461
- package/scripts/prompt-immediate-render-test.mjs +0 -89
- package/scripts/prompt-input-parity-test.mjs +0 -145
- package/scripts/provider-admission-scheduler-test.mjs +0 -681
- package/scripts/provider-contract-test.mjs +0 -632
- package/scripts/provider-stream-stall-test.mjs +0 -276
- package/scripts/provider-toolcall-test.mjs +0 -3063
- package/scripts/reactive-compact-persist-smoke.mjs +0 -203
- package/scripts/recall-bench.mjs +0 -359
- package/scripts/resource-admission-test.mjs +0 -792
- package/scripts/result-classification-test.mjs +0 -75
- package/scripts/rg-runner-test.mjs +0 -240
- package/scripts/routing-corpus-test.mjs +0 -349
- package/scripts/sanitize-tool-pairs-test.mjs +0 -260
- package/scripts/session-bench-cache-break-test.mjs +0 -102
- package/scripts/session-bench.mjs +0 -1708
- package/scripts/session-context-bench.mjs +0 -344
- package/scripts/session-heartbeat-lifecycle-test.mjs +0 -68
- package/scripts/session-ingest-compaction-smoke.mjs +0 -279
- package/scripts/session-ingest-smoke.mjs +0 -177
- package/scripts/session-orphan-sweep-test.mjs +0 -109
- package/scripts/set-effort-config-test.mjs +0 -41
- package/scripts/shell-failure-diagnostics-test.mjs +0 -280
- package/scripts/shell-hardening-test.mjs +0 -209
- package/scripts/shell-jobs-windows-hide-test.mjs +0 -164
- package/scripts/ship-mode-test.mjs +0 -98
- package/scripts/smoke-loop-failure-summary-test.mjs +0 -38
- package/scripts/smoke-loop-failure-summary.mjs +0 -16
- package/scripts/smoke-loop-report.mjs +0 -221
- package/scripts/smoke-loop.mjs +0 -202
- package/scripts/smoke-runtime-negative.ps1 +0 -106
- package/scripts/statusline-quota-hysteresis-test.mjs +0 -62
- package/scripts/steering-drain-buckets-test.mjs +0 -467
- package/scripts/steering-fold-provenance-test.mjs +0 -71
- package/scripts/streaming-tail-window-test.mjs +0 -175
- package/scripts/submit-commandbusy-race-test.mjs +0 -257
- package/scripts/task-bench.mjs +0 -205
- package/scripts/terminal-bench-isolation-guards-test.mjs +0 -102
- package/scripts/termio-input-smoke.mjs +0 -199
- package/scripts/tool-result-hook-test.mjs +0 -48
- package/scripts/tool-smoke.mjs +0 -2453
- package/scripts/tool-tui-presentation-test.mjs +0 -286
- package/scripts/toolcall-args-test.mjs +0 -239
- package/scripts/tui-ambiguous-width-test.mjs +0 -113
- package/scripts/tui-background-failure-smoke.mjs +0 -73
- package/scripts/tui-perf-run.ps1 +0 -26
- package/scripts/tui-render-smoke.mjs +0 -90
- package/scripts/tui-runtime-load-bench-entry.jsx +0 -608
- package/scripts/tui-runtime-load-bench.mjs +0 -50
- package/scripts/tui-store-frame-batch-test.mjs +0 -99
- package/scripts/tui-transcript-jitter-harness-entry.jsx +0 -383
- package/scripts/tui-transcript-perf-test.mjs +0 -934
- package/scripts/usage-metrics-epoch-smoke.mjs +0 -114
- package/scripts/verify-release-assets-test.mjs +0 -281
- package/scripts/web-fetch-routing-test.mjs +0 -158
- package/scripts/webhook-smoke.mjs +0 -201
- package/scripts/windows-hide-spawn-options-test.mjs +0 -19
- package/scripts/worker-notify-rejection-test.mjs +0 -51
- package/scripts/write-backpressure-test.mjs +0 -147
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
// ChatGPT-backend Responses payload builders, extracted from openai-oauth.mjs.
|
|
2
|
+
/**
|
|
3
|
+
* OpenAI ChatGPT OAuth subscription provider.
|
|
4
|
+
*
|
|
5
|
+
* Dispatches over the WebSocket upgrade of chatgpt.com/backend-api/codex/
|
|
6
|
+
* responses (responses_websockets=2026-02-06 beta). Authenticates via PKCE
|
|
7
|
+
* OAuth using Mixdog-owned token storage. Streaming/framing lives in
|
|
8
|
+
* openai-oauth-ws.mjs; this file owns auth, model catalog, request-body
|
|
9
|
+
* shape, and HTTP/SSE fallback when WebSocket transport is unhealthy.
|
|
10
|
+
*/
|
|
11
|
+
import { createHash } from 'crypto';
|
|
12
|
+
import { readFileSync, existsSync, mkdirSync, statSync, unlinkSync } from 'fs';
|
|
13
|
+
import { join, resolve } from 'path';
|
|
14
|
+
import { getPluginData } from '../config.mjs';
|
|
15
|
+
import { enrichModels } from './model-catalog.mjs';
|
|
16
|
+
import { sanitizeModelList } from './model-list-sanitize.mjs';
|
|
17
|
+
import { writeJsonAtomicSync, withFileLock } from '../../../shared/atomic-file.mjs';
|
|
18
|
+
import { boundProviderAuthPath } from '../../../shared/provider-auth-binding.mjs';
|
|
19
|
+
import { makeModelCache } from './model-cache.mjs';
|
|
20
|
+
|
|
21
|
+
import { sendViaWebSocket } from './openai-oauth-ws.mjs';
|
|
22
|
+
import { _combineUsageWithWarmup } from './openai-ws-events.mjs';
|
|
23
|
+
import { resolveOpenAiTransportPolicy } from './openai-transport-policy.mjs';
|
|
24
|
+
import {
|
|
25
|
+
buildStableProviderPromptCacheKey,
|
|
26
|
+
resolveProviderPromptCacheLane,
|
|
27
|
+
resolveProviderCacheKey,
|
|
28
|
+
} from '../agent-runtime/cache-strategy.mjs';
|
|
29
|
+
import {
|
|
30
|
+
appendAgentTrace,
|
|
31
|
+
traceAgentFetch,
|
|
32
|
+
traceAgentSse,
|
|
33
|
+
traceAgentUsage,
|
|
34
|
+
} from '../agent-trace.mjs';
|
|
35
|
+
import {
|
|
36
|
+
PROVIDER_HTTP_RESPONSE_TIMEOUT_MS,
|
|
37
|
+
PROVIDER_SEMANTIC_IDLE_TIMEOUT_MS,
|
|
38
|
+
PROVIDER_SSE_IDLE_WATCHDOG_ENABLED,
|
|
39
|
+
streamStalledError,
|
|
40
|
+
createTimeoutSignal,
|
|
41
|
+
createPassthroughSignal,
|
|
42
|
+
} from '../stall-policy.mjs';
|
|
43
|
+
import { populateHttpStatusFromMessage, shouldFallbackTransport } from './retry-classifier.mjs';
|
|
44
|
+
import { getLlmDispatcher, preconnect } from '../../../shared/llm/http-agent.mjs';
|
|
45
|
+
import { makeInvalidToolArgsMarker } from './openai-compat-stream.mjs';
|
|
46
|
+
import { createLeakGuard, createToolCallDedupe, dedupeToolCallList } from './anthropic-leaked-toolcall.mjs';
|
|
47
|
+
import {
|
|
48
|
+
normalizeContentForOpenAIResponses,
|
|
49
|
+
splitToolContentForOpenAIResponses,
|
|
50
|
+
} from './media-normalization.mjs';
|
|
51
|
+
import {
|
|
52
|
+
customToolCallFromResponseItem,
|
|
53
|
+
customToolInputFromArguments,
|
|
54
|
+
isCustomToolCallRecord,
|
|
55
|
+
isResponsesFreeformTool,
|
|
56
|
+
nativeToolSearchCallInput,
|
|
57
|
+
nativeToolSearchOutputInput,
|
|
58
|
+
toResponsesCustomTool,
|
|
59
|
+
} from './custom-tool-wire.mjs';
|
|
60
|
+
import {
|
|
61
|
+
sendViaHttpSse,
|
|
62
|
+
_envFlag,
|
|
63
|
+
_shouldUseOpenAIHttpFallback,
|
|
64
|
+
} from './openai-oauth-http-sse.mjs';
|
|
65
|
+
import { createOpenAIOAuthLogin } from './openai-oauth-login.mjs';
|
|
66
|
+
import { warmCodexClientVersion } from './codex-client-meta.mjs';
|
|
67
|
+
import {
|
|
68
|
+
_displayCodexModel,
|
|
69
|
+
_codexFamily,
|
|
70
|
+
_normalizeCodexModel,
|
|
71
|
+
_compareVersion,
|
|
72
|
+
_isMainCodexFamily,
|
|
73
|
+
_markLatestCodex,
|
|
74
|
+
} from './openai-codex-model.mjs';
|
|
75
|
+
|
|
76
|
+
// Public test/integration entry retained alongside the transport module export.
|
|
77
|
+
// --- Constants ---
|
|
78
|
+
|
|
79
|
+
import { _findCachedCodexModel, codexModelSupportsServiceTier } from './openai-oauth.mjs';
|
|
80
|
+
|
|
81
|
+
function _contentTextParts(content, type = 'input_text') {
|
|
82
|
+
if (typeof content === 'string') return content ? [{ type, text: content }] : [];
|
|
83
|
+
if (!Array.isArray(content)) {
|
|
84
|
+
const text = content == null ? '' : JSON.stringify(content);
|
|
85
|
+
return text ? [{ type, text }] : [];
|
|
86
|
+
}
|
|
87
|
+
const out = [];
|
|
88
|
+
for (const item of content) {
|
|
89
|
+
if (!item || typeof item !== 'object') continue;
|
|
90
|
+
if (typeof item.text === 'string') {
|
|
91
|
+
out.push({ type: item.type === 'output_text' ? 'output_text' : type, text: item.text });
|
|
92
|
+
} else if (typeof item.content === 'string') {
|
|
93
|
+
out.push({ type, text: item.content });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Convert a message slice to Responses API input items.
|
|
101
|
+
*/
|
|
102
|
+
export function convertMessagesToResponsesInput(messages, opts = {}) {
|
|
103
|
+
const out = [];
|
|
104
|
+
const pendingToolMedia = [];
|
|
105
|
+
const customToolCallNameById = new Map();
|
|
106
|
+
const wireParity = process.env.MIXDOG_OAI_CODEX_WIRE_PARITY === '1';
|
|
107
|
+
const wireMessage = (role, content) => (wireParity
|
|
108
|
+
? { type: 'message', role, content, internal_chat_message_metadata_passthrough: {} }
|
|
109
|
+
: { role, content });
|
|
110
|
+
const flushToolMedia = () => {
|
|
111
|
+
if (!pendingToolMedia.length) return;
|
|
112
|
+
out.push(wireMessage('user', pendingToolMedia.splice(0)));
|
|
113
|
+
};
|
|
114
|
+
for (const m of messages) {
|
|
115
|
+
if (!m || m.role === 'system') continue;
|
|
116
|
+
if (m.role === 'tool') {
|
|
117
|
+
const { output, mediaContent } = splitToolContentForOpenAIResponses(m.content);
|
|
118
|
+
if (customToolCallNameById.has(m.toolCallId || '')) {
|
|
119
|
+
out.push({
|
|
120
|
+
type: 'custom_tool_call_output',
|
|
121
|
+
call_id: m.toolCallId || '',
|
|
122
|
+
name: customToolCallNameById.get(m.toolCallId || '') || undefined,
|
|
123
|
+
output,
|
|
124
|
+
});
|
|
125
|
+
if (mediaContent) pendingToolMedia.push(...mediaContent);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const nativeSearchOutput = nativeToolSearchOutputInput(
|
|
129
|
+
m,
|
|
130
|
+
opts.nativeToolSearchProvider || 'openai-oauth',
|
|
131
|
+
);
|
|
132
|
+
if (nativeSearchOutput) {
|
|
133
|
+
out.push(nativeSearchOutput);
|
|
134
|
+
if (mediaContent) pendingToolMedia.push(...mediaContent);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
out.push({
|
|
138
|
+
type: 'function_call_output',
|
|
139
|
+
call_id: m.toolCallId || '',
|
|
140
|
+
output,
|
|
141
|
+
});
|
|
142
|
+
if (mediaContent) pendingToolMedia.push(...mediaContent);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
flushToolMedia();
|
|
146
|
+
if (m.role === 'assistant' && Array.isArray(m.toolCalls) && m.toolCalls.length) {
|
|
147
|
+
// Reasoning replay deliberately omitted: openai-oauth rejects an
|
|
148
|
+
// `rs_*` reasoning item with the same id across the same
|
|
149
|
+
// handshake session_id (in-memory conversation state lives
|
|
150
|
+
// for the WS_IDLE_MS window even after a socket close).
|
|
151
|
+
// Server-side state already preserves the prefix; sending
|
|
152
|
+
// reasoning in `input` triggers "Duplicate item".
|
|
153
|
+
if (m.content) out.push(wireMessage('assistant', normalizeContentForOpenAIResponses(m.content, { role: 'assistant' })));
|
|
154
|
+
for (const tc of m.toolCalls) {
|
|
155
|
+
const nativeSearchCall = nativeToolSearchCallInput(tc);
|
|
156
|
+
if (nativeSearchCall) {
|
|
157
|
+
out.push(nativeSearchCall);
|
|
158
|
+
} else if (isCustomToolCallRecord(tc)) {
|
|
159
|
+
if (tc.id) customToolCallNameById.set(tc.id, tc.name || '');
|
|
160
|
+
out.push({
|
|
161
|
+
type: 'custom_tool_call',
|
|
162
|
+
call_id: tc.id,
|
|
163
|
+
name: tc.name,
|
|
164
|
+
input: customToolInputFromArguments(tc.name, tc.arguments),
|
|
165
|
+
});
|
|
166
|
+
} else {
|
|
167
|
+
out.push({
|
|
168
|
+
type: 'function_call',
|
|
169
|
+
call_id: tc.id,
|
|
170
|
+
name: tc.name === 'tool_search' ? 'load_tool' : tc.name,
|
|
171
|
+
arguments: JSON.stringify(tc.arguments),
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
out.push(wireMessage(
|
|
178
|
+
m.role === 'assistant' ? 'assistant' : 'user',
|
|
179
|
+
normalizeContentForOpenAIResponses(m.content, { role: m.role }),
|
|
180
|
+
));
|
|
181
|
+
}
|
|
182
|
+
flushToolMedia();
|
|
183
|
+
return out;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export function toOpenAIResponsesTool(t) {
|
|
187
|
+
if (t?.name === 'load_tool' || t?.name === 'tool_search') {
|
|
188
|
+
return {
|
|
189
|
+
type: 'tool_search',
|
|
190
|
+
execution: 'client',
|
|
191
|
+
description: t.description,
|
|
192
|
+
parameters: t.inputSchema,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
if (isResponsesFreeformTool(t)) return toResponsesCustomTool(t);
|
|
196
|
+
return {
|
|
197
|
+
type: 'function',
|
|
198
|
+
name: t.name,
|
|
199
|
+
description: t.description,
|
|
200
|
+
parameters: t.inputSchema,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export const _convertMessagesToResponsesInputForTest = convertMessagesToResponsesInput;
|
|
205
|
+
|
|
206
|
+
// codex build_reasoning() (core/src/client.rs:785-805) only attaches the
|
|
207
|
+
// reasoning object when model_info.supports_reasoning_summaries; models
|
|
208
|
+
// without summary support get NO reasoning field at all. Mirror that via the
|
|
209
|
+
// cached codex catalog; unknown models default to true (gpt-5 family all
|
|
210
|
+
// support summaries) so a cold catalog cannot strip reasoning from the wire.
|
|
211
|
+
function _codexModelSupportsReasoningSummaries(id) {
|
|
212
|
+
const info = _findCachedCodexModel(id);
|
|
213
|
+
if (!info) return true;
|
|
214
|
+
const flags = [info.supportsReasoningSummaries, info.supports_reasoning_summaries, info.supportsReasoning, info.supports_reasoning];
|
|
215
|
+
for (const flag of flags) {
|
|
216
|
+
if (typeof flag === 'boolean') return flag;
|
|
217
|
+
}
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// codex reasoning_effort_for_request (core/src/client.rs): `ultra` collapses to
|
|
222
|
+
// `max` on the wire — the openai-oauth backend does not accept `ultra`. Every
|
|
223
|
+
// other effort passes through unchanged; empty/unknown falls back to medium.
|
|
224
|
+
export function _normalizeReasoningEffort(effort) {
|
|
225
|
+
const e = String(effort || '').trim().toLowerCase();
|
|
226
|
+
if (!e) return 'medium';
|
|
227
|
+
if (e === 'ultra') return 'max';
|
|
228
|
+
return e;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export function buildRequestBody(messages, model, tools, sendOpts) {
|
|
232
|
+
// codex reasoning_effort_for_request: `ultra` collapses to `max` on the
|
|
233
|
+
// wire (the only remap; every other effort passes through). Default medium.
|
|
234
|
+
// Kept inline (not a module const) so buildRequestBody stays self-contained.
|
|
235
|
+
// Extract system/instructions
|
|
236
|
+
const systemMsgs = messages.filter(m => m.role === 'system');
|
|
237
|
+
const instructions = systemMsgs.map(m => m.content).join('\n\n') || 'You are a helpful assistant.';
|
|
238
|
+
const opts = sendOpts || {};
|
|
239
|
+
const input = convertMessagesToResponsesInput(messages, {
|
|
240
|
+
providerState: opts.providerState,
|
|
241
|
+
model,
|
|
242
|
+
nativeToolSearchProvider: opts.promptCacheProvider || 'openai-oauth',
|
|
243
|
+
});
|
|
244
|
+
// Match the request body shape the OAuth backend expects so the
|
|
245
|
+
// server-side auto-cache routes correctly. text.verbosity / include /
|
|
246
|
+
// tool_choice / parallel_tool_calls are all inert without side effects
|
|
247
|
+
// for most callers but their presence affects how the OAuth backend classifies the
|
|
248
|
+
// request (and therefore whether the prompt cache is consulted).
|
|
249
|
+
const include = ['reasoning.encrypted_content'];
|
|
250
|
+
for (const item of Array.isArray(opts.nativeInclude) ? opts.nativeInclude : []) {
|
|
251
|
+
const value = String(item || '').trim();
|
|
252
|
+
if (value && !include.includes(value)) include.push(value);
|
|
253
|
+
}
|
|
254
|
+
// Field order MIRRORS codex-rs ResponsesApiRequest (common.rs struct order):
|
|
255
|
+
// model, instructions, input, tools, tool_choice, parallel_tool_calls,
|
|
256
|
+
// reasoning, store, stream, include, service_tier, prompt_cache_key, text.
|
|
257
|
+
// JSON serialization order is load-bearing for the server prompt cache
|
|
258
|
+
// (exact-prefix match): matching codex's byte layout keeps our requests on
|
|
259
|
+
// the same cache-routing shape codex warms. tools/service_tier/
|
|
260
|
+
// prompt_cache_key are appended below in the same relative order.
|
|
261
|
+
const body = {
|
|
262
|
+
model,
|
|
263
|
+
instructions,
|
|
264
|
+
input,
|
|
265
|
+
tool_choice: opts.toolChoice || 'auto',
|
|
266
|
+
parallel_tool_calls: true,
|
|
267
|
+
// codex build_reasoning() sends { effort, summary } — summary defaults to
|
|
268
|
+
// ReasoningSummary::Auto (protocol config_types.rs), serialized lowercase
|
|
269
|
+
// as "auto". Matching this keeps our reasoning object byte-identical to
|
|
270
|
+
// codex so the server prompt-cache prefix hash lines up. codex also
|
|
271
|
+
// normalizes `ultra` -> `max` on the wire (reasoning_effort_for_request
|
|
272
|
+
// in core/src/client.rs); the openai-oauth backend does not accept
|
|
273
|
+
// `ultra` as a wire value, so mirror that mapping here.
|
|
274
|
+
// WIRE-VERIFIED (codex desktop logs_2.sqlite, 40 response.create
|
|
275
|
+
// captures, 2026-07-03): codex sends reasoning as {"effort":"..."}
|
|
276
|
+
// with NO summary field on gpt-5.5, regardless of what the repo's
|
|
277
|
+
// build_reasoning() suggests. Match the observed bytes.
|
|
278
|
+
reasoning: { effort: _normalizeReasoningEffort(opts.effort) },
|
|
279
|
+
store: process.env.MIXDOG_OAI_STORE === 'true' ? true : false,
|
|
280
|
+
stream: true,
|
|
281
|
+
include,
|
|
282
|
+
};
|
|
283
|
+
const maxOutputTokens = Number(opts.maxOutputTokens ?? opts.outputTokens ?? opts.max_output_tokens);
|
|
284
|
+
if (_envFlag('MIXDOG_OPENAI_OAUTH_SEND_MAX_OUTPUT_TOKENS', false)
|
|
285
|
+
&& Number.isFinite(maxOutputTokens)
|
|
286
|
+
&& maxOutputTokens > 0) {
|
|
287
|
+
body.max_output_tokens = Math.floor(maxOutputTokens);
|
|
288
|
+
}
|
|
289
|
+
if (opts.fast === true) {
|
|
290
|
+
// 'priority' is the only fast-class value the OpenAI OAuth backend
|
|
291
|
+
// accepts on the wire: 'fast' is hard-rejected ("Unsupported
|
|
292
|
+
// service_tier: fast", probed 2026-06-11). Only send the request value
|
|
293
|
+
// when the model catalog advertises it.
|
|
294
|
+
if (codexModelSupportsServiceTier(model, 'priority')) {
|
|
295
|
+
body.service_tier = 'priority';
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
// Add tools. `nativeTools` are server-hosted Responses tools (for
|
|
299
|
+
// example web_search) and must be passed through without wrapping them as
|
|
300
|
+
// function tools. codex places `tools` right after `input` (before
|
|
301
|
+
// tool_choice); we insert it there via a rebuilt object so serialization
|
|
302
|
+
// order matches, rather than appending it last.
|
|
303
|
+
const functionTools = tools?.length ? tools.map(toOpenAIResponsesTool) : [];
|
|
304
|
+
const nativeTools = Array.isArray(opts.nativeTools)
|
|
305
|
+
? opts.nativeTools.filter(t => t && typeof t === 'object')
|
|
306
|
+
: [];
|
|
307
|
+
const toolsList = (functionTools.length || nativeTools.length)
|
|
308
|
+
? [...nativeTools, ...functionTools]
|
|
309
|
+
: null;
|
|
310
|
+
const promptCacheProvider = opts.promptCacheProvider || 'openai-oauth';
|
|
311
|
+
const promptCacheLane = opts.promptCacheLane || resolveProviderPromptCacheLane(promptCacheProvider, opts);
|
|
312
|
+
const promptCacheKey = buildStableProviderPromptCacheKey(promptCacheProvider, opts, {
|
|
313
|
+
model,
|
|
314
|
+
instructions,
|
|
315
|
+
tools: toolsList || [],
|
|
316
|
+
effort: body.reasoning?.effort,
|
|
317
|
+
fast: opts.fast === true,
|
|
318
|
+
serviceTier: body.service_tier || '',
|
|
319
|
+
toolChoice: body.tool_choice,
|
|
320
|
+
parallelToolCalls: body.parallel_tool_calls,
|
|
321
|
+
cacheLaneSlot: promptCacheLane.slot,
|
|
322
|
+
cacheLaneShards: promptCacheLane.shards,
|
|
323
|
+
});
|
|
324
|
+
// WIRE-VERIFIED (codex desktop logs, 2026-07-03): every live gpt-5.5
|
|
325
|
+
// response.create carries text:{"verbosity":"low"} (or a schema variant);
|
|
326
|
+
// none omit the field. Default to codex's observed "low", allow override.
|
|
327
|
+
const verbosity = (typeof opts.verbosity === 'string' && opts.verbosity.trim()
|
|
328
|
+
? opts.verbosity.trim().toLowerCase()
|
|
329
|
+
: null) || 'low';
|
|
330
|
+
// Rebuild the body in codex struct order so JSON serialization is
|
|
331
|
+
// byte-compatible with codex: ... input, tools, tool_choice,
|
|
332
|
+
// parallel_tool_calls, reasoning, store, stream, include, service_tier,
|
|
333
|
+
// prompt_cache_key, text. service_tier is only present when fast set it.
|
|
334
|
+
const ordered = {
|
|
335
|
+
model: body.model,
|
|
336
|
+
instructions: body.instructions,
|
|
337
|
+
input: body.input,
|
|
338
|
+
...(toolsList ? { tools: toolsList } : {}),
|
|
339
|
+
tool_choice: body.tool_choice,
|
|
340
|
+
parallel_tool_calls: body.parallel_tool_calls,
|
|
341
|
+
reasoning: body.reasoning,
|
|
342
|
+
store: body.store,
|
|
343
|
+
stream: body.stream,
|
|
344
|
+
include: body.include,
|
|
345
|
+
...(body.service_tier ? { service_tier: body.service_tier } : {}),
|
|
346
|
+
prompt_cache_key: promptCacheKey,
|
|
347
|
+
text: { verbosity },
|
|
348
|
+
...(body.max_output_tokens ? { max_output_tokens: body.max_output_tokens } : {}),
|
|
349
|
+
};
|
|
350
|
+
// NOTE: prompt_cache_retention is a public OpenAI Responses API parameter,
|
|
351
|
+
// but the openai-oauth endpoint still rejects it ("Unsupported parameter:
|
|
352
|
+
// prompt_cache_retention", re-probed 2026-06-22). Leave retention on the
|
|
353
|
+
// openai-oauth server default; public OpenAI direct injects 24h separately.
|
|
354
|
+
return ordered;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// --- Provider ---
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
// Codex WS handshake helpers: CF cookie jar, id parity, debug dump redaction. Extracted from openai-ws-pool.mjs.
|
|
2
|
+
/**
|
|
3
|
+
* openai-ws-pool.mjs — WebSocket connection pool for the OpenAI OAuth provider.
|
|
4
|
+
*
|
|
5
|
+
* Extracted from openai-oauth-ws.mjs. Owns the socket pool singleton
|
|
6
|
+
* (_wsPool), handshake/open/acquire/release lifecycle, idle-close timers and
|
|
7
|
+
* the process-exit drain fence. openai-oauth-ws.mjs imports acquire/release/
|
|
8
|
+
* _sendFrame and re-exports the drain hooks for legacy import paths.
|
|
9
|
+
*/
|
|
10
|
+
import WebSocket from 'ws';
|
|
11
|
+
import { errText } from '../../../shared/err-text.mjs';
|
|
12
|
+
import { createHash, randomBytes } from 'crypto';
|
|
13
|
+
import { performance } from 'node:perf_hooks';
|
|
14
|
+
import { appendFileSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
15
|
+
import { join } from 'node:path';
|
|
16
|
+
import { codexOriginator, codexUserAgent, codexVersionHeader } from './codex-client-meta.mjs';
|
|
17
|
+
import {
|
|
18
|
+
PROVIDER_WS_ACQUIRE_TIMEOUT_MS,
|
|
19
|
+
PROVIDER_WS_HANDSHAKE_TIMEOUT_MS,
|
|
20
|
+
PROVIDER_WS_PING_ENABLED,
|
|
21
|
+
PROVIDER_WS_PING_INTERVAL_MS,
|
|
22
|
+
PROVIDER_WS_PONG_TIMEOUT_MS,
|
|
23
|
+
PROVIDER_WS_LIVENESS_STALE_MS,
|
|
24
|
+
resolveTimeoutMs,
|
|
25
|
+
} from '../stall-policy.mjs';
|
|
26
|
+
|
|
27
|
+
// Human-readable transport label for handshake/acquire error messages. Shared
|
|
28
|
+
// with openai-oauth-ws.mjs (stream-side errors use the same labels).
|
|
29
|
+
import { _wsPool, _sendFrame } from './openai-ws-pool.mjs';
|
|
30
|
+
|
|
31
|
+
const _cfCookieJar = new Map(); // accountKey -> { name -> value }
|
|
32
|
+
const _CF_COOKIE_ALLOWLIST = new Set(['__cf_bm', '_cfuvid']);
|
|
33
|
+
|
|
34
|
+
export function _envOn(name) {
|
|
35
|
+
const v = String(process.env[name] || '').trim().toLowerCase();
|
|
36
|
+
return ['1', 'true', 'yes', 'on'].includes(v);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// --- Opt-in Codex fingerprint/id parity knobs ------------------------------
|
|
40
|
+
// All default OFF; unset envs leave the winning combo
|
|
41
|
+
// (MIXDOG_OAI_CODEX_WIRE_PARITY=1 + ws-delta + underscore session_id) exactly
|
|
42
|
+
// as-is. These add EXTRA parity dimensions for backend fingerprint probes.
|
|
43
|
+
|
|
44
|
+
// codex sends dashed RFC-4122 UUIDs as session-id/thread-id (client.rs:1033-
|
|
45
|
+
// 1057); we key those dashed handshake headers off the underscore cacheKey by
|
|
46
|
+
// default. Opt in with MIXDOG_OAI_CODEX_WIRE_PARITY_UUID_IDS to reshape ONLY
|
|
47
|
+
// the dashed pair (session-id/thread-id/x-client-request-id) into codex's UUID
|
|
48
|
+
// format. The value is derived deterministically from the id so it stays
|
|
49
|
+
// stable per cache key (prefix-cache continuity preserved), and the underscore
|
|
50
|
+
// `session_id` header (the backend prefix-dedupe key) is left untouched.
|
|
51
|
+
export function _codexUuidIdParity() {
|
|
52
|
+
const v = String(process.env.MIXDOG_OAI_CODEX_WIRE_PARITY_UUID_IDS || '').trim().toLowerCase();
|
|
53
|
+
return ['1', 'true', 'yes', 'on', 'uuid', 'dashed'].includes(v);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function _codexDashedId(value) {
|
|
57
|
+
const h = createHash('sha256').update(String(value)).digest();
|
|
58
|
+
const b = Buffer.from(h.subarray(0, 16));
|
|
59
|
+
b[6] = (b[6] & 0x0f) | 0x50; // version 5 nibble
|
|
60
|
+
b[8] = (b[8] & 0x3f) | 0x80; // RFC-4122 variant
|
|
61
|
+
const hex = b.toString('hex');
|
|
62
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Opt-in turn-state gate experiment bundle (MIXDOG_OAI_CODEX_TURN_STATE_GATE).
|
|
66
|
+
// The debugger's working hypothesis for what gates x-codex-turn-state issuance
|
|
67
|
+
// is a specific wire shape: Codex-shaped UUIDv7 session/thread ids + dashed-only
|
|
68
|
+
// handshake headers (drop the underscore session_id) + NO duplicated
|
|
69
|
+
// x-client-request-id + a parent-thread header (added in openai-oauth-ws.mjs).
|
|
70
|
+
// This env ties those dimensions together as ONE experiment so operators can
|
|
71
|
+
// A/B the whole gate shape without hand-composing four flags. Default OFF; it
|
|
72
|
+
// leaves MIXDOG_OAI_CODEX_WIRE_PARITY_UUID_IDS / _SESSION_ID and every existing
|
|
73
|
+
// flag intact and only reshapes the wire when explicitly enabled.
|
|
74
|
+
export function _codexTurnStateGate() {
|
|
75
|
+
const v = String(process.env.MIXDOG_OAI_CODEX_TURN_STATE_GATE || '').trim().toLowerCase();
|
|
76
|
+
return ['1', 'true', 'yes', 'on'].includes(v);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Same derivation as _codexDashedId but stamps the version-7 nibble so the
|
|
80
|
+
// dashed pair reads as a Codex-shaped UUIDv7. Deterministic per id (prefix
|
|
81
|
+
// cache continuity preserved); only used under the turn-state gate bundle.
|
|
82
|
+
export function _codexDashedIdV7(value) {
|
|
83
|
+
const h = createHash('sha256').update(String(value)).digest();
|
|
84
|
+
const b = Buffer.from(h.subarray(0, 16));
|
|
85
|
+
b[6] = (b[6] & 0x0f) | 0x70; // version 7 nibble
|
|
86
|
+
b[8] = (b[8] & 0x3f) | 0x80; // RFC-4122 variant
|
|
87
|
+
const hex = b.toString('hex');
|
|
88
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// codex advertises enabled beta features on the WS handshake; the backend
|
|
92
|
+
// plausibly gates x-codex-turn-state issuance on that list (see the
|
|
93
|
+
// x-codex-beta-features comment below). MIXDOG_CODEX_BETA_FEATURES replaces the
|
|
94
|
+
// whole list; MIXDOG_OAI_CODEX_TURN_STATE_FEATURES is a safe ADD-ONLY opt-in
|
|
95
|
+
// that appends turn-state-gating feature token(s) (comma-separated, de-duped)
|
|
96
|
+
// without dropping the default `remote_compaction_v2`. Unset = default list.
|
|
97
|
+
export function _codexBetaFeatures() {
|
|
98
|
+
const base = process.env.MIXDOG_CODEX_BETA_FEATURES || 'remote_compaction_v2';
|
|
99
|
+
const extra = String(process.env.MIXDOG_OAI_CODEX_TURN_STATE_FEATURES || '').trim();
|
|
100
|
+
if (!extra) return base;
|
|
101
|
+
const seen = new Set();
|
|
102
|
+
const out = [];
|
|
103
|
+
for (const tok of `${base},${extra}`.split(',').map((s) => s.trim()).filter(Boolean)) {
|
|
104
|
+
if (seen.has(tok)) continue;
|
|
105
|
+
seen.add(tok);
|
|
106
|
+
out.push(tok);
|
|
107
|
+
}
|
|
108
|
+
return out.join(',');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// --- Opt-in raw WS capture for byte-diff against codex-rs -------------------
|
|
112
|
+
// Enabled ONLY when MIXDOG_OAI_WS_DUMP_DIR names a directory. Persists the
|
|
113
|
+
// (redacted) handshake header metadata and the exact serialized
|
|
114
|
+
// response.create frame bytes so our wire format can be byte-diffed against
|
|
115
|
+
// codex. Secrets (Authorization / Cookie / account-id / routing tokens) are
|
|
116
|
+
// hashed, never written in clear. When the env is unset both helpers are
|
|
117
|
+
// no-ops, so there is no default behavior change.
|
|
118
|
+
const _WS_DUMP_SECRET_RE = /^(authorization|proxy-authorization|cookie|set-cookie|chatgpt-account-id|x-codex-turn-state|session_id|session-id|thread-id|x-codex-parent-thread-id|x-client-request-id|x-session-affinity)$/i;
|
|
119
|
+
|
|
120
|
+
function _wsDumpDir() {
|
|
121
|
+
const dir = String(process.env.MIXDOG_OAI_WS_DUMP_DIR || '').trim();
|
|
122
|
+
return dir || null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function _redactHeaderValue(key, value) {
|
|
126
|
+
const v = String(value ?? '');
|
|
127
|
+
if (_WS_DUMP_SECRET_RE.test(String(key))) {
|
|
128
|
+
if (!v) return '';
|
|
129
|
+
return `<redacted:sha256:${createHash('sha256').update(v).digest('hex').slice(0, 12)}:len${v.length}>`;
|
|
130
|
+
}
|
|
131
|
+
return v;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function _redactDumpUrl(url) {
|
|
135
|
+
try {
|
|
136
|
+
const parsed = new URL(String(url));
|
|
137
|
+
for (const [key, value] of parsed.searchParams.entries()) {
|
|
138
|
+
if (_WS_DUMP_SECRET_RE.test(String(key))) {
|
|
139
|
+
parsed.searchParams.set(key, _redactHeaderValue(key, value));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return parsed.toString();
|
|
143
|
+
} catch {
|
|
144
|
+
return String(url || '');
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function _dumpHandshakeHeaders(url, headers) {
|
|
149
|
+
const dir = _wsDumpDir();
|
|
150
|
+
if (!dir) return;
|
|
151
|
+
try {
|
|
152
|
+
mkdirSync(dir, { recursive: true });
|
|
153
|
+
const redacted = {};
|
|
154
|
+
for (const [k, v] of Object.entries(headers || {})) redacted[k] = _redactHeaderValue(k, v);
|
|
155
|
+
const rec = {
|
|
156
|
+
ts: new Date().toISOString(),
|
|
157
|
+
kind: 'ws_handshake',
|
|
158
|
+
url: _redactDumpUrl(url),
|
|
159
|
+
// Header order matters for the codex byte-diff; keep it explicit.
|
|
160
|
+
headerOrder: Object.keys(headers || {}),
|
|
161
|
+
headers: redacted,
|
|
162
|
+
};
|
|
163
|
+
const stamp = `${Date.now()}-${randomBytes(4).toString('hex')}`;
|
|
164
|
+
writeFileSync(join(dir, `handshake-${stamp}.json`), JSON.stringify(rec, null, 2));
|
|
165
|
+
} catch {}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function _dumpFrame(payload) {
|
|
169
|
+
const dir = _wsDumpDir();
|
|
170
|
+
if (!dir) return;
|
|
171
|
+
try {
|
|
172
|
+
mkdirSync(dir, { recursive: true });
|
|
173
|
+
const stamp = `${Date.now()}-${randomBytes(4).toString('hex')}`;
|
|
174
|
+
// Persist the serialized response.create bytes for codex byte-diff,
|
|
175
|
+
// but never dump x-codex-turn-state in clear. That token is a
|
|
176
|
+
// per-turn credential-like routing secret; header dumps already hash
|
|
177
|
+
// it, so frame dumps must do the same when client_metadata carries it.
|
|
178
|
+
let out = payload;
|
|
179
|
+
try {
|
|
180
|
+
const frame = JSON.parse(String(payload));
|
|
181
|
+
const meta = frame?.client_metadata;
|
|
182
|
+
if (meta && typeof meta === 'object' && typeof meta['x-codex-turn-state'] === 'string') {
|
|
183
|
+
meta['x-codex-turn-state'] = _redactHeaderValue('x-codex-turn-state', meta['x-codex-turn-state']);
|
|
184
|
+
out = JSON.stringify(frame);
|
|
185
|
+
}
|
|
186
|
+
} catch {}
|
|
187
|
+
writeFileSync(join(dir, `frame-${stamp}.json`), out);
|
|
188
|
+
} catch {}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function _cfCookieAccountKey(auth) {
|
|
192
|
+
return String(auth?.account_id || auth?.apiKey || 'default');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function _cfCookieHeader(auth) {
|
|
196
|
+
if (!_envOn('MIXDOG_OAI_CF_COOKIES')) return null;
|
|
197
|
+
const jar = _cfCookieJar.get(_cfCookieAccountKey(auth));
|
|
198
|
+
if (!jar || !jar.size) return null;
|
|
199
|
+
return [...jar.entries()].map(([k, v]) => `${k}=${v}`).join('; ');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export function _cfCookieCapture(auth, setCookieHeaders) {
|
|
203
|
+
if (!_envOn('MIXDOG_OAI_CF_COOKIES')) return;
|
|
204
|
+
const list = Array.isArray(setCookieHeaders) ? setCookieHeaders : (setCookieHeaders ? [setCookieHeaders] : []);
|
|
205
|
+
if (!list.length) return;
|
|
206
|
+
const key = _cfCookieAccountKey(auth);
|
|
207
|
+
let jar = _cfCookieJar.get(key);
|
|
208
|
+
if (!jar) { jar = new Map(); _cfCookieJar.set(key, jar); }
|
|
209
|
+
for (const raw of list) {
|
|
210
|
+
const pair = String(raw || '').split(';', 1)[0];
|
|
211
|
+
const eq = pair.indexOf('=');
|
|
212
|
+
if (eq <= 0) continue;
|
|
213
|
+
const name = pair.slice(0, eq).trim();
|
|
214
|
+
if (_CF_COOKIE_ALLOWLIST.has(name)) jar.set(name, pair.slice(eq + 1).trim());
|
|
215
|
+
}
|
|
216
|
+
}
|