mixdog 1.4.2 → 1.4.3
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 +2 -2
- package/scripts/build-shipped-history.mjs +15 -5
- package/scripts/gate-local.mjs +65 -19
- package/scripts/graph-parity.mjs +8 -3
- package/scripts/lib/gate-scheduler.mjs +2 -1
- package/scripts/lib/run-node-tests.mjs +17 -5
- package/scripts/lib/test-failure-summary.mjs +1 -8
- package/scripts/lib/test-spawn-ledger.mjs +33 -2
- package/scripts/post-release-check.mjs +26 -16
- package/scripts/provider-pingpong-live.mjs +1 -1
- package/scripts/prune-embedding-runtime.mjs +3 -1
- package/scripts/release-paths.mjs +7 -1
- package/src/defaults/shipped-history.json +20 -0
- package/src/defaults/skills/setup/SKILL.md +2 -2
- package/src/defaults/skills/setup/references/actions.md +16 -3
- package/src/defaults/skills/setup/references/surfaces.md +3 -0
- package/src/defaults/skills/setup-guide/SKILL.md +6 -1
- package/src/lib/instruction-text.cjs +36 -0
- package/src/lib/rules-builder.cjs +34 -20
- package/src/orchestration/balanced.md +23 -0
- package/src/orchestration/focused.md +22 -0
- package/src/orchestration/none.md +5 -0
- package/src/orchestration/swarm.md +24 -0
- package/src/rules/agent-mode/AGENT_MODE.md +3 -1
- package/src/rules/agent-mode/MIXY.md +2 -2
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/session-prep.mjs +3 -3
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +0 -1
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +4 -2
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +0 -9
- package/src/runtime/agent/orchestrator/agent-runtime/heartbeat-completion.mjs +2 -2
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +67 -0
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +1 -0
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +4 -4
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +3 -1
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +199 -46
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +3 -5
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +9 -3
- package/src/runtime/agent/orchestrator/mcp/client.mjs +3 -5
- package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +1 -1
- package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +8 -2
- package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +1 -1
- package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +14 -0
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-stop.mjs +3 -3
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +4 -6
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2784 -2872
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +5 -8
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +288 -300
- package/src/runtime/agent/orchestrator/providers/vertex-ai.mjs +10 -1
- package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +10 -30
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +30 -0
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +0 -11
- package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +8 -0
- package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +17 -3
- package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +47 -27
- package/src/runtime/agent/orchestrator/runtime-core/goal-deadlines.mjs +141 -10
- package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +26 -63
- package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +28 -3
- package/src/runtime/agent/orchestrator/runtime-core/goal-runtime.mjs +36 -11
- package/src/runtime/agent/orchestrator/runtime-core/goal-state.mjs +88 -56
- package/src/runtime/agent/orchestrator/runtime-core/goal-storage.mjs +4 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +51 -32
- package/src/runtime/agent/orchestrator/runtime-core/goal-text.mjs +45 -145
- package/src/runtime/agent/orchestrator/runtime-core/goal-tool-defs.mjs +15 -98
- package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +32 -99
- package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +23 -78
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +69 -48
- package/src/runtime/agent/orchestrator/runtime-core/todo-list.mjs +367 -0
- package/src/runtime/agent/orchestrator/runtime-core/todo-tool-defs.mjs +47 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-availability.mjs +155 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +9 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +119 -35
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +28 -22
- package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +30 -0
- package/src/runtime/agent/orchestrator/session/attachment-preflight.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/compact/summary-route.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -12
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +7 -3
- package/src/runtime/agent/orchestrator/session/human-gate/held-message.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +1 -2
- package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/image-strip-recovery.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +11 -1
- package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +8 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/todo-check.mjs +196 -0
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +116 -50
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +8 -1
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +5 -6
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +6 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +16 -2
- package/src/runtime/agent/orchestrator/session/loop/turn-report.mjs +35 -0
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +57 -26
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +9 -7
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +21 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +27 -11
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-open.mjs +37 -34
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +25 -15
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +79 -24
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +12 -1
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +6 -1
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +9 -1
- package/src/runtime/agent/orchestrator/session/manager/pending-spool-path.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/manager/pending-spool-shard.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/prompt-settings.mjs +598 -0
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +19 -0
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +19 -10
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +31 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lock.mjs +31 -0
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +42 -6
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +11 -1
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +8 -9
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +339 -88
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +135 -11
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +377 -104
- package/src/runtime/agent/orchestrator/session/manager/turn-durability.mjs +144 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/mixy-name.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +8 -1
- package/src/runtime/agent/orchestrator/session/save-session-worker.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/store/canonical-reader.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +23 -2
- package/src/runtime/agent/orchestrator/session/store/sweep/sub-agent-retention.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/store/transcript-durability.mjs +88 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/store-summary-log.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +14 -5
- package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/store.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +9 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/agent-envelope.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +2 -2
- package/src/runtime/agent/orchestrator/stall-policy.mjs +3 -5
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +4 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +21 -3
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/worktree-add-guard.mjs +77 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +0 -1
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +7 -3
- package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +27 -9
- package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-fast-paths.mjs +0 -1
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +0 -10
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +1 -2
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +1 -24
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary/child-kill.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +1 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/modes/calls.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/modes/symbols.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +4 -5
- package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +3 -4
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4 -22
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +0 -4
- package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +0 -1
- package/src/runtime/attachments/attachment-reference.mjs +1 -1
- package/src/runtime/attachments/pdf-extract.mjs +1 -1
- package/src/runtime/attachments/store.d.mts +1 -0
- package/src/runtime/attachments/store.mjs +2 -2
- package/src/runtime/channels/lib/config-reload-watch.mjs +42 -0
- package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +29 -9
- package/src/runtime/channels/lib/scheduler.mjs +33 -0
- package/src/runtime/channels/lib/schedules-db.mjs +11 -4
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +4 -1
- package/src/runtime/channels/lib/webhooks-db.mjs +9 -3
- package/src/runtime/channels/lib/whisper-server.mjs +12 -12
- package/src/runtime/channels/lib/worker-main.mjs +9 -31
- package/src/runtime/computer-bridge/linux-readiness.mjs +10 -14
- package/src/runtime/connectors/connector-accounts-mcp.mjs +169 -33
- package/src/runtime/connectors/gmail-app-password.mjs +2 -2
- package/src/runtime/connectors/google-mcp.mjs +1 -1
- package/src/runtime/effort-judge/judge-client.mjs +2 -2
- package/src/runtime/effort-judge/judge-input.mjs +4 -4
- package/src/runtime/explore/explorer.mjs +0 -5
- package/src/runtime/explore/tool.mjs +3 -3
- package/src/runtime/local-provider/hardware.mjs +1 -1
- package/src/runtime/media/adapters/codex-image.mjs +3 -3
- package/src/runtime/media/adapters/gemini-video.mjs +1 -1
- package/src/runtime/media/media-usage.mjs +1 -1
- package/src/runtime/media/store.mjs +1 -1
- package/src/runtime/memory/index.mjs +11 -1
- package/src/runtime/memory/lib/embedding-reindex.mjs +27 -0
- package/src/runtime/memory/lib/memory-embed.mjs +83 -14
- package/src/runtime/memory/lib/memory-process-lock.mjs +159 -36
- package/src/runtime/memory/lib/memory-text-utils.mjs +6 -1
- package/src/runtime/memory/lib/memory.mjs +17 -0
- package/src/runtime/memory/lib/pg/process.mjs +1 -1
- package/src/runtime/memory/lib/pg/supervisor.mjs +16 -96
- package/src/runtime/memory/lib/recall-hybrid/hybrid-sql.mjs +12 -3
- package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
- package/src/runtime/office/authoring/pptx-author-action.mjs +1 -1
- package/src/runtime/office/authoring/xlsx-html-build.mjs +1 -1
- package/src/runtime/office/authoring/xlsx-html-runner.mjs +1 -1
- package/src/runtime/office/capabilities.mjs +1 -1
- package/src/runtime/office/core/office-core.mjs +1 -1
- package/src/runtime/office/design/content-model.mjs +3 -3
- package/src/runtime/office/design/docx/design-docx/section.mjs +6 -6
- package/src/runtime/office/design/xlsx/design-xlsx-components.mjs +1 -1
- package/src/runtime/office/design/xlsx/design-xlsx.mjs +1 -1
- package/src/runtime/office/pdf/ocr-engine.mjs +1 -1
- package/src/runtime/office/pdf/pdf-writer.mjs +4 -4
- package/src/runtime/office/portable/portable-docx-operations.mjs +2 -2
- package/src/runtime/office/portable/portable-soffice.mjs +8 -6
- package/src/runtime/office/portable/xlsx-contract.mjs +1 -1
- package/src/runtime/shared/atomic-file.d.mts +8 -0
- package/src/runtime/shared/background-tasks.mjs +22 -4
- package/src/runtime/shared/background-wait.mjs +66 -0
- package/src/runtime/shared/child-guardian.mjs +17 -7
- package/src/runtime/shared/config.mjs +313 -16
- package/src/runtime/shared/connector-catalog.d.mts +4 -5
- package/src/runtime/shared/connector-catalog.mjs +11 -1
- package/src/runtime/shared/file-lock.mjs +8 -3
- package/src/runtime/shared/git-runner.mjs +7 -2
- package/src/runtime/shared/idle-gc.mjs +30 -7
- package/src/runtime/shared/llm/http-agent.mjs +8 -5
- package/src/runtime/shared/llm/system-proxy.mjs +2 -1
- package/src/runtime/shared/llm/usage-ledger-quota.mjs +31 -12
- package/src/runtime/shared/llm/usage-ledger-rollup.mjs +84 -8
- package/src/runtime/shared/llm/usage-ledger.mjs +3 -0
- package/src/runtime/shared/llm/usage-rollup.mjs +48 -0
- package/src/runtime/shared/maintenance-schedule.mjs +109 -0
- package/src/runtime/shared/process-runner.mjs +8 -4
- package/src/runtime/shared/routine-trigger.d.mts +13 -0
- package/src/runtime/shared/routine-trigger.mjs +34 -0
- package/src/runtime/shared/run-child.d.mts +2 -1
- package/src/runtime/shared/run-child.mjs +70 -18
- package/src/runtime/shared/session-scratch.mjs +14 -2
- package/src/runtime/shared/shipped-definitions.mjs +7 -1
- package/src/runtime/shared/tool-card-model.golden.json +3 -12
- package/src/runtime/shared/tool-execution-contract.mjs +2 -0
- package/src/runtime/shared/tool-work-units.mjs +31 -6
- package/src/runtime/shared/turn-snapshot.mjs +26 -4
- package/src/runtime/shared/turn-worktree-snapshot.mjs +6 -11
- package/src/runtime/shared/worker-requests.mjs +17 -3
- package/src/runtime/shared/worktrees/branch-management.mjs +1 -5
- package/src/runtime/shared/worktrees/contract.mjs +16 -6
- package/src/runtime/shared/worktrees/dependencies.mjs +127 -89
- package/src/runtime/shared/worktrees/disk.mjs +79 -2
- package/src/runtime/shared/worktrees/git.mjs +44 -11
- package/src/runtime/shared/worktrees/include.mjs +6 -4
- package/src/runtime/shared/worktrees/maintenance.mjs +422 -30
- package/src/runtime/shared/worktrees/manager.mjs +772 -75
- package/src/runtime/shared/worktrees/settings.mjs +33 -7
- package/src/runtime/shared/worktrees/test-support.mjs +5 -1
- package/src/runtime/shared/worktrees/worker-snapshots.mjs +82 -0
- package/src/runtime/tidy/process.mjs +2 -1
- package/src/runtime/web-search/index.mjs +3 -22
- package/src/runtime/web-search/lib/web-tools.mjs +2 -2
- package/src/runtime/web-search/tool-defs.mjs +17 -26
- package/src/session-runtime/agent-profile-changes.mjs +55 -4
- package/src/session-runtime/boot/apis.mjs +27 -4
- package/src/session-runtime/boot/begin.mjs +2 -0
- package/src/session-runtime/boot/config.mjs +10 -1
- package/src/session-runtime/boot/facade.mjs +1 -0
- package/src/session-runtime/boot/providers.mjs +70 -3
- package/src/session-runtime/boot/session.mjs +2 -0
- package/src/session-runtime/boot/tools.mjs +69 -25
- package/src/session-runtime/channel-config-api.mjs +1 -0
- package/src/session-runtime/config-change-effects.mjs +179 -0
- package/src/session-runtime/config-lifecycle/config-writers.mjs +1 -0
- package/src/session-runtime/config-lifecycle.mjs +160 -24
- package/src/session-runtime/conversation-import/discovery.mjs +86 -7
- package/src/session-runtime/conversation-import/service.mjs +3 -2
- package/src/session-runtime/goal-facade-api.mjs +49 -3
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +3 -0
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -2
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +3 -11
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +18 -4
- package/src/session-runtime/internal-tool-executor.mjs +12 -19
- package/src/session-runtime/lifecycle/cold-heir.mjs +7 -0
- package/src/session-runtime/lifecycle/memory-ingest.mjs +3 -3
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +53 -5
- package/src/session-runtime/lifecycle/session-switch.mjs +13 -2
- package/src/session-runtime/lifecycle/teardown/session-close.mjs +4 -4
- package/src/session-runtime/lifecycle-api.mjs +1 -0
- package/src/session-runtime/mcp-glue/server-catalog.mjs +14 -3
- package/src/session-runtime/mcp-glue/server-connection.mjs +34 -8
- package/src/session-runtime/model-route/set-route.mjs +40 -7
- package/src/session-runtime/native-web-search/routes.mjs +3 -3
- package/src/session-runtime/provider-auth/refresh.mjs +6 -3
- package/src/session-runtime/provider-auth/setup.mjs +1 -1
- package/src/session-runtime/provider-readiness.mjs +53 -4
- package/src/session-runtime/resource-api.mjs +1 -1
- package/src/session-runtime/resource-extension-sync.mjs +4 -8
- package/src/session-runtime/resource-mcp-connector-accounts.mjs +5 -1
- package/src/session-runtime/resource-mcp-secrets.mjs +3 -3
- package/src/session-runtime/resource-plugins-api.mjs +4 -0
- package/src/session-runtime/routine-executor.mjs +152 -0
- package/src/session-runtime/routine-home-turn.mjs +46 -5
- package/src/session-runtime/runtime-facade.mjs +5 -0
- package/src/session-runtime/runtime-feature-gates.mjs +2 -11
- package/src/session-runtime/schedule-session-run.mjs +1 -0
- package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +6 -1
- package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +7 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +110 -6
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +12 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +5 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +24 -6
- package/src/session-runtime/services/agent-tool.mjs +51 -1
- package/src/session-runtime/services/channel-admin.mjs +18 -0
- package/src/session-runtime/services/hook-bus/command-handler.mjs +7 -11
- package/src/session-runtime/services/plugin-admin.mjs +4 -0
- package/src/session-runtime/services/seeds.mjs +7 -0
- package/src/session-runtime/services/usage-stats-model.mjs +32 -11
- package/src/session-runtime/session-create/materialize.mjs +4 -2
- package/src/session-runtime/session-create/session-options.mjs +2 -0
- package/src/session-runtime/settings-builtin-tools-api.mjs +1 -9
- package/src/session-runtime/setup-tool/connector-widen-approval.mjs +1 -1
- package/src/session-runtime/setup-tool/executor.mjs +8 -1
- package/src/session-runtime/setup-tool/extended-actions.mjs +2 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +28 -0
- package/src/session-runtime/setup-tool/tool-defs.mjs +26 -1
- package/src/session-runtime/tool-policy/agent-profile-fold.mjs +40 -43
- package/src/session-runtime/tool-policy/mode-switch.mjs +1 -1
- package/src/session-runtime/tool-policy/policy-stage.mjs +106 -8
- package/src/session-runtime/tool-policy/workflow-overlay.mjs +2 -1
- package/src/session-runtime/tool-policy-refresh.mjs +182 -5
- package/src/session-runtime/tool-surface.mjs +38 -1
- package/src/session-runtime/turn/agent-ops.mjs +10 -2
- package/src/session-runtime/turn/session-ops.mjs +2 -0
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +5 -0
- package/src/session-runtime/turn/turn-run.mjs +1 -1
- package/src/session-runtime/webhook-session-run.mjs +2 -0
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +1 -4
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +3 -10
- package/src/session-runtime/workflow-agents-api/instruction-files.mjs +165 -0
- package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +5 -4
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +2 -3
- package/src/session-runtime/workflow-agents-api.mjs +2 -0
- package/src/session-runtime/workspace/project-branches.mjs +1 -1
- package/src/session-runtime/workspace/session-view.mjs +1 -1
- package/src/session-runtime/workspace/transitions.mjs +20 -4
- package/src/session-runtime/workspace/worktree-maintenance.mjs +126 -6
- package/src/session-runtime/workspace/worktree-setup.mjs +13 -1
- package/src/session-runtime/workspace/worktree-tool.mjs +16 -0
- package/src/standalone/daemon-agent-control.mjs +25 -8
- package/src/standalone/daemon-desktop-runtime.mjs +6 -2
- package/src/standalone/daemon-lag-profiler.mjs +7 -7
- package/src/standalone/daemon.mjs +54 -2
- package/src/standalone/local-session-runtime.mjs +16 -0
- package/src/standalone/session-client/daemon-unavailable.mjs +1 -1
- package/src/standalone/session-protocol.mjs +11 -0
- package/src/standalone/session-service/agent-route-follow.mjs +23 -20
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +18 -6
- package/src/standalone/session-service/quota-resume.mjs +9 -0
- package/src/standalone/session-service/session-calls/session-action.mjs +51 -1
- package/src/standalone/session-service/session-calls/session-turns.mjs +37 -18
- package/src/standalone/session-service/session-calls/turn-gate.mjs +34 -0
- package/src/standalone/session-service/session-calls.mjs +2 -1
- package/src/tui/App.jsx +8 -0
- package/src/tui/app/clipboard.mjs +1 -1
- package/src/tui/app/create-app-pickers.mjs +2 -0
- package/src/tui/app/doctor.mjs +2 -2
- package/src/tui/app/panel-signature.mjs +1 -1
- package/src/tui/app/settings-picker.mjs +53 -8
- package/src/tui/app/shell-layout/row-budgets.mjs +2 -2
- package/src/tui/app/slash-commands.mjs +1 -1
- package/src/tui/app/slash-dispatch/route-commands.mjs +1 -1
- package/src/tui/app/slash-dispatch/session-commands.mjs +1 -1
- package/src/tui/app/use-prompt-queue-history.mjs +2 -2
- package/src/tui/app/use-transcript-activity.mjs +1 -1
- package/src/tui/app/use-transcript-window/geometry.mjs +1 -1
- package/src/tui/components/prompt-input/escape-policy.d.mts +0 -1
- package/src/tui/components/prompt-input/escape-policy.mjs +1 -1
- package/src/tui/components/question-panel-model.mjs +4 -4
- package/src/tui/components/tool-execution/standard-card.jsx +3 -4
- package/src/tui/components/user-message-skills.mjs +1 -1
- package/src/tui/dist/index.mjs +309 -30
- package/src/tui/markdown/render-ansi.mjs +1 -1
- package/src/tui/session/agent-job-feed/notification-router.mjs +10 -0
- package/src/tui/session/agent-job-feed.mjs +2 -0
- package/src/tui/session/context-state.mjs +3 -0
- package/src/tui/session/quota-resume.mjs +1 -1
- package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
- package/src/tui/session/session-api/lifecycle/session-reset.mjs +7 -0
- package/src/tui/session/session-api/routes-agent-definitions.mjs +5 -0
- package/src/tui/session/session-api/worktree.mjs +13 -1
- package/src/tui/session/session-flow/drain.mjs +11 -14
- package/src/tui/session/tool-card-results/grouped-result.mjs +2 -2
- package/src/tui/session/turn-quiet.mjs +1 -1
- package/src/tui/session/turn.mjs +3 -0
- package/src/tui/session/worktree-setup-notice.mjs +1 -1
- package/src/tui/spinner-meta.mjs +3 -3
- package/src/tui/spinner-verbs.mjs +2 -2
- package/src/defaults/skills/goal-management/SKILL.md +0 -169
- package/src/runtime/agent/orchestrator/runtime-core/goal-tasks.mjs +0 -156
- package/src/session-runtime/goal-tasks.mjs +0 -1
|
@@ -37,7 +37,17 @@ export function crossTurnSignature(name, args) {
|
|
|
37
37
|
// they must not reset the escalation ladder's "zero edit" condition. Skill /
|
|
38
38
|
// recall / agent / task / cwd / load_tool are exploration/meta plumbing.
|
|
39
39
|
// (tool_search kept as legacy alias for old transcripts.)
|
|
40
|
-
const NON_PROGRESS_TOOLS = new Set([
|
|
40
|
+
const NON_PROGRESS_TOOLS = new Set([
|
|
41
|
+
'Skill',
|
|
42
|
+
'recall',
|
|
43
|
+
'agent',
|
|
44
|
+
'task',
|
|
45
|
+
'cwd',
|
|
46
|
+
'session',
|
|
47
|
+
'load_tool',
|
|
48
|
+
'tool_search',
|
|
49
|
+
'todo',
|
|
50
|
+
]);
|
|
41
51
|
|
|
42
52
|
// True when a successfully-executed tool represents real edit/progress. A tool
|
|
43
53
|
// counts as progress only if its def lacks readOnlyHint (not eager) AND it is
|
|
@@ -55,7 +55,7 @@ const tokens = (value) => `${Number(value || 0).toLocaleString('en-US')} tokens`
|
|
|
55
55
|
// for any history, so compacting the history cannot help and is not tried.
|
|
56
56
|
// The wording avoids provider context-overflow phrasing on purpose: this is
|
|
57
57
|
// not a "conversation too long" refusal and must not be routed as one.
|
|
58
|
-
|
|
58
|
+
class ToolSurfaceExceedsContextError extends Error {
|
|
59
59
|
constructor({ sessionId, provider, model, overhead }) {
|
|
60
60
|
const target = [provider, model].filter(Boolean).join('/') || 'this model';
|
|
61
61
|
const reserve = overhead.kind === 'configured_reserve';
|
|
@@ -129,6 +129,8 @@ export function createLoopState({ provider, messages, model, tools, cwd, sendOpt
|
|
|
129
129
|
opts,
|
|
130
130
|
sessionId,
|
|
131
131
|
onSkillPrompt: (content, message) => state.pendingSkillPrompts.push({ content, message }),
|
|
132
|
+
// Input taken into the turn at any boundary is new work to answer.
|
|
133
|
+
onInjected: () => state.noToolTurn.noteNewInput(),
|
|
132
134
|
});
|
|
133
135
|
// Bounded recovery for provider turns that returned no client tool calls
|
|
134
136
|
// (max-output ladder, refusal retry, provider continuation, empty-turn
|
|
@@ -143,6 +145,8 @@ export function createLoopState({ provider, messages, model, tools, cwd, sendOpt
|
|
|
143
145
|
escalateMaxTokens: () => state.provider?.escalatedMaxTokens?.(state.model, state.opts, state.lastSendTools) ?? null,
|
|
144
146
|
// Characters the latest send put on screen through the live text stream.
|
|
145
147
|
streamedChars: () => state.lastStreamedChars,
|
|
148
|
+
// A capped turn was told to reply; it may end without the todo check.
|
|
149
|
+
turnLimited: () => state.turnLimitNoticed === true,
|
|
146
150
|
});
|
|
147
151
|
return state;
|
|
148
152
|
}
|
|
@@ -155,6 +159,9 @@ export function finishLoop(state) {
|
|
|
155
159
|
// A reaction-only turn is a successful completion, never an empty finish.
|
|
156
160
|
const terminationReason = classifyTerminationReason(response, { sessionAgent: state.sessionAgent });
|
|
157
161
|
const reactionCompleted = terminationReason === 'empty' && state.noToolTurn.reactionCompleted;
|
|
162
|
+
// So is an empty end after a kept answer only todo bookkeeping followed:
|
|
163
|
+
// that answer is the turn's report (no-tool-turn.mjs).
|
|
164
|
+
const reportCompleted = terminationReason === 'empty' && state.noToolTurn.reportStands;
|
|
158
165
|
return {
|
|
159
166
|
...response,
|
|
160
167
|
usage: state.lastUsage || response.usage,
|
|
@@ -165,7 +172,7 @@ export function finishLoop(state) {
|
|
|
165
172
|
toolCallsTotal: state.toolCallsTotal,
|
|
166
173
|
providerState: state.providerState,
|
|
167
174
|
providerStateUpdated: state.providerStateUpdated,
|
|
168
|
-
terminationReason: reactionCompleted ? undefined : terminationReason,
|
|
175
|
+
terminationReason: reactionCompleted || reportCompleted ? undefined : terminationReason,
|
|
169
176
|
...(reactionCompleted ? { reactionCompleted: true } : {}),
|
|
170
177
|
providerContinuations: state.noToolTurn.providerContinuations,
|
|
171
178
|
...(state.routeUsageHops?.length
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
// End-of-turn completion check for the session's todo list.
|
|
2
|
+
//
|
|
3
|
+
// A turn that ends without a tool call while pending/in-progress items remain
|
|
4
|
+
// gets one hidden reminder naming them, and the loop sends again. Bounded:
|
|
5
|
+
// at most MAX_TODO_REMINDERS per user cycle (reset only by a genuine user
|
|
6
|
+
// prompt, never by an automatic continuation), and silent after a reminder
|
|
7
|
+
// that produced no progress (no tool batch since). Skipped while the turn is
|
|
8
|
+
// genuinely waiting: on the user (an approval denied or a question left
|
|
9
|
+
// unanswered this turn), on an agent, or on a background shell started this
|
|
10
|
+
// user cycle (background-wait.mjs).
|
|
11
|
+
// Cancelled, failed and usage-limited turns never reach this point.
|
|
12
|
+
//
|
|
13
|
+
// With an active Goal whose items are all closed, the same check asks once
|
|
14
|
+
// per cycle for the completion audit: complete the Goal or append the rest.
|
|
15
|
+
import { resolvePluginData } from '../../../../../shared/plugin-paths.mjs';
|
|
16
|
+
import { awaitingBackgroundWork, beginUserCycle } from '../../../../../shared/background-wait.mjs';
|
|
17
|
+
import { readStoredGoalSnapshot } from '../../../runtime-core/goal-storage.mjs';
|
|
18
|
+
import {
|
|
19
|
+
clearTodo,
|
|
20
|
+
openTodoItems,
|
|
21
|
+
todoAllClosed,
|
|
22
|
+
todoPhases,
|
|
23
|
+
unfinishedTodoItems,
|
|
24
|
+
} from '../../../runtime-core/todo-list.mjs';
|
|
25
|
+
import { TODO_TOOL } from '../../../runtime-core/todo-tool-defs.mjs';
|
|
26
|
+
import { HIDDEN_AGENT_NAMES } from '../hidden-agents.mjs';
|
|
27
|
+
import { _isMutationTool, _isShellTool } from '../tool-classify.mjs';
|
|
28
|
+
|
|
29
|
+
const MAX_TODO_REMINDERS = 3;
|
|
30
|
+
|
|
31
|
+
// Sessions whose current turn waits on the user's decision (in memory: the
|
|
32
|
+
// turn itself is in memory, and a new turn clears it).
|
|
33
|
+
const userWaits = new Set();
|
|
34
|
+
|
|
35
|
+
/** The current turn now waits on the user (approval denied, question dismissed). */
|
|
36
|
+
export function noteTodoUserWait(sessionId) {
|
|
37
|
+
if (sessionId) userWaits.add(String(sessionId));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function checkState(session) {
|
|
41
|
+
const current = session.todoCheck;
|
|
42
|
+
if (current && typeof current === 'object') return current;
|
|
43
|
+
session.todoCheck = { reminders: 0, awaitingProgress: false, auditAsked: false };
|
|
44
|
+
return session.todoCheck;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** A turn starts: `genuine` (a real user prompt) opens a new reminder cycle. */
|
|
48
|
+
export function beginTodoTurn(session, { genuine = false } = {}) {
|
|
49
|
+
if (!session || typeof session !== 'object') return;
|
|
50
|
+
if (session.id) userWaits.delete(String(session.id));
|
|
51
|
+
if (genuine) {
|
|
52
|
+
session.todoCheck = { reminders: 0, awaitingProgress: false, auditAsked: false };
|
|
53
|
+
beginUserCycle(session.id);
|
|
54
|
+
// A finished list stays on screen until the user moves on, then goes the
|
|
55
|
+
// way a finished Goal does. An active Goal keeps it for its audit.
|
|
56
|
+
if (todoAllClosed(session) && !activeGoal(session.id)) clearTodo(session);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* A delegated agent received a new brief or follow-up (a genuine prompt) with
|
|
62
|
+
* no open list: the hidden reminder trailing that prompt, once per prompt, or
|
|
63
|
+
* null. The tool description alone was read past on short multi-ask briefs.
|
|
64
|
+
*/
|
|
65
|
+
export function todoStartReminder(session) {
|
|
66
|
+
if (!session || typeof session !== 'object' || session.owner !== 'agent') return null;
|
|
67
|
+
if (HIDDEN_AGENT_NAMES.has(session.agent)) return null;
|
|
68
|
+
if (!session.tools?.some((tool) => tool?.name === TODO_TOOL.name)) return null;
|
|
69
|
+
if (openTodoItems(session).length) return null;
|
|
70
|
+
// `init` refuses while any item is unfinished (blocked included), so such a
|
|
71
|
+
// list is reconciled or appended to, never re-initialized.
|
|
72
|
+
if (unfinishedTodoItems(session).length) {
|
|
73
|
+
return [
|
|
74
|
+
'<system-reminder>',
|
|
75
|
+
'The todo list still has blocked items. If this brief adds asks, append them; first done, drop or unblock each blocked item that this brief settles. Do not init over them. Do not mention this reminder.',
|
|
76
|
+
'</system-reminder>',
|
|
77
|
+
].join('\n');
|
|
78
|
+
}
|
|
79
|
+
return [
|
|
80
|
+
'<system-reminder>',
|
|
81
|
+
'If this brief has three or more steps or several asks, init the todo list with every ask as its own item in the same response as your first tool call; each item the brief lists is its own todo item, never folded into one. A single step or a plain answer needs none. Do not mention this reminder.',
|
|
82
|
+
'</system-reminder>',
|
|
83
|
+
].join('\n');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** A tool batch ran: the last reminder produced progress. */
|
|
87
|
+
export function noteTodoProgress(session) {
|
|
88
|
+
if (session?.todoCheck?.awaitingProgress) session.todoCheck.awaitingProgress = false;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Mid-turn nudge: a long turn can finish items without ever touching the list,
|
|
92
|
+
// leaving the progress shown to the user stale. After this many successful
|
|
93
|
+
// mutating tool calls with no todo call (and no earlier nudge), one hidden
|
|
94
|
+
// reminder is appended. Counted per call, not per batch, so a turn of parallel
|
|
95
|
+
// edits ages the list faster than a turn of reads; a batch of three edits is
|
|
96
|
+
// three. What mutates is the work the list tracks: file edits, command
|
|
97
|
+
// execution (shell, as a bash tool is) and mutating git/github requests.
|
|
98
|
+
const STALE_TODO_MUTATIONS = 10;
|
|
99
|
+
|
|
100
|
+
function mutatingCall(call, results) {
|
|
101
|
+
const name = call?.name ?? call?.function?.name;
|
|
102
|
+
const args = call?.arguments ?? call?.function?.arguments;
|
|
103
|
+
if (!_isMutationTool(name, args) && !_isShellTool(name)) return false;
|
|
104
|
+
const result = results.find((message) => message?.toolCallId === call.id);
|
|
105
|
+
// A call that failed or was skipped (a dependency guard after a failed edit) changed nothing.
|
|
106
|
+
return result?.toolKind !== 'error' && result?.toolKind !== 'skipped';
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* A tool batch ran with `calls` (and their result messages): the hidden
|
|
111
|
+
* stale-list reminder to append to the transcript, or null. Calls are read in
|
|
112
|
+
* order: a todo call restarts the count, a successful mutating call adds one.
|
|
113
|
+
* Outside the end-of-turn budget (`todoCheck.reminders`) and its progress gate.
|
|
114
|
+
*/
|
|
115
|
+
export function staleTodoReminder(session, calls = [], results = [], { sessionAgent = null } = {}) {
|
|
116
|
+
if (!session || typeof session !== 'object' || HIDDEN_AGENT_NAMES.has(sessionAgent)) return null;
|
|
117
|
+
const check = checkState(session);
|
|
118
|
+
for (const call of calls) {
|
|
119
|
+
if ((call?.name ?? call?.function?.name) === TODO_TOOL.name) check.staleMutations = 0;
|
|
120
|
+
else if (mutatingCall(call, results)) check.staleMutations = (check.staleMutations || 0) + 1;
|
|
121
|
+
}
|
|
122
|
+
const phases = todoPhases(session);
|
|
123
|
+
// A finished list needs nothing more; no list at all is nudged once per
|
|
124
|
+
// user cycle (long runs that never made one), an open list repeatedly.
|
|
125
|
+
if (phases.length && !openTodoItems(session).length) {
|
|
126
|
+
check.staleMutations = 0;
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
if (!phases.length && check.createNudged) return null;
|
|
130
|
+
if ((check.staleMutations || 0) < STALE_TODO_MUTATIONS) return null;
|
|
131
|
+
check.staleMutations = 0;
|
|
132
|
+
if (!phases.length) {
|
|
133
|
+
check.createNudged = true;
|
|
134
|
+
return [
|
|
135
|
+
'<system-reminder>',
|
|
136
|
+
'No todo list exists for this work yet. If it has three or more steps, init one now with the steps left and keep it current; if it is a single step, ignore this. Keep working; do not mention this reminder.',
|
|
137
|
+
'</system-reminder>',
|
|
138
|
+
].join('\n');
|
|
139
|
+
}
|
|
140
|
+
return [
|
|
141
|
+
'<system-reminder>',
|
|
142
|
+
'The todo tool has not been used for a while. Mark finished items done now (one call each, never batched at the end) so the in-progress pointer is on what you are doing. Keep working; do not mention this reminder.',
|
|
143
|
+
...phases.flatMap((phase) => phase.tasks.map((task) => `- [${task.status}] ${task.content}`)),
|
|
144
|
+
'</system-reminder>',
|
|
145
|
+
].join('\n');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function activeGoal(sessionId) {
|
|
149
|
+
try {
|
|
150
|
+
const goal = readStoredGoalSnapshot({ dataDir: resolvePluginData(), sessionId });
|
|
151
|
+
return goal?.status === 'active' ? goal : null;
|
|
152
|
+
} catch {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function openItemsReminder(open, count) {
|
|
158
|
+
return [
|
|
159
|
+
'<system-reminder>',
|
|
160
|
+
`You ended the turn with ${open.length} open todo item(s):`,
|
|
161
|
+
...open.map((task) => `- ${task.content}`),
|
|
162
|
+
'Continue them, or close each with the todo tool (done, drop, or block with its reason).',
|
|
163
|
+
`(Reminder ${count}/${MAX_TODO_REMINDERS})`,
|
|
164
|
+
'</system-reminder>',
|
|
165
|
+
].join('\n');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const GOAL_AUDIT_REMINDER = [
|
|
169
|
+
'<system-reminder>',
|
|
170
|
+
'Every todo item is closed but the Goal is still active. Audit each user condition of the Goal objective against current evidence: when all are proven met, call goal with action complete; otherwise append the remaining work to todo and continue.',
|
|
171
|
+
'</system-reminder>',
|
|
172
|
+
].join('\n');
|
|
173
|
+
|
|
174
|
+
/** The reminder to send before the turn may end, or null to let it end. */
|
|
175
|
+
export function todoCompletionReminder(session, { sessionId = null, sessionAgent = null, turnLimited = false } = {}) {
|
|
176
|
+
if (!session || typeof session !== 'object' || turnLimited) return null;
|
|
177
|
+
if (HIDDEN_AGENT_NAMES.has(sessionAgent)) return null;
|
|
178
|
+
const id = String(sessionId || session.id || '');
|
|
179
|
+
const phases = todoPhases(session);
|
|
180
|
+
if (!phases.length) return null;
|
|
181
|
+
const check = checkState(session);
|
|
182
|
+
if (check.awaitingProgress || userWaits.has(id)) return null;
|
|
183
|
+
const open = openTodoItems(session);
|
|
184
|
+
if (open.length) {
|
|
185
|
+
if (check.reminders >= MAX_TODO_REMINDERS) return null;
|
|
186
|
+
if (awaitingBackgroundWork({ sessionId: id })) return null;
|
|
187
|
+
check.reminders += 1;
|
|
188
|
+
check.awaitingProgress = true;
|
|
189
|
+
return openItemsReminder(open, check.reminders);
|
|
190
|
+
}
|
|
191
|
+
if (check.auditAsked || !id || !activeGoal(id)) return null;
|
|
192
|
+
if (awaitingBackgroundWork({ sessionId: id })) return null;
|
|
193
|
+
check.auditAsked = true;
|
|
194
|
+
check.awaitingProgress = true;
|
|
195
|
+
return GOAL_AUDIT_REMINDER;
|
|
196
|
+
}
|
|
@@ -18,9 +18,12 @@ import { resetOutputLimitRecovery, resolveOutputLimit } from './no-tool-turn/out
|
|
|
18
18
|
import { resolveRefusal } from './no-tool-turn/refusal.mjs';
|
|
19
19
|
import { resumeContinuation } from './no-tool-turn/continuation.mjs';
|
|
20
20
|
import { nudgeEmptyTurn } from './no-tool-turn/empty-nudge.mjs';
|
|
21
|
+
import { noteTodoProgress, staleTodoReminder, todoCompletionReminder } from './no-tool-turn/todo-check.mjs';
|
|
21
22
|
import { isReactionSuccess, reactionCallIds, takeReactionTarget } from '../../runtime-core/reaction-tool-defs.mjs';
|
|
22
23
|
import { messageIdOf } from '../message-ids.mjs';
|
|
23
24
|
import { isReactableMessage } from '../message-reactions.mjs';
|
|
25
|
+
import { joinReports, withEarlierReport } from './turn-report.mjs';
|
|
26
|
+
import { TODO_TOOL } from '../../runtime-core/todo-tool-defs.mjs';
|
|
24
27
|
|
|
25
28
|
// `escalateMaxTokens()` asks the live provider for a higher one-shot max_tokens
|
|
26
29
|
// (number) or reports none (null/undefined) — the loop stays provider-agnostic.
|
|
@@ -32,6 +35,7 @@ export function createNoToolTurnResolver({
|
|
|
32
35
|
drainSteering,
|
|
33
36
|
escalateMaxTokens = () => null,
|
|
34
37
|
streamedChars = () => 0,
|
|
38
|
+
turnLimited = () => false,
|
|
35
39
|
}) {
|
|
36
40
|
const segments = createTurnSegments({ messages, opts });
|
|
37
41
|
// Per-turn recovery counters shared by the ladders.
|
|
@@ -51,6 +55,14 @@ export function createNoToolTurnResolver({
|
|
|
51
55
|
// Continuations since the last executed tool batch — bounds the text-only
|
|
52
56
|
// continuation runaway (see PROVIDER_CONTINUATION_NO_TOOL_LIMIT).
|
|
53
57
|
continuationsSinceToolBatch: 0,
|
|
58
|
+
// Answers the turn went on past (keepEndedAnswer): those still in the
|
|
59
|
+
// segments (parts before endedPartsEnd), and those a tool batch cleared
|
|
60
|
+
// from them.
|
|
61
|
+
endedPartsEnd: 0,
|
|
62
|
+
carriedAnswers: [],
|
|
63
|
+
// The newest kept answer was followed by nothing but todo bookkeeping:
|
|
64
|
+
// it is the turn's answer, and an empty end after it is no failure.
|
|
65
|
+
reportStands: false,
|
|
54
66
|
};
|
|
55
67
|
// The stable id (message-ids.mjs, kept across compaction) of the newest
|
|
56
68
|
// real user input; runtime reminders and notices are not reactable.
|
|
@@ -112,60 +124,108 @@ export function createNoToolTurnResolver({
|
|
|
112
124
|
};
|
|
113
125
|
};
|
|
114
126
|
|
|
127
|
+
// An answer the turn goes on past (queued input or a todo reminder arrived
|
|
128
|
+
// after it) is committed like any segment and also kept as part of the
|
|
129
|
+
// turn's report: a tool batch clears the segments, and the caller (an
|
|
130
|
+
// agent's owner) must still receive that answer, not only the short reply
|
|
131
|
+
// that follows it. The answer is every part since the previous one or the
|
|
132
|
+
// last tool batch (an output-limit cut and its resumption included).
|
|
133
|
+
const keepEndedAnswer = (response, hasContent) => {
|
|
134
|
+
if (!segments.commitIntermediate(response) || !hasContent) return false;
|
|
135
|
+
segments.record(response.content, { committed: true });
|
|
136
|
+
state.endedPartsEnd = segments.parts.length;
|
|
137
|
+
return true;
|
|
138
|
+
};
|
|
139
|
+
const endedReport = () =>
|
|
140
|
+
joinReports([...state.carriedAnswers, segments.parts.slice(0, state.endedPartsEnd).join('')]);
|
|
141
|
+
// Answers still in the segments are in the response's own aggregate.
|
|
142
|
+
const finalize = (response) =>
|
|
143
|
+
state.carriedAnswers.length === 0 ? response : withEarlierReport(response, joinReports(state.carriedAnswers));
|
|
144
|
+
|
|
145
|
+
async function resolveTurn(response, iteration) {
|
|
146
|
+
const hasContent = typeof response.content === 'string' && response.content.trim().length > 0;
|
|
147
|
+
const stopReason = response.stopReason ?? response.stop_reason ?? null;
|
|
148
|
+
const isOutputLimitStop = isOutputLimitStopReason(stopReason);
|
|
149
|
+
if (isOutputLimitStop || (hasContent && response.streamCut === true)) {
|
|
150
|
+
return resolveOutputLimit(response, ladder);
|
|
151
|
+
}
|
|
152
|
+
if (stopReason === 'refusal') return resolveRefusal(response, hasContent, ladder);
|
|
153
|
+
// Output-limit stops keep the bounded max-output ladder above and
|
|
154
|
+
// refusals (already returned) keep the bounded refusal retry; both
|
|
155
|
+
// own their own continuation semantics. No lexical/progress-text
|
|
156
|
+
// heuristic is consulted.
|
|
157
|
+
const continuationSignal = isOutputLimitStop ? null : providerContinuationSignal(response);
|
|
158
|
+
if (
|
|
159
|
+
continuationSignal &&
|
|
160
|
+
resumeContinuation(response, { iteration, signal: continuationSignal, hasContent, stopReason }, ladder)
|
|
161
|
+
) {
|
|
162
|
+
return { action: 'continue', response };
|
|
163
|
+
}
|
|
164
|
+
// Hidden roles are exempt from the empty-turn nudge: their own role
|
|
165
|
+
// rules define a different output contract (pipe-separated chunker
|
|
166
|
+
// output, …) and a text-only terminal turn is the correct shape —
|
|
167
|
+
// nudging them produces a contradictory user message that traps the
|
|
168
|
+
// model in a tool-call-blocked vs contract-required oscillation.
|
|
169
|
+
// A turn that left a reaction on the user's message may end with no
|
|
170
|
+
// text: the reaction is its answer (react tool), never an empty turn.
|
|
171
|
+
// Nor does a turn whose kept answer only todo bookkeeping followed: that
|
|
172
|
+
// answer is its reply.
|
|
173
|
+
if (!hasContent && !HIDDEN_AGENT_NAMES.has(sessionAgent) && !reactionAnswersLatest() && !state.reportStands) {
|
|
174
|
+
return nudgeEmptyTurn(
|
|
175
|
+
response,
|
|
176
|
+
{ stopReason, isIncompleteStop: stopReason && INCOMPLETE_STOP_REASONS.has(stopReason) },
|
|
177
|
+
ladder
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
// Pending-input rule: queued user input is folded into
|
|
181
|
+
// needs_follow_up before terminal completion. Commit the terminal
|
|
182
|
+
// text first (beforeAppend), then resume.
|
|
183
|
+
if (
|
|
184
|
+
drainSteering('terminal', {
|
|
185
|
+
maxPriority: 'next',
|
|
186
|
+
beforeAppend: () => keepEndedAnswer(response, hasContent),
|
|
187
|
+
})
|
|
188
|
+
) {
|
|
189
|
+
state.emptyNudgeStreak = 0;
|
|
190
|
+
resetOutputLimitRecovery(state);
|
|
191
|
+
return { action: 'continue', response };
|
|
192
|
+
}
|
|
193
|
+
const reminder = todoCompletionReminder(opts.session, {
|
|
194
|
+
sessionId,
|
|
195
|
+
sessionAgent,
|
|
196
|
+
turnLimited: turnLimited(),
|
|
197
|
+
});
|
|
198
|
+
if (reminder) {
|
|
199
|
+
if (keepEndedAnswer(response, hasContent)) state.reportStands = true;
|
|
200
|
+
messages.push({ role: 'user', content: reminder });
|
|
201
|
+
return { action: 'continue', response };
|
|
202
|
+
}
|
|
203
|
+
return finishTurn(response);
|
|
204
|
+
}
|
|
205
|
+
|
|
115
206
|
return {
|
|
116
207
|
// { action: 'continue' | 'break', response }. 'continue' means the
|
|
117
208
|
// recovery appended to the transcript and the loop must re-send;
|
|
118
|
-
// 'break' returns the (possibly aggregated) terminal response
|
|
209
|
+
// 'break' returns the (possibly aggregated) terminal response, with the
|
|
210
|
+
// ended answers a tool batch cleared from it as its report.
|
|
119
211
|
async resolve(response, iteration) {
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
// Hidden roles are exempt from the empty-turn nudge: their own role
|
|
139
|
-
// rules define a different output contract (pipe-separated chunker
|
|
140
|
-
// output, …) and a text-only terminal turn is the correct shape —
|
|
141
|
-
// nudging them produces a contradictory user message that traps the
|
|
142
|
-
// model in a tool-call-blocked vs contract-required oscillation.
|
|
143
|
-
// A turn that left a reaction on the user's message may end with no
|
|
144
|
-
// text: the reaction is its answer (react tool), never an empty turn.
|
|
145
|
-
if (!hasContent && !HIDDEN_AGENT_NAMES.has(sessionAgent) && !reactionAnswersLatest()) {
|
|
146
|
-
return nudgeEmptyTurn(
|
|
147
|
-
response,
|
|
148
|
-
{ stopReason, isIncompleteStop: stopReason && INCOMPLETE_STOP_REASONS.has(stopReason) },
|
|
149
|
-
ladder
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
// Pending-input rule: queued user input is folded into
|
|
153
|
-
// needs_follow_up before terminal completion. Commit the terminal
|
|
154
|
-
// text first (beforeAppend), then resume.
|
|
155
|
-
if (
|
|
156
|
-
drainSteering('terminal', {
|
|
157
|
-
maxPriority: 'next',
|
|
158
|
-
beforeAppend: () => {
|
|
159
|
-
if (segments.commitIntermediate(response) && hasContent)
|
|
160
|
-
segments.record(response.content, { committed: true });
|
|
161
|
-
},
|
|
162
|
-
})
|
|
163
|
-
) {
|
|
164
|
-
state.emptyNudgeStreak = 0;
|
|
165
|
-
resetOutputLimitRecovery(state);
|
|
166
|
-
return { action: 'continue', response };
|
|
167
|
-
}
|
|
168
|
-
return finishTurn(response);
|
|
212
|
+
const outcome = await resolveTurn(response, iteration);
|
|
213
|
+
if (outcome.action !== 'break') return outcome;
|
|
214
|
+
return { ...outcome, response: finalize(outcome.response) };
|
|
215
|
+
},
|
|
216
|
+
// The terminal response of a turn that ended any other way (a capped
|
|
217
|
+
// turn's overrun) gets the same report.
|
|
218
|
+
finalize,
|
|
219
|
+
// Every answer the turn went on past, for a turn that fails after them.
|
|
220
|
+
endedReport,
|
|
221
|
+
// Input the turn took in (steering at any boundary) is new work: its
|
|
222
|
+
// outcome is the turn's, not the kept answer's.
|
|
223
|
+
noteNewInput() {
|
|
224
|
+
state.reportStands = false;
|
|
225
|
+
},
|
|
226
|
+
// An empty end after the kept answer is that answer's turn ending.
|
|
227
|
+
get reportStands() {
|
|
228
|
+
return state.reportStands;
|
|
169
229
|
},
|
|
170
230
|
// A turn that produced tool calls is never an empty contract violation,
|
|
171
231
|
// and it is real progress: a later output-limit cut starts a fresh ladder.
|
|
@@ -177,6 +237,12 @@ export function createNoToolTurnResolver({
|
|
|
177
237
|
// succeeded marks the turn as having reacted.
|
|
178
238
|
noteToolBatchCompleted(calls = [], results = []) {
|
|
179
239
|
state.continuationsSinceToolBatch = 0;
|
|
240
|
+
noteTodoProgress(opts.session);
|
|
241
|
+
const stale = staleTodoReminder(opts.session, calls, results, { sessionAgent });
|
|
242
|
+
if (stale) messages.push({ role: 'user', content: stale, meta: 'hook' });
|
|
243
|
+
if (state.endedPartsEnd > 0) state.carriedAnswers.push(segments.parts.slice(0, state.endedPartsEnd).join(''));
|
|
244
|
+
state.endedPartsEnd = 0;
|
|
245
|
+
if (calls.some((call) => (call?.name ?? call?.function?.name) !== TODO_TOOL.name)) state.reportStands = false;
|
|
180
246
|
segments.clear();
|
|
181
247
|
state.reactions.push(...batchReactions(calls, results));
|
|
182
248
|
},
|
|
@@ -14,7 +14,11 @@
|
|
|
14
14
|
import { isAgentOwner } from '../../agent-owner.mjs';
|
|
15
15
|
import { isOffReadonlySurface } from './deferred-call-through.mjs';
|
|
16
16
|
import { BRIDGE_CALL_TOOL_NAME, bridgeErrorText, isToolBridgeEnabled } from '../../runtime-core/tool-bridge.mjs';
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
sessionAllowlistExcludes,
|
|
19
|
+
sessionDisallows,
|
|
20
|
+
sessionFeatureDenies,
|
|
21
|
+
} from '../../runtime-core/deferred-tool-availability.mjs';
|
|
18
22
|
import { providerToolExclusionReason } from './provider-tool-exclusions.mjs';
|
|
19
23
|
import { workflowOverlayDenial } from '../manager/workflow-switch-notice.mjs';
|
|
20
24
|
import { agentMcpToolPermission, connectorPolicyAgentOf, projectMcpToolDisabled } from '../../mcp/agent-connectors.mjs';
|
|
@@ -125,6 +129,9 @@ export function preDispatchDenyForSession(sessionRef, call) {
|
|
|
125
129
|
const workflowDenial = workflowOverlayDenial(sessionRef, schemaName);
|
|
126
130
|
if (workflowDenial) return workflowDenial;
|
|
127
131
|
if (sessionDisallows(sessionRef, schemaName)) {
|
|
132
|
+
if (sessionFeatureDenies(sessionRef, schemaName)) {
|
|
133
|
+
return `Error: tool "${schemaName}" is disabled in settings by the user. Do not retry unless the user turns it back on.`;
|
|
134
|
+
}
|
|
128
135
|
return `Error: tool "${name}" is not available in this session.`;
|
|
129
136
|
}
|
|
130
137
|
// An agent's connectors: a tool of a server it does not mount, or one set
|
|
@@ -43,7 +43,7 @@ export function beginProviderToolExclusions(sessionRef) {
|
|
|
43
43
|
if (isSessionRef(sessionRef)) sessions.get(sessionRef)?.current.clear();
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
function excludedToolNoticeText({ name, pointer, reason }) {
|
|
47
47
|
return `Tool "${name}" was excluded from this session's requests: its input schema is invalid at ${pointer || '/'} (${reason}). Fix the tool's schema or disable the tool.`;
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -38,7 +38,7 @@ const HOP_REASONS = {
|
|
|
38
38
|
const routeLabel = (route) => displayModelName(route.model, route.provider) || `${route.provider}/${route.model}`;
|
|
39
39
|
|
|
40
40
|
/** The muted transcript line for a hop: `<from> <reason> — switched to <to>.` */
|
|
41
|
-
|
|
41
|
+
function routeFallbackNoticeText(from, to, error) {
|
|
42
42
|
const reason = HOP_REASONS[providerErrorKind(error).kind] || 'unavailable';
|
|
43
43
|
return `${routeLabel(from)} ${reason} — switched to ${routeLabel(to)}.`;
|
|
44
44
|
}
|
|
@@ -198,7 +198,8 @@ function injectSteeringEntry(merged, { messages, opts, stage, onSkillPrompt }) {
|
|
|
198
198
|
// The drain is synchronous (terminal guards depend on that) and returns whether
|
|
199
199
|
// anything was injected. `onSkillPrompt` receives each typed entry so the loop
|
|
200
200
|
// can run its policy-checked skill selection before the next provider snapshot.
|
|
201
|
-
|
|
201
|
+
// `onInjected` learns of every drain that added input, whatever its stage.
|
|
202
|
+
export function createSteeringDrain({ messages, opts, sessionId, onSkillPrompt, onInjected = () => {} }) {
|
|
202
203
|
return function drainSteeringIntoMessages(stage = 'mid-turn', options = {}) {
|
|
203
204
|
if (typeof opts.drainSteering !== 'function') return false;
|
|
204
205
|
let steerMsgs = [];
|
|
@@ -232,6 +233,7 @@ export function createSteeringDrain({ messages, opts, sessionId, onSkillPrompt }
|
|
|
232
233
|
totalTextLen += injected.textLength;
|
|
233
234
|
maxQueueWaitMs = Math.max(maxQueueWaitMs, injected.queueWaitMs);
|
|
234
235
|
}
|
|
236
|
+
onInjected(stage);
|
|
235
237
|
if (sessionId) {
|
|
236
238
|
try {
|
|
237
239
|
process.stderr.write(
|
|
@@ -6,12 +6,11 @@
|
|
|
6
6
|
// copy `[mixdog compacted …]` back as literal patch input.
|
|
7
7
|
//
|
|
8
8
|
// Mutation bodies (patch / old_string / new_string / content / rewrite) are
|
|
9
|
-
// never collapsed after the fact.
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// REMAINING turns, and a task rarely has enough of them left. Bodies now stay
|
|
9
|
+
// never collapsed after the fact. A later sweep would rewrite a prefix the
|
|
10
|
+
// provider has already cached, and every rewrite re-bills that whole request at
|
|
11
|
+
// the uncached rate. Measured over one 89-task run: $1.20 lost to recover
|
|
12
|
+
// $0.16, because the collapsed tokens only come back at the cached rate over
|
|
13
|
+
// the REMAINING turns, and a task rarely has enough of them left. Bodies stay
|
|
15
14
|
// verbatim in history, so the prefix — and its cache — survives the session.
|
|
16
15
|
import { createHash } from 'node:crypto';
|
|
17
16
|
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from '../../human-gate/gate.mjs';
|
|
17
17
|
import { applyEditedArgs } from '../../human-gate/requests.mjs';
|
|
18
18
|
import { effectiveToolCwd } from '../../../tools/builtin/bash-tool/shell-cwd.mjs';
|
|
19
|
+
import { noteTodoUserWait } from '../no-tool-turn/todo-check.mjs';
|
|
19
20
|
|
|
20
21
|
const isArgsObject = (value) => value && typeof value === 'object' && !Array.isArray(value);
|
|
21
22
|
|
|
@@ -56,7 +57,11 @@ async function askApproval(
|
|
|
56
57
|
}
|
|
57
58
|
const approval = askOutcome.approval;
|
|
58
59
|
await recordHumanDecision(gate, approval);
|
|
59
|
-
if (askOutcome.denial)
|
|
60
|
+
if (askOutcome.denial) {
|
|
61
|
+
// The user said no: this turn may end waiting on them (todo-check.mjs).
|
|
62
|
+
noteTodoUserWait(callerSessionId);
|
|
63
|
+
return { denial: askOutcome.denial };
|
|
64
|
+
}
|
|
60
65
|
if (approval && typeof approval === 'object' && isArgsObject(approval.args)) call.args = approval.args;
|
|
61
66
|
// The card's edited text replaces the model's before the call runs.
|
|
62
67
|
if (request?.kind === 'outbound' && approval?.editedArgs) {
|
|
@@ -19,7 +19,9 @@ import {
|
|
|
19
19
|
} from '../../../tools/builtin.mjs';
|
|
20
20
|
import { executePatchTool } from '../../../tools/patch.mjs';
|
|
21
21
|
import { executeInternalTool, isInternalTool } from '../../../internal-tools.mjs';
|
|
22
|
+
import { settingDisabledTool } from '../../../runtime-core/tool-availability.mjs';
|
|
22
23
|
import { buildSkillsListResponse, viewSkill } from '../tool-helpers.mjs';
|
|
24
|
+
import { executeTodoTool } from '../../../runtime-core/todo-list.mjs';
|
|
23
25
|
import { isOnDeferredToolSurface } from '../deferred-call-through.mjs';
|
|
24
26
|
import { _executeCodeGraphToolLazy } from '../../manager/runtime-loaders.mjs';
|
|
25
27
|
import { requiresReadBody } from '../tool-classify.mjs';
|
|
@@ -57,8 +59,8 @@ function dispatchMcp(name, args, { cwd, callerSessionId, sessionRef, executeOpts
|
|
|
57
59
|
return formatUnknownBuiltinToolMessage(name, args, 'tool');
|
|
58
60
|
}
|
|
59
61
|
// 24h trace data shows ~24% of external MCP calls are cwd-sensitive
|
|
60
|
-
// (bash / grep / read / list / glob etc.)
|
|
61
|
-
// cwd
|
|
62
|
+
// (bash / grep / read / list / glob etc.), so the worker session's
|
|
63
|
+
// cwd must reach them. Inject cwd only when the tool's
|
|
62
64
|
// inputSchema declares the field — schemas without it would reject
|
|
63
65
|
// an unknown argument.
|
|
64
66
|
const needsCwdInjection = cwd && mcpToolHasField(name, 'cwd', mcpScopeId) && (args == null || args.cwd == null);
|
|
@@ -120,8 +122,20 @@ function dispatchInternal(
|
|
|
120
122
|
*/
|
|
121
123
|
export function dispatchToolCall({ name, args }, ctx) {
|
|
122
124
|
const { cwd, callerSessionId, sessionRef, executeOpts, toolOpts, completionToolOpts } = ctx;
|
|
125
|
+
const disabled = settingDisabledTool(name, sessionRef?.mcpScopeId);
|
|
126
|
+
if (disabled) {
|
|
127
|
+
return `Error: tool "${disabled}" is disabled in settings by the user; do not retry unless the user turns it back on`;
|
|
128
|
+
}
|
|
123
129
|
if (name === 'Skill' || name === 'skill_view') return viewSkill(cwd, args?.name, sessionRef);
|
|
124
130
|
if (name === 'skills_list') return buildSkillsListResponse(cwd);
|
|
131
|
+
// The step list belongs to the calling session itself (Lead or agent).
|
|
132
|
+
if (name === 'todo') {
|
|
133
|
+
try {
|
|
134
|
+
return executeTodoTool(sessionRef, args || {});
|
|
135
|
+
} catch (error) {
|
|
136
|
+
return `Error: ${error?.message || String(error)}`;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
125
139
|
if (isMcpTool(name)) return dispatchMcp(name, args, ctx);
|
|
126
140
|
if (name === 'code_graph') {
|
|
127
141
|
// cwd chain: args.cwd (caller-explicit) → session cwd → undefined (handler throws)
|