@gajae-code/coding-agent 0.11.1 → 0.11.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/CHANGELOG.md +64 -0
- package/dist/types/cli/config-cli.d.ts +11 -1
- package/dist/types/cli/launch-disposition.d.ts +23 -0
- 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 +141 -11
- 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 +4 -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/prompt-action-autocomplete.d.ts +4 -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 +29 -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/sdk/session.d.ts +2 -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 +5 -0
- package/dist/types/tools/search-tool-bm25.d.ts +3 -4
- package/dist/types/tools/subagent.d.ts +1 -0
- package/dist/types/utils/event-bus.d.ts +1 -1
- package/dist/types/utils/file-mentions.d.ts +3 -3
- 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/launch-disposition.ts +42 -0
- 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 +214 -12
- 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 +327 -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 +127 -30
- 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/prompt-action-autocomplete.ts +7 -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 +782 -94
- 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 +44 -2
- 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 +462 -480
- 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 +19 -7
- package/src/tools/read.ts +219 -64
- package/src/tools/resource-gc.ts +2 -2
- package/src/tools/search-tool-bm25.ts +11 -74
- package/src/tools/subagent.ts +43 -2
- package/src/utils/event-bus.ts +9 -4
- package/src/utils/file-mentions.ts +4 -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,
|
|
@@ -396,6 +390,8 @@ export interface CreateAgentSessionOptions {
|
|
|
396
390
|
hasUI?: boolean;
|
|
397
391
|
/** Whether this host mode can own a notification session endpoint. Default: true. */
|
|
398
392
|
notificationHostModeSupported?: boolean;
|
|
393
|
+
/** Whether this host mode can own the root SDK endpoint. Default: true. */
|
|
394
|
+
sdkHostModeSupported?: boolean;
|
|
399
395
|
|
|
400
396
|
/**
|
|
401
397
|
* Opt-in OpenTelemetry instrumentation forwarded to the underlying Agent.
|
|
@@ -498,7 +494,16 @@ export async function discoverAuthStorage(agentDir: string = getDefaultAgentDir(
|
|
|
498
494
|
sourceLabel: `broker ${brokerConfig.url}`,
|
|
499
495
|
credentialRankingMode,
|
|
500
496
|
});
|
|
501
|
-
|
|
497
|
+
try {
|
|
498
|
+
await storage.reload();
|
|
499
|
+
} catch (error) {
|
|
500
|
+
try {
|
|
501
|
+
storage.close();
|
|
502
|
+
} catch {
|
|
503
|
+
// Preserve the initial reload failure.
|
|
504
|
+
}
|
|
505
|
+
throw error;
|
|
506
|
+
}
|
|
502
507
|
return storage;
|
|
503
508
|
}
|
|
504
509
|
const dbPath = getAgentDbPath(agentDir);
|
|
@@ -507,7 +512,16 @@ export async function discoverAuthStorage(agentDir: string = getDefaultAgentDir(
|
|
|
507
512
|
sourceLabel: `local ${dbPath}`,
|
|
508
513
|
credentialRankingMode,
|
|
509
514
|
});
|
|
510
|
-
|
|
515
|
+
try {
|
|
516
|
+
await storage.reload();
|
|
517
|
+
} catch (error) {
|
|
518
|
+
try {
|
|
519
|
+
storage.close();
|
|
520
|
+
} catch {
|
|
521
|
+
// Preserve the initial reload failure.
|
|
522
|
+
}
|
|
523
|
+
throw error;
|
|
524
|
+
}
|
|
511
525
|
return storage;
|
|
512
526
|
}
|
|
513
527
|
|
|
@@ -629,9 +643,6 @@ function isCustomTool(tool: CustomTool | ToolDefinition): tool is CustomTool {
|
|
|
629
643
|
|
|
630
644
|
const TOOL_DEFINITION_MARKER = Symbol("__isToolDefinition");
|
|
631
645
|
|
|
632
|
-
/** Matches the truncation applied to per-server instructions inside `rebuildSystemPrompt`. */
|
|
633
|
-
const MAX_MCP_INSTRUCTIONS_LENGTH = 4000;
|
|
634
|
-
|
|
635
646
|
let sshCleanupRegistered = false;
|
|
636
647
|
|
|
637
648
|
async function cleanupSshResources(): Promise<void> {
|
|
@@ -976,6 +987,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
976
987
|
// Pin authStorage to modelRegistry.authStorage: ModelRegistry.getApiKey() routes refresh
|
|
977
988
|
// failures through that instance, so any divergent storage handed to the bridge / mcpManager
|
|
978
989
|
// / session would silently miss credential_disabled events.
|
|
990
|
+
const ownsAuthStorage = options.modelRegistry === undefined && options.authStorage === undefined;
|
|
979
991
|
const modelRegistry =
|
|
980
992
|
options.modelRegistry ??
|
|
981
993
|
new ModelRegistry(options.authStorage ?? (await logger.time("discoverModels", discoverAuthStorage, agentDir)));
|
|
@@ -985,409 +997,424 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
985
997
|
"options.authStorage and options.modelRegistry.authStorage must be the same instance when both are provided",
|
|
986
998
|
);
|
|
987
999
|
}
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
}
|
|
1002
|
-
let
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1000
|
+
let agent: Agent;
|
|
1001
|
+
let session!: AgentSession;
|
|
1002
|
+
let hasSession = false;
|
|
1003
|
+
let hasRegistered = false;
|
|
1004
|
+
let cleanupOwnedMcpManager: (() => Promise<void>) | undefined;
|
|
1005
|
+
const agentRegistry = options.agentRegistry ?? AgentRegistry.global();
|
|
1006
|
+
const resolvedAgentId = options.agentId ?? options.parentTaskPrefix ?? MAIN_AGENT_ID;
|
|
1007
|
+
const resolvedAgentDisplayName = options.agentDisplayName ?? (isCanonicalSubSession ? "sub" : "main");
|
|
1008
|
+
const resolvedAgentRosterLabel = resolveAgentRosterLabel(
|
|
1009
|
+
options.agentRosterLabel,
|
|
1010
|
+
resolvedAgentId,
|
|
1011
|
+
resolvedAgentDisplayName,
|
|
1012
|
+
);
|
|
1013
|
+
const evalKernelOwnerId = `agent-session:${Snowflake.next()}`;
|
|
1014
|
+
let disposeLocalProtocolOverride: (() => void) | undefined;
|
|
1015
|
+
let localProtocolOverrideReleased = false;
|
|
1016
|
+
const releaseLocalProtocolOverride = (): void => {
|
|
1017
|
+
if (localProtocolOverrideReleased) return;
|
|
1018
|
+
localProtocolOverrideReleased = true;
|
|
1019
|
+
disposeLocalProtocolOverride?.();
|
|
1020
|
+
};
|
|
1021
|
+
const enableLsp = options.enableLsp ?? true;
|
|
1022
|
+
let authStorageClosed = false;
|
|
1023
|
+
const closeOwnedAuthStorage = (): void => {
|
|
1024
|
+
if (!ownsAuthStorage || authStorageClosed) return;
|
|
1025
|
+
authStorageClosed = true;
|
|
1026
|
+
authStorage.close();
|
|
1027
|
+
};
|
|
1028
|
+
let unsubscribeCredentialDisabled: (() => void) | undefined;
|
|
1029
|
+
const releaseCredentialDisabledSubscription = (): void => {
|
|
1030
|
+
const unsubscribe = unsubscribeCredentialDisabled;
|
|
1031
|
+
unsubscribeCredentialDisabled = undefined;
|
|
1032
|
+
unsubscribe?.();
|
|
1007
1033
|
};
|
|
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
1034
|
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1035
|
+
try {
|
|
1036
|
+
// Subscribe before any getApiKey() call so startup model probes can't fire a
|
|
1037
|
+
// credential_disabled event past us. An embedder's constructor handler makes the
|
|
1038
|
+
// listener set non-empty from construction, which defeats AuthStorage's no-listener
|
|
1039
|
+
// buffer — so we can't rely on it to catch startup events for the extension runner.
|
|
1040
|
+
const startupCredentialDisabledEvents: CredentialDisabledEvent[] = [];
|
|
1041
|
+
let credentialDisabledTarget: ExtensionRunner | undefined;
|
|
1042
|
+
unsubscribeCredentialDisabled = authStorage.onCredentialDisabled(event => {
|
|
1043
|
+
if (credentialDisabledTarget) {
|
|
1044
|
+
// Discard return: any handler error is routed through runner.onError listeners.
|
|
1045
|
+
void credentialDisabledTarget.emitCredentialDisabled(event);
|
|
1046
|
+
} else {
|
|
1047
|
+
startupCredentialDisabledEvents.push(event);
|
|
1048
|
+
}
|
|
1049
|
+
});
|
|
1050
|
+
let runtimeCredentialSelectorInstalled = false;
|
|
1051
|
+
const installRuntimeCredentialSelector = (provider: string): void => {
|
|
1052
|
+
if (!options.credentialSelector || runtimeCredentialSelectorInstalled) return;
|
|
1053
|
+
authStorage.setRuntimeCredentialSelector(provider, options.credentialSelector.selector);
|
|
1054
|
+
runtimeCredentialSelectorInstalled = true;
|
|
1055
|
+
};
|
|
1056
|
+
const earlyCredentialSelectorProvider = options.credentialSelector?.provider ?? options.model?.provider;
|
|
1057
|
+
if (earlyCredentialSelectorProvider) {
|
|
1058
|
+
installRuntimeCredentialSelector(earlyCredentialSelectorProvider);
|
|
1081
1059
|
}
|
|
1060
|
+
const settings = options.settings ?? (await logger.time("settings", Settings.init, { cwd, agentDir }));
|
|
1061
|
+
modelRegistry.applyConfiguredModelBindings(settings);
|
|
1062
|
+
logger.time("initializeWithSettings", initializeWithSettings, settings);
|
|
1063
|
+
const canRefreshModelsBeforeCredentialSelector =
|
|
1064
|
+
!options.credentialSelector || runtimeCredentialSelectorInstalled || options.modelRegistry !== undefined;
|
|
1065
|
+
if (!options.modelRegistry && canRefreshModelsBeforeCredentialSelector) {
|
|
1066
|
+
modelRegistry.refreshInBackground();
|
|
1067
|
+
}
|
|
1068
|
+
// Kick off workspace tree discovery early. The native workspace scan returns
|
|
1069
|
+
// both the rendered-tree input and the AGENTS.md directory-context index, so
|
|
1070
|
+
// startup does not perform a second recursive filesystem search. Subagents
|
|
1071
|
+
// inherit the parent's resolved values via options.
|
|
1072
|
+
const STARTUP_SCAN_DEADLINE_MS = 5000;
|
|
1073
|
+
const workspaceTreePromise: Promise<WorkspaceTree> = options.workspaceTree
|
|
1074
|
+
? Promise.resolve(options.workspaceTree)
|
|
1075
|
+
: logger.time("buildWorkspaceTree", () => buildWorkspaceTree(cwd, { timeoutMs: STARTUP_SCAN_DEADLINE_MS }));
|
|
1076
|
+
workspaceTreePromise.catch(() => {});
|
|
1077
|
+
|
|
1078
|
+
// Independent discoveries that depend only on cwd/agentDir — kicked off in parallel and awaited
|
|
1079
|
+
// at their respective consumer sites. Their work can overlap with model resolution, secret loading,
|
|
1080
|
+
// session-context build, tool creation, MCP discovery, and extension discovery.
|
|
1081
|
+
const contextFilesPromise = options.contextFiles
|
|
1082
|
+
? Promise.resolve(options.contextFiles)
|
|
1083
|
+
: logger.time("discoverContextFiles", discoverContextFiles, cwd, agentDir);
|
|
1084
|
+
contextFilesPromise.catch(() => {});
|
|
1085
|
+
const promptTemplatesPromise = options.promptTemplates
|
|
1086
|
+
? Promise.resolve(options.promptTemplates)
|
|
1087
|
+
: logger.time("discoverPromptTemplates", discoverPromptTemplates, cwd, agentDir);
|
|
1088
|
+
promptTemplatesPromise.catch(() => {});
|
|
1089
|
+
const slashCommandsPromise = options.slashCommands ? Promise.resolve(options.slashCommands) : Promise.resolve([]);
|
|
1090
|
+
slashCommandsPromise.catch(() => {});
|
|
1091
|
+
|
|
1092
|
+
// Initialize provider preferences from settings
|
|
1093
|
+
const webSearchProvider = getConfiguredSearchProviderPreference(settings);
|
|
1094
|
+
setPreferredSearchProvider(webSearchProvider);
|
|
1095
|
+
const webSearchFallback = settings.get("web_search.fallback");
|
|
1096
|
+
if (Array.isArray(webSearchFallback)) {
|
|
1097
|
+
setSearchFallbackProviders(
|
|
1098
|
+
webSearchFallback.filter(value => typeof value === "string" && isConfigurableSearchProviderId(value)),
|
|
1099
|
+
);
|
|
1100
|
+
}
|
|
1101
|
+
applyConfiguredSearchTimeout(settings);
|
|
1082
1102
|
|
|
1083
|
-
const
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
return false;
|
|
1103
|
+
const imageProvider = settings.get("providers.image");
|
|
1104
|
+
if (
|
|
1105
|
+
imageProvider === "auto" ||
|
|
1106
|
+
imageProvider === "openai" ||
|
|
1107
|
+
imageProvider === "gemini" ||
|
|
1108
|
+
imageProvider === "openrouter" ||
|
|
1109
|
+
imageProvider === "antigravity"
|
|
1110
|
+
) {
|
|
1111
|
+
setPreferredImageProvider(imageProvider);
|
|
1093
1112
|
}
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1113
|
+
|
|
1114
|
+
const sessionManager =
|
|
1115
|
+
options.sessionManager ??
|
|
1116
|
+
(await logger.time("sessionManager", async () => {
|
|
1117
|
+
const sessionDir = SessionManager.getDefaultSessionDir(cwd, agentDir);
|
|
1118
|
+
return SessionManager.create(cwd, sessionDir);
|
|
1119
|
+
}));
|
|
1120
|
+
const logicalSessionId = sessionManager.getSessionId();
|
|
1121
|
+
const providerSessionId = options.providerSessionId ?? options.forkContextSeed?.cacheIdentity ?? logicalSessionId;
|
|
1122
|
+
const modelApiKeyAvailability = new Map<string, boolean>();
|
|
1123
|
+
const getModelAvailabilityKey = (candidate: Model): string =>
|
|
1124
|
+
`${candidate.provider}\u0000${candidate.baseUrl ?? ""}`;
|
|
1125
|
+
const hasModelApiKey = async (candidate: Model): Promise<boolean> => {
|
|
1126
|
+
const availabilityKey = getModelAvailabilityKey(candidate);
|
|
1127
|
+
const cached = modelApiKeyAvailability.get(availabilityKey);
|
|
1128
|
+
if (cached !== undefined) {
|
|
1129
|
+
return cached;
|
|
1102
1130
|
}
|
|
1103
|
-
throw error;
|
|
1104
|
-
});
|
|
1105
|
-
const hasKey = Boolean(key) && (!credentialSelector || key !== kNoAuth);
|
|
1106
|
-
modelApiKeyAvailability.set(availabilityKey, hasKey);
|
|
1107
|
-
return hasKey;
|
|
1108
|
-
};
|
|
1109
1131
|
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1132
|
+
const credentialSelector =
|
|
1133
|
+
options.credentialSelector && !runtimeCredentialSelectorInstalled
|
|
1134
|
+
? options.credentialSelector.provider === undefined ||
|
|
1135
|
+
options.credentialSelector.provider === candidate.provider
|
|
1136
|
+
? options.credentialSelector.selector
|
|
1137
|
+
: undefined
|
|
1138
|
+
: undefined;
|
|
1139
|
+
if (options.credentialSelector?.provider && options.credentialSelector.provider !== candidate.provider) {
|
|
1140
|
+
modelApiKeyAvailability.set(availabilityKey, false);
|
|
1141
|
+
return false;
|
|
1142
|
+
}
|
|
1143
|
+
const key = await modelRegistry
|
|
1144
|
+
.getApiKey(candidate, providerSessionId, { credentialSelector })
|
|
1145
|
+
.catch(error => {
|
|
1146
|
+
if (credentialSelector) {
|
|
1147
|
+
logger.debug("Credential selector did not match model availability candidate", {
|
|
1148
|
+
provider: candidate.provider,
|
|
1149
|
+
model: candidate.id,
|
|
1150
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1151
|
+
});
|
|
1152
|
+
return undefined;
|
|
1153
|
+
}
|
|
1154
|
+
throw error;
|
|
1155
|
+
});
|
|
1156
|
+
const hasKey = Boolean(key) && (!credentialSelector || key !== kNoAuth);
|
|
1157
|
+
modelApiKeyAvailability.set(availabilityKey, hasKey);
|
|
1158
|
+
return hasKey;
|
|
1159
|
+
};
|
|
1160
|
+
|
|
1161
|
+
// Load and create secret obfuscator early so resumed session state and prompt warnings
|
|
1162
|
+
// reflect actual loaded secrets, not just the setting toggle.
|
|
1163
|
+
let obfuscator: SecretObfuscator | undefined;
|
|
1164
|
+
if (settings.get("secrets.enabled")) {
|
|
1165
|
+
const fileEntries = await logger.time("loadSecrets", loadSecrets, cwd, agentDir);
|
|
1166
|
+
const envEntries = collectEnvSecrets();
|
|
1167
|
+
const allEntries = [...envEntries, ...fileEntries];
|
|
1168
|
+
if (allEntries.length > 0) {
|
|
1169
|
+
obfuscator = new SecretObfuscator(allEntries);
|
|
1170
|
+
}
|
|
1119
1171
|
}
|
|
1120
|
-
|
|
1121
|
-
const secretsEnabled = obfuscator?.hasSecrets() === true;
|
|
1172
|
+
const secretsEnabled = obfuscator?.hasSecrets() === true;
|
|
1122
1173
|
|
|
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,
|
|
1174
|
+
// Check if session has existing data to restore
|
|
1175
|
+
const existingSession = logger.time("loadSessionContext", () =>
|
|
1176
|
+
deobfuscateSessionContext(sessionManager.buildSessionContext(), obfuscator),
|
|
1177
|
+
);
|
|
1178
|
+
const existingBranch = logger.time("getSessionBranch", () => sessionManager.getBranch());
|
|
1179
|
+
const hasExistingSession = existingBranch.length > 0;
|
|
1180
|
+
const hasThinkingEntry = existingBranch.some(entry => entry.type === "thinking_level_change");
|
|
1181
|
+
const hasServiceTierEntry = existingBranch.some(entry => entry.type === "service_tier_change");
|
|
1182
|
+
|
|
1183
|
+
const hasExplicitModel = options.model !== undefined || options.modelPattern !== undefined;
|
|
1184
|
+
const modelMatchPreferences = {
|
|
1185
|
+
usageOrder: settings.getStorage()?.getModelUsageOrder(),
|
|
1186
|
+
};
|
|
1187
|
+
const allowedModels = await logger.time("resolveAllowedModels", () =>
|
|
1188
|
+
resolveAllowedModels(modelRegistry, settings, modelMatchPreferences),
|
|
1189
|
+
);
|
|
1190
|
+
const defaultRoleSpec = logger.time("resolveDefaultModelRole", () =>
|
|
1191
|
+
resolveModelRoleValue(settings.getModelRole("default"), allowedModels, {
|
|
1162
1192
|
settings,
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
)
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1193
|
+
matchPreferences: modelMatchPreferences,
|
|
1194
|
+
modelRegistry,
|
|
1195
|
+
}),
|
|
1196
|
+
);
|
|
1197
|
+
let model = options.model;
|
|
1198
|
+
let modelFallbackMessage: string | undefined;
|
|
1199
|
+
const persistedDefaultChain = existingSession.configuredModelChains.default?.entries;
|
|
1200
|
+
const defaultModelEntries =
|
|
1201
|
+
persistedDefaultChain && persistedDefaultChain.length > 0
|
|
1202
|
+
? persistedDefaultChain
|
|
1203
|
+
: existingSession.models.default
|
|
1204
|
+
? [existingSession.models.default]
|
|
1205
|
+
: [];
|
|
1206
|
+
// If session has data, restore its configured default chain rather than the
|
|
1207
|
+
// scalar runtime model, which may be a stale fallback from the prior run.
|
|
1208
|
+
if (!hasExplicitModel && !model && hasExistingSession && defaultModelEntries.length > 0) {
|
|
1209
|
+
await logger.time("restoreSessionModel", async () => {
|
|
1210
|
+
const restoredDefaultResolution = await resolveModelChainWithAuth(
|
|
1211
|
+
defaultModelEntries,
|
|
1212
|
+
modelRegistry,
|
|
1213
|
+
settings,
|
|
1214
|
+
providerSessionId,
|
|
1215
|
+
{ managedFallback: defaultModelEntries.length > 1 },
|
|
1216
|
+
);
|
|
1217
|
+
model = restoredDefaultResolution.model;
|
|
1218
|
+
if (!model) modelFallbackMessage = `Could not restore model ${defaultModelEntries.join(" -> ")}`;
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1183
1221
|
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1222
|
+
// If still no model, try settings default.
|
|
1223
|
+
// Skip settings fallback when an explicit model was requested.
|
|
1224
|
+
if (!hasExplicitModel && !model && defaultRoleSpec.model) {
|
|
1225
|
+
const settingsDefaultModel = defaultRoleSpec.model;
|
|
1226
|
+
logger.time("resolveSettingsDefaultModel", () => {
|
|
1227
|
+
// defaultRoleSpec.model already comes from modelRegistry.getAvailable(),
|
|
1228
|
+
// so re-validating auth here just repeats the expensive lookup path.
|
|
1229
|
+
model = settingsDefaultModel;
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1187
1232
|
|
|
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
|
-
}
|
|
1233
|
+
const taskDepth = options.taskDepth ?? 0;
|
|
1196
1234
|
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1235
|
+
let thinkingLevel = options.thinkingLevel;
|
|
1236
|
+
const hasExplicitDefaultThinkingLevel = settings.has("defaultThinkingLevel");
|
|
1237
|
+
let thinkingLevelFromSchemaDefault = false;
|
|
1200
1238
|
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1239
|
+
// If session has data and includes a thinking entry, restore an explicit session
|
|
1240
|
+
// override. A persisted inherit marker deliberately re-enters the normal
|
|
1241
|
+
// default-role/global/model resolution path instead of resolving to `undefined`.
|
|
1242
|
+
const restoredThinkingLevel =
|
|
1243
|
+
hasExistingSession && hasThinkingEntry ? parseThinkingLevel(existingSession.thinkingLevel) : undefined;
|
|
1244
|
+
if (thinkingLevel === undefined && restoredThinkingLevel !== ThinkingLevel.Inherit) {
|
|
1245
|
+
thinkingLevel = restoredThinkingLevel;
|
|
1246
|
+
}
|
|
1207
1247
|
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1248
|
+
if (thinkingLevel === undefined && !hasExplicitModel && defaultRoleSpec.explicitThinkingLevel) {
|
|
1249
|
+
thinkingLevel = defaultRoleSpec.thinkingLevel;
|
|
1250
|
+
}
|
|
1211
1251
|
|
|
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
|
-
}
|
|
1252
|
+
// An explicit user/project default should win over the model's bundled
|
|
1253
|
+
// defaultLevel. The schema default is only a final fallback so model metadata
|
|
1254
|
+
// can keep driving first-run behavior until the user chooses "Set as default".
|
|
1255
|
+
if (thinkingLevel === undefined && hasExplicitDefaultThinkingLevel) {
|
|
1256
|
+
thinkingLevel = settings.get("defaultThinkingLevel");
|
|
1257
|
+
}
|
|
1229
1258
|
|
|
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
|
-
}
|
|
1259
|
+
if (thinkingLevel === undefined && model?.thinking?.defaultLevel !== undefined) {
|
|
1260
|
+
thinkingLevel = model.thinking.defaultLevel;
|
|
1261
|
+
}
|
|
1254
1262
|
|
|
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
|
-
}
|
|
1263
|
+
if (thinkingLevel === undefined) {
|
|
1264
|
+
thinkingLevel = settings.get("defaultThinkingLevel");
|
|
1265
|
+
thinkingLevelFromSchemaDefault = true;
|
|
1277
1266
|
}
|
|
1278
|
-
if (
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1267
|
+
if (model) {
|
|
1268
|
+
const resolvedModel = model;
|
|
1269
|
+
thinkingLevel = logger.time("resolveThinkingLevelForModel", () =>
|
|
1270
|
+
resolveThinkingLevelForModel(resolvedModel, thinkingLevel),
|
|
1271
|
+
);
|
|
1272
|
+
// Fire-and-forget TLS+H2 handshake to the model's host so it overlaps
|
|
1273
|
+
// with the rest of session setup (extension/skill load, tool registry,
|
|
1274
|
+
// system prompt build). Without this, the first `fetch(...)` pays the
|
|
1275
|
+
// full handshake serially — 100–300 ms transcontinental for
|
|
1276
|
+
// api.anthropic.com from a residential IP. Every session frontend benefits
|
|
1277
|
+
// (interactive, print, SDK, ACP).
|
|
1278
|
+
preconnectModelHost(model.baseUrl);
|
|
1287
1279
|
}
|
|
1288
|
-
return { ttsrManager, rulebookRules, alwaysApplyRules };
|
|
1289
|
-
});
|
|
1290
1280
|
|
|
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,
|
|
1281
|
+
let skills: Skill[];
|
|
1282
|
+
let skillWarnings: SkillWarning[];
|
|
1283
|
+
if (options.skills !== undefined) {
|
|
1284
|
+
// The four public GJC workflow skills are a product invariant, not
|
|
1285
|
+
// ordinary filesystem-discovered skills. Keep them available even for
|
|
1286
|
+
// explicit SDK skill lists so startup and command routing survive
|
|
1287
|
+
// accidental `.gjc` deletion or overzealous caller filtering.
|
|
1288
|
+
skills = withEmbeddedDefaultGjcSkills(options.skills);
|
|
1289
|
+
skillWarnings = [];
|
|
1290
|
+
} else if (settings.get("skills.enabled")) {
|
|
1291
|
+
const skillsResult = await logger.time("loadSkills", loadSkills, {
|
|
1292
|
+
...settings.getGroup("skills"),
|
|
1309
1293
|
cwd,
|
|
1294
|
+
disabledExtensions: settings.get("disabledExtensions"),
|
|
1310
1295
|
});
|
|
1296
|
+
skills = withEmbeddedDefaultGjcSkills(skillsResult.skills);
|
|
1297
|
+
skillWarnings = skillsResult.warnings;
|
|
1298
|
+
} else {
|
|
1299
|
+
// GJC's four public workflow skills are bundled into the binary so the
|
|
1300
|
+
// default workflow surface survives accidental .gjc deletion. Arbitrary
|
|
1301
|
+
// filesystem skill discovery remains gated by skills.enabled above.
|
|
1302
|
+
skills = getEmbeddedDefaultGjcSkills();
|
|
1303
|
+
skillWarnings = [];
|
|
1311
1304
|
}
|
|
1312
|
-
return result;
|
|
1313
|
-
};
|
|
1314
|
-
const [contextFiles, resolvedWorkspaceTree] = await Promise.all([
|
|
1315
|
-
contextFilesPromise,
|
|
1316
|
-
raceWithDeadline("buildWorkspaceTree", workspaceTreePromise),
|
|
1317
|
-
]);
|
|
1318
1305
|
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1306
|
+
// Discover rules and bucket them in one pass to avoid repeated scans over large rule sets.
|
|
1307
|
+
const { ttsrManager, rulebookRules, alwaysApplyRules } = await logger.time("discoverTtsrRules", async () => {
|
|
1308
|
+
const ttsrSettings = settings.getGroup("ttsr");
|
|
1309
|
+
const ttsrManager = new TtsrManager(ttsrSettings);
|
|
1310
|
+
const rulesResult =
|
|
1311
|
+
options.rules !== undefined
|
|
1312
|
+
? { items: options.rules, warnings: undefined }
|
|
1313
|
+
: await loadCapability<Rule>(ruleCapability.id, { cwd });
|
|
1314
|
+
const rulebookRules: Rule[] = [];
|
|
1315
|
+
const alwaysApplyRules: Rule[] = [];
|
|
1316
|
+
for (const rule of rulesResult.items) {
|
|
1317
|
+
const isTtsrRule = rule.condition && rule.condition.length > 0 ? ttsrManager.addRule(rule) : false;
|
|
1318
|
+
if (isTtsrRule) {
|
|
1319
|
+
continue;
|
|
1320
|
+
}
|
|
1321
|
+
if (rule.alwaysApply === true) {
|
|
1322
|
+
alwaysApplyRules.push(rule);
|
|
1323
|
+
continue;
|
|
1324
|
+
}
|
|
1325
|
+
if (rule.description) {
|
|
1326
|
+
rulebookRules.push(rule);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
if (ttsrManager.getSettings().enabled !== false) {
|
|
1330
|
+
if ((existingSession.ttsrMessageCount ?? 0) > 0) {
|
|
1331
|
+
ttsrManager.restoreMessageCount(existingSession.ttsrMessageCount ?? 0);
|
|
1332
|
+
}
|
|
1333
|
+
if (existingSession.injectedTtsrRuleRecords && existingSession.injectedTtsrRuleRecords.length > 0) {
|
|
1334
|
+
ttsrManager.restoreInjected(existingSession.injectedTtsrRuleRecords);
|
|
1335
|
+
} else if (existingSession.injectedTtsrRules.length > 0) {
|
|
1336
|
+
ttsrManager.restoreInjected(existingSession.injectedTtsrRules);
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
return { ttsrManager, rulebookRules, alwaysApplyRules };
|
|
1340
|
+
});
|
|
1341
|
+
|
|
1342
|
+
// Resolve contextFiles up-front (it's needed before tool creation). The
|
|
1343
|
+
// workspace tree scan is slow on large repos and we MUST NOT block startup on
|
|
1344
|
+
// it. On timeout we forward `undefined` to ToolSession; buildSystemPromptInternal
|
|
1345
|
+
// will re-race the same promise through its own withDeadline path. Background
|
|
1346
|
+
// work continues so caches still warm.
|
|
1347
|
+
const raceWithDeadline = async <T>(name: string, work: Promise<T>): Promise<T | undefined> => {
|
|
1348
|
+
let timedOut = false;
|
|
1349
|
+
const result = await Promise.race([
|
|
1350
|
+
work,
|
|
1351
|
+
Bun.sleep(STARTUP_SCAN_DEADLINE_MS).then(() => {
|
|
1352
|
+
timedOut = true;
|
|
1353
|
+
return undefined;
|
|
1354
|
+
}),
|
|
1355
|
+
]);
|
|
1356
|
+
if (timedOut) {
|
|
1357
|
+
logger.warn("Startup scan exceeded deadline; deferring to system prompt fallback", {
|
|
1358
|
+
name,
|
|
1359
|
+
timeoutMs: STARTUP_SCAN_DEADLINE_MS,
|
|
1360
|
+
cwd,
|
|
1361
|
+
});
|
|
1362
|
+
}
|
|
1331
1363
|
return result;
|
|
1332
|
-
}
|
|
1364
|
+
};
|
|
1365
|
+
const [contextFiles, resolvedWorkspaceTree] = await Promise.all([
|
|
1366
|
+
contextFilesPromise,
|
|
1367
|
+
raceWithDeadline("buildWorkspaceTree", workspaceTreePromise),
|
|
1368
|
+
]);
|
|
1333
1369
|
|
|
1334
|
-
const
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1370
|
+
const backgroundJobsEnabled = isBackgroundJobSupportEnabled(settings);
|
|
1371
|
+
const asyncMaxJobs = Math.min(100, Math.max(1, settings.get("async.maxJobs") ?? 100));
|
|
1372
|
+
const ASYNC_INLINE_RESULT_MAX_CHARS = 12_000;
|
|
1373
|
+
const ASYNC_PREVIEW_MAX_CHARS = 4_000;
|
|
1374
|
+
const formatAsyncResultForFollowUp = async (result: string): Promise<string> => {
|
|
1375
|
+
if (result.length <= ASYNC_INLINE_RESULT_MAX_CHARS) {
|
|
1376
|
+
return result;
|
|
1340
1377
|
}
|
|
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
1378
|
|
|
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;
|
|
1379
|
+
const preview = `${result.slice(0, ASYNC_PREVIEW_MAX_CHARS)}\n\n[Output truncated. Showing first ${ASYNC_PREVIEW_MAX_CHARS.toLocaleString()} characters.]`;
|
|
1380
|
+
try {
|
|
1381
|
+
const { path: artifactPath, id: artifactId } = await sessionManager.allocateArtifactPath("async");
|
|
1382
|
+
if (artifactPath && artifactId) {
|
|
1383
|
+
await Bun.write(artifactPath, result);
|
|
1384
|
+
return `${preview}\nFull output: artifact://${artifactId}`;
|
|
1385
|
+
}
|
|
1386
|
+
} catch (error) {
|
|
1387
|
+
logger.warn("Failed to persist async follow-up artifact", {
|
|
1388
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1389
|
+
});
|
|
1390
|
+
}
|
|
1372
1391
|
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1392
|
+
return preview;
|
|
1393
|
+
};
|
|
1394
|
+
// Only top-level sessions own an AsyncJobManager. Subagents reach the
|
|
1395
|
+
// parent's manager via `AsyncJobManager.instance()` (set below), so creating
|
|
1396
|
+
// a second instance here just to leave it orphaned wastes a constructor and
|
|
1397
|
+
// risks accidental disposal of the parent's manager on subagent teardown.
|
|
1398
|
+
const asyncJobManager =
|
|
1399
|
+
backgroundJobsEnabled && !options.parentTaskPrefix
|
|
1400
|
+
? new AsyncJobManager({
|
|
1401
|
+
maxRunningJobs: asyncMaxJobs,
|
|
1402
|
+
onJobComplete: async (jobId, result, job) => {
|
|
1403
|
+
if (!session || asyncJobManager!.isDeliverySuppressed(jobId)) return;
|
|
1404
|
+
const formattedResult = await formatAsyncResultForFollowUp(result);
|
|
1405
|
+
if (asyncJobManager!.isDeliverySuppressed(jobId)) return;
|
|
1406
|
+
|
|
1407
|
+
const durationMs = job ? jobElapsedMs(job) : undefined;
|
|
1408
|
+
session.yieldQueue.enqueue<AsyncResultEntry>("async-result", {
|
|
1409
|
+
jobId,
|
|
1410
|
+
result: formattedResult,
|
|
1411
|
+
job,
|
|
1412
|
+
durationMs,
|
|
1413
|
+
});
|
|
1414
|
+
},
|
|
1415
|
+
})
|
|
1416
|
+
: undefined;
|
|
1389
1417
|
|
|
1390
|
-
try {
|
|
1391
1418
|
let promptMetadataModel: Model | undefined;
|
|
1392
1419
|
const getActiveModelString = (): string | undefined => {
|
|
1393
1420
|
const activeModel = promptMetadataModel ?? agent?.state.model;
|
|
@@ -1454,11 +1481,6 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1454
1481
|
getCompactContext: () => session.formatCompactContext(),
|
|
1455
1482
|
getTodoPhases: () => session.getTodoPhases(),
|
|
1456
1483
|
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
1484
|
// Generic tool discovery (unified — covers built-in + MCP + extension)
|
|
1463
1485
|
isToolDiscoveryEnabled: () => session.isToolDiscoveryEnabled(),
|
|
1464
1486
|
getDiscoverableTools: filter => session.getDiscoverableTools(filter),
|
|
@@ -1743,7 +1765,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1743
1765
|
currentAgentType: options.currentAgentType,
|
|
1744
1766
|
spawnedByGjc,
|
|
1745
1767
|
}) ||
|
|
1746
|
-
shouldHostSdk(notificationCfg, isTopLevelSdkSession)
|
|
1768
|
+
(shouldHostSdk(notificationCfg, isTopLevelSdkSession) && (options.sdkHostModeSupported ?? true))
|
|
1747
1769
|
) {
|
|
1748
1770
|
inlineExtensions.push(async api => {
|
|
1749
1771
|
try {
|
|
@@ -1754,6 +1776,12 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1754
1776
|
settings,
|
|
1755
1777
|
controller: notificationSessionController,
|
|
1756
1778
|
spawnedByGjc,
|
|
1779
|
+
sdkHostModeSupported: options.sdkHostModeSupported,
|
|
1780
|
+
runEphemeralTurn: async (promptText, signal) => {
|
|
1781
|
+
if (!session) throw new Error("Ephemeral turns are unavailable.");
|
|
1782
|
+
const { replyText } = await session.runEphemeralTurn({ promptText, signal });
|
|
1783
|
+
return { replyText };
|
|
1784
|
+
},
|
|
1757
1785
|
});
|
|
1758
1786
|
} catch (error) {
|
|
1759
1787
|
lifecycleStartupCapability?.settleFailure(
|
|
@@ -1904,12 +1932,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1904
1932
|
// No runner to forward to; release our subscription. The embedder's own
|
|
1905
1933
|
// onCredentialDisabled (if any) keeps firing through its own subscription.
|
|
1906
1934
|
startupCredentialDisabledEvents.length = 0;
|
|
1907
|
-
|
|
1908
|
-
unsubscribeCredentialDisabled = undefined;
|
|
1935
|
+
releaseCredentialDisabledSubscription();
|
|
1909
1936
|
}
|
|
1910
1937
|
|
|
1911
1938
|
const getSessionContext = () => ({
|
|
1912
|
-
sessionManager,
|
|
1939
|
+
sessionManager: createReadonlySessionManager(sessionManager),
|
|
1913
1940
|
modelRegistry,
|
|
1914
1941
|
model: agent.state.model,
|
|
1915
1942
|
isIdle: () => !session.isStreaming,
|
|
@@ -1938,7 +1965,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1938
1965
|
// Without extension runner: wrap CustomTools directly with CustomToolAdapter
|
|
1939
1966
|
// ToolDefinition items require ExtensionContext and cannot be used without a runner
|
|
1940
1967
|
const customToolContext = (): CustomToolContext => ({
|
|
1941
|
-
sessionManager,
|
|
1968
|
+
sessionManager: createReadonlySessionManager(sessionManager),
|
|
1942
1969
|
modelRegistry,
|
|
1943
1970
|
model: agent?.state.model,
|
|
1944
1971
|
isIdle: () => !session?.isStreaming,
|
|
@@ -2040,36 +2067,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2040
2067
|
candidateModel?: Model,
|
|
2041
2068
|
): Promise<BuildSystemPromptResult> => {
|
|
2042
2069
|
toolContextStore.setToolNames(toolNames);
|
|
2043
|
-
const
|
|
2070
|
+
const promptTools = (() => {
|
|
2044
2071
|
const previousPromptMetadataModel = promptMetadataModel;
|
|
2045
2072
|
promptMetadataModel = candidateModel;
|
|
2046
2073
|
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 };
|
|
2074
|
+
return buildSystemPromptToolMetadata(tools);
|
|
2073
2075
|
} finally {
|
|
2074
2076
|
promptMetadataModel = previousPromptMetadataModel;
|
|
2075
2077
|
}
|
|
@@ -2080,25 +2082,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2080
2082
|
session,
|
|
2081
2083
|
);
|
|
2082
2084
|
|
|
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
|
-
}
|
|
2085
|
+
const appendPrompt: string | undefined = memoryInstructions ?? undefined;
|
|
2102
2086
|
let pluginSystemAppendices = "";
|
|
2103
2087
|
try {
|
|
2104
2088
|
pluginSystemAppendices = await renderAlwaysOnSystemAppendices({ cwd });
|
|
@@ -2118,12 +2102,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2118
2102
|
pluginAppendices: pluginSystemAppendices,
|
|
2119
2103
|
repeatToolDescriptions,
|
|
2120
2104
|
intentField,
|
|
2121
|
-
mcpDiscoveryMode: false,
|
|
2122
|
-
mcpDiscoveryServerSummaries: [],
|
|
2123
2105
|
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
2106
|
eagerTasks,
|
|
2128
2107
|
secretsEnabled,
|
|
2129
2108
|
workspaceTree: workspaceTreePromise,
|
|
@@ -2152,12 +2131,15 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2152
2131
|
: toolNamesFromRegistry;
|
|
2153
2132
|
const normalizedRequested = requestedToolNames.filter(name => toolRegistry.has(name));
|
|
2154
2133
|
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.
|
|
2134
|
+
// Normalize the user-facing mcp.discoveryMode alias once at session construction.
|
|
2158
2135
|
const toolsDiscoveryModeSetting = settings.get("tools.discoveryMode");
|
|
2159
|
-
const effectiveDiscoveryMode: "off" | "
|
|
2160
|
-
|
|
2136
|
+
const effectiveDiscoveryMode: "off" | "mcp-only" | "all" =
|
|
2137
|
+
toolsDiscoveryModeSetting !== "off"
|
|
2138
|
+
? (toolsDiscoveryModeSetting as "mcp-only" | "all")
|
|
2139
|
+
: settings.get("mcp.discoveryMode") || explicitMcpConfigPath !== undefined
|
|
2140
|
+
? "mcp-only"
|
|
2141
|
+
: "off";
|
|
2142
|
+
const mcpDiscoveryEnabled = effectiveDiscoveryMode !== "off";
|
|
2161
2143
|
const defaultInactiveToolNames = new Set(
|
|
2162
2144
|
registeredTools.filter(tool => tool.definition.defaultInactive).map(tool => tool.definition.name),
|
|
2163
2145
|
);
|
|
@@ -2190,7 +2172,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2190
2172
|
toolRegistry.has(name),
|
|
2191
2173
|
);
|
|
2192
2174
|
defaultSelectedMCPToolNames = [
|
|
2193
|
-
...new Set([
|
|
2175
|
+
...new Set([
|
|
2176
|
+
...discoveryDefaultServerToolNames,
|
|
2177
|
+
...explicitlyRequestedMCPToolNames,
|
|
2178
|
+
...(explicitMcpConfigPath !== undefined ? exactMcpToolNames : []),
|
|
2179
|
+
]),
|
|
2194
2180
|
];
|
|
2195
2181
|
initialSelectedMCPToolNames = existingSession.hasPersistedMCPToolSelection
|
|
2196
2182
|
? restoredSelectedMCPToolNames
|
|
@@ -2303,11 +2289,13 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2303
2289
|
if (!obfuscator?.hasSecrets()) return converted;
|
|
2304
2290
|
return obfuscateMessages(obfuscator, converted);
|
|
2305
2291
|
};
|
|
2306
|
-
const transformContext =
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2292
|
+
const transformContext = async (messages: AgentMessage[], _signal?: AbortSignal) => {
|
|
2293
|
+
// External Agent events dispatch listeners without awaiting them. The
|
|
2294
|
+
// session-owned barrier makes any pre-admission artifact transformation
|
|
2295
|
+
// visible before this provider context is normalized.
|
|
2296
|
+
await session?.awaitPendingContextTransformations();
|
|
2297
|
+
return extensionRunner ? await extensionRunner.emitContext(messages) : messages;
|
|
2298
|
+
};
|
|
2311
2299
|
const onPayload = extensionRunner
|
|
2312
2300
|
? async (payload: unknown, _model?: Model) => {
|
|
2313
2301
|
return await extensionRunner.emitBeforeProviderRequest(payload);
|
|
@@ -2524,28 +2512,14 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2524
2512
|
onResponse,
|
|
2525
2513
|
convertToLlm: convertToLlmFinal,
|
|
2526
2514
|
rebuildSystemPrompt,
|
|
2515
|
+
getMcpServerInstructions:
|
|
2516
|
+
explicitMcpConfigPath === undefined && mcpManager ? () => mcpManager.getServerInstructions() : undefined,
|
|
2527
2517
|
workspaceTree: resolvedWorkspaceTree,
|
|
2528
2518
|
reloadSshTool,
|
|
2529
2519
|
requestedToolNames: requestedToolNameSet,
|
|
2530
2520
|
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
2521
|
mcpDiscoveryEnabled,
|
|
2522
|
+
discoveryMode: effectiveDiscoveryMode,
|
|
2549
2523
|
initialSelectedMCPToolNames,
|
|
2550
2524
|
defaultSelectedMCPToolNames,
|
|
2551
2525
|
persistInitialMCPToolSelection: !hasExistingSession,
|
|
@@ -2580,9 +2554,13 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2580
2554
|
try {
|
|
2581
2555
|
await originalDispose();
|
|
2582
2556
|
} finally {
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2557
|
+
try {
|
|
2558
|
+
agentRegistry.unregister(resolvedAgentId);
|
|
2559
|
+
releaseCredentialDisabledSubscription();
|
|
2560
|
+
releaseLocalProtocolOverride();
|
|
2561
|
+
} finally {
|
|
2562
|
+
closeOwnedAuthStorage();
|
|
2563
|
+
}
|
|
2586
2564
|
}
|
|
2587
2565
|
};
|
|
2588
2566
|
}
|
|
@@ -2697,9 +2675,8 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2697
2675
|
};
|
|
2698
2676
|
} catch (error) {
|
|
2699
2677
|
// Release the subscription if the throw happened after install but before the
|
|
2700
|
-
// dispose-wrap took ownership.
|
|
2701
|
-
|
|
2702
|
-
unsubscribeCredentialDisabled?.();
|
|
2678
|
+
// dispose-wrap took ownership.
|
|
2679
|
+
releaseCredentialDisabledSubscription();
|
|
2703
2680
|
try {
|
|
2704
2681
|
if (hasSession) {
|
|
2705
2682
|
await session.dispose();
|
|
@@ -2713,6 +2690,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2713
2690
|
logger.warn("Failed to clean up createAgentSession resources after startup error");
|
|
2714
2691
|
} finally {
|
|
2715
2692
|
releaseLocalProtocolOverride();
|
|
2693
|
+
try {
|
|
2694
|
+
closeOwnedAuthStorage();
|
|
2695
|
+
} catch {
|
|
2696
|
+
logger.warn("Failed to close owned auth storage after startup error");
|
|
2697
|
+
}
|
|
2716
2698
|
}
|
|
2717
2699
|
throw error;
|
|
2718
2700
|
}
|