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
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// throttled crash-recovery checkpoint sidecar, and the close snapshot that
|
|
4
4
|
// canonicalizes the transcript when the turn is interrupted.
|
|
5
5
|
import { captureTurnCheckpointContextState, createTurnCheckpointRecorder } from './turn-checkpoint.mjs';
|
|
6
|
+
import { finalizeTurnInterruptionSnapshot } from './turn-interruption.mjs';
|
|
6
7
|
|
|
7
8
|
// Coalescing window for streaming-delta flushes. Each flush journals only the
|
|
8
9
|
// delta since the previous one, so the window just bounds syscalls.
|
|
@@ -83,28 +84,46 @@ export function createTurnCheckpointScheduler({ sessionId, generation, turnToken
|
|
|
83
84
|
};
|
|
84
85
|
}
|
|
85
86
|
|
|
87
|
+
// The live-session fields a staged close snapshot rewrites.
|
|
88
|
+
const CLOSE_SNAPSHOT_SESSION_FIELDS = [
|
|
89
|
+
'liveTurnMessages',
|
|
90
|
+
'_providerPrefixGuardState',
|
|
91
|
+
'messages',
|
|
92
|
+
'activeTurnCheckpoint',
|
|
93
|
+
'providerState',
|
|
94
|
+
'updatedAt',
|
|
95
|
+
'lastUsedAt',
|
|
96
|
+
];
|
|
97
|
+
|
|
86
98
|
/** closeSession is synchronous and generation-first by design. This turn-local
|
|
87
99
|
* hook lets it canonicalize the in-flight transcript before
|
|
88
100
|
* bumpSessionGeneration()/markSessionClosed() writes the disk snapshot and
|
|
89
101
|
* invalidates the ordinary cancellation cleanup save. Finalizes at most once;
|
|
90
|
-
* later calls return the same snapshot.
|
|
102
|
+
* later calls return the same snapshot.
|
|
103
|
+
*
|
|
104
|
+
* `prepare.tentative(reason)` stages the snapshot on the live session only:
|
|
105
|
+
* the checkpoint scheduler and the interruption tracker keep running until
|
|
106
|
+
* `commit()`, and `rollback()` restores the live session exactly, so a close
|
|
107
|
+
* whose lifecycle barrier is refused leaves the turn as it was. */
|
|
91
108
|
export function createCloseSnapshot({ turn, interruption, checkpoint, runtime }) {
|
|
92
109
|
let snapshot = null;
|
|
93
|
-
|
|
94
|
-
if (snapshot) return snapshot;
|
|
110
|
+
const stage = (abortReason) => {
|
|
95
111
|
const session = turn.session;
|
|
96
112
|
if (!session) return null;
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
interruption.restoreTombstonedText();
|
|
103
|
-
const finalized = interruption.finalize({
|
|
113
|
+
const saved = CLOSE_SNAPSHOT_SESSION_FIELDS.map((key) => [key, Object.hasOwn(session, key), session[key]]);
|
|
114
|
+
const savedRuntimeSession = runtime.session;
|
|
115
|
+
// The tracker snapshot already counts retracted (tombstoned) text as
|
|
116
|
+
// output, so finalizing from it leaves the tracker itself untouched.
|
|
117
|
+
const finalized = finalizeTurnInterruptionSnapshot({
|
|
104
118
|
turnOutgoing: turn.outgoing || session.messages,
|
|
105
119
|
currentUserContent: turn.userTurnContent,
|
|
106
|
-
|
|
120
|
+
snapshot: interruption.snapshot(),
|
|
121
|
+
abortReason: abortReason ?? null,
|
|
107
122
|
});
|
|
123
|
+
session.liveTurnMessages = null;
|
|
124
|
+
// The finalized transcript is a rewrite; the mid-turn provider prefix
|
|
125
|
+
// snapshot must not survive it.
|
|
126
|
+
delete session._providerPrefixGuardState;
|
|
108
127
|
session.messages = finalized.messages;
|
|
109
128
|
delete session.activeTurnCheckpoint;
|
|
110
129
|
// A preserved response — or a non-user detach that keeps the provisional
|
|
@@ -113,7 +132,32 @@ export function createCloseSnapshot({ turn, interruption, checkpoint, runtime })
|
|
|
113
132
|
session.updatedAt = Date.now();
|
|
114
133
|
session.lastUsedAt = Date.now();
|
|
115
134
|
runtime.session = session;
|
|
116
|
-
|
|
117
|
-
|
|
135
|
+
return {
|
|
136
|
+
snapshot: finalized,
|
|
137
|
+
commit() {
|
|
138
|
+
checkpoint.stop();
|
|
139
|
+
interruption.restoreTombstonedText();
|
|
140
|
+
snapshot = finalized;
|
|
141
|
+
},
|
|
142
|
+
rollback() {
|
|
143
|
+
for (const [key, had, value] of saved) {
|
|
144
|
+
if (had) session[key] = value;
|
|
145
|
+
else delete session[key];
|
|
146
|
+
}
|
|
147
|
+
runtime.session = savedRuntimeSession;
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
const prepare = (abortReason) => {
|
|
152
|
+
if (snapshot) return snapshot;
|
|
153
|
+
const staged = stage(abortReason);
|
|
154
|
+
if (!staged) return null;
|
|
155
|
+
staged.commit();
|
|
156
|
+
return staged.snapshot;
|
|
157
|
+
};
|
|
158
|
+
prepare.tentative = (abortReason) => {
|
|
159
|
+
if (snapshot) return { snapshot, commit() {}, rollback() {} };
|
|
160
|
+
return stage(abortReason);
|
|
118
161
|
};
|
|
162
|
+
return prepare;
|
|
119
163
|
}
|
|
@@ -45,3 +45,19 @@ export function rewindUnansweredPrompt(session, prompt) {
|
|
|
45
45
|
delete session._providerPrefixGuardState;
|
|
46
46
|
return true;
|
|
47
47
|
}
|
|
48
|
+
|
|
49
|
+
/** Resolve a retry against the durable failure, never against display text. */
|
|
50
|
+
export function retainedFailedTurnInput(messages, messageId, attemptId) {
|
|
51
|
+
const list = Array.isArray(messages) ? messages : [];
|
|
52
|
+
const index = list.findLastIndex((message) => message?.role !== 'system');
|
|
53
|
+
const message = list[index];
|
|
54
|
+
const transcript = message?.meta?.transcript;
|
|
55
|
+
if (!messageId || transcript?.messageId !== messageId || transcript?.completion?.status !== 'failed') {
|
|
56
|
+
throw new Error('The failed turn is no longer the latest execution.');
|
|
57
|
+
}
|
|
58
|
+
if (transcript.completion.attemptId && transcript.completion.attemptId !== attemptId) {
|
|
59
|
+
throw new Error('The failed attempt is no longer the latest execution.');
|
|
60
|
+
}
|
|
61
|
+
if (message.role !== 'user') return null;
|
|
62
|
+
return { index, message };
|
|
63
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// Steering / pending-message queue with sync buffering and atomic persistence.
|
|
2
|
-
import {
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
3
|
import { loadSession } from '../store.mjs';
|
|
4
|
-
import { ForeignPendingMessageController } from './foreign-pending-messages.mjs';
|
|
5
4
|
import {
|
|
6
5
|
currentPendingLifecycleToken,
|
|
7
6
|
lifecycleTokenStale,
|
|
@@ -29,7 +28,7 @@ import {
|
|
|
29
28
|
pendingIdSet,
|
|
30
29
|
pruneEmptyPendingIdSet,
|
|
31
30
|
} from './pending-claim-ledger.mjs';
|
|
32
|
-
import { legacyPendingMessagesPath
|
|
31
|
+
import { legacyPendingMessagesPath } from './pending-spool-path.mjs';
|
|
33
32
|
import { pruneCleanupConfirmedLedger } from './pending-delivered-ledger.mjs';
|
|
34
33
|
// The durable delivered-id ledger on the session record lives in
|
|
35
34
|
// pending-delivered-ledger.mjs; re-exported so prior importers stay unchanged.
|
|
@@ -83,16 +82,6 @@ const _sessionPendingMessages = new Map();
|
|
|
83
82
|
const _hydratedPendingMessages = new Map();
|
|
84
83
|
const _pendingHydrations = new Map();
|
|
85
84
|
|
|
86
|
-
// Exposed for live-share owners: they fs.watch this session's shard file for
|
|
87
|
-
// instant pickup of cross-surface submits (the 3s drain tick remains the
|
|
88
|
-
// safety net). Without a valid session id there is nothing to watch.
|
|
89
|
-
export function pendingMessagesSpoolPath(sessionId) {
|
|
90
|
-
if (!isValidPendingSessionId(sessionId)) return '';
|
|
91
|
-
// fs.watch needs the directory to exist before the first shard is written.
|
|
92
|
-
mkdirSync(pendingShardDir(), { recursive: true });
|
|
93
|
-
return pendingMessagesPath(sessionId);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
85
|
function pendingIdStillQueued(sessionId, id) {
|
|
97
86
|
for (const map of [_sessionPendingMessages, _pendingPersistBuffers, _hydratedPendingMessages]) {
|
|
98
87
|
const q = map.get(sessionId);
|
|
@@ -196,11 +185,10 @@ function acknowledgePendingMessages(sessionId, deliveredEntries, options = {}) {
|
|
|
196
185
|
return false;
|
|
197
186
|
}
|
|
198
187
|
// Keep the acked ids when the spool cleanup FAILED: the durable entry
|
|
199
|
-
// still exists, and forgetting that it was already delivered let
|
|
200
|
-
//
|
|
201
|
-
//
|
|
202
|
-
//
|
|
203
|
-
// once a later ack round actually lands.
|
|
188
|
+
// still exists, and forgetting that it was already delivered would let
|
|
189
|
+
// the hydrate path re-take it as a new message (the same message
|
|
190
|
+
// duplicated in the transcript). They are dropped only once a later ack
|
|
191
|
+
// round actually lands.
|
|
204
192
|
if (!ok) return false;
|
|
205
193
|
forgetAckedIds();
|
|
206
194
|
return true;
|
|
@@ -462,99 +450,6 @@ export function enqueuePendingMessage(sessionId, message) {
|
|
|
462
450
|
return Math.max(q.length, bufferedDepth || 0);
|
|
463
451
|
}
|
|
464
452
|
|
|
465
|
-
/**
|
|
466
|
-
* Remote-attach injection enqueue: persist a user message into the shared
|
|
467
|
-
* cross-process spool WITHOUT touching this process's in-memory queues. Used
|
|
468
|
-
* by a viewer surface attached to a session another live process owns — the
|
|
469
|
-
* owner's injection poller (drainForeignUserInjections) picks it up there.
|
|
470
|
-
* Skipping the local queues is deliberate: if this process later takes real
|
|
471
|
-
* ownership of the session, a lingering local copy would double-inject.
|
|
472
|
-
*/
|
|
473
|
-
export function enqueueRemotePendingMessage(sessionId, message) {
|
|
474
|
-
if (!isValidPendingSessionId(sessionId)) return 0;
|
|
475
|
-
// Same durable-lifecycle authority as the local enqueue: a cross-surface
|
|
476
|
-
// submit that lands after the session was closed is refused before any
|
|
477
|
-
// spool mutation.
|
|
478
|
-
const token = currentPendingLifecycleToken(sessionId);
|
|
479
|
-
if (pendingLifecycleInvalidated(sessionId)) return 0;
|
|
480
|
-
const normalized = pendingMessageQueueEntry(message);
|
|
481
|
-
if (!normalized) return 0;
|
|
482
|
-
// The token rides into the async spool commit, which revalidates under the
|
|
483
|
-
// spool lock (see persistPendingMessages).
|
|
484
|
-
if (pendingLifecycleInvalidated(sessionId, token)) return 0;
|
|
485
|
-
// Preserve the viewer's submission id end-to-end. Minting a fresh id here
|
|
486
|
-
// made pipe-delivered + spool-fallback twins look like two messages
|
|
487
|
-
// (owner accepted the pipe copy, then re-took the spool copy).
|
|
488
|
-
const preservedId = pendingMessageId(normalized) || pendingMessageId(message);
|
|
489
|
-
const remoteEntry = stampLifecycleToken(
|
|
490
|
-
{
|
|
491
|
-
...normalized,
|
|
492
|
-
id: typeof preservedId === 'string' && preservedId.trim() ? preservedId.trim() : newPendingMessageId(),
|
|
493
|
-
},
|
|
494
|
-
token
|
|
495
|
-
);
|
|
496
|
-
return persistPendingMessages(sessionId, [remoteEntry]);
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
function _foreignLocalIds(sessionId) {
|
|
500
|
-
const localIds = new Set();
|
|
501
|
-
for (const map of [_sessionPendingMessages, _pendingPersistBuffers, _hydratedPendingMessages]) {
|
|
502
|
-
for (const entry of map.get(sessionId) || []) {
|
|
503
|
-
const id = pendingMessageId(entry);
|
|
504
|
-
if (id) localIds.add(id);
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
for (const set of [_inDeliveryPendingIds.get(sessionId), _ackedPendingIds.get(sessionId)]) {
|
|
508
|
-
for (const id of set || []) localIds.add(id);
|
|
509
|
-
}
|
|
510
|
-
// The durable delivered-ledger mirrors the hydrate path's suppression: an
|
|
511
|
-
// entry whose id was recorded as delivered (but whose spool cleanup has
|
|
512
|
-
// not landed yet — crash, lock contention, another process) is NOT a
|
|
513
|
-
// foreign submit and must never re-inject.
|
|
514
|
-
try {
|
|
515
|
-
for (const id of loadSession(sessionId)?.deliveredPendingMessageIds || []) {
|
|
516
|
-
if (typeof id === 'string' && id) localIds.add(id);
|
|
517
|
-
}
|
|
518
|
-
} catch {
|
|
519
|
-
/* ledger unavailable — in-memory sets still guard */
|
|
520
|
-
}
|
|
521
|
-
return localIds;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
function addForeignInDeliveryIds(sessionId, ids) {
|
|
525
|
-
const inDelivery = pendingIdSet(_inDeliveryPendingIds, sessionId);
|
|
526
|
-
for (const id of ids) inDelivery.add(id);
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
function removeForeignInDeliveryIds(sessionId, ids) {
|
|
530
|
-
const inDelivery = _inDeliveryPendingIds.get(sessionId);
|
|
531
|
-
for (const id of ids) inDelivery?.delete(id);
|
|
532
|
-
pruneEmptyPendingIdSet(_inDeliveryPendingIds, sessionId);
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
const foreignPendingMessages = new ForeignPendingMessageController({
|
|
536
|
-
addInDeliveryIds: addForeignInDeliveryIds,
|
|
537
|
-
chainSpoolTail,
|
|
538
|
-
currentLifecycleToken: currentPendingLifecycleToken,
|
|
539
|
-
getSpoolTail: (sessionId) => _pendingPersistTails.get(sessionId),
|
|
540
|
-
isValidSessionId: isValidPendingSessionId,
|
|
541
|
-
lifecycleEpochMoved: pendingLifecycleEpochMoved,
|
|
542
|
-
lifecycleInvalidated: pendingLifecycleInvalidated,
|
|
543
|
-
localIds: _foreignLocalIds,
|
|
544
|
-
normalizeStore: normalizePendingStore,
|
|
545
|
-
removeInDeliveryIds: removeForeignInDeliveryIds,
|
|
546
|
-
setSpoolQueue,
|
|
547
|
-
spoolPath: pendingMessagesPath,
|
|
548
|
-
updateSpool,
|
|
549
|
-
warn: pendingWarn,
|
|
550
|
-
});
|
|
551
|
-
|
|
552
|
-
// The controller parks rows before delivery so an owner crash can redeliver
|
|
553
|
-
// accepted input instead of losing it.
|
|
554
|
-
export async function drainForeignUserInjections(sessionId) {
|
|
555
|
-
return foreignPendingMessages.drainUserInjections(sessionId);
|
|
556
|
-
}
|
|
557
|
-
|
|
558
453
|
// Drain order: enqueue time, then source (hydrated < buffered < memory), then
|
|
559
454
|
// position within the source.
|
|
560
455
|
function byEnqueueOrder(a, b) {
|
|
@@ -710,15 +605,6 @@ export function _dropPendingMessageState(id, { clearPersisted = true } = {}) {
|
|
|
710
605
|
} catch {
|
|
711
606
|
/* ignore */
|
|
712
607
|
}
|
|
713
|
-
// A tombstoned close removes the whole durable queue anyway; a DETACH keeps
|
|
714
|
-
// its scheduled release so this process still cleans up rows it parked.
|
|
715
|
-
if (clearPersisted) {
|
|
716
|
-
try {
|
|
717
|
-
foreignPendingMessages.cancelHandoffRelease(id);
|
|
718
|
-
} catch {
|
|
719
|
-
/* ignore */
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
608
|
_inDeliveryPendingIds.delete(id);
|
|
723
609
|
_ackedPendingIds.delete(id);
|
|
724
610
|
_pendingHydrations.delete(id);
|
|
@@ -93,7 +93,7 @@ export function persistPendingMessages(sessionId, messages) {
|
|
|
93
93
|
// schedule the retry HERE. Waiting for "the next scheduled flush or
|
|
94
94
|
// session takeover" meant a FINAL submit (nothing else ever
|
|
95
95
|
// enqueues afterwards) stayed process-local forever, while
|
|
96
|
-
//
|
|
96
|
+
// enqueuePendingMessage had already reported success.
|
|
97
97
|
try {
|
|
98
98
|
// Closed/detached since this write started: its buffer and its
|
|
99
99
|
// retry timer were torn down on purpose — do not rebuild them.
|
|
@@ -229,7 +229,7 @@ export function replaceWorkspaceCoreSlices(core, { coreMemoryContext, instructio
|
|
|
229
229
|
if (memory) parts.push(`${CORE_MEMORY_HEADING}${memory}`);
|
|
230
230
|
}
|
|
231
231
|
if (instructionFilesContext !== undefined) instructionFiles = trimmedSlice(instructionFilesContext);
|
|
232
|
-
return [...parts, instructionFiles].filter((part) => part
|
|
232
|
+
return [...parts, instructionFiles].filter((part) => part?.trim()).join(BP3_PART_SEPARATOR);
|
|
233
233
|
}
|
|
234
234
|
|
|
235
235
|
/**
|
|
@@ -243,7 +243,7 @@ export function replaceWorkspaceEnvironment(environmentTail, environmentContext)
|
|
|
243
243
|
const facts = trimmedSlice(environmentContext);
|
|
244
244
|
if (parts[0]?.startsWith('- ')) parts[0] = facts;
|
|
245
245
|
else parts.unshift(facts);
|
|
246
|
-
return parts.filter((part) => part
|
|
246
|
+
return parts.filter((part) => part?.trim()).join(BP3_PART_SEPARATOR);
|
|
247
247
|
}
|
|
248
248
|
|
|
249
249
|
/**
|
|
@@ -399,12 +399,13 @@ function sameWorkspacePath(left, right) {
|
|
|
399
399
|
/** The lines a move from the project folder into a worktree adds to the notice. */
|
|
400
400
|
function workspaceMoveLines(move, cwd) {
|
|
401
401
|
if (!move?.from || sameWorkspacePath(move.from, cwd)) return [];
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
402
|
+
let changes = '';
|
|
403
|
+
if (move.changes === 'carried') {
|
|
404
|
+
changes =
|
|
405
|
+
'Uncommitted changes were moved into the worktree; ignored files (dependencies, build output, env files) were not.';
|
|
406
|
+
} else if (move.changes === 'left') {
|
|
407
|
+
changes = `Uncommitted changes were left in ${move.from}; they are not present here.`;
|
|
408
|
+
}
|
|
408
409
|
return [
|
|
409
410
|
changes,
|
|
410
411
|
`For continued work, substitute ${cwd} for the project root ${move.from} in paths mentioned earlier; absolute paths are not remapped automatically. Re-read affected files before editing them.`,
|
|
@@ -418,6 +419,7 @@ function workspaceNoticeContent({ seen, target }) {
|
|
|
418
419
|
[
|
|
419
420
|
'# Working Folder Changed',
|
|
420
421
|
`The working folder is now ${target.cwd}. This replaces the Cwd and environment facts given earlier in this conversation; relative paths and shell commands resolve here.`,
|
|
422
|
+
'Keep the conversation goals and decisions, but treat earlier file contents, search results and Git observations as historical, not as evidence of this checkout. Check the target project instructions and Git status, and re-read the files needed for the next edit before continuing. A folder change alone does not transfer uncommitted changes.',
|
|
421
423
|
...workspaceMoveLines(target.move, target.cwd),
|
|
422
424
|
changed('environmentContext') ? target.environmentContext : '',
|
|
423
425
|
]
|
|
@@ -455,6 +457,25 @@ export function snapshotPendingWorkspaceNotice(session) {
|
|
|
455
457
|
return content ? { revision: pending.revision, content } : null;
|
|
456
458
|
}
|
|
457
459
|
|
|
460
|
+
/**
|
|
461
|
+
* The report of a new worktree's preparation (session.pendingSetupNotice, set
|
|
462
|
+
* by the first turn's workspace gate) for this turn, or null. Acknowledged
|
|
463
|
+
* when the provider accepted the turn, like the workspace notice.
|
|
464
|
+
* @returns {{ revision: number, content: string } | null}
|
|
465
|
+
*/
|
|
466
|
+
export function snapshotPendingSetupNotice(session) {
|
|
467
|
+
const pending = session?.pendingSetupNotice;
|
|
468
|
+
return typeof pending?.content === 'string' && pending.content
|
|
469
|
+
? { revision: pending.revision, content: pending.content }
|
|
470
|
+
: null;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
export function acknowledgePendingSetupNotice(session, revision) {
|
|
474
|
+
if (session?.pendingSetupNotice?.revision !== revision) return false;
|
|
475
|
+
delete session.pendingSetupNotice;
|
|
476
|
+
return true;
|
|
477
|
+
}
|
|
478
|
+
|
|
458
479
|
/** The notice of `revision` reached the model: what it was told is now the target. */
|
|
459
480
|
export function acknowledgePendingWorkspaceNotice(session, revision) {
|
|
460
481
|
const pending = session?.workspaceReroot;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
// ── Runtime liveness map ──────────────────────────────────────────────
|
|
2
|
-
// In-memory only. Tracks per-session stage + stream
|
|
2
|
+
// In-memory only. Tracks per-session stage + stream progress so agent type=list
|
|
3
3
|
// can surface whether a session is actually alive vs stuck. Never persisted —
|
|
4
|
-
//
|
|
4
|
+
// progress would otherwise churn the session JSON on every SSE delta. The Map
|
|
5
|
+
// itself lives in the import-free leaf runtime-state.mjs so cold readers can
|
|
6
|
+
// ask which turns are in flight (isSessionTurnInFlight /
|
|
7
|
+
// inFlightSessionActivity); every mutation stays here.
|
|
5
8
|
//
|
|
6
9
|
// The Map and its timer companion are
|
|
7
10
|
// module-level singletons — preserving the baseline's single-process shape.
|
|
@@ -20,14 +23,16 @@
|
|
|
20
23
|
// }
|
|
21
24
|
import { createAbortController } from '../../../../shared/abort-controller.mjs';
|
|
22
25
|
import { emitSessionApprovalWaitChange } from '../../../../shared/session-approval-wait.mjs';
|
|
23
|
-
import { publishHeartbeat, deleteHeartbeat } from '../store.mjs';
|
|
24
26
|
import { DEFAULT_ACTIVITY_HEARTBEAT_MS } from '../../stall-policy.mjs';
|
|
27
|
+
import { MODEL_THINKING_STAGE, awaitingModelResponse, lastProgressAt } from '../../../../shared/quiet-progress.mjs';
|
|
25
28
|
import { finishBrowserTurn } from '../../../../browser-bridge/client.mjs';
|
|
26
29
|
import { configureUsageMetricsRuntime, dropMetricSeenState, bumpUsageMetricsTurnId } from './usage-metrics.mjs';
|
|
30
|
+
import { runtimeState as _runtimeState, isTurnInFlight } from './runtime-state.mjs';
|
|
31
|
+
|
|
32
|
+
export { IN_FLIGHT_STAGES, inFlightSessionActivity } from './runtime-state.mjs';
|
|
27
33
|
|
|
28
34
|
const HEARTBEAT_THROTTLE_MS = 60_000; // 60s
|
|
29
35
|
|
|
30
|
-
const _runtimeState = new Map();
|
|
31
36
|
const _toolActivityHeartbeats = new Map();
|
|
32
37
|
const VALID_STAGES = new Set([
|
|
33
38
|
'connecting',
|
|
@@ -99,7 +104,6 @@ function _touchSessionActivityProgress(id) {
|
|
|
99
104
|
const now = Date.now();
|
|
100
105
|
entry.lastProgressAt = now;
|
|
101
106
|
entry.updatedAt = now;
|
|
102
|
-
publishHeartbeat(id, now);
|
|
103
107
|
}
|
|
104
108
|
|
|
105
109
|
function _startToolActivityHeartbeat(id) {
|
|
@@ -111,11 +115,17 @@ function _startToolActivityHeartbeat(id) {
|
|
|
111
115
|
}
|
|
112
116
|
|
|
113
117
|
export function updateSessionStage(id, stage) {
|
|
118
|
+
if (stage === MODEL_THINKING_STAGE) {
|
|
119
|
+
markSessionRequestSent(id);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
114
122
|
if (!id || !VALID_STAGES.has(stage)) return;
|
|
115
123
|
const entry = _touchRuntime(id);
|
|
116
124
|
const now = Date.now();
|
|
117
125
|
const priorStage = entry.stage;
|
|
118
126
|
entry.stage = stage;
|
|
127
|
+
// A new stage (a retried attempt included) has not sent its request yet.
|
|
128
|
+
entry.requestSentAt = null;
|
|
119
129
|
if (stage === 'requesting' && priorStage !== 'requesting') {
|
|
120
130
|
entry.modelRequestStartedAt = now;
|
|
121
131
|
}
|
|
@@ -148,6 +158,7 @@ export function markSessionAskStart(id) {
|
|
|
148
158
|
entry.lastToolProtocolAt = null;
|
|
149
159
|
entry.lastSemanticKind = null;
|
|
150
160
|
entry.transportTrackingEnabled = false;
|
|
161
|
+
entry.requestSentAt = null;
|
|
151
162
|
entry.lastToolCall = null;
|
|
152
163
|
entry.toolStartedAt = null;
|
|
153
164
|
entry.toolOutputTail = null;
|
|
@@ -166,14 +177,18 @@ export function markSessionAskStart(id) {
|
|
|
166
177
|
entry.modelRequestStartedAt = null;
|
|
167
178
|
entry.lastProgressAt = now;
|
|
168
179
|
entry.updatedAt = now;
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
180
|
+
}
|
|
181
|
+
/** The provider put the request on the wire; its response headers are
|
|
182
|
+
* pending. The turn stays `requesting` (every stage set and the watchdog
|
|
183
|
+
* clock are unchanged); the send time lets surfaces show "model thinking"
|
|
184
|
+
* until transport arrives. Not progress: lastProgressAt is untouched. */
|
|
185
|
+
export function markSessionRequestSent(id) {
|
|
186
|
+
if (!id) return;
|
|
187
|
+
const entry = _runtimeState.get(id);
|
|
188
|
+
if (!entry || entry.closed || entry.controller?.signal?.aborted || entry.stage !== 'requesting') return;
|
|
189
|
+
const now = Date.now();
|
|
190
|
+
entry.requestSentAt = now;
|
|
191
|
+
entry.updatedAt = now;
|
|
177
192
|
}
|
|
178
193
|
export function enableSessionTransportTracking(id) {
|
|
179
194
|
if (!id) return;
|
|
@@ -194,7 +209,6 @@ export function markSessionTransportActivity(id) {
|
|
|
194
209
|
const now = Date.now();
|
|
195
210
|
entry.lastTransportAt = now;
|
|
196
211
|
entry.updatedAt = now;
|
|
197
|
-
publishHeartbeat(id, now);
|
|
198
212
|
}
|
|
199
213
|
function _normalizeModelProgressKind(kind) {
|
|
200
214
|
let value = 'semantic';
|
|
@@ -211,10 +225,10 @@ export async function markSessionStreamDelta(id, kind = 'semantic') {
|
|
|
211
225
|
// creates it before streaming begins). _touchRuntime would instead resurrect a
|
|
212
226
|
// blank entry — and closeSession()/idle-sweep clear _runtimeState on a deferred
|
|
213
227
|
// tick while a detached provider stream may still be trickling deltas. A delta
|
|
214
|
-
// arriving after that clear must NOT re-create an entry or it would
|
|
215
|
-
//
|
|
216
|
-
//
|
|
217
|
-
//
|
|
228
|
+
// arriving after that clear must NOT re-create an entry or it would revive a
|
|
229
|
+
// dead session's runtime state (the disk tombstone blocks ask resumption but
|
|
230
|
+
// not this path). Skip a missing, tombstoned, or aborted entry — never refresh
|
|
231
|
+
// liveness.
|
|
218
232
|
const entry = _runtimeState.get(id);
|
|
219
233
|
if (!entry || entry.closed || entry.controller?.signal?.aborted || TERMINAL_STAGES.has(entry.stage)) return;
|
|
220
234
|
const progressKind = _normalizeModelProgressKind(kind);
|
|
@@ -240,11 +254,7 @@ export async function markSessionStreamDelta(id, kind = 'semantic') {
|
|
|
240
254
|
if (entry.stage === 'connecting' || entry.stage === 'requesting') {
|
|
241
255
|
entry.stage = 'streaming';
|
|
242
256
|
}
|
|
243
|
-
//
|
|
244
|
-
// Disk-side session.lastHeartbeatAt below is the heavy 60s zombie-reaper
|
|
245
|
-
// signal; the .hb file is the fast fresh-session signal consumed by the
|
|
246
|
-
// status line.
|
|
247
|
-
publishHeartbeat(id, now);
|
|
257
|
+
// Disk-side session.lastHeartbeatAt is the 60s zombie-reaper signal.
|
|
248
258
|
const session = entry.session;
|
|
249
259
|
if (session && now - (session.lastHeartbeatAt || 0) > HEARTBEAT_THROTTLE_MS) {
|
|
250
260
|
session.lastHeartbeatAt = now;
|
|
@@ -271,9 +281,7 @@ export function markSessionToolCall(id, toolName) {
|
|
|
271
281
|
entry.lastToolProtocolAt = entry.toolStartedAt;
|
|
272
282
|
entry.lastProgressAt = entry.toolStartedAt;
|
|
273
283
|
entry.updatedAt = entry.toolStartedAt;
|
|
274
|
-
const heartbeat = publishHeartbeat(id, entry.toolStartedAt);
|
|
275
284
|
_startToolActivityHeartbeat(id);
|
|
276
|
-
return heartbeat;
|
|
277
285
|
}
|
|
278
286
|
// Live shell-output tail for the CURRENT running tool. Written by the shell
|
|
279
287
|
// tool's onOutputTail timer (~1 s cadence), read by engine transcript
|
|
@@ -341,10 +349,6 @@ export function markSessionDone(id, { empty = false } = {}) {
|
|
|
341
349
|
entry.emptyFinal = false;
|
|
342
350
|
entry.emptyFinalAt = null;
|
|
343
351
|
}
|
|
344
|
-
// Terminal stage — drop the heartbeat so the status badge releases
|
|
345
|
-
// immediately. A subsequent ask on the same session re-publishes via
|
|
346
|
-
// markSessionStreamDelta on the first chunk.
|
|
347
|
-
return deleteHeartbeat(id);
|
|
348
352
|
}
|
|
349
353
|
// Tag a session as having completed with empty final synthesis (no
|
|
350
354
|
// content/reasoning). Distinct from `markSessionDone`: still a success
|
|
@@ -368,9 +372,7 @@ export function markSessionError(id, msg) {
|
|
|
368
372
|
// silent empty final). Clear the flag so the next ask starts clean.
|
|
369
373
|
entry.emptyFinal = false;
|
|
370
374
|
entry.emptyFinalAt = null;
|
|
371
|
-
const heartbeatDeleted = deleteHeartbeat(id);
|
|
372
375
|
_unlinkParentAbortListener(entry);
|
|
373
|
-
return heartbeatDeleted;
|
|
374
376
|
}
|
|
375
377
|
export function markSessionCancelled(id) {
|
|
376
378
|
if (!id) return;
|
|
@@ -380,24 +382,19 @@ export function markSessionCancelled(id) {
|
|
|
380
382
|
_settleTerminalEntry(entry, 'done', null);
|
|
381
383
|
entry.emptyFinal = false;
|
|
382
384
|
entry.emptyFinalAt = null;
|
|
383
|
-
const heartbeatDeleted = deleteHeartbeat(id);
|
|
384
385
|
_unlinkParentAbortListener(entry);
|
|
385
|
-
return heartbeatDeleted;
|
|
386
386
|
}
|
|
387
387
|
export function getSessionRuntime(id) {
|
|
388
388
|
return id ? _runtimeState.get(id) || null : null;
|
|
389
389
|
}
|
|
390
390
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
391
|
+
/** Whether this session's turn (provider or tool work) is running now. */
|
|
392
|
+
export function isSessionTurnInFlight(sessionId) {
|
|
393
|
+
return Boolean(sessionId) && isTurnInFlight(_runtimeState.get(sessionId));
|
|
394
|
+
}
|
|
394
395
|
|
|
395
396
|
export function isSessionCompactionBlocked(sessionId) {
|
|
396
|
-
|
|
397
|
-
const entry = _runtimeState.get(sessionId);
|
|
398
|
-
if (!entry || entry.closed === true) return false;
|
|
399
|
-
if (entry.controller && !entry.controller.signal?.aborted) return true;
|
|
400
|
-
return IN_FLIGHT_STAGES.has(entry.stage);
|
|
397
|
+
return isSessionTurnInFlight(sessionId);
|
|
401
398
|
}
|
|
402
399
|
|
|
403
400
|
export function getSessionProgressSnapshot(sessionId) {
|
|
@@ -418,6 +415,9 @@ export function getSessionProgressSnapshot(sessionId) {
|
|
|
418
415
|
firstActivityAt,
|
|
419
416
|
firstSemanticAt,
|
|
420
417
|
lastTransportAt: entry.lastTransportAt || 0,
|
|
418
|
+
requestSentAt: entry.requestSentAt || 0,
|
|
419
|
+
// Request on the wire, headers pending: the model is queued or thinking.
|
|
420
|
+
awaitingModelResponse: awaitingModelResponse(entry),
|
|
421
421
|
lastSemanticAt: entry.lastSemanticAt || 0,
|
|
422
422
|
lastSemanticKind: entry.lastSemanticKind || null,
|
|
423
423
|
lastReasoningAt: entry.lastReasoningAt || 0,
|
|
@@ -482,14 +482,7 @@ export function getSessionAbortSignal(sessionId) {
|
|
|
482
482
|
* either skip the watchdog or treat 0 as "no progress yet".
|
|
483
483
|
*/
|
|
484
484
|
export function getSessionLastProgressAt(sessionId) {
|
|
485
|
-
|
|
486
|
-
if (!entry) return 0;
|
|
487
|
-
return Math.max(
|
|
488
|
-
entry.lastProgressAt || 0,
|
|
489
|
-
entry.lastStreamDeltaAt || 0,
|
|
490
|
-
entry.toolStartedAt || 0,
|
|
491
|
-
entry.askStartedAt || 0
|
|
492
|
-
);
|
|
485
|
+
return lastProgressAt(_runtimeState.get(sessionId));
|
|
493
486
|
}
|
|
494
487
|
|
|
495
488
|
/**
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// manager/runtime-state.mjs
|
|
2
|
+
// The process-global runtime liveness map and its turn-activity reads.
|
|
3
|
+
// runtime-liveness.mjs owns every entry and mutation; this leaf has no
|
|
4
|
+
// imports, so a cold reader (the daemon's session catalog) can ask which turns
|
|
5
|
+
// are in flight without loading the session manager graph. Every session runs
|
|
6
|
+
// inline in the daemon, so this map is the whole answer to "is this session's
|
|
7
|
+
// turn running".
|
|
8
|
+
|
|
9
|
+
export const runtimeState = new Map();
|
|
10
|
+
|
|
11
|
+
// Stages that still own live provider/tool work: compaction, idle cleanup and
|
|
12
|
+
// runtime unload all stay away from an entry in one of them.
|
|
13
|
+
export const IN_FLIGHT_STAGES = new Set(['connecting', 'requesting', 'streaming', 'tool_running', 'cancelling']);
|
|
14
|
+
|
|
15
|
+
/** Whether a runtime entry's turn (provider or tool work) is running now. */
|
|
16
|
+
export function isTurnInFlight(entry) {
|
|
17
|
+
if (!entry || entry.closed === true) return false;
|
|
18
|
+
if (entry.controller && !entry.controller.signal?.aborted) return true;
|
|
19
|
+
return IN_FLIGHT_STAGES.has(entry.stage);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const cleanLower = (value) =>
|
|
23
|
+
String(value || '')
|
|
24
|
+
.trim()
|
|
25
|
+
.toLowerCase();
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Turn activity of every session this process runs: `working` holds the ids
|
|
29
|
+
* whose turn is in flight, `agentWorking` the root owner (Lead) ids of every
|
|
30
|
+
* in-flight Agent session.
|
|
31
|
+
*/
|
|
32
|
+
export function inFlightSessionActivity() {
|
|
33
|
+
const working = new Set();
|
|
34
|
+
const agentWorking = new Set();
|
|
35
|
+
for (const [id, entry] of runtimeState) {
|
|
36
|
+
if (!isTurnInFlight(entry)) continue;
|
|
37
|
+
working.add(id);
|
|
38
|
+
const session = entry.session;
|
|
39
|
+
const ownerSessionId = String(session?.ownerSessionId || session?.parentSessionId || '').trim();
|
|
40
|
+
const agent = cleanLower(session?.agent);
|
|
41
|
+
if (
|
|
42
|
+
ownerSessionId &&
|
|
43
|
+
ownerSessionId !== id &&
|
|
44
|
+
(cleanLower(session?.owner) === 'agent' || (agent && agent !== 'lead'))
|
|
45
|
+
) {
|
|
46
|
+
agentWorking.add(ownerSessionId);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return { working, agentWorking };
|
|
50
|
+
}
|