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
|
@@ -26,6 +26,11 @@ import { createSdkStreamReader } from './gemini-sdk-stream/reader.mjs';
|
|
|
26
26
|
import { createRestStreamWatchdogs } from './gemini-rest-stream/watchdogs.mjs';
|
|
27
27
|
import { drainSseDataLines, sseDataPayload } from './gemini-rest-stream/sse-lines.mjs';
|
|
28
28
|
import { noteAbandonedUsage } from '../../../shared/llm/usage-context.mjs';
|
|
29
|
+
import {
|
|
30
|
+
applyGeminiErrorContract,
|
|
31
|
+
assertNoGeminiInBandError,
|
|
32
|
+
geminiFinishReasonKind,
|
|
33
|
+
} from './gemini-error-contract.mjs';
|
|
29
34
|
|
|
30
35
|
export const GEMINI_FIRST_BYTE_TIMEOUT_MS = resolveTimeoutMs(
|
|
31
36
|
'MIXDOG_GEMINI_FIRST_BYTE_TIMEOUT_MS',
|
|
@@ -132,9 +137,16 @@ export function normalizeGeminiSdkError(err, label) {
|
|
|
132
137
|
const transport = geminiSdkTransportError(err, label);
|
|
133
138
|
if (transport) return transport;
|
|
134
139
|
const stamped = stampGeminiRpcError(err);
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
140
|
+
if (isGeminiSdkStreamParseError(stamped)) {
|
|
141
|
+
return geminiStreamCorruptionError(`${label} corrupt SDK SSE JSON`, stamped);
|
|
142
|
+
}
|
|
143
|
+
if (!stamped || typeof stamped !== 'object') return stamped;
|
|
144
|
+
return applyGeminiErrorContract(stamped, {
|
|
145
|
+
details: stamped.details,
|
|
146
|
+
errorDetails: stamped.errorDetails,
|
|
147
|
+
googleStatus: stamped.geminiStatus,
|
|
148
|
+
message: stamped.message,
|
|
149
|
+
});
|
|
138
150
|
}
|
|
139
151
|
|
|
140
152
|
// CC-rule safety stamp for Gemini stream failures (provider-stall audit):
|
|
@@ -175,8 +187,10 @@ function stampGeminiStreamFailure(
|
|
|
175
187
|
const visible = visibleText.length > 0;
|
|
176
188
|
// Native functionCall chunks are only dispatched after successful stream
|
|
177
189
|
// completion in gemini.mjs. Until then a reconnect is safe. Text-leaked
|
|
178
|
-
// calls are dispatched while parsing and remain a hard replay boundary
|
|
179
|
-
|
|
190
|
+
// calls are dispatched while parsing and remain a hard replay boundary,
|
|
191
|
+
// unless the guard holds them back (`deferToolCalls`): a held call never
|
|
192
|
+
// runs when the stream fails, so a reconnect cannot double-execute it.
|
|
193
|
+
const pendingTool = leaked && textLeakGuard?.defersToolCalls !== true;
|
|
180
194
|
try {
|
|
181
195
|
if (visible) {
|
|
182
196
|
err.liveTextEmitted = true;
|
|
@@ -225,25 +239,35 @@ export function geminiChunkProgressKind(chunk) {
|
|
|
225
239
|
* (same shape as a non-streaming generateContent JSON body).
|
|
226
240
|
* Mirrors @google/generative-ai aggregateResponses().
|
|
227
241
|
*/
|
|
228
|
-
function aggregateGeminiStreamChunks(responses) {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
};
|
|
242
|
+
function aggregateGeminiStreamChunks(responses, label = 'Gemini stream') {
|
|
243
|
+
// An error envelope anywhere in the stream — including after STOP — fails
|
|
244
|
+
// the turn instead of aggregating into a success.
|
|
245
|
+
for (const response of responses) assertNoGeminiInBandError(response, label);
|
|
246
|
+
const aggregatedResponse = {};
|
|
247
|
+
// Candidates are keyed by their own `index`; chunks that omit it fall back
|
|
248
|
+
// to the position inside that chunk's candidate list.
|
|
249
|
+
const candidatesByIndex = new Map();
|
|
233
250
|
for (const response of responses) {
|
|
251
|
+
// Early block info must survive later chunks that carry none.
|
|
252
|
+
if (response?.promptFeedback) {
|
|
253
|
+
aggregatedResponse.promptFeedback = { ...aggregatedResponse.promptFeedback, ...response.promptFeedback };
|
|
254
|
+
}
|
|
234
255
|
if (response?.candidates) {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
if (!
|
|
238
|
-
|
|
239
|
-
|
|
256
|
+
response.candidates.forEach((candidate, position) => {
|
|
257
|
+
const candidateIndex = Number.isInteger(candidate?.index) ? candidate.index : position;
|
|
258
|
+
if (!candidatesByIndex.has(candidateIndex)) candidatesByIndex.set(candidateIndex, { index: candidateIndex });
|
|
259
|
+
const aggCand = candidatesByIndex.get(candidateIndex);
|
|
260
|
+
// A later chunk that omits a field never erases an earlier value.
|
|
261
|
+
if (candidate.citationMetadata !== undefined) {
|
|
262
|
+
aggCand.citationMetadata = mergeStreamMetadata(aggCand.citationMetadata, candidate.citationMetadata);
|
|
240
263
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
aggCand.finishReason = candidate.finishReason;
|
|
245
|
-
aggCand.finishMessage = candidate.finishMessage;
|
|
246
|
-
aggCand.safetyRatings = candidate.safetyRatings;
|
|
264
|
+
if (candidate.groundingMetadata !== undefined) {
|
|
265
|
+
aggCand.groundingMetadata = mergeStreamMetadata(aggCand.groundingMetadata, candidate.groundingMetadata);
|
|
266
|
+
}
|
|
267
|
+
if (geminiFinishReasonKind(candidate.finishReason) !== 'none') aggCand.finishReason = candidate.finishReason;
|
|
268
|
+
if (candidate.finishMessage !== undefined) aggCand.finishMessage = candidate.finishMessage;
|
|
269
|
+
if (candidate.safetyRatings !== undefined) aggCand.safetyRatings = candidate.safetyRatings;
|
|
270
|
+
if (candidate.continuationToken !== undefined) aggCand.continuationToken = candidate.continuationToken;
|
|
247
271
|
if (candidate.content?.parts) {
|
|
248
272
|
if (!aggCand.content) {
|
|
249
273
|
aggCand.content = {
|
|
@@ -262,19 +286,52 @@ function aggregateGeminiStreamChunks(responses) {
|
|
|
262
286
|
aggCand.content.parts.push(newPart);
|
|
263
287
|
}
|
|
264
288
|
}
|
|
265
|
-
|
|
266
|
-
}
|
|
289
|
+
});
|
|
267
290
|
}
|
|
268
291
|
if (response?.usageMetadata) aggregatedResponse.usageMetadata = response.usageMetadata;
|
|
269
292
|
}
|
|
293
|
+
if (candidatesByIndex.size) {
|
|
294
|
+
aggregatedResponse.candidates = [...candidatesByIndex.values()].sort((a, b) => a.index - b.index);
|
|
295
|
+
}
|
|
270
296
|
return aggregatedResponse;
|
|
271
297
|
}
|
|
272
298
|
|
|
299
|
+
// GroundingMetadata / CitationMetadata arrive in pieces while streaming and
|
|
300
|
+
// are merged, not replaced: groundingChunks carry only the chunks not sent
|
|
301
|
+
// before (appended as-is, so groundingSupports indices stay valid); every
|
|
302
|
+
// other list is a de-duplicated union, nested objects merge, scalars take the
|
|
303
|
+
// latest value.
|
|
304
|
+
function mergeStreamMetadata(previous, next) {
|
|
305
|
+
if (!previous) return next;
|
|
306
|
+
if (!next || typeof next !== 'object') return previous;
|
|
307
|
+
const merged = { ...previous };
|
|
308
|
+
for (const [key, value] of Object.entries(next)) {
|
|
309
|
+
if (value === undefined || value === null) continue;
|
|
310
|
+
const before = previous[key];
|
|
311
|
+
if (Array.isArray(value)) {
|
|
312
|
+
if (key === 'groundingChunks') {
|
|
313
|
+
merged[key] = [...(before || []), ...value];
|
|
314
|
+
} else {
|
|
315
|
+
const seen = new Set((before || []).map((item) => JSON.stringify(item)));
|
|
316
|
+
merged[key] = [...(before || []), ...value.filter((item) => !seen.has(JSON.stringify(item)))];
|
|
317
|
+
}
|
|
318
|
+
} else if (typeof value === 'object' && before && typeof before === 'object') {
|
|
319
|
+
merged[key] = { ...before, ...value };
|
|
320
|
+
} else {
|
|
321
|
+
merged[key] = value;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return merged;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// A stream that ends with no finishReason is unfinished, whatever it carried
|
|
328
|
+
// (thoughts only, an empty body, even right after a tool result); only a
|
|
329
|
+
// STOP that carries no text is a completed, empty answer.
|
|
273
330
|
function assertGeminiStreamCompleted({ sawStreamChunk, finishReason, promptBlockReason, label }) {
|
|
274
331
|
if (!sawStreamChunk) {
|
|
275
332
|
throw geminiTruncatedStreamError(`${label} truncated: empty stream`);
|
|
276
333
|
}
|
|
277
|
-
if (
|
|
334
|
+
if (geminiFinishReasonKind(finishReason) === 'none' && geminiFinishReasonKind(promptBlockReason) === 'none') {
|
|
278
335
|
throw geminiTruncatedStreamError(`${label} truncated: no finishReason`);
|
|
279
336
|
}
|
|
280
337
|
}
|
|
@@ -316,13 +373,23 @@ function relayGeminiStreamText(t, { onTextDelta, textLeakGuard }) {
|
|
|
316
373
|
* `part.text` streams. Mirrors the Anthropic OAuth guard: suppress tags from
|
|
317
374
|
* visible text, synthesize known-tool calls, dispatch via onToolCall.
|
|
318
375
|
*/
|
|
319
|
-
export function createGeminiTextLeakGuard({
|
|
376
|
+
export function createGeminiTextLeakGuard({
|
|
377
|
+
knownToolNames,
|
|
378
|
+
onTextDelta,
|
|
379
|
+
onToolCall,
|
|
380
|
+
onStreamDelta,
|
|
381
|
+
deferToolCalls = false,
|
|
382
|
+
}) {
|
|
320
383
|
const _knownTools = knownToolNameSet(knownToolNames);
|
|
321
384
|
const _enabled = _knownTools.size > 0;
|
|
322
385
|
const _isKnownTool = (name) => _knownTools.has(name);
|
|
323
386
|
let leakBuffer = '';
|
|
324
387
|
let relayedText = '';
|
|
325
388
|
const leakedCalls = [];
|
|
389
|
+
// With `deferToolCalls`, recovered calls wait here until the caller has seen
|
|
390
|
+
// the response finish cleanly (releaseDeferredToolCalls); a failed response
|
|
391
|
+
// never runs them.
|
|
392
|
+
const deferredCalls = [];
|
|
326
393
|
const dispatchedFingerprints = new Set();
|
|
327
394
|
|
|
328
395
|
const dispatchLeakedCall = (recovered) => {
|
|
@@ -344,9 +411,12 @@ export function createGeminiTextLeakGuard({ knownToolNames, onTextDelta, onToolC
|
|
|
344
411
|
arguments: args,
|
|
345
412
|
};
|
|
346
413
|
leakedCalls.push(call);
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
414
|
+
if (deferToolCalls) deferredCalls.push(call);
|
|
415
|
+
else {
|
|
416
|
+
try {
|
|
417
|
+
onToolCall?.(call);
|
|
418
|
+
} catch {}
|
|
419
|
+
}
|
|
350
420
|
try {
|
|
351
421
|
onStreamDelta?.('tool');
|
|
352
422
|
} catch {}
|
|
@@ -373,6 +443,9 @@ export function createGeminiTextLeakGuard({ knownToolNames, onTextDelta, onToolC
|
|
|
373
443
|
get enabled() {
|
|
374
444
|
return _enabled;
|
|
375
445
|
},
|
|
446
|
+
get defersToolCalls() {
|
|
447
|
+
return deferToolCalls === true;
|
|
448
|
+
},
|
|
376
449
|
feedText(text) {
|
|
377
450
|
if (!text) return;
|
|
378
451
|
if (!_enabled) {
|
|
@@ -411,6 +484,13 @@ export function createGeminiTextLeakGuard({ knownToolNames, onTextDelta, onToolC
|
|
|
411
484
|
getLeakedToolCalls() {
|
|
412
485
|
return [...leakedCalls];
|
|
413
486
|
},
|
|
487
|
+
releaseDeferredToolCalls() {
|
|
488
|
+
for (const call of deferredCalls.splice(0)) {
|
|
489
|
+
try {
|
|
490
|
+
onToolCall?.(call);
|
|
491
|
+
} catch {}
|
|
492
|
+
}
|
|
493
|
+
},
|
|
414
494
|
getRelayedText() {
|
|
415
495
|
return relayedText;
|
|
416
496
|
},
|
|
@@ -436,7 +516,16 @@ function createLeakGuardFinalizer(textLeakGuard) {
|
|
|
436
516
|
// aggregation, leak guard, watchdogs — stays shared.
|
|
437
517
|
export async function consumeGeminiRestStreamResponse(
|
|
438
518
|
response,
|
|
439
|
-
{
|
|
519
|
+
{
|
|
520
|
+
signal,
|
|
521
|
+
onStreamDelta,
|
|
522
|
+
onTextDelta,
|
|
523
|
+
textLeakGuard,
|
|
524
|
+
label,
|
|
525
|
+
unwrapChunk = null,
|
|
526
|
+
onChunk = null,
|
|
527
|
+
failureUsage = null,
|
|
528
|
+
}
|
|
440
529
|
) {
|
|
441
530
|
const unwrap =
|
|
442
531
|
typeof unwrapChunk === 'function'
|
|
@@ -464,7 +553,10 @@ export async function consumeGeminiRestStreamResponse(
|
|
|
464
553
|
});
|
|
465
554
|
// One decoded chunk: collected for aggregation and relayed to every sink.
|
|
466
555
|
const relayChunk = (rawChunk) => {
|
|
556
|
+
// In-band errors stay top level even on a transport that nests payloads.
|
|
557
|
+
assertNoGeminiInBandError(rawChunk, label);
|
|
467
558
|
const parsed = unwrap(rawChunk);
|
|
559
|
+
assertNoGeminiInBandError(parsed, label);
|
|
468
560
|
if (!sawStreamChunk) {
|
|
469
561
|
sawStreamChunk = true;
|
|
470
562
|
watchdogs.clearFirstByte();
|
|
@@ -530,12 +622,13 @@ export async function consumeGeminiRestStreamResponse(
|
|
|
530
622
|
}
|
|
531
623
|
const tail = sseDataPayload(buffer.trim());
|
|
532
624
|
if (tail) {
|
|
625
|
+
let rawTail;
|
|
533
626
|
try {
|
|
534
|
-
|
|
535
|
-
relayChunk(rawTail);
|
|
627
|
+
[rawTail] = await parseProviderJsonBatch([tail]);
|
|
536
628
|
} catch (cause) {
|
|
537
629
|
throw geminiStreamCorruptionError(`${label} corrupt SSE tail JSON`, cause);
|
|
538
630
|
}
|
|
631
|
+
relayChunk(rawTail);
|
|
539
632
|
}
|
|
540
633
|
} catch (err) {
|
|
541
634
|
finalizeLeakGuard();
|
|
@@ -558,7 +651,7 @@ export async function consumeGeminiRestStreamResponse(
|
|
|
558
651
|
finalizeLeakGuard();
|
|
559
652
|
}
|
|
560
653
|
|
|
561
|
-
const aggregated = aggregateGeminiStreamChunks(allChunks);
|
|
654
|
+
const aggregated = aggregateGeminiStreamChunks(allChunks, label);
|
|
562
655
|
const finishReason = aggregated.candidates?.[0]?.finishReason || null;
|
|
563
656
|
const promptBlockReason = aggregated.promptFeedback?.blockReason || null;
|
|
564
657
|
// Truncation (no finishReason) after visible output must carry the same
|
|
@@ -566,7 +659,12 @@ export async function consumeGeminiRestStreamResponse(
|
|
|
566
659
|
// above, so stamp here too (review High: transient TRUNCATED_STREAM would
|
|
567
660
|
// otherwise replay/double-render live text via withRetry).
|
|
568
661
|
try {
|
|
569
|
-
assertGeminiStreamCompleted({
|
|
662
|
+
assertGeminiStreamCompleted({
|
|
663
|
+
sawStreamChunk,
|
|
664
|
+
finishReason,
|
|
665
|
+
promptBlockReason,
|
|
666
|
+
label,
|
|
667
|
+
});
|
|
570
668
|
} catch (err) {
|
|
571
669
|
throw stampGeminiStreamFailure(err, { relayedText, textLeakGuard, chunks: allChunks, failureUsage });
|
|
572
670
|
}
|
|
@@ -636,6 +734,7 @@ export async function consumeGeminiSdkStream(
|
|
|
636
734
|
if (signal?.aborted) throw abortError();
|
|
637
735
|
if (step.done) break;
|
|
638
736
|
reader.noteChunk();
|
|
737
|
+
assertNoGeminiInBandError(step.value, label);
|
|
639
738
|
if (step.value) collectedChunks.push(step.value);
|
|
640
739
|
try {
|
|
641
740
|
onStreamDelta?.(geminiChunkProgressKind(step.value));
|
|
@@ -652,7 +751,7 @@ export async function consumeGeminiSdkStream(
|
|
|
652
751
|
// locally; retain the SDK response path only for an empty collection.
|
|
653
752
|
let raw;
|
|
654
753
|
if (collectedChunks.length > 0) {
|
|
655
|
-
raw = aggregateGeminiStreamChunks(collectedChunks);
|
|
754
|
+
raw = aggregateGeminiStreamChunks(collectedChunks, label);
|
|
656
755
|
} else {
|
|
657
756
|
let response;
|
|
658
757
|
try {
|
|
@@ -661,10 +760,16 @@ export async function consumeGeminiSdkStream(
|
|
|
661
760
|
throw normalizeGeminiSdkError(err, label);
|
|
662
761
|
}
|
|
663
762
|
raw = response?.candidates ? response : response?.response || response;
|
|
763
|
+
assertNoGeminiInBandError(raw, label);
|
|
664
764
|
}
|
|
665
765
|
const finishReason = raw?.candidates?.[0]?.finishReason || null;
|
|
666
766
|
const promptBlockReason = raw?.promptFeedback?.blockReason || null;
|
|
667
|
-
assertGeminiStreamCompleted({
|
|
767
|
+
assertGeminiStreamCompleted({
|
|
768
|
+
sawStreamChunk: reader.sawStreamChunk,
|
|
769
|
+
finishReason,
|
|
770
|
+
promptBlockReason,
|
|
771
|
+
label,
|
|
772
|
+
});
|
|
668
773
|
return raw;
|
|
669
774
|
} catch (err) {
|
|
670
775
|
reader?.clearFirstByte();
|
|
@@ -1,11 +1,67 @@
|
|
|
1
|
+
import { getModelMetadataSync } from '../../../shared/llm/model-catalog.mjs';
|
|
2
|
+
|
|
3
|
+
// The thinkingLevel values the Gemini wire accepts.
|
|
1
4
|
const LEVELS = ['minimal', 'low', 'medium', 'high'];
|
|
2
5
|
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
// The thinkingLevel values the catalogs declare for the model (provider live
|
|
7
|
+
// roster, then models.dev / LiteLLM rows, resolved by getModelMetadataSync),
|
|
8
|
+
// limited to what the Gemini wire accepts. null when no catalog declares a ladder.
|
|
9
|
+
function catalogThinkingLevels(model, provider) {
|
|
10
|
+
const bare = String(model || '').replace(/^models\//i, '');
|
|
11
|
+
const effort = getModelMetadataSync(bare, provider)?.reasoningOptions?.find((option) => option?.type === 'effort');
|
|
12
|
+
const declared = (Array.isArray(effort?.values) ? effort.values : [])
|
|
13
|
+
.map((value) => String(value).toLowerCase())
|
|
14
|
+
.filter((value) => LEVELS.includes(value));
|
|
15
|
+
return declared.length ? [...new Set(declared)] : null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Gemini 2.5 models take thinkingBudget only (thinkingLevel is unsupported).
|
|
19
|
+
// Documented ranges: 2.5 Pro 128–32768 (cannot disable), 2.5 Flash 0–24576,
|
|
20
|
+
// 2.5 Flash-Lite 0 or 512–24576; -1 is dynamic thinking for all of them.
|
|
21
|
+
function budgetSpec(model) {
|
|
22
|
+
const bare = String(model || '').replace(/^models\//i, '').toLowerCase();
|
|
23
|
+
if (!/^gemini-2\.5(?:-|$)/.test(bare)) return null;
|
|
24
|
+
if (/^gemini-2\.5-pro/.test(bare)) {
|
|
25
|
+
return { name: 'Gemini 2.5 Pro', min: 128, max: 32768, canDisable: false, efforts: { minimal: 128, low: 1024, medium: 8192, high: 32768 } };
|
|
26
|
+
}
|
|
27
|
+
if (/^gemini-2\.5-flash-lite/.test(bare)) {
|
|
28
|
+
return { name: 'Gemini 2.5 Flash-Lite', min: 512, max: 24576, canDisable: true, efforts: { minimal: 512, low: 1024, medium: 8192, high: 24576 } };
|
|
29
|
+
}
|
|
30
|
+
return { name: 'Gemini 2.5 Flash', min: 0, max: 24576, canDisable: true, efforts: { minimal: 0, low: 1024, medium: 8192, high: 24576 } };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Levels documented for models whose ladder differs from the generic wire
|
|
34
|
+
// vocabulary (a catalog ladder, when declared, still takes precedence).
|
|
35
|
+
function documentedThinkingLevels(model) {
|
|
36
|
+
const bare = String(model || '').replace(/^models\//i, '').toLowerCase();
|
|
37
|
+
if (bare === 'gemini-4-argon' || bare === 'gemini-3.8-flash') return ['low', 'medium', 'high'];
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function checkBudget(model, spec, budget) {
|
|
42
|
+
if (!Number.isInteger(budget) || budget < -1) {
|
|
43
|
+
throw new TypeError('thinkingBudget must be -1 (dynamic), 0, or a positive integer.');
|
|
44
|
+
}
|
|
45
|
+
if (!spec || budget === -1) return;
|
|
46
|
+
if (budget === 0 && !spec.canDisable) {
|
|
47
|
+
throw new TypeError(`${model} (${spec.name}) cannot disable thinking; thinkingBudget 0 is not allowed.`);
|
|
48
|
+
}
|
|
49
|
+
if (budget !== 0 && (budget < spec.min || budget > spec.max)) {
|
|
50
|
+
throw new TypeError(`${model} (${spec.name}) thinkingBudget must be -1, ${spec.canDisable ? '0, or ' : ''}${spec.min}–${spec.max}; received ${budget}.`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Only translate the public option names. Omitting settings preserves the
|
|
55
|
+
// provider's model default. Gemini 2.5 models use thinkingBudget (a generic
|
|
56
|
+
// effort maps to a budget; an explicit thinkingLevel is rejected locally and
|
|
57
|
+
// budgets are range-checked). Other models use thinkingLevel, checked against
|
|
58
|
+
// the catalog/documented ladder; unknown models pass values within the wire
|
|
59
|
+
// vocabulary and the server decides.
|
|
60
|
+
export function geminiThinkingConfig(model, opts = {}, { includeThoughts, provider = 'gemini' } = {}) {
|
|
7
61
|
const rawBudget = opts.thinkingBudget ?? opts.thinkingBudgetTokens;
|
|
8
62
|
const hasBudget = rawBudget !== undefined && rawBudget !== null && rawBudget !== '';
|
|
63
|
+
const spec = budgetSpec(model);
|
|
64
|
+
const explicitLevel = opts.thinkingLevel == null ? '' : String(opts.thinkingLevel).trim().toLowerCase();
|
|
9
65
|
const rawLevel = opts.thinkingLevel ?? (hasBudget ? undefined : opts.effort);
|
|
10
66
|
const level = rawLevel == null ? '' : String(rawLevel).trim().toLowerCase();
|
|
11
67
|
const config = {};
|
|
@@ -14,15 +70,16 @@ export function geminiThinkingConfig(model, opts = {}, { includeThoughts } = {})
|
|
|
14
70
|
if (level && hasBudget) {
|
|
15
71
|
throw new TypeError('Choose thinkingLevel/effort or thinkingBudget, not both.');
|
|
16
72
|
}
|
|
17
|
-
if (
|
|
18
|
-
|
|
19
|
-
|
|
73
|
+
if (spec && explicitLevel) {
|
|
74
|
+
throw new TypeError(`${model} (${spec.name}) does not support thinkingLevel; use thinkingBudget.`);
|
|
75
|
+
}
|
|
76
|
+
if (spec && level) {
|
|
77
|
+
if (!Object.hasOwn(spec.efforts, level)) {
|
|
78
|
+
throw new TypeError(`${model} supports thinking levels ${Object.keys(spec.efforts).join(', ')}; received ${level}.`);
|
|
20
79
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
supported = ['low', 'medium', 'high'];
|
|
25
|
-
} else if (/^gemini-3\.1-flash-lite.*image/.test(id)) supported = ['minimal', 'high'];
|
|
80
|
+
config.thinkingBudget = spec.efforts[level];
|
|
81
|
+
} else if (level) {
|
|
82
|
+
const supported = catalogThinkingLevels(model, provider) ?? documentedThinkingLevels(model) ?? LEVELS;
|
|
26
83
|
if (!supported.includes(level)) {
|
|
27
84
|
throw new TypeError(`${model} supports thinking levels ${supported.join(', ')}; received ${level}.`);
|
|
28
85
|
}
|
|
@@ -30,18 +87,7 @@ export function geminiThinkingConfig(model, opts = {}, { includeThoughts } = {})
|
|
|
30
87
|
}
|
|
31
88
|
if (hasBudget) {
|
|
32
89
|
const budget = Number(rawBudget);
|
|
33
|
-
|
|
34
|
-
throw new TypeError('thinkingBudget must be -1 (dynamic), 0, or a positive integer.');
|
|
35
|
-
}
|
|
36
|
-
if (/^gemini-2\.5-pro(?:-|$)/.test(id) && budget !== -1 && (budget < 128 || budget > 32768)) {
|
|
37
|
-
throw new TypeError(`${model} requires thinkingBudget -1 or 128..32768.`);
|
|
38
|
-
}
|
|
39
|
-
if (/^gemini-2\.5-flash(?:-|$)/.test(id) && budget > 24576) {
|
|
40
|
-
throw new TypeError(`${model} requires thinkingBudget at most 24576.`);
|
|
41
|
-
}
|
|
42
|
-
if (/^gemini-2\.5-flash-lite(?:-|$)/.test(id) && budget > 0 && budget < 512) {
|
|
43
|
-
throw new TypeError(`${model} requires thinkingBudget -1, 0, or 512..24576.`);
|
|
44
|
-
}
|
|
90
|
+
checkBudget(model, spec, budget);
|
|
45
91
|
config.thinkingBudget = budget;
|
|
46
92
|
}
|
|
47
93
|
return Object.keys(config).length ? config : undefined;
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { GoogleGenerativeAI } from '@google/generative-ai';
|
|
2
2
|
import { reloadProviderApiKey, resolveProviderApiKey } from '../../../shared/provider-api-key.mjs';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
canFallbackNonStreaming,
|
|
5
|
+
emitProviderRetryStage,
|
|
6
|
+
markProviderRecoveryExhausted,
|
|
7
|
+
withRetry,
|
|
8
|
+
} from './retry-classifier.mjs';
|
|
4
9
|
import { noteErrorUsage } from './lib/note-error-usage.mjs';
|
|
5
10
|
import { traceNonStreamingFallback } from './lib/transport-fallback-trace.mjs';
|
|
6
11
|
import {
|
|
@@ -12,6 +17,18 @@ import {
|
|
|
12
17
|
} from '../stall-policy.mjs';
|
|
13
18
|
import { getLlmDispatcher, preconnect } from '../../../shared/llm/http-agent.mjs';
|
|
14
19
|
import { GEMINI_FIRST_BYTE_TIMEOUT_MS, consumeGeminiRestStreamResponse } from './gemini-stream.mjs';
|
|
20
|
+
import {
|
|
21
|
+
applyGeminiErrorContract,
|
|
22
|
+
geminiContinuationUnsupportedError,
|
|
23
|
+
geminiFinishErrorFields,
|
|
24
|
+
geminiFinishReasonKind,
|
|
25
|
+
} from './gemini-error-contract.mjs';
|
|
26
|
+
import {
|
|
27
|
+
GEMINI_MIDSTREAM_MAX_ATTEMPTS,
|
|
28
|
+
geminiEndsWithFunctionResponse,
|
|
29
|
+
geminiInvalidStreamReason,
|
|
30
|
+
runGeminiStreamAttempts,
|
|
31
|
+
} from './gemini-retry-policy.mjs';
|
|
15
32
|
import { geminiTextLeakGuardFor, streamGeminiSdkAttempt } from './gemini-sdk-request.mjs';
|
|
16
33
|
import { emitGeminiToolCalls } from './gemini-schema.mjs';
|
|
17
34
|
import { buildGeminiRequest, geminiCachedRestBody } from './gemini-request-body.mjs';
|
|
@@ -32,10 +49,13 @@ import {
|
|
|
32
49
|
GEMINI_GLOBAL_CACHE_DELETE_GRACE_MS,
|
|
33
50
|
_geminiCredentialFingerprint,
|
|
34
51
|
_invalidateGeminiCachesForCredentialFingerprint,
|
|
52
|
+
geminiExplicitCacheRefused,
|
|
53
|
+
markGeminiExplicitCacheRefused,
|
|
35
54
|
} from './gemini-cache.mjs';
|
|
36
55
|
import {
|
|
37
56
|
awaitSharedCreate,
|
|
38
57
|
dropRejectedGeminiCache,
|
|
58
|
+
geminiBareModelId,
|
|
39
59
|
geminiCacheCreateBody,
|
|
40
60
|
geminiCacheEntry,
|
|
41
61
|
geminiCachePrefixIdentity,
|
|
@@ -59,7 +79,7 @@ import {
|
|
|
59
79
|
let _modelRefreshInFlight = null;
|
|
60
80
|
const GEMINI_AVAILABILITY_TIMEOUT_MS = 1_000;
|
|
61
81
|
|
|
62
|
-
function geminiRestError(res, text, label) {
|
|
82
|
+
export function geminiRestError(res, text, label) {
|
|
63
83
|
let payload = null;
|
|
64
84
|
try {
|
|
65
85
|
payload = text ? JSON.parse(text) : null;
|
|
@@ -78,16 +98,11 @@ function geminiRestError(res, text, label) {
|
|
|
78
98
|
err.error = detail;
|
|
79
99
|
err.data = payload;
|
|
80
100
|
if (detail.status) err.geminiStatus = detail.status;
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
// A 429 RESOURCE_EXHAUSTED is a request-local rate limit even without
|
|
87
|
-
// Retry-After (Google/LiteLLM retry). Do not stamp it as a quota code.
|
|
88
|
-
if (detail.status && (retryAfter == null || retryAfter === '') && res.status !== 429) {
|
|
89
|
-
err.code = detail.status;
|
|
90
|
-
}
|
|
101
|
+
const details = detail.details ?? detail.errorDetails;
|
|
102
|
+
if (Array.isArray(details)) err.details = details;
|
|
103
|
+
// Typed contract (code/retryAfterMs/resetAt/quotaScope); the core decides
|
|
104
|
+
// whether a 429 RESOURCE_EXHAUSTED is request-local or a quota refusal.
|
|
105
|
+
applyGeminiErrorContract(err, { details, googleStatus: detail.status, message: detail.message });
|
|
91
106
|
}
|
|
92
107
|
return err;
|
|
93
108
|
}
|
|
@@ -139,6 +154,9 @@ export class GeminiProvider {
|
|
|
139
154
|
// input already includes cache. See registry.mjs.
|
|
140
155
|
static inputExcludesCache = false;
|
|
141
156
|
name = 'gemini';
|
|
157
|
+
// The two-phase ladder (gemini-retry-policy.mjs) is the whole recovery:
|
|
158
|
+
// a spent ladder surfaces instead of parking on loop recovery cycles.
|
|
159
|
+
retryPolicy = Object.freeze({ recoveryCycles: false });
|
|
142
160
|
genAI;
|
|
143
161
|
config;
|
|
144
162
|
_fetch;
|
|
@@ -263,7 +281,11 @@ export class GeminiProvider {
|
|
|
263
281
|
if (decision.canReuseState) {
|
|
264
282
|
return state.cacheName;
|
|
265
283
|
}
|
|
266
|
-
|
|
284
|
+
// A request forked from a shared prefix (/btw: opts.sharedCachePrefixCount)
|
|
285
|
+
// only reads the session's live cache. Creating or refreshing one would
|
|
286
|
+
// store the fork's own suffix (the appended reply and question).
|
|
287
|
+
if (opts.sharedCachePrefixCount) return decision.canAttachState ? state.cacheName : null;
|
|
288
|
+
if (!apiKey || geminiExplicitCacheRefused(model)) return null;
|
|
267
289
|
const { canAttachState } = decision;
|
|
268
290
|
if (geminiPrefixBelowMinimum({ model, systemInstruction, geminiTools, contents, opts, currentIter })) {
|
|
269
291
|
return canAttachState ? state.cacheName : null;
|
|
@@ -443,6 +465,7 @@ export class GeminiProvider {
|
|
|
443
465
|
_setGeminiGlobalCache(globalCacheKey, entry);
|
|
444
466
|
return entry;
|
|
445
467
|
} catch (err) {
|
|
468
|
+
markGeminiExplicitCacheRefused(model, err);
|
|
446
469
|
process.stderr.write(`[gemini] cachedContents.create error: ${err?.message || err}\n`);
|
|
447
470
|
return null;
|
|
448
471
|
}
|
|
@@ -571,10 +594,28 @@ export class GeminiProvider {
|
|
|
571
594
|
cachedContent,
|
|
572
595
|
});
|
|
573
596
|
const parsed = parseGeminiCandidate(response, textLeakGuard);
|
|
574
|
-
emitGeminiToolCalls(parsed.nativeToolCalls, callbacks.onToolCall);
|
|
575
597
|
const usage = resolveGeminiUsage(response, opts, cachedContent, useModel);
|
|
598
|
+
// Terminal status first: a failed candidate's calls are never dispatched.
|
|
576
599
|
const incomplete = geminiIncompleteError(response, parsed, useModel, usage);
|
|
577
|
-
if (incomplete)
|
|
600
|
+
if (incomplete) {
|
|
601
|
+
Object.assign(incomplete, geminiFinishErrorFields(response));
|
|
602
|
+
if (geminiFinishReasonKind(incomplete.finishReason) === 'continuation') {
|
|
603
|
+
// Direct Gemini only: surface the typed result with its token.
|
|
604
|
+
throw geminiContinuationUnsupportedError(incomplete, response);
|
|
605
|
+
}
|
|
606
|
+
// A malformed / unexpected tool call that survived the stream ladder
|
|
607
|
+
// (4 attempts) is spent; the loop must not multiply that budget.
|
|
608
|
+
if (
|
|
609
|
+
geminiInvalidStreamReason(response, textLeakGuard, {
|
|
610
|
+
afterToolResult: geminiEndsWithFunctionResponse(request.contents),
|
|
611
|
+
})
|
|
612
|
+
) {
|
|
613
|
+
markProviderRecoveryExhausted(incomplete, { owner: 'gemini-stream', attempts: GEMINI_MIDSTREAM_MAX_ATTEMPTS });
|
|
614
|
+
}
|
|
615
|
+
throw incomplete;
|
|
616
|
+
}
|
|
617
|
+
textLeakGuard?.releaseDeferredToolCalls?.();
|
|
618
|
+
emitGeminiToolCalls(parsed.nativeToolCalls, callbacks.onToolCall);
|
|
578
619
|
return geminiSendResult(parsed, useModel, opts, usage);
|
|
579
620
|
}
|
|
580
621
|
|
|
@@ -602,7 +643,7 @@ export class GeminiProvider {
|
|
|
602
643
|
}
|
|
603
644
|
|
|
604
645
|
async _restGenerateContent(useModel, apiKey, body, fallbackSignal) {
|
|
605
|
-
const nonStreamUrl = `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(useModel)}:generateContent?key=${encodeURIComponent(apiKey)}`;
|
|
646
|
+
const nonStreamUrl = `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(geminiBareModelId(useModel))}:generateContent?key=${encodeURIComponent(apiKey)}`;
|
|
606
647
|
const res = await this._fetch(nonStreamUrl, {
|
|
607
648
|
method: 'POST',
|
|
608
649
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -626,10 +667,10 @@ export class GeminiProvider {
|
|
|
626
667
|
// { retryUncached: true } when the cache itself was rejected and the send
|
|
627
668
|
// must be replayed without it.
|
|
628
669
|
async _streamCachedViaRest(stream, internal) {
|
|
629
|
-
const { opts, signal, useModel, contents, generationConfig, cachedContent, callbacks } = stream;
|
|
670
|
+
const { opts, signal, useModel, contents, generationConfig, safetySettings, cachedContent, callbacks } = stream;
|
|
630
671
|
const apiKey = this._getApiKey();
|
|
631
|
-
const genUrl = `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(useModel)}:streamGenerateContent?alt=sse&key=${encodeURIComponent(apiKey)}`;
|
|
632
|
-
const body = geminiCachedRestBody({ opts, contents, cachedContent, generationConfig });
|
|
672
|
+
const genUrl = `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(geminiBareModelId(useModel))}:streamGenerateContent?alt=sse&key=${encodeURIComponent(apiKey)}`;
|
|
673
|
+
const body = geminiCachedRestBody({ opts, contents, cachedContent, generationConfig, safetySettings });
|
|
633
674
|
// cachedContent owns tools + toolConfig. The API rejects a
|
|
634
675
|
// generateContent request that repeats either field.
|
|
635
676
|
// Option A (mirror anthropic-oauth): no absolute wall-clock cap on a
|
|
@@ -643,10 +684,16 @@ export class GeminiProvider {
|
|
|
643
684
|
const restPassthrough = createPassthroughSignal(signal);
|
|
644
685
|
const totalSignal = restPassthrough.signal;
|
|
645
686
|
try {
|
|
646
|
-
|
|
647
|
-
|
|
687
|
+
const afterToolResult = geminiEndsWithFunctionResponse(contents);
|
|
688
|
+
return await runGeminiStreamAttempts({
|
|
689
|
+
signal: totalSignal,
|
|
690
|
+
sleepFn: this.config?.sleepFn,
|
|
691
|
+
onRetry: geminiRetryLogger(opts, '[gemini-rest]'),
|
|
692
|
+
afterToolResult,
|
|
693
|
+
run: async ({ signal: attemptSignal, connected }) => {
|
|
648
694
|
signalRequesting(opts);
|
|
649
695
|
const res = await this._openRestStream(genUrl, body, attemptSignal);
|
|
696
|
+
connected();
|
|
650
697
|
const textLeakGuard = geminiTextLeakGuardFor(stream);
|
|
651
698
|
const response = await consumeGeminiRestStreamResponse(res, {
|
|
652
699
|
signal: attemptSignal,
|
|
@@ -658,8 +705,7 @@ export class GeminiProvider {
|
|
|
658
705
|
});
|
|
659
706
|
return { response, textLeakGuard };
|
|
660
707
|
},
|
|
661
|
-
|
|
662
|
-
);
|
|
708
|
+
});
|
|
663
709
|
} catch (err) {
|
|
664
710
|
if (
|
|
665
711
|
!internal.skipExplicitCache &&
|
|
@@ -685,26 +731,31 @@ export class GeminiProvider {
|
|
|
685
731
|
}
|
|
686
732
|
|
|
687
733
|
async _streamViaSdk(stream) {
|
|
688
|
-
const { opts, signal, useModel, systemInstruction, geminiTools, toolConfig, generationConfig, contents } =
|
|
734
|
+
const { opts, signal, useModel, systemInstruction, geminiTools, toolConfig, generationConfig, safetySettings, contents } =
|
|
735
|
+
stream;
|
|
689
736
|
const genModel = this._currentGenAI().getGenerativeModel({
|
|
690
737
|
model: useModel,
|
|
691
738
|
systemInstruction,
|
|
692
739
|
tools: geminiTools,
|
|
693
740
|
...(toolConfig ? { toolConfig } : {}),
|
|
694
741
|
...(generationConfig ? { generationConfig } : {}),
|
|
742
|
+
...(safetySettings ? { safetySettings } : {}),
|
|
695
743
|
});
|
|
696
744
|
// Option A (mirror anthropic-oauth): pure pass-through of the external
|
|
697
745
|
// signal, no absolute streaming total cap. See the REST path.
|
|
698
746
|
const sdkPassthrough = createPassthroughSignal(signal);
|
|
699
747
|
const totalSignal = sdkPassthrough.signal;
|
|
700
748
|
try {
|
|
701
|
-
return await
|
|
702
|
-
|
|
749
|
+
return await runGeminiStreamAttempts({
|
|
750
|
+
signal: totalSignal,
|
|
751
|
+
sleepFn: this.config?.sleepFn,
|
|
752
|
+
onRetry: geminiRetryLogger(opts, '[gemini]'),
|
|
753
|
+
afterToolResult: geminiEndsWithFunctionResponse(contents),
|
|
754
|
+
run: async ({ signal: attemptSignal, connected }) => {
|
|
703
755
|
signalRequesting(opts);
|
|
704
|
-
return await streamGeminiSdkAttempt(genModel, stream, attemptSignal);
|
|
756
|
+
return await streamGeminiSdkAttempt(genModel, stream, attemptSignal, connected);
|
|
705
757
|
},
|
|
706
|
-
|
|
707
|
-
);
|
|
758
|
+
});
|
|
708
759
|
} catch (err) {
|
|
709
760
|
const recovered = await this._recoverGeminiNonStreaming({
|
|
710
761
|
streamErr: err,
|
|
@@ -3,7 +3,7 @@ import { createNpmVersionSource, maxSemver } from './npm-cli-version.mjs';
|
|
|
3
3
|
// Grok CLI client version for the cli-chat-proxy version gate (HTTP 426).
|
|
4
4
|
// Effective = env override, else max(floor, learned-from-426, live npm latest
|
|
5
5
|
// of the official @xai-official/grok CLI).
|
|
6
|
-
export const GROK_CLI_VERSION_FLOOR = '1.0.
|
|
6
|
+
export const GROK_CLI_VERSION_FLOOR = '1.0.60';
|
|
7
7
|
export const GROK_CLI_NPM_PACKAGE = '@xai-official/grok';
|
|
8
8
|
|
|
9
9
|
const live = createNpmVersionSource(GROK_CLI_NPM_PACKAGE, { persistKey: 'grok-cli' });
|