mixdog 1.2.1 → 1.2.3
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 +18 -0
- package/package.json +2 -1
- package/scripts/gate-local.mjs +19 -3
- package/scripts/model-catalog-audit.mjs +1 -15
- package/scripts/provider-pingpong-live.mjs +509 -0
- package/src/agents/advisor/AGENT.md +1 -1
- package/src/agents/advisor/agent.json +1 -1
- package/src/agents/reviewer/AGENT.md +3 -3
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +6 -0
- package/src/defaults/skills/setup/SKILL.md +6 -1
- package/src/defaults/skills/setup/references/actions.md +44 -22
- package/src/defaults/skills/setup/references/surfaces.md +10 -8
- package/src/headless-exec.mjs +15 -8
- package/src/lib/keychain-cjs.cjs +7 -4
- package/src/output-styles/common.md +11 -10
- package/src/repl/slash-commands.mjs +16 -1
- package/src/rules/agent/AGENT.md +5 -5
- package/src/rules/lead/LEAD.md +5 -5
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -4
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +10 -0
- package/src/runtime/agent/orchestrator/agent-trace-io.mjs +92 -61
- package/src/runtime/agent/orchestrator/cache-mtime.mjs +10 -1
- package/src/runtime/agent/orchestrator/config-providers-merge.mjs +7 -0
- package/src/runtime/agent/orchestrator/config.mjs +5 -0
- package/src/runtime/agent/orchestrator/context/collect.mjs +1 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +26 -7
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +112 -7
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +36 -7
- package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +49 -10
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +40 -3
- package/src/runtime/agent/orchestrator/mcp/client.mjs +230 -96
- package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +103 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +150 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +111 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +87 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +95 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-request.mjs +122 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +9 -0
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +229 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +188 -29
- package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +48 -20
- package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +94 -31
- package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +98 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +39 -18
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +55 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +48 -37
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +10 -7
- package/src/runtime/agent/orchestrator/providers/anthropic-midstream-recovery.mjs +18 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +13 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-midstream.mjs +10 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-recovery.mjs +23 -9
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +46 -20
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request.mjs +14 -9
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +102 -45
- package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +69 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-blocks.mjs +20 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-delta.mjs +15 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +11 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/message-events.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +12 -5
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-outcome.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-state.mjs +14 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +10 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +40 -7
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +30 -9
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +88 -21
- package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +30 -10
- package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +106 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +10 -61
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +94 -15
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +117 -72
- package/src/runtime/agent/orchestrator/providers/compat-request-policy.mjs +78 -2
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +75 -10
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-wire-guards.mjs +97 -2
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +103 -23
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +43 -2
- package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +103 -33
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +32 -6
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +27 -3
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +64 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +70 -6
- package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +34 -7
- package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +32 -6
- package/src/runtime/agent/orchestrator/providers/deepseek.mjs +67 -0
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +80 -18
- package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +11 -4
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +46 -8
- package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +273 -0
- package/src/runtime/agent/orchestrator/providers/gemini-family.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/gemini-history-signatures.mjs +9 -4
- package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +41 -5
- package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +180 -0
- package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +369 -112
- package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +140 -35
- package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +70 -24
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +80 -29
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +69 -19
- package/src/runtime/agent/orchestrator/providers/lib/action-input-contract.mjs +60 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +246 -42
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-server-tool-usage.mjs +18 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-system-blocks.mjs +27 -6
- package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +388 -0
- package/src/runtime/agent/orchestrator/providers/lib/inclusive-usage.mjs +54 -0
- package/src/runtime/agent/orchestrator/providers/lib/origin-bound-fetch.mjs +16 -0
- package/src/runtime/agent/orchestrator/providers/lib/responses-terminal-fields.mjs +11 -0
- package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +48 -22
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +119 -18
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +13 -15
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +1 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +33 -1
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +4 -9
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +123 -61
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +35 -14
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +27 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +37 -7
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/tool-call-acc.mjs +2 -9
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +50 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +47 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +47 -25
- package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +5 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +151 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +64 -23
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +79 -33
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2901 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +172 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +144 -15
- package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +193 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +66 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +109 -26
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +27 -6
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +34 -20
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +23 -4
- package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +37 -28
- package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +274 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +72 -32
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +23 -10
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +43 -15
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +10 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-items.mjs +18 -7
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-stamps.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +7 -3
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/text-relay.mjs +9 -1
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +1 -3
- package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +80 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +37 -4
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +12 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +22 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +12 -1
- package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +76 -33
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +323 -0
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +44 -16
- package/src/runtime/agent/orchestrator/providers/openai-retry-policy.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +7 -16
- package/src/runtime/agent/orchestrator/providers/openai-ws-handshake.mjs +16 -8
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/refusals.mjs +60 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +51 -35
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state.mjs +30 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +1 -2
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/policy.mjs +25 -14
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +12 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/terminal-frames.mjs +25 -6
- package/src/runtime/agent/orchestrator/providers/openai-ws-terminal.mjs +18 -11
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +41 -22
- package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +170 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +75 -70
- package/src/runtime/agent/orchestrator/providers/openrouter.mjs +75 -0
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +720 -0
- package/src/runtime/agent/orchestrator/providers/registry.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/retry-backoff.mjs +46 -7
- package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +123 -219
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +148 -45
- package/src/runtime/agent/orchestrator/providers/retry-midstream.mjs +81 -16
- package/src/runtime/agent/orchestrator/providers/transport-scope.d.mts +6 -0
- package/src/runtime/agent/orchestrator/providers/transport-scope.mjs +28 -0
- package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +157 -0
- package/src/runtime/agent/orchestrator/providers/wire-route.mjs +512 -0
- package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +1131 -0
- package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +183 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +100 -0
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +21 -0
- package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -0
- package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +0 -18
- package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +57 -28
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +19 -16
- package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -97
- package/src/runtime/agent/orchestrator/runtime-core/provider-request-snapshot.mjs +7 -3
- package/src/runtime/agent/orchestrator/runtime-core/session-title.mjs +21 -1
- package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +14 -3
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +526 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +10 -7
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +176 -71
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +62 -10
- package/src/runtime/agent/orchestrator/runtime-core/tool-exposure.mjs +96 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/compact/constants.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +14 -93
- package/src/runtime/agent/orchestrator/session/compact/summary-anchor.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +120 -0
- package/src/runtime/agent/orchestrator/session/context-tool-schema.mjs +17 -2
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -4
- package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +6 -1
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +91 -1
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +56 -0
- package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +18 -8
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +21 -10
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +132 -0
- package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +30 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +67 -20
- package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +104 -19
- package/src/runtime/agent/orchestrator/session/loop/tool-call-resolution.mjs +95 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +30 -3
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +150 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +7 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +30 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +34 -12
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +57 -21
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +57 -25
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +5 -10
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +208 -14
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +16 -4
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +25 -3
- package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +82 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +19 -2
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +18 -7
- package/src/runtime/agent/orchestrator/session/manager.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +168 -29
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +96 -0
- package/src/runtime/agent/orchestrator/session/side-question.mjs +192 -0
- package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +17 -3
- package/src/runtime/agent/orchestrator/session/store/live-state.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +58 -2
- package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +6 -3
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +41 -28
- package/src/runtime/agent/orchestrator/session/store/session-observers.mjs +4 -2
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +12 -1
- package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +22 -10
- package/src/runtime/agent/orchestrator/session/store-summary-archived-agent.mjs +34 -15
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +10 -2
- package/src/runtime/agent/orchestrator/session/store.mjs +19 -3
- package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +77 -0
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +20 -1
- package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +8 -2
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +12 -15
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +14 -10
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +49 -34
- package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +23 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +73 -39
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +18 -1
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -4
- package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +88 -12
- package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +2 -0
- package/src/runtime/computer-bridge/action-schema.mjs +44 -21
- package/src/runtime/github/tool.mjs +92 -2
- package/src/runtime/memory/index.mjs +1 -0
- package/src/runtime/memory/lib/http-router/ingest-routes.mjs +22 -1
- package/src/runtime/memory/lib/ingest/transcript-offsets.mjs +2 -0
- package/src/runtime/memory/lib/pg/adapter.mjs +98 -1
- package/src/runtime/memory/lib/pg/process.mjs +65 -50
- package/src/runtime/memory/lib/pg/run-child.mjs +49 -0
- package/src/runtime/memory/lib/pg/supervisor.mjs +124 -16
- package/src/runtime/memory/lib/runtime-fetcher.mjs +12 -13
- package/src/runtime/memory/lib/transcript-ingest.mjs +14 -0
- package/src/runtime/office/README.md +2 -2
- package/src/runtime/office/authoring/html-document-author.mjs +2 -0
- package/src/runtime/office/authoring/pptx-contact-sheet.mjs +2 -0
- package/src/runtime/office/authoring/pptx-html-measure.mjs +2 -0
- package/src/runtime/office/authoring/pptx-html-runner.mjs +2 -0
- package/src/runtime/office/authoring/xlsx-html-runner.mjs +2 -0
- package/src/runtime/office/core/office-actions-read.mjs +3 -0
- package/src/runtime/office/core/office-render-preview.mjs +2 -0
- package/src/runtime/office/core/office-session-dispatch.mjs +7 -0
- package/src/runtime/office/core/office-sessionless-actions.mjs +8 -0
- package/src/runtime/office/core/office-sessions.mjs +5 -0
- package/src/runtime/office/core/office-transactions.mjs +3 -0
- package/src/runtime/office/core/office-write-ledger.mjs +98 -0
- package/src/runtime/office/design/library/templates/mixdog-executive.mixdog-edit.pptx +0 -0
- package/src/runtime/office/index.mjs +30 -0
- package/src/runtime/office/pdf/pdf-edit-document.mjs +2 -0
- package/src/runtime/office/pdf/pdf-render.mjs +23 -7
- package/src/runtime/office/pdf/pdf-security.mjs +2 -0
- package/src/runtime/office/portable/portable-opc.mjs +4 -1
- package/src/runtime/office/quality/visual-diff.mjs +2 -0
- package/src/runtime/office/shared/values.mjs +0 -5
- package/src/runtime/shared/background-tasks.mjs +92 -14
- package/src/runtime/shared/bounded-file-read.mjs +13 -0
- package/src/runtime/shared/bounded-line-diff.mjs +182 -0
- package/src/runtime/shared/buffered-appender.mjs +18 -0
- package/src/runtime/shared/config.mjs +78 -18
- package/src/runtime/shared/err-text.mjs +31 -0
- package/src/runtime/shared/error-presentation.mjs +159 -19
- package/src/runtime/shared/file-permissions.d.mts +6 -1
- package/src/runtime/shared/file-permissions.mjs +54 -6
- package/src/runtime/shared/llm/anthropic-betas.mjs +4 -3
- package/src/runtime/shared/llm/anthropic-effort.mjs +129 -134
- package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +50 -14
- package/src/runtime/shared/llm/model-catalog.mjs +53 -40
- package/src/runtime/shared/llm/openai-daybreak.mjs +4 -16
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +11 -0
- package/src/runtime/shared/llm/provider-model-identities.mjs +13 -4
- package/src/runtime/shared/llm/usage-accounting.mjs +5 -2
- package/src/runtime/shared/llm/usage-ledger-rollup.mjs +3 -0
- package/src/runtime/shared/llm/usage-rollup.mjs +0 -1
- package/src/runtime/shared/loopback-listener.mjs +9 -0
- package/src/runtime/shared/model-display.mjs +13 -0
- package/src/runtime/shared/provider-api-key.mjs +2 -0
- package/src/runtime/shared/quota-resume-store.mjs +11 -0
- package/src/runtime/shared/review-diff.mjs +52 -0
- package/src/runtime/shared/session-baseline-store.mjs +960 -0
- package/src/runtime/shared/session-sidebar-host.d.mts +4 -0
- package/src/runtime/shared/session-sidebar-host.mjs +38 -0
- package/src/runtime/shared/slow-span.mjs +114 -0
- package/src/runtime/shared/statusline/statusline-format.mjs +4 -4
- package/src/runtime/shared/statusline/statusline-segments.mjs +28 -4
- package/src/runtime/shared/task-notification-envelope.mjs +2 -2
- package/src/runtime/shared/tool-card-model/card-header.mjs +6 -1
- package/src/runtime/shared/tool-card-model/generic-detail.mjs +39 -5
- package/src/runtime/shared/tool-card-model.mjs +5 -2
- package/src/runtime/shared/tool-output-limit.mjs +4 -0
- package/src/runtime/shared/tool-primitives.mjs +13 -0
- package/src/runtime/shared/tool-result-summary.mjs +8 -1
- package/src/runtime/shared/tool-surface.mjs +18 -3
- package/src/runtime/shared/tool-work-units.mjs +40 -4
- package/src/runtime/shared/transcript-writer/purge.mjs +74 -0
- package/src/runtime/shared/transcript-writer.mjs +10 -2
- package/src/runtime/shared/turn-changes.mjs +670 -274
- package/src/runtime/shared/turn-review-reply.mjs +8 -39
- package/src/runtime/shared/turn-snapshot-store.mjs +94 -2
- package/src/runtime/shared/turn-snapshot.mjs +986 -690
- package/src/runtime/shared/turn-worktree-snapshot.mjs +279 -262
- package/src/runtime/shared/user-data-guard.mjs +262 -49
- package/src/runtime/shared/worktrees/carry.mjs +531 -0
- package/src/runtime/shared/worktrees/contract.mjs +34 -24
- package/src/runtime/shared/worktrees/file-recovery.mjs +68 -0
- package/src/runtime/shared/worktrees/git-head.mjs +205 -0
- package/src/runtime/shared/worktrees/git.mjs +8 -3
- package/src/runtime/shared/worktrees/maintenance.mjs +1 -1
- package/src/runtime/shared/worktrees/manager.mjs +156 -8
- package/src/runtime/shared/worktrees/merge.mjs +31 -21
- package/src/runtime/shared/worktrees/paths.d.mts +6 -0
- package/src/runtime/shared/worktrees/test-support.mjs +19 -4
- package/src/runtime/terminal-bridge/client.mjs +44 -11
- package/src/runtime/terminal-bridge/tool-defs.mjs +13 -6
- package/src/runtime/tidy/apply.mjs +47 -2
- package/src/runtime/tidy/run-engines.mjs +11 -5
- package/src/session-runtime/agent-tool-routing.mjs +19 -13
- package/src/session-runtime/boot/apis.mjs +19 -5
- package/src/session-runtime/boot/facade.mjs +1 -0
- package/src/session-runtime/boot/infrastructure.mjs +12 -1
- package/src/session-runtime/boot/session.mjs +0 -1
- package/src/session-runtime/boot/tools.mjs +4 -1
- package/src/session-runtime/cwd-plugins/cwd-apply.mjs +12 -5
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +65 -0
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -1
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +11 -4
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +115 -18
- package/src/session-runtime/internal-tool-executor.mjs +6 -2
- package/src/session-runtime/lifecycle/cold-heir.mjs +188 -0
- package/src/session-runtime/lifecycle/inheritance.mjs +71 -27
- package/src/session-runtime/lifecycle/session-catalog.mjs +14 -3
- package/src/session-runtime/lifecycle/session-switch/resume.mjs +6 -0
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +29 -6
- package/src/session-runtime/lifecycle/teardown.mjs +73 -8
- package/src/session-runtime/lifecycle-api.mjs +1 -0
- package/src/session-runtime/mcp-glue/connect.mjs +46 -14
- package/src/session-runtime/mcp-glue/server-catalog.mjs +20 -3
- package/src/session-runtime/mcp-glue.mjs +3 -0
- package/src/session-runtime/mcp-oauth-login.mjs +174 -0
- package/src/session-runtime/model-route/model-switch-target.mjs +34 -0
- package/src/session-runtime/model-route/set-route.mjs +85 -17
- package/src/session-runtime/model-route/web-search-route.mjs +1 -1
- package/src/session-runtime/native-web-search/routes.mjs +22 -3
- package/src/session-runtime/native-web-search-usage.mjs +51 -0
- package/src/session-runtime/native-web-search.mjs +10 -1
- package/src/session-runtime/new-session-config.mjs +4 -2
- package/src/session-runtime/provider-auth/login.mjs +4 -0
- package/src/session-runtime/provider-models/model-meta.mjs +12 -3
- package/src/session-runtime/quick-model-rows/web-search-rows.mjs +13 -8
- package/src/session-runtime/quick-web-search-models.mjs +13 -38
- package/src/session-runtime/resource-extension-sync.mjs +4 -0
- package/src/session-runtime/resource-mcp-api.mjs +98 -2
- package/src/session-runtime/resource-scope-decorate.mjs +10 -3
- package/src/session-runtime/runtime-review-api.mjs +21 -2
- package/src/session-runtime/services/agent-tool/index-write-queue.mjs +81 -20
- package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +13 -1
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +7 -2
- package/src/session-runtime/services/agent-tool/lead-worker-index/forgotten-leads.mjs +29 -0
- package/src/session-runtime/services/agent-tool/lead-worker-index/index-file.mjs +1 -1
- package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +73 -7
- package/src/session-runtime/services/agent-tool/send-flow.mjs +22 -4
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +2 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +22 -5
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +15 -1
- package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -1
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -2
- package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +10 -1
- package/src/session-runtime/services/agent-tool/worker-index.mjs +46 -7
- package/src/session-runtime/services/agent-tool/worker-rows.mjs +17 -0
- package/src/session-runtime/services/agent-tool.mjs +3 -0
- package/src/session-runtime/services/channel-admin.mjs +19 -3
- package/src/session-runtime/services/memory-runtime-proxy/calls.mjs +4 -0
- package/src/session-runtime/services/memory-runtime-proxy.mjs +1 -0
- package/src/session-runtime/services/provider-admin.mjs +81 -15
- package/src/session-runtime/session-transcript-purge.mjs +32 -0
- package/src/session-runtime/session-turn-api.mjs +14 -5
- package/src/session-runtime/settings-builtin-tools-api.mjs +9 -0
- package/src/session-runtime/settings-compaction-api.mjs +1 -0
- package/src/session-runtime/setup-tool/executor.mjs +36 -6
- package/src/session-runtime/setup-tool/extended-actions.mjs +86 -6
- package/src/session-runtime/setup-tool/settings-contract.mjs +13 -3
- package/src/session-runtime/setup-tool/tool-defs.mjs +13 -4
- package/src/session-runtime/skills-api.mjs +3 -5
- package/src/session-runtime/tool-surface.mjs +5 -1
- package/src/session-runtime/turn/compaction-gate.mjs +25 -0
- package/src/session-runtime/turn/session-ops.mjs +7 -5
- package/src/session-runtime/turn/side-question-ops.mjs +22 -0
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +5 -1
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +8 -3
- package/src/session-runtime/turn/turn-run/turn-settle.mjs +10 -0
- package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
- package/src/session-runtime/turn/turn-run.mjs +25 -9
- package/src/session-runtime/usage-stats-api.mjs +43 -11
- package/src/session-runtime/workspace/project-branches.mjs +7 -5
- package/src/session-runtime/workspace/transition-steps.mjs +129 -31
- package/src/session-runtime/workspace/transitions.mjs +190 -15
- package/src/standalone/daemon-agent-control.mjs +9 -1
- package/src/standalone/daemon-drain-policy.mjs +8 -0
- package/src/standalone/daemon-local-session-bridge.mjs +14 -1
- package/src/standalone/daemon-owner.mjs +17 -4
- package/src/standalone/daemon-pg-stop.mjs +51 -0
- package/src/standalone/daemon-stop-budget.d.mts +2 -0
- package/src/standalone/daemon-stop-budget.mjs +18 -0
- package/src/standalone/daemon-stored-session-views.mjs +2 -0
- package/src/standalone/daemon-telemetry.mjs +74 -0
- package/src/standalone/daemon.mjs +64 -8
- package/src/standalone/desktop-service-registry.mjs +5 -0
- package/src/standalone/local-session-runtime.mjs +70 -19
- package/src/standalone/session-client.mjs +42 -0
- package/src/standalone/session-protocol.mjs +14 -0
- package/src/standalone/session-proxy/projection.mjs +41 -4
- package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +15 -1
- package/src/standalone/session-runtime-inline-host.mjs +1 -0
- package/src/standalone/session-service/agent-tree/agent-cancel.mjs +33 -2
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +26 -10
- package/src/standalone/session-service/agent-tree.mjs +12 -0
- package/src/standalone/session-service/quota-resume.mjs +8 -0
- package/src/standalone/session-service/retention/busy.mjs +15 -1
- package/src/standalone/session-service/session-calls/session-action.mjs +18 -3
- package/src/standalone/session-service-api.mjs +11 -1
- package/src/standalone/session-service.mjs +1 -0
- package/src/standalone/session-state-patch.d.mts +2 -1
- package/src/standalone/session-state-patch.mjs +41 -1
- package/src/tui/App.jsx +25 -0
- package/src/tui/app/app-view/floating-panel.jsx +26 -1
- package/src/tui/app/app-view.jsx +1 -0
- package/src/tui/app/btw-controller.mjs +118 -0
- package/src/tui/app/create-app-pickers.mjs +6 -0
- package/src/tui/app/extension-pickers/mcp-login.mjs +107 -0
- package/src/tui/app/extension-pickers/mcp-servers-picker.mjs +2 -1
- package/src/tui/app/extension-pickers.mjs +2 -1
- package/src/tui/app/model-options.mjs +11 -16
- package/src/tui/app/shell-layout/row-budgets.mjs +11 -1
- package/src/tui/app/shell-layout/surfaces.mjs +3 -1
- package/src/tui/app/slash-commands.mjs +20 -5
- package/src/tui/app/slash-dispatch/panel-commands.mjs +16 -1
- package/src/tui/app/slash-dispatch/session-commands.mjs +19 -6
- package/src/tui/app/use-global-key-input/approval-shortcut.mjs +12 -0
- package/src/tui/app/use-global-key-input.mjs +5 -12
- package/src/tui/app/use-prompt-handlers.mjs +11 -0
- package/src/tui/components/BtwPanel.jsx +53 -0
- package/src/tui/components/QuestionPanel.jsx +275 -0
- package/src/tui/components/StatusLine.jsx +2 -0
- package/src/tui/components/question-panel-model.mjs +156 -0
- package/src/tui/components/status-line/local-line.mjs +5 -2
- package/src/tui/components/status-line/use-statusline-text.mjs +7 -1
- package/src/tui/dist/index.mjs +3221 -1500
- package/src/tui/session/context-state.mjs +4 -2
- package/src/tui/session/quota-resume.mjs +46 -14
- package/src/tui/session/session-api/commands.mjs +43 -24
- package/src/tui/session/session-api/controls.mjs +2 -2
- package/src/tui/session/session-api/extensions.mjs +22 -0
- package/src/tui/session/session-api/integrations.mjs +16 -2
- package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
- package/src/tui/session/session-api/lifecycle.mjs +7 -2
- package/src/tui/session/session-api/routes.mjs +71 -7
- package/src/tui/session/session-api/settings.mjs +11 -14
- package/src/tui/session/session-api.mjs +1 -0
- package/src/tui/session/session-flow/drain.mjs +7 -1
- package/src/tui/session/session-flow/failed-turn-rewind.mjs +10 -4
- package/src/tui/session/tool-approval.mjs +10 -7
- package/src/tui/session/transcript-spill.mjs +14 -7
- package/src/tui/session/turn-stream.mjs +174 -31
- package/src/tui/session/turn.mjs +46 -16
- package/src/tui/statusline-ansi-bridge.mjs +1 -1
- package/src/ui/statusline-agents.mjs +15 -4
- package/src/ui/statusline.mjs +7 -3
- package/src/ui/streaming-markdown-heal.mjs +34 -3
- package/src/vendor/statusline/src/gateway/claude-current.mjs +14 -4
- package/src/workflows/default/WORKFLOW.md +3 -1
- package/src/runtime/memory/lib/memory-session-merge.mjs +0 -32
- package/src/runtime/shared/llm/usage-session-history.mjs +0 -266
|
@@ -4,6 +4,7 @@ import crypto from 'node:crypto';
|
|
|
4
4
|
import http2 from 'node:http2';
|
|
5
5
|
import { MAX_CONNECT_FRAME_BYTES, createCursorByteQueue } from './cursor-wire-guards.mjs';
|
|
6
6
|
import { cursorClientVersion, warmCursorClientVersion } from './cursor-client-version.mjs';
|
|
7
|
+
import { retryAfterMsFromError } from './retry-classifier.mjs';
|
|
7
8
|
|
|
8
9
|
export { warmCursorClientVersion };
|
|
9
10
|
|
|
@@ -40,7 +41,66 @@ function rpcHeaders(accessToken, path, unary) {
|
|
|
40
41
|
};
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
// HTTP-equivalent status for every Connect error code.
|
|
45
|
+
const CONNECT_CODE_STATUS = Object.freeze({
|
|
46
|
+
canceled: 499,
|
|
47
|
+
unknown: 500,
|
|
48
|
+
invalid_argument: 400,
|
|
49
|
+
deadline_exceeded: 504,
|
|
50
|
+
not_found: 404,
|
|
51
|
+
already_exists: 409,
|
|
52
|
+
permission_denied: 403,
|
|
53
|
+
resource_exhausted: 429,
|
|
54
|
+
failed_precondition: 400,
|
|
55
|
+
aborted: 409,
|
|
56
|
+
out_of_range: 400,
|
|
57
|
+
unimplemented: 501,
|
|
58
|
+
internal: 500,
|
|
59
|
+
unavailable: 503,
|
|
60
|
+
data_loss: 500,
|
|
61
|
+
unauthenticated: 401,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Connect code for a plain HTTP failure that carried no Connect error body.
|
|
65
|
+
const HTTP_STATUS_CODE = Object.freeze({
|
|
66
|
+
401: 'unauthenticated',
|
|
67
|
+
403: 'permission_denied',
|
|
68
|
+
404: 'not_found',
|
|
69
|
+
429: 'resource_exhausted',
|
|
70
|
+
500: 'internal',
|
|
71
|
+
502: 'unavailable',
|
|
72
|
+
503: 'unavailable',
|
|
73
|
+
504: 'deadline_exceeded',
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Only explicit wording about the tool catalog or request payload being too
|
|
77
|
+
// large counts; resource_exhausted otherwise stays a throttle.
|
|
78
|
+
const REQUEST_TOO_LARGE_RE =
|
|
79
|
+
/\b(?:tool\s+(?:catalog|definitions?|schemas?)|tools|payload|request(?:\s+body)?)\b[^.\n]{0,80}?\b(?:too\s+(?:large|big)|exceed(?:s|ed)?\b[^.\n]{0,30}?\b(?:size|limit|maximum))/i;
|
|
80
|
+
|
|
81
|
+
// Rate/quota wording wins over the size match: "request exceeded the rate
|
|
82
|
+
// limit" is a throttle, not an oversized request.
|
|
83
|
+
const THROTTLE_CUE_RE = /too\s+many\s+requests|quota|rate[\s_-]*limit|throttl/i;
|
|
84
|
+
|
|
85
|
+
function firstValue(value) {
|
|
86
|
+
return Array.isArray(value) ? value[0] : value;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Lowercased string-valued header map without HTTP/2 pseudo-headers.
|
|
90
|
+
function plainHeaders(source) {
|
|
91
|
+
const headers = {};
|
|
92
|
+
for (const [key, value] of Object.entries(source || {})) {
|
|
93
|
+
const first = firstValue(value);
|
|
94
|
+
if (key.startsWith(':') || first == null || typeof first === 'object') continue;
|
|
95
|
+
headers[key.toLowerCase()] = String(first);
|
|
96
|
+
}
|
|
97
|
+
return headers;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function cursorError(
|
|
101
|
+
message,
|
|
102
|
+
{ status = 0, code = '', cursorCode = code, headers = null, retryAfter = null, reauthRequired = false, detail } = {}
|
|
103
|
+
) {
|
|
44
104
|
const error = new Error(message);
|
|
45
105
|
if (status) {
|
|
46
106
|
error.status = status;
|
|
@@ -48,17 +108,32 @@ export function cursorError(message, { status = 0, code = '', retryAfter = null
|
|
|
48
108
|
}
|
|
49
109
|
if (code) {
|
|
50
110
|
error.code = code;
|
|
51
|
-
error.cursorCode =
|
|
111
|
+
error.cursorCode = cursorCode;
|
|
52
112
|
}
|
|
113
|
+
if (detail != null) error.cursorDetail = detail;
|
|
114
|
+
if (reauthRequired) error.reauthRequired = true;
|
|
115
|
+
const errorHeaders = plainHeaders(headers);
|
|
53
116
|
if (retryAfter != null && retryAfter !== '') {
|
|
54
|
-
const headers = { 'retry-after': String(retryAfter) };
|
|
55
117
|
error.retryAfter = retryAfter;
|
|
56
|
-
|
|
57
|
-
|
|
118
|
+
errorHeaders['retry-after'] = String(retryAfter);
|
|
119
|
+
}
|
|
120
|
+
if (Object.keys(errorHeaders).length) {
|
|
121
|
+
error.headers = errorHeaders;
|
|
122
|
+
error.response = { status, headers: errorHeaders };
|
|
123
|
+
const retryAfterMs = retryAfterMsFromError(error);
|
|
124
|
+
if (Number.isFinite(retryAfterMs)) error.retryAfterMs = retryAfterMs;
|
|
58
125
|
}
|
|
59
126
|
return error;
|
|
60
127
|
}
|
|
61
128
|
|
|
129
|
+
function httpStatusError(status, headers) {
|
|
130
|
+
return cursorError(`Cursor request failed (${status})`, {
|
|
131
|
+
status,
|
|
132
|
+
code: HTTP_STATUS_CODE[status] || '',
|
|
133
|
+
headers,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
62
137
|
export function openCursorStream({ accessToken, path = RUN_PATH, url = API_URL }) {
|
|
63
138
|
const session = http2.connect(url);
|
|
64
139
|
const request = session.request(rpcHeaders(accessToken, path, false));
|
|
@@ -66,7 +141,7 @@ export function openCursorStream({ accessToken, path = RUN_PATH, url = API_URL }
|
|
|
66
141
|
let closeHandler = null;
|
|
67
142
|
let closed = false;
|
|
68
143
|
let status = 0;
|
|
69
|
-
let
|
|
144
|
+
let responseHeaders = null;
|
|
70
145
|
let closeError = null;
|
|
71
146
|
let timeout = setTimeout(
|
|
72
147
|
() => close(cursorError('Cursor connection timed out', { code: 'connection_timeout' })),
|
|
@@ -97,8 +172,7 @@ export function openCursorStream({ accessToken, path = RUN_PATH, url = API_URL }
|
|
|
97
172
|
closed = true;
|
|
98
173
|
clearTimeout(timeout);
|
|
99
174
|
clearInterval(ping);
|
|
100
|
-
closeError =
|
|
101
|
-
error || (status >= 400 ? cursorError(`Cursor request failed (${status})`, { status, retryAfter }) : null);
|
|
175
|
+
closeError = error || (status >= 400 ? httpStatusError(status, responseHeaders) : null);
|
|
102
176
|
try {
|
|
103
177
|
request.close();
|
|
104
178
|
} catch {}
|
|
@@ -120,7 +194,7 @@ export function openCursorStream({ accessToken, path = RUN_PATH, url = API_URL }
|
|
|
120
194
|
|
|
121
195
|
request.on('response', (headers) => {
|
|
122
196
|
status = Number(headers[':status'] || 0);
|
|
123
|
-
|
|
197
|
+
responseHeaders = headers;
|
|
124
198
|
resetTimeout();
|
|
125
199
|
});
|
|
126
200
|
request.on('data', (chunk) => {
|
|
@@ -167,7 +241,7 @@ export async function callCursorUnary({ accessToken, path, body, url = API_URL,
|
|
|
167
241
|
const request = session.request(rpcHeaders(accessToken, path, true));
|
|
168
242
|
const chunks = [];
|
|
169
243
|
let status = 0;
|
|
170
|
-
let
|
|
244
|
+
let responseHeaders = null;
|
|
171
245
|
let settled = false;
|
|
172
246
|
const timeout = setTimeout(() => finish(new Error('Cursor request timed out')), timeoutMs);
|
|
173
247
|
const finish = (error = null) => {
|
|
@@ -181,12 +255,12 @@ export async function callCursorUnary({ accessToken, path, body, url = API_URL,
|
|
|
181
255
|
session.close();
|
|
182
256
|
} catch {}
|
|
183
257
|
if (error) reject(error);
|
|
184
|
-
else if (status >= 400) reject(
|
|
258
|
+
else if (status >= 400) reject(httpStatusError(status, responseHeaders));
|
|
185
259
|
else resolve(Buffer.concat(chunks));
|
|
186
260
|
};
|
|
187
261
|
request.on('response', (headers) => {
|
|
188
262
|
status = Number(headers[':status'] || 0);
|
|
189
|
-
|
|
263
|
+
responseHeaders = headers;
|
|
190
264
|
});
|
|
191
265
|
request.on('data', (chunk) => chunks.push(Buffer.from(chunk)));
|
|
192
266
|
request.on('end', () => finish());
|
|
@@ -235,7 +309,7 @@ export function createFrameParser(onMessage, onEnd) {
|
|
|
235
309
|
};
|
|
236
310
|
parse.finish = () => {
|
|
237
311
|
if (pending.byteLength) {
|
|
238
|
-
throw cursorError('Cursor stream ended with a truncated frame', { code: '
|
|
312
|
+
throw cursorError('Cursor stream ended with a truncated frame', { code: 'incomplete_stream' });
|
|
239
313
|
}
|
|
240
314
|
};
|
|
241
315
|
parse.bufferedBytes = () => pending.byteLength;
|
|
@@ -246,26 +320,22 @@ export function parseEndStream(bytes) {
|
|
|
246
320
|
try {
|
|
247
321
|
const payload = JSON.parse(textDecoder.decode(bytes));
|
|
248
322
|
if (!payload?.error) return null;
|
|
249
|
-
const
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
retryAfter:
|
|
264
|
-
|
|
265
|
-
payload.error.retry_after ??
|
|
266
|
-
payload.metadata?.['retry-after'] ??
|
|
267
|
-
payload.metadata?.retryAfter ??
|
|
268
|
-
null,
|
|
323
|
+
const connectCode = String(payload.error.code || 'error').toLowerCase();
|
|
324
|
+
const detail = String(payload.error.message || 'request failed');
|
|
325
|
+
const tooLarge = connectCode === 'resource_exhausted' && !THROTTLE_CUE_RE.test(detail) && REQUEST_TOO_LARGE_RE.test(detail);
|
|
326
|
+
const retryAfter =
|
|
327
|
+
payload.error.retryAfter ??
|
|
328
|
+
payload.error.retry_after ??
|
|
329
|
+
payload.metadata?.['retry-after'] ??
|
|
330
|
+
payload.metadata?.retryAfter ??
|
|
331
|
+
null;
|
|
332
|
+
return cursorError(`Cursor ${connectCode}: ${detail}`, {
|
|
333
|
+
status: tooLarge ? 413 : CONNECT_CODE_STATUS[connectCode] || 0,
|
|
334
|
+
code: tooLarge ? 'request_too_large' : connectCode,
|
|
335
|
+
cursorCode: connectCode,
|
|
336
|
+
headers: payload.metadata,
|
|
337
|
+
retryAfter: firstValue(retryAfter),
|
|
338
|
+
detail,
|
|
269
339
|
});
|
|
270
340
|
} catch {
|
|
271
341
|
return cursorError('Cursor returned an invalid end-stream frame', { code: 'protocol_error' });
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
} from './cursor-wire-protobuf.mjs';
|
|
15
15
|
import {
|
|
16
16
|
assertCursorUserImages,
|
|
17
|
+
createCursorCredentialRefresher,
|
|
17
18
|
createCursorStreamWatchdog,
|
|
18
19
|
resolveCursorStreamTuning,
|
|
19
20
|
storeCursorBlob,
|
|
@@ -41,6 +42,7 @@ import {
|
|
|
41
42
|
import { handleExecMessage, heartbeatFrame, sendToolResult } from './cursor-wire-exec.mjs';
|
|
42
43
|
import { completionChunk, createStreamSink } from './cursor-wire-stream-sink.mjs';
|
|
43
44
|
import { createBridgeController } from './cursor-wire-stream-bridge.mjs';
|
|
45
|
+
import { TRANSPORT_SCOPE_DISPOSED } from './transport-scope.mjs';
|
|
44
46
|
|
|
45
47
|
export { clearModelCache, getCursorModels, getCursorUsage } from './cursor-wire-models.mjs';
|
|
46
48
|
|
|
@@ -116,6 +118,8 @@ globalThis.__mixdogCloseProviderConnectionsForSession = (sessionId, reason) => {
|
|
|
116
118
|
_priorCursorSessionCloseHook?.(sessionId, reason);
|
|
117
119
|
} finally {
|
|
118
120
|
closeCursorRunsForSession(sessionId, reason);
|
|
121
|
+
// A disposed transport scope never sends again: drop its conversation.
|
|
122
|
+
if (reason === TRANSPORT_SCOPE_DISPOSED && sessionId) conversations.delete(conversationKey([], sessionId));
|
|
119
123
|
}
|
|
120
124
|
};
|
|
121
125
|
const _priorCursorDrainHook = globalThis.__mixdogDrainProviderConnections;
|
|
@@ -358,12 +362,16 @@ function createStreamResponse({
|
|
|
358
362
|
sessionId = '',
|
|
359
363
|
sawTurnEnded = false,
|
|
360
364
|
restart = null,
|
|
365
|
+
sleep = undefined,
|
|
366
|
+
onStageChange = null,
|
|
361
367
|
}) {
|
|
362
368
|
const id = newCompletionId();
|
|
363
369
|
// The bridge currently feeding the stream; a restart swaps it in place.
|
|
364
370
|
const live = { bridge, heartbeat };
|
|
365
371
|
let watchdog = null;
|
|
366
372
|
let cancelled = false;
|
|
373
|
+
// Cuts a pending retry backoff short when the caller cancels.
|
|
374
|
+
const cancelController = new AbortController();
|
|
367
375
|
const runs = { get: (runKey) => activeRuns.get(runKey), store: storeActiveRun, forget: forgetActiveRun };
|
|
368
376
|
const stream = new ReadableStream({
|
|
369
377
|
start(controller) {
|
|
@@ -395,12 +403,16 @@ function createStreamResponse({
|
|
|
395
403
|
run: { key, conversation, tools, cloudRule, modelParameters, maxMode, sessionId },
|
|
396
404
|
runs,
|
|
397
405
|
restart,
|
|
406
|
+
sleep,
|
|
407
|
+
onStageChange,
|
|
408
|
+
cancelSignal: cancelController.signal,
|
|
398
409
|
isCancelled: () => cancelled,
|
|
399
410
|
});
|
|
400
411
|
bridges.attach(bridge, heartbeat);
|
|
401
412
|
},
|
|
402
413
|
cancel(reason) {
|
|
403
414
|
cancelled = true;
|
|
415
|
+
cancelController.abort();
|
|
404
416
|
watchdog?.stop();
|
|
405
417
|
clearInterval(live.heartbeat);
|
|
406
418
|
const active = activeRuns.get(key);
|
|
@@ -459,7 +471,7 @@ function noUserMessageResponse() {
|
|
|
459
471
|
});
|
|
460
472
|
}
|
|
461
473
|
|
|
462
|
-
export async function handleChatCompletion(body, accessToken) {
|
|
474
|
+
export async function handleChatCompletion(body, accessToken, { onStageChange = null, getAccessToken = null } = {}) {
|
|
463
475
|
await warmCursorClientVersion();
|
|
464
476
|
const parsed = parseMessages(body.messages);
|
|
465
477
|
if (
|
|
@@ -504,6 +516,10 @@ export async function handleChatCompletion(body, accessToken) {
|
|
|
504
516
|
};
|
|
505
517
|
const requestBytes = buildRunRequest(runInput);
|
|
506
518
|
const { bridge, heartbeat } = startRun(accessToken, requestBytes);
|
|
519
|
+
// Every retry force-refreshes credentials and falls back to the previous
|
|
520
|
+
// token if the refresh fails. A rejected credential is only
|
|
521
|
+
// retried when the refresh produced a different token.
|
|
522
|
+
const credentials = createCursorCredentialRefresher(accessToken, getAccessToken);
|
|
507
523
|
return createStreamResponse({
|
|
508
524
|
bridge,
|
|
509
525
|
heartbeat,
|
|
@@ -515,11 +531,21 @@ export async function handleChatCompletion(body, accessToken) {
|
|
|
515
531
|
maxMode,
|
|
516
532
|
key,
|
|
517
533
|
sessionId,
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
534
|
+
onStageChange,
|
|
535
|
+
restart: async ({ fromCheckpoint, reason, error }) => {
|
|
536
|
+
if (reason === 'throttle') {
|
|
537
|
+
// Cursor can pin resource_exhausted to one conversation id (conversation
|
|
538
|
+
// rotation after a rate limit): start a fresh one from the full
|
|
539
|
+
// history instead of the checkpoint it refused.
|
|
540
|
+
conversation.id = crypto.randomUUID();
|
|
541
|
+
conversation.checkpoint = null;
|
|
542
|
+
}
|
|
543
|
+
const token = await credentials.refresh(reason, error);
|
|
544
|
+
let bytes = requestBytes;
|
|
545
|
+
if (fromCheckpoint) bytes = buildRunRequest({ ...runInput, userText: '', userImages: [] });
|
|
546
|
+
else if (reason === 'throttle') bytes = buildRunRequest(runInput);
|
|
547
|
+
return startRun(token, bytes);
|
|
548
|
+
},
|
|
523
549
|
});
|
|
524
550
|
}
|
|
525
551
|
|
|
@@ -10,7 +10,9 @@ import {
|
|
|
10
10
|
} from './openai-compat-wire.mjs';
|
|
11
11
|
import { preparePdfTextForProvider } from './media-normalization.mjs';
|
|
12
12
|
import { consumeCompatChatCompletionStream } from './openai-compat-stream.mjs';
|
|
13
|
+
import { retryAfterMsFromError } from './retry-classifier.mjs';
|
|
13
14
|
import { ensureChatToolPairs } from './lib/wire-pairing.mjs';
|
|
15
|
+
import { acceptedWireTools } from './lib/claude-bridge-schema.mjs';
|
|
14
16
|
import { cursorTokenExpiry, exchangeCursorToken, resolveCursorOAuthAccessToken } from './cursor-auth.mjs';
|
|
15
17
|
import {
|
|
16
18
|
canonicalCursorModelId,
|
|
@@ -62,14 +64,24 @@ function toCursorToolChoice(toolChoice) {
|
|
|
62
64
|
async function responseError(response, label) {
|
|
63
65
|
const text = await response.text().catch(() => '');
|
|
64
66
|
let message = text;
|
|
67
|
+
let code = '';
|
|
65
68
|
try {
|
|
66
69
|
const parsed = JSON.parse(text);
|
|
67
70
|
message = parsed?.error?.message || parsed?.message || text;
|
|
71
|
+
code = String(parsed?.error?.code || parsed?.code || '').toLowerCase();
|
|
68
72
|
} catch {
|
|
69
73
|
/* plain text */
|
|
70
74
|
}
|
|
71
75
|
const error = new Error(`${label} request failed (${response.status})${message ? `: ${message}` : ''}`);
|
|
72
76
|
error.status = response.status;
|
|
77
|
+
error.httpStatus = response.status;
|
|
78
|
+
if (code) error.code = code;
|
|
79
|
+
const headers = Object.fromEntries(response.headers?.entries?.() ?? []);
|
|
80
|
+
if (Object.keys(headers).length) {
|
|
81
|
+
error.headers = headers;
|
|
82
|
+
const retryAfterMs = retryAfterMsFromError(error);
|
|
83
|
+
if (Number.isFinite(retryAfterMs)) error.retryAfterMs = retryAfterMs;
|
|
84
|
+
}
|
|
73
85
|
throw error;
|
|
74
86
|
}
|
|
75
87
|
|
|
@@ -535,6 +547,9 @@ class CursorProviderBase {
|
|
|
535
547
|
nativePdf = false;
|
|
536
548
|
|
|
537
549
|
static inputExcludesCache = false;
|
|
550
|
+
// The in-place stream retry budget is the whole recovery: a spent budget
|
|
551
|
+
// surfaces instead of being re-run by the outer recovery cycles.
|
|
552
|
+
retryPolicy = Object.freeze({ recoveryCycles: false });
|
|
538
553
|
name;
|
|
539
554
|
config;
|
|
540
555
|
_runtimeOverride;
|
|
@@ -622,7 +637,10 @@ class CursorProviderBase {
|
|
|
622
637
|
sendOpts.onStageChange?.('requesting');
|
|
623
638
|
} catch {}
|
|
624
639
|
try {
|
|
625
|
-
const response = await runtime.handleChatCompletion(body, accessToken
|
|
640
|
+
const response = await runtime.handleChatCompletion(body, accessToken, {
|
|
641
|
+
onStageChange: sendOpts.onStageChange,
|
|
642
|
+
getAccessToken: (options) => this._accessToken({ signal, ...options }),
|
|
643
|
+
});
|
|
626
644
|
try {
|
|
627
645
|
sendOpts.onStageChange?.('streaming');
|
|
628
646
|
} catch {}
|
|
@@ -676,10 +694,16 @@ class CursorProviderBase {
|
|
|
676
694
|
const runtime = await this._runtime();
|
|
677
695
|
let accessToken = await this._accessToken({ signal });
|
|
678
696
|
let cursorSelection = await this._resolveCursorModel(model, sendOpts, runtime, accessToken);
|
|
697
|
+
// The Cursor run and conversation (checkpoint, pending tool batch) live
|
|
698
|
+
// under this scope; a forked request keeps its own (transport-scope.mjs).
|
|
679
699
|
const sessionScope = String(
|
|
680
|
-
sendOpts.
|
|
700
|
+
sendOpts.transportScope ||
|
|
701
|
+
sendOpts.sessionId ||
|
|
702
|
+
sendOpts.providerCacheKey || sendOpts.promptCacheKey || `cursor-call:${randomUUID()}`
|
|
681
703
|
);
|
|
682
|
-
const openAiTools = tools?.length
|
|
704
|
+
const openAiTools = tools?.length
|
|
705
|
+
? toOpenAITools(acceptedWireTools(tools, 'openai', sendOpts.onToolExcluded, '[cursor] tool'))
|
|
706
|
+
: undefined;
|
|
683
707
|
const dispatch = async () => {
|
|
684
708
|
noteRequestServiceTier(cursorSelectionIsFast(cursorSelection) ? 'fast' : '');
|
|
685
709
|
// Every attempt (retries included) prepares right before it lowers.
|
|
@@ -9,7 +9,7 @@ export const CUSTOM_PROVIDER_PROTOCOLS = Object.freeze(['openai-chat', 'openai-r
|
|
|
9
9
|
export const CUSTOM_PROVIDER_SCHEMA_VERSION = 2;
|
|
10
10
|
// Ranked weakest → strongest.
|
|
11
11
|
export const CUSTOM_REASONING_LEVELS = CUSTOM_EFFORT_LEVELS;
|
|
12
|
-
export const CUSTOM_REASONING_WIRE_FORMATS = Object.freeze(['standard', 'deepseek']);
|
|
12
|
+
export const CUSTOM_REASONING_WIRE_FORMATS = Object.freeze(['standard', 'deepseek', 'together', 'vllm']);
|
|
13
13
|
export const CUSTOM_PROVIDER_AUTH_MODES = Object.freeze(['key', 'none']);
|
|
14
14
|
export const CUSTOM_MODEL_OVERRIDE_LIMIT = 500;
|
|
15
15
|
|
|
@@ -74,10 +74,22 @@ const V2_TOP_LEVEL_KEYS = new Set([
|
|
|
74
74
|
'auth',
|
|
75
75
|
'discovery',
|
|
76
76
|
'modelOverrides',
|
|
77
|
+
'wires',
|
|
78
|
+
'modelWires',
|
|
77
79
|
'id',
|
|
78
80
|
'apiKey',
|
|
81
|
+
'apiKeyEnv',
|
|
79
82
|
'preconnect',
|
|
80
83
|
]);
|
|
84
|
+
export const CUSTOM_API_KEY_ENV_RE = /^[A-Za-z_][A-Za-z0-9_]{0,127}$/;
|
|
85
|
+
|
|
86
|
+
// Env var name that supplies the key, or '' when unset (undefined / null).
|
|
87
|
+
function normalizeApiKeyEnv(raw) {
|
|
88
|
+
if (raw === undefined || raw === null) return '';
|
|
89
|
+
if (typeof raw !== 'string' || !CUSTOM_API_KEY_ENV_RE.test(raw))
|
|
90
|
+
fail('apiKeyEnv must be a valid environment variable name');
|
|
91
|
+
return raw;
|
|
92
|
+
}
|
|
81
93
|
const MAX_BASE_URL = 2048;
|
|
82
94
|
|
|
83
95
|
function onlyKnownKeys(value, allowed, label) {
|
|
@@ -229,6 +241,49 @@ function normalizeOverrides(raw, protocol, legacy) {
|
|
|
229
241
|
return out;
|
|
230
242
|
}
|
|
231
243
|
|
|
244
|
+
// The wire each OpenAI-compatible protocol speaks (wire-route.mjs WIRES).
|
|
245
|
+
export const CUSTOM_PROTOCOL_WIRES = Object.freeze({
|
|
246
|
+
'openai-chat': 'chat',
|
|
247
|
+
'openai-responses': 'responses',
|
|
248
|
+
anthropic: 'messages',
|
|
249
|
+
});
|
|
250
|
+
// Wires a user-defined OpenAI-compatible endpoint can be declared to serve.
|
|
251
|
+
export const CUSTOM_PROVIDER_WIRES = Object.freeze(['chat', 'responses', 'messages']);
|
|
252
|
+
|
|
253
|
+
// `wires`: the wires the endpoint serves (the protocol's own wire included);
|
|
254
|
+
// absent = the protocol's wire only. Anthropic-protocol providers speak one wire.
|
|
255
|
+
function normalizeWires(raw, protocol) {
|
|
256
|
+
if (raw === undefined) return null;
|
|
257
|
+
if (protocol === 'anthropic') fail("wires requires an 'openai-chat' or 'openai-responses' protocol");
|
|
258
|
+
if (!Array.isArray(raw) || raw.length === 0) fail('wires must be a non-empty array');
|
|
259
|
+
const seen = new Set();
|
|
260
|
+
for (const wire of raw) {
|
|
261
|
+
if (!CUSTOM_PROVIDER_WIRES.includes(wire)) fail(`wires has unsupported wire: ${String(wire)}`);
|
|
262
|
+
if (seen.has(wire)) fail(`wires has duplicate wire: ${wire}`);
|
|
263
|
+
seen.add(wire);
|
|
264
|
+
}
|
|
265
|
+
if (!seen.has(CUSTOM_PROTOCOL_WIRES[protocol]))
|
|
266
|
+
fail(`wires must include the protocol wire: ${CUSTOM_PROTOCOL_WIRES[protocol]}`);
|
|
267
|
+
return CUSTOM_PROVIDER_WIRES.filter((wire) => seen.has(wire));
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// `modelWires`: per-model wire override, each one of the served wires.
|
|
271
|
+
function normalizeModelWires(raw, protocol, wires) {
|
|
272
|
+
if (raw === undefined) return {};
|
|
273
|
+
if (protocol === 'anthropic') fail("modelWires requires an 'openai-chat' or 'openai-responses' protocol");
|
|
274
|
+
if (!isPlainObject(raw)) fail('modelWires must be an object');
|
|
275
|
+
const keys = Object.keys(raw);
|
|
276
|
+
if (keys.length > CUSTOM_MODEL_OVERRIDE_LIMIT) fail(`at most ${CUSTOM_MODEL_OVERRIDE_LIMIT} model wires are allowed`);
|
|
277
|
+
const served = wires || [CUSTOM_PROTOCOL_WIRES[protocol]];
|
|
278
|
+
const out = {};
|
|
279
|
+
for (const key of keys) {
|
|
280
|
+
const id = modelIdKey(key, 'modelWires key');
|
|
281
|
+
if (!served.includes(raw[key])) fail(`modelWires[${id}] must be one of the served wires: ${served.join(', ')}`);
|
|
282
|
+
out[id] = raw[key];
|
|
283
|
+
}
|
|
284
|
+
return out;
|
|
285
|
+
}
|
|
286
|
+
|
|
232
287
|
// Legacy (pre-v2) `models: [{ id, name?, contextWindow?, maxOutputTokens? }]`
|
|
233
288
|
// become manual, visible overrides; their presence hides newly discovered ids.
|
|
234
289
|
function migrateLegacy(input) {
|
|
@@ -268,6 +323,8 @@ export function normalizeCustomProviderConfig(input) {
|
|
|
268
323
|
// v2 fields without the version would be silently dropped by migration.
|
|
269
324
|
if (input.modelOverrides !== undefined || input.discovery !== undefined)
|
|
270
325
|
fail('modelOverrides and discovery require schemaVersion 2');
|
|
326
|
+
if (input.wires !== undefined || input.modelWires !== undefined)
|
|
327
|
+
fail('wires and modelWires require schemaVersion 2');
|
|
271
328
|
source = migrateLegacy(input);
|
|
272
329
|
} else if (Number.isInteger(version) && version > CUSTOM_PROVIDER_SCHEMA_VERSION)
|
|
273
330
|
fail(`unsupported schemaVersion ${version}; update mixdog to use this provider`);
|
|
@@ -293,10 +350,13 @@ export function normalizeCustomProviderConfig(input) {
|
|
|
293
350
|
if (!CUSTOM_PROVIDER_PROTOCOLS.includes(protocol)) fail(`unsupported protocol: ${protocol}`);
|
|
294
351
|
const auth = source.auth === undefined || source.auth === null ? 'key' : text(source.auth);
|
|
295
352
|
if (!CUSTOM_PROVIDER_AUTH_MODES.includes(auth)) fail(`invalid auth: ${String(source.auth)}`);
|
|
353
|
+
const apiKeyEnv = normalizeApiKeyEnv(source.apiKeyEnv);
|
|
296
354
|
const discovery = source.discovery === undefined ? {} : source.discovery;
|
|
297
355
|
if (!isPlainObject(discovery)) fail('discovery must be an object');
|
|
298
356
|
onlyKnownKeys(discovery, DISCOVERY_KEYS, 'discovery');
|
|
299
357
|
const newModelsHidden = optionalBoolean(discovery.newModelsHidden, 'discovery.newModelsHidden') ?? false;
|
|
358
|
+
const wires = normalizeWires(source.wires, protocol);
|
|
359
|
+
const modelWires = normalizeModelWires(source.modelWires, protocol, wires);
|
|
300
360
|
return {
|
|
301
361
|
type: 'custom',
|
|
302
362
|
schemaVersion: CUSTOM_PROVIDER_SCHEMA_VERSION,
|
|
@@ -305,8 +365,11 @@ export function normalizeCustomProviderConfig(input) {
|
|
|
305
365
|
baseURL: normalizeBaseURL(source.baseURL),
|
|
306
366
|
enabled: source.enabled !== false,
|
|
307
367
|
auth,
|
|
368
|
+
...(apiKeyEnv && auth === 'key' ? { apiKeyEnv } : {}),
|
|
308
369
|
discovery: { newModelsHidden },
|
|
309
370
|
modelOverrides: normalizeOverrides(source.modelOverrides, protocol, legacy),
|
|
371
|
+
...(wires ? { wires } : {}),
|
|
372
|
+
...(Object.keys(modelWires).length ? { modelWires } : {}),
|
|
310
373
|
};
|
|
311
374
|
}
|
|
312
375
|
|
|
@@ -5,7 +5,19 @@
|
|
|
5
5
|
// under the custom id so model routes and provider identity stay `custom-…`.
|
|
6
6
|
|
|
7
7
|
import { resolveProviderApiKey } from '../../../shared/provider-api-key.mjs';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
CUSTOM_PROTOCOL_WIRES,
|
|
10
|
+
effectiveCustomModelRows,
|
|
11
|
+
normalizeCustomProviderConfig,
|
|
12
|
+
} from './custom-provider-config.mjs';
|
|
13
|
+
import {
|
|
14
|
+
customWireProfile,
|
|
15
|
+
providerOffersWire,
|
|
16
|
+
registerWireProfile,
|
|
17
|
+
resolveWireRoute,
|
|
18
|
+
sendOnRoute,
|
|
19
|
+
} from './wire-route.mjs';
|
|
20
|
+
import { withInclusiveUsage } from './lib/inclusive-usage.mjs';
|
|
9
21
|
import { ANTHROPIC_VERSION } from './lib/anthropic-models.mjs';
|
|
10
22
|
import { enrichModels } from './model-catalog.mjs';
|
|
11
23
|
import { fetchCompatModelItems, listCompatModels } from './openai-compat-models.mjs';
|
|
@@ -45,6 +57,22 @@ function withCustomModels(Base, discover) {
|
|
|
45
57
|
_customKey() {
|
|
46
58
|
return this._customKeyless ? '' : resolveProviderApiKey(this.name, this.config);
|
|
47
59
|
}
|
|
60
|
+
// Env mode with the variable unset: fail before any request is sent.
|
|
61
|
+
_assertCustomKey() {
|
|
62
|
+
const name = this.customConfig?.apiKeyEnv;
|
|
63
|
+
if (name && !this._customKeyless && !resolveProviderApiKey(this.name, this.config))
|
|
64
|
+
throw new Error(`API key environment variable ${name} is not set`);
|
|
65
|
+
}
|
|
66
|
+
// A 401 reload must not fall back to the stale key once the variable is
|
|
67
|
+
// gone; with a new value the base reload picks it up for the retry.
|
|
68
|
+
reloadApiKey() {
|
|
69
|
+
this._assertCustomKey();
|
|
70
|
+
return super.reloadApiKey();
|
|
71
|
+
}
|
|
72
|
+
async send(...args) {
|
|
73
|
+
this._assertCustomKey();
|
|
74
|
+
return super.send(...args);
|
|
75
|
+
}
|
|
48
76
|
_customRows() {
|
|
49
77
|
return effectiveCustomModelRows(this.customConfig, this._customDiscovered || [], { providerId: this.name });
|
|
50
78
|
}
|
|
@@ -57,6 +85,7 @@ function withCustomModels(Base, discover) {
|
|
|
57
85
|
async listModels({ signal = null, throwOnError = false } = {}) {
|
|
58
86
|
let failure = null;
|
|
59
87
|
try {
|
|
88
|
+
this._assertCustomKey();
|
|
60
89
|
this._customDiscovered = await discover(this, signal);
|
|
61
90
|
this.customDiscoveryError = null;
|
|
62
91
|
} catch (error) {
|
|
@@ -112,10 +141,14 @@ export async function createCustomProvider(id, config) {
|
|
|
112
141
|
// `auth: 'none'` is authoritative: a supplied/injected key is ignored and
|
|
113
142
|
// `keyless` makes the engine omit every credential header.
|
|
114
143
|
const keyless = cfg.auth === 'none';
|
|
115
|
-
|
|
144
|
+
// Env mode: the named variable is the only key source.
|
|
145
|
+
let apiKey = '';
|
|
146
|
+
if (cfg.apiKeyEnv) apiKey = process.env[cfg.apiKeyEnv] || '';
|
|
147
|
+
else if (!keyless) apiKey = config.apiKey || '';
|
|
116
148
|
const engine = {
|
|
117
149
|
baseURL: cfg.baseURL,
|
|
118
150
|
apiKey: apiKey || undefined,
|
|
151
|
+
...(cfg.apiKeyEnv ? { apiKeyEnv: cfg.apiKeyEnv } : {}),
|
|
119
152
|
...(keyless ? { keyless: true } : {}),
|
|
120
153
|
...(config.preconnect === false ? { preconnect: false } : {}),
|
|
121
154
|
};
|
|
@@ -129,14 +162,41 @@ export async function createCustomProvider(id, config) {
|
|
|
129
162
|
provider.nativePdf = false;
|
|
130
163
|
} else {
|
|
131
164
|
const { OpenAICompatProvider } = await import('./openai-compat.mjs');
|
|
132
|
-
|
|
165
|
+
// The wires the endpoint is declared to serve (default: the protocol's
|
|
166
|
+
// own) and the per-model `modelWires` override pick each model's wire
|
|
167
|
+
// through the shared wire-route table, pinned per session like a gateway.
|
|
168
|
+
registerWireProfile(
|
|
169
|
+
providerId,
|
|
170
|
+
customWireProfile({ protocolWire: CUSTOM_PROTOCOL_WIRES[cfg.protocol], wires: cfg.wires })
|
|
171
|
+
);
|
|
172
|
+
let messagesEngine = null;
|
|
173
|
+
if (providerOffersWire(providerId, 'messages')) {
|
|
174
|
+
const { AnthropicProvider } = await import('./anthropic.mjs');
|
|
175
|
+
// The Anthropic SDK appends /v1/messages itself; the endpoint's /v1 base maps to it.
|
|
176
|
+
messagesEngine = new AnthropicProvider({ ...engine, name: providerId, baseURL: cfg.baseURL.replace(/\/v1$/i, '') });
|
|
177
|
+
messagesEngine.nativePdf = false;
|
|
178
|
+
}
|
|
133
179
|
class CompatBase extends OpenAICompatProvider {
|
|
180
|
+
messagesEngine = messagesEngine;
|
|
134
181
|
_fetchModelItems({ signal = null } = {}) {
|
|
135
182
|
return fetchCompatModelItems(this, { signal, keyless: this._customKeyless });
|
|
136
183
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
184
|
+
resolveWireRoute(model, ctx = {}) {
|
|
185
|
+
return resolveWireRoute(this.name, model, { ...ctx, override: cfg.modelWires?.[model] ?? null });
|
|
186
|
+
}
|
|
187
|
+
send(messages, model, tools, sendOpts) {
|
|
188
|
+
const useModel = model || this.defaultModel;
|
|
189
|
+
// The resolved route is the only wire authority: a caller's own wire
|
|
190
|
+
// switches never reach the engine. A custom provider declares the
|
|
191
|
+
// wires its endpoint serves, so a clear "unsupported" refusal moves
|
|
192
|
+
// the send to another declared wire once (sendOnRoute).
|
|
193
|
+
return sendOnRoute(this, useModel, tools, sendOpts, messages, (wire, history, opts) => {
|
|
194
|
+
if (wire === 'messages' && this.messagesEngine) {
|
|
195
|
+
return withInclusiveUsage(() => this.messagesEngine.send(history, useModel, tools, opts));
|
|
196
|
+
}
|
|
197
|
+
if (wire === 'responses') return super.send(history, model, tools, { ...opts, compatWireApi: 'responses' });
|
|
198
|
+
return super.send(history, model, tools, opts);
|
|
199
|
+
});
|
|
140
200
|
}
|
|
141
201
|
}
|
|
142
202
|
const Custom = withCustomModels(CompatBase, (self, signal) =>
|
|
@@ -144,6 +204,10 @@ export async function createCustomProvider(id, config) {
|
|
|
144
204
|
);
|
|
145
205
|
provider = new Custom(providerId, engine);
|
|
146
206
|
}
|
|
207
|
+
// The bound Messages engine reads the parent's model rows, so a routed
|
|
208
|
+
// Messages request carries the same row-driven thinking/effort as the
|
|
209
|
+
// Anthropic protocol.
|
|
210
|
+
if (provider.messagesEngine) provider.messagesEngine.getCachedModelInfo = (model) => provider.getCachedModelInfo(model);
|
|
147
211
|
provider.customConfig = cfg;
|
|
148
212
|
provider._customKeyless = keyless;
|
|
149
213
|
provider._applyCustomRows(provider._customRows());
|