mixdog 1.4.0 → 1.4.2
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 +3 -2
- package/scripts/build-shipped-history.mjs +115 -33
- package/scripts/check-voice-runtime-inputs.mjs +25 -0
- package/scripts/gate-local.mjs +183 -63
- package/scripts/latest-guard.mjs +21 -9
- package/scripts/lib/gate-scheduler.mjs +138 -32
- package/scripts/lib/gate-timing-reporter.mjs +16 -0
- package/scripts/lib/isolated-test-env.mjs +10 -5
- package/scripts/lib/run-node-tests.mjs +91 -66
- package/scripts/lib/scoped-temp.d.mts +16 -0
- package/scripts/lib/scoped-temp.mjs +124 -0
- package/scripts/lib/stale-temp.mjs +44 -0
- package/scripts/lib/test-failure-records.mjs +14 -1
- package/scripts/lib/test-failure-summary.mjs +16 -4
- package/scripts/lib/test-spawn-ledger.mjs +12 -3
- package/scripts/post-release-check.mjs +1 -6
- package/scripts/pptx-kit-index.mjs +17 -5
- package/scripts/suite-health.mjs +115 -24
- package/scripts/test-data-dir.mjs +10 -7
- package/scripts/test.mjs +9 -14
- package/src/agents/advisor/AGENT.md +4 -4
- package/src/agents/advisor/agent.json +1 -1
- package/src/agents/explore/AGENT.md +22 -0
- package/src/agents/explore/agent.json +6 -0
- package/src/app.mjs +4 -0
- package/src/cli.mjs +7 -0
- package/src/defaults/agents.json +7 -0
- package/src/defaults/shipped-history.json +23 -2
- package/src/defaults/skills/browser-use/SKILL.md +10 -5
- package/src/defaults/skills/code-tidy/SKILL.md +71 -102
- package/src/defaults/skills/code-tidy/references/agent-cleanup.md +66 -114
- package/src/defaults/skills/code-tidy/references/cleanup-report.md +19 -35
- package/src/defaults/skills/code-tidy/references/dead-code.md +3 -9
- package/src/defaults/skills/code-tidy/references/test-suite-slop.md +16 -27
- package/src/defaults/skills/computer-use/SKILL.md +16 -4
- package/src/defaults/skills/goal-management/SKILL.md +1 -1
- package/src/defaults/skills/setup/references/actions.md +12 -6
- package/src/defaults/skills/setup/references/surfaces.md +2 -2
- package/src/defaults/skills/setup-guide/SKILL.md +5 -2
- package/src/defaults/skills/setup-guide/model-recommendations.json +13 -0
- package/src/defaults/skills/skill-creator/SKILL.md +85 -190
- package/src/defaults/skills/skill-creator/references/design.md +70 -162
- package/src/defaults/skills/skill-creator/references/evaluation.md +33 -92
- package/src/defaults/skills/test-suite/SKILL.md +194 -0
- package/src/defaults/skills/test-suite/references/case-management.md +51 -0
- package/src/defaults/skills/test-suite/references/flaky-policy.md +39 -0
- package/src/defaults/skills/test-suite/references/reliability.md +49 -0
- package/src/defaults/skills/test-suite/references/suite-design.md +78 -0
- package/src/defaults/skills/test-suite/scripts/inventory.mjs +335 -0
- package/src/defaults/skills/visualize/SKILL.md +6 -2
- package/src/lib/rules-builder.cjs +35 -42
- package/src/output-styles/common.md +2 -2
- package/src/output-styles/simple.md +1 -1
- package/src/rules/agent/AGENT.md +5 -4
- package/src/rules/lead/LEAD.md +12 -7
- package/src/rules/shared/10-tool-workflow.md +3 -1
- package/src/rules/shared/20-research.md +3 -6
- package/src/rules/shared/40-editing.md +1 -0
- package/src/rules/shared/45-destructive.md +0 -2
- package/src/rules/shared/50-execution.md +2 -0
- package/src/rules/shared/60-verification.md +10 -9
- package/src/rules/shared/70-delivery.md +8 -9
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/abort-link.mjs +5 -1
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +10 -1
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +156 -24
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +13 -0
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +4 -1
- package/src/runtime/agent/orchestrator/cache-break-trace.mjs +2 -0
- package/src/runtime/agent/orchestrator/config.mjs +12 -7
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +8 -8
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +5 -26
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +3 -1
- package/src/runtime/agent/orchestrator/internal-agents.mjs +3 -14
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +122 -12
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +5 -3
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +13 -2
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +152 -58
- package/src/runtime/agent/orchestrator/mcp/client.mjs +51 -18
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +88 -54
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +42 -26
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +54 -8
- package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +37 -31
- package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +8 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +31 -21
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +14 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +6 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +40 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider-keys.mjs +34 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +14 -7
- package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/devin.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +248 -41
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -11
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +45 -6
- package/src/runtime/agent/orchestrator/providers/lib/first-output-window.mjs +58 -0
- package/src/runtime/agent/orchestrator/providers/lib/listen-on.mjs +14 -0
- package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +0 -18
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +138 -6
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/model-cache.mjs +100 -33
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/oauth-secret-fields.fixtures.mjs +45 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +14 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +4 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +5 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +16 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +13 -3
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +13 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +81 -42
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +160 -31
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +22 -12
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +49 -22
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/registry.mjs +45 -2
- package/src/runtime/agent/orchestrator/providers/vertex-ai-auth.mjs +622 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai-maas.mjs +185 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai-models.mjs +445 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai.mjs +567 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +41 -13
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -6
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +7 -3
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +6 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +14 -5
- package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -0
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -5
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +171 -37
- package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +1 -3
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +102 -12
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -8
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/compact/observation-supersession.mjs +103 -23
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +160 -36
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +164 -23
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +139 -19
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +38 -7
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +100 -22
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -3
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -6
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +33 -3
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +9 -2
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +13 -5
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +23 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +23 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +39 -21
- package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +13 -8
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +50 -28
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +30 -13
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +63 -6
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +35 -13
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +24 -14
- package/src/runtime/agent/orchestrator/session/manager/session-scratch-environment.mjs +70 -0
- package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +0 -3
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +10 -6
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +56 -29
- package/src/runtime/agent/orchestrator/session/manager/turn-reap.mjs +125 -0
- package/src/runtime/agent/orchestrator/session/mixy-name.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +30 -7
- package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +154 -0
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +37 -8
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +252 -39
- package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +163 -64
- package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +164 -4
- package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +142 -18
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +61 -2
- package/src/runtime/agent/orchestrator/stall-policy.mjs +23 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +46 -20
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +67 -31
- package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +25 -13
- package/src/runtime/agent/orchestrator/tools/builtin/lib/scoped-search-flight.mjs +9 -5
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +58 -20
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +23 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +1 -8
- package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +20 -15
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +96 -20
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +59 -10
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/federation.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/lib/isolated-test-env.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +99 -2
- package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +103 -13
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +49 -15
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +45 -27
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +34 -10
- package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +28 -4
- package/src/runtime/agent/orchestrator/tools/lib/wait-until-fixture.mjs +26 -0
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -2
- package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
- package/src/runtime/channels/lib/webhook/signature.mjs +4 -1
- package/src/runtime/channels/lib/whisper-port.mjs +29 -11
- package/src/runtime/channels/lib/whisper-server.mjs +10 -1
- package/src/runtime/computer-bridge/action-schema.mjs +2 -2
- package/src/runtime/computer-bridge/core-actions.mjs +2 -2
- package/src/runtime/computer-bridge/error-recovery.mjs +5 -4
- package/src/runtime/computer-bridge/linux-action-capabilities.mjs +24 -5
- package/src/runtime/computer-bridge/linux-readiness.d.mts +7 -2
- package/src/runtime/connectors/connector-accounts-mcp.mjs +236 -103
- package/src/runtime/connectors/gmail-app-password.mjs +3 -3
- package/src/runtime/explore/explorer.mjs +93 -0
- package/src/runtime/explore/tool-defs.mjs +35 -0
- package/src/runtime/explore/tool.mjs +123 -0
- package/src/runtime/local-provider/server-process.mjs +2 -1
- package/src/runtime/media/adapters/gemini-video.mjs +4 -1
- package/src/runtime/media/adapters/xai-media.mjs +2 -1
- package/src/runtime/memory/index.mjs +4 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +4 -1
- package/src/runtime/memory/lib/embedding-worker.mjs +10 -3
- package/src/runtime/memory/lib/memory-action-handlers/cycle-backfill-action.mjs +1 -7
- package/src/runtime/memory/lib/memory-chunk-quality.mjs +1 -6
- package/src/runtime/office/authoring/pdf-author-action.mjs +1 -6
- package/src/runtime/office/design/design-art-direction.mjs +29 -27
- package/src/runtime/office/pdf/pdf-writer.mjs +6 -1
- package/src/runtime/office/portable/portable-snapshot-docx.mjs +7 -1
- package/src/runtime/office/portable/portable-snapshot-shared.mjs +6 -1
- package/src/runtime/office/quality/assurance-rendered.mjs +9 -2
- package/src/runtime/office/quality/assurance-structure-docx.mjs +4 -2
- package/src/runtime/office/quality/design-review.mjs +1 -5
- package/src/runtime/office/quality/document-brief.mjs +1 -5
- package/src/runtime/office/quality/forced-break-pages.mjs +9 -6
- package/src/runtime/office/quality/quality-pipeline.mjs +1 -1
- package/src/runtime/shared/agent-route-config.mjs +17 -2
- package/src/runtime/shared/atomic-file.mjs +103 -2
- package/src/runtime/shared/background-tasks.mjs +15 -6
- package/src/runtime/shared/bot-owned-work.mjs +56 -0
- package/src/runtime/shared/connector-accounts.mjs +5 -5
- package/src/runtime/shared/connector-catalog.d.mts +11 -4
- package/src/runtime/shared/connector-catalog.mjs +60 -52
- package/src/runtime/shared/custom-provider-keys.mjs +20 -0
- package/src/runtime/shared/defaults-separation.mjs +1 -4
- package/src/runtime/shared/fetch-safe-listen.d.mts +16 -0
- package/src/runtime/shared/fetch-safe-listen.mjs +50 -0
- package/src/runtime/shared/file-has-data.mjs +26 -2
- package/src/runtime/shared/file-lock.mjs +13 -15
- package/src/runtime/shared/git-launch.d.mts +9 -0
- package/src/runtime/shared/git-launch.mjs +213 -0
- package/src/runtime/shared/git-runner-worker.mjs +2 -1
- package/src/runtime/shared/handoff-artifacts.d.mts +2 -1
- package/src/runtime/shared/handoff-artifacts.mjs +18 -8
- package/src/runtime/shared/idle-auto-clear-gate.mjs +29 -7
- package/src/runtime/shared/llm/cost.mjs +11 -2
- package/src/runtime/shared/llm/http-agent.mjs +313 -29
- package/src/runtime/shared/llm/model-catalog-projection.mjs +3 -2
- package/src/runtime/shared/llm/model-catalog.mjs +46 -6
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +3 -0
- package/src/runtime/shared/llm/system-proxy.mjs +452 -0
- package/src/runtime/shared/loopback-listener.mjs +25 -2
- package/src/runtime/shared/model-route-chain.d.mts +7 -2
- package/src/runtime/shared/model-route-chain.mjs +22 -4
- package/src/runtime/shared/open-url.mjs +10 -0
- package/src/runtime/shared/provider-accounts.mjs +52 -2
- package/src/runtime/shared/session-activity-signal.mjs +14 -0
- package/src/runtime/shared/session-scratch.mjs +37 -0
- package/src/runtime/shared/staged-install-worker.mjs +5 -0
- package/src/runtime/shared/staged-update.mjs +47 -2
- package/src/runtime/shared/tool-card-model/agent-surface.mjs +1 -3
- package/src/runtime/shared/tool-card-model/card-status.mjs +15 -2
- package/src/runtime/shared/tool-result-summary.mjs +1 -1
- package/src/runtime/shared/tool-surface.mjs +113 -36
- package/src/runtime/shared/tool-work-units.mjs +6 -0
- package/src/runtime/shared/turn-snapshot-store.mjs +13 -6
- package/src/runtime/shared/turn-worktree-snapshot.mjs +414 -54
- package/src/runtime/shared/worktrees/activity-gate.mjs +215 -318
- package/src/runtime/shared/worktrees/activity-ledger-worker.mjs +56 -0
- package/src/runtime/shared/worktrees/activity-ledger.mjs +391 -0
- package/src/runtime/shared/worktrees/branch-management.mjs +9 -3
- package/src/runtime/shared/worktrees/contract.mjs +4 -1
- package/src/runtime/shared/worktrees/git.mjs +72 -0
- package/src/runtime/shared/worktrees/manager.mjs +285 -168
- package/src/runtime/shared/worktrees/test-support.mjs +6 -10
- package/src/runtime/tidy/install.mjs +95 -15
- package/src/runtime/tidy/languages.mjs +17 -15
- package/src/runtime/tidy/process.mjs +7 -4
- package/src/runtime/tidy/resolve.mjs +19 -16
- package/src/runtime/tidy/runners/biome.mjs +3 -3
- package/src/runtime/tidy/tool.mjs +1 -1
- package/src/runtime/tidy/worktree.mjs +10 -6
- package/src/runtime/visualize-bridge/client.mjs +6 -1
- package/src/runtime/visualize-bridge/tool-defs.mjs +7 -2
- package/src/runtime/web-search/index.mjs +1 -1
- package/src/session-runtime/agent-home-delivery.mjs +41 -0
- package/src/session-runtime/agent-task-sessions.mjs +458 -312
- package/src/session-runtime/agent-tool-routing.mjs +8 -41
- package/src/session-runtime/boot/tools.mjs +7 -1
- package/src/session-runtime/bot-status.mjs +107 -101
- package/src/session-runtime/bot-target.mjs +38 -0
- package/src/session-runtime/channel-config-api.mjs +6 -1
- package/src/session-runtime/connector-merge-migration.mjs +18 -15
- package/src/session-runtime/conversation-import/codex-titles.mjs +88 -0
- package/src/session-runtime/conversation-import/discovery.mjs +401 -36
- package/src/session-runtime/conversation-import/service.mjs +35 -8
- package/src/session-runtime/handoff-attachments.mjs +82 -31
- package/src/session-runtime/held-requests.mjs +3 -1
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +12 -13
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +1 -0
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -0
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +8 -0
- package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +4 -1
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +145 -112
- package/src/session-runtime/lifecycle/cold-heir.mjs +11 -6
- package/src/session-runtime/lifecycle/session-catalog.mjs +9 -1
- package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -1
- package/src/session-runtime/lifecycle/teardown.mjs +1 -1
- package/src/session-runtime/mcp-glue/server-catalog.mjs +16 -10
- package/src/session-runtime/mcp-glue/server-input.mjs +4 -1
- package/src/session-runtime/mixy-heartbeat.mjs +1 -1
- package/src/session-runtime/model-route/set-route.mjs +11 -2
- package/src/session-runtime/provider-auth/login.mjs +2 -2
- package/src/session-runtime/provider-catalog-cache.mjs +82 -36
- package/src/session-runtime/provider-models/catalog-load.mjs +23 -6
- package/src/session-runtime/provider-models.mjs +4 -2
- package/src/session-runtime/resource-mcp-api.mjs +98 -35
- package/src/session-runtime/resource-mcp-connector-accounts.mjs +44 -31
- package/src/session-runtime/resource-mcp-secrets.mjs +28 -11
- package/src/session-runtime/resource-mcp-servers.mjs +5 -4
- package/src/session-runtime/resource-recall-api.mjs +6 -1
- package/src/session-runtime/runtime-feature-gates.mjs +5 -1
- package/src/session-runtime/services/agent-tool/execute.mjs +14 -9
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +20 -4
- package/src/session-runtime/services/agent-tool/model-select.mjs +48 -7
- package/src/session-runtime/services/agent-tool/render.mjs +71 -17
- package/src/session-runtime/services/agent-tool/send-flow.mjs +10 -2
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +8 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +4 -1
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +6 -2
- package/src/session-runtime/services/agent-tool/tool-def.mjs +9 -9
- package/src/session-runtime/services/agent-watchdog-registry.mjs +32 -4
- package/src/session-runtime/services/channel-worker/daemon-spawn.mjs +2 -0
- package/src/session-runtime/services/daemon-candidate.mjs +4 -1
- package/src/session-runtime/services/memory-runtime-proxy/daemon-spawn.mjs +4 -0
- package/src/session-runtime/services/plugin-admin.mjs +10 -6
- package/src/session-runtime/services/provider-admin.mjs +283 -11
- package/src/session-runtime/session-turn-api.mjs +2 -0
- package/src/session-runtime/settings-builtin-tools-api.mjs +4 -1
- package/src/session-runtime/settings-system-api.mjs +1 -1
- package/src/session-runtime/setup-tool/agent-settings-actions.mjs +13 -3
- package/src/session-runtime/setup-tool/connector-widen-approval.mjs +96 -0
- package/src/session-runtime/setup-tool/executor.mjs +6 -2
- package/src/session-runtime/setup-tool/tool-defs.mjs +2 -1
- package/src/session-runtime/tool-policy/policy-stage.mjs +1 -0
- package/src/session-runtime/turn/agent-ops.mjs +23 -0
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +49 -11
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +5 -1
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +25 -5
- package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -3
- package/src/session-runtime/workspace/activity-guards.mjs +176 -0
- package/src/session-runtime/workspace/session-view.mjs +149 -0
- package/src/session-runtime/workspace/side-checkouts.mjs +203 -0
- package/src/session-runtime/workspace/transition-runner.mjs +188 -0
- package/src/session-runtime/workspace/transitions.mjs +108 -1041
- package/src/session-runtime/workspace/workspace-merge.mjs +132 -0
- package/src/session-runtime/workspace/worktree-intents.mjs +242 -0
- package/src/session-runtime/workspace/worktree-maintenance.mjs +80 -0
- package/src/session-runtime/workspace/worktree-setup.mjs +85 -0
- package/src/session-runtime/workspace/worktree-tool.mjs +73 -56
- package/src/standalone/daemon-desktop-runtime.mjs +2 -0
- package/src/standalone/daemon-session-control.mjs +169 -138
- package/src/standalone/daemon.mjs +7 -0
- package/src/standalone/desktop-service-registry.mjs +9 -0
- package/src/standalone/local-session-runtime.mjs +5 -1
- package/src/standalone/session-client/daemon-unavailable.mjs +3 -0
- package/src/standalone/session-client.mjs +5 -1
- package/src/standalone/session-frame-stream.mjs +83 -11
- package/src/standalone/session-protocol.mjs +4 -0
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +16 -12
- package/src/standalone/session-service/agent-tree.mjs +45 -9
- package/src/standalone/session-service/projection/transcript-window.mjs +700 -64
- package/src/standalone/session-service/session-calls/session-action.mjs +10 -3
- package/src/standalone/session-service/session-calls/session-views.mjs +160 -104
- package/src/standalone/session-service/stored-reader.mjs +127 -40
- package/src/standalone/session-transport/client-registry/client-grace.mjs +12 -9
- package/src/tui/App.jsx +154 -164
- package/src/tui/app/app-view/floating-panel.jsx +10 -4
- package/src/tui/app/app-view/text-entry-labels.mjs +1 -0
- package/src/tui/app/clipboard.mjs +21 -10
- package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +1 -3
- package/src/tui/app/model-picker/route-selection.mjs +5 -6
- package/src/tui/app/prompt-handlers/use-prompt-history-nav.mjs +1 -1
- package/src/tui/app/prompt-handlers/use-prompt-interrupt.mjs +3 -0
- package/src/tui/app/prompt-submit/provider-prompts.mjs +3 -1
- package/src/tui/app/provider-setup/api-key-actions.mjs +31 -1
- package/src/tui/app/provider-setup/oauth-actions.mjs +58 -21
- package/src/tui/app/provider-setup/provider-items.mjs +8 -2
- package/src/tui/app/provider-setup-picker.mjs +29 -18
- package/src/tui/app/shell-layout/row-budgets.mjs +12 -10
- package/src/tui/app/slash-commands.mjs +1 -0
- package/src/tui/app/slash-dispatch/session-commands.mjs +46 -0
- package/src/tui/app/slash-dispatch.mjs +1 -1
- package/src/tui/app/use-btw-panel.mjs +29 -0
- package/src/tui/app/use-context-panel-refresh.mjs +31 -0
- package/src/tui/app/use-model-catalog-cache.mjs +13 -10
- package/src/tui/app/use-mouse-input.mjs +11 -0
- package/src/tui/app/use-onboarding-start.mjs +8 -3
- package/src/tui/app/use-panel-transition.mjs +10 -1
- package/src/tui/app/use-pasted-buffers.mjs +28 -20
- package/src/tui/app/use-prompt-draft-flow.mjs +7 -0
- package/src/tui/app/use-prompt-layout-rows.mjs +3 -3
- package/src/tui/app/use-prompt-queue-history.mjs +3 -2
- package/src/tui/app/use-selection-focus.mjs +11 -2
- package/src/tui/app/use-selection-geometry.mjs +18 -9
- package/src/tui/app/use-selection-paint.mjs +4 -4
- package/src/tui/app/use-selection-stitch.mjs +3 -3
- package/src/tui/app/use-slash-palette.mjs +62 -0
- package/src/tui/app/use-terminal-chrome.mjs +2 -2
- package/src/tui/app/use-transcript-activity.mjs +47 -32
- package/src/tui/app/use-transcript-follow.mjs +12 -4
- package/src/tui/app/use-transcript-scroll.mjs +46 -17
- package/src/tui/app/use-transcript-swap-reset.mjs +27 -0
- package/src/tui/app/use-transcript-window/geometry.mjs +19 -5
- package/src/tui/app/use-transcript-window/instance-state.mjs +4 -0
- package/src/tui/app/use-transcript-window/selection-shift.mjs +5 -1
- package/src/tui/app/use-transcript-window.mjs +21 -11
- package/src/tui/app/use-tui-ready.mjs +18 -0
- package/src/tui/app/use-welcome-prompt-hint.mjs +5 -0
- package/src/tui/app/use-workflow-tab-cycle.mjs +5 -3
- package/src/tui/components/Picker.jsx +27 -3
- package/src/tui/components/QuestionPanel.jsx +13 -4
- package/src/tui/components/SignInUrl.jsx +68 -0
- package/src/tui/components/TextEntryPanel.jsx +76 -46
- package/src/tui/components/sign-in-url-layout.mjs +24 -0
- package/src/tui/dist/index.mjs +1963 -1361
- package/src/tui/session/goal-turn-state.mjs +6 -2
- package/src/tui/session/session-api/controls.mjs +4 -0
- package/src/tui/session/session-api/extensions.mjs +8 -0
- package/src/tui/session/session-api/intake/abort.mjs +2 -1
- package/src/tui/session/session-api/intake.mjs +2 -0
- package/src/tui/session/session-api/integrations.mjs +2 -2
- package/src/tui/session/session-api/routes-agent-definitions.mjs +1 -0
- package/src/tui/session/session-api/settings.mjs +2 -2
- package/src/tui/session/session-flow/queue/take-entries.mjs +11 -0
- package/src/tui/session/transcript-spill/spill-writer.mjs +15 -0
- package/src/tui/session/transcript-spill.mjs +92 -4
- package/src/tui/session/transcript-store.mjs +2 -0
- package/src/ui/statusline-agents.mjs +1 -3
- package/src/defaults/skills/skill-creator/references/source-review.md +0 -94
|
@@ -15,6 +15,12 @@
|
|
|
15
15
|
* answer or approval posts one faint line instead; the card stays in the task
|
|
16
16
|
* session for the user.
|
|
17
17
|
*
|
|
18
|
+
* Whether a turn reports is apart from whose work it is: every accepted send
|
|
19
|
+
* of an agent is the agent's work in that session (bot-owned-work.mjs, shown
|
|
20
|
+
* as the bot working) until its chain ends, the point a report would be
|
|
21
|
+
* final, and with `notify: false` or an unstored watch it reports nothing.
|
|
22
|
+
* A turn the user types there is owned by no agent.
|
|
23
|
+
*
|
|
18
24
|
* An agent's send to any other session reports the same way, by an origin for
|
|
19
25
|
* that send only (reportOrigin). Every reporting turn is also watched durably
|
|
20
26
|
* (agent-home-delivery.mjs `watches`) until its end is queued, so a daemon
|
|
@@ -41,6 +47,7 @@ import { wrapAgentMessage } from '../runtime/shared/agent-message-envelope.mjs';
|
|
|
41
47
|
import { hasPendingAgentWork, sessionsWithPendingWork } from '../runtime/shared/pending-agent-work.mjs';
|
|
42
48
|
import { agentTaskIdOfExecution } from './services/agent-tool/restart-notify.mjs';
|
|
43
49
|
import { botChainOf } from '../runtime/shared/bot-hops.mjs';
|
|
50
|
+
import { endBotWork, noteBotWork } from '../runtime/shared/bot-owned-work.mjs';
|
|
44
51
|
import { worktreeError, worktreeNameError } from '../runtime/shared/worktrees/contract.mjs';
|
|
45
52
|
import { samePath } from '../runtime/shared/worktrees/paths.mjs';
|
|
46
53
|
import { readModelCatalog, routeByDisplayName, withEffort } from './task-session-route.mjs';
|
|
@@ -813,17 +820,24 @@ async function sendReportOrigin({ loadSession, agentName }, sessionId, agentId,
|
|
|
813
820
|
}
|
|
814
821
|
|
|
815
822
|
/** Re-attach one watch a stopped daemon left: report the turn's end once
|
|
816
|
-
* from the target's record, or watch it until it ends.
|
|
823
|
+
* from the target's record, or watch it until it ends. `quiet`: `watch` is
|
|
824
|
+
* the record of work that reports nothing (no home, no title): the same
|
|
825
|
+
* follow, but its end is only the end of the agent's work, dropped from
|
|
826
|
+
* `disown`, and no progress update or report goes out. */
|
|
817
827
|
async function rearmTaskWatch(
|
|
818
|
-
{ deliver, loadSession, materializeSession, queuedSubmissionIds, artifactFields, followToFinal, log },
|
|
819
|
-
watch
|
|
828
|
+
{ deliver, disown, loadSession, materializeSession, queuedSubmissionIds, artifactFields, followToFinal, log },
|
|
829
|
+
watch,
|
|
830
|
+
{ quiet = false } = {}
|
|
820
831
|
) {
|
|
821
832
|
const sessionId = watch.taskSessionId;
|
|
822
833
|
// The turn that answers: the watched submission's own, or the one it
|
|
823
834
|
// follows (a room member's turn under another submission id).
|
|
824
835
|
const turnId = watch.follows || watch.runId;
|
|
825
|
-
|
|
826
|
-
|
|
836
|
+
// The work is the agent's until its end is reported (or cannot be).
|
|
837
|
+
const finish = async (status, text = '', answerId = '') => {
|
|
838
|
+
endBotWork(watch.runId);
|
|
839
|
+
if (quiet) return disown(watch.runId);
|
|
840
|
+
return deliver(watch.agentId, {
|
|
827
841
|
runId: `${watch.runId}_end`,
|
|
828
842
|
taskSessionId: sessionId,
|
|
829
843
|
title: watch.title,
|
|
@@ -836,6 +850,7 @@ async function rearmTaskWatch(
|
|
|
836
850
|
...progressOf(watch.runId, answerId),
|
|
837
851
|
...(watch.textOnly || text === GONE_TEXT || text === LOST_TEXT ? {} : await artifactFields(sessionId, turnId)),
|
|
838
852
|
});
|
|
853
|
+
};
|
|
839
854
|
if (!(await loadSession(sessionId))) return finish('cancelled', GONE_TEXT);
|
|
840
855
|
let runtime;
|
|
841
856
|
try {
|
|
@@ -845,6 +860,7 @@ async function rearmTaskWatch(
|
|
|
845
860
|
log(`${sessionId} could not be loaded after the restart: ${error?.message || error}`);
|
|
846
861
|
return finish('failed', RESUME_FAILED_TEXT);
|
|
847
862
|
}
|
|
863
|
+
noteBotWork({ runId: watch.runId, sessionId, agentId: watch.agentId });
|
|
848
864
|
let done = false;
|
|
849
865
|
let checking = false;
|
|
850
866
|
let again = false;
|
|
@@ -878,22 +894,26 @@ async function rearmTaskWatch(
|
|
|
878
894
|
sessionId,
|
|
879
895
|
runId: turnId,
|
|
880
896
|
runtime,
|
|
881
|
-
|
|
897
|
+
// Only a report wakes the session for the results the restart left
|
|
898
|
+
// it; work that reports nothing is only observed, never driven.
|
|
899
|
+
wakeOwed: !quiet,
|
|
882
900
|
// The turns an earlier process already reported as progress.
|
|
883
901
|
progressedThrough: watch.progressed || '',
|
|
884
|
-
interim:
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
902
|
+
interim: quiet
|
|
903
|
+
? null
|
|
904
|
+
: (answer) =>
|
|
905
|
+
deliver(watch.agentId, {
|
|
906
|
+
runId: progressRunId(watch.runId, answer.id),
|
|
907
|
+
taskSessionId: sessionId,
|
|
908
|
+
title: watch.title,
|
|
909
|
+
status: 'working',
|
|
910
|
+
text: answer.text,
|
|
911
|
+
progressWatchId: watch.runId,
|
|
912
|
+
answerId: answer.id,
|
|
913
|
+
...(watch.target === 'session' ? { target: 'session' } : {}),
|
|
914
|
+
...(watch.hop > 0 ? { hop: watch.hop } : {}),
|
|
915
|
+
...roomFrom(watch.homeSessionId),
|
|
916
|
+
}),
|
|
897
917
|
finish: async (status, text, answerId) => {
|
|
898
918
|
done = true;
|
|
899
919
|
unsubscribe();
|
|
@@ -925,13 +945,16 @@ function createSendSettlement(log) {
|
|
|
925
945
|
const settledTurns = new WeakMap();
|
|
926
946
|
let sendCount = 0;
|
|
927
947
|
|
|
928
|
-
/** Add send `member` (`{ seq, id, unwatch, settle }`) to the settlement
|
|
948
|
+
/** Add send `member` (`{ seq, id, notify, unwatch, settle }`) to the settlement
|
|
929
949
|
* `detail` of its turn, per reporting conversation. The sends of one turn
|
|
930
950
|
* settle in the same tick; after it the earliest (the turn's own, whose
|
|
931
951
|
* record holds the whole turn) settles with all their ids and the others
|
|
932
952
|
* stand down. */
|
|
933
953
|
function join(detail, origin, member) {
|
|
934
|
-
|
|
954
|
+
// Sends that report and sends that do not settle apart: the group's first
|
|
955
|
+
// member settles for the group, so a quiet one must never stand for a
|
|
956
|
+
// send that owes a report.
|
|
957
|
+
const key = `${origin.agentId}\0${origin.sessionId}\0${member.notify ? 'report' : 'quiet'}`;
|
|
935
958
|
let groups = settledTurns.get(detail);
|
|
936
959
|
if (!groups) {
|
|
937
960
|
groups = new Map();
|
|
@@ -1071,17 +1094,392 @@ function startedGate() {
|
|
|
1071
1094
|
return { ready, started };
|
|
1072
1095
|
}
|
|
1073
1096
|
|
|
1097
|
+
/** The report delivery of send `id` of `origin` to task session `sessionId`.
|
|
1098
|
+
* `turn` (`{ runtime, sendIds }`) is what its turn knows when a report goes
|
|
1099
|
+
* out: the live runtime and the sends its end closes. A report that cannot
|
|
1100
|
+
* be queued is retried in this process; when every try fails the durable
|
|
1101
|
+
* watch stays and restart recovery delivers it (the queue dedupes by runId,
|
|
1102
|
+
* so a retry never posts twice). `answerId`: the turn whose answer a
|
|
1103
|
+
* progress update or the end carries. `deliverReport` rejects once every
|
|
1104
|
+
* try failed (a progress update is tried again at the follow's next check);
|
|
1105
|
+
* `report` logs it instead. */
|
|
1106
|
+
function sendReporter({ deliver, retryDelaysMs, artifactFields, log }, { sessionId, id, origin, beforeReport, turn }) {
|
|
1107
|
+
const target = origin.target === 'session' ? { target: 'session' } : {};
|
|
1108
|
+
const deliverReport = (status, text = '', { approvalId = '', answerId = '' } = {}) =>
|
|
1109
|
+
Promise.resolve(beforeReport).then(async () =>
|
|
1110
|
+
deliverWithRetries({ deliver, retryDelaysMs, log }, origin.agentId, sessionId, {
|
|
1111
|
+
runId: turnReportRunId(sessionId, id, status, { approvalId, answerId }),
|
|
1112
|
+
taskSessionId: sessionId,
|
|
1113
|
+
title: origin.title,
|
|
1114
|
+
status,
|
|
1115
|
+
text,
|
|
1116
|
+
...target,
|
|
1117
|
+
...(origin.hop > 0 ? { hop: origin.hop } : {}),
|
|
1118
|
+
...roomFrom(origin.sessionId),
|
|
1119
|
+
// A progress update moves this send's durable mark to its turn
|
|
1120
|
+
// (agent-home-delivery.mjs enqueueTask), in the same write.
|
|
1121
|
+
...(status === 'working' ? { progressWatchId: id, answerId } : {}),
|
|
1122
|
+
// A turn's end brings back the files it produced, when the agent
|
|
1123
|
+
// may receive them (reportOrigin `textOnly`).
|
|
1124
|
+
...(status === 'blocked' || status === 'working'
|
|
1125
|
+
? {}
|
|
1126
|
+
: {
|
|
1127
|
+
watchId: id,
|
|
1128
|
+
...(turn.sendIds.length > 1 ? { watchIds: turn.sendIds } : {}),
|
|
1129
|
+
...progressOf(id, answerId),
|
|
1130
|
+
...(origin.textOnly ? {} : await artifactFields(sessionId, id, turn.runtime)),
|
|
1131
|
+
}),
|
|
1132
|
+
})
|
|
1133
|
+
);
|
|
1134
|
+
const report = (status, text = '', options = {}) =>
|
|
1135
|
+
deliverReport(status, text, options).catch((error) =>
|
|
1136
|
+
log(`report of ${sessionId} failed: ${error?.message || error}`)
|
|
1137
|
+
);
|
|
1138
|
+
return { deliverReport, report };
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
/** The agent's work in `sessionId` for send `id`: owned from the send's
|
|
1142
|
+
* acceptance until it settles or is cancelled, whether or not it reports. A
|
|
1143
|
+
* send that holds no report watch keeps a durable record of the work instead
|
|
1144
|
+
* (`watches.own`), so a restart re-attaches it (recover); the writes of one
|
|
1145
|
+
* send go in order, so a record never outlives its work. */
|
|
1146
|
+
function sendWork({ watches, owner, log }, { sessionId, id, agentId }) {
|
|
1147
|
+
let owning = true;
|
|
1148
|
+
let recorded = false;
|
|
1149
|
+
let recording = Promise.resolve();
|
|
1150
|
+
const record = (write) => {
|
|
1151
|
+
recording = recording
|
|
1152
|
+
.then(write)
|
|
1153
|
+
.catch((error) => log(`recording the work of ${sessionId} failed: ${error?.message || error}`));
|
|
1154
|
+
return recording;
|
|
1155
|
+
};
|
|
1156
|
+
return {
|
|
1157
|
+
/** The work of every send `ids` this turn answered ends together: one
|
|
1158
|
+
* write drops all their records (a send standing down for the turn's
|
|
1159
|
+
* first leaves its record to that one write). */
|
|
1160
|
+
disown(ids = [id]) {
|
|
1161
|
+
owning = false;
|
|
1162
|
+
for (const done of ids) endBotWork(done);
|
|
1163
|
+
if (recorded || ids.length > 1) void record(() => watches.disown?.(ids));
|
|
1164
|
+
},
|
|
1165
|
+
/** Standing down for the turn's first send, which owns the same work. */
|
|
1166
|
+
standDown() {
|
|
1167
|
+
owning = false;
|
|
1168
|
+
endBotWork(id);
|
|
1169
|
+
},
|
|
1170
|
+
/** The send was accepted: unless it already settled (nothing then is left
|
|
1171
|
+
* to end the work), the work is the agent's, recorded when `notify` is off.
|
|
1172
|
+
* Returns the recording to await, or nothing when there is none. */
|
|
1173
|
+
claim(notify) {
|
|
1174
|
+
if (!owning) return undefined;
|
|
1175
|
+
noteBotWork({ runId: id, sessionId, agentId });
|
|
1176
|
+
if (notify) return undefined;
|
|
1177
|
+
recorded = true;
|
|
1178
|
+
return record(() => watches.own?.({ runId: id, agentId, taskSessionId: sessionId, owner, at: Date.now() }));
|
|
1179
|
+
},
|
|
1180
|
+
};
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
/** Submit `prompt` as the origin agent's turn; its end (and a wait for the
|
|
1184
|
+
* user in it) reports to the agent's home. Resolves on intake. `submit`
|
|
1185
|
+
* takes the turn in another way than a prompt to `sessionId` (a message
|
|
1186
|
+
* into a group room, whose member answers in `sessionId`): given `{ id,
|
|
1187
|
+
* onSettled }`, it resolves `{ accepted }`. */
|
|
1188
|
+
async function runAgentTurn(
|
|
1189
|
+
deps,
|
|
1190
|
+
sessionId,
|
|
1191
|
+
prompt,
|
|
1192
|
+
origin,
|
|
1193
|
+
id = `atask_${randomUUID()}`,
|
|
1194
|
+
beforeReport = null,
|
|
1195
|
+
submit = null
|
|
1196
|
+
) {
|
|
1197
|
+
const { watches, followToFinal, settlement, processToken, log } = deps;
|
|
1198
|
+
const sessions = deps.service();
|
|
1199
|
+
const { notify, noReport } = await watchTurn({ watches, owner: processToken, log }, sessionId, origin, id);
|
|
1200
|
+
const dropWatch = () =>
|
|
1201
|
+
watches.remove(id).catch((error) => log(`dropping the watch of ${sessionId} failed: ${error?.message || error}`));
|
|
1202
|
+
// `sendIds`: the sends this turn's end closes: this one, plus any that its
|
|
1203
|
+
// turn answered too (createSendSettlement).
|
|
1204
|
+
const turn = { runtime: null, sendIds: [id] };
|
|
1205
|
+
const { deliverReport, report } = sendReporter(deps, { sessionId, id, origin, beforeReport, turn });
|
|
1206
|
+
let unwatch = () => {};
|
|
1207
|
+
const work = sendWork({ watches, owner: processToken, log }, { sessionId, id, agentId: origin.agentId });
|
|
1208
|
+
// Set once the turn ended completed: the work and any report wait for the
|
|
1209
|
+
// final answer.
|
|
1210
|
+
let follow = null;
|
|
1211
|
+
let result;
|
|
1212
|
+
/** This send ends the turn `detail` for the sends `answered` (createSendSettlement). */
|
|
1213
|
+
const settleTurn = (detail, answered) => {
|
|
1214
|
+
turn.sendIds = answered;
|
|
1215
|
+
const status = turnStatus(detail);
|
|
1216
|
+
const text = detail?.result?.content || detail?.error || '';
|
|
1217
|
+
// A failed or cancelled turn ends at once; a completed one ends with
|
|
1218
|
+
// the task's final answer (followToFinal).
|
|
1219
|
+
if (status !== 'completed') {
|
|
1220
|
+
unwatch();
|
|
1221
|
+
work.disown(turn.sendIds);
|
|
1222
|
+
if (notify) void report(status, text);
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
follow = followToFinal({
|
|
1226
|
+
sessionId,
|
|
1227
|
+
runId: id,
|
|
1228
|
+
runtime: turn.runtime,
|
|
1229
|
+
immediate: { status, text },
|
|
1230
|
+
finish: async (endStatus, endText, answerId) => {
|
|
1231
|
+
unwatch();
|
|
1232
|
+
work.disown(turn.sendIds);
|
|
1233
|
+
if (notify) await report(endStatus, endText, { answerId });
|
|
1234
|
+
},
|
|
1235
|
+
// Each other answer of its chain: a progress update that wakes nobody
|
|
1236
|
+
// (only a send that reports gives them).
|
|
1237
|
+
...(notify ? { interim: (answer) => deliverReport('working', answer.text, { answerId: answer.id }) } : {}),
|
|
1238
|
+
});
|
|
1239
|
+
follow.check();
|
|
1240
|
+
};
|
|
1241
|
+
try {
|
|
1242
|
+
const runtime = await sessions.materializeSession(sessionId);
|
|
1243
|
+
turn.runtime = runtime;
|
|
1244
|
+
const onState = notify ? approvalWaitReporter(id, report) : null;
|
|
1245
|
+
unwatch =
|
|
1246
|
+
runtime?.subscribe?.(() => {
|
|
1247
|
+
follow?.check();
|
|
1248
|
+
onState?.(runtime.getState?.() || {});
|
|
1249
|
+
}) || unwatch;
|
|
1250
|
+
// A bot's send to a session that is not its own task session reaches the
|
|
1251
|
+
// model inside the sender envelope (`envelopeName`, set by reportOrigin).
|
|
1252
|
+
const sent = origin.envelopeName
|
|
1253
|
+
? wrapAgentMessage(prompt, { name: origin.envelopeName, agentId: origin.agentId })
|
|
1254
|
+
: prompt;
|
|
1255
|
+
const take = submit ?? ((options) => sessions.submitSession({ sessionId, prompt: sent, options }));
|
|
1256
|
+
const seq = settlement.nextSeq();
|
|
1257
|
+
result = await take({
|
|
1258
|
+
id,
|
|
1259
|
+
mode: 'prompt',
|
|
1260
|
+
transcriptMeta: sendTranscriptMeta(origin),
|
|
1261
|
+
// A room answers this send in a turn under another submission id (one
|
|
1262
|
+
// turn for several sends, or a fresh turn for one cut short): the
|
|
1263
|
+
// watch follows that turn, recorded before it runs.
|
|
1264
|
+
...(notify ? { follow: (submissionId) => watches.follow?.(id, submissionId) } : {}),
|
|
1265
|
+
onSettled: (detail) =>
|
|
1266
|
+
settlement.join(detail, origin, {
|
|
1267
|
+
seq,
|
|
1268
|
+
id,
|
|
1269
|
+
notify,
|
|
1270
|
+
unwatch: () => {
|
|
1271
|
+
unwatch();
|
|
1272
|
+
work.standDown();
|
|
1273
|
+
},
|
|
1274
|
+
settle: (answered) => settleTurn(detail, answered),
|
|
1275
|
+
}),
|
|
1276
|
+
});
|
|
1277
|
+
} catch (error) {
|
|
1278
|
+
unwatch();
|
|
1279
|
+
work.disown();
|
|
1280
|
+
if (notify) await dropWatch();
|
|
1281
|
+
throw error;
|
|
1282
|
+
}
|
|
1283
|
+
const accepted = result?.accepted === true;
|
|
1284
|
+
if (!accepted) {
|
|
1285
|
+
unwatch();
|
|
1286
|
+
work.disown();
|
|
1287
|
+
if (notify) await dropWatch();
|
|
1288
|
+
} else {
|
|
1289
|
+
const recording = work.claim(notify);
|
|
1290
|
+
if (recording) await recording;
|
|
1291
|
+
}
|
|
1292
|
+
return sendResult(accepted, notify, id, noReport);
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
/** Daemon start: re-attach every reporting turn an earlier process watched,
|
|
1296
|
+
* and every turn of a bot's that reported nothing but whose work it owned
|
|
1297
|
+
* (nothing is reported for those, they are only the bot's work again).
|
|
1298
|
+
* Resolves once each is reported or watched. */
|
|
1299
|
+
async function recoverTaskWatches({ watches, settleAgentResults, rearm, processToken, log }) {
|
|
1300
|
+
const earlier = (list) => list.filter((entry) => entry?.owner !== processToken);
|
|
1301
|
+
const pending = earlier(await watches.list());
|
|
1302
|
+
// A store without records of quiet work (`owned` is optional) has none; a
|
|
1303
|
+
// failed read of them never keeps the reporting turns from re-attaching.
|
|
1304
|
+
const quiet = earlier(
|
|
1305
|
+
await Promise.resolve(watches.owned?.() ?? []).catch((error) => {
|
|
1306
|
+
log(`reading the records of bot work failed: ${error?.message || error}`);
|
|
1307
|
+
return [];
|
|
1308
|
+
})
|
|
1309
|
+
);
|
|
1310
|
+
// The agents the restart killed become queued failure results first, so
|
|
1311
|
+
// each re-attached task session has them to take (followToFinal wakeOwed).
|
|
1312
|
+
if (pending.length) {
|
|
1313
|
+
await Promise.resolve()
|
|
1314
|
+
.then(settleAgentResults)
|
|
1315
|
+
.catch((error) => log(`settling the agents of the previous process failed: ${error?.message || error}`));
|
|
1316
|
+
}
|
|
1317
|
+
const reattach = (work, options) =>
|
|
1318
|
+
rearm(work, options).catch((error) =>
|
|
1319
|
+
log(`re-attaching ${work?.taskSessionId} failed: ${error?.message || error}`)
|
|
1320
|
+
);
|
|
1321
|
+
await Promise.all([
|
|
1322
|
+
...pending.map((watch) => reattach(watch)),
|
|
1323
|
+
...quiet.map((work) => reattach(work, { quiet: true })),
|
|
1324
|
+
]);
|
|
1325
|
+
return pending.length + quiet.length;
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
/** The route a task session starts on: it runs in coding mode under Lead: an
|
|
1329
|
+
* explicit model wins, else the Lead route, else the last-used model. Never a
|
|
1330
|
+
* model-less session — the composer would show no model and its first turn
|
|
1331
|
+
* would fail. The catalog is read only when a display name or an effort
|
|
1332
|
+
* needs it. */
|
|
1333
|
+
async function taskRoute({ modelRoute, modelCatalog, leadRoute, lastUsedRoute, service }, args, callerSessionId) {
|
|
1334
|
+
let catalog = null;
|
|
1335
|
+
const catalogRows = async () => (catalog ??= await modelCatalog(callerSessionId));
|
|
1336
|
+
let route = clean(args.model)
|
|
1337
|
+
? await modelRoute(clean(args.model), async (text) =>
|
|
1338
|
+
routeByDisplayName(text, await catalogRows(), args.effort !== undefined)
|
|
1339
|
+
)
|
|
1340
|
+
: (await leadRoute()) || (await lastUsedRoute(service()));
|
|
1341
|
+
if (!route) throw new Error('session: no model to start the task session on. Choose a Lead model first.');
|
|
1342
|
+
// An explicit effort is the setting the menu's effort pick makes (session.effort,
|
|
1343
|
+
// Auto effort off); it wins over one a model ref or name carried.
|
|
1344
|
+
if (args.effort !== undefined) route = withEffort(route, args.effort, await catalogRows());
|
|
1345
|
+
return route;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
/** Nothing was sent after the worktree failure `error`: drop the empty task
|
|
1349
|
+
* session `sessionId` so a retry starts clean, then throw `error` (an
|
|
1350
|
+
* orphanSessionError when the session could not be dropped). */
|
|
1351
|
+
async function dropEmptyTaskSession(sessions, sessionId, error, log) {
|
|
1352
|
+
let dropFailure = null;
|
|
1353
|
+
try {
|
|
1354
|
+
const dropped = await sessions.configureSession(
|
|
1355
|
+
{ sessionId, action: 'deleteSession', args: [sessionId] },
|
|
1356
|
+
{ revision: 1 }
|
|
1357
|
+
);
|
|
1358
|
+
// A resolved `false` is a refusal, not a deletion.
|
|
1359
|
+
if (dropped?.value === false) dropFailure = new Error('the session service refused the deletion');
|
|
1360
|
+
} catch (deleteError) {
|
|
1361
|
+
dropFailure = deleteError;
|
|
1362
|
+
}
|
|
1363
|
+
if (dropFailure) log(`dropping ${sessionId} failed: ${dropFailure?.message || dropFailure}`);
|
|
1364
|
+
if (!dropFailure) throw error;
|
|
1365
|
+
throw orphanSessionError(error, sessionId, dropFailure);
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
/** Create the task session for `brief` and start it; returns at once.
|
|
1369
|
+
* `callerScope` is the caller's trusted worktree scope (worktree-access.mjs
|
|
1370
|
+
* worktreeCallerScope): provisioning a worktree is a mutation only an
|
|
1371
|
+
* attended conversation may make, so an explicit worktree from any other
|
|
1372
|
+
* caller is refused and the New task default keeps it in the Project folder. */
|
|
1373
|
+
async function createTaskSession(
|
|
1374
|
+
deps,
|
|
1375
|
+
args = {},
|
|
1376
|
+
{
|
|
1377
|
+
callerSessionId,
|
|
1378
|
+
callerAgentId,
|
|
1379
|
+
callerCwd,
|
|
1380
|
+
callerHop = 0,
|
|
1381
|
+
callerBotChain = [],
|
|
1382
|
+
callerScope,
|
|
1383
|
+
attachmentParts = [],
|
|
1384
|
+
} = {}
|
|
1385
|
+
) {
|
|
1386
|
+
const { service, listProjects, newTaskDefault, deliver, agentTurn, log } = deps;
|
|
1387
|
+
const { brief, location } = createRequest(args, callerAgentId, callerScope);
|
|
1388
|
+
const where = createWhere(args, await listProjects(), callerCwd, location);
|
|
1389
|
+
const requestId = `atask_${randomUUID()}`;
|
|
1390
|
+
const title = (clean(args.title) || clean(brief.split('\n')[0])).slice(0, TITLE_LIMIT);
|
|
1391
|
+
const taskOrigin = {
|
|
1392
|
+
agentId: callerAgentId,
|
|
1393
|
+
sessionId: callerSessionId,
|
|
1394
|
+
requestId,
|
|
1395
|
+
title,
|
|
1396
|
+
notify: args.notify !== false,
|
|
1397
|
+
};
|
|
1398
|
+
const route = await taskRoute(deps, args, callerSessionId);
|
|
1399
|
+
const sessions = service();
|
|
1400
|
+
// Where it starts: the `worktree` option, else the user's New task default
|
|
1401
|
+
// for a caller that may provision one. Decided before the session exists,
|
|
1402
|
+
// so a failure here leaves nothing behind.
|
|
1403
|
+
const explicit = location.mode === 'worktree';
|
|
1404
|
+
const inWorktree =
|
|
1405
|
+
explicit ||
|
|
1406
|
+
(location.mode === 'default' &&
|
|
1407
|
+
where.project &&
|
|
1408
|
+
callerScope?.attended === true &&
|
|
1409
|
+
(await newTaskDefault()) === 'worktree');
|
|
1410
|
+
const created = await sessions.createSession({
|
|
1411
|
+
...route,
|
|
1412
|
+
cwd: where.cwd,
|
|
1413
|
+
desktopSession: where.desktopSession,
|
|
1414
|
+
sessionProfile: { taskOrigin },
|
|
1415
|
+
});
|
|
1416
|
+
const sessionId = String(created?.sessionId || '');
|
|
1417
|
+
if (!sessionId) throw new Error('session: task session creation returned no session id');
|
|
1418
|
+
if (inWorktree) {
|
|
1419
|
+
try {
|
|
1420
|
+
await requestTaskWorktree(sessions, sessionId, {
|
|
1421
|
+
title,
|
|
1422
|
+
requestId,
|
|
1423
|
+
name: location.name,
|
|
1424
|
+
confirmLarge: args.confirm_large === true,
|
|
1425
|
+
explicit,
|
|
1426
|
+
});
|
|
1427
|
+
} catch (error) {
|
|
1428
|
+
await dropEmptyTaskSession(sessions, sessionId, error, log);
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
const { ready, started } = startedGate();
|
|
1432
|
+
// The brief carries the files the agent forwarded (workspace-tools.mjs).
|
|
1433
|
+
const prompt = handoffContent(brief, attachmentParts);
|
|
1434
|
+
const botChain = botChainOf(callerBotChain);
|
|
1435
|
+
const { accepted, reportsBack, reportsBackReason } = await agentTurn(
|
|
1436
|
+
sessionId,
|
|
1437
|
+
prompt,
|
|
1438
|
+
{ ...taskOrigin, ...(callerHop > 0 ? { hop: callerHop } : {}), ...(botChain.length ? { botChain } : {}) },
|
|
1439
|
+
requestId,
|
|
1440
|
+
ready
|
|
1441
|
+
);
|
|
1442
|
+
if (!accepted) throw new Error(`session: task session ${sessionId} did not accept the brief`);
|
|
1443
|
+
if (reportsBack) {
|
|
1444
|
+
await deliver(callerAgentId, {
|
|
1445
|
+
runId: `${requestId}_started`,
|
|
1446
|
+
taskSessionId: sessionId,
|
|
1447
|
+
title,
|
|
1448
|
+
status: 'started',
|
|
1449
|
+
...roomFrom(callerSessionId),
|
|
1450
|
+
}).catch((error) => log(`start line of ${sessionId} failed: ${error?.message || error}`));
|
|
1451
|
+
}
|
|
1452
|
+
started();
|
|
1453
|
+
// Started, not done: the final answer is reported later.
|
|
1454
|
+
return {
|
|
1455
|
+
session_id: sessionId,
|
|
1456
|
+
status: 'started',
|
|
1457
|
+
title,
|
|
1458
|
+
project: where.project?.path ?? null,
|
|
1459
|
+
...(taskOrigin.notify && !reportsBack ? { reportsBack: false, reportsBackReason } : {}),
|
|
1460
|
+
};
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
const homeDelivery = () => import('./agent-home-delivery.mjs');
|
|
1464
|
+
|
|
1465
|
+
// The durable watch of each reporting turn until its end is queued. A bot's
|
|
1466
|
+
// turn that reports nothing (reports off, or a watch that could not be
|
|
1467
|
+
// stored) keeps a record of its work instead (`own`, `owned`, `disown`),
|
|
1468
|
+
// which no report and no hand-off follows: a restart re-attaches both.
|
|
1469
|
+
const HOME_DELIVERY_WATCHES = {
|
|
1470
|
+
add: async (watch) => (await homeDelivery()).watchAgentTask(watch),
|
|
1471
|
+
list: async () => (await homeDelivery()).agentTaskWatches(),
|
|
1472
|
+
remove: async (runId) => (await homeDelivery()).unwatchAgentTask(runId),
|
|
1473
|
+
follow: async (runId, submissionId) => (await homeDelivery()).followAgentTask(runId, submissionId),
|
|
1474
|
+
own: async (work) => (await homeDelivery()).ownAgentTask(work),
|
|
1475
|
+
owned: async () => (await homeDelivery()).agentOwnedTasks(),
|
|
1476
|
+
disown: async (runId) => (await homeDelivery()).disownAgentTask(runId),
|
|
1477
|
+
};
|
|
1478
|
+
|
|
1074
1479
|
export function createAgentTaskSessions({
|
|
1075
1480
|
getSessionService,
|
|
1076
|
-
deliver = async (agentId, report) => (await
|
|
1077
|
-
|
|
1078
|
-
watches = {
|
|
1079
|
-
add: async (watch) => (await import('./agent-home-delivery.mjs')).watchAgentTask(watch),
|
|
1080
|
-
list: async () => (await import('./agent-home-delivery.mjs')).agentTaskWatches(),
|
|
1081
|
-
remove: async (runId) => (await import('./agent-home-delivery.mjs')).unwatchAgentTask(runId),
|
|
1082
|
-
follow: async (runId, submissionId) =>
|
|
1083
|
-
(await import('./agent-home-delivery.mjs')).followAgentTask(runId, submissionId),
|
|
1084
|
-
},
|
|
1481
|
+
deliver = async (agentId, report) => (await homeDelivery()).deliverAgentTask(agentId, report),
|
|
1482
|
+
watches = HOME_DELIVERY_WATCHES,
|
|
1085
1483
|
// Submissions still queued (durably) for a session after a restart.
|
|
1086
1484
|
queuedSubmissionIds = async (sessionId) =>
|
|
1087
1485
|
(await (await import('../tui/session/tui-steering-persist.mjs')).readTuiSteeringPersist(sessionId))
|
|
@@ -1148,150 +1546,24 @@ export function createAgentTaskSessions({
|
|
|
1148
1546
|
const followToFinal = (follow) =>
|
|
1149
1547
|
followTaskToFinal({ loadSession, owedResults, deliverCompletion, pendingWork, settleMs, pollMs, log }, follow);
|
|
1150
1548
|
|
|
1151
|
-
const
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
beforeReport = null,
|
|
1164
|
-
submit = null
|
|
1165
|
-
) {
|
|
1166
|
-
const sessions = service();
|
|
1167
|
-
const target = origin.target === 'session' ? { target: 'session' } : {};
|
|
1168
|
-
const { notify, noReport } = await watchTurn({ watches, owner: processToken, log }, sessionId, origin, id);
|
|
1169
|
-
const dropWatch = () =>
|
|
1170
|
-
watches.remove(id).catch((error) => log(`dropping the watch of ${sessionId} failed: ${error?.message || error}`));
|
|
1171
|
-
let runtime = null;
|
|
1172
|
-
// The sends this turn's end closes: this one, plus any that its turn
|
|
1173
|
-
// answered too (createSendSettlement).
|
|
1174
|
-
let sendIds = [id];
|
|
1175
|
-
// A report that cannot be queued is retried in this process; when every try
|
|
1176
|
-
// fails the durable watch stays and restart recovery delivers it (the queue
|
|
1177
|
-
// dedupes by runId, so a retry never posts twice).
|
|
1178
|
-
// `answerId`: the turn whose answer a progress update or the end carries.
|
|
1179
|
-
// `deliverReport` rejects once every try failed (a progress update is
|
|
1180
|
-
// tried again at the follow's next check); `report` logs it instead.
|
|
1181
|
-
const deliverReport = (status, text = '', { approvalId = '', answerId = '' } = {}) =>
|
|
1182
|
-
Promise.resolve(beforeReport).then(async () =>
|
|
1183
|
-
deliverWithRetries({ deliver, retryDelaysMs, log }, origin.agentId, sessionId, {
|
|
1184
|
-
runId: turnReportRunId(sessionId, id, status, { approvalId, answerId }),
|
|
1185
|
-
taskSessionId: sessionId,
|
|
1186
|
-
title: origin.title,
|
|
1187
|
-
status,
|
|
1188
|
-
text,
|
|
1189
|
-
...target,
|
|
1190
|
-
...(origin.hop > 0 ? { hop: origin.hop } : {}),
|
|
1191
|
-
...roomFrom(origin.sessionId),
|
|
1192
|
-
// A progress update moves this send's durable mark to its turn
|
|
1193
|
-
// (agent-home-delivery.mjs enqueueTask), in the same write.
|
|
1194
|
-
...(status === 'working' ? { progressWatchId: id, answerId } : {}),
|
|
1195
|
-
// A turn's end brings back the files it produced, when the agent
|
|
1196
|
-
// may receive them (reportOrigin `textOnly`).
|
|
1197
|
-
...(status === 'blocked' || status === 'working'
|
|
1198
|
-
? {}
|
|
1199
|
-
: {
|
|
1200
|
-
watchId: id,
|
|
1201
|
-
...(sendIds.length > 1 ? { watchIds: sendIds } : {}),
|
|
1202
|
-
...progressOf(id, answerId),
|
|
1203
|
-
...(origin.textOnly ? {} : await artifactFields(sessionId, id, runtime)),
|
|
1204
|
-
}),
|
|
1205
|
-
})
|
|
1206
|
-
);
|
|
1207
|
-
const report = (status, text = '', options = {}) =>
|
|
1208
|
-
deliverReport(status, text, options).catch((error) =>
|
|
1209
|
-
log(`report of ${sessionId} failed: ${error?.message || error}`)
|
|
1210
|
-
);
|
|
1211
|
-
let unwatch = () => {};
|
|
1212
|
-
// Set once the turn ended completed: the report waits for the final answer.
|
|
1213
|
-
let follow = null;
|
|
1214
|
-
let result;
|
|
1215
|
-
/** This send ends the turn `detail` for the sends `answered` (createSendSettlement). */
|
|
1216
|
-
const settleTurn = (detail, answered) => {
|
|
1217
|
-
sendIds = answered;
|
|
1218
|
-
const status = turnStatus(detail);
|
|
1219
|
-
const text = detail?.result?.content || detail?.error || '';
|
|
1220
|
-
// A failed or cancelled turn reports at once; a completed one
|
|
1221
|
-
// reports the task's final answer (followToFinal).
|
|
1222
|
-
if (status !== 'completed') {
|
|
1223
|
-
unwatch();
|
|
1224
|
-
void report(status, text);
|
|
1225
|
-
return;
|
|
1226
|
-
}
|
|
1227
|
-
follow = followToFinal({
|
|
1228
|
-
sessionId,
|
|
1229
|
-
runId: id,
|
|
1230
|
-
runtime,
|
|
1231
|
-
immediate: { status, text },
|
|
1232
|
-
finish: async (endStatus, endText, answerId) => {
|
|
1233
|
-
unwatch();
|
|
1234
|
-
await report(endStatus, endText, { answerId });
|
|
1235
|
-
},
|
|
1236
|
-
// Each other answer of its chain: a progress update that wakes nobody.
|
|
1237
|
-
interim: (answer) => deliverReport('working', answer.text, { answerId: answer.id }),
|
|
1238
|
-
});
|
|
1239
|
-
follow.check();
|
|
1240
|
-
};
|
|
1241
|
-
try {
|
|
1242
|
-
if (notify) {
|
|
1243
|
-
runtime = await sessions.materializeSession(sessionId);
|
|
1244
|
-
const onState = approvalWaitReporter(id, report);
|
|
1245
|
-
unwatch =
|
|
1246
|
-
runtime?.subscribe?.(() => {
|
|
1247
|
-
follow?.check();
|
|
1248
|
-
onState(runtime.getState?.() || {});
|
|
1249
|
-
}) || unwatch;
|
|
1250
|
-
}
|
|
1251
|
-
// A bot's send to a session that is not its own task session reaches the
|
|
1252
|
-
// model inside the sender envelope (`envelopeName`, set by reportOrigin).
|
|
1253
|
-
const sent = origin.envelopeName
|
|
1254
|
-
? wrapAgentMessage(prompt, { name: origin.envelopeName, agentId: origin.agentId })
|
|
1255
|
-
: prompt;
|
|
1256
|
-
const take = submit ?? ((options) => sessions.submitSession({ sessionId, prompt: sent, options }));
|
|
1257
|
-
const seq = settlement.nextSeq();
|
|
1258
|
-
result = await take({
|
|
1259
|
-
id,
|
|
1260
|
-
mode: 'prompt',
|
|
1261
|
-
transcriptMeta: sendTranscriptMeta(origin),
|
|
1262
|
-
...(notify
|
|
1263
|
-
? {
|
|
1264
|
-
// A room answers this send in a turn under another submission
|
|
1265
|
-
// id (one turn for several sends, or a fresh turn for one cut
|
|
1266
|
-
// short): the watch follows that turn, recorded before it runs.
|
|
1267
|
-
follow: (submissionId) => watches.follow?.(id, submissionId),
|
|
1268
|
-
onSettled: (detail) =>
|
|
1269
|
-
settlement.join(detail, origin, {
|
|
1270
|
-
seq,
|
|
1271
|
-
id,
|
|
1272
|
-
unwatch: () => unwatch(),
|
|
1273
|
-
settle: (answered) => settleTurn(detail, answered),
|
|
1274
|
-
}),
|
|
1275
|
-
}
|
|
1276
|
-
: {}),
|
|
1277
|
-
});
|
|
1278
|
-
} catch (error) {
|
|
1279
|
-
unwatch();
|
|
1280
|
-
if (notify) await dropWatch();
|
|
1281
|
-
throw error;
|
|
1282
|
-
}
|
|
1283
|
-
const accepted = result?.accepted === true;
|
|
1284
|
-
if (!accepted) {
|
|
1285
|
-
unwatch();
|
|
1286
|
-
if (notify) await dropWatch();
|
|
1287
|
-
}
|
|
1288
|
-
return sendResult(accepted, notify, id, noReport);
|
|
1289
|
-
}
|
|
1549
|
+
const turnDeps = {
|
|
1550
|
+
service,
|
|
1551
|
+
watches,
|
|
1552
|
+
deliver,
|
|
1553
|
+
retryDelaysMs,
|
|
1554
|
+
artifactFields,
|
|
1555
|
+
followToFinal,
|
|
1556
|
+
settlement: createSendSettlement(log),
|
|
1557
|
+
processToken,
|
|
1558
|
+
log,
|
|
1559
|
+
};
|
|
1560
|
+
const agentTurn = (...turnArgs) => runAgentTurn(turnDeps, ...turnArgs);
|
|
1290
1561
|
|
|
1291
|
-
const rearm = (watch) =>
|
|
1562
|
+
const rearm = (watch, options) =>
|
|
1292
1563
|
rearmTaskWatch(
|
|
1293
1564
|
{
|
|
1294
1565
|
deliver,
|
|
1566
|
+
disown: async (runId) => watches.disown?.(runId),
|
|
1295
1567
|
loadSession,
|
|
1296
1568
|
materializeSession: (sessionId) => service().materializeSession(sessionId),
|
|
1297
1569
|
queuedSubmissionIds,
|
|
@@ -1299,156 +1571,30 @@ export function createAgentTaskSessions({
|
|
|
1299
1571
|
followToFinal,
|
|
1300
1572
|
log,
|
|
1301
1573
|
},
|
|
1302
|
-
watch
|
|
1574
|
+
watch,
|
|
1575
|
+
options
|
|
1303
1576
|
);
|
|
1304
1577
|
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
pending.map((watch) =>
|
|
1318
|
-
rearm(watch).catch((error) => log(`re-attaching ${watch?.taskSessionId} failed: ${error?.message || error}`))
|
|
1319
|
-
)
|
|
1320
|
-
);
|
|
1321
|
-
return pending.length;
|
|
1322
|
-
}
|
|
1323
|
-
|
|
1324
|
-
/** Create the task session for `brief` and start it; returns at once.
|
|
1325
|
-
* `callerScope` is the caller's trusted worktree scope (worktree-access.mjs
|
|
1326
|
-
* worktreeCallerScope): provisioning a worktree is a mutation only an
|
|
1327
|
-
* attended conversation may make, so an explicit worktree from any other
|
|
1328
|
-
* caller is refused and the New task default keeps it in the Project folder. */
|
|
1329
|
-
async function create(
|
|
1330
|
-
args = {},
|
|
1331
|
-
{
|
|
1332
|
-
callerSessionId,
|
|
1333
|
-
callerAgentId,
|
|
1334
|
-
callerCwd,
|
|
1335
|
-
callerHop = 0,
|
|
1336
|
-
callerBotChain = [],
|
|
1337
|
-
callerScope,
|
|
1338
|
-
attachmentParts = [],
|
|
1339
|
-
} = {}
|
|
1340
|
-
) {
|
|
1341
|
-
const { brief, location } = createRequest(args, callerAgentId, callerScope);
|
|
1342
|
-
const where = createWhere(args, await listProjects(), callerCwd, location);
|
|
1343
|
-
const requestId = `atask_${randomUUID()}`;
|
|
1344
|
-
const title = (clean(args.title) || clean(brief.split('\n')[0])).slice(0, TITLE_LIMIT);
|
|
1345
|
-
const taskOrigin = {
|
|
1346
|
-
agentId: callerAgentId,
|
|
1347
|
-
sessionId: callerSessionId,
|
|
1348
|
-
requestId,
|
|
1349
|
-
title,
|
|
1350
|
-
notify: args.notify !== false,
|
|
1351
|
-
};
|
|
1352
|
-
// A task session runs in coding mode under Lead: an explicit model wins,
|
|
1353
|
-
// else the Lead route, else the last-used model. Never a model-less
|
|
1354
|
-
// session — the composer would show no model and its first turn would fail.
|
|
1355
|
-
// The catalog is read only when a display name or an effort needs it.
|
|
1356
|
-
let catalog = null;
|
|
1357
|
-
const catalogRows = async () => (catalog ??= await modelCatalog(callerSessionId));
|
|
1358
|
-
let route = clean(args.model)
|
|
1359
|
-
? await modelRoute(clean(args.model), async (text) =>
|
|
1360
|
-
routeByDisplayName(text, await catalogRows(), args.effort !== undefined)
|
|
1361
|
-
)
|
|
1362
|
-
: (await leadRoute()) || (await lastUsedRoute(service()));
|
|
1363
|
-
if (!route) throw new Error('session: no model to start the task session on. Choose a Lead model first.');
|
|
1364
|
-
// An explicit effort is the setting the menu's effort pick makes (session.effort,
|
|
1365
|
-
// Auto effort off); it wins over one a model ref or name carried.
|
|
1366
|
-
if (args.effort !== undefined) route = withEffort(route, args.effort, await catalogRows());
|
|
1367
|
-
const sessions = service();
|
|
1368
|
-
// Where it starts: the `worktree` option, else the user's New task default
|
|
1369
|
-
// for a caller that may provision one. Decided before the session exists,
|
|
1370
|
-
// so a failure here leaves nothing behind.
|
|
1371
|
-
const explicit = location.mode === 'worktree';
|
|
1372
|
-
const inWorktree =
|
|
1373
|
-
explicit ||
|
|
1374
|
-
(location.mode === 'default' &&
|
|
1375
|
-
where.project &&
|
|
1376
|
-
callerScope?.attended === true &&
|
|
1377
|
-
(await newTaskDefault()) === 'worktree');
|
|
1378
|
-
const created = await sessions.createSession({
|
|
1379
|
-
...route,
|
|
1380
|
-
cwd: where.cwd,
|
|
1381
|
-
desktopSession: where.desktopSession,
|
|
1382
|
-
sessionProfile: { taskOrigin },
|
|
1383
|
-
});
|
|
1384
|
-
const sessionId = String(created?.sessionId || '');
|
|
1385
|
-
if (!sessionId) throw new Error('session: task session creation returned no session id');
|
|
1386
|
-
if (inWorktree) {
|
|
1387
|
-
try {
|
|
1388
|
-
await requestTaskWorktree(sessions, sessionId, {
|
|
1389
|
-
title,
|
|
1390
|
-
requestId,
|
|
1391
|
-
name: location.name,
|
|
1392
|
-
confirmLarge: args.confirm_large === true,
|
|
1393
|
-
explicit,
|
|
1394
|
-
});
|
|
1395
|
-
} catch (error) {
|
|
1396
|
-
// Nothing was sent: drop the empty session so a retry starts clean.
|
|
1397
|
-
let dropFailure = null;
|
|
1398
|
-
try {
|
|
1399
|
-
const dropped = await sessions.configureSession(
|
|
1400
|
-
{ sessionId, action: 'deleteSession', args: [sessionId] },
|
|
1401
|
-
{ revision: 1 }
|
|
1402
|
-
);
|
|
1403
|
-
// A resolved `false` is a refusal, not a deletion.
|
|
1404
|
-
if (dropped?.value === false) dropFailure = new Error('the session service refused the deletion');
|
|
1405
|
-
} catch (deleteError) {
|
|
1406
|
-
dropFailure = deleteError;
|
|
1407
|
-
}
|
|
1408
|
-
if (dropFailure) log(`dropping ${sessionId} failed: ${dropFailure?.message || dropFailure}`);
|
|
1409
|
-
if (!dropFailure) throw error;
|
|
1410
|
-
throw orphanSessionError(error, sessionId, dropFailure);
|
|
1411
|
-
}
|
|
1412
|
-
}
|
|
1413
|
-
const { ready, started } = startedGate();
|
|
1414
|
-
// The brief carries the files the agent forwarded (workspace-tools.mjs).
|
|
1415
|
-
const prompt = handoffContent(brief, attachmentParts);
|
|
1416
|
-
const botChain = botChainOf(callerBotChain);
|
|
1417
|
-
const { accepted, reportsBack, reportsBackReason } = await agentTurn(
|
|
1418
|
-
sessionId,
|
|
1419
|
-
prompt,
|
|
1420
|
-
{ ...taskOrigin, ...(callerHop > 0 ? { hop: callerHop } : {}), ...(botChain.length ? { botChain } : {}) },
|
|
1421
|
-
requestId,
|
|
1422
|
-
ready
|
|
1423
|
-
);
|
|
1424
|
-
if (!accepted) throw new Error(`session: task session ${sessionId} did not accept the brief`);
|
|
1425
|
-
if (reportsBack) {
|
|
1426
|
-
await deliver(callerAgentId, {
|
|
1427
|
-
runId: `${requestId}_started`,
|
|
1428
|
-
taskSessionId: sessionId,
|
|
1429
|
-
title,
|
|
1430
|
-
status: 'started',
|
|
1431
|
-
...roomFrom(callerSessionId),
|
|
1432
|
-
}).catch((error) => log(`start line of ${sessionId} failed: ${error?.message || error}`));
|
|
1433
|
-
}
|
|
1434
|
-
started();
|
|
1435
|
-
// Started, not done: the final answer is reported later.
|
|
1436
|
-
return {
|
|
1437
|
-
session_id: sessionId,
|
|
1438
|
-
status: 'started',
|
|
1439
|
-
title,
|
|
1440
|
-
project: where.project?.path ?? null,
|
|
1441
|
-
...(taskOrigin.notify && !reportsBack ? { reportsBack: false, reportsBackReason } : {}),
|
|
1442
|
-
};
|
|
1443
|
-
}
|
|
1578
|
+
const createDeps = {
|
|
1579
|
+
service,
|
|
1580
|
+
listProjects,
|
|
1581
|
+
newTaskDefault,
|
|
1582
|
+
modelRoute,
|
|
1583
|
+
modelCatalog,
|
|
1584
|
+
leadRoute,
|
|
1585
|
+
lastUsedRoute,
|
|
1586
|
+
deliver,
|
|
1587
|
+
agentTurn,
|
|
1588
|
+
log,
|
|
1589
|
+
};
|
|
1444
1590
|
|
|
1445
1591
|
const reportOrigin = (sessionId, agentId, callerSessionId) =>
|
|
1446
1592
|
sendReportOrigin({ loadSession, agentName }, sessionId, agentId, callerSessionId);
|
|
1447
1593
|
|
|
1448
1594
|
return {
|
|
1449
|
-
create,
|
|
1595
|
+
create: (args, caller) => createTaskSession(createDeps, args, caller),
|
|
1450
1596
|
reportOrigin,
|
|
1451
|
-
recover,
|
|
1597
|
+
recover: () => recoverTaskWatches({ watches, settleAgentResults, rearm, processToken, log }),
|
|
1452
1598
|
send: (sessionId, prompt, origin, submit = null) => agentTurn(sessionId, prompt, origin, undefined, null, submit),
|
|
1453
1599
|
};
|
|
1454
1600
|
}
|