@gajae-code/coding-agent 0.11.1 → 0.11.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/CHANGELOG.md +54 -0
- package/dist/types/cli/config-cli.d.ts +11 -1
- package/dist/types/cli/notify-cli.d.ts +1 -0
- package/dist/types/cli/session-picker.d.ts +2 -1
- package/dist/types/cli/setup-cli.d.ts +1 -1
- package/dist/types/commands/mcp-serve.d.ts +33 -0
- package/dist/types/commands/mcp.d.ts +1 -1
- package/dist/types/commands/notify.d.ts +0 -2
- package/dist/types/commands/sdk.d.ts +1 -1
- package/dist/types/config/atomic-yaml-patch.d.ts +18 -0
- package/dist/types/config/file-lock.d.ts +14 -4
- package/dist/types/config/keybindings.d.ts +42 -1
- package/dist/types/config/model-auth.d.ts +3 -0
- package/dist/types/config/model-bindings-applier.d.ts +13 -0
- package/dist/types/config/model-discovery-manager.d.ts +49 -0
- package/dist/types/config/model-equivalence.d.ts +20 -0
- package/dist/types/config/model-registry.d.ts +16 -15
- package/dist/types/config/model-resolver.d.ts +28 -18
- package/dist/types/config/models-config-schema.d.ts +11 -0
- package/dist/types/config/settings-schema.d.ts +56 -1
- package/dist/types/config/settings.d.ts +14 -11
- package/dist/types/coordinator-mcp/policy.d.ts +5 -0
- package/dist/types/coordinator-mcp/question-gate-codec.d.ts +129 -0
- package/dist/types/coordinator-mcp/question-state.d.ts +356 -0
- package/dist/types/coordinator-mcp/server.d.ts +4 -0
- package/dist/types/discovery/helpers.d.ts +0 -6
- package/dist/types/edit/index.d.ts +3 -0
- package/dist/types/eval/py/env.d.ts +9 -0
- package/dist/types/extensibility/extensions/loader.d.ts +2 -1
- package/dist/types/extensibility/extensions/runner.d.ts +2 -2
- package/dist/types/extensibility/extensions/types.d.ts +34 -3
- package/dist/types/extensibility/hooks/runner.d.ts +1 -1
- package/dist/types/extensibility/shared-events.d.ts +2 -0
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +10 -1
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +44 -0
- package/dist/types/gjc-runtime/goal-mode-request.d.ts +11 -1
- package/dist/types/gjc-runtime/launch-worktree.d.ts +4 -2
- package/dist/types/gjc-runtime/linux-proc.d.ts +29 -0
- package/dist/types/gjc-runtime/session-resolution.d.ts +2 -2
- package/dist/types/gjc-runtime/state-migrations.d.ts +1 -1
- package/dist/types/gjc-runtime/state-writer.d.ts +2 -1
- package/dist/types/gjc-runtime/team-launch.d.ts +59 -0
- package/dist/types/gjc-runtime/team-notify.d.ts +45 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +29 -121
- package/dist/types/gjc-runtime/team-store.d.ts +160 -0
- package/dist/types/gjc-runtime/team-workers.d.ts +78 -0
- package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +8 -0
- package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +13 -0
- package/dist/types/gjc-runtime/ultragoal-evidence.d.ts +38 -0
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +7 -0
- package/dist/types/gjc-runtime/ultragoal-pipeline.d.ts +23 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +55 -33
- package/dist/types/gjc-runtime/workflow-cli-common.d.ts +8 -0
- package/dist/types/gjc-runtime/workflow-manifest.d.ts +3 -0
- package/dist/types/goals/continuation-timeout-guard.d.ts +22 -0
- package/dist/types/goals/runtime.d.ts +1 -0
- package/dist/types/goals/state.d.ts +8 -0
- package/dist/types/harness-control-plane/lifecycle-reconciliation.d.ts +17 -0
- package/dist/types/harness-control-plane/phase-rollup.d.ts +4 -7
- package/dist/types/harness-control-plane/receipt-ingest.d.ts +5 -0
- package/dist/types/harness-control-plane/receipt-spool.d.ts +4 -0
- package/dist/types/hindsight/state.d.ts +11 -4
- package/dist/types/lsp/lspmux.d.ts +5 -3
- package/dist/types/lsp/path-trust.d.ts +1 -0
- package/dist/types/main.d.ts +3 -2
- package/dist/types/memories/storage.d.ts +1 -0
- package/dist/types/modes/action-registry.d.ts +29 -0
- package/dist/types/modes/components/chrome.d.ts +14 -0
- package/dist/types/modes/components/command-palette.d.ts +27 -0
- package/dist/types/modes/components/custom-provider-wizard.d.ts +1 -0
- package/dist/types/modes/components/index.d.ts +2 -1
- package/dist/types/modes/components/pet-selector.d.ts +1 -1
- package/dist/types/modes/components/plan-preview-overlay.d.ts +43 -0
- package/dist/types/modes/components/queue-mode-selector.d.ts +1 -1
- package/dist/types/modes/components/queue-pane.d.ts +12 -0
- package/dist/types/modes/components/read-tool-group.d.ts +6 -0
- package/dist/types/modes/components/session-observer-overlay.d.ts +3 -4
- package/dist/types/modes/components/sessions-dashboard.d.ts +32 -0
- package/dist/types/modes/components/settings-selector.d.ts +1 -1
- package/dist/types/modes/components/show-images-selector.d.ts +1 -1
- package/dist/types/modes/components/status-line/types.d.ts +1 -1
- package/dist/types/modes/components/status-line.d.ts +1 -94
- package/dist/types/modes/components/tasks-pane.d.ts +15 -0
- package/dist/types/modes/components/theme-selector.d.ts +1 -1
- package/dist/types/modes/components/tool-execution.d.ts +15 -0
- package/dist/types/modes/components/tool-status-header.d.ts +111 -0
- package/dist/types/modes/components/transcript-viewer-overlay.d.ts +42 -0
- package/dist/types/modes/controllers/goal-mode-controller.d.ts +62 -0
- package/dist/types/modes/controllers/input-controller.d.ts +8 -1
- package/dist/types/modes/controllers/mode-gate.d.ts +8 -0
- package/dist/types/modes/controllers/plan-mode-controller.d.ts +65 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +15 -3
- package/dist/types/modes/controllers/stt-controller.d.ts +26 -0
- package/dist/types/modes/interactive-mode.d.ts +19 -17
- package/dist/types/modes/jobs-observer.d.ts +2 -0
- package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +4 -11
- package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +20 -2
- package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +31 -0
- package/dist/types/modes/tasks-aggregator.d.ts +39 -0
- package/dist/types/modes/transcript-item-registry.d.ts +60 -0
- package/dist/types/modes/types.d.ts +20 -13
- package/dist/types/modes/utils/ui-helpers.d.ts +2 -2
- package/dist/types/runtime-mcp/manager.d.ts +1 -1
- package/dist/types/sdk/broker/broker.d.ts +78 -12
- package/dist/types/sdk/broker/lifecycle-codec.d.ts +4 -0
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +15 -1
- package/dist/types/sdk/broker/lifecycle.d.ts +6 -2
- package/dist/types/sdk/broker/process-incarnation.d.ts +2 -0
- package/dist/types/sdk/broker/session-index.d.ts +0 -1
- package/dist/types/sdk/broker/state-version.d.ts +2 -0
- package/dist/types/sdk/bus/chat-effect-journal.d.ts +1 -0
- package/dist/types/sdk/bus/config-commands.d.ts +1 -1
- package/dist/types/sdk/bus/config.d.ts +11 -0
- package/dist/types/sdk/bus/daemon-paths.d.ts +1 -0
- package/dist/types/sdk/bus/html-format.d.ts +3 -2
- package/dist/types/sdk/bus/index.d.ts +27 -0
- package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
- package/dist/types/sdk/bus/notification-service.d.ts +20 -0
- package/dist/types/sdk/bus/rate-limit-pool.d.ts +13 -2
- package/dist/types/sdk/bus/recent-activity.d.ts +21 -12
- package/dist/types/sdk/bus/rich-document.d.ts +7 -0
- package/dist/types/sdk/bus/rich-render.d.ts +18 -41
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +9 -4
- package/dist/types/sdk/bus/telegram-daemon.d.ts +46 -3
- package/dist/types/sdk/bus/threaded-inbound.d.ts +1 -1
- package/dist/types/sdk/bus/threaded-render.d.ts +13 -0
- package/dist/types/sdk/bus/topic-registry.d.ts +24 -2
- package/dist/types/sdk/host/control/operations.d.ts +1 -1
- package/dist/types/sdk/host/host.d.ts +2 -0
- package/dist/types/sdk/index.d.ts +1 -0
- package/dist/types/sdk/session-directory.d.ts +56 -0
- package/dist/types/session/agent-session.d.ts +82 -47
- package/dist/types/session/agent-storage.d.ts +7 -0
- package/dist/types/session/fallback-chain-controller.d.ts +10 -2
- package/dist/types/session/internal/managed-session-scope.d.ts +102 -0
- package/dist/types/session/internal/managed-session-storage.d.ts +38 -0
- package/dist/types/session/messages.d.ts +16 -0
- package/dist/types/session/session-manager-internal.d.ts +14 -0
- package/dist/types/session/session-manager.d.ts +82 -12
- package/dist/types/session/session-storage.d.ts +43 -3
- package/dist/types/session/volatile-context-pruning.d.ts +15 -0
- package/dist/types/skill-state/{deep-interview-mutation-guard.d.ts → workflow-mutation-guard.d.ts} +24 -8
- package/dist/types/skill-state/workflow-state-contract.d.ts +1 -3
- package/dist/types/slash-commands/builtin-registry.d.ts +4 -1
- package/dist/types/system-prompt.d.ts +2 -11
- package/dist/types/task/executor.d.ts +3 -1
- package/dist/types/thinking.d.ts +7 -0
- package/dist/types/tool-discovery/tool-index.d.ts +1 -50
- package/dist/types/tools/ask.d.ts +64 -2
- package/dist/types/tools/bash.d.ts +3 -0
- package/dist/types/tools/browser/dead-tab-recovery.d.ts +24 -0
- package/dist/types/tools/browser/tab-supervisor.d.ts +21 -0
- package/dist/types/tools/cron.d.ts +2 -0
- package/dist/types/tools/fetch.d.ts +1 -0
- package/dist/types/tools/index.d.ts +30 -15
- package/dist/types/tools/output-meta.d.ts +1 -0
- package/dist/types/tools/read.d.ts +3 -0
- package/dist/types/tools/search-tool-bm25.d.ts +3 -4
- package/dist/types/utils/event-bus.d.ts +1 -1
- package/dist/types/web/search/index.d.ts +3 -1
- package/package.json +21 -9
- package/scripts/build-sdk-package-smoke.ts +34 -1
- package/scripts/generate-hotkeys-docs.ts +74 -0
- package/scripts/generate-sdk-operation-inventory.ts +64 -20
- package/scripts/verify-gjc-sdk-canonicalization.ts +182 -2
- package/src/async/job-manager.ts +49 -6
- package/src/cli/config-cli.ts +75 -2
- package/src/cli/notify-cli.ts +92 -26
- package/src/cli/session-picker.ts +20 -3
- package/src/cli/setup-cli.ts +1 -1
- package/src/cli.ts +1 -1
- package/src/commands/config.ts +1 -1
- package/src/commands/harness.ts +34 -106
- package/src/commands/launch.ts +6 -4
- package/src/commands/mcp-serve.ts +85 -8
- package/src/commands/mcp.ts +2 -2
- package/src/commands/notify.ts +8 -4
- package/src/commands/sdk.ts +61 -40
- package/src/commands/ultragoal.ts +4 -1
- package/src/config/atomic-yaml-patch.ts +80 -13
- package/src/config/file-lock.ts +105 -43
- package/src/config/keybindings.ts +64 -20
- package/src/config/model-auth.ts +9 -0
- package/src/config/model-bindings-applier.ts +139 -0
- package/src/config/model-discovery-manager.ts +224 -0
- package/src/config/model-equivalence.ts +66 -0
- package/src/config/model-registry.ts +169 -302
- package/src/config/model-resolver.ts +361 -369
- package/src/config/models-config-schema.ts +5 -4
- package/src/config/settings-schema.ts +159 -2
- package/src/config/settings.ts +458 -482
- package/src/coordinator-mcp/policy.ts +76 -11
- package/src/coordinator-mcp/question-gate-codec.ts +274 -0
- package/src/coordinator-mcp/question-state.ts +778 -0
- package/src/coordinator-mcp/server.ts +1702 -238
- package/src/debug/index.ts +1 -1
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +13 -1
- package/src/defaults/gjc/skills/team/SKILL.md +16 -0
- package/src/discovery/helpers.ts +1 -50
- package/src/edit/index.ts +64 -0
- package/src/eval/py/env.ts +26 -0
- package/src/eval/py/kernel.ts +5 -3
- package/src/extensibility/extensions/loader.ts +9 -1
- package/src/extensibility/extensions/runner.ts +12 -3
- package/src/extensibility/extensions/types.ts +39 -1
- package/src/extensibility/gjc-plugins/installer.ts +16 -16
- package/src/extensibility/hooks/runner.ts +2 -2
- package/src/extensibility/runtime-skill-discovery.ts +33 -13
- package/src/extensibility/shared-events.ts +2 -0
- package/src/gjc-runtime/deep-interview-recorder.ts +63 -3
- package/src/gjc-runtime/deep-interview-runtime.ts +76 -27
- package/src/gjc-runtime/deep-interview-state.ts +317 -5
- package/src/gjc-runtime/goal-mode-request.ts +55 -8
- package/src/gjc-runtime/launch-tmux.ts +2 -5
- package/src/gjc-runtime/launch-worktree.ts +5 -5
- package/src/gjc-runtime/linux-proc.ts +71 -0
- package/src/gjc-runtime/ralplan-runtime.ts +74 -90
- package/src/gjc-runtime/session-resolution.ts +18 -3
- package/src/gjc-runtime/session-state-sidecar.ts +6 -107
- package/src/gjc-runtime/state-migrations.ts +1 -1
- package/src/gjc-runtime/state-runtime.ts +320 -249
- package/src/gjc-runtime/state-writer.ts +36 -40
- package/src/gjc-runtime/team-launch.ts +319 -0
- package/src/gjc-runtime/team-notify.ts +326 -0
- package/src/gjc-runtime/team-runtime.ts +1099 -1482
- package/src/gjc-runtime/team-store.ts +828 -0
- package/src/gjc-runtime/team-workers.ts +962 -0
- package/src/gjc-runtime/tmux-owner-isolation-cli.ts +2 -11
- package/src/gjc-runtime/tmux-owner-isolation.ts +14 -9
- package/src/gjc-runtime/tmux-sessions.ts +4 -21
- package/src/gjc-runtime/ultragoal-change-set.ts +172 -0
- package/src/gjc-runtime/ultragoal-evidence.ts +874 -0
- package/src/gjc-runtime/ultragoal-guard.ts +29 -5
- package/src/gjc-runtime/ultragoal-pipeline.ts +306 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +84 -1311
- package/src/gjc-runtime/workflow-cli-common.ts +30 -0
- package/src/gjc-runtime/workflow-manifest.generated.json +58 -0
- package/src/gjc-runtime/workflow-manifest.ts +18 -0
- package/src/goals/continuation-timeout-guard.ts +79 -0
- package/src/goals/runtime.ts +7 -5
- package/src/goals/state.ts +18 -0
- package/src/harness-control-plane/lifecycle-reconciliation.ts +64 -0
- package/src/harness-control-plane/phase-rollup.ts +4 -7
- package/src/harness-control-plane/receipt-ingest.ts +5 -0
- package/src/harness-control-plane/receipt-spool.ts +51 -7
- package/src/harness-control-plane/session-lease.ts +12 -130
- package/src/hindsight/backend.ts +26 -27
- package/src/hindsight/state.ts +101 -32
- package/src/hooks/skill-state.ts +17 -11
- package/src/internal-urls/docs-index.generated.ts +21 -18
- package/src/lsp/client.ts +1 -1
- package/src/lsp/config.ts +145 -26
- package/src/lsp/index.ts +1 -1
- package/src/lsp/lspmux.ts +39 -10
- package/src/lsp/path-trust.ts +81 -0
- package/src/main.ts +28 -8
- package/src/memories/index.ts +1 -0
- package/src/memories/storage.ts +6 -2
- package/src/modes/action-registry.ts +165 -0
- package/src/modes/components/chrome.ts +40 -0
- package/src/modes/components/command-palette.ts +168 -0
- package/src/modes/components/custom-editor.ts +1 -1
- package/src/modes/components/custom-provider-wizard.ts +51 -14
- package/src/modes/components/index.ts +2 -1
- package/src/modes/components/pet-selector.ts +11 -17
- package/src/modes/components/plan-preview-overlay.ts +295 -0
- package/src/modes/components/queue-mode-selector.ts +10 -27
- package/src/modes/components/queue-pane.ts +79 -0
- package/src/modes/components/read-tool-group.ts +13 -0
- package/src/modes/components/session-observer-overlay.ts +207 -772
- package/src/modes/components/sessions-dashboard.ts +181 -0
- package/src/modes/components/settings-selector.ts +1 -1
- package/src/modes/components/show-images-selector.ts +10 -24
- package/src/modes/components/status-line/types.ts +1 -1
- package/src/modes/components/status-line.ts +1 -969
- package/src/modes/components/tasks-pane.ts +73 -0
- package/src/modes/components/theme-selector.ts +11 -31
- package/src/modes/components/tool-execution.ts +22 -0
- package/src/modes/components/tool-status-header.ts +1056 -0
- package/src/modes/components/transcript-viewer-overlay.ts +384 -0
- package/src/modes/controllers/btw-controller.ts +1 -0
- package/src/modes/controllers/event-controller.ts +3 -2
- package/src/modes/controllers/extension-ui-controller.ts +24 -1
- package/src/modes/controllers/goal-mode-controller.ts +474 -0
- package/src/modes/controllers/input-controller.ts +764 -229
- package/src/modes/controllers/mode-gate.ts +24 -0
- package/src/modes/controllers/plan-mode-controller.ts +517 -0
- package/src/modes/controllers/selector-controller.ts +225 -10
- package/src/modes/controllers/stt-controller.ts +125 -0
- package/src/modes/interactive-mode.ts +289 -1150
- package/src/modes/jobs-observer.ts +3 -0
- package/src/modes/runtime-init.ts +8 -0
- package/src/modes/shared/agent-wire/deep-interview-gate.ts +31 -106
- package/src/modes/shared/agent-wire/workflow-gate-broker.ts +71 -16
- package/src/modes/shared/agent-wire/workflow-gate-types.ts +177 -0
- package/src/modes/tasks-aggregator.ts +199 -0
- package/src/modes/transcript-item-registry.ts +229 -0
- package/src/modes/types.ts +45 -18
- package/src/modes/utils/ui-helpers.ts +17 -9
- package/src/prompts/agent-fragments/ralplan-persistence.md +6 -0
- package/src/prompts/agent-fragments/restricted-bash.md +1 -0
- package/src/prompts/agents/architect.md +2 -8
- package/src/prompts/agents/critic.md +2 -8
- package/src/prompts/agents/executor.md +3 -0
- package/src/prompts/agents/planner.md +4 -12
- package/src/prompts/system/custom-system-prompt.md +1 -23
- package/src/prompts/system/plan-mode-approved.md +8 -0
- package/src/prompts/system/system-prompt.md +17 -96
- package/src/prompts/tools/bash.md +4 -4
- package/src/prompts/tools/browser.md +15 -52
- package/src/prompts/tools/find.md +2 -2
- package/src/prompts/tools/hashline.md +13 -55
- package/src/prompts/tools/read.md +3 -6
- package/src/prompts/tools/search-tool-bm25.md +0 -2
- package/src/prompts/tools/search.md +2 -4
- package/src/prompts/tools/skill-discovery.md +1 -2
- package/src/prompts/tools/task.md +1 -1
- package/src/runtime-mcp/manager.ts +1 -1
- package/src/sdk/broker/broker.ts +206 -78
- package/src/sdk/broker/discovery.ts +1 -1
- package/src/sdk/broker/ensure.ts +3 -1
- package/src/sdk/broker/lifecycle-codec.ts +11 -0
- package/src/sdk/broker/lifecycle-ledger.ts +371 -74
- package/src/sdk/broker/lifecycle.ts +1399 -142
- package/src/sdk/broker/process-incarnation.ts +5 -13
- package/src/sdk/broker/session-index.ts +145 -56
- package/src/sdk/broker/state-version.ts +21 -0
- package/src/sdk/broker/transport.ts +1 -1
- package/src/sdk/bus/chat-daemon-cli.ts +2 -0
- package/src/sdk/bus/chat-daemon-control.ts +8 -28
- package/src/sdk/bus/chat-effect-journal.ts +10 -2
- package/src/sdk/bus/config-commands.ts +5 -4
- package/src/sdk/bus/config.ts +98 -0
- package/src/sdk/bus/conversation-store.ts +5 -29
- package/src/sdk/bus/daemon-paths.ts +2 -0
- package/src/sdk/bus/html-format.ts +20 -3
- package/src/sdk/bus/index.ts +778 -93
- package/src/sdk/bus/lifecycle-control-runtime.ts +91 -33
- package/src/sdk/bus/natives-augment.d.ts +26 -1
- package/src/sdk/bus/notification-service.ts +168 -20
- package/src/sdk/bus/rate-limit-pool.ts +58 -14
- package/src/sdk/bus/recent-activity.ts +188 -74
- package/src/sdk/bus/rich-document.ts +258 -0
- package/src/sdk/bus/rich-render.ts +62 -70
- package/src/sdk/bus/telegram-daemon-cli.ts +15 -59
- package/src/sdk/bus/telegram-daemon-contract.ts +9 -4
- package/src/sdk/bus/telegram-daemon.ts +1389 -237
- package/src/sdk/bus/threaded-inbound.ts +8 -3
- package/src/sdk/bus/threaded-render.ts +57 -1
- package/src/sdk/bus/topic-registry.ts +120 -13
- package/src/sdk/host/control/dispatch.ts +14 -2
- package/src/sdk/host/control/operations.ts +6 -1
- package/src/sdk/host/host.ts +31 -1
- package/src/sdk/host/query/handlers.ts +20 -22
- package/src/sdk/host/query/revision-store.ts +80 -57
- package/src/sdk/index.ts +1 -0
- package/src/sdk/protocol/operation-inventory.generated.json +943 -1907
- package/src/sdk/session-directory.ts +141 -0
- package/src/sdk/session.ts +458 -479
- package/src/session/agent-session.ts +1700 -583
- package/src/session/agent-storage.ts +18 -0
- package/src/session/cache-economics.ts +25 -8
- package/src/session/fallback-chain-controller.ts +53 -3
- package/src/session/internal/managed-session-scope.ts +2226 -0
- package/src/session/internal/managed-session-storage.ts +453 -0
- package/src/session/messages.ts +91 -2
- package/src/session/session-manager-internal.ts +33 -0
- package/src/session/session-manager.ts +1112 -333
- package/src/session/session-storage.ts +444 -39
- package/src/session/volatile-context-pruning.ts +78 -0
- package/src/setup/credential-auto-import.ts +2 -1
- package/src/setup/hermes/templates/operator-instructions.v1.md +1 -1
- package/src/setup/provider-onboarding.ts +36 -61
- package/src/setup/provider-presets.json +5 -0
- package/src/skill-state/active-state.ts +3 -13
- package/src/skill-state/{deep-interview-mutation-guard.ts → workflow-mutation-guard.ts} +47 -29
- package/src/skill-state/workflow-state-contract.ts +6 -41
- package/src/slash-commands/builtin-registry.ts +46 -11
- package/src/system-prompt.ts +37 -44
- package/src/task/agents.ts +19 -1
- package/src/task/executor.ts +90 -6
- package/src/task/index.ts +36 -21
- package/src/thinking.ts +21 -6
- package/src/tool-discovery/tool-index.ts +2 -134
- package/src/tools/ask.ts +157 -21
- package/src/tools/ast-edit.ts +1 -1
- package/src/tools/bash.ts +38 -0
- package/src/tools/browser/dead-tab-recovery.ts +78 -0
- package/src/tools/browser/tab-supervisor.ts +282 -36
- package/src/tools/computer.ts +10 -3
- package/src/tools/cron.ts +30 -16
- package/src/tools/eval.ts +1 -2
- package/src/tools/fetch.ts +11 -4
- package/src/tools/index.ts +76 -24
- package/src/tools/output-meta.ts +13 -5
- package/src/tools/read.ts +37 -1
- package/src/tools/resource-gc.ts +2 -2
- package/src/tools/search-tool-bm25.ts +11 -74
- package/src/utils/event-bus.ts +9 -4
- package/src/web/search/index.ts +3 -3
- package/dist/types/discovery/plugin-dir-roots.d.ts +0 -15
- package/dist/types/runtime-mcp/discoverable-tool-metadata.d.ts +0 -7
- package/src/discovery/plugin-dir-roots.ts +0 -28
- package/src/runtime-mcp/discoverable-tool-metadata.ts +0 -25
package/src/sdk/session.ts
CHANGED
|
@@ -114,7 +114,7 @@ import { AgentSession, type ForkContextSeed } from "../session/agent-session";
|
|
|
114
114
|
import { resolveAuthBrokerConfig } from "../session/auth-broker-config";
|
|
115
115
|
import { AuthBrokerClient, AuthStorage, RemoteAuthCredentialStore } from "../session/auth-storage";
|
|
116
116
|
import { type CustomMessage, convertToLlm } from "../session/messages";
|
|
117
|
-
import { SessionManager } from "../session/session-manager";
|
|
117
|
+
import { createReadonlySessionManager, SessionManager } from "../session/session-manager";
|
|
118
118
|
import { formatNoModelsAvailableFallback } from "../setup/model-onboarding-guidance";
|
|
119
119
|
import { closeAllConnections } from "../ssh/connection-manager";
|
|
120
120
|
import { unmountAll } from "../ssh/sshfs-mount";
|
|
@@ -126,12 +126,7 @@ import {
|
|
|
126
126
|
} from "../system-prompt";
|
|
127
127
|
import { AgentOutputManager } from "../task/output-manager";
|
|
128
128
|
import { parseThinkingLevel, resolveThinkingLevelForModel, toReasoningEffort } from "../thinking";
|
|
129
|
-
import {
|
|
130
|
-
collectDiscoverableTools,
|
|
131
|
-
type DiscoverableTool,
|
|
132
|
-
isMCPBridgeTool,
|
|
133
|
-
isMCPToolName,
|
|
134
|
-
} from "../tool-discovery/tool-index";
|
|
129
|
+
import { isMCPBridgeTool } from "../tool-discovery/tool-index";
|
|
135
130
|
import {
|
|
136
131
|
applyConfiguredSearchTimeout,
|
|
137
132
|
BashTool,
|
|
@@ -150,7 +145,6 @@ import {
|
|
|
150
145
|
loadSshTool,
|
|
151
146
|
ReadTool,
|
|
152
147
|
ResolveTool,
|
|
153
|
-
renderSearchToolBm25Description,
|
|
154
148
|
SearchTool,
|
|
155
149
|
setPreferredImageProvider,
|
|
156
150
|
setPreferredSearchProvider,
|
|
@@ -498,7 +492,16 @@ export async function discoverAuthStorage(agentDir: string = getDefaultAgentDir(
|
|
|
498
492
|
sourceLabel: `broker ${brokerConfig.url}`,
|
|
499
493
|
credentialRankingMode,
|
|
500
494
|
});
|
|
501
|
-
|
|
495
|
+
try {
|
|
496
|
+
await storage.reload();
|
|
497
|
+
} catch (error) {
|
|
498
|
+
try {
|
|
499
|
+
storage.close();
|
|
500
|
+
} catch {
|
|
501
|
+
// Preserve the initial reload failure.
|
|
502
|
+
}
|
|
503
|
+
throw error;
|
|
504
|
+
}
|
|
502
505
|
return storage;
|
|
503
506
|
}
|
|
504
507
|
const dbPath = getAgentDbPath(agentDir);
|
|
@@ -507,7 +510,16 @@ export async function discoverAuthStorage(agentDir: string = getDefaultAgentDir(
|
|
|
507
510
|
sourceLabel: `local ${dbPath}`,
|
|
508
511
|
credentialRankingMode,
|
|
509
512
|
});
|
|
510
|
-
|
|
513
|
+
try {
|
|
514
|
+
await storage.reload();
|
|
515
|
+
} catch (error) {
|
|
516
|
+
try {
|
|
517
|
+
storage.close();
|
|
518
|
+
} catch {
|
|
519
|
+
// Preserve the initial reload failure.
|
|
520
|
+
}
|
|
521
|
+
throw error;
|
|
522
|
+
}
|
|
511
523
|
return storage;
|
|
512
524
|
}
|
|
513
525
|
|
|
@@ -629,9 +641,6 @@ function isCustomTool(tool: CustomTool | ToolDefinition): tool is CustomTool {
|
|
|
629
641
|
|
|
630
642
|
const TOOL_DEFINITION_MARKER = Symbol("__isToolDefinition");
|
|
631
643
|
|
|
632
|
-
/** Matches the truncation applied to per-server instructions inside `rebuildSystemPrompt`. */
|
|
633
|
-
const MAX_MCP_INSTRUCTIONS_LENGTH = 4000;
|
|
634
|
-
|
|
635
644
|
let sshCleanupRegistered = false;
|
|
636
645
|
|
|
637
646
|
async function cleanupSshResources(): Promise<void> {
|
|
@@ -976,6 +985,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
976
985
|
// Pin authStorage to modelRegistry.authStorage: ModelRegistry.getApiKey() routes refresh
|
|
977
986
|
// failures through that instance, so any divergent storage handed to the bridge / mcpManager
|
|
978
987
|
// / session would silently miss credential_disabled events.
|
|
988
|
+
const ownsAuthStorage = options.modelRegistry === undefined && options.authStorage === undefined;
|
|
979
989
|
const modelRegistry =
|
|
980
990
|
options.modelRegistry ??
|
|
981
991
|
new ModelRegistry(options.authStorage ?? (await logger.time("discoverModels", discoverAuthStorage, agentDir)));
|
|
@@ -985,409 +995,424 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
985
995
|
"options.authStorage and options.modelRegistry.authStorage must be the same instance when both are provided",
|
|
986
996
|
);
|
|
987
997
|
}
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
}
|
|
1002
|
-
let
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
998
|
+
let agent: Agent;
|
|
999
|
+
let session!: AgentSession;
|
|
1000
|
+
let hasSession = false;
|
|
1001
|
+
let hasRegistered = false;
|
|
1002
|
+
let cleanupOwnedMcpManager: (() => Promise<void>) | undefined;
|
|
1003
|
+
const agentRegistry = options.agentRegistry ?? AgentRegistry.global();
|
|
1004
|
+
const resolvedAgentId = options.agentId ?? options.parentTaskPrefix ?? MAIN_AGENT_ID;
|
|
1005
|
+
const resolvedAgentDisplayName = options.agentDisplayName ?? (isCanonicalSubSession ? "sub" : "main");
|
|
1006
|
+
const resolvedAgentRosterLabel = resolveAgentRosterLabel(
|
|
1007
|
+
options.agentRosterLabel,
|
|
1008
|
+
resolvedAgentId,
|
|
1009
|
+
resolvedAgentDisplayName,
|
|
1010
|
+
);
|
|
1011
|
+
const evalKernelOwnerId = `agent-session:${Snowflake.next()}`;
|
|
1012
|
+
let disposeLocalProtocolOverride: (() => void) | undefined;
|
|
1013
|
+
let localProtocolOverrideReleased = false;
|
|
1014
|
+
const releaseLocalProtocolOverride = (): void => {
|
|
1015
|
+
if (localProtocolOverrideReleased) return;
|
|
1016
|
+
localProtocolOverrideReleased = true;
|
|
1017
|
+
disposeLocalProtocolOverride?.();
|
|
1018
|
+
};
|
|
1019
|
+
const enableLsp = options.enableLsp ?? true;
|
|
1020
|
+
let authStorageClosed = false;
|
|
1021
|
+
const closeOwnedAuthStorage = (): void => {
|
|
1022
|
+
if (!ownsAuthStorage || authStorageClosed) return;
|
|
1023
|
+
authStorageClosed = true;
|
|
1024
|
+
authStorage.close();
|
|
1025
|
+
};
|
|
1026
|
+
let unsubscribeCredentialDisabled: (() => void) | undefined;
|
|
1027
|
+
const releaseCredentialDisabledSubscription = (): void => {
|
|
1028
|
+
const unsubscribe = unsubscribeCredentialDisabled;
|
|
1029
|
+
unsubscribeCredentialDisabled = undefined;
|
|
1030
|
+
unsubscribe?.();
|
|
1007
1031
|
};
|
|
1008
|
-
const earlyCredentialSelectorProvider = options.credentialSelector?.provider ?? options.model?.provider;
|
|
1009
|
-
if (earlyCredentialSelectorProvider) {
|
|
1010
|
-
installRuntimeCredentialSelector(earlyCredentialSelectorProvider);
|
|
1011
|
-
}
|
|
1012
|
-
const settings = options.settings ?? (await logger.time("settings", Settings.init, { cwd, agentDir }));
|
|
1013
|
-
modelRegistry.applyConfiguredModelBindings(settings);
|
|
1014
|
-
logger.time("initializeWithSettings", initializeWithSettings, settings);
|
|
1015
|
-
const canRefreshModelsBeforeCredentialSelector =
|
|
1016
|
-
!options.credentialSelector || runtimeCredentialSelectorInstalled || options.modelRegistry !== undefined;
|
|
1017
|
-
if (!options.modelRegistry && canRefreshModelsBeforeCredentialSelector) {
|
|
1018
|
-
modelRegistry.refreshInBackground();
|
|
1019
|
-
}
|
|
1020
|
-
// Kick off workspace tree discovery early. The native workspace scan returns
|
|
1021
|
-
// both the rendered-tree input and the AGENTS.md directory-context index, so
|
|
1022
|
-
// startup does not perform a second recursive filesystem search. Subagents
|
|
1023
|
-
// inherit the parent's resolved values via options.
|
|
1024
|
-
const STARTUP_SCAN_DEADLINE_MS = 5000;
|
|
1025
|
-
const workspaceTreePromise: Promise<WorkspaceTree> = options.workspaceTree
|
|
1026
|
-
? Promise.resolve(options.workspaceTree)
|
|
1027
|
-
: logger.time("buildWorkspaceTree", () => buildWorkspaceTree(cwd, { timeoutMs: STARTUP_SCAN_DEADLINE_MS }));
|
|
1028
|
-
workspaceTreePromise.catch(() => {});
|
|
1029
|
-
|
|
1030
|
-
// Independent discoveries that depend only on cwd/agentDir — kicked off in parallel and awaited
|
|
1031
|
-
// at their respective consumer sites. Their work can overlap with model resolution, secret loading,
|
|
1032
|
-
// session-context build, tool creation, MCP discovery, and extension discovery.
|
|
1033
|
-
const contextFilesPromise = options.contextFiles
|
|
1034
|
-
? Promise.resolve(options.contextFiles)
|
|
1035
|
-
: logger.time("discoverContextFiles", discoverContextFiles, cwd, agentDir);
|
|
1036
|
-
contextFilesPromise.catch(() => {});
|
|
1037
|
-
const promptTemplatesPromise = options.promptTemplates
|
|
1038
|
-
? Promise.resolve(options.promptTemplates)
|
|
1039
|
-
: logger.time("discoverPromptTemplates", discoverPromptTemplates, cwd, agentDir);
|
|
1040
|
-
promptTemplatesPromise.catch(() => {});
|
|
1041
|
-
const slashCommandsPromise = options.slashCommands ? Promise.resolve(options.slashCommands) : Promise.resolve([]);
|
|
1042
|
-
slashCommandsPromise.catch(() => {});
|
|
1043
|
-
|
|
1044
|
-
// Initialize provider preferences from settings
|
|
1045
|
-
const webSearchProvider = getConfiguredSearchProviderPreference(settings);
|
|
1046
|
-
setPreferredSearchProvider(webSearchProvider);
|
|
1047
|
-
const webSearchFallback = settings.get("web_search.fallback");
|
|
1048
|
-
if (Array.isArray(webSearchFallback)) {
|
|
1049
|
-
setSearchFallbackProviders(
|
|
1050
|
-
webSearchFallback.filter(value => typeof value === "string" && isConfigurableSearchProviderId(value)),
|
|
1051
|
-
);
|
|
1052
|
-
}
|
|
1053
|
-
applyConfiguredSearchTimeout(settings);
|
|
1054
|
-
|
|
1055
|
-
const imageProvider = settings.get("providers.image");
|
|
1056
|
-
if (
|
|
1057
|
-
imageProvider === "auto" ||
|
|
1058
|
-
imageProvider === "openai" ||
|
|
1059
|
-
imageProvider === "gemini" ||
|
|
1060
|
-
imageProvider === "openrouter" ||
|
|
1061
|
-
imageProvider === "antigravity"
|
|
1062
|
-
) {
|
|
1063
|
-
setPreferredImageProvider(imageProvider);
|
|
1064
|
-
}
|
|
1065
1032
|
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1033
|
+
try {
|
|
1034
|
+
// Subscribe before any getApiKey() call so startup model probes can't fire a
|
|
1035
|
+
// credential_disabled event past us. An embedder's constructor handler makes the
|
|
1036
|
+
// listener set non-empty from construction, which defeats AuthStorage's no-listener
|
|
1037
|
+
// buffer — so we can't rely on it to catch startup events for the extension runner.
|
|
1038
|
+
const startupCredentialDisabledEvents: CredentialDisabledEvent[] = [];
|
|
1039
|
+
let credentialDisabledTarget: ExtensionRunner | undefined;
|
|
1040
|
+
unsubscribeCredentialDisabled = authStorage.onCredentialDisabled(event => {
|
|
1041
|
+
if (credentialDisabledTarget) {
|
|
1042
|
+
// Discard return: any handler error is routed through runner.onError listeners.
|
|
1043
|
+
void credentialDisabledTarget.emitCredentialDisabled(event);
|
|
1044
|
+
} else {
|
|
1045
|
+
startupCredentialDisabledEvents.push(event);
|
|
1046
|
+
}
|
|
1047
|
+
});
|
|
1048
|
+
let runtimeCredentialSelectorInstalled = false;
|
|
1049
|
+
const installRuntimeCredentialSelector = (provider: string): void => {
|
|
1050
|
+
if (!options.credentialSelector || runtimeCredentialSelectorInstalled) return;
|
|
1051
|
+
authStorage.setRuntimeCredentialSelector(provider, options.credentialSelector.selector);
|
|
1052
|
+
runtimeCredentialSelectorInstalled = true;
|
|
1053
|
+
};
|
|
1054
|
+
const earlyCredentialSelectorProvider = options.credentialSelector?.provider ?? options.model?.provider;
|
|
1055
|
+
if (earlyCredentialSelectorProvider) {
|
|
1056
|
+
installRuntimeCredentialSelector(earlyCredentialSelectorProvider);
|
|
1081
1057
|
}
|
|
1058
|
+
const settings = options.settings ?? (await logger.time("settings", Settings.init, { cwd, agentDir }));
|
|
1059
|
+
modelRegistry.applyConfiguredModelBindings(settings);
|
|
1060
|
+
logger.time("initializeWithSettings", initializeWithSettings, settings);
|
|
1061
|
+
const canRefreshModelsBeforeCredentialSelector =
|
|
1062
|
+
!options.credentialSelector || runtimeCredentialSelectorInstalled || options.modelRegistry !== undefined;
|
|
1063
|
+
if (!options.modelRegistry && canRefreshModelsBeforeCredentialSelector) {
|
|
1064
|
+
modelRegistry.refreshInBackground();
|
|
1065
|
+
}
|
|
1066
|
+
// Kick off workspace tree discovery early. The native workspace scan returns
|
|
1067
|
+
// both the rendered-tree input and the AGENTS.md directory-context index, so
|
|
1068
|
+
// startup does not perform a second recursive filesystem search. Subagents
|
|
1069
|
+
// inherit the parent's resolved values via options.
|
|
1070
|
+
const STARTUP_SCAN_DEADLINE_MS = 5000;
|
|
1071
|
+
const workspaceTreePromise: Promise<WorkspaceTree> = options.workspaceTree
|
|
1072
|
+
? Promise.resolve(options.workspaceTree)
|
|
1073
|
+
: logger.time("buildWorkspaceTree", () => buildWorkspaceTree(cwd, { timeoutMs: STARTUP_SCAN_DEADLINE_MS }));
|
|
1074
|
+
workspaceTreePromise.catch(() => {});
|
|
1075
|
+
|
|
1076
|
+
// Independent discoveries that depend only on cwd/agentDir — kicked off in parallel and awaited
|
|
1077
|
+
// at their respective consumer sites. Their work can overlap with model resolution, secret loading,
|
|
1078
|
+
// session-context build, tool creation, MCP discovery, and extension discovery.
|
|
1079
|
+
const contextFilesPromise = options.contextFiles
|
|
1080
|
+
? Promise.resolve(options.contextFiles)
|
|
1081
|
+
: logger.time("discoverContextFiles", discoverContextFiles, cwd, agentDir);
|
|
1082
|
+
contextFilesPromise.catch(() => {});
|
|
1083
|
+
const promptTemplatesPromise = options.promptTemplates
|
|
1084
|
+
? Promise.resolve(options.promptTemplates)
|
|
1085
|
+
: logger.time("discoverPromptTemplates", discoverPromptTemplates, cwd, agentDir);
|
|
1086
|
+
promptTemplatesPromise.catch(() => {});
|
|
1087
|
+
const slashCommandsPromise = options.slashCommands ? Promise.resolve(options.slashCommands) : Promise.resolve([]);
|
|
1088
|
+
slashCommandsPromise.catch(() => {});
|
|
1089
|
+
|
|
1090
|
+
// Initialize provider preferences from settings
|
|
1091
|
+
const webSearchProvider = getConfiguredSearchProviderPreference(settings);
|
|
1092
|
+
setPreferredSearchProvider(webSearchProvider);
|
|
1093
|
+
const webSearchFallback = settings.get("web_search.fallback");
|
|
1094
|
+
if (Array.isArray(webSearchFallback)) {
|
|
1095
|
+
setSearchFallbackProviders(
|
|
1096
|
+
webSearchFallback.filter(value => typeof value === "string" && isConfigurableSearchProviderId(value)),
|
|
1097
|
+
);
|
|
1098
|
+
}
|
|
1099
|
+
applyConfiguredSearchTimeout(settings);
|
|
1082
1100
|
|
|
1083
|
-
const
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
return false;
|
|
1101
|
+
const imageProvider = settings.get("providers.image");
|
|
1102
|
+
if (
|
|
1103
|
+
imageProvider === "auto" ||
|
|
1104
|
+
imageProvider === "openai" ||
|
|
1105
|
+
imageProvider === "gemini" ||
|
|
1106
|
+
imageProvider === "openrouter" ||
|
|
1107
|
+
imageProvider === "antigravity"
|
|
1108
|
+
) {
|
|
1109
|
+
setPreferredImageProvider(imageProvider);
|
|
1093
1110
|
}
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1111
|
+
|
|
1112
|
+
const sessionManager =
|
|
1113
|
+
options.sessionManager ??
|
|
1114
|
+
(await logger.time("sessionManager", async () => {
|
|
1115
|
+
const sessionDir = SessionManager.getDefaultSessionDir(cwd, agentDir);
|
|
1116
|
+
return SessionManager.create(cwd, sessionDir);
|
|
1117
|
+
}));
|
|
1118
|
+
const logicalSessionId = sessionManager.getSessionId();
|
|
1119
|
+
const providerSessionId = options.providerSessionId ?? options.forkContextSeed?.cacheIdentity ?? logicalSessionId;
|
|
1120
|
+
const modelApiKeyAvailability = new Map<string, boolean>();
|
|
1121
|
+
const getModelAvailabilityKey = (candidate: Model): string =>
|
|
1122
|
+
`${candidate.provider}\u0000${candidate.baseUrl ?? ""}`;
|
|
1123
|
+
const hasModelApiKey = async (candidate: Model): Promise<boolean> => {
|
|
1124
|
+
const availabilityKey = getModelAvailabilityKey(candidate);
|
|
1125
|
+
const cached = modelApiKeyAvailability.get(availabilityKey);
|
|
1126
|
+
if (cached !== undefined) {
|
|
1127
|
+
return cached;
|
|
1102
1128
|
}
|
|
1103
|
-
throw error;
|
|
1104
|
-
});
|
|
1105
|
-
const hasKey = Boolean(key) && (!credentialSelector || key !== kNoAuth);
|
|
1106
|
-
modelApiKeyAvailability.set(availabilityKey, hasKey);
|
|
1107
|
-
return hasKey;
|
|
1108
|
-
};
|
|
1109
1129
|
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1130
|
+
const credentialSelector =
|
|
1131
|
+
options.credentialSelector && !runtimeCredentialSelectorInstalled
|
|
1132
|
+
? options.credentialSelector.provider === undefined ||
|
|
1133
|
+
options.credentialSelector.provider === candidate.provider
|
|
1134
|
+
? options.credentialSelector.selector
|
|
1135
|
+
: undefined
|
|
1136
|
+
: undefined;
|
|
1137
|
+
if (options.credentialSelector?.provider && options.credentialSelector.provider !== candidate.provider) {
|
|
1138
|
+
modelApiKeyAvailability.set(availabilityKey, false);
|
|
1139
|
+
return false;
|
|
1140
|
+
}
|
|
1141
|
+
const key = await modelRegistry
|
|
1142
|
+
.getApiKey(candidate, providerSessionId, { credentialSelector })
|
|
1143
|
+
.catch(error => {
|
|
1144
|
+
if (credentialSelector) {
|
|
1145
|
+
logger.debug("Credential selector did not match model availability candidate", {
|
|
1146
|
+
provider: candidate.provider,
|
|
1147
|
+
model: candidate.id,
|
|
1148
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1149
|
+
});
|
|
1150
|
+
return undefined;
|
|
1151
|
+
}
|
|
1152
|
+
throw error;
|
|
1153
|
+
});
|
|
1154
|
+
const hasKey = Boolean(key) && (!credentialSelector || key !== kNoAuth);
|
|
1155
|
+
modelApiKeyAvailability.set(availabilityKey, hasKey);
|
|
1156
|
+
return hasKey;
|
|
1157
|
+
};
|
|
1158
|
+
|
|
1159
|
+
// Load and create secret obfuscator early so resumed session state and prompt warnings
|
|
1160
|
+
// reflect actual loaded secrets, not just the setting toggle.
|
|
1161
|
+
let obfuscator: SecretObfuscator | undefined;
|
|
1162
|
+
if (settings.get("secrets.enabled")) {
|
|
1163
|
+
const fileEntries = await logger.time("loadSecrets", loadSecrets, cwd, agentDir);
|
|
1164
|
+
const envEntries = collectEnvSecrets();
|
|
1165
|
+
const allEntries = [...envEntries, ...fileEntries];
|
|
1166
|
+
if (allEntries.length > 0) {
|
|
1167
|
+
obfuscator = new SecretObfuscator(allEntries);
|
|
1168
|
+
}
|
|
1119
1169
|
}
|
|
1120
|
-
|
|
1121
|
-
const secretsEnabled = obfuscator?.hasSecrets() === true;
|
|
1170
|
+
const secretsEnabled = obfuscator?.hasSecrets() === true;
|
|
1122
1171
|
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
settings,
|
|
1142
|
-
matchPreferences: modelMatchPreferences,
|
|
1143
|
-
modelRegistry,
|
|
1144
|
-
}),
|
|
1145
|
-
);
|
|
1146
|
-
let model = options.model;
|
|
1147
|
-
let modelFallbackMessage: string | undefined;
|
|
1148
|
-
const persistedDefaultChain = existingSession.configuredModelChains.default?.entries;
|
|
1149
|
-
const defaultModelEntries =
|
|
1150
|
-
persistedDefaultChain && persistedDefaultChain.length > 0
|
|
1151
|
-
? persistedDefaultChain
|
|
1152
|
-
: existingSession.models.default
|
|
1153
|
-
? [existingSession.models.default]
|
|
1154
|
-
: [];
|
|
1155
|
-
// If session has data, restore its configured default chain rather than the
|
|
1156
|
-
// scalar runtime model, which may be a stale fallback from the prior run.
|
|
1157
|
-
if (!hasExplicitModel && !model && hasExistingSession && defaultModelEntries.length > 0) {
|
|
1158
|
-
await logger.time("restoreSessionModel", async () => {
|
|
1159
|
-
const restoredDefaultResolution = await resolveModelChainWithAuth(
|
|
1160
|
-
defaultModelEntries,
|
|
1161
|
-
modelRegistry,
|
|
1172
|
+
// Check if session has existing data to restore
|
|
1173
|
+
const existingSession = logger.time("loadSessionContext", () =>
|
|
1174
|
+
deobfuscateSessionContext(sessionManager.buildSessionContext(), obfuscator),
|
|
1175
|
+
);
|
|
1176
|
+
const existingBranch = logger.time("getSessionBranch", () => sessionManager.getBranch());
|
|
1177
|
+
const hasExistingSession = existingBranch.length > 0;
|
|
1178
|
+
const hasThinkingEntry = existingBranch.some(entry => entry.type === "thinking_level_change");
|
|
1179
|
+
const hasServiceTierEntry = existingBranch.some(entry => entry.type === "service_tier_change");
|
|
1180
|
+
|
|
1181
|
+
const hasExplicitModel = options.model !== undefined || options.modelPattern !== undefined;
|
|
1182
|
+
const modelMatchPreferences = {
|
|
1183
|
+
usageOrder: settings.getStorage()?.getModelUsageOrder(),
|
|
1184
|
+
};
|
|
1185
|
+
const allowedModels = await logger.time("resolveAllowedModels", () =>
|
|
1186
|
+
resolveAllowedModels(modelRegistry, settings, modelMatchPreferences),
|
|
1187
|
+
);
|
|
1188
|
+
const defaultRoleSpec = logger.time("resolveDefaultModelRole", () =>
|
|
1189
|
+
resolveModelRoleValue(settings.getModelRole("default"), allowedModels, {
|
|
1162
1190
|
settings,
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
)
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1191
|
+
matchPreferences: modelMatchPreferences,
|
|
1192
|
+
modelRegistry,
|
|
1193
|
+
}),
|
|
1194
|
+
);
|
|
1195
|
+
let model = options.model;
|
|
1196
|
+
let modelFallbackMessage: string | undefined;
|
|
1197
|
+
const persistedDefaultChain = existingSession.configuredModelChains.default?.entries;
|
|
1198
|
+
const defaultModelEntries =
|
|
1199
|
+
persistedDefaultChain && persistedDefaultChain.length > 0
|
|
1200
|
+
? persistedDefaultChain
|
|
1201
|
+
: existingSession.models.default
|
|
1202
|
+
? [existingSession.models.default]
|
|
1203
|
+
: [];
|
|
1204
|
+
// If session has data, restore its configured default chain rather than the
|
|
1205
|
+
// scalar runtime model, which may be a stale fallback from the prior run.
|
|
1206
|
+
if (!hasExplicitModel && !model && hasExistingSession && defaultModelEntries.length > 0) {
|
|
1207
|
+
await logger.time("restoreSessionModel", async () => {
|
|
1208
|
+
const restoredDefaultResolution = await resolveModelChainWithAuth(
|
|
1209
|
+
defaultModelEntries,
|
|
1210
|
+
modelRegistry,
|
|
1211
|
+
settings,
|
|
1212
|
+
providerSessionId,
|
|
1213
|
+
{ managedFallback: defaultModelEntries.length > 1 },
|
|
1214
|
+
);
|
|
1215
|
+
model = restoredDefaultResolution.model;
|
|
1216
|
+
if (!model) modelFallbackMessage = `Could not restore model ${defaultModelEntries.join(" -> ")}`;
|
|
1217
|
+
});
|
|
1218
|
+
}
|
|
1183
1219
|
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1220
|
+
// If still no model, try settings default.
|
|
1221
|
+
// Skip settings fallback when an explicit model was requested.
|
|
1222
|
+
if (!hasExplicitModel && !model && defaultRoleSpec.model) {
|
|
1223
|
+
const settingsDefaultModel = defaultRoleSpec.model;
|
|
1224
|
+
logger.time("resolveSettingsDefaultModel", () => {
|
|
1225
|
+
// defaultRoleSpec.model already comes from modelRegistry.getAvailable(),
|
|
1226
|
+
// so re-validating auth here just repeats the expensive lookup path.
|
|
1227
|
+
model = settingsDefaultModel;
|
|
1228
|
+
});
|
|
1229
|
+
}
|
|
1187
1230
|
|
|
1188
|
-
|
|
1189
|
-
// override. A persisted inherit marker deliberately re-enters the normal
|
|
1190
|
-
// default-role/global/model resolution path instead of resolving to `undefined`.
|
|
1191
|
-
const restoredThinkingLevel =
|
|
1192
|
-
hasExistingSession && hasThinkingEntry ? parseThinkingLevel(existingSession.thinkingLevel) : undefined;
|
|
1193
|
-
if (thinkingLevel === undefined && restoredThinkingLevel !== ThinkingLevel.Inherit) {
|
|
1194
|
-
thinkingLevel = restoredThinkingLevel;
|
|
1195
|
-
}
|
|
1231
|
+
const taskDepth = options.taskDepth ?? 0;
|
|
1196
1232
|
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1233
|
+
let thinkingLevel = options.thinkingLevel;
|
|
1234
|
+
const hasExplicitDefaultThinkingLevel = settings.has("defaultThinkingLevel");
|
|
1235
|
+
let thinkingLevelFromSchemaDefault = false;
|
|
1200
1236
|
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1237
|
+
// If session has data and includes a thinking entry, restore an explicit session
|
|
1238
|
+
// override. A persisted inherit marker deliberately re-enters the normal
|
|
1239
|
+
// default-role/global/model resolution path instead of resolving to `undefined`.
|
|
1240
|
+
const restoredThinkingLevel =
|
|
1241
|
+
hasExistingSession && hasThinkingEntry ? parseThinkingLevel(existingSession.thinkingLevel) : undefined;
|
|
1242
|
+
if (thinkingLevel === undefined && restoredThinkingLevel !== ThinkingLevel.Inherit) {
|
|
1243
|
+
thinkingLevel = restoredThinkingLevel;
|
|
1244
|
+
}
|
|
1207
1245
|
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1246
|
+
if (thinkingLevel === undefined && !hasExplicitModel && defaultRoleSpec.explicitThinkingLevel) {
|
|
1247
|
+
thinkingLevel = defaultRoleSpec.thinkingLevel;
|
|
1248
|
+
}
|
|
1211
1249
|
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
thinkingLevel = logger.time("resolveThinkingLevelForModel", () =>
|
|
1219
|
-
resolveThinkingLevelForModel(resolvedModel, thinkingLevel),
|
|
1220
|
-
);
|
|
1221
|
-
// Fire-and-forget TLS+H2 handshake to the model's host so it overlaps
|
|
1222
|
-
// with the rest of session setup (extension/skill load, tool registry,
|
|
1223
|
-
// system prompt build). Without this, the first `fetch(...)` pays the
|
|
1224
|
-
// full handshake serially — 100–300 ms transcontinental for
|
|
1225
|
-
// api.anthropic.com from a residential IP. Every session frontend benefits
|
|
1226
|
-
// (interactive, print, SDK, ACP).
|
|
1227
|
-
preconnectModelHost(model.baseUrl);
|
|
1228
|
-
}
|
|
1250
|
+
// An explicit user/project default should win over the model's bundled
|
|
1251
|
+
// defaultLevel. The schema default is only a final fallback so model metadata
|
|
1252
|
+
// can keep driving first-run behavior until the user chooses "Set as default".
|
|
1253
|
+
if (thinkingLevel === undefined && hasExplicitDefaultThinkingLevel) {
|
|
1254
|
+
thinkingLevel = settings.get("defaultThinkingLevel");
|
|
1255
|
+
}
|
|
1229
1256
|
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
// The four public GJC workflow skills are a product invariant, not
|
|
1234
|
-
// ordinary filesystem-discovered skills. Keep them available even for
|
|
1235
|
-
// explicit SDK skill lists so startup and command routing survive
|
|
1236
|
-
// accidental `.gjc` deletion or overzealous caller filtering.
|
|
1237
|
-
skills = withEmbeddedDefaultGjcSkills(options.skills);
|
|
1238
|
-
skillWarnings = [];
|
|
1239
|
-
} else if (settings.get("skills.enabled")) {
|
|
1240
|
-
const skillsResult = await logger.time("loadSkills", loadSkills, {
|
|
1241
|
-
...settings.getGroup("skills"),
|
|
1242
|
-
cwd,
|
|
1243
|
-
disabledExtensions: settings.get("disabledExtensions"),
|
|
1244
|
-
});
|
|
1245
|
-
skills = withEmbeddedDefaultGjcSkills(skillsResult.skills);
|
|
1246
|
-
skillWarnings = skillsResult.warnings;
|
|
1247
|
-
} else {
|
|
1248
|
-
// GJC's four public workflow skills are bundled into the binary so the
|
|
1249
|
-
// default workflow surface survives accidental .gjc deletion. Arbitrary
|
|
1250
|
-
// filesystem skill discovery remains gated by skills.enabled above.
|
|
1251
|
-
skills = getEmbeddedDefaultGjcSkills();
|
|
1252
|
-
skillWarnings = [];
|
|
1253
|
-
}
|
|
1257
|
+
if (thinkingLevel === undefined && model?.thinking?.defaultLevel !== undefined) {
|
|
1258
|
+
thinkingLevel = model.thinking.defaultLevel;
|
|
1259
|
+
}
|
|
1254
1260
|
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
const ttsrManager = new TtsrManager(ttsrSettings);
|
|
1259
|
-
const rulesResult =
|
|
1260
|
-
options.rules !== undefined
|
|
1261
|
-
? { items: options.rules, warnings: undefined }
|
|
1262
|
-
: await loadCapability<Rule>(ruleCapability.id, { cwd });
|
|
1263
|
-
const rulebookRules: Rule[] = [];
|
|
1264
|
-
const alwaysApplyRules: Rule[] = [];
|
|
1265
|
-
for (const rule of rulesResult.items) {
|
|
1266
|
-
const isTtsrRule = rule.condition && rule.condition.length > 0 ? ttsrManager.addRule(rule) : false;
|
|
1267
|
-
if (isTtsrRule) {
|
|
1268
|
-
continue;
|
|
1269
|
-
}
|
|
1270
|
-
if (rule.alwaysApply === true) {
|
|
1271
|
-
alwaysApplyRules.push(rule);
|
|
1272
|
-
continue;
|
|
1273
|
-
}
|
|
1274
|
-
if (rule.description) {
|
|
1275
|
-
rulebookRules.push(rule);
|
|
1276
|
-
}
|
|
1261
|
+
if (thinkingLevel === undefined) {
|
|
1262
|
+
thinkingLevel = settings.get("defaultThinkingLevel");
|
|
1263
|
+
thinkingLevelFromSchemaDefault = true;
|
|
1277
1264
|
}
|
|
1278
|
-
if (
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1265
|
+
if (model) {
|
|
1266
|
+
const resolvedModel = model;
|
|
1267
|
+
thinkingLevel = logger.time("resolveThinkingLevelForModel", () =>
|
|
1268
|
+
resolveThinkingLevelForModel(resolvedModel, thinkingLevel),
|
|
1269
|
+
);
|
|
1270
|
+
// Fire-and-forget TLS+H2 handshake to the model's host so it overlaps
|
|
1271
|
+
// with the rest of session setup (extension/skill load, tool registry,
|
|
1272
|
+
// system prompt build). Without this, the first `fetch(...)` pays the
|
|
1273
|
+
// full handshake serially — 100–300 ms transcontinental for
|
|
1274
|
+
// api.anthropic.com from a residential IP. Every session frontend benefits
|
|
1275
|
+
// (interactive, print, SDK, ACP).
|
|
1276
|
+
preconnectModelHost(model.baseUrl);
|
|
1287
1277
|
}
|
|
1288
|
-
return { ttsrManager, rulebookRules, alwaysApplyRules };
|
|
1289
|
-
});
|
|
1290
1278
|
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
}),
|
|
1304
|
-
]);
|
|
1305
|
-
if (timedOut) {
|
|
1306
|
-
logger.warn("Startup scan exceeded deadline; deferring to system prompt fallback", {
|
|
1307
|
-
name,
|
|
1308
|
-
timeoutMs: STARTUP_SCAN_DEADLINE_MS,
|
|
1279
|
+
let skills: Skill[];
|
|
1280
|
+
let skillWarnings: SkillWarning[];
|
|
1281
|
+
if (options.skills !== undefined) {
|
|
1282
|
+
// The four public GJC workflow skills are a product invariant, not
|
|
1283
|
+
// ordinary filesystem-discovered skills. Keep them available even for
|
|
1284
|
+
// explicit SDK skill lists so startup and command routing survive
|
|
1285
|
+
// accidental `.gjc` deletion or overzealous caller filtering.
|
|
1286
|
+
skills = withEmbeddedDefaultGjcSkills(options.skills);
|
|
1287
|
+
skillWarnings = [];
|
|
1288
|
+
} else if (settings.get("skills.enabled")) {
|
|
1289
|
+
const skillsResult = await logger.time("loadSkills", loadSkills, {
|
|
1290
|
+
...settings.getGroup("skills"),
|
|
1309
1291
|
cwd,
|
|
1292
|
+
disabledExtensions: settings.get("disabledExtensions"),
|
|
1310
1293
|
});
|
|
1294
|
+
skills = withEmbeddedDefaultGjcSkills(skillsResult.skills);
|
|
1295
|
+
skillWarnings = skillsResult.warnings;
|
|
1296
|
+
} else {
|
|
1297
|
+
// GJC's four public workflow skills are bundled into the binary so the
|
|
1298
|
+
// default workflow surface survives accidental .gjc deletion. Arbitrary
|
|
1299
|
+
// filesystem skill discovery remains gated by skills.enabled above.
|
|
1300
|
+
skills = getEmbeddedDefaultGjcSkills();
|
|
1301
|
+
skillWarnings = [];
|
|
1311
1302
|
}
|
|
1312
|
-
return result;
|
|
1313
|
-
};
|
|
1314
|
-
const [contextFiles, resolvedWorkspaceTree] = await Promise.all([
|
|
1315
|
-
contextFilesPromise,
|
|
1316
|
-
raceWithDeadline("buildWorkspaceTree", workspaceTreePromise),
|
|
1317
|
-
]);
|
|
1318
1303
|
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1304
|
+
// Discover rules and bucket them in one pass to avoid repeated scans over large rule sets.
|
|
1305
|
+
const { ttsrManager, rulebookRules, alwaysApplyRules } = await logger.time("discoverTtsrRules", async () => {
|
|
1306
|
+
const ttsrSettings = settings.getGroup("ttsr");
|
|
1307
|
+
const ttsrManager = new TtsrManager(ttsrSettings);
|
|
1308
|
+
const rulesResult =
|
|
1309
|
+
options.rules !== undefined
|
|
1310
|
+
? { items: options.rules, warnings: undefined }
|
|
1311
|
+
: await loadCapability<Rule>(ruleCapability.id, { cwd });
|
|
1312
|
+
const rulebookRules: Rule[] = [];
|
|
1313
|
+
const alwaysApplyRules: Rule[] = [];
|
|
1314
|
+
for (const rule of rulesResult.items) {
|
|
1315
|
+
const isTtsrRule = rule.condition && rule.condition.length > 0 ? ttsrManager.addRule(rule) : false;
|
|
1316
|
+
if (isTtsrRule) {
|
|
1317
|
+
continue;
|
|
1318
|
+
}
|
|
1319
|
+
if (rule.alwaysApply === true) {
|
|
1320
|
+
alwaysApplyRules.push(rule);
|
|
1321
|
+
continue;
|
|
1322
|
+
}
|
|
1323
|
+
if (rule.description) {
|
|
1324
|
+
rulebookRules.push(rule);
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
if (ttsrManager.getSettings().enabled !== false) {
|
|
1328
|
+
if ((existingSession.ttsrMessageCount ?? 0) > 0) {
|
|
1329
|
+
ttsrManager.restoreMessageCount(existingSession.ttsrMessageCount ?? 0);
|
|
1330
|
+
}
|
|
1331
|
+
if (existingSession.injectedTtsrRuleRecords && existingSession.injectedTtsrRuleRecords.length > 0) {
|
|
1332
|
+
ttsrManager.restoreInjected(existingSession.injectedTtsrRuleRecords);
|
|
1333
|
+
} else if (existingSession.injectedTtsrRules.length > 0) {
|
|
1334
|
+
ttsrManager.restoreInjected(existingSession.injectedTtsrRules);
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
return { ttsrManager, rulebookRules, alwaysApplyRules };
|
|
1338
|
+
});
|
|
1339
|
+
|
|
1340
|
+
// Resolve contextFiles up-front (it's needed before tool creation). The
|
|
1341
|
+
// workspace tree scan is slow on large repos and we MUST NOT block startup on
|
|
1342
|
+
// it. On timeout we forward `undefined` to ToolSession; buildSystemPromptInternal
|
|
1343
|
+
// will re-race the same promise through its own withDeadline path. Background
|
|
1344
|
+
// work continues so caches still warm.
|
|
1345
|
+
const raceWithDeadline = async <T>(name: string, work: Promise<T>): Promise<T | undefined> => {
|
|
1346
|
+
let timedOut = false;
|
|
1347
|
+
const result = await Promise.race([
|
|
1348
|
+
work,
|
|
1349
|
+
Bun.sleep(STARTUP_SCAN_DEADLINE_MS).then(() => {
|
|
1350
|
+
timedOut = true;
|
|
1351
|
+
return undefined;
|
|
1352
|
+
}),
|
|
1353
|
+
]);
|
|
1354
|
+
if (timedOut) {
|
|
1355
|
+
logger.warn("Startup scan exceeded deadline; deferring to system prompt fallback", {
|
|
1356
|
+
name,
|
|
1357
|
+
timeoutMs: STARTUP_SCAN_DEADLINE_MS,
|
|
1358
|
+
cwd,
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
1331
1361
|
return result;
|
|
1332
|
-
}
|
|
1362
|
+
};
|
|
1363
|
+
const [contextFiles, resolvedWorkspaceTree] = await Promise.all([
|
|
1364
|
+
contextFilesPromise,
|
|
1365
|
+
raceWithDeadline("buildWorkspaceTree", workspaceTreePromise),
|
|
1366
|
+
]);
|
|
1333
1367
|
|
|
1334
|
-
const
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1368
|
+
const backgroundJobsEnabled = isBackgroundJobSupportEnabled(settings);
|
|
1369
|
+
const asyncMaxJobs = Math.min(100, Math.max(1, settings.get("async.maxJobs") ?? 100));
|
|
1370
|
+
const ASYNC_INLINE_RESULT_MAX_CHARS = 12_000;
|
|
1371
|
+
const ASYNC_PREVIEW_MAX_CHARS = 4_000;
|
|
1372
|
+
const formatAsyncResultForFollowUp = async (result: string): Promise<string> => {
|
|
1373
|
+
if (result.length <= ASYNC_INLINE_RESULT_MAX_CHARS) {
|
|
1374
|
+
return result;
|
|
1340
1375
|
}
|
|
1341
|
-
} catch (error) {
|
|
1342
|
-
logger.warn("Failed to persist async follow-up artifact", {
|
|
1343
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1344
|
-
});
|
|
1345
|
-
}
|
|
1346
1376
|
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
const formattedResult = await formatAsyncResultForFollowUp(result);
|
|
1360
|
-
if (asyncJobManager!.isDeliverySuppressed(jobId)) return;
|
|
1361
|
-
|
|
1362
|
-
const durationMs = job ? jobElapsedMs(job) : undefined;
|
|
1363
|
-
session.yieldQueue.enqueue<AsyncResultEntry>("async-result", {
|
|
1364
|
-
jobId,
|
|
1365
|
-
result: formattedResult,
|
|
1366
|
-
job,
|
|
1367
|
-
durationMs,
|
|
1368
|
-
});
|
|
1369
|
-
},
|
|
1370
|
-
})
|
|
1371
|
-
: undefined;
|
|
1377
|
+
const preview = `${result.slice(0, ASYNC_PREVIEW_MAX_CHARS)}\n\n[Output truncated. Showing first ${ASYNC_PREVIEW_MAX_CHARS.toLocaleString()} characters.]`;
|
|
1378
|
+
try {
|
|
1379
|
+
const { path: artifactPath, id: artifactId } = await sessionManager.allocateArtifactPath("async");
|
|
1380
|
+
if (artifactPath && artifactId) {
|
|
1381
|
+
await Bun.write(artifactPath, result);
|
|
1382
|
+
return `${preview}\nFull output: artifact://${artifactId}`;
|
|
1383
|
+
}
|
|
1384
|
+
} catch (error) {
|
|
1385
|
+
logger.warn("Failed to persist async follow-up artifact", {
|
|
1386
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1387
|
+
});
|
|
1388
|
+
}
|
|
1372
1389
|
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1390
|
+
return preview;
|
|
1391
|
+
};
|
|
1392
|
+
// Only top-level sessions own an AsyncJobManager. Subagents reach the
|
|
1393
|
+
// parent's manager via `AsyncJobManager.instance()` (set below), so creating
|
|
1394
|
+
// a second instance here just to leave it orphaned wastes a constructor and
|
|
1395
|
+
// risks accidental disposal of the parent's manager on subagent teardown.
|
|
1396
|
+
const asyncJobManager =
|
|
1397
|
+
backgroundJobsEnabled && !options.parentTaskPrefix
|
|
1398
|
+
? new AsyncJobManager({
|
|
1399
|
+
maxRunningJobs: asyncMaxJobs,
|
|
1400
|
+
onJobComplete: async (jobId, result, job) => {
|
|
1401
|
+
if (!session || asyncJobManager!.isDeliverySuppressed(jobId)) return;
|
|
1402
|
+
const formattedResult = await formatAsyncResultForFollowUp(result);
|
|
1403
|
+
if (asyncJobManager!.isDeliverySuppressed(jobId)) return;
|
|
1404
|
+
|
|
1405
|
+
const durationMs = job ? jobElapsedMs(job) : undefined;
|
|
1406
|
+
session.yieldQueue.enqueue<AsyncResultEntry>("async-result", {
|
|
1407
|
+
jobId,
|
|
1408
|
+
result: formattedResult,
|
|
1409
|
+
job,
|
|
1410
|
+
durationMs,
|
|
1411
|
+
});
|
|
1412
|
+
},
|
|
1413
|
+
})
|
|
1414
|
+
: undefined;
|
|
1389
1415
|
|
|
1390
|
-
try {
|
|
1391
1416
|
let promptMetadataModel: Model | undefined;
|
|
1392
1417
|
const getActiveModelString = (): string | undefined => {
|
|
1393
1418
|
const activeModel = promptMetadataModel ?? agent?.state.model;
|
|
@@ -1454,11 +1479,6 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1454
1479
|
getCompactContext: () => session.formatCompactContext(),
|
|
1455
1480
|
getTodoPhases: () => session.getTodoPhases(),
|
|
1456
1481
|
setTodoPhases: phases => session.setTodoPhases(phases),
|
|
1457
|
-
isMCPDiscoveryEnabled: () => session.isMCPDiscoveryEnabled(),
|
|
1458
|
-
getDiscoverableMCPTools: () => session.getDiscoverableMCPTools(),
|
|
1459
|
-
getDiscoverableMCPSearchIndex: () => session.getDiscoverableMCPSearchIndex(),
|
|
1460
|
-
getSelectedMCPToolNames: () => session.getSelectedMCPToolNames(),
|
|
1461
|
-
activateDiscoveredMCPTools: toolNames => session.activateDiscoveredMCPTools(toolNames),
|
|
1462
1482
|
// Generic tool discovery (unified — covers built-in + MCP + extension)
|
|
1463
1483
|
isToolDiscoveryEnabled: () => session.isToolDiscoveryEnabled(),
|
|
1464
1484
|
getDiscoverableTools: filter => session.getDiscoverableTools(filter),
|
|
@@ -1754,6 +1774,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1754
1774
|
settings,
|
|
1755
1775
|
controller: notificationSessionController,
|
|
1756
1776
|
spawnedByGjc,
|
|
1777
|
+
runEphemeralTurn: async (promptText, signal) => {
|
|
1778
|
+
if (!session) throw new Error("Ephemeral turns are unavailable.");
|
|
1779
|
+
const { replyText } = await session.runEphemeralTurn({ promptText, signal });
|
|
1780
|
+
return { replyText };
|
|
1781
|
+
},
|
|
1757
1782
|
});
|
|
1758
1783
|
} catch (error) {
|
|
1759
1784
|
lifecycleStartupCapability?.settleFailure(
|
|
@@ -1904,12 +1929,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1904
1929
|
// No runner to forward to; release our subscription. The embedder's own
|
|
1905
1930
|
// onCredentialDisabled (if any) keeps firing through its own subscription.
|
|
1906
1931
|
startupCredentialDisabledEvents.length = 0;
|
|
1907
|
-
|
|
1908
|
-
unsubscribeCredentialDisabled = undefined;
|
|
1932
|
+
releaseCredentialDisabledSubscription();
|
|
1909
1933
|
}
|
|
1910
1934
|
|
|
1911
1935
|
const getSessionContext = () => ({
|
|
1912
|
-
sessionManager,
|
|
1936
|
+
sessionManager: createReadonlySessionManager(sessionManager),
|
|
1913
1937
|
modelRegistry,
|
|
1914
1938
|
model: agent.state.model,
|
|
1915
1939
|
isIdle: () => !session.isStreaming,
|
|
@@ -1938,7 +1962,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1938
1962
|
// Without extension runner: wrap CustomTools directly with CustomToolAdapter
|
|
1939
1963
|
// ToolDefinition items require ExtensionContext and cannot be used without a runner
|
|
1940
1964
|
const customToolContext = (): CustomToolContext => ({
|
|
1941
|
-
sessionManager,
|
|
1965
|
+
sessionManager: createReadonlySessionManager(sessionManager),
|
|
1942
1966
|
modelRegistry,
|
|
1943
1967
|
model: agent?.state.model,
|
|
1944
1968
|
isIdle: () => !session?.isStreaming,
|
|
@@ -2040,36 +2064,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2040
2064
|
candidateModel?: Model,
|
|
2041
2065
|
): Promise<BuildSystemPromptResult> => {
|
|
2042
2066
|
toolContextStore.setToolNames(toolNames);
|
|
2043
|
-
const
|
|
2067
|
+
const promptTools = (() => {
|
|
2044
2068
|
const previousPromptMetadataModel = promptMetadataModel;
|
|
2045
2069
|
promptMetadataModel = candidateModel;
|
|
2046
2070
|
try {
|
|
2047
|
-
|
|
2048
|
-
const discoverableBuiltinTools: DiscoverableTool[] =
|
|
2049
|
-
effectiveDiscoveryMode === "all"
|
|
2050
|
-
? collectDiscoverableTools(
|
|
2051
|
-
Array.from(tools.values()).filter(
|
|
2052
|
-
tool => tool.loadMode === "discoverable" && !activeToolNames.has(tool.name),
|
|
2053
|
-
),
|
|
2054
|
-
{ source: "builtin" },
|
|
2055
|
-
)
|
|
2056
|
-
: [];
|
|
2057
|
-
const discoverableMCPTools: DiscoverableTool[] = mcpDiscoveryEnabled
|
|
2058
|
-
? collectDiscoverableTools(
|
|
2059
|
-
Array.from(tools.values()).filter(
|
|
2060
|
-
tool => isMCPToolName(tool.name) && !activeToolNames.has(tool.name),
|
|
2061
|
-
),
|
|
2062
|
-
{ source: "mcp" },
|
|
2063
|
-
)
|
|
2064
|
-
: [];
|
|
2065
|
-
const discoverableToolsForDesc: DiscoverableTool[] = [
|
|
2066
|
-
...discoverableBuiltinTools,
|
|
2067
|
-
...discoverableMCPTools,
|
|
2068
|
-
];
|
|
2069
|
-
const promptTools = buildSystemPromptToolMetadata(tools, {
|
|
2070
|
-
search_tool_bm25: { description: renderSearchToolBm25Description(discoverableToolsForDesc) },
|
|
2071
|
-
});
|
|
2072
|
-
return { discoverableBuiltinTools, discoverableMCPTools, promptTools };
|
|
2071
|
+
return buildSystemPromptToolMetadata(tools);
|
|
2073
2072
|
} finally {
|
|
2074
2073
|
promptMetadataModel = previousPromptMetadataModel;
|
|
2075
2074
|
}
|
|
@@ -2080,25 +2079,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2080
2079
|
session,
|
|
2081
2080
|
);
|
|
2082
2081
|
|
|
2083
|
-
|
|
2084
|
-
const serverInstructions =
|
|
2085
|
-
explicitMcpConfigPath === undefined ? mcpManager?.getServerInstructions() : undefined;
|
|
2086
|
-
let appendPrompt: string | undefined = memoryInstructions ?? undefined;
|
|
2087
|
-
if (serverInstructions && serverInstructions.size > 0) {
|
|
2088
|
-
const parts: string[] = [];
|
|
2089
|
-
if (appendPrompt) parts.push(appendPrompt);
|
|
2090
|
-
parts.push(
|
|
2091
|
-
"## MCP Server Instructions\n\nThe following instructions are provided by connected MCP servers. They are server-controlled and may not be verified.",
|
|
2092
|
-
);
|
|
2093
|
-
for (const [srvName, srvInstructions] of serverInstructions) {
|
|
2094
|
-
const truncated =
|
|
2095
|
-
srvInstructions.length > MAX_MCP_INSTRUCTIONS_LENGTH
|
|
2096
|
-
? `${srvInstructions.slice(0, MAX_MCP_INSTRUCTIONS_LENGTH)}\n[truncated]`
|
|
2097
|
-
: srvInstructions;
|
|
2098
|
-
parts.push(`### ${srvName}\n${truncated}`);
|
|
2099
|
-
}
|
|
2100
|
-
appendPrompt = parts.join("\n\n");
|
|
2101
|
-
}
|
|
2082
|
+
const appendPrompt: string | undefined = memoryInstructions ?? undefined;
|
|
2102
2083
|
let pluginSystemAppendices = "";
|
|
2103
2084
|
try {
|
|
2104
2085
|
pluginSystemAppendices = await renderAlwaysOnSystemAppendices({ cwd });
|
|
@@ -2118,12 +2099,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2118
2099
|
pluginAppendices: pluginSystemAppendices,
|
|
2119
2100
|
repeatToolDescriptions,
|
|
2120
2101
|
intentField,
|
|
2121
|
-
mcpDiscoveryMode: false,
|
|
2122
|
-
mcpDiscoveryServerSummaries: [],
|
|
2123
2102
|
toolDiscoveryActive: effectiveDiscoveryMode === "all" || mcpDiscoveryEnabled,
|
|
2124
|
-
discoverableTools: [...discoverableBuiltinTools, ...discoverableMCPTools]
|
|
2125
|
-
.map(tool => ({ name: tool.name, summary: tool.summary }))
|
|
2126
|
-
.sort((a, b) => a.name.localeCompare(b.name)),
|
|
2127
2103
|
eagerTasks,
|
|
2128
2104
|
secretsEnabled,
|
|
2129
2105
|
workspaceTree: workspaceTreePromise,
|
|
@@ -2152,12 +2128,15 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2152
2128
|
: toolNamesFromRegistry;
|
|
2153
2129
|
const normalizedRequested = requestedToolNames.filter(name => toolRegistry.has(name));
|
|
2154
2130
|
const requestedToolNameSet = new Set(normalizedRequested);
|
|
2155
|
-
//
|
|
2156
|
-
// Legacy MCP discovery remains separately controlled by mcp.discoveryMode so
|
|
2157
|
-
// loaded MCP catalogs can be searched without enabling every hidden built-in.
|
|
2131
|
+
// Normalize the user-facing mcp.discoveryMode alias once at session construction.
|
|
2158
2132
|
const toolsDiscoveryModeSetting = settings.get("tools.discoveryMode");
|
|
2159
|
-
const effectiveDiscoveryMode: "off" | "
|
|
2160
|
-
|
|
2133
|
+
const effectiveDiscoveryMode: "off" | "mcp-only" | "all" =
|
|
2134
|
+
toolsDiscoveryModeSetting !== "off"
|
|
2135
|
+
? (toolsDiscoveryModeSetting as "mcp-only" | "all")
|
|
2136
|
+
: settings.get("mcp.discoveryMode") || explicitMcpConfigPath !== undefined
|
|
2137
|
+
? "mcp-only"
|
|
2138
|
+
: "off";
|
|
2139
|
+
const mcpDiscoveryEnabled = effectiveDiscoveryMode !== "off";
|
|
2161
2140
|
const defaultInactiveToolNames = new Set(
|
|
2162
2141
|
registeredTools.filter(tool => tool.definition.defaultInactive).map(tool => tool.definition.name),
|
|
2163
2142
|
);
|
|
@@ -2190,7 +2169,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2190
2169
|
toolRegistry.has(name),
|
|
2191
2170
|
);
|
|
2192
2171
|
defaultSelectedMCPToolNames = [
|
|
2193
|
-
...new Set([
|
|
2172
|
+
...new Set([
|
|
2173
|
+
...discoveryDefaultServerToolNames,
|
|
2174
|
+
...explicitlyRequestedMCPToolNames,
|
|
2175
|
+
...(explicitMcpConfigPath !== undefined ? exactMcpToolNames : []),
|
|
2176
|
+
]),
|
|
2194
2177
|
];
|
|
2195
2178
|
initialSelectedMCPToolNames = existingSession.hasPersistedMCPToolSelection
|
|
2196
2179
|
? restoredSelectedMCPToolNames
|
|
@@ -2303,11 +2286,13 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2303
2286
|
if (!obfuscator?.hasSecrets()) return converted;
|
|
2304
2287
|
return obfuscateMessages(obfuscator, converted);
|
|
2305
2288
|
};
|
|
2306
|
-
const transformContext =
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2289
|
+
const transformContext = async (messages: AgentMessage[], _signal?: AbortSignal) => {
|
|
2290
|
+
// External Agent events dispatch listeners without awaiting them. The
|
|
2291
|
+
// session-owned barrier makes any pre-admission artifact transformation
|
|
2292
|
+
// visible before this provider context is normalized.
|
|
2293
|
+
await session?.awaitPendingContextTransformations();
|
|
2294
|
+
return extensionRunner ? await extensionRunner.emitContext(messages) : messages;
|
|
2295
|
+
};
|
|
2311
2296
|
const onPayload = extensionRunner
|
|
2312
2297
|
? async (payload: unknown, _model?: Model) => {
|
|
2313
2298
|
return await extensionRunner.emitBeforeProviderRequest(payload);
|
|
@@ -2524,28 +2509,14 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2524
2509
|
onResponse,
|
|
2525
2510
|
convertToLlm: convertToLlmFinal,
|
|
2526
2511
|
rebuildSystemPrompt,
|
|
2512
|
+
getMcpServerInstructions:
|
|
2513
|
+
explicitMcpConfigPath === undefined && mcpManager ? () => mcpManager.getServerInstructions() : undefined,
|
|
2527
2514
|
workspaceTree: resolvedWorkspaceTree,
|
|
2528
2515
|
reloadSshTool,
|
|
2529
2516
|
requestedToolNames: requestedToolNameSet,
|
|
2530
2517
|
discoverableToolAllowedNames: options.discoverableToolAllowedNames,
|
|
2531
|
-
getMcpServerInstructions:
|
|
2532
|
-
mcpManager && explicitMcpConfigPath === undefined
|
|
2533
|
-
? () => {
|
|
2534
|
-
const raw = mcpManager.getServerInstructions();
|
|
2535
|
-
if (!raw || raw.size === 0) return raw;
|
|
2536
|
-
const out = new Map<string, string>();
|
|
2537
|
-
for (const [name, text] of raw) {
|
|
2538
|
-
out.set(
|
|
2539
|
-
name,
|
|
2540
|
-
text.length > MAX_MCP_INSTRUCTIONS_LENGTH
|
|
2541
|
-
? text.slice(0, MAX_MCP_INSTRUCTIONS_LENGTH)
|
|
2542
|
-
: text,
|
|
2543
|
-
);
|
|
2544
|
-
}
|
|
2545
|
-
return out;
|
|
2546
|
-
}
|
|
2547
|
-
: undefined,
|
|
2548
2518
|
mcpDiscoveryEnabled,
|
|
2519
|
+
discoveryMode: effectiveDiscoveryMode,
|
|
2549
2520
|
initialSelectedMCPToolNames,
|
|
2550
2521
|
defaultSelectedMCPToolNames,
|
|
2551
2522
|
persistInitialMCPToolSelection: !hasExistingSession,
|
|
@@ -2580,9 +2551,13 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2580
2551
|
try {
|
|
2581
2552
|
await originalDispose();
|
|
2582
2553
|
} finally {
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2554
|
+
try {
|
|
2555
|
+
agentRegistry.unregister(resolvedAgentId);
|
|
2556
|
+
releaseCredentialDisabledSubscription();
|
|
2557
|
+
releaseLocalProtocolOverride();
|
|
2558
|
+
} finally {
|
|
2559
|
+
closeOwnedAuthStorage();
|
|
2560
|
+
}
|
|
2586
2561
|
}
|
|
2587
2562
|
};
|
|
2588
2563
|
}
|
|
@@ -2697,9 +2672,8 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2697
2672
|
};
|
|
2698
2673
|
} catch (error) {
|
|
2699
2674
|
// Release the subscription if the throw happened after install but before the
|
|
2700
|
-
// dispose-wrap took ownership.
|
|
2701
|
-
|
|
2702
|
-
unsubscribeCredentialDisabled?.();
|
|
2675
|
+
// dispose-wrap took ownership.
|
|
2676
|
+
releaseCredentialDisabledSubscription();
|
|
2703
2677
|
try {
|
|
2704
2678
|
if (hasSession) {
|
|
2705
2679
|
await session.dispose();
|
|
@@ -2713,6 +2687,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2713
2687
|
logger.warn("Failed to clean up createAgentSession resources after startup error");
|
|
2714
2688
|
} finally {
|
|
2715
2689
|
releaseLocalProtocolOverride();
|
|
2690
|
+
try {
|
|
2691
|
+
closeOwnedAuthStorage();
|
|
2692
|
+
} catch {
|
|
2693
|
+
logger.warn("Failed to close owned auth storage after startup error");
|
|
2694
|
+
}
|
|
2716
2695
|
}
|
|
2717
2696
|
throw error;
|
|
2718
2697
|
}
|