mixdog 1.2.0 → 1.2.2
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 +7 -5
- package/package.json +1 -1
- package/scripts/gate-local.mjs +19 -3
- package/scripts/model-catalog-audit.mjs +1 -15
- package/src/agents/reviewer/AGENT.md +3 -3
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +5 -0
- package/src/defaults/skills/pptx/SKILL.md +6 -6
- package/src/defaults/skills/pptx/references/review.md +6 -4
- package/src/defaults/skills/pptx/scripts/source-extract.mjs +1 -1
- package/src/defaults/skills/setup/references/actions.md +13 -3
- package/src/defaults/skills/visualize/SKILL.md +12 -9
- package/src/repl/slash-commands.mjs +16 -1
- package/src/rules/shared/60-verification.md +3 -1
- package/src/rules/shared/70-delivery.md +4 -2
- 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/cache-mtime.mjs +26 -5
- package/src/runtime/agent/orchestrator/config.mjs +10 -4
- package/src/runtime/agent/orchestrator/context/collect.mjs +2 -1
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +11 -5
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +74 -21
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +122 -15
- package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +54 -11
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +104 -9
- package/src/runtime/agent/orchestrator/mcp/client.mjs +358 -140
- package/src/runtime/agent/orchestrator/mcp/lazy-output-validator.mjs +25 -0
- 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/mcp/plugin-placeholders.mjs +54 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +294 -44
- package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +94 -31
- package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +96 -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 +25 -21
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +3 -1
- 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 +73 -35
- 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.mjs +8 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +53 -18
- 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 +30 -14
- package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +93 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +82 -9
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +337 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-tokens.mjs +159 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +447 -0
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +38 -5
- 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 +102 -23
- package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +103 -33
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +29 -6
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +18 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -4
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +86 -19
- package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +29 -8
- package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +191 -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-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 +21 -82
- package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -12
- package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +21 -20
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +97 -51
- package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +68 -19
- package/src/runtime/agent/orchestrator/providers/lib/gemini-model-catalog.mjs +7 -1
- 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-bridge.mjs +1080 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +15 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +35 -0
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +4 -9
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +12 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +6 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +5 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +22 -0
- 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 +6 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +11 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +23 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +16 -8
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +94 -13
- 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 +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +6 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +6 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +23 -14
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +26 -6
- package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +42 -25
- 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/terminal-frames.mjs +18 -11
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +1 -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 +2 -3
- 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-oauth-dispatch.mjs +34 -3
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +5 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +22 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +5 -0
- package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +5 -9
- package/src/runtime/agent/orchestrator/providers/openai-retry-policy.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-handshake.mjs +16 -8
- 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-terminal.mjs +18 -11
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +35 -24
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +581 -0
- package/src/runtime/agent/orchestrator/providers/registry.mjs +35 -9
- package/src/runtime/agent/orchestrator/providers/retry-backoff.mjs +46 -7
- package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +118 -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/runtime-core/config-helpers.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +15 -55
- package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +15 -2
- 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 +268 -181
- package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +4 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +21 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +54 -3
- package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +284 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +270 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/sqlite-gate.mjs +27 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +628 -0
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +184 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +136 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +128 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +127 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +101 -0
- package/src/runtime/agent/orchestrator/session/explicit-skills.mjs +83 -5
- package/src/runtime/agent/orchestrator/session/imported-message.mjs +11 -0
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -4
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +4 -3
- package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +102 -18
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +42 -5
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +14 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +20 -12
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +50 -23
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +22 -14
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +18 -7
- package/src/runtime/agent/orchestrator/session/manager.mjs +0 -1
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +4 -3
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +155 -29
- package/src/runtime/agent/orchestrator/session/store/listing.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +6 -3
- package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +6 -0
- 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-catalog.mjs +819 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +22 -12
- package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +158 -0
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +183 -374
- package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +41 -3
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +38 -17
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +12 -15
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +17 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -0
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +6 -6
- package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +173 -22
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +8 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +5 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +15 -2
- package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +13 -10
- package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +17 -12
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/patch/apply-patch/route.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/read-redirects.mjs +34 -30
- package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +7 -7
- package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -0
- package/src/runtime/attachments/store.d.mts +3 -0
- package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +1 -1
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +16 -4
- package/src/runtime/channels/lib/worker-main.mjs +17 -14
- package/src/runtime/computer-bridge/linux-readiness.mjs +0 -2
- package/src/runtime/effort-judge/judge-client.mjs +56 -18
- package/src/runtime/memory/lib/memory.mjs +1 -1
- package/src/runtime/memory/lib/pg/process.mjs +34 -24
- package/src/runtime/memory/lib/pg/supervisor.mjs +16 -13
- package/src/runtime/memory/lib/session-ingest.mjs +2 -2
- package/src/runtime/office/README.md +1 -1
- package/src/runtime/office/shared/values.mjs +0 -5
- package/src/runtime/shared/atomic-file.mjs +25 -4
- package/src/runtime/shared/background-tasks.mjs +92 -14
- package/src/runtime/shared/err-text.mjs +25 -0
- package/src/runtime/shared/error-presentation.mjs +159 -19
- package/src/runtime/shared/extension-scopes.mjs +5 -3
- package/src/runtime/shared/file-lock.mjs +37 -11
- package/src/runtime/shared/llm/anthropic-betas.mjs +4 -3
- package/src/runtime/shared/llm/anthropic-effort.mjs +134 -131
- package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +50 -14
- package/src/runtime/shared/llm/model-catalog.mjs +53 -52
- package/src/runtime/shared/llm/openai-daybreak.mjs +4 -16
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +17 -0
- package/src/runtime/shared/llm/provider-model-identities.mjs +13 -4
- package/src/runtime/shared/llm/usage-rollup.mjs +0 -1
- package/src/runtime/shared/model-display.mjs +13 -0
- package/src/runtime/shared/plugin-manifest.mjs +18 -9
- package/src/runtime/shared/pristine-execution-contract.json +9 -2
- package/src/runtime/shared/pristine-execution.mjs +28 -4
- package/src/runtime/shared/provider-accounts.mjs +124 -20
- package/src/runtime/shared/provider-api-key.mjs +12 -0
- package/src/runtime/shared/quota-resume-store.mjs +11 -0
- package/src/runtime/shared/session-baseline-store.mjs +960 -0
- package/src/runtime/shared/shell-display.mjs +9 -3
- package/src/runtime/shared/skill-mentions.d.mts +10 -0
- package/src/runtime/shared/skill-mentions.mjs +133 -0
- package/src/runtime/shared/skill-script-runtime.mjs +264 -0
- package/src/runtime/shared/statusline/statusline-format.mjs +4 -4
- package/src/runtime/shared/task-notification-envelope.mjs +2 -2
- package/src/runtime/shared/tool-primitives.mjs +35 -2
- package/src/runtime/shared/turn-changes.mjs +447 -219
- package/src/runtime/shared/turn-snapshot-store.mjs +182 -1
- package/src/runtime/shared/turn-snapshot.mjs +170 -48
- package/src/runtime/shared/turn-worktree-snapshot.mjs +160 -51
- package/src/runtime/shared/worker-requests.mjs +15 -2
- package/src/runtime/shared/worktrees/contract.mjs +0 -24
- package/src/runtime/shared/worktrees/test-support.mjs +19 -4
- package/src/session-runtime/automation-agents.mjs +8 -2
- package/src/session-runtime/boot/apis.mjs +61 -0
- package/src/session-runtime/boot/config.mjs +5 -2
- package/src/session-runtime/boot/facade.mjs +1 -0
- package/src/session-runtime/boot/infrastructure.mjs +35 -18
- package/src/session-runtime/conversation-import/discovery.mjs +698 -0
- package/src/session-runtime/conversation-import/service.mjs +369 -0
- package/src/session-runtime/cwd-plugins/cwd-apply.mjs +10 -5
- package/src/session-runtime/cwd-plugins/plugin-status.mjs +47 -42
- package/src/session-runtime/lifecycle/session-catalog.mjs +2 -0
- package/src/session-runtime/lifecycle/teardown.mjs +1 -1
- package/src/session-runtime/mcp-glue/connect.mjs +83 -16
- package/src/session-runtime/mcp-glue/plugin-servers.mjs +499 -0
- package/src/session-runtime/mcp-glue/server-catalog.mjs +135 -33
- package/src/session-runtime/mcp-glue.mjs +25 -2
- 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 +83 -15
- 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/new-session-config.mjs +3 -2
- package/src/session-runtime/notification-bus.mjs +9 -2
- package/src/session-runtime/provider-auth/accounts.mjs +33 -15
- package/src/session-runtime/provider-models/model-meta.mjs +12 -3
- package/src/session-runtime/provider-models/web-search-catalog.mjs +5 -1
- package/src/session-runtime/provider-readiness.mjs +16 -10
- 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 +24 -5
- package/src/session-runtime/resource-mcp-api.mjs +198 -78
- package/src/session-runtime/resource-plugins-api.mjs +29 -41
- package/src/session-runtime/resource-scope-decorate.mjs +6 -8
- package/src/session-runtime/resource-skills-api.mjs +23 -2
- package/src/session-runtime/runtime-review-api.mjs +13 -0
- package/src/session-runtime/schedule-session-run.mjs +1 -1
- 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/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/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-rows.mjs +17 -0
- package/src/session-runtime/services/channel-session-router.mjs +4 -1
- package/src/session-runtime/services/hook-bus/command-handler.mjs +4 -1
- package/src/session-runtime/services/hook-bus/handlers.mjs +7 -3
- package/src/session-runtime/services/provider-admin.mjs +64 -18
- package/src/session-runtime/services/usage-dashboard-model.mjs +3 -0
- package/src/session-runtime/settings-compaction-api.mjs +1 -0
- package/src/session-runtime/setup-tool/executor.mjs +12 -1
- package/src/session-runtime/setup-tool/extended-actions.mjs +1 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +1 -0
- package/src/session-runtime/setup-tool/tool-defs.mjs +7 -1
- package/src/session-runtime/skills-api.mjs +7 -3
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
- package/src/session-runtime/webhook-session-run.mjs +16 -4
- package/src/skill-script-entry.mjs +36 -0
- package/src/standalone/daemon-drain-policy.mjs +8 -0
- package/src/standalone/daemon-stored-session-views.mjs +11 -3
- package/src/standalone/daemon-telemetry.mjs +55 -0
- package/src/standalone/daemon.mjs +44 -11
- package/src/standalone/session-protocol.mjs +12 -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 +6 -1
- package/src/standalone/session-service-api.mjs +5 -0
- package/src/standalone/session-service.mjs +1 -0
- package/src/tui/App.jsx +9 -1
- package/src/tui/app/app-view/floating-panel.jsx +9 -1
- package/src/tui/app/app-view.jsx +7 -0
- package/src/tui/app/create-app-pickers.mjs +4 -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/plugins-pickers.mjs +35 -16
- package/src/tui/app/extension-pickers.mjs +2 -1
- package/src/tui/app/model-options.mjs +13 -16
- package/src/tui/app/skill-mention-palette.mjs +88 -0
- package/src/tui/app/slash-commands.mjs +7 -2
- package/src/tui/app/slash-dispatch/panel-commands.mjs +16 -1
- package/src/tui/app/slash-palette.mjs +23 -7
- package/src/tui/app/transcript-row-estimate.mjs +11 -3
- package/src/tui/app/use-prompt-draft-flow.mjs +7 -2
- package/src/tui/app/use-prompt-state.mjs +5 -0
- package/src/tui/components/Message.jsx +22 -1
- package/src/tui/components/PromptInput.jsx +21 -3
- package/src/tui/components/SlashCommandPalette.jsx +12 -3
- package/src/tui/components/StatusLine.jsx +2 -0
- package/src/tui/components/TranscriptItem.jsx +9 -1
- package/src/tui/components/prompt-input/key-handler.mjs +21 -8
- 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/components/user-message-skills.mjs +38 -0
- package/src/tui/dist/index.mjs +1323 -214
- package/src/tui/session/queue-helpers.mjs +7 -2
- package/src/tui/session/quota-resume.mjs +46 -14
- package/src/tui/session/session-api/commands.mjs +33 -24
- package/src/tui/session/session-api/extensions.mjs +26 -2
- package/src/tui/session/session-api/integrations.mjs +7 -0
- package/src/tui/session/session-api/lifecycle.mjs +5 -1
- package/src/tui/session/session-api/routes.mjs +71 -7
- package/src/tui/session/session-api/settings.mjs +12 -14
- package/src/tui/session/session-flow/drain.mjs +21 -5
- package/src/tui/session/session-flow/failed-turn-rewind.mjs +10 -4
- package/src/tui/session/tui-steering-persist.mjs +25 -9
- package/src/tui/session/turn.mjs +55 -15
- 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/runtime/effort-judge/previous-human-request.mjs +0 -162
- package/src/runtime/effort-judge/verified-context-input.mjs +0 -10
- package/src/runtime/memory/lib/memory-session-merge.mjs +0 -32
- package/src/runtime/shared/llm/usage-session-history.mjs +0 -266
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// turn tool loops keep the model's reasoning chain without server storage.
|
|
8
8
|
|
|
9
9
|
import { markProviderRecoveryExhausted, withRetry } from './retry-classifier.mjs';
|
|
10
|
+
import { compatRetryOptions, withCompatRetryProfile } from './openai-compat-retry-profile.mjs';
|
|
10
11
|
import { consumeCompatResponsesStream } from './openai-compat-stream.mjs';
|
|
11
12
|
import { getModelMetadataSync } from './model-catalog.mjs';
|
|
12
13
|
import { PROVIDER_FIRST_BYTE_TIMEOUT_MS, createPassthroughSignal } from '../stall-policy.mjs';
|
|
@@ -24,6 +25,8 @@ import {
|
|
|
24
25
|
import { preparePdfTextForProvider } from './media-normalization.mjs';
|
|
25
26
|
import { normalizeOpencodeGoReasoningEffort } from './openai-compat-xai.mjs';
|
|
26
27
|
import { isCustomProviderName, resolveCustomReasoning } from './custom-reasoning.mjs';
|
|
28
|
+
import { projectEffortConfiguration, withEffortConfigurationFallback } from './effort-configuration.mjs';
|
|
29
|
+
import { normalizeCacheKey } from '../agent-runtime/cache-strategy.mjs';
|
|
27
30
|
import { createProviderReplay } from './lib/provider-replay.mjs';
|
|
28
31
|
import {
|
|
29
32
|
applyCompatToolChoice,
|
|
@@ -53,9 +56,65 @@ function resolveReasoning(provider, useModel, opts) {
|
|
|
53
56
|
return reasoningEffort ? { effort: reasoningEffort } : null;
|
|
54
57
|
}
|
|
55
58
|
|
|
59
|
+
/**
|
|
60
|
+
* A custom route's mid-conversation effort projection (GPT-6+ on this wire)
|
|
61
|
+
* with every effort in the row's wire value, or null for the per-request
|
|
62
|
+
* effort. Consecutive efforts sharing one wire value collapse into none; an
|
|
63
|
+
* effort the row cannot serve falls back to the per-request effort.
|
|
64
|
+
*/
|
|
65
|
+
function customEffortProjection(provider, useModel, messages, opts) {
|
|
66
|
+
if (!isCustomProviderName(provider.name)) return null;
|
|
67
|
+
const projection = projectEffortConfiguration(messages, provider.name, useModel, {
|
|
68
|
+
...opts,
|
|
69
|
+
protocol: 'openai-responses',
|
|
70
|
+
});
|
|
71
|
+
if (!projection) return null;
|
|
72
|
+
const model = provider.getCachedModelInfo?.(useModel) || null;
|
|
73
|
+
const wire = (effort) =>
|
|
74
|
+
resolveCustomReasoning({ protocol: 'openai-responses', model, effort }).fields.reasoning?.effort || null;
|
|
75
|
+
const initialEffort = wire(projection.initialEffort);
|
|
76
|
+
if (!initialEffort) return null;
|
|
77
|
+
const updates = new Map();
|
|
78
|
+
let current = initialEffort;
|
|
79
|
+
for (const [message, effort] of projection.updates) {
|
|
80
|
+
const value = wire(effort);
|
|
81
|
+
if (!value) return null;
|
|
82
|
+
if (value !== current) {
|
|
83
|
+
current = value;
|
|
84
|
+
updates.set(message, value);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return { ...projection, initialEffort, effort: current, updates };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* A custom route's session identity: its prompt_cache_key and session
|
|
92
|
+
* headers, '' without a session. The session wins over the provider-scoped
|
|
93
|
+
* cache key, so parallel sessions never evict each other; a one-shot role
|
|
94
|
+
* ('shared' scope, a fresh session per call) keys on the provider key instead.
|
|
95
|
+
* Never the effort, so an effort change keeps the cache routing.
|
|
96
|
+
*/
|
|
97
|
+
function customSessionCacheKey(provider, opts) {
|
|
98
|
+
if (!isCustomProviderName(provider.name)) return '';
|
|
99
|
+
const explicit = opts.promptCacheKey || opts.providerCacheKey || opts.session?.promptCacheKey;
|
|
100
|
+
return normalizeCacheKey(
|
|
101
|
+
opts.promptCacheScope === 'shared' ? explicit || opts.sessionId : opts.sessionId || explicit
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
56
105
|
/** The request body: lowered transcript plus the per-turn knobs (output cap,
|
|
57
|
-
* tools and tool choice, reasoning effort). */
|
|
58
|
-
function buildCompatResponsesParams({
|
|
106
|
+
* tools and tool choice, reasoning effort, session cache key). */
|
|
107
|
+
function buildCompatResponsesParams({
|
|
108
|
+
provider,
|
|
109
|
+
useModel,
|
|
110
|
+
input,
|
|
111
|
+
previousResponseId,
|
|
112
|
+
tools,
|
|
113
|
+
opts,
|
|
114
|
+
instructions,
|
|
115
|
+
effortProjection,
|
|
116
|
+
sessionCacheKey,
|
|
117
|
+
}) {
|
|
59
118
|
const params = {
|
|
60
119
|
model: useModel,
|
|
61
120
|
input,
|
|
@@ -71,14 +130,19 @@ function buildCompatResponsesParams({ provider, useModel, input, previousRespons
|
|
|
71
130
|
params.parallel_tool_calls = true;
|
|
72
131
|
}
|
|
73
132
|
applyCompatToolChoice(params, opts);
|
|
74
|
-
|
|
133
|
+
// A projected conversation keeps its initial effort on top; changes ride as input items.
|
|
134
|
+
const reasoning = effortProjection
|
|
135
|
+
? { effort: effortProjection.initialEffort }
|
|
136
|
+
: resolveReasoning(provider, useModel, opts);
|
|
75
137
|
if (reasoning) params.reasoning = reasoning;
|
|
76
138
|
// Opt-in system-as-instructions: set before the hook so the hook can override it.
|
|
77
139
|
if (instructions) params.instructions = instructions;
|
|
140
|
+
if (sessionCacheKey) params.prompt_cache_key = sessionCacheKey;
|
|
78
141
|
// Opt-in per-provider final shaping (a provider passes the hook in its config).
|
|
79
142
|
const hook = provider.config?.responsesParamsHook;
|
|
80
143
|
if (typeof hook === 'function') {
|
|
81
|
-
const modelInfo =
|
|
144
|
+
const modelInfo =
|
|
145
|
+
(typeof provider.getCachedModelInfo === 'function' && provider.getCachedModelInfo(useModel)) || null;
|
|
82
146
|
hook(params, { useModel, opts, modelInfo });
|
|
83
147
|
}
|
|
84
148
|
return params;
|
|
@@ -90,16 +154,16 @@ function buildCompatResponsesParams({ provider, useModel, input, previousRespons
|
|
|
90
154
|
* that re-opens the request. A content-idle stall is terminal for this
|
|
91
155
|
* transport, so it is marked recovery-exhausted rather than retried.
|
|
92
156
|
*/
|
|
93
|
-
async function streamCompatResponses({ provider, params, label, signal, opts }) {
|
|
157
|
+
async function streamCompatResponses({ provider, params, label, signal, opts, headers }) {
|
|
94
158
|
const totalSignal = createPassthroughSignal(signal);
|
|
95
159
|
try {
|
|
96
160
|
return await withRetry(
|
|
97
|
-
async ({ signal: attemptSignal }) => {
|
|
161
|
+
withCompatRetryProfile(provider.name, async ({ signal: attemptSignal }) => {
|
|
98
162
|
const stream = await withRetry(
|
|
99
163
|
({ signal: openSignal }) =>
|
|
100
164
|
provider.client.responses.create(params, {
|
|
101
165
|
signal: openSignal,
|
|
102
|
-
...(
|
|
166
|
+
...(headers ? { headers } : {}),
|
|
103
167
|
}),
|
|
104
168
|
{
|
|
105
169
|
signal: attemptSignal,
|
|
@@ -130,11 +194,12 @@ async function streamCompatResponses({ provider, params, label, signal, opts })
|
|
|
130
194
|
}
|
|
131
195
|
throw error;
|
|
132
196
|
}
|
|
133
|
-
},
|
|
197
|
+
}),
|
|
134
198
|
{
|
|
135
199
|
signal: totalSignal.signal,
|
|
136
200
|
onRetry: compatStreamRetryReporter(label, opts),
|
|
137
201
|
retry529: opts.retry529,
|
|
202
|
+
...compatRetryOptions(provider.name),
|
|
138
203
|
}
|
|
139
204
|
);
|
|
140
205
|
} finally {
|
|
@@ -145,9 +210,17 @@ async function streamCompatResponses({ provider, params, label, signal, opts })
|
|
|
145
210
|
/**
|
|
146
211
|
* Send one turn over `POST {baseURL}/responses` (streaming) using the
|
|
147
212
|
* provider's existing OpenAI SDK client. Returns the same result shape as
|
|
148
|
-
* the chat/completions path so the agent loop stays wire-agnostic.
|
|
213
|
+
* the chat/completions path so the agent loop stays wire-agnostic. A custom
|
|
214
|
+
* route whose model rejects the mid-conversation effort update is replayed
|
|
215
|
+
* once with the per-request effort.
|
|
149
216
|
*/
|
|
150
|
-
export
|
|
217
|
+
export function sendCompatResponses(provider, messages, useModel, tools, opts = {}) {
|
|
218
|
+
const send = (sendOpts) => sendCompatResponsesOnce(provider, messages, useModel, tools, sendOpts);
|
|
219
|
+
if (!isCustomProviderName(provider.name)) return send(opts);
|
|
220
|
+
return withEffortConfigurationFallback(provider.name, useModel, opts, send);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
async function sendCompatResponsesOnce(provider, messages, useModel, tools, opts) {
|
|
151
224
|
const replayProvider = compatResponsesReplayProvider(provider.name);
|
|
152
225
|
const signal = opts.signal || null;
|
|
153
226
|
if (signal?.aborted) {
|
|
@@ -156,7 +229,10 @@ export async function sendCompatResponses(provider, messages, useModel, tools, o
|
|
|
156
229
|
}
|
|
157
230
|
const label = `${provider.name}:responses`;
|
|
158
231
|
messages = await preparePdfTextForProvider(messages, provider);
|
|
232
|
+
const effortProjection = customEffortProjection(provider, useModel, messages, opts);
|
|
233
|
+
const sessionCacheKey = customSessionCacheKey(provider, opts);
|
|
159
234
|
const { input, previousResponseId, continuationResetReason } = toXaiResponsesInput(messages, opts.providerState, {
|
|
235
|
+
effortProjection,
|
|
160
236
|
model: useModel,
|
|
161
237
|
stateKey: COMPAT_RESPONSES_STATE_KEY,
|
|
162
238
|
replayProvider,
|
|
@@ -165,8 +241,7 @@ export async function sendCompatResponses(provider, messages, useModel, tools, o
|
|
|
165
241
|
// Opt-in: system prompts travel as top-level `instructions`, not input items.
|
|
166
242
|
includeSystem: provider.config?.responsesSystemAsInstructions !== true,
|
|
167
243
|
});
|
|
168
|
-
const instructions =
|
|
169
|
-
provider.config?.responsesSystemAsInstructions === true ? xaiSystemInstructions(messages) : '';
|
|
244
|
+
const instructions = provider.config?.responsesSystemAsInstructions === true ? xaiSystemInstructions(messages) : '';
|
|
170
245
|
const params = buildCompatResponsesParams({
|
|
171
246
|
provider,
|
|
172
247
|
useModel,
|
|
@@ -175,14 +250,20 @@ export async function sendCompatResponses(provider, messages, useModel, tools, o
|
|
|
175
250
|
tools,
|
|
176
251
|
opts,
|
|
177
252
|
instructions,
|
|
253
|
+
effortProjection,
|
|
254
|
+
sessionCacheKey,
|
|
178
255
|
});
|
|
256
|
+
// The session identity also travels as headers; caller headers win.
|
|
257
|
+
const headers = sessionCacheKey
|
|
258
|
+
? { 'session-id': sessionCacheKey, 'x-client-request-id': sessionCacheKey, ...opts.requestHeaders }
|
|
259
|
+
: opts.requestHeaders;
|
|
179
260
|
|
|
180
261
|
try {
|
|
181
262
|
opts.onStageChange?.('requesting');
|
|
182
263
|
} catch {
|
|
183
264
|
/* heartbeat best-effort */
|
|
184
265
|
}
|
|
185
|
-
const streamed = await streamCompatResponses({ provider, params, label, signal, opts });
|
|
266
|
+
const streamed = await streamCompatResponses({ provider, params, label, signal, opts, headers });
|
|
186
267
|
const response = streamed.response;
|
|
187
268
|
const usage = response?.usage || null;
|
|
188
269
|
const inputTokens = Number(usage?.input_tokens ?? usage?.prompt_tokens ?? 0);
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// Per-provider request retry profile for the OpenAI-compatible family. Each
|
|
2
|
+
// provider carries its own retry constants; the
|
|
3
|
+
// shared withRetry still owns classification, the exposure/replay veto,
|
|
4
|
+
// quota refusals, x-should-retry and Retry-After. Providers with no profile
|
|
5
|
+
// keep the shared defaults.
|
|
6
|
+
//
|
|
7
|
+
// `backoffMs[n]` is the base wait before retry n (index 0 is never read, so
|
|
8
|
+
// the first value is the duplicate the withRetry schedule expects).
|
|
9
|
+
// statusRetryCaps — retries allowed for one status (for example a
|
|
10
|
+
// 429 stops after a single retry, whatever the overall budget).
|
|
11
|
+
// terminalStatuses — statuses that are terminal although the
|
|
12
|
+
// shared classifier would retry them.
|
|
13
|
+
// retryOnlyStatuses — the complete retryable error set: any other 4xx/5xx
|
|
14
|
+
// status surfaces.
|
|
15
|
+
// maxRetryAfterMs — give up instead of waiting longer than this.
|
|
16
|
+
// maxFailedAttemptMs — a 5xx that took longer than this is not replayed.
|
|
17
|
+
// retryEmptyResponse — a completed turn with no text, tool call or
|
|
18
|
+
// reasoning is re-asked inside the ladder (nothing was exposed); a number
|
|
19
|
+
// bounds how many times per send, true leaves it to the ladder.
|
|
20
|
+
// adviceWindow - outside exceptStatuses, Retry-After is clamped to maxMs
|
|
21
|
+
// and jittered by jitterRatio (the advice of the excepted statuses stays raw).
|
|
22
|
+
// recycleDispatcherOn5xx — a retried 5xx rebuilds the shared HTTP pool.
|
|
23
|
+
// adviceAtLeastBackoff — the advice is a floor under the jittered backoff step.
|
|
24
|
+
// Every stop is provider-terminal: the profile's limits are final, so the
|
|
25
|
+
// agent loop never re-runs a stopped or exhausted request (see
|
|
26
|
+
// COMPAT_RETRY_POLICY).
|
|
27
|
+
import { markProviderRecoveryExhausted } from './retry-classifier.mjs';
|
|
28
|
+
import { retryAfterMsFromError } from './provider-error-kind.mjs';
|
|
29
|
+
import { STREAM_TRANSPORTS, stampStreamOutcome } from './lib/stream-outcome.mjs';
|
|
30
|
+
import { jitterDelayMs } from './retry-backoff.mjs';
|
|
31
|
+
|
|
32
|
+
const statusOf = (err) => Number(err?.httpStatus || err?.status || err?.response?.status || 0);
|
|
33
|
+
|
|
34
|
+
/** Loop retry policy of every profiled provider: no recovery cycles on top of the profile. */
|
|
35
|
+
export const COMPAT_RETRY_POLICY = Object.freeze({ recoveryCycles: false });
|
|
36
|
+
|
|
37
|
+
/** xAI additionally treats an in-band invalid-request error as retryable. */
|
|
38
|
+
export const XAI_COMPAT_RETRY_POLICY = Object.freeze({ ...COMPAT_RETRY_POLICY, inBandInvalidRequestRetryable: true });
|
|
39
|
+
|
|
40
|
+
export const COMPAT_RETRY_PROFILES = Object.freeze({
|
|
41
|
+
// A budget of 15 sends (the retry limit is reached when the next retry number
|
|
42
|
+
// equals it, so 14 waits), 2s doubling to 30s, ±20% jitter, one retry for a
|
|
43
|
+
// 429. Outside a 429, Retry-After is capped at 30s and jittered.
|
|
44
|
+
xai: Object.freeze({
|
|
45
|
+
maxAttempts: 15,
|
|
46
|
+
backoffMs: [2000, 2000, 4000, 8000, 16000, 30000],
|
|
47
|
+
retryJitterRatio: 0.2,
|
|
48
|
+
statusRetryCaps: { 429: 1 },
|
|
49
|
+
terminalStatuses: [408, 409, 425],
|
|
50
|
+
retryEmptyResponse: true,
|
|
51
|
+
adviceWindow: Object.freeze({ maxMs: 30_000, jitterRatio: 0.2, exceptStatuses: [429] }),
|
|
52
|
+
recycleDispatcherOn5xx: true,
|
|
53
|
+
}),
|
|
54
|
+
// 5 retries, 500ms doubling to 10s, ±10% jitter;
|
|
55
|
+
// a Retry-After beyond the 10s ceiling is not waited out.
|
|
56
|
+
deepseek: Object.freeze({
|
|
57
|
+
maxAttempts: 6,
|
|
58
|
+
backoffMs: [500, 500, 1000, 2000, 4000, 8000],
|
|
59
|
+
retryJitterRatio: 0.1,
|
|
60
|
+
maxRetryAfterMs: 10_000,
|
|
61
|
+
terminalStatuses: [408, 409, 425],
|
|
62
|
+
retryEmptyResponse: true,
|
|
63
|
+
}),
|
|
64
|
+
// The HTTP transport layer governs one request: 6 sends, 500ms doubling, no
|
|
65
|
+
// jitter, a Retry-After beyond 60s is not waited out; only 408, 429 and 5xx
|
|
66
|
+
// are transient, every other 4xx is terminal. A benign empty completion is
|
|
67
|
+
// re-asked at most twice.
|
|
68
|
+
'muse-code-oauth': Object.freeze({
|
|
69
|
+
maxAttempts: 6,
|
|
70
|
+
backoffMs: [500, 500, 1000, 2000, 4000, 8000],
|
|
71
|
+
retryJitterRatio: 0,
|
|
72
|
+
terminalStatuses: [409, 425],
|
|
73
|
+
maxRetryAfterMs: 60_000,
|
|
74
|
+
retryEmptyResponse: 2,
|
|
75
|
+
}),
|
|
76
|
+
// server budget 8 retries (2s doubling to 30s,
|
|
77
|
+
// ±10%), rate-limit budget 5 retries; 408, 409, 501 and 505 are terminal
|
|
78
|
+
// (425 stays retryable); a Retry-After beyond 300s is not waited out.
|
|
79
|
+
'mimo-oauth': Object.freeze({
|
|
80
|
+
maxAttempts: 9,
|
|
81
|
+
backoffMs: [2000, 2000, 4000, 8000, 16000, 30000],
|
|
82
|
+
retryJitterRatio: 0.1,
|
|
83
|
+
statusRetryCaps: { 429: 5 },
|
|
84
|
+
terminalStatuses: [408, 409, 501, 505],
|
|
85
|
+
maxRetryAfterMs: 300_000,
|
|
86
|
+
}),
|
|
87
|
+
// 3 sends (400ms doubling to 5s) for exactly
|
|
88
|
+
// 500/502/503/504/520/521/522 — every 4xx (429 included) and every other
|
|
89
|
+
// 5xx is terminal; a failed attempt slower than 15s is returned.
|
|
90
|
+
'command-code-oauth': Object.freeze({
|
|
91
|
+
maxAttempts: 3,
|
|
92
|
+
backoffMs: [400, 400, 800],
|
|
93
|
+
retryOnlyStatuses: [500, 502, 503, 504, 520, 521, 522],
|
|
94
|
+
maxFailedAttemptMs: 15_000,
|
|
95
|
+
maxRetryAfterMs: 60_000,
|
|
96
|
+
adviceAtLeastBackoff: true,
|
|
97
|
+
}),
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
/** withRetry options (attempt budget, schedule, jitter) for a provider; {} for the shared defaults. */
|
|
101
|
+
export function compatRetryOptions(providerName) {
|
|
102
|
+
const profile = COMPAT_RETRY_PROFILES[providerName];
|
|
103
|
+
if (!profile) return {};
|
|
104
|
+
return {
|
|
105
|
+
maxAttempts: profile.maxAttempts,
|
|
106
|
+
backoffMs: profile.backoffMs,
|
|
107
|
+
retryJitterRatio: profile.retryJitterRatio,
|
|
108
|
+
finalOnExhaust: true,
|
|
109
|
+
...(profile.adviceAtLeastBackoff ? { adviceAtLeastBackoff: true } : {}),
|
|
110
|
+
...(profile.recycleDispatcherOn5xx ? { recycleDispatcherOn5xx: true } : {}),
|
|
111
|
+
...(profile.retryJitterMode ? { retryJitterMode: profile.retryJitterMode } : {}),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function profileStops(profile, err, { attempt, elapsedMs }) {
|
|
116
|
+
const status = statusOf(err);
|
|
117
|
+
if (profile.terminalStatuses?.includes(status)) return true;
|
|
118
|
+
const cap = profile.statusRetryCaps?.[status];
|
|
119
|
+
if (cap !== undefined && attempt >= cap) return true;
|
|
120
|
+
if (profile.retryOnlyStatuses && status >= 400 && status < 600 && !profile.retryOnlyStatuses.includes(status)) {
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
if (profile.maxFailedAttemptMs && status >= 500 && status < 600 && elapsedMs > profile.maxFailedAttemptMs) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
const advice = retryAfterMsFromError(err);
|
|
127
|
+
return profile.maxRetryAfterMs !== undefined && advice != null && advice > profile.maxRetryAfterMs;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Restamps the advice as a deadline (the highest-precedence source) so the
|
|
131
|
+
// shared loop waits the clamped, jittered value instead of the raw one.
|
|
132
|
+
function shapeAdvice(window, err) {
|
|
133
|
+
if (!window || !err || typeof err !== 'object' || window.exceptStatuses?.includes(statusOf(err))) return;
|
|
134
|
+
const advice = retryAfterMsFromError(err);
|
|
135
|
+
if (advice == null) return;
|
|
136
|
+
err.retryAfterAt = Date.now() + jitterDelayMs(Math.min(advice, window.maxMs), window.jitterRatio);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// A completed turn that produced nothing: no text, tool call or reasoning, and
|
|
140
|
+
// a normal finish (a Responses turn carries no stop reason when it completes).
|
|
141
|
+
function isEmptyNormalFinish(result) {
|
|
142
|
+
if (!result || typeof result !== 'object') return false;
|
|
143
|
+
if (result.stopReason != null && result.stopReason !== 'stop') return false;
|
|
144
|
+
return (
|
|
145
|
+
!String(result.content ?? '').trim() &&
|
|
146
|
+
!result.toolCalls?.length &&
|
|
147
|
+
!result.reasoningContent &&
|
|
148
|
+
!result.reasoningDetails?.length &&
|
|
149
|
+
result.reasoningEmitted !== true
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function emptyResponseError(providerName) {
|
|
154
|
+
const err = Object.assign(new Error(`${providerName} returned an empty response`), {
|
|
155
|
+
code: 'server_error',
|
|
156
|
+
emptyResponse: true,
|
|
157
|
+
});
|
|
158
|
+
// The turn finished: a failed ladder must not reopen it as a non-streaming request.
|
|
159
|
+
stampStreamOutcome(err, { transport: STREAM_TRANSPORTS.SSE, terminalObserved: true });
|
|
160
|
+
return err;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Wrap one withRetry attempt with the provider's profile: a failure the
|
|
165
|
+
* profile treats as final is marked recovery-exhausted and provider-terminal
|
|
166
|
+
* (withRetry then surfaces it unchanged and no outer layer replays it), and a
|
|
167
|
+
* profiled empty response is raised as a retryable failure.
|
|
168
|
+
*/
|
|
169
|
+
export function withCompatRetryProfile(providerName, attemptFn) {
|
|
170
|
+
const profile = COMPAT_RETRY_PROFILES[providerName];
|
|
171
|
+
if (!profile) return attemptFn;
|
|
172
|
+
let emptyRetries = 0;
|
|
173
|
+
return async (ctx) => {
|
|
174
|
+
const startedAt = Date.now();
|
|
175
|
+
try {
|
|
176
|
+
const result = await attemptFn(ctx);
|
|
177
|
+
if (profile.retryEmptyResponse && isEmptyNormalFinish(result)) {
|
|
178
|
+
const bound = profile.retryEmptyResponse === true ? Infinity : profile.retryEmptyResponse;
|
|
179
|
+
if (emptyRetries < bound) {
|
|
180
|
+
emptyRetries += 1;
|
|
181
|
+
throw emptyResponseError(providerName);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return result;
|
|
185
|
+
} catch (err) {
|
|
186
|
+
if (profileStops(profile, err, { attempt: ctx?.attempt | 0, elapsedMs: Date.now() - startedAt })) {
|
|
187
|
+
throw markProviderRecoveryExhausted(err, { owner: `${providerName}-retry-profile`, terminal: true });
|
|
188
|
+
}
|
|
189
|
+
shapeAdvice(profile.adviceWindow, err);
|
|
190
|
+
throw err;
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto';
|
|
2
2
|
import { PROVIDER_FIRST_BYTE_TIMEOUT_MS, providerTimeoutError, streamStalledError } from '../stall-policy.mjs';
|
|
3
3
|
import { typedStatusFrom } from './retry-classifier.mjs';
|
|
4
|
+
import { applyCompatErrorContract } from './openai-compat-error-contract.mjs';
|
|
5
|
+
import { truncatedCompatStreamError } from './lib/openai-tool-args.mjs';
|
|
4
6
|
|
|
5
7
|
// Shared lifecycle and replay boundaries for both OpenAI-compatible protocols.
|
|
6
8
|
|
|
@@ -22,10 +24,68 @@ function markInBandWireError(err) {
|
|
|
22
24
|
if (typed && !err.httpStatus) err.httpStatus = typed;
|
|
23
25
|
const code = detail.code ?? detail.type ?? null;
|
|
24
26
|
if (code != null && code !== '' && !err.providerErrorCode) err.providerErrorCode = String(code);
|
|
27
|
+
applyCompatErrorContract(err, detail);
|
|
25
28
|
} catch {}
|
|
26
29
|
return err;
|
|
27
30
|
}
|
|
28
31
|
|
|
32
|
+
/**
|
|
33
|
+
* A frame the SDK failed to JSON-decode. Raised only at the wire-decoding
|
|
34
|
+
* boundary (the iterator's own next()); consumers stamp the exposure evidence
|
|
35
|
+
* (partial output, replay safety) on it in their failure path.
|
|
36
|
+
*/
|
|
37
|
+
export function malformedCompatStreamError(label, cause) {
|
|
38
|
+
const err = new Error(`${label || 'compat SSE'} malformed stream frame: ${cause?.message || 'invalid JSON'}`, {
|
|
39
|
+
cause,
|
|
40
|
+
});
|
|
41
|
+
err.name = 'MalformedStreamError';
|
|
42
|
+
err.code = 'malformed_stream';
|
|
43
|
+
err.malformedStream = true;
|
|
44
|
+
return err;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* A chat `finish_reason: network_error` is an interruption the gateway reports
|
|
49
|
+
* in-band, never a completion. Typed as a truncated stream so the shared
|
|
50
|
+
* classifier treats it as transient; exposure gates decide replay.
|
|
51
|
+
*/
|
|
52
|
+
export function networkInterruptedCompatStreamError(label) {
|
|
53
|
+
const err = truncatedCompatStreamError(label, 'finish_reason=network_error');
|
|
54
|
+
err.name = 'StreamInterruptedError';
|
|
55
|
+
err.streamInterrupted = true;
|
|
56
|
+
err.finishReason = 'network_error';
|
|
57
|
+
return err;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function isNetworkErrorFinishReason(finishReason) {
|
|
61
|
+
return typeof finishReason === 'string' && finishReason.trim().toLowerCase() === 'network_error';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* A chat `finish_reason: error` means the upstream failed the generation
|
|
66
|
+
* (gateways surface it as a 502 upstream_error). Typed like the network interruption, with the gateway status.
|
|
67
|
+
*/
|
|
68
|
+
export function upstreamErrorCompatStreamError(label) {
|
|
69
|
+
const err = truncatedCompatStreamError(label, 'finish_reason=error');
|
|
70
|
+
err.name = 'StreamInterruptedError';
|
|
71
|
+
err.streamInterrupted = true;
|
|
72
|
+
err.finishReason = 'error';
|
|
73
|
+
err.status = 502;
|
|
74
|
+
err.code = 'upstream_error';
|
|
75
|
+
return err;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function isErrorFinishReason(finishReason) {
|
|
79
|
+
return typeof finishReason === 'string' && finishReason.trim().toLowerCase() === 'error';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** The typed interruption for a failing chat finish_reason, or null for any other value. */
|
|
83
|
+
export function failingFinishReasonError(finishReason, label) {
|
|
84
|
+
if (isNetworkErrorFinishReason(finishReason)) return networkInterruptedCompatStreamError(label);
|
|
85
|
+
if (isErrorFinishReason(finishReason)) return upstreamErrorCompatStreamError(label);
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
29
89
|
export function synthLeakedOpenAICall(recovered) {
|
|
30
90
|
let args = recovered?.arguments;
|
|
31
91
|
if (args === null || typeof args !== 'object' || Array.isArray(args)) args = {};
|
|
@@ -59,7 +119,7 @@ export function closeCompatStream(stream, iterator) {
|
|
|
59
119
|
|
|
60
120
|
export async function nextAsyncWithWatchdog(
|
|
61
121
|
iterator,
|
|
62
|
-
{ signal, idleMs, idleDeadlineAt, idleEnabled, idleLabel, emittedToolCall } = {}
|
|
122
|
+
{ signal, idleMs, idleDeadlineAt, idleEnabled, idleLabel, streamLabel, emittedToolCall } = {}
|
|
63
123
|
) {
|
|
64
124
|
let idleTimer = null;
|
|
65
125
|
let idleReject = null;
|
|
@@ -106,7 +166,11 @@ export async function nextAsyncWithWatchdog(
|
|
|
106
166
|
};
|
|
107
167
|
signal.addEventListener('abort', onAbort, { once: true });
|
|
108
168
|
}
|
|
109
|
-
|
|
169
|
+
// The SDK JSON-decodes each frame inside next(): a SyntaxError here is a
|
|
170
|
+
// malformed wire frame, typed at this boundary and nowhere else.
|
|
171
|
+
iterator.next().then(resolve, (error) =>
|
|
172
|
+
reject(error instanceof SyntaxError ? malformedCompatStreamError(streamLabel || idleLabel, error) : error)
|
|
173
|
+
);
|
|
110
174
|
});
|
|
111
175
|
} catch (err) {
|
|
112
176
|
if (idleTimedOut)
|
|
@@ -99,6 +99,7 @@ export async function consumeCompatResponsesStream(
|
|
|
99
99
|
idleDeadlineAt: state.semanticIdleDeadlineAt,
|
|
100
100
|
idleEnabled: sawFirstEvent && idleEnabled && state.semanticIdleDeadlineAt > 0,
|
|
101
101
|
idleLabel: `${label} SSE idle`,
|
|
102
|
+
streamLabel: label,
|
|
102
103
|
// Unsafe-to-retry once any tool call (native or recovered-leaked)
|
|
103
104
|
// has been emitted this stream — avoid a double side-effect.
|
|
104
105
|
emittedToolCall: () => state.emittedToolCall || leakedCalls.length > 0,
|
|
@@ -144,7 +145,7 @@ export async function consumeCompatResponsesStream(
|
|
|
144
145
|
}
|
|
145
146
|
throw stampOutcome(err);
|
|
146
147
|
}
|
|
147
|
-
const unresolved = unresolvedSalvageError(state);
|
|
148
|
+
const unresolved = unresolvedSalvageError(state, label);
|
|
148
149
|
if (unresolved) {
|
|
149
150
|
attachPartialState(unresolved, state, leakedCalls);
|
|
150
151
|
throw stampOutcome(unresolved);
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
import { customToolCallFromResponseItem, nativeToolSearchCallFromArguments } from './custom-tool-wire.mjs';
|
|
19
19
|
import { providerReplayItems } from './lib/provider-replay.mjs';
|
|
20
20
|
import { ensureResponsesCallOutputs } from './lib/wire-pairing.mjs';
|
|
21
|
+
import { responsesEffortUpdates } from './effort-configuration.mjs';
|
|
21
22
|
|
|
22
23
|
function positiveTokenInt(value) {
|
|
23
24
|
const n = Number(value);
|
|
@@ -423,10 +424,14 @@ export function toXaiResponsesInput(messages, providerState, options = {}) {
|
|
|
423
424
|
if (!pendingToolMedia.length) return;
|
|
424
425
|
input.push({ role: 'user', content: pendingToolMedia.splice(0) });
|
|
425
426
|
};
|
|
427
|
+
// `options.effortProjection` (custom GPT-6+ routes) carries wire-ready effort updates.
|
|
428
|
+
const effortUpdates = responsesEffortUpdates(options.effortProjection);
|
|
426
429
|
for (let messageIndex = startIndex; messageIndex < messages.length; messageIndex += 1) {
|
|
427
430
|
const m = messages[messageIndex];
|
|
428
431
|
if (!includeSystem && m.role === 'system') continue;
|
|
432
|
+
const updates = effortUpdates.before(m);
|
|
429
433
|
if (m.role !== 'tool') flushToolMedia();
|
|
434
|
+
input.push(...updates);
|
|
430
435
|
const orderedReplay = m.role === 'assistant' ? providerReplayItems(m, replayProvider) : undefined;
|
|
431
436
|
if (orderedReplay?.length) {
|
|
432
437
|
input.push(...orderedReplay);
|
|
@@ -444,6 +449,7 @@ export function toXaiResponsesInput(messages, providerState, options = {}) {
|
|
|
444
449
|
flushToolMedia();
|
|
445
450
|
const trailingReasoning = reasoningByMessageIndex.get(messages.length);
|
|
446
451
|
if (trailingReasoning) input.push(...trailingReasoning);
|
|
452
|
+
input.push(...effortUpdates.end());
|
|
447
453
|
// Wire-level pairing guard: replay envelopes can carry a call whose
|
|
448
454
|
// result never committed (cancel/abort). The provider hard-rejects the
|
|
449
455
|
// unpaired call, so synthesize the missing outputs here.
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { resolveProviderApiKey } from '../../../shared/provider-api-key.mjs';
|
|
1
2
|
import { markProviderRecoveryExhausted, withRetry } from './retry-classifier.mjs';
|
|
3
|
+
import { compatRetryOptions, withCompatRetryProfile } from './openai-compat-retry-profile.mjs';
|
|
2
4
|
import { consumeCompatResponsesStream } from './openai-compat-stream.mjs';
|
|
3
5
|
import { PROVIDER_FIRST_BYTE_TIMEOUT_MS, createPassthroughSignal } from '../stall-policy.mjs';
|
|
4
6
|
import {
|
|
@@ -90,7 +92,7 @@ export async function sendXaiResponses(provider, messages, useModel, tools, opts
|
|
|
90
92
|
let streamed;
|
|
91
93
|
try {
|
|
92
94
|
streamed = await withRetry(
|
|
93
|
-
async ({ signal: attemptSignal }) => {
|
|
95
|
+
withCompatRetryProfile(provider.name, async ({ signal: attemptSignal }) => {
|
|
94
96
|
const stream = await withRetry(
|
|
95
97
|
({ signal: openSignal }) => provider.client.responses.create(params, { signal: openSignal }),
|
|
96
98
|
{
|
|
@@ -126,11 +128,12 @@ export async function sendXaiResponses(provider, messages, useModel, tools, opts
|
|
|
126
128
|
}
|
|
127
129
|
throw error;
|
|
128
130
|
}
|
|
129
|
-
},
|
|
131
|
+
}),
|
|
130
132
|
{
|
|
131
133
|
signal: totalSignal.signal,
|
|
132
134
|
onRetry: compatStreamRetryReporter('xai:responses', opts),
|
|
133
135
|
retry529: opts.retry529,
|
|
136
|
+
...compatRetryOptions(provider.name),
|
|
134
137
|
}
|
|
135
138
|
);
|
|
136
139
|
} finally {
|
|
@@ -158,7 +161,7 @@ export async function sendXaiResponsesWebSocket(provider, messages, useModel, to
|
|
|
158
161
|
const reason = signal.reason;
|
|
159
162
|
throw reason instanceof Error ? reason : new Error('xAI Responses WebSocket request aborted by session close');
|
|
160
163
|
}
|
|
161
|
-
const apiKey = provider.config
|
|
164
|
+
const apiKey = resolveProviderApiKey('xai', provider.config);
|
|
162
165
|
if (!apiKey) throw new Error('xAI API key not configured');
|
|
163
166
|
messages = await preparePdfTextForProvider(messages, provider);
|
|
164
167
|
const chatMessagesForTrace = toOpenAIMessages(messages, provider.name, { nativePdf: provider.nativePdf });
|
|
@@ -14,7 +14,7 @@ import { appendAgentTrace } from '../agent-trace.mjs';
|
|
|
14
14
|
import { resolveProviderCacheKey, resolveProviderPromptCacheLane } from '../agent-runtime/cache-strategy.mjs';
|
|
15
15
|
import { shouldFallbackTransport } from './retry-classifier.mjs';
|
|
16
16
|
import { envFlag as _envFlag } from '../../../shared/env.mjs';
|
|
17
|
-
import { getModelsDevRowSync } from '../../../shared/llm/model-catalog.mjs';
|
|
17
|
+
import { getModelMetadataSync, getModelsDevRowSync } from '../../../shared/llm/model-catalog.mjs';
|
|
18
18
|
import {
|
|
19
19
|
traceHash,
|
|
20
20
|
stableTraceStringify,
|
|
@@ -166,26 +166,35 @@ export function normalizeXaiReasoningEffort(value) {
|
|
|
166
166
|
return ['low', 'medium', 'high', 'xhigh'].includes(effort) ? effort : null;
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
//
|
|
173
|
-
//
|
|
169
|
+
const hasEffortValues = (modelOptions) =>
|
|
170
|
+
(modelOptions || []).some((option) => option?.type === 'effort' && option.values?.length > 0);
|
|
171
|
+
|
|
172
|
+
// The first Grok generations (grok-3, grok-4, grok-4-fast, grok-code-fast)
|
|
173
|
+
// REJECT reasoning_effort outright (HTTP 400 "does not support parameter
|
|
174
|
+
// reasoningEffort"). That generation is closed: it is told apart by a bare
|
|
175
|
+
// major with no minor version, so a later release never matches.
|
|
176
|
+
const LEGACY_NO_EFFORT_GROK = /^grok[-_]?(?:[123]|4|code)(?![.\d])/;
|
|
177
|
+
|
|
178
|
+
// The parameter ships when the catalog says the model takes it. A model the
|
|
179
|
+
// catalog does not list yet is sent the caller's effort (the server decides),
|
|
180
|
+
// as is an unknown/absent model id — a custom xAI-compatible deployment that
|
|
181
|
+
// never saw the 400 must not silently lose the caller's effort choice. Only
|
|
182
|
+
// the closed legacy generation above is held back offline, because sending to
|
|
183
|
+
// it hard-fails.
|
|
174
184
|
export function xaiModelSupportsReasoningEffort(model) {
|
|
175
185
|
const id = String(model || '')
|
|
176
186
|
.trim()
|
|
177
187
|
.toLowerCase();
|
|
178
188
|
if (!id) return true;
|
|
179
189
|
if (!id.startsWith('grok')) return true;
|
|
180
|
-
// The catalog answers first
|
|
181
|
-
//
|
|
182
|
-
|
|
190
|
+
// The catalog answers first, from the live roster and the pricing catalogs:
|
|
191
|
+
// a model that publishes effort values takes the parameter.
|
|
192
|
+
if (hasEffortValues(getModelMetadataSync(id, 'xai')?.reasoningOptions)) return true;
|
|
193
|
+
// A listed model takes the parameter exactly when it publishes effort
|
|
194
|
+
// values (grok-4.3 does, grok-4.20-*-reasoning does not).
|
|
183
195
|
const listed = getModelsDevRowSync(id, 'xai');
|
|
184
|
-
if (listed)
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
// grok-4.5 / grok-4.6 and anything newer in that line.
|
|
188
|
-
return /grok[-_]?4\.(?:[5-9]|\d{2,})/.test(id);
|
|
196
|
+
if (listed) return hasEffortValues(listed.reasoning_options);
|
|
197
|
+
return !LEGACY_NO_EFFORT_GROK.test(id);
|
|
189
198
|
}
|
|
190
199
|
|
|
191
200
|
function opencodeGoReasoningEffortValues(modelInfo) {
|