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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Shared request controls for Chat Completions and Responses gateways.
|
|
2
2
|
import { emitProviderRetryStage, retryDelayLabel } from './retry-classifier.mjs';
|
|
3
|
+
import { isTogetherBaseURL } from './openai-compat-reasoning-field.mjs';
|
|
3
4
|
|
|
4
5
|
// withRetry onRetry for the compat stream sends: one stderr line plus a
|
|
5
6
|
// display-only 'reconnecting' stage for the UI.
|
|
@@ -13,8 +14,83 @@ export function compatStreamRetryReporter(label, opts) {
|
|
|
13
14
|
};
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
// Providers whose docs accept `required` / named tool_choice, and the subset
|
|
18
|
+
// that also documents `parallel_tool_calls`. DeepSeek documents no
|
|
19
|
+
// parallel_tool_calls, and rejects forced choices in thinking mode.
|
|
20
|
+
const FORCED_CHOICE_PROVIDERS = new Set([
|
|
21
|
+
'xai',
|
|
22
|
+
'deepseek',
|
|
23
|
+
'openrouter',
|
|
24
|
+
'mistral',
|
|
25
|
+
'groq',
|
|
26
|
+
'fireworks',
|
|
27
|
+
'together',
|
|
28
|
+
'command-code-oauth',
|
|
29
|
+
]);
|
|
30
|
+
const PARALLEL_CALLS_PROVIDERS = new Set([
|
|
31
|
+
'xai',
|
|
32
|
+
'openrouter',
|
|
33
|
+
'mistral',
|
|
34
|
+
'groq',
|
|
35
|
+
'fireworks',
|
|
36
|
+
'together',
|
|
37
|
+
'command-code-oauth',
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
function hostMatches(baseURL, domain) {
|
|
41
|
+
try {
|
|
42
|
+
const host = new URL(String(baseURL || '')).hostname.toLowerCase();
|
|
43
|
+
return host === domain || host.endsWith(`.${domain}`);
|
|
44
|
+
} catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function compatToolFamily(provider, baseURL) {
|
|
50
|
+
if (FORCED_CHOICE_PROVIDERS.has(provider)) return provider;
|
|
51
|
+
if (isTogetherBaseURL(baseURL)) return 'together';
|
|
52
|
+
if (hostMatches(baseURL, 'fireworks.ai')) return 'fireworks';
|
|
53
|
+
if (hostMatches(baseURL, 'mistral.ai')) return 'mistral';
|
|
54
|
+
if (hostMatches(baseURL, 'groq.com')) return 'groq';
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function forcedToolChoice(choice, wire) {
|
|
59
|
+
if (choice === 'required') return 'required';
|
|
60
|
+
if (!choice || typeof choice !== 'object') return null;
|
|
61
|
+
const name = choice.function?.name || choice.name;
|
|
62
|
+
if (typeof name !== 'string' || !name) return null;
|
|
63
|
+
return wire === 'responses' ? { type: 'function', name } : { type: 'function', function: { name } };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Tool-choice controls. `none` is universal. With `ctx` ({ provider, baseURL,
|
|
68
|
+
* wire: 'chat'|'responses', thinking: 'enabled'|'disabled'|null }) the
|
|
69
|
+
* documented providers also get explicit `required` / named tool_choice and an
|
|
70
|
+
* explicit boolean `opts.parallelToolCalls`; without it only `none` applies.
|
|
71
|
+
* DeepSeek rejects forced choices while thinking is explicitly enabled and
|
|
72
|
+
* keeps omitting them when thinking is left to the server default.
|
|
73
|
+
*/
|
|
74
|
+
export function applyCompatToolChoice(body, opts = {}, ctx = null) {
|
|
75
|
+
if (!(body.tools?.length > 0)) return body;
|
|
76
|
+
if (opts.toolChoice === 'none') body.tool_choice = 'none';
|
|
77
|
+
const family = ctx?.provider ? compatToolFamily(ctx.provider, ctx.baseURL) : null;
|
|
78
|
+
if (!family) return body;
|
|
79
|
+
const forced = forcedToolChoice(opts.toolChoice, ctx.wire);
|
|
80
|
+
if (forced) {
|
|
81
|
+
if (family === 'deepseek' && ctx.thinking === 'enabled') {
|
|
82
|
+
throw Object.assign(
|
|
83
|
+
new Error(
|
|
84
|
+
'[deepseek] tool_choice "required" or a named tool is not supported in thinking mode; disable thinking (effort none) to force a tool call'
|
|
85
|
+
),
|
|
86
|
+
{ code: 'unsupported_tool_choice' }
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
if (family !== 'deepseek' || ctx.thinking === 'disabled') body.tool_choice = forced;
|
|
90
|
+
}
|
|
91
|
+
if (typeof opts.parallelToolCalls === 'boolean' && PARALLEL_CALLS_PROVIDERS.has(family)) {
|
|
92
|
+
body.parallel_tool_calls = opts.parallelToolCalls;
|
|
93
|
+
}
|
|
18
94
|
return body;
|
|
19
95
|
}
|
|
20
96
|
|
|
@@ -8,6 +8,7 @@ import { modelProxyClientMode } from '../../../shared/model-proxy-mode.mjs';
|
|
|
8
8
|
import { openInBrowser } from '../../../shared/open-url.mjs';
|
|
9
9
|
import { createOAuthPkce } from './lib/oauth-pkce.mjs';
|
|
10
10
|
import { accountIdentityFields, normalizeAccountIdentity } from './lib/oauth-token-utils.mjs';
|
|
11
|
+
import { retryAfterMsFromError } from './retry-classifier.mjs';
|
|
11
12
|
|
|
12
13
|
const LOGIN_URL = 'https://cursor.com/loginDeepControl';
|
|
13
14
|
const POLL_URL = 'https://api2.cursor.sh/auth/poll';
|
|
@@ -17,6 +18,23 @@ const REFRESH_SKEW_MS = 5 * 60_000;
|
|
|
17
18
|
// abort signal, which must never govern work every other waiter depends on.
|
|
18
19
|
const REFRESH_TIMEOUT_MS = 30_000;
|
|
19
20
|
const refreshesInFlight = new Map();
|
|
21
|
+
export const REAUTH_GUIDANCE = 'Open /providers in Mixdog to sign in again.';
|
|
22
|
+
// The refresh credential itself was rejected.
|
|
23
|
+
const PERMANENT_REFRESH_STATUS = new Set([400, 401, 403]);
|
|
24
|
+
const EXCHANGE_STATUS_CODE = Object.freeze({
|
|
25
|
+
400: 'invalid_argument',
|
|
26
|
+
401: 'unauthenticated',
|
|
27
|
+
403: 'permission_denied',
|
|
28
|
+
429: 'resource_exhausted',
|
|
29
|
+
500: 'internal',
|
|
30
|
+
502: 'unavailable',
|
|
31
|
+
503: 'unavailable',
|
|
32
|
+
504: 'deadline_exceeded',
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
function reauthError(message) {
|
|
36
|
+
return Object.assign(new Error(message), { reauthRequired: true });
|
|
37
|
+
}
|
|
20
38
|
|
|
21
39
|
// Wait on the shared refresh while still honouring THIS caller's abort signal.
|
|
22
40
|
// Aborting only ends this caller's wait; the exchange keeps running for the
|
|
@@ -112,7 +130,7 @@ function saveCredentials(tokens) {
|
|
|
112
130
|
|
|
113
131
|
export function hasCursorOAuthCredentials() {
|
|
114
132
|
const tokens = loadStoredCredentials();
|
|
115
|
-
if (!tokens?.access_token) return false;
|
|
133
|
+
if (!tokens?.access_token || tokens.reauth_required === true) return false;
|
|
116
134
|
const expiresAt = Number(tokens.expires_at) || 0;
|
|
117
135
|
return expiresAt === 0 || expiresAt > Date.now() || Boolean(tokens.refresh_token);
|
|
118
136
|
}
|
|
@@ -129,6 +147,18 @@ export function describeCursorOAuthCredentials() {
|
|
|
129
147
|
detail: 'Mixdog token store or CURSOR_ACCESS_TOKEN',
|
|
130
148
|
};
|
|
131
149
|
}
|
|
150
|
+
if (tokens.reauth_required === true) {
|
|
151
|
+
return {
|
|
152
|
+
authenticated: false,
|
|
153
|
+
usable: false,
|
|
154
|
+
refreshable: false,
|
|
155
|
+
reauthRequired: true,
|
|
156
|
+
status: 'Reauth Required',
|
|
157
|
+
detail: tokens.source || 'Cursor OAuth',
|
|
158
|
+
expiresAt: Number(tokens.expires_at) || null,
|
|
159
|
+
...accountIdentityFields(tokens.identity),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
132
162
|
const expiresAt = Number(tokens.expires_at) || 0;
|
|
133
163
|
const expired = expiresAt > 0 && expiresAt <= Date.now();
|
|
134
164
|
const expiring = expiresAt > 0 && expiresAt <= Date.now() + REFRESH_SKEW_MS;
|
|
@@ -197,8 +227,25 @@ export async function exchangeCursorToken(token, { fetchFn = fetch, signal } = {
|
|
|
197
227
|
});
|
|
198
228
|
if (!response.ok) {
|
|
199
229
|
const detail = await response.text().catch(() => '');
|
|
200
|
-
|
|
230
|
+
// Only a credential verdict is permanent; throttles, 5xx and network
|
|
231
|
+
// failures leave the refresh token valid and stay retryable upstream.
|
|
232
|
+
const reauthRequired = PERMANENT_REFRESH_STATUS.has(response.status);
|
|
233
|
+
const error = new Error(
|
|
234
|
+
`Cursor token exchange failed (${response.status})${detail ? `: ${detail}` : ''}${
|
|
235
|
+
reauthRequired ? `. ${REAUTH_GUIDANCE}` : ''
|
|
236
|
+
}`
|
|
237
|
+
);
|
|
201
238
|
error.status = response.status;
|
|
239
|
+
error.httpStatus = response.status;
|
|
240
|
+
const code = EXCHANGE_STATUS_CODE[response.status];
|
|
241
|
+
if (code) error.code = code;
|
|
242
|
+
const headers = Object.fromEntries(response.headers?.entries?.() ?? []);
|
|
243
|
+
if (Object.keys(headers).length) {
|
|
244
|
+
error.headers = headers;
|
|
245
|
+
const retryAfterMs = retryAfterMsFromError(error);
|
|
246
|
+
if (Number.isFinite(retryAfterMs)) error.retryAfterMs = retryAfterMs;
|
|
247
|
+
}
|
|
248
|
+
if (reauthRequired) error.reauthRequired = true;
|
|
202
249
|
throw error;
|
|
203
250
|
}
|
|
204
251
|
const data = await response.json();
|
|
@@ -277,9 +324,7 @@ export async function resolveCursorOAuthAccessToken({ forceRefresh = false, fetc
|
|
|
277
324
|
if (!forceRefresh && !expiring) return tokens.access_token;
|
|
278
325
|
if (!tokens.refresh_token) {
|
|
279
326
|
if (!tokens.expires_at || tokens.expires_at > Date.now()) return tokens.access_token;
|
|
280
|
-
throw
|
|
281
|
-
'Cursor access token expired and has no refresh token. Open /providers in Mixdog to sign in again.'
|
|
282
|
-
);
|
|
327
|
+
throw reauthError(`Cursor access token expired and has no refresh token. ${REAUTH_GUIDANCE}`);
|
|
283
328
|
}
|
|
284
329
|
const refreshPath = credentialsPath();
|
|
285
330
|
let refreshInFlight = refreshesInFlight.get(refreshPath);
|
|
@@ -296,17 +341,37 @@ export async function resolveCursorOAuthAccessToken({ forceRefresh = false, fetc
|
|
|
296
341
|
return latest;
|
|
297
342
|
}
|
|
298
343
|
if (!latest.refresh_token) {
|
|
299
|
-
throw
|
|
344
|
+
throw reauthError(`Cursor OAuth refresh token is unavailable. ${REAUTH_GUIDANCE}`);
|
|
300
345
|
}
|
|
301
346
|
// Deliberately NOT the caller's signal: this exchange is shared by
|
|
302
347
|
// every concurrent waiter, so letting the first caller's abort
|
|
303
348
|
// (turn cancel / session close) kill it would fail the refresh for
|
|
304
349
|
// all of them and leave the process without a usable token. Its own
|
|
305
350
|
// timeout bounds the request instead.
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
351
|
+
let next;
|
|
352
|
+
try {
|
|
353
|
+
next = await exchangeCursorToken(latest.refresh_token, {
|
|
354
|
+
fetchFn,
|
|
355
|
+
signal: AbortSignal.timeout(REFRESH_TIMEOUT_MS),
|
|
356
|
+
});
|
|
357
|
+
} catch (error) {
|
|
358
|
+
if (error?.reauthRequired !== true) throw error;
|
|
359
|
+
// Mark the account dead only if no other process replaced the
|
|
360
|
+
// refresh token meanwhile. Non-destructive: tokens stay intact and
|
|
361
|
+
// a new sign-in rewrites the file without this marker.
|
|
362
|
+
if (!process.env.CURSOR_ACCESS_TOKEN || boundProviderAuthPath('cursor-oauth')) {
|
|
363
|
+
const current = loadStoredCredentials();
|
|
364
|
+
if (current?.refresh_token && current.refresh_token === latest.refresh_token) {
|
|
365
|
+
const { source: _source, ...persisted } = current;
|
|
366
|
+
try {
|
|
367
|
+
saveCredentials({ ...persisted, reauth_required: true });
|
|
368
|
+
} catch (saveError) {
|
|
369
|
+
process.stderr.write(`[cursor-oauth] dead-account mark failed: ${String(saveError?.message || saveError).slice(0, 200)}\n`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
throw error;
|
|
374
|
+
}
|
|
310
375
|
if (!process.env.CURSOR_ACCESS_TOKEN || boundProviderAuthPath('cursor-oauth')) {
|
|
311
376
|
saveCredentials(next);
|
|
312
377
|
}
|
|
@@ -4,7 +4,7 @@ import { createRemoteVersionSource } from './npm-cli-version.mjs';
|
|
|
4
4
|
// documented version endpoint; the official installer script embeds the
|
|
5
5
|
// current build (…/lab/<build>/…), parsed best-effort. Any format change or
|
|
6
6
|
// failure falls back to the floor.
|
|
7
|
-
export const CURSOR_CLIENT_VERSION_FLOOR = 'cli-2026.10.
|
|
7
|
+
export const CURSOR_CLIENT_VERSION_FLOOR = 'cli-2026.10.14-941492e';
|
|
8
8
|
const BUILD_PATTERN = /downloads\.cursor\.com\/lab\/(\d{4}\.\d{2}\.\d{2}-[0-9a-f]{6,40})\//;
|
|
9
9
|
export const CURSOR_INSTALL_URL = 'https://cursor.com/install';
|
|
10
10
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { mergeFlatSchemaProperty } from './lib/flat-schema-merge.mjs';
|
|
2
|
+
import { REAUTH_GUIDANCE } from './cursor-auth.mjs';
|
|
3
|
+
import { isTransientErrorCode } from './provider-error-kind.mjs';
|
|
2
4
|
|
|
3
5
|
const SCHEMA_ANNOTATIONS = new Set([
|
|
4
6
|
'$comment',
|
|
@@ -32,6 +34,15 @@ export function resolveCursorStreamTuning(env = process.env) {
|
|
|
32
34
|
idleTimeoutMs: boundedInteger(env.MIXDOG_CURSOR_STREAM_IDLE_TIMEOUT_MS, 180_000),
|
|
33
35
|
parkTimeoutMs: boundedInteger(env.MIXDOG_CURSOR_STREAM_PARK_TIMEOUT_MS, 45_000, { min: 1_000 }),
|
|
34
36
|
maxRetries: boundedInteger(env.MIXDOG_CURSOR_STREAM_IDLE_MAX_RETRIES, 5, { max: 10 }),
|
|
37
|
+
// Transport retry: 250ms base, 2s ceiling.
|
|
38
|
+
retryBaseDelayMs: boundedInteger(env.MIXDOG_CURSOR_STREAM_RETRY_BASE_MS, 250, { max: 60_000 }),
|
|
39
|
+
retryMaxDelayMs: boundedInteger(env.MIXDOG_CURSOR_STREAM_RETRY_MAX_MS, 2_000, { max: 120_000 }),
|
|
40
|
+
// A rate limit gets one recovery (min(1, maxRetries)).
|
|
41
|
+
maxThrottleRetries: boundedInteger(env.MIXDOG_CURSOR_THROTTLE_MAX_RETRIES, 1, { max: 5 }),
|
|
42
|
+
// One credential-refresh retry; the outer provider layer adds none for a
|
|
43
|
+
// stream that already ran, and re-sending a rejected credential only
|
|
44
|
+
// hammers the token endpoint.
|
|
45
|
+
maxAuthRetries: boundedInteger(env.MIXDOG_CURSOR_AUTH_MAX_RETRIES, 1, { max: 5 }),
|
|
35
46
|
};
|
|
36
47
|
}
|
|
37
48
|
|
|
@@ -221,6 +232,13 @@ export function createCursorStreamWatchdog({ idleTimeoutMs, parkTimeoutMs, onTim
|
|
|
221
232
|
if (kind === 'work') arm(idleTimeoutMs, 'idle');
|
|
222
233
|
else if (kind === 'park') arm(parkTimeoutMs, 'park');
|
|
223
234
|
},
|
|
235
|
+
// Suspend both deadlines during an intentional retry wait; the next
|
|
236
|
+
// start()/progress('work'|'park') re-arms them, so only real stream
|
|
237
|
+
// silence is ever counted.
|
|
238
|
+
pause() {
|
|
239
|
+
if (timer) clearTimeout(timer);
|
|
240
|
+
timer = null;
|
|
241
|
+
},
|
|
224
242
|
stop() {
|
|
225
243
|
stopped = true;
|
|
226
244
|
if (timer) clearTimeout(timer);
|
|
@@ -251,8 +269,85 @@ export function cursorInteractionProgress(update) {
|
|
|
251
269
|
return 'none';
|
|
252
270
|
}
|
|
253
271
|
|
|
272
|
+
// Codes that describe a transient server verdict or a recognized transport
|
|
273
|
+
// truncation. Everything else (protocol/decoding errors, 4xx verdicts,
|
|
274
|
+
// unknown failures) is deterministic and is never replayed in place.
|
|
275
|
+
const TRANSIENT_STREAM_CODES = new Set([
|
|
276
|
+
'unavailable',
|
|
277
|
+
'internal',
|
|
278
|
+
'deadline_exceeded',
|
|
279
|
+
'stream_aborted',
|
|
280
|
+
'goaway',
|
|
281
|
+
'connection_timeout',
|
|
282
|
+
'stream_idle_timeout',
|
|
283
|
+
'stream_park_timeout',
|
|
284
|
+
'incomplete_stream',
|
|
285
|
+
'ERR_HTTP2_STREAM_CANCEL',
|
|
286
|
+
'ERR_HTTP2_GOAWAY_SESSION',
|
|
287
|
+
]);
|
|
288
|
+
|
|
289
|
+
// Protocol-mismatch check: Cursor wraps a wire mismatch in `internal`, and
|
|
290
|
+
// re-sending a request the schema cannot decode only burns the retry budget.
|
|
291
|
+
// Tested on the server's own detail, before the transient code is trusted.
|
|
292
|
+
const PROTOCOL_DRIFT_RE = /\b(protocol|protobuf|wire drift|invalid argument|failed_precondition)\b/i;
|
|
293
|
+
|
|
294
|
+
export function isCursorProtocolDrift(error) {
|
|
295
|
+
if (error?.code === 'protocol_error') return true;
|
|
296
|
+
return PROTOCOL_DRIFT_RE.test(String(error?.cursorDetail ?? ''));
|
|
297
|
+
}
|
|
298
|
+
|
|
254
299
|
export function isRetryableCursorStreamError(error) {
|
|
255
|
-
const status = Number(error?.httpStatus || error?.status || 0);
|
|
256
300
|
if (error?.name === 'AbortError') return false;
|
|
257
|
-
|
|
301
|
+
const code = String(error?.code || '');
|
|
302
|
+
if (!TRANSIENT_STREAM_CODES.has(code) && !isTransientErrorCode(code)) return false;
|
|
303
|
+
return !isCursorProtocolDrift(error);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Rejected credentials: worth one forced token refresh before giving up.
|
|
307
|
+
export function isCursorAuthError(error) {
|
|
308
|
+
if (error?.name === 'AbortError') return false;
|
|
309
|
+
return error?.code === 'unauthenticated' || error?.code === 'permission_denied';
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Credentials for in-place restarts. Every retry force-refreshes and keeps the
|
|
313
|
+
// previous token if the refresh fails; a rejected credential is
|
|
314
|
+
// only retried when the refresh produced a different token.
|
|
315
|
+
export function createCursorCredentialRefresher(initialToken, getAccessToken) {
|
|
316
|
+
let current = initialToken;
|
|
317
|
+
return {
|
|
318
|
+
async refresh(reason, error) {
|
|
319
|
+
let next = current;
|
|
320
|
+
if (getAccessToken) {
|
|
321
|
+
try {
|
|
322
|
+
next = (await getAccessToken({ forceRefresh: true })) || current;
|
|
323
|
+
} catch {
|
|
324
|
+
/* keep the previous token */
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
if (reason === 'auth' && next === current) throw error;
|
|
328
|
+
current = next;
|
|
329
|
+
return current;
|
|
330
|
+
},
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Final-failure guidance appended once to the original Cursor detail
|
|
335
|
+
// (transport-failure hint).
|
|
336
|
+
export function withCursorFailureHint(error) {
|
|
337
|
+
if (!(error instanceof Error) || error.cursorHintApplied) return error;
|
|
338
|
+
const hint = isCursorAuthError(error)
|
|
339
|
+
? REAUTH_GUIDANCE
|
|
340
|
+
: isCursorProtocolDrift(error)
|
|
341
|
+
? 'Cursor may have changed its wire protocol; update Mixdog or set MIXDOG_CURSOR_CLIENT_VERSION if this persists.'
|
|
342
|
+
: '';
|
|
343
|
+
if (!hint) return error;
|
|
344
|
+
error.cursorHintApplied = true;
|
|
345
|
+
error.message = `${error.message} ${hint}`;
|
|
346
|
+
return error;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// resource_exhausted / 429 that is a throttle, not an oversized request.
|
|
350
|
+
export function isCursorThrottleError(error) {
|
|
351
|
+
if (error?.name === 'AbortError' || error?.code === 'request_too_large') return false;
|
|
352
|
+
return error?.code === 'resource_exhausted' || Number(error?.httpStatus || error?.status || 0) === 429;
|
|
258
353
|
}
|
|
@@ -3,11 +3,30 @@
|
|
|
3
3
|
* response: frame parsing, tool-batch hand-off to the run registry, the
|
|
4
4
|
* close verdict and the bounded in-place restart.
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
7
|
-
|
|
6
|
+
import {
|
|
7
|
+
isCursorAuthError,
|
|
8
|
+
isCursorThrottleError,
|
|
9
|
+
isRetryableCursorStreamError,
|
|
10
|
+
withCursorFailureHint,
|
|
11
|
+
} from './cursor-wire-guards.mjs';
|
|
12
|
+
import { emitProviderRetryStage, markProviderRecoveryExhausted, retryAfterMsFromError } from './retry-classifier.mjs';
|
|
8
13
|
import { createFrameParser, cursorError, parseEndStream } from './cursor-wire-transport.mjs';
|
|
9
14
|
import { processServerMessage } from './cursor-wire-stream-messages.mjs';
|
|
10
15
|
|
|
16
|
+
// Resolves after `ms`, or early when the stream is cancelled.
|
|
17
|
+
function abortableSleep(ms, signal) {
|
|
18
|
+
return new Promise((resolve) => {
|
|
19
|
+
if (signal?.aborted) return resolve();
|
|
20
|
+
const done = () => {
|
|
21
|
+
clearTimeout(timer);
|
|
22
|
+
signal?.removeEventListener('abort', done);
|
|
23
|
+
resolve();
|
|
24
|
+
};
|
|
25
|
+
const timer = setTimeout(done, ms);
|
|
26
|
+
signal?.addEventListener('abort', done, { once: true });
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
11
30
|
/**
|
|
12
31
|
* @param {object} ctx
|
|
13
32
|
* @param {{ bridge, heartbeat }} ctx.live the bridge currently feeding the stream (mutated on restart)
|
|
@@ -16,7 +35,10 @@ import { processServerMessage } from './cursor-wire-stream-messages.mjs';
|
|
|
16
35
|
*/
|
|
17
36
|
export function createBridgeController(ctx) {
|
|
18
37
|
const { live, state, filter, watchdog, sink, tuning, run, runs, restart, isCancelled } = ctx;
|
|
38
|
+
const { sleep = abortableSleep, cancelSignal = null, onStageChange = null } = ctx;
|
|
19
39
|
let retryCount = 0;
|
|
40
|
+
let throttleCount = 0;
|
|
41
|
+
let authCount = 0;
|
|
20
42
|
|
|
21
43
|
const finishToolBatch = () => {
|
|
22
44
|
if (state.closed || state.pending.length === 0) return;
|
|
@@ -35,37 +57,91 @@ export function createBridgeController(ctx) {
|
|
|
35
57
|
sink.finish('tool_calls');
|
|
36
58
|
};
|
|
37
59
|
|
|
60
|
+
// Exponential backoff with +-20% jitter for in-place retries.
|
|
61
|
+
const backoffMs = (attempt) => {
|
|
62
|
+
const ceiling = Math.min(tuning.retryMaxDelayMs, tuning.retryBaseDelayMs * 2 ** (attempt - 1));
|
|
63
|
+
return Math.floor(ceiling * (0.8 + Math.random() * 0.4));
|
|
64
|
+
};
|
|
65
|
+
|
|
38
66
|
const recoverOrFail = (error) => {
|
|
39
67
|
const retryable = isRetryableCursorStreamError(error);
|
|
68
|
+
// A throttle retries within the bounded throttle retry count; otherwise
|
|
69
|
+
// the error surfaces with retryAfterMs for the outer layer.
|
|
70
|
+
const throttled = !retryable && isCursorThrottleError(error);
|
|
71
|
+
// Rejected credentials get a forced token refresh before the retry.
|
|
72
|
+
const authFailure = !retryable && !throttled && isCursorAuthError(error);
|
|
73
|
+
// A throttle retry rotates the conversation and drops the checkpoint
|
|
74
|
+
// so unlike other recoveries it can only replay a run that
|
|
75
|
+
// has shown nothing; the rest may also continue from a checkpoint.
|
|
40
76
|
const recoveryEligible =
|
|
41
|
-
!isCancelled() &&
|
|
42
|
-
|
|
77
|
+
!isCancelled() &&
|
|
78
|
+
typeof restart === 'function' &&
|
|
79
|
+
(!state.visibleOutput || (!throttled && Boolean(run.conversation.checkpoint)));
|
|
80
|
+
const serverDelay = retryAfterMsFromError(error);
|
|
81
|
+
// Server advice is honored in full for every retryable kind; local
|
|
82
|
+
// backoff applies only when the server gave none.
|
|
83
|
+
const delayMs = Number.isFinite(serverDelay)
|
|
84
|
+
? serverDelay
|
|
85
|
+
: backoffMs(throttled ? throttleCount + 1 : retryCount + 1);
|
|
86
|
+
const throttleOk = throttled && throttleCount < tuning.maxThrottleRetries;
|
|
87
|
+
const authOk = authFailure && authCount < tuning.maxAuthRetries;
|
|
88
|
+
const canRetry =
|
|
89
|
+
retryCount < tuning.maxRetries && recoveryEligible && (retryable || throttleOk || authOk);
|
|
43
90
|
if (!canRetry) {
|
|
44
91
|
// A fresh Cursor run owns its bounded in-place retries. Mark
|
|
45
92
|
// exhaustion so the outer loop does not multiply that budget.
|
|
46
93
|
// Resumed tool-result streams have no restart closure; those
|
|
47
94
|
// intentionally fall through unmarked so the outer loop can
|
|
48
95
|
// rebuild from the committed assistant/tool-result history.
|
|
49
|
-
|
|
96
|
+
// A throttle that spent its bounded retries is final for the turn too.
|
|
97
|
+
if (
|
|
98
|
+
recoveryEligible &&
|
|
99
|
+
((retryable && retryCount >= tuning.maxRetries) ||
|
|
100
|
+
(throttled && throttleCount >= tuning.maxThrottleRetries))
|
|
101
|
+
) {
|
|
50
102
|
markProviderRecoveryExhausted(error, { owner: 'cursor-wire', attempts: retryCount + 1 });
|
|
51
103
|
}
|
|
52
|
-
sink.fail(error);
|
|
104
|
+
sink.fail(withCursorFailureHint(error));
|
|
53
105
|
return;
|
|
54
106
|
}
|
|
55
107
|
retryCount += 1;
|
|
108
|
+
if (throttled) throttleCount += 1;
|
|
109
|
+
if (authFailure) authCount += 1;
|
|
56
110
|
state.sawEnd = false;
|
|
57
111
|
state.batchBoundaryReady = false;
|
|
58
112
|
state.batchBoundaryChunkSeq = -1;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
113
|
+
// The wait is intentional, not stream silence; attach() re-arms on restart.
|
|
114
|
+
watchdog.pause();
|
|
115
|
+
emitProviderRetryStage(onStageChange, {
|
|
116
|
+
attempt: retryCount + 1,
|
|
117
|
+
maxAttempts: tuning.maxRetries + 1,
|
|
118
|
+
lastErr: error,
|
|
119
|
+
delayMs,
|
|
120
|
+
});
|
|
121
|
+
void sleep(delayMs, cancelSignal).then(async () => {
|
|
122
|
+
if (isCancelled() || state.closed) return;
|
|
123
|
+
try {
|
|
124
|
+
// restart() may refresh credentials first, so it can be async.
|
|
125
|
+
const next = await restart({
|
|
126
|
+
attempt: retryCount,
|
|
127
|
+
fromCheckpoint: !throttled && Boolean(run.conversation.checkpoint),
|
|
128
|
+
visibleOutput: state.visibleOutput,
|
|
129
|
+
reason: throttled ? 'throttle' : authFailure ? 'auth' : 'transient',
|
|
130
|
+
error,
|
|
131
|
+
});
|
|
132
|
+
if (isCancelled() || state.closed) {
|
|
133
|
+
clearInterval(next.heartbeat);
|
|
134
|
+
next.bridge.close();
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
attach(next.bridge, next.heartbeat);
|
|
138
|
+
try {
|
|
139
|
+
onStageChange?.('streaming');
|
|
140
|
+
} catch {}
|
|
141
|
+
} catch (restartError) {
|
|
142
|
+
sink.fail(withCursorFailureHint(restartError));
|
|
143
|
+
}
|
|
144
|
+
});
|
|
69
145
|
};
|
|
70
146
|
|
|
71
147
|
/** The Connect end frame: an error closes, pending tools delimit, a finished turn completes. */
|
|
@@ -99,20 +175,23 @@ export function createBridgeController(ctx) {
|
|
|
99
175
|
closeError = frameError;
|
|
100
176
|
}
|
|
101
177
|
}
|
|
102
|
-
// Cursor commonly closes HTTP/2 immediately after turnEnded without
|
|
103
|
-
// a separate Connect end frame. The turn is already complete.
|
|
104
|
-
if (state.sawTurnEnded) {
|
|
105
|
-
sink.finish();
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
178
|
// Tool calls already emitted to the caller remain actionable even if
|
|
109
179
|
// the parked transport vanished. The next request rebuilds/resumes.
|
|
180
|
+
// Checked before turnEnded: a close that follows turnEnded only ends a
|
|
181
|
+
// completed turn when no exec is still waiting (turn ended
|
|
182
|
+
// with no MCP exec outstanding), never by dropping a tool call.
|
|
110
183
|
if (state.pending.length > 0) {
|
|
111
184
|
sink.finish('tool_calls');
|
|
112
185
|
return;
|
|
113
186
|
}
|
|
187
|
+
// Cursor commonly closes HTTP/2 immediately after turnEnded, with or
|
|
188
|
+
// without an end-stream error. The turn is already complete.
|
|
189
|
+
if (state.sawTurnEnded) {
|
|
190
|
+
sink.finish();
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
114
193
|
if (!closeError && !state.sawEnd) {
|
|
115
|
-
closeError = cursorError('Cursor stream closed before its end frame', { code: '
|
|
194
|
+
closeError = cursorError('Cursor stream closed before its end frame', { code: 'incomplete_stream' });
|
|
116
195
|
}
|
|
117
196
|
if (closeError) recoverOrFail(closeError);
|
|
118
197
|
else sink.finish();
|
|
@@ -128,6 +207,7 @@ export function createBridgeController(ctx) {
|
|
|
128
207
|
conversation: run.conversation,
|
|
129
208
|
tools: run.tools,
|
|
130
209
|
cloudRule: run.cloudRule,
|
|
210
|
+
sessionId: run.sessionId,
|
|
131
211
|
};
|
|
132
212
|
const frameParser = createFrameParser(
|
|
133
213
|
// Server requests answer on whichever bridge is live when they arrive.
|
|
@@ -3,12 +3,46 @@
|
|
|
3
3
|
* to the shared stream state and relayed to the SSE sink. Returns the
|
|
4
4
|
* message's forward-progress kind for the watchdog.
|
|
5
5
|
*/
|
|
6
|
+
import { appendAgentTrace } from '../agent-trace.mjs';
|
|
6
7
|
import { decodeMessage } from './cursor-wire-protobuf.mjs';
|
|
7
8
|
import { MAX_CHECKPOINT_BYTES, cursorInteractionProgress } from './cursor-wire-guards.mjs';
|
|
8
9
|
import { buildCursorInteractionResponse } from './cursor-wire-interactions.mjs';
|
|
9
10
|
import { cursorError } from './cursor-wire-transport.mjs';
|
|
10
11
|
import { handleExecMessage, handleKvMessage, sendClientMessage } from './cursor-wire-exec.mjs';
|
|
11
12
|
|
|
13
|
+
// Unknown fields seen on every live frame: AgentServerMessage field 8 (timing
|
|
14
|
+
// doubles) and InteractionUpdate field 25 (epoch-ms timestamp). Never traced.
|
|
15
|
+
const NOISE_SERVER_FIELDS = new Set([8]);
|
|
16
|
+
const NOISE_UPDATE_FIELDS = new Set([25]);
|
|
17
|
+
const TRACE_MAX_FIELDS = 8;
|
|
18
|
+
const TRACE_PREVIEW_BYTES = 48;
|
|
19
|
+
|
|
20
|
+
// Records undecoded fields (number, wire type, bounded hex of the raw field)
|
|
21
|
+
// so a new server event such as a mid-turn model fallback can be inspected.
|
|
22
|
+
function traceUnknownFields(trace, sessionId, scope, unknown, noise) {
|
|
23
|
+
const fields = unknown?.filter((field) => !noise.has(field.no));
|
|
24
|
+
if (!fields?.length) return;
|
|
25
|
+
try {
|
|
26
|
+
trace({
|
|
27
|
+
sessionId,
|
|
28
|
+
kind: 'cursor_unknown_field',
|
|
29
|
+
provider: 'cursor',
|
|
30
|
+
payload: {
|
|
31
|
+
scope,
|
|
32
|
+
count: fields.length,
|
|
33
|
+
fields: fields.slice(0, TRACE_MAX_FIELDS).map((field) => ({
|
|
34
|
+
no: field.no,
|
|
35
|
+
wire_type: field.wireType,
|
|
36
|
+
bytes: field.data.byteLength,
|
|
37
|
+
preview_hex: Buffer.from(field.data.subarray(0, TRACE_PREVIEW_BYTES)).toString('hex'),
|
|
38
|
+
})),
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
} catch {
|
|
42
|
+
/* best-effort */
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
12
46
|
// Relays one interaction update to the SSE stream and returns its progress.
|
|
13
47
|
function applyInteractionUpdate(update, state, filter, emit) {
|
|
14
48
|
if (update.textDelta?.text) {
|
|
@@ -62,11 +96,18 @@ function announcePendingToolCall(state, pending, emit) {
|
|
|
62
96
|
|
|
63
97
|
/**
|
|
64
98
|
* @param {Uint8Array} bytes one Connect frame payload
|
|
65
|
-
* @param {object} ctx { state, filter, emit, conversation, tools, cloudRule, bridge }
|
|
99
|
+
* @param {object} ctx { state, filter, emit, conversation, tools, cloudRule, bridge, sessionId?, trace? }
|
|
66
100
|
* @returns {'work'|'park'|'none'|string} progress kind for the watchdog
|
|
67
101
|
*/
|
|
68
|
-
export function processServerMessage(
|
|
102
|
+
export function processServerMessage(
|
|
103
|
+
bytes,
|
|
104
|
+
{ state, filter, emit, conversation, tools, cloudRule, bridge, sessionId = '', trace = appendAgentTrace }
|
|
105
|
+
) {
|
|
69
106
|
const message = decodeMessage('AgentServerMessage', bytes);
|
|
107
|
+
traceUnknownFields(trace, sessionId, 'agent_server_message', message.$unknown, NOISE_SERVER_FIELDS);
|
|
108
|
+
if (message.interactionUpdate) {
|
|
109
|
+
traceUnknownFields(trace, sessionId, 'interaction_update', message.interactionUpdate.$unknown, NOISE_UPDATE_FIELDS);
|
|
110
|
+
}
|
|
70
111
|
if (message.interactionUpdate) return applyInteractionUpdate(message.interactionUpdate, state, filter, emit);
|
|
71
112
|
if (message.kvServerMessage) {
|
|
72
113
|
handleKvMessage(bridge, message.kvServerMessage, conversation);
|