mixdog 1.3.5 → 1.4.1
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/NOTICE.md +2 -2
- package/README.md +2 -2
- package/package.json +2 -11
- package/scripts/check-voice-runtime-inputs.mjs +25 -0
- package/scripts/daemon-stub.mjs +1 -1
- package/scripts/gate-local.mjs +16 -5
- package/scripts/latest-guard.mjs +21 -9
- package/scripts/lib/isolated-test-env.mjs +10 -5
- package/scripts/lib/run-node-tests.mjs +37 -37
- package/scripts/lib/scoped-temp.d.mts +16 -0
- package/scripts/lib/scoped-temp.mjs +123 -0
- package/scripts/lib/stale-temp.mjs +44 -0
- package/scripts/native-release-status.mjs +2 -2
- package/scripts/post-release-check.mjs +1 -6
- package/scripts/pptx-kit-index.mjs +17 -4
- package/scripts/recall-history-cases.json +1 -1
- package/scripts/suite-health.mjs +20 -2
- package/scripts/test-data-dir.mjs +10 -7
- package/scripts/test.mjs +7 -11
- package/src/agents/reviewer/AGENT.md +7 -11
- package/src/agents/reviewer/agent.json +1 -1
- package/src/app.mjs +4 -0
- package/src/defaults/shipped-history.json +22 -1
- package/src/defaults/skills/browser-use/SKILL.md +62 -12
- package/src/defaults/skills/code-tidy/SKILL.md +142 -270
- package/src/defaults/skills/code-tidy/references/agent-cleanup.md +4 -4
- package/src/defaults/skills/code-tidy/references/cleanup-report.md +31 -76
- package/src/defaults/skills/code-tidy/references/dead-code.md +6 -12
- package/src/defaults/skills/computer-use/SKILL.md +35 -9
- package/src/defaults/skills/setup/SKILL.md +22 -0
- package/src/defaults/skills/setup/references/actions.md +39 -5
- package/src/defaults/skills/setup/references/surfaces.md +11 -2
- package/src/defaults/skills/visualize/SKILL.md +2 -1
- package/src/lib/rules-builder.cjs +39 -20
- package/src/output-styles/common.md +2 -2
- package/src/output-styles/simple.md +1 -1
- package/src/rules/agent/AGENT.md +11 -10
- package/src/rules/lead/LEAD.md +23 -20
- package/src/rules/shared/05-tool-calls.md +5 -6
- package/src/rules/shared/10-tool-workflow.md +4 -0
- package/src/rules/shared/45-destructive.md +0 -2
- package/src/rules/shared/50-execution.md +2 -0
- package/src/rules/shared/60-verification.md +7 -5
- package/src/rules/shared/70-delivery.md +7 -9
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -6
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -3
- package/src/runtime/agent/orchestrator/agent-runtime/title-completion.mjs +3 -1
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +3 -1
- package/src/runtime/agent/orchestrator/cache-break-trace.mjs +2 -0
- package/src/runtime/agent/orchestrator/config.mjs +17 -1
- package/src/runtime/agent/orchestrator/context/collect.mjs +3 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +73 -68
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +57 -2
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +3 -3
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +176 -72
- package/src/runtime/agent/orchestrator/mcp/client.mjs +19 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +192 -133
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +42 -6
- package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +7 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +8 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-cache-warm.mjs +165 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +14 -14
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +159 -69
- package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +25 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +70 -33
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +135 -87
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +123 -102
- package/src/runtime/agent/orchestrator/providers/cache-warm-admission.mjs +90 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +25 -9
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +25 -13
- package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/devin.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +210 -20
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -11
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +45 -6
- package/src/runtime/agent/orchestrator/providers/lib/first-output-window.mjs +58 -0
- package/src/runtime/agent/orchestrator/providers/lib/listen-on.mjs +14 -0
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +17 -3
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +52 -10
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +8 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/npm-cli-version.mjs +11 -3
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +14 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +4 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +5 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +16 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +13 -3
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +13 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +81 -42
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +136 -5
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -9
- package/src/runtime/agent/orchestrator/providers/openai-ws-send/send-context.mjs +22 -3
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +43 -5
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/handshake-failure.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/stream-failure.mjs +6 -3
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +20 -12
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +48 -22
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +65 -1
- package/src/runtime/agent/orchestrator/providers/quota-reading.mjs +38 -12
- package/src/runtime/agent/orchestrator/providers/registry.mjs +38 -0
- package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +39 -7
- package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +6 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +49 -16
- package/src/runtime/agent/orchestrator/runtime-core/compaction-config-keys.mjs +62 -0
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +37 -16
- package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +100 -23
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +7 -6
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +9 -3
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +19 -4
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +125 -30
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +3 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +1 -3
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +798 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -8
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/compact/observation-supersession.mjs +103 -23
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +280 -45
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +475 -58
- package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +42 -17
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +163 -22
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +132 -17
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +38 -7
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +90 -22
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +0 -2
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -4
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +51 -25
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +37 -3
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +13 -5
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +31 -3
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +20 -3
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/after-hook.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +5 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +16 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +16 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +49 -21
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -10
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +12 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +19 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +133 -90
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +31 -4
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +30 -18
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +24 -14
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +130 -0
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +27 -9
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +81 -8
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +27 -8
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +12 -5
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +9 -4
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +102 -15
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +21 -5
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +9 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +24 -9
- package/src/runtime/agent/orchestrator/session/prompt-cache-idle-gaps.mjs +113 -0
- package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +150 -0
- package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +154 -0
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +36 -9
- package/src/runtime/agent/orchestrator/session/sensitive-projection.mjs +100 -0
- package/src/runtime/agent/orchestrator/session/sensitive-values.mjs +257 -0
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +20 -7
- package/src/runtime/agent/orchestrator/session/side-question.mjs +18 -0
- package/src/runtime/agent/orchestrator/session/skill-update-notice.mjs +60 -0
- package/src/runtime/agent/orchestrator/session/store/live-state.mjs +6 -3
- package/src/runtime/agent/orchestrator/session/store/save-delta.mjs +9 -5
- package/src/runtime/agent/orchestrator/session/store/serialize.mjs +9 -8
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/store/session-persistence-events.mjs +29 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +8 -6
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +16 -2
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +81 -22
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +92 -3
- package/src/runtime/agent/orchestrator/session/stored-attachment-history.mjs +32 -0
- package/src/runtime/agent/orchestrator/session/thinking-binding.mjs +108 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +79 -3
- package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs +9 -7
- package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-text.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/turn-failure.mjs +5 -1
- package/src/runtime/agent/orchestrator/stall-policy.mjs +23 -0
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +5 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +12 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +240 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/shell-cwd.mjs +38 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +31 -6
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +110 -26
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +31 -5
- package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +22 -8
- package/src/runtime/agent/orchestrator/tools/builtin/lib/scoped-search-flight.mjs +9 -5
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +23 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +1 -8
- package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/federation.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/lib/isolated-test-env.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +26 -4
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +36 -13
- package/src/runtime/browser-bridge/action-schema.mjs +13 -2
- package/src/runtime/browser-bridge/client.mjs +73 -8
- package/src/runtime/browser-bridge/input-fields.mjs +8 -9
- package/src/runtime/browser-bridge/mail-links.mjs +107 -0
- package/src/runtime/browser-bridge/tool-defs.mjs +1 -1
- package/src/runtime/channels/lib/config.mjs +6 -61
- package/src/runtime/channels/lib/crash-log.mjs +1 -1
- package/src/runtime/channels/lib/event-pipeline.mjs +4 -19
- package/src/runtime/channels/lib/event-queue.mjs +3 -18
- package/src/runtime/channels/lib/owned-runtime/automation-services.mjs +2 -2
- package/src/runtime/channels/lib/owned-runtime/automation-start.mjs +3 -4
- package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +4 -59
- package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +33 -115
- package/src/runtime/channels/lib/owned-runtime/owned-stop.mjs +5 -22
- package/src/runtime/channels/lib/owned-runtime/state.mjs +2 -8
- package/src/runtime/channels/lib/owned-runtime.mjs +6 -23
- package/src/runtime/channels/lib/parent-bridge.mjs +2 -2
- package/src/runtime/channels/lib/runtime-paths.mjs +4 -43
- package/src/runtime/channels/lib/scheduler.mjs +33 -147
- package/src/runtime/channels/lib/schedules-db.mjs +34 -11
- package/src/runtime/channels/lib/status-snapshot.mjs +1 -1
- package/src/runtime/channels/lib/tool-dispatch.mjs +1 -2
- package/src/runtime/channels/lib/webhook/signature.mjs +4 -1
- package/src/runtime/channels/lib/webhooks-db.mjs +5 -9
- package/src/runtime/channels/lib/whisper-port.mjs +10 -1
- package/src/runtime/channels/lib/worker-bootstrap.mjs +0 -1
- package/src/runtime/channels/lib/worker-ipc.mjs +0 -1
- package/src/runtime/channels/lib/worker-main.mjs +10 -34
- package/src/runtime/computer-bridge/action-schema.mjs +42 -1
- package/src/runtime/computer-bridge/actions.mjs +9 -1
- package/src/runtime/computer-bridge/client.mjs +180 -8
- package/src/runtime/computer-bridge/core-actions.mjs +2 -2
- package/src/runtime/computer-bridge/error-recovery.mjs +28 -2
- package/src/runtime/computer-bridge/linux-action-capabilities.mjs +24 -5
- package/src/runtime/computer-bridge/linux-readiness.d.mts +7 -2
- package/src/runtime/computer-bridge/linux-readiness.mjs +65 -23
- package/src/runtime/computer-bridge/pending-continuation.mjs +1 -1
- package/src/runtime/connectors/connector-accounts-mcp.mjs +230 -0
- package/src/runtime/connectors/gmail-app-password.mjs +172 -39
- package/src/runtime/connectors/google-mcp.mjs +10 -12
- package/src/runtime/local-provider/server-process.mjs +2 -1
- package/src/runtime/media/adapters/gemini-video.mjs +4 -1
- package/src/runtime/media/adapters/xai-media.mjs +2 -1
- package/src/runtime/memory/lib/embedding-worker.mjs +6 -3
- package/src/runtime/memory/lib/memory-action-handlers/cycle-backfill-action.mjs +1 -7
- package/src/runtime/memory/lib/memory-chunk-quality.mjs +1 -6
- package/src/runtime/memory/lib/pg/adapter.mjs +77 -70
- package/src/runtime/memory/lib/pg/supervisor.mjs +24 -12
- package/src/runtime/memory/lib/runtime-fetcher.mjs +23 -5
- package/src/runtime/office/authoring/pdf-author-action.mjs +1 -6
- package/src/runtime/office/design/design-art-direction.mjs +29 -27
- package/src/runtime/office/pdf/pdf-writer.mjs +6 -1
- package/src/runtime/office/portable/portable-snapshot-docx.mjs +7 -1
- package/src/runtime/office/portable/portable-snapshot-shared.mjs +6 -1
- package/src/runtime/office/quality/assurance-rendered.mjs +9 -2
- package/src/runtime/office/quality/assurance-structure-docx.mjs +3 -1
- package/src/runtime/office/quality/design-review.mjs +1 -5
- package/src/runtime/office/quality/document-brief.mjs +1 -5
- package/src/runtime/office/quality/forced-break-pages.mjs +9 -6
- package/src/runtime/office/quality/quality-pipeline.mjs +1 -1
- package/src/runtime/session-search/session-search-db.mjs +73 -9
- package/src/runtime/session-search/session-search-ingest.mjs +110 -20
- package/src/runtime/shared/abort-race.mjs +89 -0
- package/src/runtime/shared/agent-avatar.d.mts +0 -1
- package/src/runtime/shared/agent-kind.mjs +4 -3
- package/src/runtime/shared/bot-owned-work.mjs +56 -0
- package/src/runtime/shared/bounded-download.mjs +8 -3
- package/src/runtime/shared/config.mjs +2 -13
- package/src/runtime/shared/connector-accounts.mjs +20 -10
- package/src/runtime/shared/connector-catalog.d.mts +29 -0
- package/src/runtime/shared/connector-catalog.mjs +150 -0
- package/src/runtime/shared/connector-triggers.mjs +22 -19
- package/src/runtime/shared/defaults-separation.mjs +2 -17
- package/src/runtime/shared/delegated-approval-host.mjs +103 -11
- package/src/runtime/shared/err-text.mjs +24 -15
- package/src/runtime/shared/fetch-safe-listen.d.mts +16 -0
- package/src/runtime/shared/fetch-safe-listen.mjs +50 -0
- package/src/runtime/shared/file-permissions.d.mts +0 -8
- package/src/runtime/shared/file-permissions.mjs +0 -11
- package/src/runtime/shared/git-direct.test-support.mjs +19 -0
- package/src/runtime/shared/handoff-artifacts.d.mts +2 -1
- package/src/runtime/shared/handoff-artifacts.mjs +18 -8
- package/src/runtime/shared/heartbeat-interval.d.mts +4 -0
- package/src/runtime/shared/heartbeat-interval.mjs +19 -0
- package/src/runtime/shared/idle-auto-clear-gate.mjs +126 -0
- package/src/runtime/shared/llm/cost.mjs +5 -1
- package/src/runtime/shared/llm/usage-rollup.mjs +1 -1
- package/src/runtime/shared/loopback-listener.mjs +25 -2
- package/src/runtime/shared/mixy-presence.mjs +22 -0
- package/src/runtime/shared/model-route-chain.d.mts +7 -2
- package/src/runtime/shared/model-route-chain.mjs +22 -4
- package/src/runtime/shared/open-url.mjs +10 -0
- package/src/runtime/shared/orchestration.d.mts +2 -0
- package/src/runtime/shared/pg-schema-db.mjs +27 -16
- package/src/runtime/shared/profile-config.cjs +1 -1
- package/src/runtime/shared/prompt-origin.d.mts +4 -0
- package/src/runtime/shared/prompt-origin.mjs +21 -0
- package/src/runtime/shared/provider-accounts.mjs +7 -1
- package/src/runtime/shared/provider-display-name.mjs +29 -0
- package/src/runtime/shared/provider-timeout-phase.mjs +2 -0
- package/src/runtime/shared/routine-trigger.d.mts +2 -0
- package/src/runtime/shared/routine-trigger.mjs +10 -0
- package/src/runtime/shared/sensitive-path-rules.d.mts +2 -10
- package/src/runtime/shared/sensitive-path-rules.mjs +19 -41
- package/src/runtime/shared/session-activity-signal.mjs +48 -1
- package/src/runtime/shared/session-scratch.mjs +37 -0
- package/src/runtime/shared/session-sidebar-host.d.mts +1 -1
- package/src/runtime/shared/session-sidebar-host.mjs +7 -3
- package/src/runtime/shared/session-turn-prelude.mjs +18 -0
- package/src/runtime/shared/tool-card-model/agent-surface.mjs +1 -3
- package/src/runtime/shared/tool-card-model/card-status.mjs +15 -2
- package/src/runtime/shared/tool-result-summary.mjs +2 -15
- package/src/runtime/shared/tool-surface.mjs +3 -0
- package/src/runtime/shared/tool-work-units.mjs +2 -0
- package/src/runtime/shared/turn-snapshot-store.mjs +13 -6
- package/src/runtime/shared/worktrees/contract.mjs +4 -1
- package/src/runtime/shared/worktrees/git.mjs +15 -0
- package/src/runtime/shared/worktrees/manager.mjs +87 -38
- package/src/runtime/shared/worktrees/test-support.mjs +14 -13
- package/src/runtime/terminal-bridge/client.mjs +10 -1
- package/src/runtime/visualize-bridge/client.mjs +29 -8
- package/src/runtime/visualize-bridge/tool-defs.mjs +22 -8
- package/src/runtime/visualize-bridge/tool-meta.d.mts +5 -0
- package/src/runtime/visualize-bridge/tool-meta.mjs +22 -0
- package/src/runtime/web-search/lib/fetch-pipeline.mjs +2 -2
- package/src/session-runtime/agent-home-delivery.mjs +489 -185
- package/src/session-runtime/agent-task-sessions.mjs +467 -229
- package/src/session-runtime/agent-tool-routing.mjs +8 -41
- package/src/session-runtime/boot/apis.mjs +9 -0
- package/src/session-runtime/boot/infrastructure.mjs +4 -0
- package/src/session-runtime/boot/providers.mjs +3 -0
- package/src/session-runtime/boot/tools.mjs +11 -2
- package/src/session-runtime/bot-status.mjs +12 -6
- package/src/session-runtime/bot-target.mjs +38 -0
- package/src/session-runtime/channel-config-api.mjs +6 -1
- package/src/session-runtime/config-lifecycle.mjs +6 -0
- package/src/session-runtime/connector-merge-migration.mjs +305 -0
- package/src/session-runtime/conversation-import/codex-titles.mjs +88 -0
- package/src/session-runtime/conversation-import/discovery.mjs +271 -25
- package/src/session-runtime/conversation-import/service.mjs +26 -5
- package/src/session-runtime/handoff-attachments.mjs +82 -31
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +144 -41
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -0
- package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +4 -1
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +8 -2
- package/src/session-runtime/lifecycle/cold-heir.mjs +11 -6
- package/src/session-runtime/lifecycle/inheritance.mjs +16 -3
- package/src/session-runtime/lifecycle/session-catalog.mjs +12 -2
- package/src/session-runtime/lifecycle/teardown/runtime-stops.mjs +50 -4
- package/src/session-runtime/lifecycle/teardown.mjs +23 -5
- package/src/session-runtime/mcp-glue/server-catalog.mjs +55 -3
- package/src/session-runtime/mcp-oauth-login.mjs +5 -3
- package/src/session-runtime/mixy-heartbeat.mjs +153 -33
- package/src/session-runtime/model-route/set-route.mjs +11 -2
- package/src/session-runtime/notification-bus.mjs +31 -117
- package/src/session-runtime/notification-completion-queue.mjs +54 -0
- package/src/session-runtime/notification-listeners.mjs +76 -0
- package/src/session-runtime/owned-automation-run.mjs +2 -1
- package/src/session-runtime/prewarm/channel-start.mjs +3 -7
- package/src/session-runtime/provider-catalog-cache.mjs +82 -36
- package/src/session-runtime/provider-models/catalog-load.mjs +23 -6
- package/src/session-runtime/provider-models.mjs +4 -2
- package/src/session-runtime/resource-mcp-api.mjs +143 -224
- package/src/session-runtime/resource-mcp-connector-accounts.mjs +163 -0
- package/src/session-runtime/resource-mcp-oauth-api.mjs +217 -0
- package/src/session-runtime/resource-mcp-secrets.mjs +82 -0
- package/src/session-runtime/resource-mcp-servers.mjs +78 -0
- package/src/session-runtime/resource-mcp-store.mjs +49 -0
- package/src/session-runtime/resource-recall-api.mjs +6 -1
- package/src/session-runtime/routine-owner.mjs +40 -9
- package/src/session-runtime/runtime-feature-gates.mjs +5 -1
- package/src/session-runtime/services/agent-tool/close-flow.mjs +3 -0
- package/src/session-runtime/services/agent-tool/execute.mjs +14 -9
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +20 -4
- package/src/session-runtime/services/agent-tool/model-select.mjs +48 -7
- package/src/session-runtime/services/agent-tool/render.mjs +71 -17
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +13 -4
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +1 -0
- package/src/session-runtime/services/agent-tool/tool-def.mjs +9 -9
- package/src/session-runtime/services/agent-tool/worker-index/awaiting-user-sync.mjs +51 -0
- package/src/session-runtime/services/agent-tool/worker-index/disposal.mjs +55 -0
- package/src/session-runtime/services/agent-tool/worker-index/released-store.mjs +123 -0
- package/src/session-runtime/services/agent-tool/worker-index/restart-settlement.mjs +112 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-reads.mjs +36 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +17 -4
- package/src/session-runtime/services/agent-tool/worker-index/row-writes.mjs +58 -0
- package/src/session-runtime/services/agent-tool/worker-index.mjs +41 -241
- package/src/session-runtime/services/agent-tool/worker-rows.mjs +3 -0
- package/src/session-runtime/services/channel-admin.mjs +7 -13
- package/src/session-runtime/services/channel-session-router.mjs +4 -2
- package/src/session-runtime/services/provider-admin.mjs +2 -1
- package/src/session-runtime/services/seeds.mjs +0 -28
- package/src/session-runtime/session-compaction-sync.mjs +27 -0
- package/src/session-runtime/session-create/session-options.mjs +1 -0
- package/src/session-runtime/settings-builtin-tools-api.mjs +11 -0
- package/src/session-runtime/settings-compaction-api.mjs +2 -40
- package/src/session-runtime/settings-system-api.mjs +13 -1
- package/src/session-runtime/setup-tool/agent-settings-actions.mjs +65 -0
- package/src/session-runtime/setup-tool/executor.mjs +145 -22
- package/src/session-runtime/setup-tool/extended-actions.mjs +8 -3
- package/src/session-runtime/setup-tool/session-route-actions.mjs +152 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +4 -3
- package/src/session-runtime/setup-tool/tool-defs.mjs +64 -5
- package/src/session-runtime/tool-policy/agent-profile-fold.mjs +17 -13
- package/src/session-runtime/tool-policy/policy-stage.mjs +17 -2
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +5 -1
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +15 -4
- package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -3
- package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +4 -0
- package/src/session-runtime/workspace/transitions.mjs +25 -0
- package/src/session-runtime/workspace/worktree-tool.mjs +26 -9
- package/src/standalone/channel-transport/client-registry/client-records.mjs +65 -0
- package/src/standalone/channel-transport/client-registry/client-registration.mjs +118 -0
- package/src/standalone/channel-transport/client-registry.mjs +24 -163
- package/src/standalone/channel-transport.mjs +1 -1
- package/src/standalone/daemon-channels-loader.mjs +10 -8
- package/src/standalone/daemon-session-control/list-page.mjs +72 -0
- package/src/standalone/daemon-session-control/request.mjs +51 -0
- package/src/standalone/daemon-session-control/room-host.mjs +57 -0
- package/src/standalone/daemon-session-control/route-control.mjs +48 -0
- package/src/standalone/daemon-session-control/send-turn.mjs +60 -0
- package/src/standalone/daemon-session-control/worktree-control.mjs +40 -0
- package/src/standalone/daemon-session-control.mjs +142 -190
- package/src/standalone/daemon.mjs +26 -3
- package/src/standalone/session-client.mjs +7 -3
- package/src/standalone/session-protocol.mjs +5 -0
- package/src/standalone/session-service/agent-tree/agent-child.mjs +1 -0
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +16 -12
- package/src/standalone/session-service/quota-resume.mjs +3 -0
- package/src/standalone/session-service/retention/busy.mjs +65 -1
- package/src/standalone/session-service/session-calls/session-action.mjs +30 -2
- package/src/standalone/session-service/session-calls/session-views.mjs +8 -0
- package/src/standalone/session-tool-output.mjs +15 -7
- package/src/standalone/session-transport/client-registry/client-grace.mjs +12 -9
- package/src/tui/app/app-view/floating-panel.jsx +7 -4
- package/src/tui/app/model-options.mjs +3 -28
- package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +1 -3
- package/src/tui/app/model-picker/route-selection.mjs +5 -6
- package/src/tui/app/provider-setup/oauth-actions.mjs +38 -20
- package/src/tui/app/provider-setup/provider-items.mjs +8 -2
- package/src/tui/app/provider-setup-picker.mjs +9 -5
- package/src/tui/components/QuestionPanel.jsx +13 -4
- package/src/tui/dist/index.mjs +133 -92
- package/src/tui/session/agent-job-feed/model-notification.mjs +3 -0
- package/src/tui/session/initial-state.mjs +3 -0
- package/src/tui/session/notice-surface.mjs +7 -1
- package/src/tui/session/queue-helpers.mjs +3 -42
- package/src/tui/session/session-api/routes-agent-definitions.mjs +14 -2
- package/src/tui/session/session-api/routes-write.mjs +5 -1
- package/src/tui/session/session-api/routes.mjs +1 -0
- package/src/tui/session/session-api/settings.mjs +17 -1
- package/src/tui/session/session-flow/auto-clear.mjs +4 -33
- package/src/tui/session/session-flow/drain-closed-queue.mjs +38 -0
- package/src/tui/session/session-flow/drain-enqueue.mjs +86 -0
- package/src/tui/session/session-flow/drain-retry.mjs +35 -0
- package/src/tui/session/session-flow/drain.mjs +118 -149
- package/src/tui/session/session-flow/queue/entry-shape.mjs +5 -0
- package/src/tui/session/session-flow/queue/take-entries.mjs +16 -2
- package/src/tui/session/tool-approval-delegation.mjs +64 -0
- package/src/tui/session/tool-approval-request.mjs +39 -0
- package/src/tui/session/tool-approval-settle.mjs +62 -0
- package/src/tui/session/tool-approval.mjs +69 -115
- package/src/tui/session/tui-steering-persist.mjs +8 -1
- package/src/tui/session/turn-stream.mjs +19 -2
- package/src/tui/session/turn.mjs +1 -0
- package/src/ui/statusline-agents.mjs +1 -3
- package/src/vendor/statusline/bin/statusline-route.mjs +1 -219
- package/src/vendor/statusline/src/gateway/route-meta.mjs +35 -13
- package/scripts/code-graph-description-contract.mjs +0 -188
- package/src/runtime/channels/lib/owned-runtime/ownership-refresh.mjs +0 -36
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ACCOUNT_PROVIDERS,
|
|
3
|
+
MAX_ACCOUNTS,
|
|
3
4
|
accountScopedSessionId,
|
|
4
5
|
readProviderAccountPool,
|
|
5
6
|
chooseProviderAccount,
|
|
@@ -243,6 +244,17 @@ function sessionAccountId(providerName, key, messages, options) {
|
|
|
243
244
|
return null;
|
|
244
245
|
}
|
|
245
246
|
|
|
247
|
+
/** The account a send of `model` for `sessionId` would try first right now —
|
|
248
|
+
* the session's binding and the choice poolSend makes for its first attempt
|
|
249
|
+
* — or null when the provider has no roster account or none is eligible. */
|
|
250
|
+
export function plannedAccountId(providerName, { sessionId = null, messages = [], providerState, model = '' } = {}) {
|
|
251
|
+
const pool = readProviderAccountPool(providerName);
|
|
252
|
+
if (!pool.accounts.length) return null;
|
|
253
|
+
const sessionKey = sessionId ? `${providerName}:${sessionId}` : null;
|
|
254
|
+
const boundId = sessionAccountId(providerName, sessionKey, messages, { providerState });
|
|
255
|
+
return chooseProviderAccount(pool, new Set(), Date.now(), model, { sessionAccountId: boundId })?.id || null;
|
|
256
|
+
}
|
|
257
|
+
|
|
246
258
|
// Stamp the serving account on the answer, independent of transport state,
|
|
247
259
|
// with the account the session stays bound to (`bindingId`).
|
|
248
260
|
function recordServingAccount(providerName, result, id, bindingId) {
|
|
@@ -358,110 +370,182 @@ async function accountQuotaExhausted(providerName, row, model, error, account) {
|
|
|
358
370
|
evidence = providerAccountExhausted(providerAccountWithBlocks(entry), Date.now(), model, options);
|
|
359
371
|
exhausted = exhausted || evidence || providerAccountExhausted(entry, Date.now(), model, options);
|
|
360
372
|
}
|
|
361
|
-
|
|
373
|
+
const reason = evidence ? 'quota' : 'unknown';
|
|
374
|
+
return { exhausted, delay, evidence, ...(exhausted ? blockUntil(evidence, reason) : {}) };
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Record an exhausted verdict on the roster. An account-level block holds
|
|
378
|
+
// every model, so it carries no model or limit scope.
|
|
379
|
+
function blockRefusedAccount(providerName, accountId, model, error, verdict) {
|
|
380
|
+
const { evidence, until, source, reset, accountBlocked } = verdict;
|
|
381
|
+
return blockProviderAccount(providerName, accountId, until, accountBlocked ? '' : model, source, {
|
|
382
|
+
quota: evidence === true,
|
|
383
|
+
reset: reset === true,
|
|
384
|
+
limit: accountBlocked ? '' : quotaLimitOf(error),
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* A refusal `error` that account `accountId` gave outside the pool's send (a
|
|
390
|
+
* cache warm, which never rotates): judged and recorded on the roster exactly
|
|
391
|
+
* as the send would, with `instance` as that account's provider. Resolves
|
|
392
|
+
* whether the account was blocked.
|
|
393
|
+
*/
|
|
394
|
+
export async function recordAccountRefusal(providerName, accountId, model, error, instance) {
|
|
395
|
+
const row = readProviderAccountPool(providerName).accounts.find((entry) => entry.id === accountId);
|
|
396
|
+
if (!row) return false;
|
|
397
|
+
const verdict = await accountQuotaExhausted(providerName, row, model, error, () => instance);
|
|
398
|
+
if (!verdict.exhausted) return false;
|
|
399
|
+
await blockRefusedAccount(providerName, row.id, model, error, verdict);
|
|
400
|
+
return true;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Whether every account in `ids` (default: the roster) is exhausted with quota
|
|
404
|
+
// evidence: observed in this send (`evidenced`), or a full window.
|
|
405
|
+
function rosterExhaustion(providerName, model, evidenced, ids) {
|
|
406
|
+
const pool = readProviderAccountPool(providerName);
|
|
407
|
+
// Manual policy: the eligible set is the selected account alone.
|
|
408
|
+
const scope = ids || (providerAccountPolicy(pool) === 'manual' ? [pool.selectedId] : null);
|
|
409
|
+
const rows = scope ? pool.accounts.filter((entry) => scope.includes(entry.id)) : pool.accounts;
|
|
410
|
+
const opts = { useCredits: pool.useCredits === true };
|
|
411
|
+
const now = Date.now();
|
|
412
|
+
const all =
|
|
413
|
+
rows.length > 0 &&
|
|
414
|
+
rows.every((entry) =>
|
|
415
|
+
providerAccountExhausted(
|
|
416
|
+
evidenced.has(entry.id) ? entry : providerAccountWithBlocks(entry, (block) => block.blockedQuota === true),
|
|
417
|
+
now,
|
|
418
|
+
model,
|
|
419
|
+
opts
|
|
420
|
+
)
|
|
421
|
+
);
|
|
422
|
+
return { rows, opts, now, all };
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// Mark `error` only when every account in `ids` is exhausted with quota
|
|
426
|
+
// evidence (`rosterExhaustion`). Without an error of its own, the send reports
|
|
427
|
+
// quota exhaustion only on that evidence, and a rate-limit cooldown otherwise.
|
|
428
|
+
function exhaustedSendError(providerName, model, evidenced, error, ids) {
|
|
429
|
+
const { rows, opts, now, all } = rosterExhaustion(providerName, model, evidenced, ids);
|
|
430
|
+
if (all) {
|
|
431
|
+
return quotaExhausted(error || accountsExhaustedError(opts.useCredits), providerName, model, rows, opts);
|
|
432
|
+
}
|
|
433
|
+
return error || accountsCoolingDownError(rows, now, model);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// The provider's bound on the time one send spends waiting for cooldowns.
|
|
437
|
+
function cooldownWaitBoundMs(providerName, account, ids) {
|
|
438
|
+
const id = ids?.[0] || readProviderAccountPool(providerName).selectedId || 'default';
|
|
439
|
+
return finiteMs(cooldownPolicyOf(account(id))?.waitForCooldownMs, 0);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// A cooldown-only eligible set whose earliest cooldown ends inside the
|
|
443
|
+
// remaining wait budget is waited out; otherwise the send fails as before.
|
|
444
|
+
// `ledger` is the send's own record of the roster (see `poolSend`).
|
|
445
|
+
async function waitOutCooldownOrThrow(request, ledger, error, ids) {
|
|
446
|
+
const { providerName, model, account, options } = request;
|
|
447
|
+
const { rows, now, all } = rosterExhaustion(providerName, model, ledger.evidenced, ids);
|
|
448
|
+
const bound = cooldownWaitBoundMs(providerName, account, ids);
|
|
449
|
+
// Persisting a short cooldown can outlast its deadline. Release only
|
|
450
|
+
// attempts cooled by this send, and only under an enabled wait policy.
|
|
451
|
+
const expired = bound > 0 && rows.some((row) => ledger.cooled.has(row.id) && !(coolingUntil(row, model) > now));
|
|
452
|
+
let wait = null;
|
|
453
|
+
if (!all) wait = expired ? 0 : earliestCooldownMs(rows, now, model);
|
|
454
|
+
if (wait == null || ledger.waitedMs + wait > bound) {
|
|
455
|
+
throw exhaustedSendError(providerName, model, ledger.evidenced, error, ids);
|
|
456
|
+
}
|
|
457
|
+
options.onStageChange?.('reconnecting', {
|
|
458
|
+
message: `Rate limited — every account is cooling down; retrying in ${Math.ceil(wait / 1000)}s`,
|
|
459
|
+
reason: 'rate_limited',
|
|
460
|
+
waitMs: wait,
|
|
461
|
+
retryAt: now + wait,
|
|
462
|
+
});
|
|
463
|
+
// A zero-duration sleep does not check cancellation, including on the
|
|
464
|
+
// final allowed send when no next loop iteration will check it either.
|
|
465
|
+
options.signal?.throwIfAborted();
|
|
466
|
+
await sleepWithAbort(wait, options.signal);
|
|
467
|
+
ledger.waitedMs += wait;
|
|
468
|
+
const lifted = Date.now();
|
|
469
|
+
for (const row of readProviderAccountPool(providerName).accounts) {
|
|
470
|
+
if (ledger.cooled.has(row.id) && !(coolingUntil(row, model) > lifted)) {
|
|
471
|
+
ledger.cooled.delete(row.id);
|
|
472
|
+
ledger.attempted.delete(row.id);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// No roster: with credit use off, a stored reading showing the plan's window
|
|
478
|
+
// spent refuses before the implicit account sends.
|
|
479
|
+
function throwIfPlanQuotaSpent(providerName, pool, model) {
|
|
480
|
+
if (pool.useCredits !== true) {
|
|
481
|
+
const stored = readCachedOAuthUsageSnapshot({ provider: providerName, model: '' });
|
|
482
|
+
// A snapshot cached before per-model gating is stale evidence.
|
|
483
|
+
if (stored?.quotaWindows?.length && !staleQuotaWindows(providerName, stored.quotaWindows)) {
|
|
484
|
+
const row = { usage: { windows: stored.quotaWindows, checkedAt: stored.cachedAt } };
|
|
485
|
+
if (providerAccountExhausted(row, Date.now(), model)) {
|
|
486
|
+
throw quotaExhausted(accountsExhaustedError(false), providerName, model, [row]);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Headroom policy: a session's first pick, or its move off its account on a
|
|
493
|
+
// limit, becomes the selection; continuing on its account does not, so
|
|
494
|
+
// concurrent sessions never flip the selection back and forth. A move forced
|
|
495
|
+
// by a model-scoped limit serves this request only (`scoped`). Stamps the
|
|
496
|
+
// serving account on `result` and resolves whether the selection may commit.
|
|
497
|
+
function bindServedAccount(providerName, result, rowId, model, binding) {
|
|
498
|
+
const { policy, boundId, sessionKey, switched, refusalScoped } = binding;
|
|
499
|
+
const leftBound = Boolean(boundId) && rowId !== boundId;
|
|
500
|
+
const scoped = switched
|
|
501
|
+
? refusalScoped
|
|
502
|
+
: policy === 'headroom' && leftBound && accountExhaustedForModelOnly(providerName, boundId, model);
|
|
503
|
+
recordServingAccount(providerName, result, rowId, scoped && boundId ? boundId : rowId);
|
|
504
|
+
if (sessionKey && policy === 'headroom' && !scoped) rememberSessionAccount(sessionKey, rowId);
|
|
505
|
+
return { scoped, commit: policy !== 'headroom' || !boundId || leftBound };
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// A failed attempt is never re-issued once output reached the caller or the
|
|
509
|
+
// attempt was unsafe to retry (`unsafe`, judged by the caller and read only
|
|
510
|
+
// when nothing was emitted).
|
|
511
|
+
function attemptUnretryable(bound, error, unsafe) {
|
|
512
|
+
return Boolean(bound.emitted() || unsafe() || error.liveTextEmitted || error.emittedToolCall);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
function rotationReason(evidence, accountBlocked) {
|
|
516
|
+
if (evidence) return 'Quota exhausted';
|
|
517
|
+
if (accountBlocked) return 'Account blocked';
|
|
518
|
+
return 'Rate limited (cooldown)';
|
|
362
519
|
}
|
|
363
520
|
|
|
364
521
|
// The pool's send: walks the eligible accounts until one answers, blocking
|
|
365
522
|
// the ones whose quota window is exhausted along the way.
|
|
366
523
|
function poolSend(providerName, account) {
|
|
367
524
|
return async function send(messages, model, tools, options = {}) {
|
|
368
|
-
const
|
|
525
|
+
const request = { providerName, model, account, options };
|
|
526
|
+
// This send's record of the roster: the accounts it tried, those it found
|
|
527
|
+
// exhausted with quota evidence, those it blocked on a rate-limit
|
|
528
|
+
// cooldown, and the time it spent waiting for cooldowns.
|
|
529
|
+
const ledger = { attempted: new Set(), evidenced: new Set(), cooled: new Set(), waitedMs: 0 };
|
|
369
530
|
let lastError;
|
|
370
531
|
let probed = false;
|
|
371
|
-
|
|
532
|
+
let sends = 0;
|
|
372
533
|
const sessionKey = options.sessionId ? `${providerName}:${options.sessionId}` : null;
|
|
373
534
|
const boundId = sessionAccountId(providerName, sessionKey, messages, options);
|
|
374
535
|
// Whether this send already left an account, and whether the latest quota
|
|
375
536
|
// refusal held only for this model's family.
|
|
376
537
|
let switched = false;
|
|
377
538
|
let refusalScoped = false;
|
|
378
|
-
//
|
|
379
|
-
|
|
380
|
-
// Without an error of its own, the send reports quota exhaustion only on
|
|
381
|
-
// that evidence, and a rate-limit cooldown otherwise.
|
|
382
|
-
const exhaustion = (ids) => {
|
|
383
|
-
const pool = readProviderAccountPool(providerName);
|
|
384
|
-
// Manual policy: the eligible set is the selected account alone.
|
|
385
|
-
const scope = ids || (providerAccountPolicy(pool) === 'manual' ? [pool.selectedId] : null);
|
|
386
|
-
const rows = scope ? pool.accounts.filter((entry) => scope.includes(entry.id)) : pool.accounts;
|
|
387
|
-
const opts = { useCredits: pool.useCredits === true };
|
|
388
|
-
const now = Date.now();
|
|
389
|
-
const all =
|
|
390
|
-
rows.length > 0 &&
|
|
391
|
-
rows.every((entry) =>
|
|
392
|
-
providerAccountExhausted(
|
|
393
|
-
evidenced.has(entry.id) ? entry : providerAccountWithBlocks(entry, (block) => block.blockedQuota === true),
|
|
394
|
-
now,
|
|
395
|
-
model,
|
|
396
|
-
opts
|
|
397
|
-
)
|
|
398
|
-
);
|
|
399
|
-
return { rows, opts, now, all };
|
|
400
|
-
};
|
|
401
|
-
const markExhausted = (error, ids) => {
|
|
402
|
-
const { rows, opts, now, all } = exhaustion(ids);
|
|
403
|
-
if (all) {
|
|
404
|
-
return quotaExhausted(error || accountsExhaustedError(opts.useCredits), providerName, model, rows, opts);
|
|
405
|
-
}
|
|
406
|
-
return error || accountsCoolingDownError(rows, now, model);
|
|
407
|
-
};
|
|
408
|
-
// Accounts this send blocked on a rate-limit cooldown, the time it spent
|
|
409
|
-
// waiting for cooldowns, and the provider's wait bound.
|
|
410
|
-
const cooled = new Set();
|
|
411
|
-
let waitedMs = 0;
|
|
412
|
-
let sends = 0;
|
|
413
|
-
const waitBoundMs = (ids) => {
|
|
414
|
-
const id = ids?.[0] || readProviderAccountPool(providerName).selectedId || 'default';
|
|
415
|
-
return finiteMs(cooldownPolicyOf(account(id))?.waitForCooldownMs, 0);
|
|
416
|
-
};
|
|
417
|
-
// A cooldown-only eligible set whose earliest cooldown ends inside the
|
|
418
|
-
// remaining wait budget is waited out; otherwise the send fails as before.
|
|
419
|
-
const waitOrThrow = async (error, ids) => {
|
|
420
|
-
const { rows, now, all } = exhaustion(ids);
|
|
421
|
-
const bound = waitBoundMs(ids);
|
|
422
|
-
// Persisting a short cooldown can outlast its deadline. Release only
|
|
423
|
-
// attempts cooled by this send, and only under an enabled wait policy.
|
|
424
|
-
const expired = bound > 0 && rows.some((row) => cooled.has(row.id) && !(coolingUntil(row, model) > now));
|
|
425
|
-
let wait = null;
|
|
426
|
-
if (!all) wait = expired ? 0 : earliestCooldownMs(rows, now, model);
|
|
427
|
-
if (wait == null || waitedMs + wait > bound) throw markExhausted(error, ids);
|
|
428
|
-
options.onStageChange?.('reconnecting', {
|
|
429
|
-
message: `Rate limited — every account is cooling down; retrying in ${Math.ceil(wait / 1000)}s`,
|
|
430
|
-
reason: 'rate_limited',
|
|
431
|
-
waitMs: wait,
|
|
432
|
-
retryAt: now + wait,
|
|
433
|
-
});
|
|
434
|
-
// A zero-duration sleep does not check cancellation, including on the
|
|
435
|
-
// final allowed send when no next loop iteration will check it either.
|
|
436
|
-
options.signal?.throwIfAborted();
|
|
437
|
-
await sleepWithAbort(wait, options.signal);
|
|
438
|
-
waitedMs += wait;
|
|
439
|
-
const lifted = Date.now();
|
|
440
|
-
for (const row of readProviderAccountPool(providerName).accounts) {
|
|
441
|
-
if (cooled.has(row.id) && !(coolingUntil(row, model) > lifted)) {
|
|
442
|
-
cooled.delete(row.id);
|
|
443
|
-
attempted.delete(row.id);
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
};
|
|
447
|
-
while (attempted.size < 20 && sends < 20) {
|
|
539
|
+
// One try per connectable account at most (provider-accounts.mjs MAX_ACCOUNTS).
|
|
540
|
+
while (ledger.attempted.size < MAX_ACCOUNTS && sends < MAX_ACCOUNTS) {
|
|
448
541
|
options.signal?.throwIfAborted();
|
|
449
542
|
const pool = readProviderAccountPool(providerName);
|
|
450
543
|
if (!pool.accounts.length) {
|
|
451
|
-
|
|
452
|
-
const stored = readCachedOAuthUsageSnapshot({ provider: providerName, model: '' });
|
|
453
|
-
// A snapshot cached before per-model gating is stale evidence.
|
|
454
|
-
if (stored?.quotaWindows?.length && !staleQuotaWindows(providerName, stored.quotaWindows)) {
|
|
455
|
-
const row = { usage: { windows: stored.quotaWindows, checkedAt: stored.cachedAt } };
|
|
456
|
-
if (providerAccountExhausted(row, Date.now(), model)) {
|
|
457
|
-
throw quotaExhausted(accountsExhaustedError(false), providerName, model, [row]);
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
}
|
|
544
|
+
throwIfPlanQuotaSpent(providerName, pool, model);
|
|
461
545
|
return account('default').send(messages, model, tools, options);
|
|
462
546
|
}
|
|
463
547
|
const policy = providerAccountPolicy(pool);
|
|
464
|
-
const row = chooseProviderAccount(pool, attempted, Date.now(), model, { sessionAccountId: boundId });
|
|
548
|
+
const row = chooseProviderAccount(pool, ledger.attempted, Date.now(), model, { sessionAccountId: boundId });
|
|
465
549
|
if (!row) {
|
|
466
550
|
// Once per send: a refusal built on a stale meter must not outlive the
|
|
467
551
|
// meter. Re-measuring can only widen the roster, so it is tried before
|
|
@@ -470,26 +554,22 @@ function poolSend(providerName, account) {
|
|
|
470
554
|
probed = true;
|
|
471
555
|
if (await probeRefusedAccounts(providerName, pool, model, account)) continue;
|
|
472
556
|
}
|
|
473
|
-
await
|
|
557
|
+
await waitOutCooldownOrThrow(request, ledger, lastError);
|
|
474
558
|
continue;
|
|
475
559
|
}
|
|
476
|
-
attempted.add(row.id);
|
|
560
|
+
ledger.attempted.add(row.id);
|
|
477
561
|
sends += 1;
|
|
478
562
|
const bound = boundAccountSend(providerName, row, messages, options);
|
|
479
563
|
try {
|
|
480
564
|
const result = await account(row.id).send(bound.history, model, tools, bound.opts);
|
|
481
565
|
quotaStrikes.delete(`${providerName}:${row.id}`);
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
: policy === 'headroom' && leftBound && accountExhaustedForModelOnly(providerName, boundId, model);
|
|
490
|
-
recordServingAccount(providerName, result, row.id, scoped && boundId ? boundId : row.id);
|
|
491
|
-
if (sessionKey && policy === 'headroom' && !scoped) rememberSessionAccount(sessionKey, row.id);
|
|
492
|
-
const commit = policy !== 'headroom' || !boundId || leftBound;
|
|
566
|
+
const { scoped, commit } = bindServedAccount(providerName, result, row.id, model, {
|
|
567
|
+
policy,
|
|
568
|
+
boundId,
|
|
569
|
+
sessionKey,
|
|
570
|
+
switched,
|
|
571
|
+
refusalScoped,
|
|
572
|
+
});
|
|
493
573
|
if (commit && (await commitFallbackAccount(providerName, pool, row, model, scoped, policy))) {
|
|
494
574
|
// Publish only a committed selection, never a speculative retry or
|
|
495
575
|
// one superseded by a manual switch. The existing progress channel
|
|
@@ -508,62 +588,41 @@ function poolSend(providerName, account) {
|
|
|
508
588
|
} catch (error) {
|
|
509
589
|
if (options.signal?.aborted) throw error;
|
|
510
590
|
if (error?.reauthRequired === true) {
|
|
511
|
-
if (
|
|
512
|
-
policy === 'manual' ||
|
|
513
|
-
bound.emitted() ||
|
|
514
|
-
error.unsafeToRetry ||
|
|
515
|
-
error.liveTextEmitted ||
|
|
516
|
-
error.emittedToolCall
|
|
517
|
-
)
|
|
518
|
-
throw error;
|
|
591
|
+
if (policy === 'manual' || attemptUnretryable(bound, error, () => error.unsafeToRetry)) throw error;
|
|
519
592
|
lastError = error;
|
|
520
593
|
switched = true;
|
|
521
594
|
refusalScoped = false;
|
|
522
595
|
options.onStageChange?.('reconnecting', { message: 'Sign-in expired — switching to the next account' });
|
|
523
596
|
continue;
|
|
524
597
|
}
|
|
525
|
-
const
|
|
526
|
-
|
|
527
|
-
row,
|
|
528
|
-
model,
|
|
529
|
-
error,
|
|
530
|
-
account
|
|
531
|
-
);
|
|
598
|
+
const verdict = await accountQuotaExhausted(providerName, row, model, error, account);
|
|
599
|
+
const { exhausted, evidence, accountBlocked } = verdict;
|
|
532
600
|
if (options.signal?.aborted || !exhausted) throw error;
|
|
533
|
-
if (evidence) evidenced.add(row.id);
|
|
534
|
-
else cooled.add(row.id);
|
|
535
|
-
|
|
536
|
-
// limit scope.
|
|
537
|
-
await blockProviderAccount(providerName, row.id, until, accountBlocked ? '' : model, source, {
|
|
538
|
-
quota: evidence === true,
|
|
539
|
-
reset: reset === true,
|
|
540
|
-
limit: accountBlocked ? '' : quotaLimitOf(error),
|
|
541
|
-
});
|
|
601
|
+
if (evidence) ledger.evidenced.add(row.id);
|
|
602
|
+
else ledger.cooled.add(row.id);
|
|
603
|
+
await blockRefusedAccount(providerName, row.id, model, error, verdict);
|
|
542
604
|
// An account block is unsafe to re-issue on THAT account only; with no
|
|
543
605
|
// output emitted, the next account may serve the same request.
|
|
544
|
-
if (
|
|
545
|
-
bound.emitted() ||
|
|
546
|
-
(error.unsafeToRetry && accountBlocked !== true) ||
|
|
547
|
-
error.liveTextEmitted ||
|
|
548
|
-
error.emittedToolCall
|
|
549
|
-
)
|
|
550
|
-
throw error;
|
|
606
|
+
if (attemptUnretryable(bound, error, () => error.unsafeToRetry && accountBlocked !== true)) throw error;
|
|
551
607
|
// Manual policy: the eligible set is the selected account alone.
|
|
552
608
|
if (policy === 'manual') {
|
|
553
|
-
await
|
|
609
|
+
await waitOutCooldownOrThrow(request, ledger, error, [row.id]);
|
|
554
610
|
lastError = error;
|
|
555
611
|
continue;
|
|
556
612
|
}
|
|
557
613
|
lastError = error;
|
|
558
614
|
switched = true;
|
|
559
615
|
refusalScoped = accountExhaustedForModelOnly(providerName, row.id, model);
|
|
560
|
-
|
|
561
|
-
if (evidence) reason = 'Quota exhausted';
|
|
562
|
-
else if (accountBlocked) reason = 'Account blocked';
|
|
616
|
+
const reason = rotationReason(evidence, accountBlocked);
|
|
563
617
|
options.onStageChange?.('reconnecting', { message: `${reason} — switching to the next account` });
|
|
564
618
|
}
|
|
565
619
|
}
|
|
566
|
-
throw
|
|
620
|
+
throw exhaustedSendError(
|
|
621
|
+
providerName,
|
|
622
|
+
model,
|
|
623
|
+
ledger.evidenced,
|
|
624
|
+
lastError || new Error('Provider account attempts exhausted.')
|
|
625
|
+
);
|
|
567
626
|
};
|
|
568
627
|
}
|
|
569
628
|
|
|
@@ -264,7 +264,9 @@ export class ProviderAdmissionScheduler {
|
|
|
264
264
|
running.parentAbort = () => {
|
|
265
265
|
try {
|
|
266
266
|
controller.abort(item.signal.reason);
|
|
267
|
-
} catch {
|
|
267
|
+
} catch {
|
|
268
|
+
// the controller may already be aborted
|
|
269
|
+
}
|
|
268
270
|
};
|
|
269
271
|
item.signal.addEventListener('abort', running.parentAbort, { once: true });
|
|
270
272
|
}
|
|
@@ -301,7 +303,9 @@ export class ProviderAdmissionScheduler {
|
|
|
301
303
|
if (running.parentAbort && running.parentSignal) {
|
|
302
304
|
try {
|
|
303
305
|
running.parentSignal.removeEventListener('abort', running.parentAbort);
|
|
304
|
-
} catch {
|
|
306
|
+
} catch {
|
|
307
|
+
// the abort listener may already be gone
|
|
308
|
+
}
|
|
305
309
|
}
|
|
306
310
|
this.running.delete(running);
|
|
307
311
|
lane.active -= 1;
|
|
@@ -312,6 +316,32 @@ export class ProviderAdmissionScheduler {
|
|
|
312
316
|
if (this._canDeleteLane(lane)) this._deleteLane(key, lane);
|
|
313
317
|
}
|
|
314
318
|
|
|
319
|
+
/**
|
|
320
|
+
* Why a request that must not wait (a cache warm) cannot start on lane
|
|
321
|
+
* `key` now, or null: the lane's rate-limit cooldown, or a lane throttled
|
|
322
|
+
* after a 429 that would queue it.
|
|
323
|
+
*/
|
|
324
|
+
immediateBlock(key) {
|
|
325
|
+
if (this.closedReason) return 'provider scheduler closed';
|
|
326
|
+
const lane = this.lanes.get(String(key || ''));
|
|
327
|
+
if (!lane) return null;
|
|
328
|
+
if (lane.adaptive && lane.cooldownUntil > this.now()) return 'rate-limit cooldown';
|
|
329
|
+
if (lane.queue.length > 0 || lane.active >= lane.limit) return 'account throttled';
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/** Record a rate limit a request outside `run` (a cache warm) received on
|
|
334
|
+
* lane `key`, into the same cooldown state (and broadcast) as a send's. */
|
|
335
|
+
recordRateLimit(key, error) {
|
|
336
|
+
const laneKey = String(key || '');
|
|
337
|
+
if (!laneKey || this.closedReason) return false;
|
|
338
|
+
const lane = this.lanes.get(laneKey) || createAdmissionLane(laneKey, this.concurrency);
|
|
339
|
+
this.lanes.set(laneKey, lane);
|
|
340
|
+
const recorded = this._recordFailure(laneKey, lane, error);
|
|
341
|
+
if (this._canDeleteLane(lane)) this._deleteLane(laneKey, lane);
|
|
342
|
+
return recorded;
|
|
343
|
+
}
|
|
344
|
+
|
|
315
345
|
snapshot() {
|
|
316
346
|
const now = this.now();
|
|
317
347
|
return {
|
|
@@ -428,7 +458,9 @@ export class ProviderAdmissionScheduler {
|
|
|
428
458
|
if (item.onAbort && item.signal) {
|
|
429
459
|
try {
|
|
430
460
|
item.signal.removeEventListener('abort', item.onAbort);
|
|
431
|
-
} catch {
|
|
461
|
+
} catch {
|
|
462
|
+
// the abort listener may already be gone
|
|
463
|
+
}
|
|
432
464
|
item.onAbort = null;
|
|
433
465
|
}
|
|
434
466
|
}
|
|
@@ -453,7 +485,9 @@ export class ProviderAdmissionScheduler {
|
|
|
453
485
|
for (const running of this.running) {
|
|
454
486
|
try {
|
|
455
487
|
running.controller.abort(this.closedReason);
|
|
456
|
-
} catch {
|
|
488
|
+
} catch {
|
|
489
|
+
// the controller may already be aborted
|
|
490
|
+
}
|
|
457
491
|
}
|
|
458
492
|
}
|
|
459
493
|
}
|
|
@@ -476,7 +510,7 @@ function digest(value) {
|
|
|
476
510
|
.digest('hex');
|
|
477
511
|
}
|
|
478
512
|
|
|
479
|
-
function providerAdmissionKey(providerName, provider) {
|
|
513
|
+
export function providerAdmissionKey(providerName, provider) {
|
|
480
514
|
const name = String(providerName || provider?.name || 'provider');
|
|
481
515
|
const stableAnthropicOAuthPath =
|
|
482
516
|
name.toLowerCase() === 'anthropic-oauth'
|
|
@@ -556,7 +590,9 @@ export function wrapProviderAdmission(provider, providerName, scheduler = provid
|
|
|
556
590
|
// time. Provider-local retry remains the sole retry owner.
|
|
557
591
|
try {
|
|
558
592
|
opts.onStageChange?.('requesting');
|
|
559
|
-
} catch {
|
|
593
|
+
} catch {
|
|
594
|
+
// the stage observer is advisory
|
|
595
|
+
}
|
|
560
596
|
const admittedOpts = {
|
|
561
597
|
...opts,
|
|
562
598
|
signal: admissionSignal,
|
|
@@ -52,7 +52,7 @@ export function createAnthropicApiRecovery({
|
|
|
52
52
|
: PROVIDER_NONSTREAM_TOTAL_TIMEOUT_MS;
|
|
53
53
|
const lifetime = createTimeoutSignal(totalSignal, timeoutMs, `${label} Anthropic non-streaming fallback`);
|
|
54
54
|
try {
|
|
55
|
-
const message = await transport.requestNonStreamingMessage(nonStreamingParams, lifetime.signal);
|
|
55
|
+
const message = await transport.requestNonStreamingMessage(nonStreamingParams, lifetime.signal, timeoutMs);
|
|
56
56
|
return buildTurnResult(normalizeAnthropicNonStreamingResponse(message, useModel));
|
|
57
57
|
} catch (error) {
|
|
58
58
|
if (error instanceof AnthropicFallbackTriggeredError || totalSignal?.aborted) throw error;
|
|
@@ -10,7 +10,11 @@
|
|
|
10
10
|
* anthropic-turn-result.mjs); nothing here touches the socket.
|
|
11
11
|
*/
|
|
12
12
|
import { prepareAnthropicImages } from './lib/anthropic-image-input.mjs';
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
anthropicPrefixFingerprint,
|
|
15
|
+
anthropicPrefixSessionId,
|
|
16
|
+
recordAnthropicPrefix,
|
|
17
|
+
} from './lib/anthropic-prefix-trace.mjs';
|
|
14
18
|
import { buildAnthropicBetaHeaders, supportsAnthropicFastMode } from './anthropic-betas.mjs';
|
|
15
19
|
import { applyAnthropicServerFallback } from './anthropic-server-fallback.mjs';
|
|
16
20
|
import { fastModeAvailable } from './anthropic-fast-mode.mjs';
|
|
@@ -93,7 +97,7 @@ export async function buildAnthropicApiRequest({
|
|
|
93
97
|
// Tools are resolved BEFORE the messages: the lowering needs the final
|
|
94
98
|
// tool list to drop tool_reference blocks whose tool no longer ships
|
|
95
99
|
// in this request (otherwise the API rejects the whole turn).
|
|
96
|
-
const requestTools = requestAnthropicTools(tools, chatMsgs, opts, name);
|
|
100
|
+
const requestTools = requestAnthropicTools(tools, chatMsgs, opts, name, config);
|
|
97
101
|
// Message-tail cache budget (4-BP layout + ANTHROPIC_MSG_SLOTS) is
|
|
98
102
|
// shared with anthropic-oauth — see resolveAnthropicMessageCacheSlots.
|
|
99
103
|
const messageCacheSlots = resolveAnthropicMessageCacheSlots(systemBlocks, ttls, { tools: requestTools });
|
|
@@ -183,7 +187,7 @@ export async function buildAnthropicApiRequest({
|
|
|
183
187
|
// (once) → mark → prepare image bytes → send.
|
|
184
188
|
params.stream = true;
|
|
185
189
|
// Diagnostic: per-block prefix hashes of exactly what is sent.
|
|
186
|
-
recordAnthropicPrefix(opts
|
|
190
|
+
recordAnthropicPrefix(anthropicPrefixSessionId(opts), anthropicPrefixFingerprint(params));
|
|
187
191
|
|
|
188
192
|
const requestHeaders = requestHeadersFor(params, {
|
|
189
193
|
config,
|
|
@@ -215,12 +215,18 @@ export function createAnthropicApiTransport({
|
|
|
215
215
|
}
|
|
216
216
|
};
|
|
217
217
|
|
|
218
|
-
|
|
218
|
+
// `timeoutMs` is the replay's own lifetime, handed to the SDK as the request
|
|
219
|
+
// timeout: without an explicit one the SDK refuses any stream:false body
|
|
220
|
+
// whose max_tokens it estimates past 10 minutes before sending it.
|
|
221
|
+
const requestNonStreamingMessage = (nonStreamingParams, signal, timeoutMs) =>
|
|
219
222
|
withRetry(
|
|
220
223
|
withBodyRecovery(nonStreamingParams, async ({ signal: attemptSignal }) => {
|
|
221
224
|
noteRequestServiceTier(nonStreamingParams.speed);
|
|
222
225
|
try {
|
|
223
|
-
return await client.messages.create(nonStreamingParams,
|
|
226
|
+
return await client.messages.create(nonStreamingParams, {
|
|
227
|
+
...requestOptions(attemptSignal),
|
|
228
|
+
timeout: timeoutMs,
|
|
229
|
+
});
|
|
224
230
|
} catch (err) {
|
|
225
231
|
throw annotateHttpFailure(err);
|
|
226
232
|
}
|