wave-agent-sdk 1.1.5 → 1.3.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/dist/agent.d.ts +128 -28
- package/dist/agent.js +201 -49
- package/dist/builtin/index.js +2 -0
- package/dist/builtin/plugins.js +11 -20
- package/dist/builtin/skills/settings.js +7 -20
- package/dist/builtin/skills/wave-daemon.d.ts +1 -0
- package/dist/builtin/skills/wave-daemon.js +194 -0
- package/dist/constants/images.d.ts +26 -0
- package/dist/constants/images.js +26 -0
- package/dist/constants/index.d.ts +16 -0
- package/dist/constants/index.js +16 -0
- package/dist/constants/memory.d.ts +26 -0
- package/dist/constants/memory.js +34 -0
- package/dist/constants/messages.d.ts +11 -0
- package/dist/constants/messages.js +11 -0
- package/dist/constants/plugins.d.ts +8 -0
- package/dist/constants/plugins.js +8 -0
- package/dist/constants/tools.d.ts +1 -0
- package/dist/constants/tools.js +1 -0
- package/dist/core/plugin.d.ts +54 -10
- package/dist/core/plugin.js +137 -23
- package/dist/core/session.d.ts +1 -1
- package/dist/core/session.js +1 -1
- package/dist/exec/catalog.d.ts +140 -0
- package/dist/exec/catalog.js +470 -0
- package/dist/exec/catalogAnnouncement.d.ts +89 -0
- package/dist/exec/catalogAnnouncement.js +293 -0
- package/dist/exec/constants.d.ts +51 -0
- package/dist/exec/constants.js +51 -0
- package/dist/exec/execRuntime.d.ts +55 -0
- package/dist/exec/execRuntime.js +217 -0
- package/dist/exec/workerSource.d.ts +28 -0
- package/dist/exec/workerSource.js +299 -0
- package/dist/host/index.d.ts +23 -0
- package/dist/host/index.js +23 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.js +8 -1
- package/dist/managers/MemoryRuleManager.d.ts +6 -0
- package/dist/managers/MemoryRuleManager.js +12 -0
- package/dist/managers/aiManager.d.ts +35 -25
- package/dist/managers/aiManager.js +204 -202
- package/dist/managers/backgroundTaskManager.js +14 -0
- package/dist/managers/bashModeManager.d.ts +33 -0
- package/dist/managers/bashModeManager.js +110 -0
- package/dist/managers/hookManager.d.ts +18 -0
- package/dist/managers/hookManager.js +37 -3
- package/dist/managers/liveConfigManager.d.ts +33 -0
- package/dist/managers/liveConfigManager.js +106 -11
- package/dist/managers/lspManager.d.ts +9 -0
- package/dist/managers/lspManager.js +47 -18
- package/dist/managers/mcpManager.d.ts +68 -10
- package/dist/managers/mcpManager.js +265 -15
- package/dist/managers/messageManager.d.ts +60 -18
- package/dist/managers/messageManager.js +170 -81
- package/dist/managers/permissionManager.d.ts +69 -0
- package/dist/managers/permissionManager.js +221 -78
- package/dist/managers/planManager.d.ts +9 -0
- package/dist/managers/planManager.js +19 -1
- package/dist/managers/pluginManager.d.ts +46 -2
- package/dist/managers/pluginManager.js +117 -11
- package/dist/managers/pluginScopeManager.d.ts +15 -2
- package/dist/managers/pluginScopeManager.js +20 -1
- package/dist/managers/skillManager.d.ts +50 -0
- package/dist/managers/skillManager.js +166 -12
- package/dist/managers/slashCommandManager.d.ts +10 -0
- package/dist/managers/slashCommandManager.js +44 -31
- package/dist/managers/subagentManager.d.ts +15 -0
- package/dist/managers/subagentManager.js +81 -9
- package/dist/managers/toolManager.d.ts +29 -3
- package/dist/managers/toolManager.js +87 -13
- package/dist/managers/workflowManager.js +6 -0
- package/dist/prompts/autoMemory.d.ts +9 -0
- package/dist/prompts/autoMemory.js +30 -31
- package/dist/prompts/autoMemoryExtraction.d.ts +4 -0
- package/dist/prompts/autoMemoryExtraction.js +8 -111
- package/dist/prompts/index.d.ts +0 -1
- package/dist/prompts/index.js +0 -4
- package/dist/prompts/memoryTypes.d.ts +63 -0
- package/dist/prompts/memoryTypes.js +191 -0
- package/dist/services/GitService.d.ts +7 -0
- package/dist/services/GitService.js +23 -0
- package/dist/services/MarketplaceService.d.ts +101 -17
- package/dist/services/MarketplaceService.js +323 -102
- package/dist/services/artifactContent.d.ts +84 -0
- package/dist/services/artifactContent.js +204 -0
- package/dist/services/artifactSession.d.ts +6 -0
- package/dist/services/artifactSession.js +17 -0
- package/dist/services/autoMemoryService.js +5 -13
- package/dist/services/configurationService.d.ts +92 -9
- package/dist/services/configurationService.js +246 -64
- package/dist/services/contentSummarizer.d.ts +15 -0
- package/dist/services/contentSummarizer.js +45 -0
- package/dist/services/execAvailability.d.ts +9 -0
- package/dist/services/execAvailability.js +32 -0
- package/dist/services/fileWatcher.js +61 -6
- package/dist/services/initializationService.js +21 -17
- package/dist/services/interactionService.d.ts +9 -1
- package/dist/services/interactionService.js +28 -8
- package/dist/services/jsonlHandler.d.ts +98 -0
- package/dist/services/jsonlHandler.js +250 -12
- package/dist/services/memory.d.ts +17 -1
- package/dist/services/memory.js +44 -7
- package/dist/services/officialMarketplaceMirror.d.ts +85 -0
- package/dist/services/officialMarketplaceMirror.js +290 -0
- package/dist/services/pluginLoader.d.ts +12 -4
- package/dist/services/pluginLoader.js +38 -7
- package/dist/services/remoteSettingsService.js +20 -6
- package/dist/services/session.d.ts +74 -0
- package/dist/services/session.js +174 -16
- package/dist/services/sessionEntries.d.ts +2 -0
- package/dist/services/sessionEntries.js +20 -0
- package/dist/services/worktreeHooks.js +6 -1
- package/dist/stdio/index.d.ts +12 -0
- package/dist/stdio/index.js +12 -0
- package/dist/stdio/notificationRouter.d.ts +38 -0
- package/dist/stdio/notificationRouter.js +97 -0
- package/dist/stdio/rpcClient.d.ts +18 -0
- package/dist/stdio/rpcClient.js +10 -0
- package/dist/stdio/stdioAgent.d.ts +229 -0
- package/dist/stdio/stdioAgent.js +360 -0
- package/dist/tools/artifactTool.js +406 -273
- package/dist/tools/bashTool.js +10 -6
- package/dist/tools/editTool.js +6 -3
- package/dist/tools/execTool.d.ts +2 -0
- package/dist/tools/execTool.js +165 -0
- package/dist/tools/exitPlanMode.js +10 -2
- package/dist/tools/grepTool.js +7 -1
- package/dist/tools/readTool.js +30 -2
- package/dist/tools/types.d.ts +34 -8
- package/dist/tools/webFetchTool.js +15 -166
- package/dist/tools/workflowTool.js +40 -8
- package/dist/tools/writeTool.js +6 -3
- package/dist/types/agent.d.ts +24 -1
- package/dist/types/commands.d.ts +7 -0
- package/dist/types/configuration.d.ts +45 -2
- package/dist/types/hooks.d.ts +1 -0
- package/dist/types/hooks.js +19 -0
- package/dist/types/marketplace.d.ts +40 -2
- package/dist/types/mcp.d.ts +42 -0
- package/dist/types/messaging.d.ts +1 -8
- package/dist/types/permissions.d.ts +22 -0
- package/dist/types/permissions.js +17 -0
- package/dist/types/plugins.d.ts +26 -2
- package/dist/types/skills.d.ts +26 -0
- package/dist/utils/bashParser.d.ts +17 -0
- package/dist/utils/bashParser.js +72 -0
- package/dist/utils/bashStructure/bashLexer.d.ts +96 -0
- package/dist/utils/bashStructure/bashLexer.js +676 -0
- package/dist/utils/bashStructure/bashParser.d.ts +144 -0
- package/dist/utils/bashStructure/bashParser.js +606 -0
- package/dist/utils/bashStructure/bashSemantics.d.ts +70 -0
- package/dist/utils/bashStructure/bashSemantics.js +477 -0
- package/dist/utils/bashStructure/index.d.ts +26 -0
- package/dist/utils/bashStructure/index.js +27 -0
- package/dist/utils/bashStructure/types.d.ts +62 -0
- package/dist/utils/bashStructure/types.js +47 -0
- package/dist/utils/constants.d.ts +10 -0
- package/dist/utils/constants.js +10 -0
- package/dist/utils/containerSetup.js +48 -6
- package/dist/utils/convertMessagesForAPI.d.ts +7 -1
- package/dist/utils/convertMessagesForAPI.js +64 -14
- package/dist/utils/fileChangeReminder.d.ts +20 -0
- package/dist/utils/fileChangeReminder.js +153 -0
- package/dist/utils/fileSearch.js +4 -3
- package/dist/utils/fileUtils.d.ts +44 -0
- package/dist/utils/fileUtils.js +118 -0
- package/dist/utils/frontmatterYaml.d.ts +33 -0
- package/dist/utils/frontmatterYaml.js +192 -0
- package/dist/utils/imageBudget.d.ts +85 -0
- package/dist/utils/imageBudget.js +109 -0
- package/dist/utils/imageDimensions.d.ts +83 -0
- package/dist/utils/imageDimensions.js +232 -0
- package/dist/utils/imageProcessor.d.ts +66 -0
- package/dist/utils/imageProcessor.js +84 -0
- package/dist/utils/imageRewrite.d.ts +29 -0
- package/dist/utils/imageRewrite.js +251 -0
- package/dist/utils/markdownParser.d.ts +5 -1
- package/dist/utils/markdownParser.js +9 -51
- package/dist/utils/mcpInstructions.d.ts +61 -0
- package/dist/utils/mcpInstructions.js +126 -0
- package/dist/utils/mcpUtils.d.ts +7 -0
- package/dist/utils/mcpUtils.js +11 -2
- package/dist/utils/memoryAge.d.ts +32 -0
- package/dist/utils/memoryAge.js +47 -0
- package/dist/utils/memoryEntrypoint.d.ts +20 -0
- package/dist/utils/memoryEntrypoint.js +49 -0
- package/dist/utils/memoryIndex.d.ts +30 -0
- package/dist/utils/memoryIndex.js +76 -0
- package/dist/utils/messageOperations.d.ts +6 -20
- package/dist/utils/messageOperations.js +40 -91
- package/dist/utils/nestedMemory.d.ts +22 -0
- package/dist/utils/nestedMemory.js +61 -0
- package/dist/utils/npmTarball.d.ts +19 -0
- package/dist/utils/npmTarball.js +92 -0
- package/dist/utils/pluginSource.d.ts +37 -0
- package/dist/utils/pluginSource.js +73 -0
- package/dist/utils/ripgrep.d.ts +18 -4
- package/dist/utils/ripgrep.js +56 -4
- package/dist/utils/runtimeDeps.d.ts +35 -0
- package/dist/utils/runtimeDeps.js +426 -0
- package/dist/utils/skillParser.js +22 -52
- package/dist/utils/subagentParser.js +48 -45
- package/dist/utils/tokenCalculation.js +0 -8
- package/dist/utils/userSettings.d.ts +90 -0
- package/dist/utils/userSettings.js +291 -0
- package/dist/utils/worktreeUtils.d.ts +2 -1
- package/dist/utils/worktreeUtils.js +64 -34
- package/package.json +12 -4
- package/dist/managers/bangManager.d.ts +0 -26
- package/dist/managers/bangManager.js +0 -78
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { bashTool } from "../tools/bashTool.js";
|
|
2
|
+
import { BASH_TOOL_NAME } from "../constants/tools.js";
|
|
3
|
+
/**
|
|
4
|
+
* Bash mode (`!command`) execution. The command is surfaced as a user-message
|
|
5
|
+
* tool block (name: BASH_TOOL_NAME) — the same rendering as fork-skill / `/plan`
|
|
6
|
+
* outputs (⎿ prefix + markdown, result enters the model context via the
|
|
7
|
+
* generic `<local-command-stdout>` rule) — and executed through the shared
|
|
8
|
+
* bash tool engine (shell resolution, CWD tracking, timeout, output handling).
|
|
9
|
+
*/
|
|
10
|
+
export class BashModeManager {
|
|
11
|
+
constructor(container, options) {
|
|
12
|
+
this.container = container;
|
|
13
|
+
this.isCommandRunning = false;
|
|
14
|
+
this.abortController = null;
|
|
15
|
+
this.workdir = options.workdir;
|
|
16
|
+
}
|
|
17
|
+
get messageManager() {
|
|
18
|
+
return this.container.get("MessageManager");
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Merged env (OS env overlaid with this session's settings snapshot) for
|
|
22
|
+
* bash-mode subprocesses, so settings `env` vars reach them without
|
|
23
|
+
* polluting other sessions in one `wave --stdio` process.
|
|
24
|
+
*/
|
|
25
|
+
get sessionEnv() {
|
|
26
|
+
return (this.container
|
|
27
|
+
.get("ConfigurationService")
|
|
28
|
+
?.getMergedEnv?.() ?? process.env);
|
|
29
|
+
}
|
|
30
|
+
setCommandRunning(isRunning) {
|
|
31
|
+
this.isCommandRunning = isRunning;
|
|
32
|
+
this.onCommandRunningChange?.(isRunning);
|
|
33
|
+
}
|
|
34
|
+
async executeCommand(command) {
|
|
35
|
+
if (this.isCommandRunning) {
|
|
36
|
+
throw new Error("Command already running");
|
|
37
|
+
}
|
|
38
|
+
this.setCommandRunning(true);
|
|
39
|
+
try {
|
|
40
|
+
// User message + running tool block. The user text mirrors the command
|
|
41
|
+
// itself (`!ls` renders as `!ls`), and incremental toolBlockUpdated
|
|
42
|
+
// notifications drive the live output on all three hosts.
|
|
43
|
+
const messageId = this.messageManager.addUserMessage({
|
|
44
|
+
content: command,
|
|
45
|
+
});
|
|
46
|
+
const blockId = this.messageManager.addToolBlockToMessage(messageId, {
|
|
47
|
+
name: BASH_TOOL_NAME,
|
|
48
|
+
parameters: command,
|
|
49
|
+
stage: "running",
|
|
50
|
+
});
|
|
51
|
+
this.abortController = new AbortController();
|
|
52
|
+
const taskManager = this.container.get("TaskManager");
|
|
53
|
+
// No permissionManager in the context: bash mode is an explicit user
|
|
54
|
+
// command, it must not be blocked by the permission gate.
|
|
55
|
+
const result = await bashTool.execute({ command }, {
|
|
56
|
+
workdir: this.workdir,
|
|
57
|
+
taskManager,
|
|
58
|
+
sessionEnv: this.sessionEnv,
|
|
59
|
+
abortSignal: this.abortController.signal,
|
|
60
|
+
// Stream realtime output into the running tool block — wired like
|
|
61
|
+
// aiManager tool execution (aiManager.ts updateToolBlock callbacks).
|
|
62
|
+
onShortResultUpdate: (shortResult) => {
|
|
63
|
+
this.messageManager.updateToolBlock({
|
|
64
|
+
id: blockId,
|
|
65
|
+
messageId,
|
|
66
|
+
shortResult,
|
|
67
|
+
stage: "running",
|
|
68
|
+
name: BASH_TOOL_NAME,
|
|
69
|
+
});
|
|
70
|
+
},
|
|
71
|
+
onResultUpdate: (resultText) => {
|
|
72
|
+
this.messageManager.updateToolBlock({
|
|
73
|
+
id: blockId,
|
|
74
|
+
messageId,
|
|
75
|
+
result: resultText,
|
|
76
|
+
stage: "running",
|
|
77
|
+
name: BASH_TOOL_NAME,
|
|
78
|
+
});
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
const exitCode = typeof result.metadata?.exitCode === "number"
|
|
82
|
+
? result.metadata.exitCode
|
|
83
|
+
: result.success
|
|
84
|
+
? 0
|
|
85
|
+
: 1;
|
|
86
|
+
const resultText = result.success
|
|
87
|
+
? result.content
|
|
88
|
+
: `[exit code: ${exitCode}]` +
|
|
89
|
+
(result.content ? `\n\n${result.content}` : "");
|
|
90
|
+
this.messageManager.updateToolBlock({
|
|
91
|
+
id: blockId,
|
|
92
|
+
messageId,
|
|
93
|
+
result: resultText,
|
|
94
|
+
shortResult: result.shortResult,
|
|
95
|
+
stage: "end",
|
|
96
|
+
success: result.success,
|
|
97
|
+
});
|
|
98
|
+
return exitCode;
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
this.abortController = null;
|
|
102
|
+
this.setCommandRunning(false);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
abortCommand() {
|
|
106
|
+
this.abortController?.abort();
|
|
107
|
+
this.abortController = null;
|
|
108
|
+
this.isCommandRunning = false;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -13,6 +13,12 @@ export declare class HookManager {
|
|
|
13
13
|
private container;
|
|
14
14
|
private configuration;
|
|
15
15
|
private programmaticHooks;
|
|
16
|
+
/**
|
|
17
|
+
* Plugin hooks grouped by plugin root path. A map rather than one merged
|
|
18
|
+
* object because mergeHooksConfiguration only appends — a flat object can
|
|
19
|
+
* never be reversed, so the in-place plugin reload path could not drop
|
|
20
|
+
* exactly one plugin's hooks (and re-registering would double them).
|
|
21
|
+
*/
|
|
16
22
|
private pluginHooks;
|
|
17
23
|
private waveConfigHooks;
|
|
18
24
|
private readonly matcher;
|
|
@@ -120,6 +126,18 @@ export declare class HookManager {
|
|
|
120
126
|
* Register hooks provided by a plugin
|
|
121
127
|
*/
|
|
122
128
|
registerPluginHooks(pluginRoot: string, hooks: PartialHookConfiguration): void;
|
|
129
|
+
/**
|
|
130
|
+
* Drop every hook contributed by a plugin, addressed by its root path.
|
|
131
|
+
* Used by the in-place plugin reload path (before re-registering) and when a
|
|
132
|
+
* plugin is disabled or uninstalled.
|
|
133
|
+
* @returns true if this root had hooks registered
|
|
134
|
+
*/
|
|
135
|
+
unregisterPluginHooks(pluginRoot: string): boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Get hooks registered by plugins (read-only view for the settings UI).
|
|
138
|
+
* Plugin hooks carry pluginRoot on each command and are read-only in the UI.
|
|
139
|
+
*/
|
|
140
|
+
getPluginHooks(): PartialHookConfiguration;
|
|
123
141
|
/**
|
|
124
142
|
* Execute SessionStart hooks during initialization.
|
|
125
143
|
* Collects additionalContext and initialUserMessage from hook stdout.
|
|
@@ -13,7 +13,13 @@ export class HookManager {
|
|
|
13
13
|
constructor(container, workdir, matcher = new HookMatcher()) {
|
|
14
14
|
this.container = container;
|
|
15
15
|
this.programmaticHooks = {};
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Plugin hooks grouped by plugin root path. A map rather than one merged
|
|
18
|
+
* object because mergeHooksConfiguration only appends — a flat object can
|
|
19
|
+
* never be reversed, so the in-place plugin reload path could not drop
|
|
20
|
+
* exactly one plugin's hooks (and re-registering would double them).
|
|
21
|
+
*/
|
|
22
|
+
this.pluginHooks = new Map();
|
|
17
23
|
this.waveConfigHooks = {};
|
|
18
24
|
this.workdir = workdir;
|
|
19
25
|
this.matcher = matcher;
|
|
@@ -78,7 +84,9 @@ export class HookManager {
|
|
|
78
84
|
rebuildConfiguration() {
|
|
79
85
|
const rebuilt = {};
|
|
80
86
|
this.mergeHooksConfiguration(rebuilt, this.programmaticHooks);
|
|
81
|
-
|
|
87
|
+
for (const hooks of this.pluginHooks.values()) {
|
|
88
|
+
this.mergeHooksConfiguration(rebuilt, hooks);
|
|
89
|
+
}
|
|
82
90
|
this.mergeHooksConfiguration(rebuilt, this.waveConfigHooks);
|
|
83
91
|
this.configuration = Object.keys(rebuilt).length > 0 ? rebuilt : undefined;
|
|
84
92
|
}
|
|
@@ -667,9 +675,35 @@ export class HookManager {
|
|
|
667
675
|
hooks: config.hooks.map((cmd) => ({ ...cmd, pluginRoot })),
|
|
668
676
|
}));
|
|
669
677
|
}
|
|
670
|
-
|
|
678
|
+
// Replace (not append) the previous registration for this root, so
|
|
679
|
+
// re-registering the same plugin never doubles its hooks.
|
|
680
|
+
this.pluginHooks.set(pluginRoot, stampedHooks);
|
|
671
681
|
this.rebuildConfiguration();
|
|
672
682
|
}
|
|
683
|
+
/**
|
|
684
|
+
* Drop every hook contributed by a plugin, addressed by its root path.
|
|
685
|
+
* Used by the in-place plugin reload path (before re-registering) and when a
|
|
686
|
+
* plugin is disabled or uninstalled.
|
|
687
|
+
* @returns true if this root had hooks registered
|
|
688
|
+
*/
|
|
689
|
+
unregisterPluginHooks(pluginRoot) {
|
|
690
|
+
const removed = this.pluginHooks.delete(pluginRoot);
|
|
691
|
+
if (removed) {
|
|
692
|
+
this.rebuildConfiguration();
|
|
693
|
+
}
|
|
694
|
+
return removed;
|
|
695
|
+
}
|
|
696
|
+
/**
|
|
697
|
+
* Get hooks registered by plugins (read-only view for the settings UI).
|
|
698
|
+
* Plugin hooks carry pluginRoot on each command and are read-only in the UI.
|
|
699
|
+
*/
|
|
700
|
+
getPluginHooks() {
|
|
701
|
+
const merged = {};
|
|
702
|
+
for (const hooks of this.pluginHooks.values()) {
|
|
703
|
+
this.mergeHooksConfiguration(merged, hooks);
|
|
704
|
+
}
|
|
705
|
+
return merged;
|
|
706
|
+
}
|
|
673
707
|
/**
|
|
674
708
|
* Execute SessionStart hooks during initialization.
|
|
675
709
|
* Collects additionalContext and initialUserMessage from hook stdout.
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* - Configuration file watching for settings.json files
|
|
7
7
|
* - Coordination between file watchers and configuration updates
|
|
8
8
|
*/
|
|
9
|
+
import type { TurnConfigurationSnapshot } from "../services/configurationService.js";
|
|
9
10
|
import { Container } from "../utils/container.js";
|
|
10
11
|
import type { WaveConfiguration } from "../types/configuration.js";
|
|
11
12
|
export interface LiveConfigManagerOptions {
|
|
@@ -19,6 +20,8 @@ export declare class LiveConfigManager {
|
|
|
19
20
|
private isInitialized;
|
|
20
21
|
private currentConfiguration;
|
|
21
22
|
private lastValidConfiguration;
|
|
23
|
+
private turnSnapshot;
|
|
24
|
+
private turnDepth;
|
|
22
25
|
private fileWatcher;
|
|
23
26
|
private userConfigPaths?;
|
|
24
27
|
private projectConfigPaths?;
|
|
@@ -28,6 +31,15 @@ export declare class LiveConfigManager {
|
|
|
28
31
|
private get hookManager();
|
|
29
32
|
private get permissionManager();
|
|
30
33
|
private get configurationService();
|
|
34
|
+
private get memoryService();
|
|
35
|
+
/**
|
|
36
|
+
* Keep the auto-memory system safe zone in sync with the live auto-memory
|
|
37
|
+
* toggle (core/agent-config.md scenario 6). Turning auto-memory off must
|
|
38
|
+
* revoke the privilege its directory got at construction time, and turning it
|
|
39
|
+
* back on must restore it — both without rebuilding the session. Idempotent:
|
|
40
|
+
* the underlying add/remove are dedup'ed by path.
|
|
41
|
+
*/
|
|
42
|
+
private syncAutoMemorySafeZone;
|
|
31
43
|
/**
|
|
32
44
|
* Initialize configuration watching
|
|
33
45
|
* Maps to FR-004: System MUST watch settings.json files
|
|
@@ -46,6 +58,19 @@ export declare class LiveConfigManager {
|
|
|
46
58
|
* Shutdown configuration management and cleanup resources
|
|
47
59
|
*/
|
|
48
60
|
shutdown(): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Turn boundary: pin the settings.json-derived configuration for the duration
|
|
63
|
+
* of a turn (called by AIManager). A live reload may land mid-turn and the
|
|
64
|
+
* turn must not see it (core/agent-config.md scenario 5) — the change is
|
|
65
|
+
* picked up by the snapshot taken when the next turn starts. Permission rules,
|
|
66
|
+
* hooks and env stay live: those are enforcement state and follow the file
|
|
67
|
+
* immediately.
|
|
68
|
+
*/
|
|
69
|
+
onTurnStart(): void;
|
|
70
|
+
/** Turn boundary: drop the snapshot so the next turn reads live values. */
|
|
71
|
+
onTurnEnd(): void;
|
|
72
|
+
/** Configuration snapshot of the running turn, or null outside a turn. */
|
|
73
|
+
getTurnSnapshot(): TurnConfigurationSnapshot | null;
|
|
49
74
|
/**
|
|
50
75
|
* Reload configuration from files
|
|
51
76
|
* Maps to FR-008: Continue with previous valid configuration on errors
|
|
@@ -77,6 +102,14 @@ export declare class LiveConfigManager {
|
|
|
77
102
|
private setupFileWatcherEvents;
|
|
78
103
|
private handleFileChange;
|
|
79
104
|
private detectChanges;
|
|
105
|
+
/**
|
|
106
|
+
* Chokidar only starts watching a non-existent path when its parent directory
|
|
107
|
+
* exists at watch time (a path whose parents are all missing is never
|
|
108
|
+
* picked up, not even after they appear). Walk up to the deepest node whose
|
|
109
|
+
* parent exists and watch that instead — events for its descendants still
|
|
110
|
+
* reach this path's callback (FileWatcherService matches by path prefix).
|
|
111
|
+
*/
|
|
112
|
+
private resolveWatchTarget;
|
|
80
113
|
/**
|
|
81
114
|
* Get configuration file paths for user and project settings
|
|
82
115
|
* Returns paths in priority order (local.json first, then .json)
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
* - Coordination between file watchers and configuration updates
|
|
8
8
|
*/
|
|
9
9
|
import { existsSync } from "fs";
|
|
10
|
+
import { dirname } from "path";
|
|
10
11
|
import { FileWatcherService, } from "../services/fileWatcher.js";
|
|
12
|
+
import { USER_MEMORY_FILE } from "../utils/constants.js";
|
|
11
13
|
import { isValidHookEvent } from "../types/hooks.js";
|
|
12
14
|
import { logger } from "../utils/globalLogger.js";
|
|
13
15
|
export class LiveConfigManager {
|
|
@@ -18,6 +20,13 @@ export class LiveConfigManager {
|
|
|
18
20
|
// Configuration state
|
|
19
21
|
this.currentConfiguration = null;
|
|
20
22
|
this.lastValidConfiguration = null;
|
|
23
|
+
// Turn-scoped snapshot of the settings.json-derived configuration the running
|
|
24
|
+
// turn reads from. Captured at turn start, dropped at turn end, so a live
|
|
25
|
+
// reload landing mid-turn takes effect at the next turn instead of shifting
|
|
26
|
+
// values under the running one (core/agent-config.md scenario 5). Nested turns
|
|
27
|
+
// (a subagent turn inside its parent's) share the outer snapshot.
|
|
28
|
+
this.turnSnapshot = null;
|
|
29
|
+
this.turnDepth = 0;
|
|
21
30
|
this.isWatching = false;
|
|
22
31
|
this.reloadInProgress = false;
|
|
23
32
|
this.workdir = options.workdir;
|
|
@@ -33,6 +42,36 @@ export class LiveConfigManager {
|
|
|
33
42
|
get configurationService() {
|
|
34
43
|
return this.container.get("ConfigurationService");
|
|
35
44
|
}
|
|
45
|
+
get memoryService() {
|
|
46
|
+
return this.container.get("MemoryService");
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Keep the auto-memory system safe zone in sync with the live auto-memory
|
|
50
|
+
* toggle (core/agent-config.md scenario 6). Turning auto-memory off must
|
|
51
|
+
* revoke the privilege its directory got at construction time, and turning it
|
|
52
|
+
* back on must restore it — both without rebuilding the session. Idempotent:
|
|
53
|
+
* the underlying add/remove are dedup'ed by path.
|
|
54
|
+
*/
|
|
55
|
+
syncAutoMemorySafeZone() {
|
|
56
|
+
const permissionManager = this.permissionManager;
|
|
57
|
+
const memoryService = this.memoryService;
|
|
58
|
+
if (!permissionManager || !memoryService) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const directories = [
|
|
62
|
+
memoryService.getAutoMemoryDirectory(this.workdir),
|
|
63
|
+
USER_MEMORY_FILE,
|
|
64
|
+
];
|
|
65
|
+
const enabled = this.configurationService.resolveAutoMemoryEnabledNow();
|
|
66
|
+
for (const directory of directories) {
|
|
67
|
+
if (enabled) {
|
|
68
|
+
permissionManager.addSystemAdditionalDirectory(directory);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
permissionManager.removeSystemAdditionalDirectory(directory);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
36
75
|
/**
|
|
37
76
|
* Initialize configuration watching
|
|
38
77
|
* Maps to FR-004: System MUST watch settings.json files
|
|
@@ -44,18 +83,18 @@ export class LiveConfigManager {
|
|
|
44
83
|
this.projectConfigPaths = projectPaths;
|
|
45
84
|
// Load initial configuration
|
|
46
85
|
await this.reloadConfiguration();
|
|
47
|
-
//
|
|
86
|
+
// Watch every configuration path, including ones that don't exist yet:
|
|
87
|
+
// chokidar delivers `add` once a missing path appears, but only if its
|
|
88
|
+
// parent chain exists when watching starts. Skipping absent paths (the
|
|
89
|
+
// pre-2026-09-10 behavior) silently dropped the very first save of a
|
|
90
|
+
// user-level settings.json created after session start
|
|
91
|
+
// (core/agent-config.md scenario 7).
|
|
48
92
|
for (const userPath of userPaths) {
|
|
49
|
-
|
|
50
|
-
await this.fileWatcher.watchFile(userPath, (event) => this.handleFileChange(event, "user"));
|
|
51
|
-
}
|
|
93
|
+
await this.fileWatcher.watchFile(this.resolveWatchTarget(userPath), (event) => this.handleFileChange(event, "user"));
|
|
52
94
|
}
|
|
53
|
-
// Start watching local configs that exist
|
|
54
95
|
if (projectPaths) {
|
|
55
96
|
for (const projectPath of projectPaths) {
|
|
56
|
-
|
|
57
|
-
await this.fileWatcher.watchFile(projectPath, (event) => this.handleFileChange(event, "project"));
|
|
58
|
-
}
|
|
97
|
+
await this.fileWatcher.watchFile(this.resolveWatchTarget(projectPath), (event) => this.handleFileChange(event, "project"));
|
|
59
98
|
}
|
|
60
99
|
}
|
|
61
100
|
this.isWatching = true;
|
|
@@ -112,6 +151,41 @@ export class LiveConfigManager {
|
|
|
112
151
|
throw error;
|
|
113
152
|
}
|
|
114
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* Turn boundary: pin the settings.json-derived configuration for the duration
|
|
156
|
+
* of a turn (called by AIManager). A live reload may land mid-turn and the
|
|
157
|
+
* turn must not see it (core/agent-config.md scenario 5) — the change is
|
|
158
|
+
* picked up by the snapshot taken when the next turn starts. Permission rules,
|
|
159
|
+
* hooks and env stay live: those are enforcement state and follow the file
|
|
160
|
+
* immediately.
|
|
161
|
+
*/
|
|
162
|
+
onTurnStart() {
|
|
163
|
+
if (this.turnDepth === 0) {
|
|
164
|
+
const configuration = this.getCurrentConfiguration();
|
|
165
|
+
this.turnSnapshot = {
|
|
166
|
+
configuration: configuration ? structuredClone(configuration) : null,
|
|
167
|
+
// `env` on the merged configuration is exactly what was published as the
|
|
168
|
+
// session env snapshot when it was loaded (both come from the same
|
|
169
|
+
// merge), so the snapshot carries both without querying the service.
|
|
170
|
+
env: { ...(configuration?.env ?? {}) },
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
this.turnDepth++;
|
|
174
|
+
}
|
|
175
|
+
/** Turn boundary: drop the snapshot so the next turn reads live values. */
|
|
176
|
+
onTurnEnd() {
|
|
177
|
+
if (this.turnDepth === 0) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
this.turnDepth--;
|
|
181
|
+
if (this.turnDepth === 0) {
|
|
182
|
+
this.turnSnapshot = null;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/** Configuration snapshot of the running turn, or null outside a turn. */
|
|
186
|
+
getTurnSnapshot() {
|
|
187
|
+
return this.turnDepth > 0 ? this.turnSnapshot : null;
|
|
188
|
+
}
|
|
115
189
|
/**
|
|
116
190
|
* Reload configuration from files
|
|
117
191
|
* Maps to FR-008: Continue with previous valid configuration on errors
|
|
@@ -172,15 +246,16 @@ export class LiveConfigManager {
|
|
|
172
246
|
}
|
|
173
247
|
// Update permission manager if available
|
|
174
248
|
if (this.permissionManager) {
|
|
175
|
-
this.permissionManager.updateConfiguredPermissionMode(this.currentConfiguration.permissions?.
|
|
249
|
+
this.permissionManager.updateConfiguredPermissionMode(this.currentConfiguration.permissions?.defaultMode);
|
|
176
250
|
this.permissionManager.updateAllowedRules(this.currentConfiguration.permissions?.allow || []);
|
|
177
251
|
this.permissionManager.updateDeniedRules(this.currentConfiguration.permissions?.deny || []);
|
|
178
252
|
this.permissionManager.updateAdditionalDirectories(this.currentConfiguration.permissions?.additionalDirectories || []);
|
|
253
|
+
this.syncAutoMemorySafeZone();
|
|
179
254
|
}
|
|
180
255
|
// Trigger reload callback. Awaited so fire-and-forget work spawned by the
|
|
181
256
|
// callback (e.g. skill rediscovery) completes before the reload resolves —
|
|
182
|
-
// otherwise Agent.create() can return
|
|
183
|
-
//
|
|
257
|
+
// otherwise Agent.create() can return while a skill rescan is still
|
|
258
|
+
// running (refreshSkills swaps caches atomically only after the scan).
|
|
184
259
|
await this.options.onReload?.(this.currentConfiguration);
|
|
185
260
|
return this.currentConfiguration;
|
|
186
261
|
}
|
|
@@ -304,6 +379,26 @@ export class LiveConfigManager {
|
|
|
304
379
|
}
|
|
305
380
|
return { added, modified, removed };
|
|
306
381
|
}
|
|
382
|
+
/**
|
|
383
|
+
* Chokidar only starts watching a non-existent path when its parent directory
|
|
384
|
+
* exists at watch time (a path whose parents are all missing is never
|
|
385
|
+
* picked up, not even after they appear). Walk up to the deepest node whose
|
|
386
|
+
* parent exists and watch that instead — events for its descendants still
|
|
387
|
+
* reach this path's callback (FileWatcherService matches by path prefix).
|
|
388
|
+
*/
|
|
389
|
+
resolveWatchTarget(configPath) {
|
|
390
|
+
let candidate = configPath;
|
|
391
|
+
while (!existsSync(dirname(candidate))) {
|
|
392
|
+
const parent = dirname(candidate);
|
|
393
|
+
if (parent === candidate) {
|
|
394
|
+
// Reached the filesystem root without an existing parent: nothing to
|
|
395
|
+
// watch (unreachable for absolute paths).
|
|
396
|
+
return configPath;
|
|
397
|
+
}
|
|
398
|
+
candidate = parent;
|
|
399
|
+
}
|
|
400
|
+
return candidate;
|
|
401
|
+
}
|
|
307
402
|
/**
|
|
308
403
|
* Get configuration file paths for user and project settings
|
|
309
404
|
* Returns paths in priority order (local.json first, then .json)
|
|
@@ -21,6 +21,14 @@ export declare class LspManager implements ILspManager {
|
|
|
21
21
|
constructor(container: Container);
|
|
22
22
|
initialize(workdir: string): Promise<void>;
|
|
23
23
|
registerServer(language: string, config: LspServerConfig): void;
|
|
24
|
+
/**
|
|
25
|
+
* Drop every LSP server contributed by a plugin (matched on pluginRoot),
|
|
26
|
+
* stopping any process already started for those languages so the next
|
|
27
|
+
* request starts the reloaded command instead of reusing the stale one.
|
|
28
|
+
* Called by the in-place plugin reload path before re-registering.
|
|
29
|
+
* @returns the number of servers removed
|
|
30
|
+
*/
|
|
31
|
+
unregisterServersForPlugin(pluginRoot: string): Promise<number>;
|
|
24
32
|
private loadConfig;
|
|
25
33
|
getProcessForFile(filePath: string): Promise<LspProcess | null>;
|
|
26
34
|
private startServer;
|
|
@@ -36,6 +44,7 @@ export declare class LspManager implements ILspManager {
|
|
|
36
44
|
success: boolean;
|
|
37
45
|
content: string;
|
|
38
46
|
}>;
|
|
47
|
+
private stopProcess;
|
|
39
48
|
cleanup(): Promise<void>;
|
|
40
49
|
}
|
|
41
50
|
export {};
|
|
@@ -17,6 +17,32 @@ export class LspManager {
|
|
|
17
17
|
this.config[language] = config;
|
|
18
18
|
logger?.debug(`Registered LSP server for ${language}`);
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Drop every LSP server contributed by a plugin (matched on pluginRoot),
|
|
22
|
+
* stopping any process already started for those languages so the next
|
|
23
|
+
* request starts the reloaded command instead of reusing the stale one.
|
|
24
|
+
* Called by the in-place plugin reload path before re-registering.
|
|
25
|
+
* @returns the number of servers removed
|
|
26
|
+
*/
|
|
27
|
+
async unregisterServersForPlugin(pluginRoot) {
|
|
28
|
+
let removed = 0;
|
|
29
|
+
for (const [language, config] of Object.entries(this.config)) {
|
|
30
|
+
if (config.pluginRoot !== pluginRoot) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
delete this.config[language];
|
|
34
|
+
const lspProc = this.processes.get(language);
|
|
35
|
+
if (lspProc) {
|
|
36
|
+
this.processes.delete(language);
|
|
37
|
+
await this.stopProcess(language, lspProc);
|
|
38
|
+
}
|
|
39
|
+
removed += 1;
|
|
40
|
+
}
|
|
41
|
+
if (removed > 0) {
|
|
42
|
+
logger?.debug(`Unregistered ${removed} LSP servers for plugin root ${pluginRoot}`);
|
|
43
|
+
}
|
|
44
|
+
return removed;
|
|
45
|
+
}
|
|
20
46
|
async loadConfig() {
|
|
21
47
|
const lspJsonPath = join(this.workdir, ".lsp.json");
|
|
22
48
|
try {
|
|
@@ -326,27 +352,30 @@ export class LspManager {
|
|
|
326
352
|
return { success: false, content: `LSP error: ${JSON.stringify(error)}` };
|
|
327
353
|
}
|
|
328
354
|
}
|
|
329
|
-
async
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
catch (error) {
|
|
342
|
-
logger?.debug(`Failed to gracefully shutdown LSP for ${language}: ${error}`);
|
|
355
|
+
async stopProcess(language, lspProc) {
|
|
356
|
+
try {
|
|
357
|
+
// Try graceful shutdown
|
|
358
|
+
const timeout = lspProc.config.shutdownTimeout || 2000;
|
|
359
|
+
await this.sendRequest(lspProc, "shutdown", {}, timeout);
|
|
360
|
+
await this.sendNotification(lspProc, "exit", {});
|
|
361
|
+
// Give it a moment to exit
|
|
362
|
+
if (timeout > 100) {
|
|
363
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
343
364
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
365
|
+
}
|
|
366
|
+
catch (error) {
|
|
367
|
+
logger?.debug(`Failed to gracefully shutdown LSP for ${language}: ${error}`);
|
|
368
|
+
}
|
|
369
|
+
finally {
|
|
370
|
+
if (!lspProc.process.killed) {
|
|
371
|
+
lspProc.process.kill();
|
|
348
372
|
}
|
|
349
373
|
}
|
|
374
|
+
}
|
|
375
|
+
async cleanup() {
|
|
376
|
+
for (const [language, lspProc] of this.processes.entries()) {
|
|
377
|
+
await this.stopProcess(language, lspProc);
|
|
378
|
+
}
|
|
350
379
|
this.processes.clear();
|
|
351
380
|
}
|
|
352
381
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ChatCompletionFunctionTool } from "openai/resources.js";
|
|
2
2
|
import type { ToolPlugin, ToolResult, ToolContext } from "../tools/types.js";
|
|
3
3
|
import { Container } from "../utils/container.js";
|
|
4
|
-
import type { Logger, McpServerConfig, McpConfig, McpTool, McpServerStatus } from "../types/index.js";
|
|
4
|
+
import type { Logger, McpServerConfig, McpConfig, McpTool, McpToolCallResult, McpServerStatus } from "../types/index.js";
|
|
5
5
|
export interface McpManagerCallbacks {
|
|
6
6
|
onMcpServersChange?: (servers: McpServerStatus[]) => void;
|
|
7
7
|
}
|
|
@@ -32,11 +32,14 @@ export declare class McpManager {
|
|
|
32
32
|
private servers;
|
|
33
33
|
private connections;
|
|
34
34
|
private configPath;
|
|
35
|
+
private userConfigPath;
|
|
35
36
|
private workdir;
|
|
36
37
|
private callbacks;
|
|
37
38
|
private mcpServers;
|
|
38
39
|
private reconnectTimers;
|
|
39
40
|
private reconnectAttempts;
|
|
41
|
+
/** Explicit disconnectServer teardowns currently in flight */
|
|
42
|
+
private disconnecting;
|
|
40
43
|
constructor(container: Container, options?: McpManagerOptions);
|
|
41
44
|
/**
|
|
42
45
|
* Merged env for this session: OS env overlaid with the per-session settings
|
|
@@ -50,13 +53,61 @@ export declare class McpManager {
|
|
|
50
53
|
initialize(workdir: string, autoConnect?: boolean): Promise<void>;
|
|
51
54
|
ensureConfigLoaded(): Promise<McpConfig | null>;
|
|
52
55
|
loadConfig(): Promise<McpConfig | null>;
|
|
56
|
+
/**
|
|
57
|
+
* Read a raw MCP config file, tolerating ENOENT and corrupt JSON.
|
|
58
|
+
*/
|
|
59
|
+
private readConfigFile;
|
|
60
|
+
/**
|
|
61
|
+
* The user-level MCP config path (~/.wave/mcp.json).
|
|
62
|
+
*/
|
|
63
|
+
getUserConfigPath(): string;
|
|
64
|
+
/**
|
|
65
|
+
* The project-level MCP config path (<workdir>/.mcp.json).
|
|
66
|
+
*/
|
|
67
|
+
getProjectConfigPath(): string;
|
|
53
68
|
saveConfig(config: McpConfig): Promise<boolean>;
|
|
54
69
|
getConfig(): McpConfig | null;
|
|
55
70
|
getAllServers(): McpServerStatus[];
|
|
56
71
|
getServer(name: string): McpServerStatus | undefined;
|
|
72
|
+
/**
|
|
73
|
+
* The usage notes each usable server described about itself (`initialize`'s
|
|
74
|
+
* `instructions`), for the announcement appended to the conversation.
|
|
75
|
+
*
|
|
76
|
+
* "Usable" is the same predicate `getAllConnectedTools` uses — connected, or
|
|
77
|
+
* reconnecting with its last-known snapshot retained — so a server's prose is
|
|
78
|
+
* visible exactly while its tools are. A server that dropped, failed to connect
|
|
79
|
+
* or went to `error` keeps its snapshot but stops being reported here, which is
|
|
80
|
+
* what keeps a dead server from still talking to the model.
|
|
81
|
+
*
|
|
82
|
+
* `isDenied` receives flattened tool names (`mcp__server__tool`, the shape
|
|
83
|
+
* permission rules match on); a server whose tools are *all* excluded by rules is
|
|
84
|
+
* dropped whole, so prose cannot reach the context after the user ruled the
|
|
85
|
+
* server out. A server exposing no tools at all is still reported: nothing was
|
|
86
|
+
* excluded, it is simply a server that brings context rather than tools.
|
|
87
|
+
*/
|
|
88
|
+
getServerInstructions(isDenied?: (toolName: string) => boolean): Array<{
|
|
89
|
+
name: string;
|
|
90
|
+
instructions: string;
|
|
91
|
+
}>;
|
|
57
92
|
updateServerStatus(name: string, updates: Partial<McpServerStatus>): void;
|
|
58
93
|
addServer(name: string, config: McpServerConfig): boolean;
|
|
59
94
|
removeServer(name: string): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Drop every MCP server contributed by a plugin (matched on pluginRoot),
|
|
97
|
+
* disconnecting each one. Needed instead of re-adding under the same name
|
|
98
|
+
* because addServer refuses a name that is already registered.
|
|
99
|
+
* Called by the in-place plugin reload path before re-registering.
|
|
100
|
+
* @returns the number of servers removed
|
|
101
|
+
*/
|
|
102
|
+
removeServersForPlugin(pluginRoot: string): number;
|
|
103
|
+
/**
|
|
104
|
+
* Remove a server from a persisted config file (user or project scope),
|
|
105
|
+
* then disconnect and drop it from the in-memory registry.
|
|
106
|
+
* @param scope - "user" removes from ~/.wave/mcp.json; "project" removes from <workdir>/.mcp.json
|
|
107
|
+
* @param name - The server name
|
|
108
|
+
* @returns true if the server was found and removed
|
|
109
|
+
*/
|
|
110
|
+
removeServerFromConfig(scope: "user" | "project", name: string): Promise<boolean>;
|
|
60
111
|
connectServer(name: string): Promise<boolean>;
|
|
61
112
|
/**
|
|
62
113
|
* Schedule auto-reconnect with exponential backoff.
|
|
@@ -71,15 +122,7 @@ export declare class McpManager {
|
|
|
71
122
|
private cancelReconnect;
|
|
72
123
|
disconnectServer(name: string): Promise<boolean>;
|
|
73
124
|
getAllConnectedTools(): McpTool[];
|
|
74
|
-
executeMcpTool(toolName: string, args: Record<string, unknown>, context?: ToolContext): Promise<
|
|
75
|
-
success: boolean;
|
|
76
|
-
content: string;
|
|
77
|
-
serverName?: string;
|
|
78
|
-
images?: Array<{
|
|
79
|
-
data: string;
|
|
80
|
-
mediaType?: string;
|
|
81
|
-
}>;
|
|
82
|
-
}>;
|
|
125
|
+
executeMcpTool(toolName: string, args: Record<string, unknown>, context?: ToolContext): Promise<McpToolCallResult>;
|
|
83
126
|
private executeToolOnConnection;
|
|
84
127
|
cleanup(): Promise<void>;
|
|
85
128
|
/**
|
|
@@ -90,6 +133,21 @@ export declare class McpManager {
|
|
|
90
133
|
* Get all currently available MCP tools as OpenAI function tools
|
|
91
134
|
*/
|
|
92
135
|
getMcpToolsConfig(): ChatCompletionFunctionTool[];
|
|
136
|
+
/**
|
|
137
|
+
* Declared output schema per flattened tool name, for the Exec catalog's return
|
|
138
|
+
* types.
|
|
139
|
+
*
|
|
140
|
+
* A separate accessor because `getMcpToolsConfig()` cannot carry it: an OpenAI
|
|
141
|
+
* function declaration has room for `parameters` and nothing else, so the schema
|
|
142
|
+
* a server declared for its *output* has no field to travel in. Correlated with
|
|
143
|
+
* the same `findToolServer` lookup `getMcpToolPlugins` uses and keyed with the
|
|
144
|
+
* same `mcpToolFlatName`, so the two agree on which server owns a tool.
|
|
145
|
+
*
|
|
146
|
+
* Servers that declare no output schema are simply absent, which renders as
|
|
147
|
+
* `Promise<unknown>`: honest about the call returning *something* of unspecified
|
|
148
|
+
* shape.
|
|
149
|
+
*/
|
|
150
|
+
getMcpToolOutputSchemas(): Map<string, Record<string, unknown>>;
|
|
93
151
|
/**
|
|
94
152
|
* Execute an MCP tool by name (registry version)
|
|
95
153
|
*/
|