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
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
* definitions, output style and orchestration mode.
|
|
5
5
|
*/
|
|
6
6
|
import { modelSwitchItem } from '../../../runtime/agent/orchestrator/session/transcript-restore/restore.mjs';
|
|
7
|
-
import { selectedModel
|
|
8
|
-
import { latestQuotaFailure } from '../quota-resume.mjs';
|
|
7
|
+
import { selectedModel } from '../../../session-runtime/model-route/model-switch-target.mjs';
|
|
9
8
|
import { createApiHelpers } from './shared.mjs';
|
|
10
9
|
|
|
11
10
|
// Optimistic route preview: the requested provider/model/effort/fast are
|
|
@@ -50,6 +49,36 @@ function optimisticRoutePatch(requested = {}, current = {}) {
|
|
|
50
49
|
return patch;
|
|
51
50
|
}
|
|
52
51
|
|
|
52
|
+
const SESSION_ONLY_KEYS = new Set(['provider', 'model', 'effort', 'fast', 'autoEffort']);
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* A session-only request (an agent child's route) may name just the model, just
|
|
56
|
+
* the tuning, or both. Completed here, inside the serialized route write,
|
|
57
|
+
* against the latest selected route — so a Fast-only change keeps the effort a
|
|
58
|
+
* previous write selected. `unchanged` when it asks for nothing the selected
|
|
59
|
+
* route does not already have.
|
|
60
|
+
*/
|
|
61
|
+
function completeSessionOnlyRequest(request, selected) {
|
|
62
|
+
const named = Boolean(request.provider || request.model);
|
|
63
|
+
const target = named ? request : { ...request, provider: selected.provider, model: selected.model };
|
|
64
|
+
const sameModel = target.provider === selected.provider && target.model === selected.model;
|
|
65
|
+
if (!sameModel) return { request: target, unchanged: false };
|
|
66
|
+
const unchanged =
|
|
67
|
+
Object.keys(request).every((key) => SESSION_ONLY_KEYS.has(key)) &&
|
|
68
|
+
(request.effort === undefined || request.effort === selected.effort) &&
|
|
69
|
+
(request.fast === undefined || request.fast === (selected.fast === true)) &&
|
|
70
|
+
(request.autoEffort === undefined || request.autoEffort === (selected.autoEffort !== false));
|
|
71
|
+
return {
|
|
72
|
+
unchanged,
|
|
73
|
+
request: {
|
|
74
|
+
...(selected.effort ? { effort: selected.effort } : {}),
|
|
75
|
+
fast: selected.fast === true,
|
|
76
|
+
autoEffort: selected.autoEffort !== false,
|
|
77
|
+
...target,
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
53
82
|
/** The live divider of an in-place model switch (restored from message meta
|
|
54
83
|
* after a reload); every switch path publishes it the same way. */
|
|
55
84
|
export function publishModelSwitch(bag, modelSwitch) {
|
|
@@ -76,6 +105,8 @@ export function createSessionRouteApi(bag) {
|
|
|
76
105
|
});
|
|
77
106
|
let routeWrite = null;
|
|
78
107
|
let routeSequence = 0;
|
|
108
|
+
// Whether this API (not another command) is the one holding commandBusy.
|
|
109
|
+
let routeLocked = false;
|
|
79
110
|
|
|
80
111
|
// A preset selector previews as the preset's model, never as its id.
|
|
81
112
|
const previewedRequest = (routeOpts) => {
|
|
@@ -84,86 +115,79 @@ export function createSessionRouteApi(bag) {
|
|
|
84
115
|
return target.provider ? { ...routeOpts, ...target } : routeOpts;
|
|
85
116
|
};
|
|
86
117
|
|
|
87
|
-
// Auto-compact on model change (default on): compact on the CURRENT model,
|
|
88
|
-
// whose cache and window still hold the history, before the switch. A model
|
|
89
|
-
// stopped on its quota cannot run it; the next turn's auto-compaction on the
|
|
90
|
-
// new model fits the history instead. A failure never blocks the switch.
|
|
91
|
-
const compactBeforeModelSwitch = async () => {
|
|
92
|
-
if (runtime.getCompactionSettings?.()?.onModelChange === false) return;
|
|
93
|
-
if (latestQuotaFailure(getState().items)) return;
|
|
94
|
-
if (typeof bag.compactBeforeModelSwitch !== 'function') return;
|
|
95
|
-
set({
|
|
96
|
-
commandStatus: { active: true, verb: 'Compacting conversation', startedAt: Date.now(), mode: 'compacting' },
|
|
97
|
-
});
|
|
98
|
-
flushEmitImmediate();
|
|
99
|
-
try {
|
|
100
|
-
await bag.compactBeforeModelSwitch();
|
|
101
|
-
} catch {
|
|
102
|
-
/* the switch goes ahead; next-turn auto-compaction fits the window */
|
|
103
|
-
} finally {
|
|
104
|
-
set({ commandStatus: null });
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
|
|
108
118
|
const setRoute = async (opts) => {
|
|
109
|
-
if (getState().commandBusy && !routeWrite) return false;
|
|
110
119
|
const routeOpts = opts && typeof opts === 'object' ? opts : {};
|
|
111
|
-
//
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
// A running turn keeps the route it started on.
|
|
115
|
-
if (switchesModel && getState().busy) {
|
|
116
|
-
throw new Error('The model cannot change while a response is running. Try again when it finishes.');
|
|
117
|
-
}
|
|
118
|
-
// Any route change supersedes waiting for the old route's quota reset.
|
|
119
|
-
bag.supersedeQuotaResume?.(getState().sessionId);
|
|
120
|
+
// All model pickers save a selection for the conversation's next turn; a
|
|
121
|
+
// running turn keeps the session model it started on. A selection is never
|
|
122
|
+
// refused: another command's lock neither blocks it nor is released by it.
|
|
120
123
|
const token = ++routeSequence;
|
|
121
124
|
const previousWrite = routeWrite;
|
|
125
|
+
// The session generation this selection was made under. The write below
|
|
126
|
+
// waits behind earlier ones, so "current" is never read later: the runtime
|
|
127
|
+
// validates this token before every route side effect, and `settle` below
|
|
128
|
+
// is the only place the display is touched once the write has started.
|
|
129
|
+
const originGeneration = runtime.sessionGeneration;
|
|
130
|
+
const owned = () => runtime.sessionGeneration === originGeneration;
|
|
122
131
|
const preview = optimisticRoutePatch(previewedRequest(routeOpts), getState());
|
|
123
132
|
// Preview immediately, serialize persistence without dropping a later
|
|
124
133
|
// click. Earlier completions cannot replace the newest visible choice.
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
set({ commandBusy: true, ...(switchesModel ? {} : preview || {}) });
|
|
134
|
+
if (!getState().commandBusy) routeLocked = true;
|
|
135
|
+
set({ ...(routeLocked ? { commandBusy: true } : {}), ...(preview || {}) });
|
|
128
136
|
flushEmitImmediate();
|
|
129
137
|
const write = (async () => {
|
|
130
138
|
if (previousWrite) await previousWrite.catch(() => {});
|
|
131
139
|
const previousRoute = routeState();
|
|
140
|
+
// A stale selection only republishes the route that is actually
|
|
141
|
+
// selected; it never restores or announces its own session's state.
|
|
142
|
+
const settle = ({ failed = false, sync = false, modelSwitch = null } = {}) => {
|
|
143
|
+
const stillOwned = owned();
|
|
144
|
+
if (stillOwned) publishModelSwitch(bag, modelSwitch);
|
|
145
|
+
// A newer selection publishes the final route itself.
|
|
146
|
+
if (token !== routeSequence) return;
|
|
147
|
+
if (stillOwned && failed) {
|
|
148
|
+
if (preview) set({ ...previousRoute, stats: { ...getState().stats } });
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (stillOwned && sync) syncContextStats({ allowEstimated: true });
|
|
152
|
+
publishRoute();
|
|
153
|
+
};
|
|
132
154
|
try {
|
|
133
|
-
//
|
|
134
|
-
// one is initialized in place. Either way an established
|
|
135
|
-
// conversation follows the user's choice in place.
|
|
155
|
+
// Keep the durable session address while deferring route application.
|
|
136
156
|
const applyToCurrentSession = routeOpts.applyToCurrentSession === true;
|
|
137
|
-
const keepMainModel = routeOpts.keepMainModel
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if (
|
|
144
|
-
|
|
145
|
-
|
|
157
|
+
const keepMainModel = routeOpts.keepMainModel !== false;
|
|
158
|
+
const sessionOnly = routeOpts.sessionOnly === true;
|
|
159
|
+
const { applyToCurrentSession: _drop, keepMainModel: _keep, sessionOnly: _scope, ...requested } = routeOpts;
|
|
160
|
+
let nextRoute = requested;
|
|
161
|
+
if (sessionOnly) {
|
|
162
|
+
const completed = completeSessionOnlyRequest(requested, previousRoute);
|
|
163
|
+
if (completed.unchanged) {
|
|
164
|
+
// An earlier failed write skipped its rollback because this one is
|
|
165
|
+
// newer, so the shown route may still be that write's preview.
|
|
166
|
+
settle();
|
|
167
|
+
return previousRoute;
|
|
146
168
|
}
|
|
169
|
+
nextRoute = completed.request;
|
|
147
170
|
}
|
|
148
171
|
const resolvedRoute = await runtime.setRoute(nextRoute, {
|
|
149
172
|
applyToCurrentSession,
|
|
150
173
|
keepMainModel,
|
|
174
|
+
...(sessionOnly ? { sessionOnly } : {}),
|
|
175
|
+
...(originGeneration !== undefined ? { originGeneration } : {}),
|
|
151
176
|
switchEstablished: true,
|
|
177
|
+
deferUntilNextTurn: true,
|
|
178
|
+
});
|
|
179
|
+
settle({
|
|
180
|
+
sync: applyToCurrentSession || Boolean(resolvedRoute?.modelSwitch),
|
|
181
|
+
modelSwitch: resolvedRoute?.modelSwitch,
|
|
152
182
|
});
|
|
153
|
-
if (token === routeSequence) {
|
|
154
|
-
if (applyToCurrentSession || resolvedRoute?.modelSwitch) syncContextStats({ allowEstimated: true });
|
|
155
|
-
publishRoute();
|
|
156
|
-
}
|
|
157
|
-
publishModelSwitch(bag, resolvedRoute?.modelSwitch);
|
|
158
183
|
return resolvedRoute;
|
|
159
184
|
} catch (error) {
|
|
160
|
-
|
|
161
|
-
set({ ...previousRoute, stats: { ...getState().stats } });
|
|
162
|
-
}
|
|
185
|
+
settle({ failed: true });
|
|
163
186
|
throw error;
|
|
164
187
|
} finally {
|
|
165
188
|
if (token === routeSequence) {
|
|
166
|
-
set({ commandBusy: false });
|
|
189
|
+
if (routeLocked) set({ commandBusy: false });
|
|
190
|
+
routeLocked = false;
|
|
167
191
|
// Publish the resolved route (or rollback) before an RPC reply
|
|
168
192
|
// reads getState(), even while the display-frame clock is busy.
|
|
169
193
|
flushEmitImmediate();
|
|
@@ -29,9 +29,9 @@ export function createSessionSettingsApi(bag) {
|
|
|
29
29
|
|
|
30
30
|
return {
|
|
31
31
|
// A model selector (/model, a preset) is the user's model choice like any
|
|
32
|
-
// picker selection: the route surface
|
|
33
|
-
//
|
|
34
|
-
//
|
|
32
|
+
// picker selection: the route surface saves it for the conversation's
|
|
33
|
+
// next turn (a running turn keeps its model) and applies it there. Never
|
|
34
|
+
// refused: another command's lock does not block a selection.
|
|
35
35
|
setModel: async (m) => (await bag.setSessionRoute({ model: m })) !== false,
|
|
36
36
|
setEffort: withCommandLock(
|
|
37
37
|
async (value) => {
|
|
@@ -23,8 +23,7 @@
|
|
|
23
23
|
* (expectedRevision: WORKTREE_REVISION_CONFLICT when the session moved on)
|
|
24
24
|
* (WORKTREE_REMOVAL_INCOMPLETE: partly removed; call again to finish)
|
|
25
25
|
* listWorktrees() → every managed worktree with its retention
|
|
26
|
-
* pruneWorktrees() → reconcile report (never a retained worktree)
|
|
27
|
-
*/
|
|
26
|
+
* pruneWorktrees() → reconcile report (never a retained worktree) */
|
|
28
27
|
import { worktreeError } from '../../../runtime/shared/worktrees/contract.mjs';
|
|
29
28
|
|
|
30
29
|
/** Session actions of the Lead worktree feature (settings live in settings.mjs). */
|
|
@@ -34,6 +33,8 @@ export const SESSION_WORKTREE_ACTIONS = Object.freeze([
|
|
|
34
33
|
'selectBranch',
|
|
35
34
|
'selectProjectBranch',
|
|
36
35
|
'mergeProjectBranch',
|
|
36
|
+
'inspectProjectBranch',
|
|
37
|
+
'manageProjectBranch',
|
|
37
38
|
'requestWorktree',
|
|
38
39
|
'mergeWorkspace',
|
|
39
40
|
'removeWorktree',
|
|
@@ -196,10 +196,8 @@ export function createAutoClearOps(bag, { reset, kickDrain }) {
|
|
|
196
196
|
|
|
197
197
|
// Same eligibility as a user submit, run before a completion wake turn so a
|
|
198
198
|
// cold cache after a long idle is compacted first. Never throws: a skipped or
|
|
199
|
-
// failed auto-clear must still let the wake run.
|
|
200
|
-
// surface's owner leaves compaction to that owner.
|
|
199
|
+
// failed auto-clear must still let the wake run.
|
|
201
200
|
async function autoClearBeforeWake() {
|
|
202
|
-
if (bag.liveShareMirroring?.() === true) return false;
|
|
203
201
|
try {
|
|
204
202
|
return await autoClearBeforeSubmit({ ignorePending: true });
|
|
205
203
|
} catch {
|
|
@@ -89,6 +89,8 @@ export function turnOptionsForBatch(batch, steering) {
|
|
|
89
89
|
return {
|
|
90
90
|
promptSource: batchPromptSource(batch),
|
|
91
91
|
retryFailedTurn: batch[0]?.retryFailedTurn === true,
|
|
92
|
+
retryTurnId: batch[0]?.retryTurnId || null,
|
|
93
|
+
retryAttemptId: batch[0]?.retryAttemptId || null,
|
|
92
94
|
displayText: batch
|
|
93
95
|
.map((entry) => entry.text)
|
|
94
96
|
.filter((text) => String(text || '').trim())
|
|
@@ -148,7 +150,7 @@ export function createDrainLoop(
|
|
|
148
150
|
// matching message under its own lock).
|
|
149
151
|
function rewindFailedTurnRows(batch) {
|
|
150
152
|
const entry = batch[0];
|
|
151
|
-
if (entry?.retryFailedTurn !== true) return;
|
|
153
|
+
if (entry?.retryFailedTurn !== true || entry.retryTurnId) return;
|
|
152
154
|
const rewound = rewoundFailedTurnItems(getState().items, entry.text);
|
|
153
155
|
if (!rewound) return;
|
|
154
156
|
set({
|
|
@@ -217,7 +219,7 @@ export function createDrainLoop(
|
|
|
217
219
|
// but so do setModel/newSession/resume/etc). Running a turn concurrently
|
|
218
220
|
// with a command that swaps or reroutes the live session is a race; the
|
|
219
221
|
// commandBusy-release hook re-kicks drain once the command finishes.
|
|
220
|
-
if (flags.autoClearRunning || getState().commandBusy) {
|
|
222
|
+
if (flags.autoClearRunning || flags.quotaResumePending || getState().commandBusy) {
|
|
221
223
|
scheduleBlockedDrainRetry();
|
|
222
224
|
return;
|
|
223
225
|
}
|
|
@@ -253,7 +255,7 @@ export function createDrainLoop(
|
|
|
253
255
|
// its pre-compaction, a reset) runs before the next turn starts. The
|
|
254
256
|
// finally below re-enters drain(), which waits on the same gate, and
|
|
255
257
|
// the commandBusy release re-kicks the queue.
|
|
256
|
-
if (flags.autoClearRunning || getState().commandBusy) return;
|
|
258
|
+
if (flags.autoClearRunning || flags.quotaResumePending || getState().commandBusy) return;
|
|
257
259
|
// Drain one priority/mode bucket at a time (unified command queue):
|
|
258
260
|
// prompt steering stays editable and task notifications stay
|
|
259
261
|
// non-editable but model-visible.
|
|
@@ -331,7 +333,7 @@ export function createDrainLoop(
|
|
|
331
333
|
submissions.remember(submissionId);
|
|
332
334
|
pending.push(entry);
|
|
333
335
|
const needsDurableSteering =
|
|
334
|
-
(getState().busy || getState().commandBusy || flags.autoClearRunning) &&
|
|
336
|
+
(getState().busy || getState().commandBusy || flags.autoClearRunning || flags.quotaResumePending) &&
|
|
335
337
|
steering.shouldMirrorSteeringEntry(entry);
|
|
336
338
|
const persistence = needsDurableSteering ? appendTuiSteeringPersist(steering.leadSessionId(), entry) : null;
|
|
337
339
|
if (isQueuedEntryVisible(entry)) {
|
|
@@ -49,5 +49,7 @@ export function makeQueueEntry(text, options = {}, nextId) {
|
|
|
49
49
|
// Retry of a failed turn: the transcript and the session rewind the
|
|
50
50
|
// failed turn's unanswered prompt before this entry runs.
|
|
51
51
|
retryFailedTurn: options.retryFailedTurn === true,
|
|
52
|
+
retryTurnId: options.retryTurnId || null,
|
|
53
|
+
retryAttemptId: options.retryAttemptId || null,
|
|
52
54
|
};
|
|
53
55
|
}
|
|
@@ -39,10 +39,11 @@ export function createTakeEntriesOps({ pending, pendingNotificationKeys, removeQ
|
|
|
39
39
|
(entry.mode || 'prompt') === targetMode &&
|
|
40
40
|
queuePriorityValue(entry.priority) === bestPriority
|
|
41
41
|
) {
|
|
42
|
+
if (batch.length > 0 && entry.retryTurnId) break;
|
|
42
43
|
batch.push(entry);
|
|
43
44
|
pending.splice(i, 1);
|
|
44
45
|
if (entry.mode === 'task-notification' && entry.key) pendingNotificationKeys.delete(entry.key);
|
|
45
|
-
if (batch.length >= limit) break;
|
|
46
|
+
if (entry.retryTurnId || batch.length >= limit) break;
|
|
46
47
|
} else {
|
|
47
48
|
i += 1;
|
|
48
49
|
}
|
|
@@ -14,7 +14,7 @@ import { createTakeEntriesOps } from './queue/take-entries.mjs';
|
|
|
14
14
|
|
|
15
15
|
// Submission-id memory for idempotent re-delivery. A prompt can legitimately
|
|
16
16
|
// reach this queue TWICE when its transport retries across a failed response
|
|
17
|
-
// (daemon view retry
|
|
17
|
+
// (daemon view retry after a missing ack). The id
|
|
18
18
|
// the surface minted is the identity of the message, so a repeat of an id we
|
|
19
19
|
// already queued is dropped instead of posting the prompt twice.
|
|
20
20
|
const SUBMISSION_ID_MEMORY = 256;
|
|
@@ -12,8 +12,14 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
|
|
|
12
12
|
|
|
13
13
|
function normalizeToolApprovalRequest(input = {}, id = nextId()) {
|
|
14
14
|
const now = Date.now();
|
|
15
|
+
// An explicit `timeoutMs: null` means no wait limit (no timer, no expiry);
|
|
16
|
+
// any other missing/invalid value falls back to the session default.
|
|
15
17
|
const requestTimeoutMs =
|
|
16
|
-
|
|
18
|
+
input?.timeoutMs === null
|
|
19
|
+
? null
|
|
20
|
+
: Number.isFinite(Number(input?.timeoutMs)) && Number(input.timeoutMs) > 0
|
|
21
|
+
? Number(input.timeoutMs)
|
|
22
|
+
: timeoutMs;
|
|
17
23
|
return {
|
|
18
24
|
id,
|
|
19
25
|
name: String(input?.name || input?.tool_name || 'tool'),
|
|
@@ -25,14 +31,14 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
|
|
|
25
31
|
reason: String(input?.reason || input?.message || 'approval requested by hook').trim(),
|
|
26
32
|
requestedAt: now,
|
|
27
33
|
timeoutMs: requestTimeoutMs,
|
|
28
|
-
expiresAt: now + requestTimeoutMs,
|
|
34
|
+
expiresAt: requestTimeoutMs === null ? null : now + requestTimeoutMs,
|
|
29
35
|
};
|
|
30
36
|
}
|
|
31
37
|
// Every request expires from ITS OWN requestedAt, queued or active. Arming
|
|
32
38
|
// the timer only on presentation let a queued request sit past expiresAt
|
|
33
39
|
// (retaining its promise and surfacing an obsolete approval later).
|
|
34
40
|
function armToolApprovalTimeout(entry) {
|
|
35
|
-
if (!entry || entry.timer) return;
|
|
41
|
+
if (!entry || entry.timer || entry.request?.expiresAt === null) return;
|
|
36
42
|
const remainingMs = Math.max(0, Number(entry.request?.expiresAt || 0) - Date.now());
|
|
37
43
|
entry.timer = setTimeout(() => {
|
|
38
44
|
finishToolApproval(entry.id, false, 'approval timed out');
|
|
@@ -42,10 +48,13 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
|
|
|
42
48
|
// Settle one entry: drop its timeout, then hand the waiter its answer. The
|
|
43
49
|
// resolve stays guarded — a waiter whose caller already went away must never
|
|
44
50
|
// take the rest of the queue down with it.
|
|
45
|
-
function settleToolApproval(entry, approved, reason, answers) {
|
|
51
|
+
function settleToolApproval(entry, approved, reason, answers, reply) {
|
|
46
52
|
if (entry?.timer) clearTimeout(entry.timer);
|
|
53
|
+
const result = { approved, reason };
|
|
54
|
+
if (answers !== undefined) result.answers = answers;
|
|
55
|
+
if (reply !== undefined) result.reply = reply;
|
|
47
56
|
try {
|
|
48
|
-
entry.resolve(
|
|
57
|
+
entry.resolve(result);
|
|
49
58
|
} catch {}
|
|
50
59
|
}
|
|
51
60
|
function presentNextToolApproval() {
|
|
@@ -59,7 +68,7 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
|
|
|
59
68
|
armToolApprovalTimeout(entry);
|
|
60
69
|
set({ toolApproval: entry.request });
|
|
61
70
|
}
|
|
62
|
-
function finishToolApproval(id, approved, reason = '', device = '', answers = undefined) {
|
|
71
|
+
function finishToolApproval(id, approved, reason = '', device = '', answers = undefined, reply = undefined) {
|
|
63
72
|
const targetId = String(id || '');
|
|
64
73
|
if (activeToolApproval && activeToolApproval.id === targetId) {
|
|
65
74
|
const entry = activeToolApproval;
|
|
@@ -70,14 +79,14 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
|
|
|
70
79
|
? { id: targetId, approved: approved === true, device: String(device), at: Date.now() }
|
|
71
80
|
: null;
|
|
72
81
|
set({ toolApproval: null, toolApprovalResult });
|
|
73
|
-
settleToolApproval(entry, approved === true, String(reason || ''), answers);
|
|
82
|
+
settleToolApproval(entry, approved === true, String(reason || ''), answers, reply);
|
|
74
83
|
presentNextToolApproval();
|
|
75
84
|
return true;
|
|
76
85
|
}
|
|
77
86
|
const index = toolApprovalQueue.findIndex((entry) => entry.id === targetId);
|
|
78
87
|
if (index >= 0) {
|
|
79
88
|
const [entry] = toolApprovalQueue.splice(index, 1);
|
|
80
|
-
settleToolApproval(entry, approved === true, String(reason || ''), answers);
|
|
89
|
+
settleToolApproval(entry, approved === true, String(reason || ''), answers, reply);
|
|
81
90
|
return true;
|
|
82
91
|
}
|
|
83
92
|
return false;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* that lets a host prove a longer text is an append of the same stream.
|
|
5
5
|
*/
|
|
6
6
|
// Non-enumerable so the marker never enters persisted transcript items,
|
|
7
|
-
//
|
|
7
|
+
// wire JSON, or renderer snapshots. The desktop host reads the shared
|
|
8
8
|
// Symbol.for key before cloning and uses it to prove that a growing text is
|
|
9
9
|
// an append, avoiding an O(total text) startsWith check on every frame.
|
|
10
10
|
const streamingTailTextEpochKey = Symbol.for('mixdog.streaming-tail-text-epoch');
|
|
@@ -99,11 +99,9 @@ function normalizePendingStore(raw) {
|
|
|
99
99
|
// FOREIGN bucket. This file is SHARED with the runtime/manager pending
|
|
100
100
|
// -message spool, and every TUI write passes the whole store through
|
|
101
101
|
// here. Flattening those rows to plain strings destroyed id,
|
|
102
|
-
// enqueuedAt, options, structured content
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
// this process does not own are copied through UNCHANGED (array copy
|
|
106
|
-
// only, so nothing here can alias-mutate them either).
|
|
102
|
+
// enqueuedAt, options, structured content and the notification markers.
|
|
103
|
+
// Rows this process does not own are copied through UNCHANGED (array
|
|
104
|
+
// copy only, so nothing here can alias-mutate them either).
|
|
107
105
|
out.sessions[sid] = value.slice();
|
|
108
106
|
const foreignTouched = Number(touchedRaw[sid]);
|
|
109
107
|
// Carry an existing stamp only: inventing one would reset the runtime's
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// The lead turn's quiet-time cue: polls the runtime's turn liveness while the
|
|
2
|
+
// turn runs and publishes `spinner.quiet` ({ since, wait, tool?, warnMs })
|
|
3
|
+
// once the turn has gone QUIET_PROGRESS_CUE_MS without counted progress, and
|
|
4
|
+
// clears it when progress resumes. The value is frozen for a whole silence, so
|
|
5
|
+
// a silence costs two publications, never one per tick. Display only.
|
|
6
|
+
import { displayProgressStage, quietProgress, lastProgressAt } from '../../runtime/shared/quiet-progress.mjs';
|
|
7
|
+
import { resolveAgentStallThresholds } from '../../runtime/agent/orchestrator/stall-policy.mjs';
|
|
8
|
+
|
|
9
|
+
const QUIET_POLL_MS = 1_000;
|
|
10
|
+
|
|
11
|
+
/** The lead's stall-watchdog warn point, in ms. */
|
|
12
|
+
export function leadStallWarnMs() {
|
|
13
|
+
return resolveAgentStallThresholds('lead').warn * 1000;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function sameQuiet(left, right) {
|
|
17
|
+
if (!left || !right) return !left && !right;
|
|
18
|
+
return left.since === right.since && left.wait === right.wait && left.tool === right.tool;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** The quiet state a liveness snapshot implies at `now` (null: not quiet). */
|
|
22
|
+
export function turnQuietState(liveness, now, warnMs) {
|
|
23
|
+
if (!liveness || typeof liveness !== 'object' || typeof liveness.then === 'function') return null;
|
|
24
|
+
const quiet = quietProgress({
|
|
25
|
+
progressAt: lastProgressAt(liveness),
|
|
26
|
+
stage: displayProgressStage(liveness),
|
|
27
|
+
tool: liveness.currentTool,
|
|
28
|
+
now,
|
|
29
|
+
});
|
|
30
|
+
return quiet ? { ...quiet, warnMs } : null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function startQuietWatch({ runtime, getState, set, isCurrentTurn, warnMs = leadStallWarnMs() }) {
|
|
34
|
+
const timer = setInterval(() => {
|
|
35
|
+
if (!isCurrentTurn()) {
|
|
36
|
+
clearInterval(timer);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const spinner = getState().spinner;
|
|
40
|
+
if (!spinner) return;
|
|
41
|
+
let liveness = null;
|
|
42
|
+
try {
|
|
43
|
+
liveness = runtime?.getTurnLiveness?.() ?? null;
|
|
44
|
+
} catch {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const next = turnQuietState(liveness, Date.now(), warnMs);
|
|
48
|
+
if (sameQuiet(spinner.quiet ?? null, next)) return;
|
|
49
|
+
set({ spinner: { ...spinner, quiet: next } });
|
|
50
|
+
}, QUIET_POLL_MS);
|
|
51
|
+
timer.unref?.();
|
|
52
|
+
return () => clearInterval(timer);
|
|
53
|
+
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// scalars); every function here takes it as its first argument.
|
|
7
7
|
import { TUI_FRAME_MS, yieldToRenderer } from './render-timing.mjs';
|
|
8
8
|
import { retryStatusLine } from '../../runtime/shared/err-text.mjs';
|
|
9
|
+
import { MODEL_THINKING_STAGE } from '../../runtime/shared/quiet-progress.mjs';
|
|
9
10
|
import { newTranscriptMessageId } from '../../runtime/shared/transcript-metadata.mjs';
|
|
10
11
|
|
|
11
12
|
// Share Ink's exact 120fps cadence with the frame-batched store. A separate
|
|
@@ -590,9 +591,12 @@ export async function applyStageChange(stream, stage, detail = null) {
|
|
|
590
591
|
await yieldToRenderer();
|
|
591
592
|
return;
|
|
592
593
|
}
|
|
593
|
-
if (value === 'requesting' || value === 'streaming'
|
|
594
|
+
if (value === 'requesting' || value === 'streaming' || value === MODEL_THINKING_STAGE) {
|
|
595
|
+
stream.compactingActive = false;
|
|
596
|
+
}
|
|
594
597
|
let mode = null;
|
|
595
598
|
if (value === 'requesting') mode = 'requesting';
|
|
599
|
+
else if (value === MODEL_THINKING_STAGE) mode = 'model-thinking';
|
|
596
600
|
else if (value === 'streaming') mode = getState().spinner.thinking ? 'thinking' : 'responding';
|
|
597
601
|
if (!mode || getState().spinner.mode === mode) return;
|
|
598
602
|
set({ spinner: { ...getState().spinner, mode } });
|
package/src/tui/session/turn.mjs
CHANGED
|
@@ -7,15 +7,20 @@
|
|
|
7
7
|
* turn record below that finalization publishes as the turndone item.
|
|
8
8
|
*/
|
|
9
9
|
import { applyUsageDelta } from './session-stats.mjs';
|
|
10
|
+
import {
|
|
11
|
+
createTranscriptRouteMetadata,
|
|
12
|
+
transcriptRouteMetadataFields,
|
|
13
|
+
} from '../../runtime/shared/transcript-metadata.mjs';
|
|
14
|
+
import { publishModelSwitch } from './session-api/routes.mjs';
|
|
10
15
|
import { compactEventLabel } from '../../runtime/shared/compact-event-label.mjs';
|
|
11
16
|
import { pickVerb, pickDoneVerb, compactEventDetail } from './labels.mjs';
|
|
12
|
-
import {
|
|
13
|
-
import { errText, isCancelLikeError } from '../../runtime/shared/err-text.mjs';
|
|
17
|
+
import { isCancelLikeError } from '../../runtime/shared/err-text.mjs';
|
|
14
18
|
import { preserveGoalStateAfterTurn } from './goal-turn-state.mjs';
|
|
15
19
|
export { preserveGoalStateAfterTurn } from './goal-turn-state.mjs';
|
|
16
20
|
export { transcriptToolCallDisplayMode } from './turn-tool-cards.mjs';
|
|
17
|
-
import { isRejected429
|
|
21
|
+
import { isRejected429 } from '../../runtime/shared/error-presentation.mjs';
|
|
18
22
|
import { QUOTA_KINDS, providerErrorKind } from '../../runtime/agent/orchestrator/providers/provider-error-kind.mjs';
|
|
23
|
+
import { turnFailureRecord } from '../../runtime/agent/orchestrator/session/turn-failure.mjs';
|
|
19
24
|
import { registerTaskWaitSteeringCheck } from '../../runtime/agent/orchestrator/session/task-wait-control.mjs';
|
|
20
25
|
import { promptDisplayText, STEERING_SUPPRESSED_DISPLAY } from './queue-helpers.mjs';
|
|
21
26
|
import { yieldToRenderer } from './render-timing.mjs';
|
|
@@ -47,6 +52,7 @@ import {
|
|
|
47
52
|
collectClosingCards,
|
|
48
53
|
startLiveTail,
|
|
49
54
|
} from './turn-tool-cards.mjs';
|
|
55
|
+
import { startQuietWatch } from './turn-quiet.mjs';
|
|
50
56
|
|
|
51
57
|
// A usage limit is exactly a spent quota, a plan-gated feature or a billing
|
|
52
58
|
// refusal; overloads, rate limits and server faults recover by waiting.
|
|
@@ -94,6 +100,13 @@ function streamingTailStore({ updateStreamingTail, settleStreamingTail, clearStr
|
|
|
94
100
|
|
|
95
101
|
// The turn record: identity, transcript metadata, and the outcome fields
|
|
96
102
|
// finalization publishes.
|
|
103
|
+
export function applyTurnRouteMetadata(ctx, session) {
|
|
104
|
+
const metadata = transcriptRouteMetadataFields(createTranscriptRouteMetadata(session));
|
|
105
|
+
Object.assign(ctx.turn.transcriptMeta, metadata);
|
|
106
|
+
Object.assign(ctx.turn.routeMeta, metadata);
|
|
107
|
+
for (const id of ctx.turn.submittedIds) ctx.patchItem(id, metadata);
|
|
108
|
+
}
|
|
109
|
+
|
|
97
110
|
function beginTurn({ flags, getState, transcriptRouteMetadata }, options) {
|
|
98
111
|
const index = getState().stats.turns || 0;
|
|
99
112
|
const startedAt = Date.now();
|
|
@@ -102,6 +115,7 @@ function beginTurn({ flags, getState, transcriptRouteMetadata }, options) {
|
|
|
102
115
|
...(flags.pendingTranscriptMeta || transcriptRouteMetadata?.(startedAt) || { at: startedAt }),
|
|
103
116
|
...(options.transcriptMeta && typeof options.transcriptMeta === 'object' ? options.transcriptMeta : {}),
|
|
104
117
|
completionVerb,
|
|
118
|
+
attemptId: globalThis.crypto.randomUUID(),
|
|
105
119
|
};
|
|
106
120
|
flags.pendingTranscriptMeta = null;
|
|
107
121
|
// The prompt's own time and stable id stay on the prompt row.
|
|
@@ -457,34 +471,13 @@ export function failTurn(ctx, error) {
|
|
|
457
471
|
}
|
|
458
472
|
turn.failed = true;
|
|
459
473
|
cards.aggregates.finalizeToolHeaders();
|
|
460
|
-
|
|
461
|
-
const errorKind = providerErrorKind(error, { legacyQuotaWording: true });
|
|
474
|
+
const record = turnFailureRecord(error, { provider: turn.routeMeta?.provider, model: turn.routeMeta?.model });
|
|
462
475
|
// The UI reads this descriptor instead of re-parsing the error text.
|
|
463
|
-
turn.errorKind =
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
resetAt: errorKind.resetAt,
|
|
469
|
-
};
|
|
470
|
-
turn.usageLimited = isUsageLimitError(error, errorKind);
|
|
471
|
-
const exhausted = error?.quotaExhausted;
|
|
472
|
-
// Quota metadata: the pool's validated exhaustion, or a spent quota whose
|
|
473
|
-
// provider named the real reset time.
|
|
474
|
-
const resetKnown = errorKind.kind === 'quota_exhausted' && Number.isFinite(errorKind.resetAt);
|
|
475
|
-
if ((exhausted && typeof exhausted === 'object') || resetKnown) {
|
|
476
|
-
const source = exhausted && typeof exhausted === 'object' ? exhausted : {};
|
|
477
|
-
let resetAt = null;
|
|
478
|
-
if (Number.isFinite(source.resetAt)) resetAt = source.resetAt;
|
|
479
|
-
else if (Number.isFinite(errorKind.resetAt)) resetAt = errorKind.resetAt;
|
|
480
|
-
turn.quota = {
|
|
481
|
-
provider: String(source.provider || turn.routeMeta?.provider || ''),
|
|
482
|
-
model: String(source.model || turn.routeMeta?.model || ''),
|
|
483
|
-
resetAt,
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
turn.failureDetail = toolErrorDisplay(error, 'turn').replace(/^Error:\s*/i, '');
|
|
487
|
-
turn.failureDiagnostic = safeErrorDetails(errText(error));
|
|
476
|
+
turn.errorKind = record.errorKind;
|
|
477
|
+
turn.usageLimited = isUsageLimitError(error, record.providerKind);
|
|
478
|
+
if (record.quota) turn.quota = record.quota;
|
|
479
|
+
turn.failureDetail = record.detail;
|
|
480
|
+
turn.failureDiagnostic = record.errorDetails;
|
|
488
481
|
pushNotice(turn.failureDetail, 'error', { owner: 'transcript' });
|
|
489
482
|
}
|
|
490
483
|
|
|
@@ -683,7 +676,12 @@ export function createRunTurn(bag) {
|
|
|
683
676
|
routeMeta: turn.routeMeta,
|
|
684
677
|
sealToolBlock: cards.aggregates.clearAggregateContinuation,
|
|
685
678
|
});
|
|
686
|
-
const
|
|
679
|
+
const stopToolTail = startLiveTail(cards);
|
|
680
|
+
const stopQuietWatch = startQuietWatch({ runtime, getState, set, isCurrentTurn });
|
|
681
|
+
const stopLiveTail = () => {
|
|
682
|
+
stopToolTail();
|
|
683
|
+
stopQuietWatch();
|
|
684
|
+
};
|
|
687
685
|
const ctx = {
|
|
688
686
|
...bag,
|
|
689
687
|
bag,
|
|
@@ -703,11 +701,20 @@ export function createRunTurn(bag) {
|
|
|
703
701
|
submittedAt: options.submittedAt,
|
|
704
702
|
promptSource: options.promptSource,
|
|
705
703
|
retryFailedTurn: options.retryFailedTurn === true,
|
|
704
|
+
retryTurnId: options.retryTurnId,
|
|
705
|
+
retryAttemptId: options.retryAttemptId,
|
|
706
706
|
transcriptMeta: turn.transcriptMeta,
|
|
707
707
|
context: options.context || null,
|
|
708
708
|
...turnHandlers(ctx),
|
|
709
709
|
...toolHandlers(ctx),
|
|
710
710
|
...streamHandlers(ctx),
|
|
711
|
+
onRouteApplied: (session) => {
|
|
712
|
+
if (isCurrentTurn()) applyTurnRouteMetadata(ctx, session);
|
|
713
|
+
},
|
|
714
|
+
onModelSwitch: (boundary) => {
|
|
715
|
+
if (!isCurrentTurn()) return;
|
|
716
|
+
publishModelSwitch(bag, boundary);
|
|
717
|
+
},
|
|
711
718
|
});
|
|
712
719
|
if (!isCurrentTurn()) turn.cancelled = true;
|
|
713
720
|
else completeTurn(ctx, result, session);
|