mixdog 1.2.3 → 1.2.4
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/package.json +1 -1
- package/scripts/gate-local.mjs +6 -4
- package/scripts/lib/gate-scheduler.mjs +29 -11
- package/scripts/probe-provider-catalog.mjs +31 -0
- package/scripts/provider-pingpong-live.mjs +128 -38
- package/scripts/session-sweep.mjs +5 -25
- package/src/agents/maintainer/AGENT.md +1 -1
- package/src/agents/maintainer/agent.json +1 -1
- package/src/agents/reviewer/AGENT.md +2 -4
- package/src/agents/security/AGENT.md +1 -2
- package/src/agents/writer/AGENT.md +2 -3
- package/src/defaults/shipped-history.json +6 -1
- package/src/defaults/skills/image/SKILL.md +21 -23
- package/src/lib/keychain-cjs.cjs +13 -11
- package/src/rules/agent/AGENT.md +7 -5
- package/src/rules/lead/LEAD.md +7 -9
- package/src/rules/shared/45-destructive.md +4 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +28 -7
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -11
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +101 -23
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-api-key-fetch.mjs +36 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +26 -44
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +2 -5
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +41 -12
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +13 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +81 -10
- package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +109 -5
- package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +107 -37
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-native-context.mjs +48 -0
- package/src/runtime/agent/orchestrator/providers/cursor-wire-exec.mjs +144 -34
- package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +28 -4
- package/src/runtime/agent/orchestrator/providers/cursor-wire-request.mjs +8 -4
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +41 -11
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +67 -5
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +14 -4
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +14 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +9 -6
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -2
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +26 -4
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +12 -6
- package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +14 -6
- package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/gemini-rest-stream/watchdogs.mjs +16 -5
- package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +6 -1
- package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +22 -10
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -2
- package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +33 -7
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +11 -2
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +9 -5
- package/src/runtime/agent/orchestrator/providers/lib/request-compression.mjs +86 -0
- package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +4 -2
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -5
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +60 -16
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +11 -13
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +30 -19
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +5 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +42 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +13 -9
- package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +1 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +18 -7
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +36 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +51 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +11 -1
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +64 -52
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +1 -4
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +0 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +7 -6
- package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +13 -2
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/openrouter.mjs +1 -2
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +5 -4
- package/src/runtime/agent/orchestrator/providers/registry.mjs +9 -1
- package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +11 -4
- package/src/runtime/agent/orchestrator/providers/wire-route.mjs +14 -4
- package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +15 -3
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +6 -2
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +8 -6
- package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +4 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +30 -2
- package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +3 -2
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -3
- package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +3 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge-contract.mjs +6 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +10 -10
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +3 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +46 -8
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -8
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -2
- package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +24 -0
- package/src/runtime/agent/orchestrator/session/cache/tool-result-reuse.mjs +10 -2
- package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -3
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +3 -11
- package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +6 -22
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +16 -2
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +28 -0
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +0 -6
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +0 -6
- package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/historical-session-closure.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +2 -5
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +2 -4
- package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +0 -27
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -10
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +2 -9
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +1 -4
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +76 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +8 -9
- package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +1 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +3 -4
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +33 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-support.mjs +0 -4
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +21 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +38 -13
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +33 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +19 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +57 -13
- package/src/runtime/agent/orchestrator/session/manager/failed-turn-rewind.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +6 -120
- package/src/runtime/agent/orchestrator/session/manager/pending-persist-queue.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +29 -8
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +42 -49
- package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +50 -0
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +32 -14
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +17 -33
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +29 -13
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +45 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +2 -9
- package/src/runtime/agent/orchestrator/session/send-instrumentation.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/side-question.mjs +12 -7
- package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +5 -12
- package/src/runtime/agent/orchestrator/session/store/lifecycle-read.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/listing.mjs +2 -6
- package/src/runtime/agent/orchestrator/session/store/live-cache-eviction.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +46 -37
- package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/load-session.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +5 -11
- package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +59 -0
- package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +27 -32
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +0 -8
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +6 -18
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +33 -106
- package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store-agent-worker-pool.mjs +5 -8
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +136 -196
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +50 -116
- package/src/runtime/agent/orchestrator/session/store-summary-locations.mjs +3 -29
- package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +7 -8
- package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +9 -20
- package/src/runtime/agent/orchestrator/session/store.mjs +3 -16
- package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +11 -12
- package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +37 -13
- package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +15 -4
- package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +4 -2
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +72 -15
- package/src/runtime/agent/orchestrator/session/turn-failure.mjs +45 -0
- package/src/runtime/agent/orchestrator/stall-policy.mjs +50 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +5 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +204 -10
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +160 -39
- package/src/runtime/agent/orchestrator/tools/builtin/git-partial-stage.mjs +7 -5
- package/src/runtime/agent/orchestrator/tools/builtin/grep-formatting.mjs +14 -5
- package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-context-expander.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-output.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-path-fanout.mjs +48 -44
- package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +10 -3
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +200 -17
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +5 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +20 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +101 -2
- package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +67 -0
- package/src/runtime/agent/orchestrator/tools/lib/process-table-fixture.mjs +50 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +303 -63
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +108 -18
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +77 -11
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +81 -5
- package/src/runtime/attachments/store.d.mts +9 -0
- package/src/runtime/attachments/store.mjs +80 -9
- package/src/runtime/browser-bridge/browser-action-contract.d.mts +0 -1
- package/src/runtime/browser-bridge/browser-action-contract.mjs +0 -2
- package/src/runtime/computer-bridge/action-schema.mjs +178 -178
- package/src/runtime/computer-bridge/linux-readiness.d.mts +0 -2
- package/src/runtime/computer-bridge/linux-readiness.mjs +0 -16
- package/src/runtime/effort-judge/judge-client.mjs +21 -4
- package/src/runtime/effort-judge/judge-worker.mjs +4 -1
- package/src/runtime/github/tool.mjs +118 -17
- package/src/runtime/media/adapters/codex-image.mjs +140 -21
- package/src/runtime/media/catalog.mjs +4 -4
- package/src/runtime/media/chatgpt-usage.mjs +55 -0
- package/src/runtime/media/defaults.mjs +37 -0
- package/src/runtime/media/jobs.mjs +12 -2
- package/src/runtime/media/lanes.mjs +12 -0
- package/src/runtime/media/tool-defs.mjs +15 -4
- package/src/runtime/media/tool.mjs +41 -12
- package/src/runtime/media/upstream-error.mjs +72 -6
- package/src/runtime/memory/lib/ingest/transcript-rows.mjs +1 -0
- package/src/runtime/memory/lib/pg/process.mjs +5 -7
- package/src/runtime/memory/lib/pg/supervisor.mjs +4 -1
- package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
- package/src/runtime/office/authoring/html-browser.mjs +18 -8
- package/src/runtime/office/authoring/pdf-html-runner.mjs +1 -1
- package/src/runtime/office/authoring/pptx-html-measure.mjs +1 -1
- package/src/runtime/office/authoring/xlsx-html-runner.mjs +1 -1
- package/src/runtime/office/core/office-write-ledger.mjs +1 -5
- package/src/runtime/office/index.mjs +2 -3
- package/src/runtime/office/pdf/pdf-analysis.mjs +0 -68
- package/src/runtime/session-search/session-search-ingest.mjs +1 -1
- package/src/runtime/shared/agent-reap-state.mjs +13 -0
- package/src/runtime/shared/atomic-file.d.mts +1 -1
- package/src/runtime/shared/background-tasks.mjs +6 -1
- package/src/runtime/shared/bounded-line-diff.mjs +11 -2
- package/src/runtime/shared/browser-launch.mjs +15 -0
- package/src/runtime/shared/err-text.mjs +42 -4
- package/src/runtime/shared/file-lock.mjs +6 -5
- package/src/runtime/shared/llm/anthropic-betas.mjs +1 -2
- package/src/runtime/shared/llm/provider-model-identities.mjs +1 -0
- package/src/runtime/shared/model-route-chain.d.mts +8 -0
- package/src/runtime/shared/model-route-chain.mjs +48 -0
- package/src/runtime/shared/model-route-fallback.mjs +22 -0
- package/src/runtime/shared/pid-liveness.mjs +12 -0
- package/src/runtime/shared/provider-api-key.mjs +6 -0
- package/src/runtime/shared/provider-timeout-phase.mjs +17 -0
- package/src/runtime/shared/quiet-progress.d.mts +35 -0
- package/src/runtime/shared/quiet-progress.mjs +101 -0
- package/src/runtime/shared/quota-resume-store.mjs +32 -1
- package/src/runtime/shared/read-row-numbers.mjs +44 -0
- package/src/runtime/shared/remote-intent.mjs +2 -42
- package/src/runtime/shared/slow-span.mjs +8 -1
- package/src/runtime/shared/statusline/statusline-segments.mjs +24 -2
- package/src/runtime/shared/tool-card-model/card-header.mjs +2 -1
- package/src/runtime/shared/tool-output-budget.mjs +2 -0
- package/src/runtime/shared/tool-result-summary.mjs +16 -2
- package/src/runtime/shared/tool-status.mjs +3 -2
- package/src/runtime/shared/tool-surface.mjs +2 -3
- package/src/runtime/shared/tool-work-units.mjs +22 -15
- package/src/runtime/shared/transcript-metadata.mjs +49 -1
- package/src/runtime/shared/transcript-turn-keys.mjs +33 -0
- package/src/runtime/shared/transcript-writer/transcript-file.mjs +10 -1
- package/src/runtime/shared/transcript-writer.mjs +14 -4
- package/src/runtime/shared/turn-changes.mjs +2 -1
- package/src/runtime/shared/turn-snapshot.mjs +11 -3
- package/src/runtime/shared/worktrees/activity-gate.mjs +175 -0
- package/src/runtime/shared/worktrees/branch-management.mjs +179 -0
- package/src/runtime/shared/worktrees/carry.mjs +6 -4
- package/src/runtime/shared/worktrees/contract.mjs +27 -1
- package/src/runtime/shared/worktrees/dependencies.mjs +456 -0
- package/src/runtime/shared/worktrees/file-recovery.mjs +29 -13
- package/src/runtime/shared/worktrees/git-head.mjs +22 -13
- package/src/runtime/shared/worktrees/include.mjs +125 -7
- package/src/runtime/shared/worktrees/lock.mjs +1 -1
- package/src/runtime/shared/worktrees/maintenance.mjs +20 -2
- package/src/runtime/shared/worktrees/manager.mjs +378 -32
- package/src/runtime/shared/worktrees/owner.mjs +2 -1
- package/src/runtime/shared/worktrees/preparation-report.mjs +79 -0
- package/src/runtime/shared/worktrees/setup-commands.mjs +232 -0
- package/src/runtime/shared/worktrees/workspace-visibility.mjs +17 -0
- package/src/runtime/terminal-bridge/client.mjs +14 -10
- package/src/session-runtime/boot/apis.mjs +7 -1
- package/src/session-runtime/boot/config.mjs +2 -0
- package/src/session-runtime/boot/facade.mjs +3 -0
- package/src/session-runtime/boot/session.mjs +3 -2
- package/src/session-runtime/boot/tools.mjs +3 -0
- package/src/session-runtime/conversation-import/service.mjs +1 -1
- package/src/session-runtime/goal-facade-api.mjs +2 -2
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +44 -18
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +4 -1
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +22 -8
- package/src/session-runtime/internal-tool-executor.mjs +2 -0
- package/src/session-runtime/lifecycle/cold-heir.mjs +0 -1
- package/src/session-runtime/lifecycle/session-catalog.mjs +14 -16
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +18 -53
- package/src/session-runtime/lifecycle/session-switch.mjs +1 -1
- package/src/session-runtime/lifecycle/shared.mjs +5 -6
- package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -5
- package/src/session-runtime/lifecycle/teardown.mjs +7 -16
- package/src/session-runtime/media-api.mjs +8 -0
- package/src/session-runtime/model-route/route-ownership.mjs +60 -0
- package/src/session-runtime/model-route/route-persist.mjs +3 -2
- package/src/session-runtime/model-route/set-route.mjs +114 -34
- package/src/session-runtime/model-route/web-search-route.mjs +7 -2
- package/src/session-runtime/model-route-api.mjs +4 -2
- package/src/session-runtime/native-web-search/routes.mjs +37 -24
- package/src/session-runtime/native-web-search.mjs +9 -8
- package/src/session-runtime/provider-auth/setup.mjs +4 -0
- package/src/session-runtime/provider-models/catalog-load.mjs +9 -0
- package/src/session-runtime/provider-models/web-search-catalog.mjs +23 -3
- package/src/session-runtime/provider-models.mjs +1 -0
- package/src/session-runtime/provider-usage.mjs +4 -0
- package/src/session-runtime/route-resolution.mjs +3 -1
- package/src/session-runtime/runtime-core.mjs +4 -0
- package/src/session-runtime/runtime-facade.mjs +6 -0
- package/src/session-runtime/services/agent-task-status.mjs +2 -0
- package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +0 -3
- package/src/session-runtime/services/agent-tool/close-flow.mjs +6 -7
- package/src/session-runtime/services/agent-tool/execute-send.mjs +2 -2
- package/src/session-runtime/services/agent-tool/execute-spawn.mjs +36 -3
- package/src/session-runtime/services/agent-tool/execute.mjs +9 -1
- package/src/session-runtime/services/agent-tool/helpers.mjs +30 -7
- package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +7 -2
- package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +6 -3
- package/src/session-runtime/services/agent-tool/lead-worker-index/lead-rows.mjs +3 -4
- package/src/session-runtime/services/agent-tool/lead-worker-index/reap-timers.mjs +9 -3
- package/src/session-runtime/services/agent-tool/lead-worker-index/row-settlement.mjs +7 -18
- package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +9 -6
- package/src/session-runtime/services/agent-tool/model-select.mjs +82 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -6
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +3 -1
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -5
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -4
- package/src/session-runtime/services/agent-tool/spawn-flow.mjs +2 -1
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
- package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +1 -3
- package/src/session-runtime/services/agent-tool/tag-registry/tag-refresh.mjs +1 -3
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -9
- package/src/session-runtime/services/agent-tool/terminal-reaper/scan-admission.mjs +8 -41
- package/src/session-runtime/services/agent-tool/terminal-reaper/stale-rows.mjs +3 -3
- package/src/session-runtime/services/agent-tool/terminal-reaper.mjs +6 -23
- package/src/session-runtime/services/agent-tool/terminal-trace.mjs +0 -1
- package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +32 -20
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -2
- package/src/session-runtime/services/agent-tool/worker-index.mjs +28 -8
- package/src/session-runtime/services/agent-tool.mjs +4 -0
- package/src/session-runtime/services/agent-watchdog-registry.mjs +2 -0
- package/src/session-runtime/services/provider-admin.mjs +77 -0
- package/src/session-runtime/session-create/session-options.mjs +7 -5
- package/src/session-runtime/session-create/session-start-hook.mjs +2 -1
- package/src/session-runtime/session-transcript.mjs +4 -5
- package/src/session-runtime/session-turn-api.mjs +3 -9
- package/src/session-runtime/settings-builtin-tools-api.mjs +9 -6
- package/src/session-runtime/setup-tool/executor.mjs +23 -5
- package/src/session-runtime/setup-tool/extended-actions.mjs +6 -6
- package/src/session-runtime/setup-tool/settings-contract.mjs +7 -2
- package/src/session-runtime/setup-tool/tool-defs.mjs +13 -1
- package/src/session-runtime/tool-policy-refresh.mjs +83 -32
- package/src/session-runtime/turn/agent-ops.mjs +49 -2
- package/src/session-runtime/turn/side-question-ops.mjs +1 -4
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +2 -0
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +4 -0
- package/src/session-runtime/turn/turn-run/turn-settle.mjs +8 -2
- package/src/session-runtime/turn/turn-run.mjs +1 -36
- package/src/session-runtime/usage-stats-api.mjs +4 -1
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +16 -1
- package/src/session-runtime/workspace/admission-gate.mjs +44 -15
- package/src/session-runtime/workspace/project-branches.mjs +28 -36
- package/src/session-runtime/workspace/transition-steps.mjs +96 -95
- package/src/session-runtime/workspace/transitions.mjs +248 -68
- package/src/standalone/channel-transport.mjs +3 -4
- package/src/standalone/daemon-desktop-runtime.mjs +32 -1
- package/src/standalone/daemon-pg-stop.mjs +1 -3
- package/src/standalone/daemon-session-control.mjs +88 -0
- package/src/standalone/daemon-stored-session-views.mjs +23 -3
- package/src/standalone/daemon.mjs +2 -0
- package/src/standalone/local-session-runtime.mjs +11 -12
- package/src/standalone/session-protocol.mjs +7 -0
- package/src/standalone/session-runtime-inline-host.mjs +2 -0
- package/src/standalone/session-service/agent-tree/agent-cancel.mjs +91 -49
- package/src/standalone/session-service/agent-tree/agent-child.mjs +19 -1
- package/src/standalone/session-service/agent-tree/agent-registry.mjs +25 -0
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +9 -1
- package/src/standalone/session-service/agent-tree.mjs +28 -2
- package/src/standalone/session-service/entries/session-loads.mjs +16 -5
- package/src/standalone/session-service/entries.mjs +1 -0
- package/src/standalone/session-service/projection/transcript-window.mjs +39 -0
- package/src/standalone/session-service/quota-resume.mjs +28 -13
- package/src/standalone/session-service/session-calls/session-turns.mjs +17 -6
- package/src/standalone/session-service/session-calls/session-views.mjs +6 -0
- package/src/standalone/session-tool-output.mjs +82 -0
- package/src/tui/app/app-view.jsx +2 -1
- package/src/tui/app/provider-setup/provider-items.mjs +8 -0
- package/src/tui/app/provider-setup-picker.mjs +15 -3
- package/src/tui/app/slash-commands.mjs +6 -0
- package/src/tui/app/slash-dispatch/session-commands.mjs +49 -0
- package/src/tui/components/Spinner.jsx +4 -0
- package/src/tui/components/SpinnerByline.jsx +21 -2
- package/src/tui/components/status-line/local-line.mjs +10 -2
- package/src/tui/dist/index.mjs +478 -251
- package/src/tui/session/active-tool-summary.mjs +1 -1
- package/src/tui/session/context-state.mjs +0 -3
- package/src/tui/session/goal-continuation/continuation-queue.mjs +2 -3
- package/src/tui/session/goal-continuation/deadline-delivery.mjs +4 -2
- package/src/tui/session/goal-continuation/session-boundary.mjs +21 -0
- package/src/tui/session/quota-resume.mjs +140 -61
- package/src/tui/session/session-api/commands.mjs +4 -10
- package/src/tui/session/session-api/controls.mjs +12 -0
- package/src/tui/session/session-api/lifecycle/dispose.mjs +2 -9
- package/src/tui/session/session-api/lifecycle/resume.mjs +2 -7
- package/src/tui/session/session-api/lifecycle.mjs +13 -11
- package/src/tui/session/session-api/media.mjs +2 -0
- package/src/tui/session/session-api/routes.mjs +81 -57
- package/src/tui/session/session-api/settings.mjs +3 -3
- package/src/tui/session/session-api/worktree.mjs +3 -2
- package/src/tui/session/session-flow/auto-clear.mjs +1 -3
- package/src/tui/session/session-flow/drain.mjs +6 -4
- package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -0
- package/src/tui/session/session-flow/queue/take-entries.mjs +2 -1
- package/src/tui/session/session-flow/queue.mjs +1 -1
- package/src/tui/session/tool-approval.mjs +17 -8
- package/src/tui/session/transcript-store/streaming-tail.mjs +1 -1
- package/src/tui/session/tui-steering-persist.mjs +3 -5
- package/src/tui/session/turn-quiet.mjs +53 -0
- package/src/tui/session/turn-stream.mjs +5 -1
- package/src/tui/session/turn.mjs +38 -31
- package/src/tui/session/worktree-setup-notice.mjs +38 -0
- package/src/tui/spinner-meta.mjs +10 -0
- package/src/tui/spinner-verbs.mjs +3 -0
- package/src/ui/statusline.mjs +13 -3
- package/src/runtime/agent/orchestrator/providers/model-pricing-rates.mjs +0 -1
- package/src/runtime/agent/orchestrator/session/manager/foreign-pending-messages.mjs +0 -346
- package/src/runtime/agent/orchestrator/session/manager/session-owner-liveness.mjs +0 -117
- package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +0 -302
- package/src/session-runtime/services/agent-tool/terminal-reaper/reap-timers.mjs +0 -142
- package/src/session-runtime/turn/share-ops.mjs +0 -77
- package/src/tui/session/cross-surface-share.mjs +0 -406
- package/src/tui/session/live-share/delta.mjs +0 -153
- package/src/tui/session/live-share/mirror.mjs +0 -106
- package/src/tui/session/live-share/owner.mjs +0 -254
- package/src/tui/session/live-share/retry.mjs +0 -54
- package/src/tui/session/live-share/viewer/frame-router.mjs +0 -32
- package/src/tui/session/live-share/viewer/pipe-client.mjs +0 -108
- package/src/tui/session/live-share/viewer/submit-acks.mjs +0 -65
- package/src/tui/session/live-share/viewer/sync-waiters.mjs +0 -53
- package/src/tui/session/live-share/viewer.mjs +0 -99
- package/src/tui/session/live-share/wire.mjs +0 -44
- package/src/tui/session/live-share.mjs +0 -154
- package/src/tui/session/shared-dir-watch.mjs +0 -69
|
@@ -19,21 +19,43 @@ function catalogThinkingLevels(model, provider) {
|
|
|
19
19
|
// Documented ranges: 2.5 Pro 128–32768 (cannot disable), 2.5 Flash 0–24576,
|
|
20
20
|
// 2.5 Flash-Lite 0 or 512–24576; -1 is dynamic thinking for all of them.
|
|
21
21
|
function budgetSpec(model) {
|
|
22
|
-
const bare = String(model || '')
|
|
22
|
+
const bare = String(model || '')
|
|
23
|
+
.replace(/^models\//i, '')
|
|
24
|
+
.toLowerCase();
|
|
23
25
|
if (!/^gemini-2\.5(?:-|$)/.test(bare)) return null;
|
|
24
26
|
if (/^gemini-2\.5-pro/.test(bare)) {
|
|
25
|
-
return {
|
|
27
|
+
return {
|
|
28
|
+
name: 'Gemini 2.5 Pro',
|
|
29
|
+
min: 128,
|
|
30
|
+
max: 32768,
|
|
31
|
+
canDisable: false,
|
|
32
|
+
efforts: { minimal: 128, low: 1024, medium: 8192, high: 32768 },
|
|
33
|
+
};
|
|
26
34
|
}
|
|
27
35
|
if (/^gemini-2\.5-flash-lite/.test(bare)) {
|
|
28
|
-
return {
|
|
36
|
+
return {
|
|
37
|
+
name: 'Gemini 2.5 Flash-Lite',
|
|
38
|
+
min: 512,
|
|
39
|
+
max: 24576,
|
|
40
|
+
canDisable: true,
|
|
41
|
+
efforts: { minimal: 512, low: 1024, medium: 8192, high: 24576 },
|
|
42
|
+
};
|
|
29
43
|
}
|
|
30
|
-
return {
|
|
44
|
+
return {
|
|
45
|
+
name: 'Gemini 2.5 Flash',
|
|
46
|
+
min: 0,
|
|
47
|
+
max: 24576,
|
|
48
|
+
canDisable: true,
|
|
49
|
+
efforts: { minimal: 0, low: 1024, medium: 8192, high: 24576 },
|
|
50
|
+
};
|
|
31
51
|
}
|
|
32
52
|
|
|
33
53
|
// Levels documented for models whose ladder differs from the generic wire
|
|
34
54
|
// vocabulary (a catalog ladder, when declared, still takes precedence).
|
|
35
55
|
function documentedThinkingLevels(model) {
|
|
36
|
-
const bare = String(model || '')
|
|
56
|
+
const bare = String(model || '')
|
|
57
|
+
.replace(/^models\//i, '')
|
|
58
|
+
.toLowerCase();
|
|
37
59
|
if (bare === 'gemini-4-argon' || bare === 'gemini-3.8-flash') return ['low', 'medium', 'high'];
|
|
38
60
|
return null;
|
|
39
61
|
}
|
|
@@ -47,7 +69,9 @@ function checkBudget(model, spec, budget) {
|
|
|
47
69
|
throw new TypeError(`${model} (${spec.name}) cannot disable thinking; thinkingBudget 0 is not allowed.`);
|
|
48
70
|
}
|
|
49
71
|
if (budget !== 0 && (budget < spec.min || budget > spec.max)) {
|
|
50
|
-
throw new TypeError(
|
|
72
|
+
throw new TypeError(
|
|
73
|
+
`${model} (${spec.name}) thinkingBudget must be -1, ${spec.canDisable ? '0, or ' : ''}${spec.min}–${spec.max}; received ${budget}.`
|
|
74
|
+
);
|
|
51
75
|
}
|
|
52
76
|
}
|
|
53
77
|
|
|
@@ -75,7 +99,9 @@ export function geminiThinkingConfig(model, opts = {}, { includeThoughts, provid
|
|
|
75
99
|
}
|
|
76
100
|
if (spec && level) {
|
|
77
101
|
if (!Object.hasOwn(spec.efforts, level)) {
|
|
78
|
-
throw new TypeError(
|
|
102
|
+
throw new TypeError(
|
|
103
|
+
`${model} supports thinking levels ${Object.keys(spec.efforts).join(', ')}; received ${level}.`
|
|
104
|
+
);
|
|
79
105
|
}
|
|
80
106
|
config.thinkingBudget = spec.efforts[level];
|
|
81
107
|
} else if (level) {
|
|
@@ -731,8 +731,17 @@ export class GeminiProvider {
|
|
|
731
731
|
}
|
|
732
732
|
|
|
733
733
|
async _streamViaSdk(stream) {
|
|
734
|
-
const {
|
|
735
|
-
|
|
734
|
+
const {
|
|
735
|
+
opts,
|
|
736
|
+
signal,
|
|
737
|
+
useModel,
|
|
738
|
+
systemInstruction,
|
|
739
|
+
geminiTools,
|
|
740
|
+
toolConfig,
|
|
741
|
+
generationConfig,
|
|
742
|
+
safetySettings,
|
|
743
|
+
contents,
|
|
744
|
+
} = stream;
|
|
736
745
|
const genModel = this._currentGenAI().getGenerativeModel({
|
|
737
746
|
model: useModel,
|
|
738
747
|
systemInstruction,
|
|
@@ -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.62';
|
|
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' });
|
|
@@ -37,7 +37,9 @@ function lastEligibleBlockIndex(content) {
|
|
|
37
37
|
export function countAnthropicCacheControls(value) {
|
|
38
38
|
if (Array.isArray(value)) return value.reduce((sum, item) => sum + countAnthropicCacheControls(item), 0);
|
|
39
39
|
if (!value || typeof value !== 'object') return 0;
|
|
40
|
-
return (
|
|
40
|
+
return (
|
|
41
|
+
(value.cache_control ? 1 : 0) + (Array.isArray(value.content) ? countAnthropicCacheControls(value.content) : 0)
|
|
42
|
+
);
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
function stripCacheControl(block, budget) {
|
|
@@ -546,7 +548,12 @@ function toAnthropicTools(tools, logTag, onToolExcluded) {
|
|
|
546
548
|
// `supportsDisableParallelToolUse: false` (gateway capability).
|
|
547
549
|
export function toAnthropicToolChoice(
|
|
548
550
|
toolChoice,
|
|
549
|
-
{
|
|
551
|
+
{
|
|
552
|
+
thinking = false,
|
|
553
|
+
disableParallelToolUse = false,
|
|
554
|
+
supportsDisableParallelToolUse = true,
|
|
555
|
+
onThinkingConflict = 'fallback',
|
|
556
|
+
} = {}
|
|
550
557
|
) {
|
|
551
558
|
let choice;
|
|
552
559
|
if (toolChoice === 'none') choice = { type: 'none' };
|
|
@@ -203,7 +203,8 @@ function assertObjectRoot(schema, rule) {
|
|
|
203
203
|
function buildSchema(inputSchema) {
|
|
204
204
|
if (!isPlainObject(inputSchema)) throw new SchemaProblem('', 'the input schema must be a JSON object schema');
|
|
205
205
|
const { $schema, ...rest } = inputSchema;
|
|
206
|
-
const schema =
|
|
206
|
+
const schema =
|
|
207
|
+
dialectOf(inputSchema) === 'draft-07' ? translateDraft07(rest, '', true, DRAFT07) : structuredClone(rest);
|
|
207
208
|
assertValidDraft202012(schema);
|
|
208
209
|
assertObjectRoot(schema, 'anthropic');
|
|
209
210
|
return schema;
|
|
@@ -222,8 +223,7 @@ function repairRoot(schema) {
|
|
|
222
223
|
if (Array.isArray(type) && type.includes('object')) return { ...schema, type: 'object' };
|
|
223
224
|
if (type !== undefined || Object.hasOwn(schema, '$ref')) return schema;
|
|
224
225
|
const out = { type: 'object', ...schema };
|
|
225
|
-
if (!Object.hasOwn(out, 'properties') && !ROOT_FORBIDDEN_KEYS.some((k) => Object.hasOwn(out, k)))
|
|
226
|
-
out.properties = {};
|
|
226
|
+
if (!Object.hasOwn(out, 'properties') && !ROOT_FORBIDDEN_KEYS.some((k) => Object.hasOwn(out, k))) out.properties = {};
|
|
227
227
|
return out;
|
|
228
228
|
}
|
|
229
229
|
|
|
@@ -232,7 +232,8 @@ function refsIntoDefinitions(node) {
|
|
|
232
232
|
if (Array.isArray(node)) return node.some(refsIntoDefinitions);
|
|
233
233
|
if (!isPlainObject(node)) return false;
|
|
234
234
|
return Object.entries(node).some(
|
|
235
|
-
([key, value]) =>
|
|
235
|
+
([key, value]) =>
|
|
236
|
+
(key === '$ref' && typeof value === 'string' && /^#\/definitions(\/|$)/.test(value)) || refsIntoDefinitions(value)
|
|
236
237
|
);
|
|
237
238
|
}
|
|
238
239
|
|
|
@@ -348,7 +349,10 @@ export function claudeBridgeInputSchema(inputSchema) {
|
|
|
348
349
|
// Not valid as written: lower undeclared draft-07/04 constructs and
|
|
349
350
|
// fill the root type; only a schema still broken is excluded.
|
|
350
351
|
const repaired = repairedToolInputSchema(inputSchema, 'anthropic');
|
|
351
|
-
result =
|
|
352
|
+
result =
|
|
353
|
+
repaired && !wireProblem(repaired, 'anthropic')
|
|
354
|
+
? { schema: repaired }
|
|
355
|
+
: { pointer: error.pointer, reason: error.message };
|
|
352
356
|
}
|
|
353
357
|
if (key !== null) {
|
|
354
358
|
if (cache.size >= CACHE_LIMIT) cache.clear();
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// Shared request-body compression for provider POSTs (Anthropic gzip, Codex
|
|
2
|
+
// zstd). Policy in one place:
|
|
3
|
+
// - bodies below REQ_COMPRESSION_MIN_BYTES are never compressed (CPU + header
|
|
4
|
+
// cost outweighs the upload saving);
|
|
5
|
+
// - a request that already carries Content-Encoding is never double-encoded;
|
|
6
|
+
// - a compression failure fails open to the plain body;
|
|
7
|
+
// - a 400/415 on a compressed request is drained and the SAME request is
|
|
8
|
+
// resent once uncompressed; compression latches off process-wide only when
|
|
9
|
+
// that plain resend succeeds (the encoding was the cause). If the resend
|
|
10
|
+
// fails too, nothing latches and the resend's response is returned.
|
|
11
|
+
import { promisify } from 'node:util';
|
|
12
|
+
import { gzip } from 'node:zlib';
|
|
13
|
+
|
|
14
|
+
export const REQ_COMPRESSION_MIN_BYTES = 8 * 1024;
|
|
15
|
+
|
|
16
|
+
export function createCompressionLatch(envVar) {
|
|
17
|
+
let latched = false;
|
|
18
|
+
return {
|
|
19
|
+
disabled: () => latched || process.env[envVar] === '0',
|
|
20
|
+
latchOff: () => {
|
|
21
|
+
latched = true;
|
|
22
|
+
},
|
|
23
|
+
reset: () => {
|
|
24
|
+
latched = false;
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// One latch for every api.anthropic.com /v1/messages path (OAuth + API key).
|
|
30
|
+
export const anthropicGzipLatch = createCompressionLatch('MIXDOG_ANTHROPIC_REQ_GZIP');
|
|
31
|
+
// Compress on the libuv threadpool so large turn bodies never block the main thread.
|
|
32
|
+
export const gzipAsync = promisify(gzip);
|
|
33
|
+
|
|
34
|
+
export const hasContentEncoding = (headers) => new Headers(headers || {}).has('content-encoding');
|
|
35
|
+
|
|
36
|
+
export function withContentEncoding(headers, encoding) {
|
|
37
|
+
if (headers instanceof Headers || Array.isArray(headers)) {
|
|
38
|
+
const next = new Headers(headers);
|
|
39
|
+
next.delete('content-length');
|
|
40
|
+
next.set('Content-Encoding', encoding);
|
|
41
|
+
return next;
|
|
42
|
+
}
|
|
43
|
+
const rest = Object.fromEntries(
|
|
44
|
+
Object.entries(headers || {}).filter(([name]) => name.toLowerCase() !== 'content-length')
|
|
45
|
+
);
|
|
46
|
+
return { ...rest, 'Content-Encoding': encoding };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Fail open: any compression error yields the plain body.
|
|
50
|
+
export async function compressBody(raw, compress, encoding) {
|
|
51
|
+
try {
|
|
52
|
+
return { bytes: await compress(raw), encoding };
|
|
53
|
+
} catch {
|
|
54
|
+
return { bytes: raw, encoding: null };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export const isEncodingRejection = (response) => response.status === 400 || response.status === 415;
|
|
59
|
+
|
|
60
|
+
export async function resendIfEncodingRejected({ response, encoded, resend, latch }) {
|
|
61
|
+
if (!encoded || !isEncodingRejection(response)) return response;
|
|
62
|
+
try {
|
|
63
|
+
await response.arrayBuffer();
|
|
64
|
+
} catch {
|
|
65
|
+
/* drain best-effort */
|
|
66
|
+
}
|
|
67
|
+
const retry = await resend();
|
|
68
|
+
if (retry.ok) latch.latchOff();
|
|
69
|
+
return retry;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Send `raw` compressed when eligible, with the rejection resend above.
|
|
74
|
+
* `send(bytes, headers)` performs one HTTP request.
|
|
75
|
+
*/
|
|
76
|
+
export async function sendWithCompression({ raw, headers, encoding, compress, latch, send }) {
|
|
77
|
+
const plain = () => send(raw, headers);
|
|
78
|
+
if (latch.disabled() || raw.length < REQ_COMPRESSION_MIN_BYTES || hasContentEncoding(headers)) return plain();
|
|
79
|
+
const packed = await compressBody(raw, compress, encoding);
|
|
80
|
+
if (!packed.encoding) return plain();
|
|
81
|
+
const response = await send(packed.bytes, withContentEncoding(headers, encoding));
|
|
82
|
+
return resendIfEncodingRejected({ response, encoded: true, resend: plain, latch });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export const sendGzipCompressed = ({ compress = gzipAsync, ...rest }) =>
|
|
86
|
+
sendWithCompression({ ...rest, encoding: 'gzip', compress, latch: anthropicGzipLatch });
|
|
@@ -29,8 +29,10 @@ function isObject(value) {
|
|
|
29
29
|
// answered by the server inside the same response. It is never a client call
|
|
30
30
|
// awaiting a client output, so the guard neither pairs nor synthesizes it.
|
|
31
31
|
function isServerToolSearch(item) {
|
|
32
|
-
return (
|
|
33
|
-
(item.
|
|
32
|
+
return (
|
|
33
|
+
(item.type === 'tool_search_call' || item.type === 'tool_search_output') &&
|
|
34
|
+
(item.execution === 'server' || item.call_id === null)
|
|
35
|
+
);
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
function responsesCallId(item) {
|
|
@@ -167,7 +167,11 @@ function officeTextForFile(file) {
|
|
|
167
167
|
});
|
|
168
168
|
if (file.ref) return memoized(officeTextMemo, `ref:${file.ref}\0${file.filename || ''}`, compute);
|
|
169
169
|
if (file.part && inlineOfficeText.has(file.part)) return inlineOfficeText.get(file.part);
|
|
170
|
-
const key = createHash('sha256')
|
|
170
|
+
const key = createHash('sha256')
|
|
171
|
+
.update(file.filename || '')
|
|
172
|
+
.update('\0')
|
|
173
|
+
.update(file.data)
|
|
174
|
+
.digest('hex');
|
|
171
175
|
const text = memoized(officeTextMemo, key, compute);
|
|
172
176
|
if (file.part) inlineOfficeText.set(file.part, text);
|
|
173
177
|
return text;
|
|
@@ -403,15 +407,19 @@ export async function preparePdfTextForProvider(messages, provider) {
|
|
|
403
407
|
continue;
|
|
404
408
|
}
|
|
405
409
|
if (file && fileKind(file) === 'pdf') found.push({ part, file });
|
|
406
|
-
else if (noDocuments && (file || part.type === 'document'))
|
|
410
|
+
else if (noDocuments && (file || part.type === 'document'))
|
|
411
|
+
texts.set(part, file ? textFormOfFilePart(part) : documentSourceText(part));
|
|
407
412
|
}
|
|
408
413
|
}
|
|
409
414
|
if (!found.length && !texts.size) return messages;
|
|
410
415
|
const extracted = await Promise.all(found.map(({ file }) => pdfTextFor(file)));
|
|
411
|
-
found.forEach(({ part, file }, i) =>
|
|
416
|
+
found.forEach(({ part, file }, i) => {
|
|
417
|
+
texts.set(part, `--- ${fileLabel(file)} ---\n${extracted[i]}`);
|
|
418
|
+
});
|
|
412
419
|
return messages.map((message) => {
|
|
413
420
|
// A message whose content is one bare part becomes a one-part array.
|
|
414
|
-
if (texts.has(message?.content))
|
|
421
|
+
if (texts.has(message?.content))
|
|
422
|
+
return { ...message, content: [{ type: 'text', text: texts.get(message.content) }] };
|
|
415
423
|
const content = replacePdfParts(message?.content, texts);
|
|
416
424
|
return content === message?.content ? message : { ...message, content };
|
|
417
425
|
});
|
|
@@ -681,7 +689,10 @@ export function contentMediaBytes(content, { nativePdf = true } = {}) {
|
|
|
681
689
|
if (!part || typeof part !== 'object') continue;
|
|
682
690
|
if (isAttachmentReference(part)) {
|
|
683
691
|
if (part.type === 'image') bytes += Math.ceil((Number(part.sizeBytes) || 0) / 3) * 4;
|
|
684
|
-
else if (
|
|
692
|
+
else if (
|
|
693
|
+
part.type === 'file' &&
|
|
694
|
+
countsAsMedia(String(part.mimeType || part.mediaType || 'application/pdf'), '')
|
|
695
|
+
) {
|
|
685
696
|
bytes += Math.ceil((Number(part.sizeBytes) || 0) / 3) * 4;
|
|
686
697
|
}
|
|
687
698
|
continue;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { noteErrorUsage } from './lib/note-error-usage.mjs';
|
|
10
10
|
import { fileMtimeMs, scrubOAuthSecrets } from './lib/oauth-token-utils.mjs';
|
|
11
11
|
import { OpenAICompatProvider, preloadOpenAICompatRuntime } from './openai-compat.mjs';
|
|
12
|
-
import { COMPAT_RETRY_POLICY } from './openai-compat-retry-profile.mjs';
|
|
12
|
+
import { COMPAT_RETRY_POLICY, compatFirstResponseBudget } from './openai-compat-retry-profile.mjs';
|
|
13
13
|
import { fetchCompatModelItems, listCompatModels } from './openai-compat-models.mjs';
|
|
14
14
|
import { makeModelCache } from './model-cache.mjs';
|
|
15
15
|
import {
|
|
@@ -152,6 +152,12 @@ export class MimoOAuthProvider {
|
|
|
152
152
|
return this.tokens;
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
// The inner client's chat profile sets a longer first-byte window; the
|
|
156
|
+
// budget needs no credentials, so it is read from the profile directly.
|
|
157
|
+
firstResponseBudget() {
|
|
158
|
+
return compatFirstResponseBudget(this.name, MIMO_CHAT_PROFILE);
|
|
159
|
+
}
|
|
160
|
+
|
|
155
161
|
_ensureInner() {
|
|
156
162
|
const { apiKey, baseUrl } = this.ensureAuth();
|
|
157
163
|
const key = `${baseUrl}:${apiKey}`;
|
|
@@ -90,6 +90,15 @@ export function inlineModelProxyAttachments(messages, { maxBytes = MODEL_PROXY_I
|
|
|
90
90
|
return out ?? messages;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
/** A first-response budget the PC reported, or null for anything malformed. */
|
|
94
|
+
function reportedBudget(value) {
|
|
95
|
+
const transportMs = Number(value?.transportMs);
|
|
96
|
+
const semanticMs = Number(value?.semanticMs);
|
|
97
|
+
return transportMs > 0 && semanticMs > 0 && Number.isFinite(transportMs) && Number.isFinite(semanticMs)
|
|
98
|
+
? { transportMs, semanticMs }
|
|
99
|
+
: null;
|
|
100
|
+
}
|
|
101
|
+
|
|
93
102
|
export class ModelProxyProvider {
|
|
94
103
|
#channel;
|
|
95
104
|
#modelInfo = new Map();
|
|
@@ -101,6 +110,7 @@ export class ModelProxyProvider {
|
|
|
101
110
|
this.#channel = channel;
|
|
102
111
|
// Adapter traits are reported by the PC's real instance.
|
|
103
112
|
if (typeof this.config.modelProxy?.nativePdf === 'boolean') this.nativePdf = this.config.modelProxy.nativePdf;
|
|
113
|
+
if (this.config.modelProxy?.consumesReadWindows === true) this.consumesReadWindows = true;
|
|
104
114
|
}
|
|
105
115
|
|
|
106
116
|
#call(method, fields = {}, options = {}) {
|
|
@@ -110,18 +120,16 @@ export class ModelProxyProvider {
|
|
|
110
120
|
async send(messages, model, tools, sendOpts) {
|
|
111
121
|
const { options, callbacks } = splitModelProxySendOptions(sendOpts);
|
|
112
122
|
const finalized = isFinalizedProviderRequestTools(tools);
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
{ signal: sendOpts?.signal || null, callbacks }
|
|
124
|
-
);
|
|
123
|
+
const fields = {
|
|
124
|
+
model: model ?? null,
|
|
125
|
+
messages: inlineModelProxyAttachments(messages),
|
|
126
|
+
tools: Array.isArray(tools) ? tools : null,
|
|
127
|
+
toolsFinalized: finalized,
|
|
128
|
+
nativePrefixCount: finalized ? providerNativeToolPrefixCount(tools) : 0,
|
|
129
|
+
options,
|
|
130
|
+
};
|
|
131
|
+
const signal = sendOpts?.signal || null;
|
|
132
|
+
const result = await this.#call('send', fields, { signal, callbacks });
|
|
125
133
|
// The PC rerouted the wire (a clear "unsupported" refusal) and reports the
|
|
126
134
|
// route it used: the daemon's own session adopts it, so the next proxied
|
|
127
135
|
// turn starts on the new wire instead of repeating the refusal.
|
|
@@ -163,6 +171,16 @@ export class ModelProxyProvider {
|
|
|
163
171
|
return this.#modelInfo.get(String(model ?? '')) ?? null;
|
|
164
172
|
}
|
|
165
173
|
|
|
174
|
+
/** The PC adapter's first-response budget for `model`: the catalog's
|
|
175
|
+
* model-specific figure, else the adapter's own from its provider config;
|
|
176
|
+
* null keeps the agent watchdog default. */
|
|
177
|
+
firstResponseBudget(model) {
|
|
178
|
+
return (
|
|
179
|
+
reportedBudget(this.getCachedModelInfo(model)?.firstResponseBudget) ??
|
|
180
|
+
reportedBudget(this.config.modelProxy?.firstResponseBudget)
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
166
184
|
/** The PC adapter's wire route for `model` (its config and roster decide);
|
|
167
185
|
* null for a single-wire adapter, which is remembered so every later turn
|
|
168
186
|
* skips the round trip. */
|
|
@@ -222,10 +240,12 @@ export function loadModelProxyProviderConfig({
|
|
|
222
240
|
channel = getModelProxyChannel(),
|
|
223
241
|
now = Date.now,
|
|
224
242
|
waitMs = MODEL_PROXY_CONFIG_WAIT_MS,
|
|
243
|
+
force = false,
|
|
225
244
|
} = {}) {
|
|
226
245
|
const generation = channel.generation;
|
|
227
246
|
const cached = _providerConfigCache;
|
|
228
247
|
if (
|
|
248
|
+
!force &&
|
|
229
249
|
cached &&
|
|
230
250
|
cached.channel === channel &&
|
|
231
251
|
cached.generation === generation &&
|
|
@@ -234,7 +254,16 @@ export function loadModelProxyProviderConfig({
|
|
|
234
254
|
return Promise.resolve(cached.value);
|
|
235
255
|
}
|
|
236
256
|
const inFlight = _providerConfigInFlight;
|
|
237
|
-
|
|
257
|
+
// A forced read starts after the caller's change, never reuses an older
|
|
258
|
+
// snapshot. Short setup reads also cannot inherit a registry init's budget.
|
|
259
|
+
if (
|
|
260
|
+
!force &&
|
|
261
|
+
inFlight &&
|
|
262
|
+
inFlight.channel === channel &&
|
|
263
|
+
inFlight.generation === generation &&
|
|
264
|
+
inFlight.waitMs === waitMs
|
|
265
|
+
)
|
|
266
|
+
return inFlight.promise;
|
|
238
267
|
const promise = (async () => {
|
|
239
268
|
const deadline = Date.now() + waitMs;
|
|
240
269
|
let delay = CONFIG_RETRY_FIRST_MS;
|
|
@@ -247,12 +276,27 @@ export function loadModelProxyProviderConfig({
|
|
|
247
276
|
}
|
|
248
277
|
}
|
|
249
278
|
try {
|
|
250
|
-
const
|
|
279
|
+
const remaining = deadline - Date.now();
|
|
280
|
+
if (remaining <= 0) throw new ModelProxyUnavailableError('the desktop provider request timed out');
|
|
281
|
+
const controller = new AbortController();
|
|
282
|
+
const timer = setTimeout(
|
|
283
|
+
() => controller.abort(new ModelProxyUnavailableError('the desktop provider request timed out')),
|
|
284
|
+
remaining
|
|
285
|
+
);
|
|
286
|
+
timer.unref?.();
|
|
287
|
+
let reply;
|
|
288
|
+
try {
|
|
289
|
+
reply = await channel.request({ provider: '', method: 'providerConfig' }, { signal: controller.signal });
|
|
290
|
+
} finally {
|
|
291
|
+
clearTimeout(timer);
|
|
292
|
+
}
|
|
251
293
|
const raw = reply?.providers && typeof reply.providers === 'object' ? reply.providers : {};
|
|
252
294
|
// Defense in depth: the PC already strips secrets before sending.
|
|
253
295
|
const value = stripModelProxySecrets(raw);
|
|
254
296
|
if (providerConfigReady(reply, value)) {
|
|
255
|
-
|
|
297
|
+
// An older read may finish after a forced refresh; only the newest
|
|
298
|
+
// request may publish to the shared cache.
|
|
299
|
+
if (channel.generation === generation && _providerConfigInFlight === entry) {
|
|
256
300
|
_providerConfigCache = { at: now(), value, channel, generation };
|
|
257
301
|
}
|
|
258
302
|
return value;
|
|
@@ -268,7 +312,7 @@ export function loadModelProxyProviderConfig({
|
|
|
268
312
|
delay = Math.min(delay * 2, CONFIG_RETRY_MAX_MS);
|
|
269
313
|
}
|
|
270
314
|
})();
|
|
271
|
-
const entry = { channel, generation, promise };
|
|
315
|
+
const entry = { channel, generation, waitMs, promise };
|
|
272
316
|
_providerConfigInFlight = entry;
|
|
273
317
|
const clear = () => {
|
|
274
318
|
if (_providerConfigInFlight === entry) _providerConfigInFlight = null;
|
|
@@ -56,11 +56,6 @@ function resolveProbeState(paths, evaluate) {
|
|
|
56
56
|
return sawUnreadable ? 'unreadable' : 'absent';
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
function pushUnique(list, value) {
|
|
60
|
-
if (!value || typeof value !== 'string') return;
|
|
61
|
-
if (!list.includes(value)) list.push(value);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
59
|
// Short-TTL memo. Under simultaneous multi-agent launch, buildDefaultConfig
|
|
65
60
|
// and registry lazy-init call these probes in bursts; each probe does
|
|
66
61
|
// synchronous existsSync + readFileSync disk work. Cache the STATE per key
|
|
@@ -113,9 +108,11 @@ function memoProbe(key, paths, compute, extraSignature = '') {
|
|
|
113
108
|
}
|
|
114
109
|
|
|
115
110
|
function anthropicOAuthState() {
|
|
116
|
-
const paths = [
|
|
117
|
-
|
|
118
|
-
|
|
111
|
+
const paths = [
|
|
112
|
+
boundProviderAuthPath('anthropic-oauth') ||
|
|
113
|
+
process.env.ANTHROPIC_OAUTH_CREDENTIALS_PATH ||
|
|
114
|
+
ANTHROPIC_DEFAULT_CREDENTIALS_PATH,
|
|
115
|
+
];
|
|
119
116
|
return memoProbe('anthropic-oauth', paths, () => {
|
|
120
117
|
return resolveProbeState(paths, (docs) => {
|
|
121
118
|
const candidates = [];
|
|
@@ -176,9 +173,7 @@ function mimoOAuthState() {
|
|
|
176
173
|
process.env.MIMO_OAUTH_CREDENTIALS_PATH ||
|
|
177
174
|
join(resolvePluginData(), 'mimo-oauth.json'),
|
|
178
175
|
];
|
|
179
|
-
return memoProbe('mimo-oauth', paths, () =>
|
|
180
|
-
resolveProbeState(paths, (docs) => docs.some((own) => !!own?.apiKey))
|
|
181
|
-
);
|
|
176
|
+
return memoProbe('mimo-oauth', paths, () => resolveProbeState(paths, (docs) => docs.some((own) => !!own?.apiKey)));
|
|
182
177
|
}
|
|
183
178
|
|
|
184
179
|
function commandCodeOAuthState() {
|
|
@@ -230,7 +225,10 @@ function cursorEnvTokenFingerprint() {
|
|
|
230
225
|
}
|
|
231
226
|
|
|
232
227
|
function cursorOAuthState() {
|
|
233
|
-
|
|
228
|
+
// Match the adapter: selected account, then explicit path, then legacy file.
|
|
229
|
+
// An environment token must not authenticate a different selected account.
|
|
230
|
+
const bound = boundProviderAuthPath('cursor-oauth');
|
|
231
|
+
const paths = [bound || process.env.CURSOR_OAUTH_CREDENTIALS_PATH || join(resolvePluginData(), 'cursor-oauth.json')];
|
|
234
232
|
// The env token is the whole answer on this branch and has no file metadata
|
|
235
233
|
// behind it, so its VALUE is what the memo signature has to track: a length
|
|
236
234
|
// (or a bare present/absent flag) let a swap to an equal-length expired token
|
|
@@ -245,7 +243,7 @@ function cursorOAuthState() {
|
|
|
245
243
|
// Expiry is read by the one shared JWT reader (cursor-auth.cursorTokenExpiry),
|
|
246
244
|
// which answers 0 for a non-JWT or unparseable token — exactly the "assume
|
|
247
245
|
// usable" outcome this branch already took for those shapes.
|
|
248
|
-
if (process.env.CURSOR_ACCESS_TOKEN) {
|
|
246
|
+
if (process.env.CURSOR_ACCESS_TOKEN && !bound) {
|
|
249
247
|
const expiresAt = cursorTokenExpiry(process.env.CURSOR_ACCESS_TOKEN);
|
|
250
248
|
return expiresAt === 0 || expiresAt > Date.now() ? 'present' : 'absent';
|
|
251
249
|
}
|
|
@@ -20,7 +20,8 @@ import { normalizeCompatChatResponse } from './openai-compat-response-normalizat
|
|
|
20
20
|
import { applyCompatToolChoice, compatStreamRetryReporter } from './compat-request-policy.mjs';
|
|
21
21
|
import { ensureChatToolPairs } from './lib/wire-pairing.mjs';
|
|
22
22
|
import { xaiCacheRouting } from './openai-compat-xai.mjs';
|
|
23
|
-
import { compatRetryOptions, withCompatRetryProfile } from './openai-compat-retry-profile.mjs';
|
|
23
|
+
import { compatFirstByteWindowMs, compatRetryOptions, withCompatRetryProfile } from './openai-compat-retry-profile.mjs';
|
|
24
|
+
import { TIMEOUT_PHASE } from '../../../shared/provider-timeout-phase.mjs';
|
|
24
25
|
import { preparePdfTextForProvider } from './media-normalization.mjs';
|
|
25
26
|
import { customWireFormat, isCustomProviderName, resolveCustomReasoning } from './custom-reasoning.mjs';
|
|
26
27
|
import { geminiAcceptedTools } from './gemini-schema.mjs';
|
|
@@ -140,29 +141,39 @@ export async function sendCompatChat(provider, messages, useModel, tools, opts)
|
|
|
140
141
|
assembled = await withRetry(
|
|
141
142
|
withCompatRetryProfile(
|
|
142
143
|
provider.name,
|
|
143
|
-
refineAttemptErrors(profile, async ({ signal: attemptSignal }) => {
|
|
144
|
+
refineAttemptErrors(profile, async ({ signal: attemptSignal, firstByteTimeouts = 0 }) => {
|
|
144
145
|
try {
|
|
145
146
|
opts.onStageChange?.('requesting');
|
|
146
147
|
} catch {
|
|
147
148
|
/* heartbeat best-effort */
|
|
148
149
|
}
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
150
|
+
const windowMs = compatFirstByteWindowMs(provider.name, firstByteTimeoutMs, firstByteTimeouts);
|
|
151
|
+
let stream;
|
|
152
|
+
try {
|
|
153
|
+
stream = await withRetry(
|
|
154
|
+
({ signal: openSignal }) =>
|
|
155
|
+
provider.client.chat.completions.create(params, {
|
|
156
|
+
signal: openSignal,
|
|
157
|
+
...(requestHeaders ? { headers: requestHeaders } : {}),
|
|
158
|
+
}),
|
|
159
|
+
{
|
|
160
|
+
signal: attemptSignal,
|
|
161
|
+
// Single attempt: this inner wrapper exists only to
|
|
162
|
+
// apply the first-byte per-attempt timeout. Retry is
|
|
163
|
+
// owned by the outer withRetry — nesting retry loops
|
|
164
|
+
// here multiplied tail latency (5x5).
|
|
165
|
+
maxAttempts: 1,
|
|
166
|
+
perAttemptTimeoutMs: windowMs,
|
|
167
|
+
perAttemptLabel: `${provider.name} first byte`,
|
|
168
|
+
}
|
|
169
|
+
);
|
|
170
|
+
} catch (error) {
|
|
171
|
+
// The per-attempt window (the only timer here) expired before headers.
|
|
172
|
+
if (error?.code === 'EPROVIDERTIMEOUT' && !attemptSignal?.aborted) {
|
|
173
|
+
error.timeoutPhase = TIMEOUT_PHASE.HEADERS;
|
|
164
174
|
}
|
|
165
|
-
|
|
175
|
+
throw error;
|
|
176
|
+
}
|
|
166
177
|
try {
|
|
167
178
|
opts.onStageChange?.('streaming');
|
|
168
179
|
} catch {
|
|
@@ -181,7 +192,7 @@ export async function sendCompatChat(provider, messages, useModel, tools, opts)
|
|
|
181
192
|
// recovered leaked calls only synthesize when they name
|
|
182
193
|
// a tool actually offered to this request.
|
|
183
194
|
knownToolNames: knownToolNamesFromOpenAITools(params.tools),
|
|
184
|
-
...(profile?.firstByteTimeoutMs ? { firstByteTimeoutMs:
|
|
195
|
+
...(profile?.firstByteTimeoutMs ? { firstByteTimeoutMs: windowMs } : {}),
|
|
185
196
|
...(profile?.semanticIdleTimeoutMs ? { semanticIdleTimeoutMs: profile.semanticIdleTimeoutMs } : {}),
|
|
186
197
|
});
|
|
187
198
|
} catch (error) {
|
|
@@ -87,7 +87,9 @@ export function isIncompleteFinishReason(finishReason) {
|
|
|
87
87
|
/** Whether `finish_reason` confirms a normal end of the turn: present, not an
|
|
88
88
|
* incomplete outcome and not a gateway-reported failure (network_error/error). */
|
|
89
89
|
export function isNormalFinishReason(finishReason) {
|
|
90
|
-
return
|
|
90
|
+
return (
|
|
91
|
+
Boolean(finishReason) && !isIncompleteFinishReason(finishReason) && !failingFinishReasonError(finishReason, '')
|
|
92
|
+
);
|
|
91
93
|
}
|
|
92
94
|
|
|
93
95
|
/** Dispatch held leaked calls once a normal finish_reason confirms the turn
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
PROVIDER_SEMANTIC_IDLE_TIMEOUT_MS,
|
|
12
12
|
createTimeoutSignal,
|
|
13
13
|
} from '../stall-policy.mjs';
|
|
14
|
+
import { TIMEOUT_PHASE } from '../../../shared/provider-timeout-phase.mjs';
|
|
14
15
|
import {
|
|
15
16
|
closeCompatStream,
|
|
16
17
|
markErrorLiveTextEmitted,
|
|
@@ -86,6 +87,10 @@ export async function consumeCompatChatCompletionStream(
|
|
|
86
87
|
}
|
|
87
88
|
if (state.leakGuard.enabled) flushLeak(state);
|
|
88
89
|
} catch (err) {
|
|
90
|
+
// The first-byte window (not a caller cancellation) ended the wait for the first chunk.
|
|
91
|
+
if (!signal?.aborted && err && typeof err === 'object' && err === firstByteTimeout.signal.reason) {
|
|
92
|
+
err.timeoutPhase = TIMEOUT_PHASE.FIRST_CHUNK;
|
|
93
|
+
}
|
|
89
94
|
// Keep exposed partial text without permitting the request to replay;
|
|
90
95
|
// every mid-flight failure carries what the stream completed (a
|
|
91
96
|
// cancellation keeps the caller's own reason untouched).
|