@oh-my-pi/pi-coding-agent 17.0.8 → 17.1.0
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 +87 -1
- package/README.md +1 -1
- package/dist/cli.js +5495 -5021
- package/dist/types/async/job-manager.d.ts +37 -1
- package/dist/types/cli/args.d.ts +2 -0
- package/dist/types/cli/bench-cli.d.ts +41 -0
- package/dist/types/commands/bench.d.ts +15 -3
- package/dist/types/commands/launch.d.ts +4 -0
- package/dist/types/config/__tests__/model-registry.test.d.ts +1 -0
- package/dist/types/config/model-registry.d.ts +30 -1
- package/dist/types/config/models-config-schema.d.ts +18 -6
- package/dist/types/config/models-config.d.ts +14 -5
- package/dist/types/config/provider-globals.d.ts +2 -2
- package/dist/types/config/service-tier.d.ts +5 -1
- package/dist/types/config/settings-schema.d.ts +350 -50
- package/dist/types/config/settings.d.ts +7 -0
- package/dist/types/dap/client.d.ts +20 -0
- package/dist/types/exec/bash-executor.d.ts +38 -0
- package/dist/types/exec/direnv.d.ts +33 -0
- package/dist/types/export/html/args.d.ts +15 -0
- package/dist/types/export/html/index.d.ts +11 -26
- package/dist/types/export/html/web-palette.d.ts +55 -116
- package/dist/types/extensibility/extensions/loader.d.ts +3 -0
- package/dist/types/extensibility/extensions/types.d.ts +17 -2
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +1 -0
- package/dist/types/extensibility/legacy-pi-tui-shim.d.ts +10 -0
- package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +14 -1
- package/dist/types/internal-urls/registry-helpers.d.ts +11 -0
- package/dist/types/live/controller.d.ts +40 -0
- package/dist/types/live/protocol.d.ts +85 -0
- package/dist/types/live/protocol.test.d.ts +1 -0
- package/dist/types/live/transport.d.ts +48 -0
- package/dist/types/live/visualizer.d.ts +33 -0
- package/dist/types/lsp/client.d.ts +18 -1
- package/dist/types/mcp/config-writer.test.d.ts +1 -0
- package/dist/types/mcp/manager.d.ts +6 -2
- package/dist/types/mcp/oauth-discovery.d.ts +2 -0
- package/dist/types/mcp/render.d.ts +2 -2
- package/dist/types/mcp/smithery-auth.d.ts +1 -1
- package/dist/types/mcp/smithery-auth.test.d.ts +1 -0
- package/dist/types/mcp/tool-bridge.d.ts +7 -3
- package/dist/types/mcp/types.d.ts +6 -0
- package/dist/types/memory-backend/tool-names.d.ts +2 -0
- package/dist/types/modes/components/login-dialog.d.ts +2 -2
- package/dist/types/modes/components/oauth-selector.d.ts +8 -0
- package/dist/types/modes/components/plan-review-overlay.d.ts +26 -0
- package/dist/types/modes/components/settings-defs.d.ts +8 -1
- package/dist/types/modes/components/status-line/component.jj-cache.test.d.ts +1 -0
- package/dist/types/modes/components/tool-execution.d.ts +9 -1
- package/dist/types/modes/controllers/command-controller.d.ts +1 -1
- package/dist/types/modes/controllers/event-controller.d.ts +6 -1
- package/dist/types/modes/controllers/live-command-controller.d.ts +14 -0
- package/dist/types/modes/controllers/mcp-command-controller.d.ts +3 -0
- package/dist/types/modes/interactive-mode.d.ts +5 -0
- package/dist/types/modes/rpc/rpc-client.d.ts +10 -1
- package/dist/types/modes/rpc/rpc-frame.d.ts +16 -0
- package/dist/types/modes/rpc/rpc-messages.d.ts +26 -0
- package/dist/types/modes/rpc/rpc-types.d.ts +40 -0
- package/dist/types/modes/setup-wizard/scenes/sign-in.d.ts +1 -1
- package/dist/types/modes/setup-wizard/scenes/types.d.ts +9 -1
- package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +1 -1
- package/dist/types/modes/theme/theme.d.ts +1 -1
- package/dist/types/modes/types.d.ts +3 -1
- package/dist/types/modes/utils/context-usage.d.ts +12 -2
- package/dist/types/plan-mode/plan-files.d.ts +10 -0
- package/dist/types/registry/agent-lifecycle.d.ts +21 -9
- package/dist/types/registry/agent-registry.d.ts +11 -4
- package/dist/types/sdk.d.ts +15 -1
- package/dist/types/secrets/index.d.ts +15 -2
- package/dist/types/secrets/obfuscator.d.ts +113 -15
- package/dist/types/session/acp-permission-gate.d.ts +19 -0
- package/dist/types/session/agent-session-events.d.ts +84 -0
- package/dist/types/session/agent-session-types.d.ts +314 -0
- package/dist/types/session/agent-session.d.ts +120 -750
- package/dist/types/session/async-job-delivery.d.ts +28 -0
- package/dist/types/session/bash-runner.d.ts +75 -0
- package/dist/types/session/blob-store.d.ts +11 -1
- package/dist/types/session/blob-store.test.d.ts +1 -0
- package/dist/types/session/checkpoint-entries.d.ts +28 -0
- package/dist/types/session/eval-runner.d.ts +49 -0
- package/dist/types/session/irc-bridge.d.ts +46 -0
- package/dist/types/session/messages.d.ts +22 -0
- package/dist/types/session/model-controls.d.ts +180 -0
- package/dist/types/session/prewalk.d.ts +46 -0
- package/dist/types/session/queued-messages.d.ts +22 -0
- package/dist/types/session/redis-session-storage.d.ts +1 -0
- package/dist/types/session/retry-fallback-chains.d.ts +74 -0
- package/dist/types/session/role-models.d.ts +15 -0
- package/dist/types/session/session-advisors.d.ts +228 -0
- package/dist/types/session/session-entries.d.ts +8 -0
- package/dist/types/session/session-handoff.d.ts +70 -0
- package/dist/types/session/session-history-format.d.ts +6 -1
- package/dist/types/session/session-loader.d.ts +6 -4
- package/dist/types/session/session-maintenance.d.ts +246 -0
- package/dist/types/session/session-manager.d.ts +41 -0
- package/dist/types/session/session-memory.d.ts +56 -0
- package/dist/types/session/session-provider-boundary.d.ts +62 -0
- package/dist/types/session/session-stats.d.ts +48 -0
- package/dist/types/session/session-tools.d.ts +143 -0
- package/dist/types/session/session-workspace.d.ts +32 -0
- package/dist/types/session/stream-guards.d.ts +44 -0
- package/dist/types/session/todo-tracker.d.ts +56 -0
- package/dist/types/session/ttsr-coordinator.d.ts +51 -0
- package/dist/types/session/turn-recovery.d.ts +225 -0
- package/dist/types/system-prompt.d.ts +2 -0
- package/dist/types/task/executor.d.ts +4 -1
- package/dist/types/task/output-manager.d.ts +3 -1
- package/dist/types/task/types.d.ts +14 -0
- package/dist/types/tools/approval.d.ts +1 -0
- package/dist/types/tools/browser/launch.d.ts +5 -0
- package/dist/types/tools/hub/jobs.d.ts +1 -1
- package/dist/types/tools/image-gen.d.ts +4 -4
- package/dist/types/tools/image-providers.d.ts +38 -0
- package/dist/types/tools/index.d.ts +8 -0
- package/dist/types/tools/path-utils.d.ts +8 -0
- package/dist/types/tools/report-tool-issue.d.ts +24 -9
- package/dist/types/tools/todo.d.ts +10 -4
- package/dist/types/tools/xdev.d.ts +5 -1
- package/dist/types/tts/streaming-player.d.ts +14 -0
- package/dist/types/tts/vocalizer.d.ts +5 -0
- package/dist/types/utils/jj.d.ts +29 -0
- package/dist/types/utils/lang-from-path.d.ts +1 -0
- package/dist/types/utils/title-generator.d.ts +30 -0
- package/dist/types/vibe/runtime.d.ts +36 -8
- package/dist/types/web/search/index.d.ts +1 -1
- package/dist/types/web/search/provider.d.ts +15 -5
- package/dist/types/web/search/providers/firecrawl.d.ts +9 -0
- package/dist/types/web/search/types.d.ts +95 -1
- package/package.json +13 -12
- package/scripts/generate-share-viewer.ts +4 -6
- package/scripts/legacy-pi-virtual-module.ts +1 -1
- package/src/advisor/__tests__/advisor.test.ts +643 -0
- package/src/advisor/runtime.ts +144 -43
- package/src/async/job-manager.ts +90 -2
- package/src/cli/args.ts +2 -0
- package/src/cli/auth-gateway-cli.ts +18 -3
- package/src/cli/bench-cli.ts +395 -29
- package/src/cli/flag-tables.ts +3 -0
- package/src/cli/gc-cli.ts +2 -2
- package/src/cli/grievances-cli.ts +2 -2
- package/src/cli/usage-cli.ts +11 -2
- package/src/collab/host.ts +3 -2
- package/src/commands/bench.ts +18 -4
- package/src/commands/launch.ts +4 -0
- package/src/config/__tests__/model-registry.test.ts +147 -0
- package/src/config/model-registry.ts +50 -2
- package/src/config/model-resolver.ts +0 -1
- package/src/config/models-config-schema.ts +15 -4
- package/src/config/provider-globals.ts +9 -9
- package/src/config/service-tier.ts +26 -1
- package/src/config/settings-schema.ts +250 -54
- package/src/config/settings.ts +81 -2
- package/src/dap/client.ts +37 -4
- package/src/edit/index.ts +49 -12
- package/src/eval/py/executor.ts +103 -33
- package/src/exec/bash-executor.ts +89 -6
- package/src/exec/direnv.ts +145 -0
- package/src/export/html/args.ts +20 -0
- package/src/export/html/index.ts +45 -47
- package/src/export/html/template.css +19 -1
- package/src/export/html/template.html +6 -0
- package/src/export/html/template.js +21 -0
- package/src/export/html/tool-views.generated.js +31 -31
- package/src/export/html/web-palette.ts +116 -132
- package/src/export/share.ts +249 -49
- package/src/extensibility/extensions/loader.ts +29 -1
- package/src/extensibility/extensions/runner.ts +6 -0
- package/src/extensibility/extensions/types.ts +33 -2
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +1 -0
- package/src/extensibility/legacy-pi-tui-shim.ts +10 -0
- package/src/extensibility/plugins/legacy-pi-compat.ts +870 -311
- package/src/hindsight/state.ts +64 -6
- package/src/internal-urls/local-protocol.ts +2 -1
- package/src/internal-urls/memory-protocol.ts +2 -2
- package/src/internal-urls/registry-helpers.ts +40 -0
- package/src/internal-urls/skill-protocol.ts +2 -2
- package/src/internal-urls/ssh-protocol.ts +2 -1
- package/src/internal-urls/vault-protocol.ts +2 -1
- package/src/live/audio-worklet.txt +59 -0
- package/src/live/browser-runtime.txt +221 -0
- package/src/live/controller.ts +464 -0
- package/src/live/prompts/agent-final-message.md +3 -0
- package/src/live/prompts/live-instructions.md +23 -0
- package/src/live/protocol.test.ts +140 -0
- package/src/live/protocol.ts +233 -0
- package/src/live/transport.ts +490 -0
- package/src/live/visualizer.ts +234 -0
- package/src/lsp/client.ts +52 -9
- package/src/lsp/clients/biome-client.ts +3 -4
- package/src/lsp/index.ts +44 -11
- package/src/main.ts +9 -1
- package/src/mcp/config-writer.test.ts +43 -0
- package/src/mcp/config-writer.ts +109 -82
- package/src/mcp/manager.ts +39 -8
- package/src/mcp/oauth-discovery.ts +10 -2
- package/src/mcp/render.ts +94 -35
- package/src/mcp/smithery-auth.test.ts +29 -0
- package/src/mcp/smithery-auth.ts +3 -2
- package/src/mcp/tool-bridge.ts +107 -11
- package/src/mcp/types.ts +7 -0
- package/src/memories/index.ts +40 -20
- package/src/memory-backend/tool-names.ts +2 -0
- package/src/mnemopi/backend.ts +24 -7
- package/src/modes/acp/acp-agent.ts +56 -10
- package/src/modes/acp/acp-event-mapper.ts +8 -1
- package/src/modes/components/agent-hub.ts +27 -10
- package/src/modes/components/login-dialog.ts +14 -4
- package/src/modes/components/oauth-selector.ts +24 -7
- package/src/modes/components/plan-review-overlay.ts +350 -35
- package/src/modes/components/settings-defs.ts +28 -3
- package/src/modes/components/settings-selector.ts +178 -6
- package/src/modes/components/status-line/component.jj-cache.test.ts +229 -0
- package/src/modes/components/status-line/component.ts +123 -2
- package/src/modes/components/tool-execution.test.ts +63 -2
- package/src/modes/components/tool-execution.ts +11 -2
- package/src/modes/controllers/command-controller.ts +70 -22
- package/src/modes/controllers/event-controller.ts +111 -16
- package/src/modes/controllers/extension-ui-controller.test.ts +1 -0
- package/src/modes/controllers/extension-ui-controller.ts +20 -4
- package/src/modes/controllers/live-command-controller.ts +178 -0
- package/src/modes/controllers/mcp-command-controller.ts +80 -41
- package/src/modes/controllers/omfg-controller.ts +44 -40
- package/src/modes/controllers/selector-controller.ts +18 -10
- package/src/modes/controllers/session-focus-controller.ts +6 -1
- package/src/modes/interactive-mode.ts +160 -38
- package/src/modes/rpc/rpc-client.ts +94 -3
- package/src/modes/rpc/rpc-frame.ts +164 -4
- package/src/modes/rpc/rpc-messages.ts +127 -0
- package/src/modes/rpc/rpc-mode.ts +79 -7
- package/src/modes/rpc/rpc-types.ts +34 -2
- package/src/modes/runtime-init.ts +2 -0
- package/src/modes/setup-wizard/scenes/model.ts +5 -7
- package/src/modes/setup-wizard/scenes/providers.ts +3 -2
- package/src/modes/setup-wizard/scenes/sign-in.ts +8 -2
- package/src/modes/setup-wizard/scenes/theme.ts +13 -3
- package/src/modes/setup-wizard/scenes/types.ts +9 -1
- package/src/modes/setup-wizard/scenes/web-search.ts +23 -10
- package/src/modes/setup-wizard/wizard-overlay.ts +1 -1
- package/src/modes/theme/theme.ts +1 -1
- package/src/modes/types.ts +3 -1
- package/src/modes/utils/context-usage.ts +23 -7
- package/src/modes/utils/ui-helpers.ts +10 -5
- package/src/plan-mode/plan-files.ts +40 -0
- package/src/prompts/bench/cache-prefix-chunk.md +1 -0
- package/src/prompts/bench/cache-prefix.md +3 -0
- package/src/prompts/bench/cache-suffix.md +1 -0
- package/src/prompts/goals/guided-goal-system.md +24 -3
- package/src/prompts/system/custom-system-prompt.md +1 -1
- package/src/prompts/system/project-prompt.md +8 -1
- package/src/prompts/system/subagent-async-pending.md +6 -0
- package/src/prompts/system/system-prompt.md +1 -1
- package/src/prompts/system/workflow-notice.md +48 -40
- package/src/prompts/system/xdev-mount-notice.md +4 -0
- package/src/prompts/tools/task.md +12 -2
- package/src/prompts/tools/todo.md +3 -1
- package/src/registry/agent-lifecycle.ts +116 -46
- package/src/registry/agent-registry.ts +35 -8
- package/src/registry/persisted-agents.ts +26 -2
- package/src/sdk.ts +255 -139
- package/src/secrets/index.ts +127 -4
- package/src/secrets/obfuscator.ts +2328 -105
- package/src/session/acp-permission-gate.ts +165 -0
- package/src/session/agent-session-error-log.test.ts +1 -1
- package/src/session/agent-session-events.ts +66 -0
- package/src/session/agent-session-types.ts +334 -0
- package/src/session/agent-session.ts +1910 -12213
- package/src/session/artifacts.ts +6 -5
- package/src/session/async-job-delivery.ts +74 -0
- package/src/session/bash-runner.ts +326 -0
- package/src/session/blob-store.test.ts +56 -0
- package/src/session/blob-store.ts +18 -2
- package/src/session/checkpoint-entries.ts +81 -0
- package/src/session/eval-runner.ts +212 -0
- package/src/session/indexed-session-storage.ts +9 -2
- package/src/session/irc-bridge.ts +203 -0
- package/src/session/messages.ts +263 -1
- package/src/session/model-controls.ts +714 -0
- package/src/session/prewalk.ts +252 -0
- package/src/session/queued-messages.ts +93 -0
- package/src/session/redis-session-storage.ts +51 -11
- package/src/session/retry-fallback-chains.ts +455 -0
- package/src/session/role-models.ts +85 -0
- package/src/session/session-advisors.ts +1679 -0
- package/src/session/session-context.test.ts +224 -1
- package/src/session/session-context.ts +47 -5
- package/src/session/session-entries.ts +8 -0
- package/src/session/session-handoff.ts +308 -0
- package/src/session/session-history-format.ts +20 -9
- package/src/session/session-loader.ts +10 -51
- package/src/session/session-maintenance.ts +2983 -0
- package/src/session/session-manager.ts +390 -30
- package/src/session/session-memory.ts +222 -0
- package/src/session/session-provider-boundary.ts +307 -0
- package/src/session/session-stats.ts +293 -0
- package/src/session/session-tools.ts +943 -0
- package/src/session/session-workspace.ts +53 -0
- package/src/session/stream-guards.ts +417 -0
- package/src/session/todo-tracker.ts +380 -0
- package/src/session/ttsr-coordinator.ts +496 -0
- package/src/session/turn-recovery.ts +1629 -0
- package/src/slash-commands/builtin-registry.ts +92 -11
- package/src/slash-commands/helpers/usage-report.ts +25 -4
- package/src/system-prompt.ts +41 -17
- package/src/task/executor.ts +288 -70
- package/src/task/index.ts +148 -111
- package/src/task/output-manager.ts +25 -3
- package/src/task/persisted-revive.ts +4 -3
- package/src/task/structured-subagent.ts +4 -1
- package/src/task/types.ts +16 -0
- package/src/tools/approval.ts +55 -10
- package/src/tools/bash-interactive.ts +26 -0
- package/src/tools/bash-skill-urls.ts +28 -2
- package/src/tools/bash.ts +339 -123
- package/src/tools/browser/launch.ts +9 -1
- package/src/tools/browser/tab-supervisor.ts +8 -5
- package/src/tools/browser.ts +94 -47
- package/src/tools/hub/index.ts +1 -1
- package/src/tools/hub/jobs.ts +67 -8
- package/src/tools/image-gen.ts +20 -28
- package/src/tools/image-providers.ts +50 -0
- package/src/tools/index.ts +12 -0
- package/src/tools/path-utils.ts +49 -2
- package/src/tools/read.ts +156 -88
- package/src/tools/renderers.ts +7 -1
- package/src/tools/report-tool-issue.ts +79 -28
- package/src/tools/todo.ts +101 -11
- package/src/tools/vibe.ts +1 -2
- package/src/tools/write.ts +51 -1
- package/src/tools/xdev.ts +67 -3
- package/src/tts/streaming-player.ts +62 -4
- package/src/tts/vocalizer.ts +18 -1
- package/src/utils/jj.ts +125 -4
- package/src/utils/lang-from-path.ts +7 -0
- package/src/utils/title-generator.ts +137 -1
- package/src/vibe/runtime.ts +852 -72
- package/src/web/search/index.ts +3 -6
- package/src/web/search/provider.ts +31 -16
- package/src/web/search/providers/firecrawl.ts +46 -13
- package/src/web/search/providers/xai.ts +7 -1
- package/src/web/search/types.ts +8 -1
package/src/sdk.ts
CHANGED
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
CredentialDisabledEvent,
|
|
15
15
|
Message,
|
|
16
16
|
Model,
|
|
17
|
+
ModelUsageHealth,
|
|
17
18
|
ProviderSessionState,
|
|
18
19
|
SimpleStreamOptions,
|
|
19
20
|
} from "@oh-my-pi/pi-ai";
|
|
@@ -32,7 +33,7 @@ import {
|
|
|
32
33
|
formatActiveRepoWatchdogPrompt,
|
|
33
34
|
formatAdvisorContextPrompt,
|
|
34
35
|
} from "./advisor";
|
|
35
|
-
import {
|
|
36
|
+
import { AsyncJobManager } from "./async";
|
|
36
37
|
import { AutoLearnController, buildAutoLearnInstructions } from "./autolearn/controller";
|
|
37
38
|
import { createAutoresearchExtension } from "./autoresearch";
|
|
38
39
|
import { loadCapability } from "./capability";
|
|
@@ -55,6 +56,7 @@ import {
|
|
|
55
56
|
resolveModelRoleValue,
|
|
56
57
|
} from "./config/model-resolver";
|
|
57
58
|
import { loadPromptTemplates as loadPromptTemplatesInternal, type PromptTemplate } from "./config/prompt-templates";
|
|
59
|
+
import { applyProviderGlobalsFromSettings } from "./config/provider-globals";
|
|
58
60
|
import { buildServiceTierByFamily } from "./config/service-tier";
|
|
59
61
|
import { Settings, type SkillsSettings } from "./config/settings";
|
|
60
62
|
import { CursorExecHandlers } from "./cursor";
|
|
@@ -105,19 +107,22 @@ import {
|
|
|
105
107
|
} from "./mcp";
|
|
106
108
|
import { MCP_CONNECTION_STATUS_EVENT_CHANNEL, type McpConnectionStatusEvent } from "./mcp/startup-events";
|
|
107
109
|
import { createSessionMemoryRuntimeContext, resolveMemoryBackend } from "./memory-backend";
|
|
110
|
+
import { MEMORY_BACKEND_TOOL_NAMES } from "./memory-backend/tool-names";
|
|
108
111
|
import type { MnemopiSessionState } from "./mnemopi/state";
|
|
109
|
-
import asyncResultTemplate from "./prompts/tools/async-result.md" with { type: "text" };
|
|
110
112
|
import lateDiagnosticTemplate from "./prompts/tools/lsp-late-diagnostic.md" with { type: "text" };
|
|
111
113
|
import { AgentLifecycleManager } from "./registry/agent-lifecycle";
|
|
112
|
-
import { AgentRegistry, MAIN_AGENT_ID } from "./registry/agent-registry";
|
|
114
|
+
import { type AgentRef, AgentRegistry, MAIN_AGENT_ID } from "./registry/agent-registry";
|
|
113
115
|
import {
|
|
114
116
|
collectEnvSecrets,
|
|
115
117
|
deobfuscateSessionContext,
|
|
116
118
|
deobfuscateToolArguments,
|
|
119
|
+
getExistingSecretPlaceholderKey,
|
|
120
|
+
getSecretPlaceholderKey,
|
|
117
121
|
loadSecrets,
|
|
118
122
|
obfuscateMessages,
|
|
119
123
|
obfuscateProviderContext,
|
|
120
124
|
SecretObfuscator,
|
|
125
|
+
secretEntriesNeedPlaceholderKey,
|
|
121
126
|
} from "./secrets";
|
|
122
127
|
import { AgentSession, type InitialRetryFallbackState, type PlanYolo, type Prewalk } from "./session/agent-session";
|
|
123
128
|
import { discoverAuthStorage as discoverAuthStorageFromConfig } from "./session/auth-broker-config";
|
|
@@ -132,6 +137,12 @@ import {
|
|
|
132
137
|
wrapSteeringForModel,
|
|
133
138
|
} from "./session/messages";
|
|
134
139
|
import { clampProviderContextImages } from "./session/provider-image-budget";
|
|
140
|
+
import {
|
|
141
|
+
expandDefaultRetryFallbackChains,
|
|
142
|
+
findRetryFallbackCandidates,
|
|
143
|
+
type RetryFallbackResolutionContext,
|
|
144
|
+
resolveRetryFallbackChainKey,
|
|
145
|
+
} from "./session/retry-fallback-chains";
|
|
135
146
|
import { getRestorableSessionModels } from "./session/session-context";
|
|
136
147
|
import { SessionManager } from "./session/session-manager";
|
|
137
148
|
import { createSettingsAwareStreamFn } from "./session/settings-stream-fn";
|
|
@@ -173,15 +184,9 @@ import {
|
|
|
173
184
|
GrepTool,
|
|
174
185
|
getSearchTools,
|
|
175
186
|
HIDDEN_TOOLS,
|
|
176
|
-
isImageProviderPreference,
|
|
177
187
|
isMountableUnderXdev,
|
|
178
|
-
isSearchProviderId,
|
|
179
|
-
isSearchProviderPreference,
|
|
180
188
|
type LspStartupServerInfo,
|
|
181
189
|
ReadTool,
|
|
182
|
-
setExcludedSearchProviders,
|
|
183
|
-
setPreferredImageProvider,
|
|
184
|
-
setPreferredSearchProvider,
|
|
185
190
|
type Tool,
|
|
186
191
|
type ToolSession,
|
|
187
192
|
WebSearchTool,
|
|
@@ -199,62 +204,14 @@ import { ttsTool } from "./tools/tts";
|
|
|
199
204
|
import { resolveActiveRepoContext } from "./utils/active-repo-context";
|
|
200
205
|
import { EventBus } from "./utils/event-bus";
|
|
201
206
|
import { buildNamedToolChoice } from "./utils/tool-choice";
|
|
207
|
+
import { VibeSessionRegistry } from "./vibe/runtime";
|
|
202
208
|
import { buildWorkspaceTree, type WorkspaceTree } from "./workspace-tree";
|
|
203
209
|
|
|
204
|
-
type AsyncResultEntry = {
|
|
205
|
-
jobId: string;
|
|
206
|
-
result: string;
|
|
207
|
-
job: AsyncJob | undefined;
|
|
208
|
-
durationMs: number | undefined;
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
type AsyncResultJobDetails = {
|
|
212
|
-
jobId: string;
|
|
213
|
-
type?: "bash" | "task";
|
|
214
|
-
label?: string;
|
|
215
|
-
durationMs?: number;
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
type AsyncResultDetails = {
|
|
219
|
-
jobs: AsyncResultJobDetails[];
|
|
220
|
-
};
|
|
221
|
-
|
|
222
210
|
type McpNotificationEntry = {
|
|
223
211
|
serverName: string;
|
|
224
212
|
uri: string;
|
|
225
213
|
};
|
|
226
214
|
|
|
227
|
-
function buildAsyncResultBatchMessage(entries: AsyncResultEntry[]): CustomMessage<AsyncResultDetails> | null {
|
|
228
|
-
if (entries.length === 0) return null;
|
|
229
|
-
const jobs = entries.map(entry => ({
|
|
230
|
-
jobId: entry.jobId,
|
|
231
|
-
result: entry.result,
|
|
232
|
-
type: entry.job?.type,
|
|
233
|
-
label: entry.job?.label,
|
|
234
|
-
durationMs: entry.durationMs,
|
|
235
|
-
}));
|
|
236
|
-
const details: AsyncResultDetails = {
|
|
237
|
-
jobs: jobs.map(job => ({
|
|
238
|
-
jobId: job.jobId,
|
|
239
|
-
type: job.type,
|
|
240
|
-
label: job.label,
|
|
241
|
-
durationMs: job.durationMs,
|
|
242
|
-
})),
|
|
243
|
-
};
|
|
244
|
-
return {
|
|
245
|
-
role: "custom",
|
|
246
|
-
customType: "async-result",
|
|
247
|
-
content: prompt.render(asyncResultTemplate, {
|
|
248
|
-
multiple: jobs.length > 1,
|
|
249
|
-
jobs,
|
|
250
|
-
}),
|
|
251
|
-
display: true,
|
|
252
|
-
attribution: "agent",
|
|
253
|
-
details,
|
|
254
|
-
timestamp: Date.now(),
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
|
-
|
|
258
215
|
type LateDiagnosticsDetails = {
|
|
259
216
|
files: Array<{ path: string; summary: string; errored: boolean; messages: string[] }>;
|
|
260
217
|
};
|
|
@@ -371,6 +328,8 @@ function applyMCPEnvironment(result: { exaApiKeys: string[] }): void {
|
|
|
371
328
|
export interface CreateAgentSessionOptions {
|
|
372
329
|
/** Working directory for project-local discovery. Default: getProjectDir() */
|
|
373
330
|
cwd?: string;
|
|
331
|
+
/** Additional workspace directories beyond cwd (multi-root), absolute or cwd-relative. */
|
|
332
|
+
additionalDirectories?: string[];
|
|
374
333
|
/** Global config directory. Default: ~/.omp/agent */
|
|
375
334
|
agentDir?: string;
|
|
376
335
|
/** Spawns to allow. Default: "*" */
|
|
@@ -525,6 +484,13 @@ export interface CreateAgentSessionOptions {
|
|
|
525
484
|
agentDisplayName?: string;
|
|
526
485
|
/** Optional shared agent registry for IRC routing. Default: AgentRegistry.global(). */
|
|
527
486
|
agentRegistry?: AgentRegistry;
|
|
487
|
+
/**
|
|
488
|
+
* Registry generation authorized for this creation. `null` requires the id
|
|
489
|
+
* to be absent; an AgentRef allows a parked revival to reuse only that ref.
|
|
490
|
+
* Undefined preserves legacy unconditional registration for external SDK callers.
|
|
491
|
+
* @internal
|
|
492
|
+
*/
|
|
493
|
+
expectedAgentRef?: AgentRef | null;
|
|
528
494
|
/** Parent task ID prefix for nested artifact naming (e.g., "Extensions") */
|
|
529
495
|
parentTaskPrefix?: string;
|
|
530
496
|
/**
|
|
@@ -554,6 +520,11 @@ export interface CreateAgentSessionOptions {
|
|
|
554
520
|
|
|
555
521
|
/** Whether UI is available (enables interactive tools like ask). Default: false */
|
|
556
522
|
hasUI?: boolean;
|
|
523
|
+
/**
|
|
524
|
+
* Defer `confirm` reserve-policy fallback until AgentSession prompt-time UI is configured.
|
|
525
|
+
* ACP uses this while capabilities are negotiated without enabling UI-only tools.
|
|
526
|
+
*/
|
|
527
|
+
deferUsageReserveConfirmation?: boolean;
|
|
557
528
|
|
|
558
529
|
/**
|
|
559
530
|
* Opt-in OpenTelemetry instrumentation forwarded to the underlying Agent.
|
|
@@ -1292,26 +1263,22 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1292
1263
|
discoveredSkillsPromise?.catch(() => {});
|
|
1293
1264
|
|
|
1294
1265
|
// Initialize provider preferences from settings
|
|
1295
|
-
|
|
1296
|
-
if (Array.isArray(excludedWebSearchProviders)) {
|
|
1297
|
-
setExcludedSearchProviders(excludedWebSearchProviders.filter(isSearchProviderId));
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
|
-
const webSearchProvider = settings.get("providers.webSearch");
|
|
1301
|
-
if (typeof webSearchProvider === "string" && isSearchProviderPreference(webSearchProvider)) {
|
|
1302
|
-
setPreferredSearchProvider(webSearchProvider);
|
|
1303
|
-
}
|
|
1304
|
-
|
|
1305
|
-
const imageProvider = settings.get("providers.image");
|
|
1306
|
-
if (isImageProviderPreference(imageProvider)) {
|
|
1307
|
-
setPreferredImageProvider(imageProvider);
|
|
1308
|
-
}
|
|
1266
|
+
applyProviderGlobalsFromSettings(settings);
|
|
1309
1267
|
|
|
1310
1268
|
const sessionManager =
|
|
1311
1269
|
options.sessionManager ??
|
|
1312
1270
|
logger.time("sessionManager", () =>
|
|
1313
1271
|
SessionManager.create(cwd, SessionManager.getDefaultSessionDir(cwd, agentDir)),
|
|
1314
1272
|
);
|
|
1273
|
+
const configuredDirs = options.additionalDirectories
|
|
1274
|
+
? options.additionalDirectories
|
|
1275
|
+
: settings.get("workspace.additionalDirectories");
|
|
1276
|
+
if (configuredDirs.length > 0) {
|
|
1277
|
+
// Merge with any roots restored from the session header (resume/fork), not replace.
|
|
1278
|
+
const existing = sessionManager.getAdditionalDirectories();
|
|
1279
|
+
const merged = [...new Set([...existing, ...configuredDirs])];
|
|
1280
|
+
await sessionManager.setAdditionalDirectories(merged);
|
|
1281
|
+
}
|
|
1315
1282
|
const providerSessionId = options.providerSessionId ?? sessionManager.getSessionId();
|
|
1316
1283
|
const forkCacheShapeChanged =
|
|
1317
1284
|
options.model !== undefined ||
|
|
@@ -1349,8 +1316,30 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1349
1316
|
const fileEntries = await logger.time("loadSecrets", loadSecrets, cwd, agentDir);
|
|
1350
1317
|
const envEntries = collectEnvSecrets();
|
|
1351
1318
|
const allEntries = [...envEntries, ...fileEntries];
|
|
1319
|
+
const needsPlaceholderKey = secretEntriesNeedPlaceholderKey(allEntries);
|
|
1320
|
+
const placeholderKey = needsPlaceholderKey
|
|
1321
|
+
? await getSecretPlaceholderKey(agentDir)
|
|
1322
|
+
: await getExistingSecretPlaceholderKey(agentDir);
|
|
1352
1323
|
if (allEntries.length > 0) {
|
|
1353
|
-
|
|
1324
|
+
// The persisted placeholder key — and creating its key file under the
|
|
1325
|
+
// configured agentDir — is only needed for reversible obfuscate-mode
|
|
1326
|
+
// placeholders, or for a default (no custom `replacement`) replace-mode
|
|
1327
|
+
// regex whose key-derived idempotent fallback marker needs a stable key
|
|
1328
|
+
// across restarts (see `secretEntryNeedsPlaceholderKey`). A replace-only
|
|
1329
|
+
// secrets set with no such regex must not require the key; otherwise a
|
|
1330
|
+
// headless run with an unwritable default config root fails startup for a
|
|
1331
|
+
// feature it does not use.
|
|
1332
|
+
obfuscator = new SecretObfuscator(allEntries, placeholderKey);
|
|
1333
|
+
}
|
|
1334
|
+
if (obfuscator?.hasSecrets() !== true && placeholderKey !== undefined) {
|
|
1335
|
+
// No configured entry produced an active secret (e.g. only ignored short
|
|
1336
|
+
// plain entries, or no entries at all), but a persisted key exists. Build a
|
|
1337
|
+
// redaction-only obfuscator so a tool read of the key file does not ship the
|
|
1338
|
+
// reusable HMAC key to the provider.
|
|
1339
|
+
obfuscator = new SecretObfuscator(
|
|
1340
|
+
[{ type: "plain", mode: "replace", content: placeholderKey }],
|
|
1341
|
+
placeholderKey,
|
|
1342
|
+
);
|
|
1354
1343
|
}
|
|
1355
1344
|
}
|
|
1356
1345
|
const secretsEnabled = obfuscator?.hasSecrets() === true;
|
|
@@ -1566,28 +1555,6 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1566
1555
|
const restrictToolNames = options.restrictToolNames === true;
|
|
1567
1556
|
const enableLsp = !restrictToolNames && (options.enableLsp ?? true);
|
|
1568
1557
|
const asyncMaxJobs = Math.min(100, Math.max(1, settings.get("async.maxJobs") ?? 100));
|
|
1569
|
-
const ASYNC_INLINE_RESULT_MAX_CHARS = 12_000;
|
|
1570
|
-
const ASYNC_PREVIEW_MAX_CHARS = 4_000;
|
|
1571
|
-
const formatAsyncResultForFollowUp = async (result: string): Promise<string> => {
|
|
1572
|
-
if (result.length <= ASYNC_INLINE_RESULT_MAX_CHARS) {
|
|
1573
|
-
return result;
|
|
1574
|
-
}
|
|
1575
|
-
|
|
1576
|
-
const preview = `${result.slice(0, ASYNC_PREVIEW_MAX_CHARS)}\n\n[Output truncated. Showing first ${ASYNC_PREVIEW_MAX_CHARS.toLocaleString()} characters.]`;
|
|
1577
|
-
try {
|
|
1578
|
-
const { path: artifactPath, id: artifactId } = await sessionManager.allocateArtifactPath("async");
|
|
1579
|
-
if (artifactPath && artifactId) {
|
|
1580
|
-
await Bun.write(artifactPath, result);
|
|
1581
|
-
return `${preview}\nFull output: artifact://${artifactId}`;
|
|
1582
|
-
}
|
|
1583
|
-
} catch (error) {
|
|
1584
|
-
logger.warn("Failed to persist async follow-up artifact", {
|
|
1585
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1586
|
-
});
|
|
1587
|
-
}
|
|
1588
|
-
|
|
1589
|
-
return preview;
|
|
1590
|
-
};
|
|
1591
1558
|
// Only the first top-level session in a process owns an AsyncJobManager.
|
|
1592
1559
|
// Subagents inherit the parent's manager via `AsyncJobManager.instance()`
|
|
1593
1560
|
// (set below), and any additional top-level session spun up in-process
|
|
@@ -1596,24 +1563,12 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1596
1563
|
// owning session's manager and break the `task`/`bash` async paths
|
|
1597
1564
|
// (issue #1923). The `instance()` guard means later sessions also skip
|
|
1598
1565
|
// constructing an orphaned manager that nothing would ever route to.
|
|
1566
|
+
// Delivery is owner-routed: every AgentSession registers its own sink
|
|
1567
|
+
// (see session/async-job-delivery.ts), so the manager takes no default
|
|
1568
|
+
// onJobComplete here.
|
|
1599
1569
|
const asyncJobManager =
|
|
1600
1570
|
!options.parentTaskPrefix && !AsyncJobManager.instance()
|
|
1601
|
-
? new AsyncJobManager({
|
|
1602
|
-
maxRunningJobs: asyncMaxJobs,
|
|
1603
|
-
onJobComplete: async (jobId, result, job) => {
|
|
1604
|
-
if (!session || asyncJobManager!.isDeliverySuppressed(jobId)) return;
|
|
1605
|
-
const formattedResult = await formatAsyncResultForFollowUp(result);
|
|
1606
|
-
if (asyncJobManager!.isDeliverySuppressed(jobId)) return;
|
|
1607
|
-
|
|
1608
|
-
const durationMs = job ? Math.max(0, Date.now() - job.startTime) : undefined;
|
|
1609
|
-
session.yieldQueue.enqueue<AsyncResultEntry>("async-result", {
|
|
1610
|
-
jobId,
|
|
1611
|
-
result: formattedResult,
|
|
1612
|
-
job,
|
|
1613
|
-
durationMs,
|
|
1614
|
-
});
|
|
1615
|
-
},
|
|
1616
|
-
})
|
|
1571
|
+
? new AsyncJobManager({ maxRunningJobs: asyncMaxJobs })
|
|
1617
1572
|
: undefined;
|
|
1618
1573
|
|
|
1619
1574
|
const scopedAsyncJobManager = asyncJobManager ?? (options.parentTaskPrefix ? AsyncJobManager.instance() : undefined);
|
|
@@ -1623,15 +1578,18 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1623
1578
|
const resolvedAgentDisplayName =
|
|
1624
1579
|
options.agentDisplayName ?? ((options.taskDepth ?? 0) > 0 || options.parentTaskPrefix ? "sub" : "main");
|
|
1625
1580
|
const agentKind = (options.taskDepth ?? 0) > 0 || options.parentTaskPrefix ? ("sub" as const) : ("main" as const);
|
|
1581
|
+
let registeredAgentRef: AgentRef | undefined;
|
|
1626
1582
|
/**
|
|
1627
1583
|
* Forget the agent ref on teardown — unless the agent is being parked (or is
|
|
1628
1584
|
* already parked). Parking disposes the session but keeps the ref addressable
|
|
1629
1585
|
* (history://, revive); only process teardown / explicit kill unregisters.
|
|
1630
1586
|
*/
|
|
1631
1587
|
const unregisterUnlessParked = (): void => {
|
|
1632
|
-
|
|
1633
|
-
if (
|
|
1634
|
-
|
|
1588
|
+
const ref = registeredAgentRef;
|
|
1589
|
+
if (!ref || agentRegistry.get(resolvedAgentId) !== ref) return;
|
|
1590
|
+
if (ref.status === "parked") return;
|
|
1591
|
+
if (AgentLifecycleManager.global().isParking(resolvedAgentId, ref)) return;
|
|
1592
|
+
agentRegistry.unregister(resolvedAgentId, ref);
|
|
1635
1593
|
};
|
|
1636
1594
|
const evalKernelOwnerId = `agent-session:${Snowflake.next()}`;
|
|
1637
1595
|
|
|
@@ -1660,6 +1618,9 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1660
1618
|
isToolActive: name => activeToolNames.has(name),
|
|
1661
1619
|
setActiveToolNames,
|
|
1662
1620
|
hasUI: options.hasUI ?? false,
|
|
1621
|
+
get additionalDirectories() {
|
|
1622
|
+
return sessionManager.getAdditionalDirectories();
|
|
1623
|
+
},
|
|
1663
1624
|
enableLsp,
|
|
1664
1625
|
enableIrc: restrictToolNames ? false : options.enableIrc,
|
|
1665
1626
|
restrictToolNames,
|
|
@@ -1684,6 +1645,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1684
1645
|
prewalkArmed: options.prewalk !== undefined,
|
|
1685
1646
|
taskDepth: options.taskDepth ?? 0,
|
|
1686
1647
|
getSessionFile: () => sessionManager.getSessionFile() ?? null,
|
|
1648
|
+
sessionManager,
|
|
1687
1649
|
getEvalKernelOwnerId: () => evalKernelOwnerId,
|
|
1688
1650
|
getEvalSessionId: () =>
|
|
1689
1651
|
session?.getEvalSessionId() ?? options.parentEvalSessionId ?? defaultEvalSessionId(toolSession),
|
|
@@ -1696,6 +1658,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1696
1658
|
getAgentId: () => resolvedAgentId,
|
|
1697
1659
|
getToolByName: name => session?.getToolByName(name),
|
|
1698
1660
|
agentRegistry,
|
|
1661
|
+
// The global lifecycle releases through AgentRegistry.global(); wiring it
|
|
1662
|
+
// onto a caller-supplied registry would report a cancel while releasing an
|
|
1663
|
+
// unrelated global ref. With no lifecycle, hub cancel falls back to
|
|
1664
|
+
// dispose + unregister on the session's own registry.
|
|
1665
|
+
agentLifecycle: options.agentRegistry ? undefined : () => AgentLifecycleManager.global(),
|
|
1699
1666
|
getSessionSpawns: () => options.spawns ?? "*",
|
|
1700
1667
|
getModelString: () => (hasExplicitModel && model ? formatModelString(model) : undefined),
|
|
1701
1668
|
getActiveModelString,
|
|
@@ -2026,8 +1993,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2026
1993
|
// the background.
|
|
2027
1994
|
await modelRegistry.refreshRuntimeProviders("offline");
|
|
2028
1995
|
// Continue runtime discovery in the background (cache-aware) so startup is
|
|
2029
|
-
// only blocked on local cache reads, not provider network fetches.
|
|
2030
|
-
|
|
1996
|
+
// only blocked on local cache reads, not provider network fetches. Stash
|
|
1997
|
+
// the promise so the deferred `--model` retry below can await it instead
|
|
1998
|
+
// of starting a second concurrent discovery pass (the unfiltered
|
|
1999
|
+
// `refresh()` also covers runtime model managers).
|
|
2000
|
+
const runtimeDiscoveryPromise = modelRegistry.refreshRuntimeProviders().catch(error => {
|
|
2031
2001
|
logger.warn("runtime provider discovery failed", {
|
|
2032
2002
|
error: error instanceof Error ? error.message : String(error),
|
|
2033
2003
|
});
|
|
@@ -2076,8 +2046,42 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2076
2046
|
// registered. Use the same CLI resolver as the immediate path so bare role
|
|
2077
2047
|
// names, exact model names, and provider selectors keep one precedence rule.
|
|
2078
2048
|
if (!model && deferredModelPatterns.length > 0) {
|
|
2079
|
-
|
|
2049
|
+
// Deferred `--model` patterns almost always failed at the immediate
|
|
2050
|
+
// path (main.ts:881) precisely because discovery-backed providers
|
|
2051
|
+
// hadn't populated yet. Await the in-flight runtime discovery
|
|
2052
|
+
// already kicked off above (stash + reuse avoids a second concurrent
|
|
2053
|
+
// `#refreshRuntimeDiscoveries` pass for the same runtime model
|
|
2054
|
+
// managers; it resolves instantly when no runtime managers are
|
|
2055
|
+
// registered). `refreshRuntimeProviders()` only covers runtime model
|
|
2056
|
+
// managers, not config-discovery providers (e.g. user-configured
|
|
2057
|
+
// ollama); fall back to a full cache-aware refresh only when the
|
|
2058
|
+
// runtime pass didn't surface a match AND config-discovery providers
|
|
2059
|
+
// exist to fetch from. By then runtime managers short-circuit on the
|
|
2060
|
+
// fresh cache written by the awaited pass, closing the double-fetch
|
|
2061
|
+
// window.
|
|
2062
|
+
await logger.time("resolveModelDiscoveryDeferredRetry", () => runtimeDiscoveryPromise);
|
|
2080
2063
|
const matchPreferences = getModelMatchPreferences(settings);
|
|
2064
|
+
const runtimeResolved = deferredModelPatterns.some(pattern =>
|
|
2065
|
+
pattern.split(",").some(selector => {
|
|
2066
|
+
const trimmedSelector = selector.trim();
|
|
2067
|
+
if (!trimmedSelector) return false;
|
|
2068
|
+
const resolved = resolveCliModel({
|
|
2069
|
+
cliModel: trimmedSelector,
|
|
2070
|
+
modelRegistry,
|
|
2071
|
+
settings,
|
|
2072
|
+
preferences: matchPreferences,
|
|
2073
|
+
});
|
|
2074
|
+
return Boolean(
|
|
2075
|
+
resolved.model || (resolved.configuredPatterns && resolved.configuredPatterns.length > 0),
|
|
2076
|
+
);
|
|
2077
|
+
}),
|
|
2078
|
+
);
|
|
2079
|
+
if (!runtimeResolved && modelRegistry.getDiscoverableProviders().length > 0) {
|
|
2080
|
+
await logger.time("resolveModelDiscoveryFallbackNonRuntime", () =>
|
|
2081
|
+
modelRegistry.refresh("online-if-uncached"),
|
|
2082
|
+
);
|
|
2083
|
+
}
|
|
2084
|
+
const availableModels = modelRegistry.getAll();
|
|
2081
2085
|
const expandedModelPatterns = deferredModelPatterns.flatMap(pattern =>
|
|
2082
2086
|
pattern.split(",").flatMap(selector => {
|
|
2083
2087
|
const trimmedSelector = selector.trim();
|
|
@@ -2099,27 +2103,38 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2099
2103
|
if (!resolved.configuredRole || !settings.get("retry.modelFallback")) {
|
|
2100
2104
|
return primaryPatterns;
|
|
2101
2105
|
}
|
|
2102
|
-
const
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2106
|
+
const fallbackContext: RetryFallbackResolutionContext = {
|
|
2107
|
+
chains: expandDefaultRetryFallbackChains(settings.get("retry.fallbackChains"), [
|
|
2108
|
+
...Object.keys(settings.getModelRoles()),
|
|
2109
|
+
resolved.configuredRole,
|
|
2110
|
+
]),
|
|
2111
|
+
getModelRole: role => settings.getModelRole(role),
|
|
2112
|
+
modelLookup: modelRegistry,
|
|
2113
|
+
};
|
|
2107
2114
|
const originalSelector = resolved.configuredPatterns[0];
|
|
2115
|
+
const originalModel = parseModelPattern(originalSelector, availableModels, matchPreferences).model;
|
|
2116
|
+
const chainKey = resolveRetryFallbackChainKey(
|
|
2117
|
+
fallbackContext,
|
|
2118
|
+
originalSelector,
|
|
2119
|
+
originalModel,
|
|
2120
|
+
resolved.configuredRole,
|
|
2121
|
+
);
|
|
2122
|
+
if (!chainKey) return primaryPatterns;
|
|
2108
2123
|
const parsedOriginal = parseModelString(originalSelector, {
|
|
2109
2124
|
allowMaxSuffix: true,
|
|
2110
2125
|
allowAutoAlias: true,
|
|
2111
2126
|
isLiteralModelId: (provider, id) => modelRegistry.find(provider, id) !== undefined,
|
|
2112
2127
|
});
|
|
2113
2128
|
const retryFallback: InitialRetryFallbackState = {
|
|
2114
|
-
role:
|
|
2129
|
+
role: chainKey,
|
|
2115
2130
|
originalSelector,
|
|
2116
2131
|
originalThinkingLevel: parsedOriginal?.thinkingLevel,
|
|
2117
2132
|
};
|
|
2118
2133
|
return [
|
|
2119
2134
|
...primaryPatterns,
|
|
2120
|
-
...
|
|
2121
|
-
|
|
2122
|
-
|
|
2135
|
+
...findRetryFallbackCandidates(fallbackContext, chainKey, originalSelector, originalModel, {
|
|
2136
|
+
allowMissingPrimary: true,
|
|
2137
|
+
}).map(candidate => ({ pattern: candidate.raw, retryFallback })),
|
|
2123
2138
|
];
|
|
2124
2139
|
}
|
|
2125
2140
|
if (resolved.model) {
|
|
@@ -2139,10 +2154,68 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2139
2154
|
}));
|
|
2140
2155
|
}),
|
|
2141
2156
|
);
|
|
2157
|
+
let usageFallbackTriggered = false;
|
|
2142
2158
|
for (let patternIndex = 0; patternIndex < expandedModelPatterns.length; patternIndex += 1) {
|
|
2143
2159
|
const { pattern, retryFallback } = expandedModelPatterns[patternIndex];
|
|
2144
2160
|
const primary = parseModelPattern(pattern, availableModels, matchPreferences);
|
|
2145
2161
|
if (!primary.model || (retryFallback && !hasModelAuth(primary.model))) continue;
|
|
2162
|
+
let hasUsageFallbackCandidate = false;
|
|
2163
|
+
for (
|
|
2164
|
+
let candidateIndex = patternIndex + 1;
|
|
2165
|
+
candidateIndex < expandedModelPatterns.length;
|
|
2166
|
+
candidateIndex += 1
|
|
2167
|
+
) {
|
|
2168
|
+
const candidate = parseModelPattern(
|
|
2169
|
+
expandedModelPatterns[candidateIndex].pattern,
|
|
2170
|
+
availableModels,
|
|
2171
|
+
matchPreferences,
|
|
2172
|
+
);
|
|
2173
|
+
if (candidate.model && hasModelAuth(candidate.model)) {
|
|
2174
|
+
hasUsageFallbackCandidate = true;
|
|
2175
|
+
break;
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
const usageReservePolicy = settings.get("retry.usageReservePolicy");
|
|
2179
|
+
if (
|
|
2180
|
+
(hasUsageFallbackCandidate || usageReservePolicy === "fail-closed") &&
|
|
2181
|
+
settings.get("retry.modelFallback") &&
|
|
2182
|
+
settings.get("retry.usageAwareFallback")
|
|
2183
|
+
) {
|
|
2184
|
+
let usageHealth: ModelUsageHealth | undefined;
|
|
2185
|
+
try {
|
|
2186
|
+
usageHealth = await modelRegistry.authStorage.getModelUsageHealth(primary.model.provider, {
|
|
2187
|
+
modelId: primary.model.id,
|
|
2188
|
+
baseUrl: primary.model.baseUrl,
|
|
2189
|
+
reserveFraction: settings.get("retry.usageReservePct") / 100,
|
|
2190
|
+
});
|
|
2191
|
+
} catch (error) {
|
|
2192
|
+
logger.debug("Usage-aware model preflight failed open", {
|
|
2193
|
+
provider: primary.model.provider,
|
|
2194
|
+
model: primary.model.id,
|
|
2195
|
+
error: String(error),
|
|
2196
|
+
});
|
|
2197
|
+
}
|
|
2198
|
+
if (usageHealth?.state === "depleted") {
|
|
2199
|
+
if (usageReservePolicy === "fail-closed") {
|
|
2200
|
+
throw new Error(
|
|
2201
|
+
`Usage depleted for ${primary.model.provider}/${primary.model.id}; reserve policy is fail-closed.`,
|
|
2202
|
+
);
|
|
2203
|
+
}
|
|
2204
|
+
usageFallbackTriggered = true;
|
|
2205
|
+
continue;
|
|
2206
|
+
}
|
|
2207
|
+
if (usageHealth?.state === "reserve") {
|
|
2208
|
+
if (usageReservePolicy === "fail-closed") {
|
|
2209
|
+
throw new Error(
|
|
2210
|
+
`Usage reserve reached for ${primary.model.provider}/${primary.model.id}; reserve policy is fail-closed.`,
|
|
2211
|
+
);
|
|
2212
|
+
}
|
|
2213
|
+
if (usageReservePolicy === "auto" || (!options.hasUI && !options.deferUsageReserveConfirmation)) {
|
|
2214
|
+
usageFallbackTriggered = true;
|
|
2215
|
+
continue;
|
|
2216
|
+
}
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2146
2219
|
let selectedModel = primary.model;
|
|
2147
2220
|
let selectedThinkingLevel = primary.thinkingLevel;
|
|
2148
2221
|
let selectedExplicitThinkingLevel = primary.explicitThinkingLevel;
|
|
@@ -2222,7 +2295,8 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2222
2295
|
}
|
|
2223
2296
|
}
|
|
2224
2297
|
model = selectedModel;
|
|
2225
|
-
initialRetryFallback =
|
|
2298
|
+
initialRetryFallback =
|
|
2299
|
+
retryFallback && usageFallbackTriggered ? { ...retryFallback, pinned: true } : retryFallback;
|
|
2226
2300
|
modelFallbackMessage = undefined;
|
|
2227
2301
|
if (selectedExplicitThinkingLevel) {
|
|
2228
2302
|
restoredSessionThinkingLevel = selectedThinkingLevel;
|
|
@@ -2602,8 +2676,13 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2602
2676
|
}
|
|
2603
2677
|
const defaultPrompt = await buildSystemPromptInternal({
|
|
2604
2678
|
cwd,
|
|
2679
|
+
additionalWorkspaceRoots: sessionManager.getAdditionalDirectories(),
|
|
2605
2680
|
xdevTools: toolSession.xdevRegistry?.entries() ?? [],
|
|
2606
|
-
xdevDocs:
|
|
2681
|
+
xdevDocs:
|
|
2682
|
+
toolSession.xdevRegistry?.docsAll(
|
|
2683
|
+
settings.get("tools.xdevDocs"),
|
|
2684
|
+
settings.get("tools.xdevInlineDevices"),
|
|
2685
|
+
) ?? "",
|
|
2607
2686
|
autoQaEnabled: !restrictToolNames && isAutoQaEnabled(settings),
|
|
2608
2687
|
resolvedCustomPrompt: options.customSystemPrompt,
|
|
2609
2688
|
skills: session?.skills ?? skills,
|
|
@@ -2708,16 +2787,25 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2708
2787
|
// so that subagents launched in the same parallel batch can see each other in
|
|
2709
2788
|
// their initial `# IRC Peers` block (rendered inside `rebuildSystemPrompt`).
|
|
2710
2789
|
// The session reference is attached after construction below.
|
|
2711
|
-
|
|
2790
|
+
const registrationInput = {
|
|
2712
2791
|
id: resolvedAgentId,
|
|
2713
2792
|
displayName: resolvedAgentDisplayName,
|
|
2714
2793
|
kind: agentKind,
|
|
2715
2794
|
parentId: options.parentAgentId,
|
|
2716
2795
|
session: null,
|
|
2717
2796
|
sessionFile: sessionManager.getSessionFile() ?? null,
|
|
2718
|
-
status: "running",
|
|
2719
|
-
}
|
|
2720
|
-
|
|
2797
|
+
status: "running" as const,
|
|
2798
|
+
};
|
|
2799
|
+
registeredAgentRef =
|
|
2800
|
+
options.expectedAgentRef === undefined
|
|
2801
|
+
? agentRegistry.register(registrationInput)
|
|
2802
|
+
: agentRegistry.registerIfAvailable(registrationInput, options.expectedAgentRef);
|
|
2803
|
+
if (!registeredAgentRef) {
|
|
2804
|
+
throw new Error(`Agent "${resolvedAgentId}" is already owned by another session generation.`);
|
|
2805
|
+
}
|
|
2806
|
+
// A reused parked ref remains parked until the new AgentSession is fully
|
|
2807
|
+
// constructed and attached. Startup failure therefore leaves it revivable.
|
|
2808
|
+
hasRegistered = options.expectedAgentRef === undefined || options.expectedAgentRef === null;
|
|
2721
2809
|
|
|
2722
2810
|
// Partition the initial enabled set for the xd:// transport: ambient
|
|
2723
2811
|
// discoverable tools become mounted devices, while explicitly requested
|
|
@@ -3028,6 +3116,16 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
3028
3116
|
skillsSettings: settings.getGroup("skills"),
|
|
3029
3117
|
modelRegistry,
|
|
3030
3118
|
toolRegistry,
|
|
3119
|
+
memoryAgentDir: agentDir,
|
|
3120
|
+
memoryTaskDepth: taskDepth,
|
|
3121
|
+
createMemoryTools: restrictToolNames
|
|
3122
|
+
? undefined
|
|
3123
|
+
: async () => {
|
|
3124
|
+
const tools = await Promise.all(
|
|
3125
|
+
MEMORY_BACKEND_TOOL_NAMES.map(name => BUILTIN_TOOLS[name](toolSession)),
|
|
3126
|
+
);
|
|
3127
|
+
return tools.filter((tool): tool is AgentTool => tool !== null);
|
|
3128
|
+
},
|
|
3031
3129
|
createVibeTools:
|
|
3032
3130
|
(options.taskDepth ?? 0) === 0 && !options.parentTaskPrefix
|
|
3033
3131
|
? () => createVibeTools(toolSession)
|
|
@@ -3074,12 +3172,6 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
3074
3172
|
titleSystemPrompt: options.titleSystemPrompt,
|
|
3075
3173
|
});
|
|
3076
3174
|
hasSession = true;
|
|
3077
|
-
if (asyncJobManager) {
|
|
3078
|
-
session.yieldQueue.register<AsyncResultEntry>("async-result", {
|
|
3079
|
-
isStale: entry => asyncJobManager.isDeliverySuppressed(entry.jobId),
|
|
3080
|
-
build: buildAsyncResultBatchMessage,
|
|
3081
|
-
});
|
|
3082
|
-
}
|
|
3083
3175
|
session.yieldQueue.register<McpNotificationEntry>("mcp-notification", {
|
|
3084
3176
|
build: buildMcpNotificationBatchMessage,
|
|
3085
3177
|
});
|
|
@@ -3091,7 +3183,19 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
3091
3183
|
// Attach the live session to the pre-registered ref so peers can route IRC
|
|
3092
3184
|
// messages here. Refresh sessionFile in case it was unavailable at pre-register
|
|
3093
3185
|
// time. The dispose wrapper below unregisters on teardown (unless parked).
|
|
3094
|
-
|
|
3186
|
+
if (
|
|
3187
|
+
!registeredAgentRef ||
|
|
3188
|
+
!agentRegistry.attachSession(
|
|
3189
|
+
resolvedAgentId,
|
|
3190
|
+
session,
|
|
3191
|
+
sessionManager.getSessionFile() ?? null,
|
|
3192
|
+
registeredAgentRef,
|
|
3193
|
+
) ||
|
|
3194
|
+
!agentRegistry.setStatus(resolvedAgentId, "running", registeredAgentRef)
|
|
3195
|
+
) {
|
|
3196
|
+
throw new Error(`Agent "${resolvedAgentId}" was replaced during session initialization.`);
|
|
3197
|
+
}
|
|
3198
|
+
hasRegistered = true;
|
|
3095
3199
|
{
|
|
3096
3200
|
const originalDispose = session.dispose.bind(session);
|
|
3097
3201
|
session.dispose = async () => {
|
|
@@ -3105,6 +3209,17 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
3105
3209
|
// adopted subagent sessions, revivers. Tear it down while shared
|
|
3106
3210
|
// resources (kernels, MCP, LSP) are still live. Subagent disposal
|
|
3107
3211
|
// must NOT touch the global lifecycle.
|
|
3212
|
+
const vibeRegistry = VibeSessionRegistry.global();
|
|
3213
|
+
const vibeParentSession = {
|
|
3214
|
+
getAgentId: () => resolvedAgentId,
|
|
3215
|
+
getSessionId: () => sessionManager.getSessionId(),
|
|
3216
|
+
getSessionFile: () => sessionManager.getSessionFile() ?? null,
|
|
3217
|
+
sessionManager,
|
|
3218
|
+
asyncJobManager: scopedAsyncJobManager,
|
|
3219
|
+
settings,
|
|
3220
|
+
getActiveModelString,
|
|
3221
|
+
};
|
|
3222
|
+
await vibeRegistry.suspendScope(vibeRegistry.ownerScope(vibeParentSession), scopedAsyncJobManager);
|
|
3108
3223
|
await AgentLifecycleManager.global().dispose();
|
|
3109
3224
|
}
|
|
3110
3225
|
await originalDispose();
|
|
@@ -3346,6 +3461,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
3346
3461
|
try {
|
|
3347
3462
|
if (hasSession) {
|
|
3348
3463
|
await session.dispose();
|
|
3464
|
+
if (hasRegistered) unregisterUnlessParked();
|
|
3349
3465
|
} else {
|
|
3350
3466
|
if (hasRegistered) unregisterUnlessParked();
|
|
3351
3467
|
if (asyncJobManager) {
|