@dexto/core 1.5.6 → 1.5.8
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/DextoAgent.cjs +189 -30
- package/dist/agent/DextoAgent.d.ts +44 -9
- package/dist/agent/DextoAgent.d.ts.map +1 -1
- package/dist/agent/DextoAgent.js +190 -31
- package/dist/agent/schemas.cjs +5 -0
- package/dist/agent/schemas.d.ts +456 -66
- package/dist/agent/schemas.d.ts.map +1 -1
- package/dist/agent/schemas.js +5 -0
- package/dist/context/manager.cjs +1 -1
- package/dist/context/manager.js +1 -1
- package/dist/context/utils.cjs +90 -17
- package/dist/context/utils.d.ts.map +1 -1
- package/dist/context/utils.js +90 -17
- package/dist/errors/types.cjs +2 -1
- package/dist/errors/types.d.ts +2 -1
- package/dist/errors/types.d.ts.map +1 -1
- package/dist/errors/types.js +2 -1
- package/dist/events/index.cjs +4 -1
- package/dist/events/index.d.ts +37 -2
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +4 -1
- package/dist/image/types.d.ts +15 -0
- package/dist/image/types.d.ts.map +1 -1
- package/dist/index.browser.d.ts +1 -1
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/llm/curation-config.cjs +82 -0
- package/dist/llm/curation-config.d.ts +13 -0
- package/dist/llm/curation-config.d.ts.map +1 -0
- package/dist/llm/curation-config.js +59 -0
- package/dist/llm/curation.cjs +57 -0
- package/dist/llm/curation.d.ts +16 -0
- package/dist/llm/curation.d.ts.map +1 -0
- package/dist/llm/curation.js +34 -0
- package/dist/llm/error-codes.cjs +1 -0
- package/dist/llm/error-codes.d.ts +1 -0
- package/dist/llm/error-codes.d.ts.map +1 -1
- package/dist/llm/error-codes.js +1 -0
- package/dist/llm/errors.cjs +16 -1
- package/dist/llm/errors.d.ts +15 -8
- package/dist/llm/errors.d.ts.map +1 -1
- package/dist/llm/errors.js +16 -1
- package/dist/llm/executor/provider-options.cjs +1 -1
- package/dist/llm/executor/provider-options.js +1 -1
- package/dist/llm/executor/turn-executor.cjs +35 -2
- package/dist/llm/executor/turn-executor.d.ts.map +1 -1
- package/dist/llm/executor/turn-executor.js +35 -2
- package/dist/llm/index.cjs +14 -3
- package/dist/llm/index.d.ts +3 -1
- package/dist/llm/index.d.ts.map +1 -1
- package/dist/llm/index.js +13 -2
- package/dist/llm/registry/auto-update.cjs +263 -0
- package/dist/llm/registry/auto-update.d.ts +27 -0
- package/dist/llm/registry/auto-update.d.ts.map +1 -0
- package/dist/llm/registry/auto-update.js +227 -0
- package/dist/llm/registry/index.cjs +806 -0
- package/dist/llm/{registry.d.ts → registry/index.d.ts} +67 -13
- package/dist/llm/registry/index.d.ts.map +1 -0
- package/dist/llm/registry/index.js +756 -0
- package/dist/llm/registry/models.generated.cjs +4861 -0
- package/dist/llm/registry/models.generated.d.ts +431 -0
- package/dist/llm/registry/models.generated.d.ts.map +1 -0
- package/dist/llm/registry/models.generated.js +4838 -0
- package/dist/llm/registry/models.manual.cjs +44 -0
- package/dist/llm/registry/models.manual.d.ts +22 -0
- package/dist/llm/registry/models.manual.d.ts.map +1 -0
- package/dist/llm/registry/models.manual.js +21 -0
- package/dist/llm/registry/sync.cjs +354 -0
- package/dist/llm/registry/sync.d.ts +41 -0
- package/dist/llm/registry/sync.d.ts.map +1 -0
- package/dist/llm/registry/sync.js +328 -0
- package/dist/llm/resolver.cjs +29 -7
- package/dist/llm/resolver.d.ts +1 -1
- package/dist/llm/resolver.d.ts.map +1 -1
- package/dist/llm/resolver.js +31 -8
- package/dist/llm/schemas.cjs +13 -1
- package/dist/llm/schemas.d.ts +59 -59
- package/dist/llm/schemas.d.ts.map +1 -1
- package/dist/llm/schemas.js +14 -1
- package/dist/llm/services/factory.cjs +43 -27
- package/dist/llm/services/factory.d.ts +20 -1
- package/dist/llm/services/factory.d.ts.map +1 -1
- package/dist/llm/services/factory.js +44 -28
- package/dist/llm/services/test-utils.integration.cjs +5 -1
- package/dist/llm/services/test-utils.integration.d.ts.map +1 -1
- package/dist/llm/services/test-utils.integration.js +5 -1
- package/dist/llm/services/vercel.cjs +4 -1
- package/dist/llm/services/vercel.d.ts +1 -0
- package/dist/llm/services/vercel.d.ts.map +1 -1
- package/dist/llm/services/vercel.js +4 -1
- package/dist/llm/types.cjs +5 -2
- package/dist/llm/types.d.ts +1 -1
- package/dist/llm/types.d.ts.map +1 -1
- package/dist/llm/types.js +5 -2
- package/dist/llm/validation.cjs +1 -1
- package/dist/llm/validation.js +1 -1
- package/dist/logger/v2/dexto-logger.cjs +4 -0
- package/dist/logger/v2/dexto-logger.d.ts +3 -0
- package/dist/logger/v2/dexto-logger.d.ts.map +1 -1
- package/dist/logger/v2/dexto-logger.js +4 -0
- package/dist/logger/v2/types.d.ts +2 -0
- package/dist/logger/v2/types.d.ts.map +1 -1
- package/dist/mcp/error-codes.cjs +1 -0
- package/dist/mcp/error-codes.d.ts +1 -0
- package/dist/mcp/error-codes.d.ts.map +1 -1
- package/dist/mcp/error-codes.js +1 -0
- package/dist/mcp/errors.cjs +13 -0
- package/dist/mcp/errors.d.ts +7 -0
- package/dist/mcp/errors.d.ts.map +1 -1
- package/dist/mcp/errors.js +13 -0
- package/dist/mcp/manager.cjs +46 -4
- package/dist/mcp/manager.d.ts +10 -2
- package/dist/mcp/manager.d.ts.map +1 -1
- package/dist/mcp/manager.js +46 -4
- package/dist/mcp/mcp-client.cjs +89 -5
- package/dist/mcp/mcp-client.d.ts +5 -1
- package/dist/mcp/mcp-client.d.ts.map +1 -1
- package/dist/mcp/mcp-client.js +89 -5
- package/dist/mcp/schemas.cjs +6 -1
- package/dist/mcp/schemas.d.ts +1 -1
- package/dist/mcp/schemas.d.ts.map +1 -1
- package/dist/mcp/schemas.js +6 -1
- package/dist/mcp/types.d.ts +5 -0
- package/dist/mcp/types.d.ts.map +1 -1
- package/dist/prompts/index.d.ts +1 -1
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/prompt-manager.cjs +90 -4
- package/dist/prompts/prompt-manager.d.ts +16 -6
- package/dist/prompts/prompt-manager.d.ts.map +1 -1
- package/dist/prompts/prompt-manager.js +90 -4
- package/dist/prompts/providers/config-prompt-provider.cjs +104 -10
- package/dist/prompts/providers/config-prompt-provider.d.ts.map +1 -1
- package/dist/prompts/providers/config-prompt-provider.js +105 -11
- package/dist/prompts/providers/custom-prompt-provider.cjs +1 -0
- package/dist/prompts/providers/custom-prompt-provider.d.ts.map +1 -1
- package/dist/prompts/providers/custom-prompt-provider.js +1 -0
- package/dist/prompts/providers/mcp-prompt-provider.cjs +1 -0
- package/dist/prompts/providers/mcp-prompt-provider.d.ts.map +1 -1
- package/dist/prompts/providers/mcp-prompt-provider.js +1 -0
- package/dist/prompts/schemas.cjs +28 -2
- package/dist/prompts/schemas.d.ts +130 -0
- package/dist/prompts/schemas.d.ts.map +1 -1
- package/dist/prompts/schemas.js +28 -2
- package/dist/prompts/types.d.ts +55 -3
- package/dist/prompts/types.d.ts.map +1 -1
- package/dist/resources/handlers/filesystem-handler.cjs +25 -0
- package/dist/resources/handlers/filesystem-handler.d.ts +1 -0
- package/dist/resources/handlers/filesystem-handler.d.ts.map +1 -1
- package/dist/resources/handlers/filesystem-handler.js +25 -0
- package/dist/session/chat-session.cjs +1 -1
- package/dist/session/chat-session.d.ts +1 -1
- package/dist/session/chat-session.d.ts.map +1 -1
- package/dist/session/chat-session.js +1 -1
- package/dist/session/index.d.ts +1 -1
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/message-queue.cjs +29 -5
- package/dist/session/message-queue.d.ts +3 -1
- package/dist/session/message-queue.d.ts.map +1 -1
- package/dist/session/message-queue.js +29 -5
- package/dist/session/session-manager.cjs +84 -3
- package/dist/session/session-manager.d.ts +12 -0
- package/dist/session/session-manager.d.ts.map +1 -1
- package/dist/session/session-manager.js +74 -3
- package/dist/session/types.d.ts +1 -0
- package/dist/session/types.d.ts.map +1 -1
- package/dist/systemPrompt/contributors.cjs +42 -0
- package/dist/systemPrompt/contributors.d.ts +13 -0
- package/dist/systemPrompt/contributors.d.ts.map +1 -1
- package/dist/systemPrompt/contributors.js +41 -0
- package/dist/tools/errors.cjs +7 -3
- package/dist/tools/errors.d.ts +5 -1
- package/dist/tools/errors.d.ts.map +1 -1
- package/dist/tools/errors.js +7 -3
- package/dist/tools/internal-tools/constants.cjs +2 -1
- package/dist/tools/internal-tools/constants.d.ts +1 -1
- package/dist/tools/internal-tools/constants.d.ts.map +1 -1
- package/dist/tools/internal-tools/constants.js +2 -1
- package/dist/tools/internal-tools/implementations/invoke-skill-tool.cjs +140 -0
- package/dist/tools/internal-tools/implementations/invoke-skill-tool.d.ts +24 -0
- package/dist/tools/internal-tools/implementations/invoke-skill-tool.d.ts.map +1 -0
- package/dist/tools/internal-tools/implementations/invoke-skill-tool.js +117 -0
- package/dist/tools/internal-tools/provider.cjs +15 -0
- package/dist/tools/internal-tools/provider.d.ts +15 -1
- package/dist/tools/internal-tools/provider.d.ts.map +1 -1
- package/dist/tools/internal-tools/provider.js +15 -0
- package/dist/tools/internal-tools/registry.cjs +6 -0
- package/dist/tools/internal-tools/registry.d.ts +35 -1
- package/dist/tools/internal-tools/registry.d.ts.map +1 -1
- package/dist/tools/internal-tools/registry.js +6 -0
- package/dist/tools/schemas.d.ts +1 -1
- package/dist/tools/schemas.d.ts.map +1 -1
- package/dist/tools/tool-call-metadata.cjs +75 -0
- package/dist/tools/tool-call-metadata.d.ts +16 -0
- package/dist/tools/tool-call-metadata.d.ts.map +1 -0
- package/dist/tools/tool-call-metadata.js +51 -0
- package/dist/tools/tool-manager.cjs +481 -103
- package/dist/tools/tool-manager.d.ts +131 -9
- package/dist/tools/tool-manager.d.ts.map +1 -1
- package/dist/tools/tool-manager.js +482 -104
- package/dist/utils/api-key-resolver.cjs +5 -2
- package/dist/utils/api-key-resolver.d.ts.map +1 -1
- package/dist/utils/api-key-resolver.js +5 -2
- package/dist/utils/env.cjs +49 -0
- package/dist/utils/env.d.ts +4 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/env.js +24 -0
- package/dist/utils/index.cjs +3 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/service-initializer.cjs +25 -7
- package/dist/utils/service-initializer.d.ts +24 -1
- package/dist/utils/service-initializer.d.ts.map +1 -1
- package/dist/utils/service-initializer.js +25 -7
- package/package.json +6 -2
- package/dist/llm/registry.cjs +0 -1631
- package/dist/llm/registry.d.ts.map +0 -1
- package/dist/llm/registry.js +0 -1586
|
@@ -9,13 +9,15 @@ import { ToolError } from "./errors.js";
|
|
|
9
9
|
import { ToolErrorCode } from "./error-codes.js";
|
|
10
10
|
import { DextoRuntimeError } from "../errors/index.js";
|
|
11
11
|
import { DextoLogComponent } from "../logger/v2/types.js";
|
|
12
|
-
import { ApprovalStatus, ApprovalType } from "../approval/types.js";
|
|
12
|
+
import { ApprovalStatus, ApprovalType, DenialReason } from "../approval/types.js";
|
|
13
13
|
import { InstrumentClass } from "../telemetry/decorators.js";
|
|
14
|
+
import { extractToolCallMeta, wrapToolParametersSchema } from "./tool-call-metadata.js";
|
|
14
15
|
import {
|
|
15
16
|
generateBashPatternKey,
|
|
16
17
|
generateBashPatternSuggestions,
|
|
17
18
|
isDangerousCommand
|
|
18
19
|
} from "./bash-pattern-utils.js";
|
|
20
|
+
import { isBackgroundTasksEnabled } from "../utils/env.js";
|
|
19
21
|
_ToolManager_decorators = [InstrumentClass({
|
|
20
22
|
prefix: "tool",
|
|
21
23
|
excludeMethods: [
|
|
@@ -45,6 +47,14 @@ let _ToolManager = class _ToolManager {
|
|
|
45
47
|
toolsCache = {};
|
|
46
48
|
cacheValid = false;
|
|
47
49
|
logger;
|
|
50
|
+
// Session-level auto-approve tools for skills
|
|
51
|
+
// When a skill with allowedTools is invoked, those tools are auto-approved (skip confirmation)
|
|
52
|
+
// This is ADDITIVE - other tools are NOT blocked, they just go through normal approval flow
|
|
53
|
+
sessionAutoApproveTools = /* @__PURE__ */ new Map();
|
|
54
|
+
// Session-level auto-approve tools set by users (UI)
|
|
55
|
+
sessionUserAutoApproveTools = /* @__PURE__ */ new Map();
|
|
56
|
+
sessionDisabledTools = /* @__PURE__ */ new Map();
|
|
57
|
+
globalDisabledTools = [];
|
|
48
58
|
constructor(mcpManager, approvalManager, allowedToolsProvider, approvalMode, agentEventBus, toolPolicies, options, logger) {
|
|
49
59
|
this.mcpManager = mcpManager;
|
|
50
60
|
this.approvalManager = approvalManager;
|
|
@@ -96,6 +106,204 @@ let _ToolManager = class _ToolManager {
|
|
|
96
106
|
this.logger.debug("Agent reference configured for custom tools");
|
|
97
107
|
}
|
|
98
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Set prompt manager for invoke_skill tool (called after construction to avoid circular dependencies)
|
|
111
|
+
* Must be called before initialize() if invoke_skill tool is enabled
|
|
112
|
+
*/
|
|
113
|
+
setPromptManager(promptManager) {
|
|
114
|
+
if (this.internalToolsProvider) {
|
|
115
|
+
this.internalToolsProvider.setPromptManager(promptManager);
|
|
116
|
+
this.logger.debug("PromptManager reference configured for invoke_skill tool");
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Set task forker for context:fork skill execution (late-binding)
|
|
121
|
+
* Called by agent-spawner custom tool provider after RuntimeService is created.
|
|
122
|
+
* This enables invoke_skill to fork execution to an isolated subagent.
|
|
123
|
+
*/
|
|
124
|
+
setTaskForker(taskForker) {
|
|
125
|
+
if (this.internalToolsProvider) {
|
|
126
|
+
this.internalToolsProvider.setTaskForker(taskForker);
|
|
127
|
+
this.logger.debug(
|
|
128
|
+
"TaskForker reference configured for invoke_skill (context:fork support)"
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// ============= SESSION AUTO-APPROVE TOOLS =============
|
|
133
|
+
/**
|
|
134
|
+
* Set session-level auto-approve tools.
|
|
135
|
+
* When set, these tools will skip confirmation prompts for this session.
|
|
136
|
+
* This is ADDITIVE - other tools are NOT blocked, they just go through normal approval flow.
|
|
137
|
+
*
|
|
138
|
+
* @param sessionId The session ID
|
|
139
|
+
* @param autoApproveTools Array of tool names to auto-approve (e.g., ['custom--bash_exec', 'custom--read_file'])
|
|
140
|
+
*/
|
|
141
|
+
setSessionAutoApproveTools(sessionId, autoApproveTools) {
|
|
142
|
+
if (autoApproveTools.length === 0) {
|
|
143
|
+
this.clearSessionAutoApproveTools(sessionId);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
this.sessionAutoApproveTools.set(sessionId, autoApproveTools);
|
|
147
|
+
this.logger.info(
|
|
148
|
+
`Session auto-approve tools set for '${sessionId}': ${autoApproveTools.length} tools`
|
|
149
|
+
);
|
|
150
|
+
this.logger.debug(`Auto-approve tools: ${autoApproveTools.join(", ")}`);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Set session-level auto-approve tools chosen by the user.
|
|
154
|
+
*/
|
|
155
|
+
setSessionUserAutoApproveTools(sessionId, autoApproveTools) {
|
|
156
|
+
if (autoApproveTools.length === 0) {
|
|
157
|
+
this.clearSessionUserAutoApproveTools(sessionId);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
this.sessionUserAutoApproveTools.set(sessionId, autoApproveTools);
|
|
161
|
+
this.logger.info(
|
|
162
|
+
`Session user auto-approve tools set for '${sessionId}': ${autoApproveTools.length} tools`
|
|
163
|
+
);
|
|
164
|
+
this.logger.debug(`User auto-approve tools: ${autoApproveTools.join(", ")}`);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Clear session-level auto-approve tools chosen by the user.
|
|
168
|
+
*/
|
|
169
|
+
clearSessionUserAutoApproveTools(sessionId) {
|
|
170
|
+
const hadAutoApprove = this.sessionUserAutoApproveTools.has(sessionId);
|
|
171
|
+
this.sessionUserAutoApproveTools.delete(sessionId);
|
|
172
|
+
if (hadAutoApprove) {
|
|
173
|
+
this.logger.info(`Session user auto-approve tools cleared for '${sessionId}'`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Clear session-level auto-approve tools.
|
|
178
|
+
* Call this when the session ends or when the skill completes.
|
|
179
|
+
*
|
|
180
|
+
* @param sessionId The session ID to clear auto-approve tools for
|
|
181
|
+
*/
|
|
182
|
+
clearSessionAutoApproveTools(sessionId) {
|
|
183
|
+
const hadAutoApprove = this.sessionAutoApproveTools.has(sessionId);
|
|
184
|
+
this.sessionAutoApproveTools.delete(sessionId);
|
|
185
|
+
if (hadAutoApprove) {
|
|
186
|
+
this.logger.info(`Session auto-approve tools cleared for '${sessionId}'`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
hasSessionUserAutoApproveTools(sessionId) {
|
|
190
|
+
return this.sessionUserAutoApproveTools.has(sessionId);
|
|
191
|
+
}
|
|
192
|
+
// ============= ENABLED/DISABLED TOOLS =============
|
|
193
|
+
/**
|
|
194
|
+
* Set global disabled tools (agent-level preferences).
|
|
195
|
+
*/
|
|
196
|
+
setGlobalDisabledTools(toolNames) {
|
|
197
|
+
this.globalDisabledTools = [...toolNames];
|
|
198
|
+
this.logger.info("Global disabled tools updated", {
|
|
199
|
+
count: toolNames.length
|
|
200
|
+
});
|
|
201
|
+
this.agentEventBus.emit("tools:enabled-updated", {
|
|
202
|
+
scope: "global",
|
|
203
|
+
disabledTools: [...this.globalDisabledTools]
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
getGlobalDisabledTools() {
|
|
207
|
+
return [...this.globalDisabledTools];
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Set session-level disabled tools (overrides global list).
|
|
211
|
+
*/
|
|
212
|
+
setSessionDisabledTools(sessionId, toolNames) {
|
|
213
|
+
if (toolNames.length === 0) {
|
|
214
|
+
this.clearSessionDisabledTools(sessionId);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
this.sessionDisabledTools.set(sessionId, [...toolNames]);
|
|
218
|
+
this.logger.info("Session disabled tools updated", {
|
|
219
|
+
sessionId,
|
|
220
|
+
count: toolNames.length
|
|
221
|
+
});
|
|
222
|
+
this.agentEventBus.emit("tools:enabled-updated", {
|
|
223
|
+
scope: "session",
|
|
224
|
+
sessionId,
|
|
225
|
+
disabledTools: [...toolNames]
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Clear session-level disabled tools.
|
|
230
|
+
*/
|
|
231
|
+
clearSessionDisabledTools(sessionId) {
|
|
232
|
+
const hadOverrides = this.sessionDisabledTools.has(sessionId);
|
|
233
|
+
this.sessionDisabledTools.delete(sessionId);
|
|
234
|
+
if (hadOverrides) {
|
|
235
|
+
this.logger.info("Session disabled tools cleared", { sessionId });
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Get disabled tools for a session (session override wins).
|
|
240
|
+
*/
|
|
241
|
+
getDisabledTools(sessionId) {
|
|
242
|
+
if (sessionId && this.sessionDisabledTools.has(sessionId)) {
|
|
243
|
+
return this.sessionDisabledTools.get(sessionId) ?? [];
|
|
244
|
+
}
|
|
245
|
+
return this.globalDisabledTools;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Filter a tool set based on disabled tools for a session.
|
|
249
|
+
*/
|
|
250
|
+
filterToolsForSession(toolSet, sessionId) {
|
|
251
|
+
const disabled = new Set(this.getDisabledTools(sessionId));
|
|
252
|
+
if (disabled.size === 0) {
|
|
253
|
+
return toolSet;
|
|
254
|
+
}
|
|
255
|
+
return Object.fromEntries(
|
|
256
|
+
Object.entries(toolSet).filter(([toolName]) => !disabled.has(toolName))
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Check if a session has auto-approve tools set.
|
|
261
|
+
*
|
|
262
|
+
* @param sessionId The session ID to check
|
|
263
|
+
* @returns true if the session has auto-approve tools
|
|
264
|
+
*/
|
|
265
|
+
hasSessionAutoApproveTools(sessionId) {
|
|
266
|
+
return this.sessionAutoApproveTools.has(sessionId);
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Get the auto-approve tools for a session (skill-provided list).
|
|
270
|
+
*
|
|
271
|
+
* @param sessionId The session ID to check
|
|
272
|
+
* @returns Array of auto-approve tool names, or undefined if none set
|
|
273
|
+
*/
|
|
274
|
+
getSessionAutoApproveTools(sessionId) {
|
|
275
|
+
return this.sessionAutoApproveTools.get(sessionId);
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Get the user auto-approve tools for a session.
|
|
279
|
+
*/
|
|
280
|
+
getSessionUserAutoApproveTools(sessionId) {
|
|
281
|
+
return this.sessionUserAutoApproveTools.get(sessionId);
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Combined auto-approve list for a session.
|
|
285
|
+
*/
|
|
286
|
+
getCombinedSessionAutoApproveTools(sessionId) {
|
|
287
|
+
return [
|
|
288
|
+
...this.sessionAutoApproveTools.get(sessionId) ?? [],
|
|
289
|
+
...this.sessionUserAutoApproveTools.get(sessionId) ?? []
|
|
290
|
+
];
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Check if a tool should be auto-approved for a session.
|
|
294
|
+
* Returns true if the tool is in the session's auto-approve list.
|
|
295
|
+
*
|
|
296
|
+
* @param sessionId The session ID
|
|
297
|
+
* @param toolName The tool name to check
|
|
298
|
+
* @returns true if the tool should be auto-approved
|
|
299
|
+
*/
|
|
300
|
+
isToolAutoApprovedForSession(sessionId, toolName) {
|
|
301
|
+
const autoApproveTools = this.getCombinedSessionAutoApproveTools(sessionId);
|
|
302
|
+
if (autoApproveTools.length === 0) {
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
return autoApproveTools.some((pattern) => this.matchesToolPolicy(toolName, pattern));
|
|
306
|
+
}
|
|
99
307
|
/**
|
|
100
308
|
* Invalidate the tools cache when tool sources change
|
|
101
309
|
*/
|
|
@@ -121,6 +329,14 @@ let _ToolManager = class _ToolManager {
|
|
|
121
329
|
);
|
|
122
330
|
this.invalidateCache();
|
|
123
331
|
});
|
|
332
|
+
this.agentEventBus.on("run:complete", (payload) => {
|
|
333
|
+
if (this.hasSessionAutoApproveTools(payload.sessionId)) {
|
|
334
|
+
this.logger.debug(
|
|
335
|
+
`\u{1F513} Run complete, clearing session auto-approve tools for '${payload.sessionId}'`
|
|
336
|
+
);
|
|
337
|
+
this.clearSessionAutoApproveTools(payload.sessionId);
|
|
338
|
+
}
|
|
339
|
+
});
|
|
124
340
|
}
|
|
125
341
|
// ==================== Bash Pattern Approval Helpers ====================
|
|
126
342
|
/**
|
|
@@ -280,7 +496,8 @@ let _ToolManager = class _ToolManager {
|
|
|
280
496
|
allTools[qualifiedName] = {
|
|
281
497
|
...toolDef,
|
|
282
498
|
name: qualifiedName,
|
|
283
|
-
description: `${toolDef.description || "No description provided"} (internal tool)
|
|
499
|
+
description: `${toolDef.description || "No description provided"} (internal tool)`,
|
|
500
|
+
parameters: wrapToolParametersSchema(toolDef.parameters)
|
|
284
501
|
};
|
|
285
502
|
}
|
|
286
503
|
for (const [toolName, toolDef] of Object.entries(customTools)) {
|
|
@@ -288,7 +505,8 @@ let _ToolManager = class _ToolManager {
|
|
|
288
505
|
allTools[qualifiedName] = {
|
|
289
506
|
...toolDef,
|
|
290
507
|
name: qualifiedName,
|
|
291
|
-
description: `${toolDef.description || "No description provided"} (custom tool)
|
|
508
|
+
description: `${toolDef.description || "No description provided"} (custom tool)`,
|
|
509
|
+
parameters: wrapToolParametersSchema(toolDef.parameters)
|
|
292
510
|
};
|
|
293
511
|
}
|
|
294
512
|
for (const [toolName, toolDef] of Object.entries(mcpTools)) {
|
|
@@ -296,7 +514,8 @@ let _ToolManager = class _ToolManager {
|
|
|
296
514
|
allTools[qualifiedName] = {
|
|
297
515
|
...toolDef,
|
|
298
516
|
name: qualifiedName,
|
|
299
|
-
description: `${toolDef.description || "No description provided"} (via MCP servers)
|
|
517
|
+
description: `${toolDef.description || "No description provided"} (via MCP servers)`,
|
|
518
|
+
parameters: wrapToolParametersSchema(toolDef.parameters)
|
|
300
519
|
};
|
|
301
520
|
}
|
|
302
521
|
const totalTools = Object.keys(allTools).length;
|
|
@@ -332,21 +551,25 @@ let _ToolManager = class _ToolManager {
|
|
|
332
551
|
* @param abortSignal Optional abort signal for cancellation support
|
|
333
552
|
*/
|
|
334
553
|
async executeTool(toolName, args, toolCallId, sessionId, abortSignal) {
|
|
554
|
+
const { toolArgs: rawToolArgs, meta } = extractToolCallMeta(args);
|
|
555
|
+
let toolArgs = rawToolArgs;
|
|
556
|
+
const backgroundTasksEnabled = isBackgroundTasksEnabled();
|
|
335
557
|
this.logger.debug(`\u{1F527} Tool execution requested: '${toolName}' (toolCallId: ${toolCallId})`);
|
|
336
|
-
this.logger.debug(`Tool args: ${JSON.stringify(
|
|
558
|
+
this.logger.debug(`Tool args: ${JSON.stringify(toolArgs, null, 2)}`);
|
|
337
559
|
if (sessionId) {
|
|
338
560
|
this.agentEventBus.emit("llm:tool-call", {
|
|
339
561
|
toolName,
|
|
340
|
-
args,
|
|
562
|
+
args: toolArgs,
|
|
341
563
|
callId: toolCallId,
|
|
342
564
|
sessionId
|
|
343
565
|
});
|
|
344
566
|
}
|
|
345
567
|
const { requireApproval, approvalStatus } = await this.handleToolApproval(
|
|
346
568
|
toolName,
|
|
347
|
-
|
|
569
|
+
toolArgs,
|
|
348
570
|
toolCallId,
|
|
349
|
-
sessionId
|
|
571
|
+
sessionId,
|
|
572
|
+
meta.callDescription
|
|
350
573
|
);
|
|
351
574
|
this.logger.debug(`\u2705 Tool execution approved: ${toolName}`);
|
|
352
575
|
this.logger.info(
|
|
@@ -363,7 +586,7 @@ let _ToolManager = class _ToolManager {
|
|
|
363
586
|
if (this.pluginManager && this.sessionManager && this.stateManager) {
|
|
364
587
|
const beforePayload = {
|
|
365
588
|
toolName,
|
|
366
|
-
args,
|
|
589
|
+
args: toolArgs,
|
|
367
590
|
...sessionId !== void 0 && { sessionId }
|
|
368
591
|
};
|
|
369
592
|
const modifiedPayload = await this.pluginManager.executePlugins(
|
|
@@ -377,10 +600,21 @@ let _ToolManager = class _ToolManager {
|
|
|
377
600
|
...sessionId !== void 0 && { sessionId }
|
|
378
601
|
}
|
|
379
602
|
);
|
|
380
|
-
|
|
603
|
+
toolArgs = modifiedPayload.args;
|
|
381
604
|
}
|
|
382
605
|
try {
|
|
383
606
|
let result;
|
|
607
|
+
const registerBackgroundTask = (promise, description) => {
|
|
608
|
+
const fallbackId = `task-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
609
|
+
return {
|
|
610
|
+
result: {
|
|
611
|
+
taskId: toolCallId ?? fallbackId,
|
|
612
|
+
status: "running",
|
|
613
|
+
description
|
|
614
|
+
},
|
|
615
|
+
promise
|
|
616
|
+
};
|
|
617
|
+
};
|
|
384
618
|
if (toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX)) {
|
|
385
619
|
this.logger.debug(`\u{1F527} Detected MCP tool: '${toolName}'`);
|
|
386
620
|
const actualToolName = toolName.substring(_ToolManager.MCP_TOOL_PREFIX.length);
|
|
@@ -388,7 +622,34 @@ let _ToolManager = class _ToolManager {
|
|
|
388
622
|
throw ToolError.invalidName(toolName, "tool name cannot be empty after prefix");
|
|
389
623
|
}
|
|
390
624
|
this.logger.debug(`\u{1F3AF} MCP routing: '${toolName}' -> '${actualToolName}'`);
|
|
391
|
-
|
|
625
|
+
const runInBackground = backgroundTasksEnabled && meta.runInBackground === true && sessionId !== void 0;
|
|
626
|
+
if (meta.runInBackground === true && !backgroundTasksEnabled) {
|
|
627
|
+
this.logger.debug(
|
|
628
|
+
"Background tool execution disabled; running synchronously instead.",
|
|
629
|
+
{ toolName }
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
if (runInBackground) {
|
|
633
|
+
const backgroundSessionId = sessionId;
|
|
634
|
+
const { result: backgroundResult, promise } = registerBackgroundTask(
|
|
635
|
+
this.mcpManager.executeTool(actualToolName, toolArgs, backgroundSessionId),
|
|
636
|
+
`MCP tool ${actualToolName}`
|
|
637
|
+
);
|
|
638
|
+
this.agentEventBus.emit("tool:background", {
|
|
639
|
+
toolName,
|
|
640
|
+
toolCallId: backgroundResult.taskId,
|
|
641
|
+
sessionId: backgroundSessionId,
|
|
642
|
+
description: backgroundResult.description,
|
|
643
|
+
promise,
|
|
644
|
+
...meta.timeoutMs !== void 0 && { timeoutMs: meta.timeoutMs },
|
|
645
|
+
...meta.notifyOnComplete !== void 0 && {
|
|
646
|
+
notifyOnComplete: meta.notifyOnComplete
|
|
647
|
+
}
|
|
648
|
+
});
|
|
649
|
+
result = backgroundResult;
|
|
650
|
+
} else {
|
|
651
|
+
result = await this.mcpManager.executeTool(actualToolName, toolArgs, sessionId);
|
|
652
|
+
}
|
|
392
653
|
} else if (toolName.startsWith(_ToolManager.INTERNAL_TOOL_PREFIX)) {
|
|
393
654
|
this.logger.debug(`\u{1F527} Detected internal tool: '${toolName}'`);
|
|
394
655
|
const actualToolName = toolName.substring(_ToolManager.INTERNAL_TOOL_PREFIX.length);
|
|
@@ -399,13 +660,46 @@ let _ToolManager = class _ToolManager {
|
|
|
399
660
|
throw ToolError.internalToolsNotInitialized(toolName);
|
|
400
661
|
}
|
|
401
662
|
this.logger.debug(`\u{1F3AF} Internal routing: '${toolName}' -> '${actualToolName}'`);
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
663
|
+
const runInBackground = backgroundTasksEnabled && meta.runInBackground === true && sessionId !== void 0;
|
|
664
|
+
if (meta.runInBackground === true && !backgroundTasksEnabled) {
|
|
665
|
+
this.logger.debug(
|
|
666
|
+
"Background tool execution disabled; running synchronously instead.",
|
|
667
|
+
{ toolName }
|
|
668
|
+
);
|
|
669
|
+
}
|
|
670
|
+
if (runInBackground) {
|
|
671
|
+
const backgroundSessionId = sessionId;
|
|
672
|
+
const { result: backgroundResult, promise } = registerBackgroundTask(
|
|
673
|
+
this.internalToolsProvider.executeTool(
|
|
674
|
+
actualToolName,
|
|
675
|
+
toolArgs,
|
|
676
|
+
backgroundSessionId,
|
|
677
|
+
abortSignal,
|
|
678
|
+
toolCallId
|
|
679
|
+
),
|
|
680
|
+
`Internal tool ${actualToolName}`
|
|
681
|
+
);
|
|
682
|
+
this.agentEventBus.emit("tool:background", {
|
|
683
|
+
toolName,
|
|
684
|
+
toolCallId: backgroundResult.taskId,
|
|
685
|
+
sessionId: backgroundSessionId,
|
|
686
|
+
description: backgroundResult.description,
|
|
687
|
+
promise,
|
|
688
|
+
...meta.timeoutMs !== void 0 && { timeoutMs: meta.timeoutMs },
|
|
689
|
+
...meta.notifyOnComplete !== void 0 && {
|
|
690
|
+
notifyOnComplete: meta.notifyOnComplete
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
result = backgroundResult;
|
|
694
|
+
} else {
|
|
695
|
+
result = await this.internalToolsProvider.executeTool(
|
|
696
|
+
actualToolName,
|
|
697
|
+
toolArgs,
|
|
698
|
+
sessionId,
|
|
699
|
+
abortSignal,
|
|
700
|
+
toolCallId
|
|
701
|
+
);
|
|
702
|
+
}
|
|
409
703
|
} else if (toolName.startsWith(_ToolManager.CUSTOM_TOOL_PREFIX)) {
|
|
410
704
|
this.logger.debug(`\u{1F527} Detected custom tool: '${toolName}'`);
|
|
411
705
|
const actualToolName = toolName.substring(_ToolManager.CUSTOM_TOOL_PREFIX.length);
|
|
@@ -416,13 +710,46 @@ let _ToolManager = class _ToolManager {
|
|
|
416
710
|
throw ToolError.internalToolsNotInitialized(toolName);
|
|
417
711
|
}
|
|
418
712
|
this.logger.debug(`\u{1F3AF} Custom routing: '${toolName}' -> '${actualToolName}'`);
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
713
|
+
const runInBackground = backgroundTasksEnabled && meta.runInBackground === true && sessionId !== void 0;
|
|
714
|
+
if (meta.runInBackground === true && !backgroundTasksEnabled) {
|
|
715
|
+
this.logger.debug(
|
|
716
|
+
"Background tool execution disabled; running synchronously instead.",
|
|
717
|
+
{ toolName }
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
if (runInBackground) {
|
|
721
|
+
const backgroundSessionId = sessionId;
|
|
722
|
+
const { result: backgroundResult, promise } = registerBackgroundTask(
|
|
723
|
+
this.internalToolsProvider.executeTool(
|
|
724
|
+
actualToolName,
|
|
725
|
+
toolArgs,
|
|
726
|
+
backgroundSessionId,
|
|
727
|
+
abortSignal,
|
|
728
|
+
toolCallId
|
|
729
|
+
),
|
|
730
|
+
`Custom tool ${actualToolName}`
|
|
731
|
+
);
|
|
732
|
+
this.agentEventBus.emit("tool:background", {
|
|
733
|
+
toolName,
|
|
734
|
+
toolCallId: backgroundResult.taskId,
|
|
735
|
+
sessionId: backgroundSessionId,
|
|
736
|
+
description: backgroundResult.description,
|
|
737
|
+
promise,
|
|
738
|
+
...meta.timeoutMs !== void 0 && { timeoutMs: meta.timeoutMs },
|
|
739
|
+
...meta.notifyOnComplete !== void 0 && {
|
|
740
|
+
notifyOnComplete: meta.notifyOnComplete
|
|
741
|
+
}
|
|
742
|
+
});
|
|
743
|
+
result = backgroundResult;
|
|
744
|
+
} else {
|
|
745
|
+
result = await this.internalToolsProvider.executeTool(
|
|
746
|
+
actualToolName,
|
|
747
|
+
toolArgs,
|
|
748
|
+
sessionId,
|
|
749
|
+
abortSignal,
|
|
750
|
+
toolCallId
|
|
751
|
+
);
|
|
752
|
+
}
|
|
426
753
|
} else {
|
|
427
754
|
this.logger.debug(`\u{1F527} Detected tool without proper prefix: '${toolName}'`);
|
|
428
755
|
const stats = await this.getToolStats();
|
|
@@ -672,21 +999,34 @@ let _ToolManager = class _ToolManager {
|
|
|
672
999
|
throw ToolError.executionDenied(toolName, sessionId);
|
|
673
1000
|
}
|
|
674
1001
|
/**
|
|
675
|
-
* Handle tool approval
|
|
676
|
-
*
|
|
677
|
-
|
|
1002
|
+
* Handle tool approval flow. Checks various precedence levels to determine
|
|
1003
|
+
* if a tool should be auto-approved, denied, or requires manual approval.
|
|
1004
|
+
*/
|
|
1005
|
+
async handleToolApproval(toolName, args, toolCallId, sessionId, callDescription) {
|
|
1006
|
+
const quickResult = await this.tryQuickApprovalResolution(toolName, args, sessionId);
|
|
1007
|
+
if (quickResult !== null) {
|
|
1008
|
+
return quickResult;
|
|
1009
|
+
}
|
|
1010
|
+
return this.requestManualApproval(toolName, args, toolCallId, sessionId, callDescription);
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
* Try to resolve tool approval quickly based on policies and cached permissions.
|
|
1014
|
+
* Returns null if manual approval is needed.
|
|
678
1015
|
*
|
|
679
|
-
*
|
|
680
|
-
*
|
|
681
|
-
*
|
|
682
|
-
*
|
|
1016
|
+
* Precedence order (highest to lowest):
|
|
1017
|
+
* 1. Static deny list (security - always blocks)
|
|
1018
|
+
* 2. Custom approval override (tool-specific approval flows)
|
|
1019
|
+
* 3. Session auto-approve (skill allowed-tools)
|
|
1020
|
+
* 4. Static allow list
|
|
1021
|
+
* 5. Dynamic "remembered" allowed list
|
|
1022
|
+
* 6. Bash command patterns
|
|
1023
|
+
* 7. Approval mode (auto-approve/auto-deny)
|
|
683
1024
|
*/
|
|
684
|
-
async
|
|
1025
|
+
async tryQuickApprovalResolution(toolName, args, sessionId) {
|
|
685
1026
|
if (this.isInAlwaysDenyList(toolName)) {
|
|
686
1027
|
this.logger.info(
|
|
687
1028
|
`Tool '${toolName}' is in static deny list \u2013 blocking execution (session: ${sessionId ?? "global"})`
|
|
688
1029
|
);
|
|
689
|
-
this.logger.debug(`\u{1F6AB} Tool execution blocked by policy: ${toolName}`);
|
|
690
1030
|
throw ToolError.executionDenied(toolName, sessionId);
|
|
691
1031
|
}
|
|
692
1032
|
const customApprovalResult = await this.checkCustomApprovalOverride(
|
|
@@ -697,25 +1037,29 @@ let _ToolManager = class _ToolManager {
|
|
|
697
1037
|
if (customApprovalResult.handled) {
|
|
698
1038
|
return { requireApproval: true, approvalStatus: "approved" };
|
|
699
1039
|
}
|
|
1040
|
+
if (sessionId && this.isToolAutoApprovedForSession(sessionId, toolName)) {
|
|
1041
|
+
this.logger.info(
|
|
1042
|
+
`Tool '${toolName}' is in session's auto-approve list \u2013 skipping confirmation (session: ${sessionId})`
|
|
1043
|
+
);
|
|
1044
|
+
return { requireApproval: false };
|
|
1045
|
+
}
|
|
700
1046
|
if (this.isInAlwaysAllowList(toolName)) {
|
|
701
1047
|
this.logger.info(
|
|
702
1048
|
`Tool '${toolName}' is in static allow list \u2013 skipping confirmation (session: ${sessionId ?? "global"})`
|
|
703
1049
|
);
|
|
704
1050
|
return { requireApproval: false };
|
|
705
1051
|
}
|
|
706
|
-
|
|
707
|
-
if (isAllowed) {
|
|
1052
|
+
if (await this.allowedToolsProvider.isToolAllowed(toolName, sessionId)) {
|
|
708
1053
|
this.logger.info(
|
|
709
1054
|
`Tool '${toolName}' already allowed for session '${sessionId ?? "global"}' \u2013 skipping confirmation.`
|
|
710
1055
|
);
|
|
711
1056
|
return { requireApproval: false };
|
|
712
1057
|
}
|
|
713
|
-
let bashPatternResult;
|
|
714
1058
|
if (this.isBashTool(toolName)) {
|
|
715
1059
|
const command = args.command;
|
|
716
1060
|
if (command) {
|
|
717
|
-
|
|
718
|
-
if (
|
|
1061
|
+
const bashResult = this.checkBashPatternApproval(command);
|
|
1062
|
+
if (bashResult.approved) {
|
|
719
1063
|
this.logger.info(
|
|
720
1064
|
`Bash command '${command}' matched approved pattern \u2013 skipping confirmation.`
|
|
721
1065
|
);
|
|
@@ -731,79 +1075,38 @@ let _ToolManager = class _ToolManager {
|
|
|
731
1075
|
this.logger.debug(`\u{1F6AB} Auto-denying tool execution: ${toolName}`);
|
|
732
1076
|
throw ToolError.executionDenied(toolName, sessionId);
|
|
733
1077
|
}
|
|
1078
|
+
return null;
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* Request manual approval from the user for a tool execution.
|
|
1082
|
+
* Generates preview, sends approval request, and handles the response.
|
|
1083
|
+
*/
|
|
1084
|
+
async requestManualApproval(toolName, args, toolCallId, sessionId, callDescription) {
|
|
734
1085
|
this.logger.info(
|
|
735
1086
|
`Tool confirmation requested for ${toolName}, sessionId: ${sessionId ?? "global"}`
|
|
736
1087
|
);
|
|
737
1088
|
try {
|
|
738
|
-
|
|
739
|
-
const actualToolName = toolName.replace(/^internal--/, "").replace(/^custom--/, "");
|
|
740
|
-
const internalTool = this.internalToolsProvider?.getTool(actualToolName);
|
|
741
|
-
if (internalTool?.generatePreview) {
|
|
742
|
-
try {
|
|
743
|
-
const context = { sessionId, toolCallId };
|
|
744
|
-
const preview = await internalTool.generatePreview(args, context);
|
|
745
|
-
displayPreview = preview ?? void 0;
|
|
746
|
-
this.logger.debug(`Generated preview for ${toolName}`);
|
|
747
|
-
} catch (previewError) {
|
|
748
|
-
if (previewError instanceof DextoRuntimeError && previewError.code === ToolErrorCode.VALIDATION_FAILED) {
|
|
749
|
-
this.logger.debug(
|
|
750
|
-
`Validation failed for ${toolName}: ${previewError.message}`
|
|
751
|
-
);
|
|
752
|
-
throw previewError;
|
|
753
|
-
}
|
|
754
|
-
this.logger.debug(
|
|
755
|
-
`Preview generation failed for ${toolName}: ${previewError instanceof Error ? previewError.message : String(previewError)}`
|
|
756
|
-
);
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
const requestData = {
|
|
1089
|
+
const displayPreview = await this.generateToolPreview(
|
|
760
1090
|
toolName,
|
|
1091
|
+
args,
|
|
761
1092
|
toolCallId,
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
1093
|
+
sessionId
|
|
1094
|
+
);
|
|
1095
|
+
const suggestedPatterns = this.getBashSuggestedPatterns(toolName, args);
|
|
1096
|
+
const response = await this.approvalManager.requestToolConfirmation({
|
|
1097
|
+
toolName,
|
|
1098
|
+
toolCallId,
|
|
1099
|
+
args,
|
|
1100
|
+
...callDescription !== void 0 && { description: callDescription },
|
|
1101
|
+
...sessionId !== void 0 && { sessionId },
|
|
1102
|
+
...displayPreview !== void 0 && { displayPreview },
|
|
1103
|
+
...suggestedPatterns !== void 0 && { suggestedPatterns }
|
|
1104
|
+
});
|
|
774
1105
|
if (response.status === ApprovalStatus.APPROVED && response.data) {
|
|
775
|
-
|
|
776
|
-
const rememberPattern = "rememberPattern" in response.data ? response.data.rememberPattern : void 0;
|
|
777
|
-
if (rememberChoice) {
|
|
778
|
-
const allowSessionId = sessionId ?? response.sessionId;
|
|
779
|
-
await this.allowedToolsProvider.allowTool(toolName, allowSessionId);
|
|
780
|
-
this.logger.info(
|
|
781
|
-
`Tool '${toolName}' added to allowed tools for session '${allowSessionId ?? "global"}' (remember choice selected)`
|
|
782
|
-
);
|
|
783
|
-
this.autoApprovePendingToolRequests(toolName, allowSessionId);
|
|
784
|
-
} else if (rememberPattern && typeof rememberPattern === "string" && this.isBashTool(toolName)) {
|
|
785
|
-
this.approvalManager.addBashPattern(rememberPattern);
|
|
786
|
-
this.logger.info(
|
|
787
|
-
`Bash pattern '${rememberPattern}' added for session approval`
|
|
788
|
-
);
|
|
789
|
-
this.autoApprovePendingBashRequests(rememberPattern, sessionId);
|
|
790
|
-
}
|
|
1106
|
+
await this.handleRememberChoice(toolName, response, sessionId);
|
|
791
1107
|
}
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
if (response.status === ApprovalStatus.CANCELLED && response.reason === "timeout") {
|
|
795
|
-
this.logger.info(
|
|
796
|
-
`Tool confirmation timed out for ${toolName}, sessionId: ${sessionId ?? "global"}`
|
|
797
|
-
);
|
|
798
|
-
this.logger.debug(`\u23F1\uFE0F Tool execution timed out: ${toolName}`);
|
|
799
|
-
const timeoutMs = response.timeoutMs ?? 0;
|
|
800
|
-
throw ToolError.executionTimeout(toolName, timeoutMs, sessionId);
|
|
801
|
-
}
|
|
802
|
-
this.logger.info(
|
|
803
|
-
`Tool confirmation denied for ${toolName}, sessionId: ${sessionId ?? "global"}, reason: ${response.reason ?? "unknown"}`
|
|
804
|
-
);
|
|
805
|
-
this.logger.debug(`\u{1F6AB} Tool execution denied: ${toolName}`);
|
|
806
|
-
throw ToolError.executionDenied(toolName, sessionId);
|
|
1108
|
+
if (response.status !== ApprovalStatus.APPROVED) {
|
|
1109
|
+
this.handleApprovalDenied(toolName, response, sessionId);
|
|
807
1110
|
}
|
|
808
1111
|
this.logger.info(
|
|
809
1112
|
`Tool confirmation approved for ${toolName}, sessionId: ${sessionId ?? "global"}`
|
|
@@ -816,6 +1119,81 @@ let _ToolManager = class _ToolManager {
|
|
|
816
1119
|
throw error;
|
|
817
1120
|
}
|
|
818
1121
|
}
|
|
1122
|
+
/**
|
|
1123
|
+
* Generate a preview for the tool approval UI if the tool supports it.
|
|
1124
|
+
*/
|
|
1125
|
+
async generateToolPreview(toolName, args, toolCallId, sessionId) {
|
|
1126
|
+
const actualToolName = toolName.replace(/^internal--/, "").replace(/^custom--/, "");
|
|
1127
|
+
const internalTool = this.internalToolsProvider?.getTool(actualToolName);
|
|
1128
|
+
if (!internalTool?.generatePreview) {
|
|
1129
|
+
return void 0;
|
|
1130
|
+
}
|
|
1131
|
+
try {
|
|
1132
|
+
const context = { sessionId, toolCallId };
|
|
1133
|
+
const preview = await internalTool.generatePreview(args, context);
|
|
1134
|
+
this.logger.debug(`Generated preview for ${toolName}`);
|
|
1135
|
+
return preview ?? void 0;
|
|
1136
|
+
} catch (previewError) {
|
|
1137
|
+
if (previewError instanceof DextoRuntimeError && previewError.code === ToolErrorCode.VALIDATION_FAILED) {
|
|
1138
|
+
this.logger.debug(`Validation failed for ${toolName}: ${previewError.message}`);
|
|
1139
|
+
throw previewError;
|
|
1140
|
+
}
|
|
1141
|
+
this.logger.debug(
|
|
1142
|
+
`Preview generation failed for ${toolName}: ${previewError instanceof Error ? previewError.message : String(previewError)}`
|
|
1143
|
+
);
|
|
1144
|
+
return void 0;
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
/**
|
|
1148
|
+
* Get suggested bash patterns for the approval UI.
|
|
1149
|
+
*/
|
|
1150
|
+
getBashSuggestedPatterns(toolName, args) {
|
|
1151
|
+
if (!this.isBashTool(toolName)) {
|
|
1152
|
+
return void 0;
|
|
1153
|
+
}
|
|
1154
|
+
const command = args.command;
|
|
1155
|
+
if (!command) {
|
|
1156
|
+
return void 0;
|
|
1157
|
+
}
|
|
1158
|
+
const result = this.checkBashPatternApproval(command);
|
|
1159
|
+
return result.suggestedPatterns?.length ? result.suggestedPatterns : void 0;
|
|
1160
|
+
}
|
|
1161
|
+
/**
|
|
1162
|
+
* Handle "remember choice" or "remember pattern" when user approves a tool.
|
|
1163
|
+
*/
|
|
1164
|
+
async handleRememberChoice(toolName, response, sessionId) {
|
|
1165
|
+
const data = response.data;
|
|
1166
|
+
if (!data) return;
|
|
1167
|
+
const rememberChoice = data.rememberChoice;
|
|
1168
|
+
const rememberPattern = data.rememberPattern;
|
|
1169
|
+
if (rememberChoice) {
|
|
1170
|
+
const allowSessionId = sessionId ?? response.sessionId;
|
|
1171
|
+
await this.allowedToolsProvider.allowTool(toolName, allowSessionId);
|
|
1172
|
+
this.logger.info(
|
|
1173
|
+
`Tool '${toolName}' added to allowed tools for session '${allowSessionId ?? "global"}' (remember choice selected)`
|
|
1174
|
+
);
|
|
1175
|
+
this.autoApprovePendingToolRequests(toolName, allowSessionId);
|
|
1176
|
+
} else if (rememberPattern && this.isBashTool(toolName)) {
|
|
1177
|
+
this.approvalManager.addBashPattern(rememberPattern);
|
|
1178
|
+
this.logger.info(`Bash pattern '${rememberPattern}' added for session approval`);
|
|
1179
|
+
this.autoApprovePendingBashRequests(rememberPattern, sessionId);
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
/**
|
|
1183
|
+
* Handle approval denied/timeout - throws appropriate error.
|
|
1184
|
+
*/
|
|
1185
|
+
handleApprovalDenied(toolName, response, sessionId) {
|
|
1186
|
+
if (response.status === ApprovalStatus.CANCELLED && response.reason === DenialReason.TIMEOUT) {
|
|
1187
|
+
this.logger.info(
|
|
1188
|
+
`Tool confirmation timed out for ${toolName}, sessionId: ${sessionId ?? "global"}`
|
|
1189
|
+
);
|
|
1190
|
+
throw ToolError.executionTimeout(toolName, response.timeoutMs ?? 0, sessionId);
|
|
1191
|
+
}
|
|
1192
|
+
this.logger.info(
|
|
1193
|
+
`Tool confirmation denied for ${toolName}, sessionId: ${sessionId ?? "global"}, reason: ${response.reason ?? "unknown"}`
|
|
1194
|
+
);
|
|
1195
|
+
throw ToolError.executionDenied(toolName, sessionId, response.message);
|
|
1196
|
+
}
|
|
819
1197
|
/**
|
|
820
1198
|
* Refresh tool discovery (call when MCP servers change)
|
|
821
1199
|
* Refreshes both MCPManager's cache (server capabilities) and ToolManager's cache (combined tools)
|