@dexto/tools-builtins 1.7.2 → 1.8.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/builtin-tools-factory.cjs +4 -0
- package/dist/builtin-tools-factory.d.ts +2 -1
- package/dist/builtin-tools-factory.d.ts.map +1 -1
- package/dist/builtin-tools-factory.js +4 -0
- package/dist/builtin-tools-factory.test.cjs +3 -2
- package/dist/builtin-tools-factory.test.js +3 -2
- package/dist/implementations/ask-user-tool.cjs +5 -5
- package/dist/implementations/ask-user-tool.d.ts +1 -1
- package/dist/implementations/ask-user-tool.d.ts.map +1 -1
- package/dist/implementations/ask-user-tool.js +6 -1
- package/dist/implementations/delegate-to-url-tool.cjs +15 -14
- package/dist/implementations/delegate-to-url-tool.d.ts +1 -1
- package/dist/implementations/delegate-to-url-tool.d.ts.map +1 -1
- package/dist/implementations/delegate-to-url-tool.js +2 -8
- package/dist/implementations/exa-code-search-tool.cjs +4 -4
- package/dist/implementations/exa-code-search-tool.d.ts +1 -1
- package/dist/implementations/exa-code-search-tool.d.ts.map +1 -1
- package/dist/implementations/exa-code-search-tool.js +1 -1
- package/dist/implementations/exa-mcp.cjs +7 -7
- package/dist/implementations/exa-mcp.d.ts +1 -1
- package/dist/implementations/exa-mcp.d.ts.map +1 -1
- package/dist/implementations/exa-mcp.js +2 -2
- package/dist/implementations/exa-web-search-tool.cjs +4 -4
- package/dist/implementations/exa-web-search-tool.d.ts +1 -1
- package/dist/implementations/exa-web-search-tool.d.ts.map +1 -1
- package/dist/implementations/exa-web-search-tool.js +1 -1
- package/dist/implementations/get-resource-tool.cjs +11 -11
- package/dist/implementations/get-resource-tool.d.ts +1 -1
- package/dist/implementations/get-resource-tool.d.ts.map +1 -1
- package/dist/implementations/get-resource-tool.js +12 -7
- package/dist/implementations/http-request-tool.cjs +45 -44
- package/dist/implementations/http-request-tool.d.ts +1 -1
- package/dist/implementations/http-request-tool.d.ts.map +1 -1
- package/dist/implementations/http-request-tool.js +2 -8
- package/dist/implementations/invoke-skill-tool.cjs +22 -170
- package/dist/implementations/invoke-skill-tool.d.ts +1 -8
- package/dist/implementations/invoke-skill-tool.d.ts.map +1 -1
- package/dist/implementations/invoke-skill-tool.js +19 -167
- package/dist/implementations/invoke-skill-tool.test.cjs +61 -85
- package/dist/implementations/invoke-skill-tool.test.js +61 -85
- package/dist/implementations/list-resources-tool.cjs +18 -16
- package/dist/implementations/list-resources-tool.d.ts +2 -2
- package/dist/implementations/list-resources-tool.d.ts.map +1 -1
- package/dist/implementations/list-resources-tool.js +15 -13
- package/dist/implementations/read-skill-tool.cjs +89 -0
- package/dist/implementations/read-skill-tool.d.ts +9 -0
- package/dist/implementations/read-skill-tool.d.ts.map +1 -0
- package/dist/implementations/read-skill-tool.js +65 -0
- package/dist/implementations/read-skill-tool.test.cjs +82 -0
- package/dist/implementations/read-skill-tool.test.d.ts +2 -0
- package/dist/implementations/read-skill-tool.test.d.ts.map +1 -0
- package/dist/implementations/read-skill-tool.test.js +81 -0
- package/dist/implementations/sleep-tool.cjs +3 -3
- package/dist/implementations/sleep-tool.d.ts +1 -1
- package/dist/implementations/sleep-tool.d.ts.map +1 -1
- package/dist/implementations/sleep-tool.js +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -23,7 +23,8 @@ __export(http_request_tool_exports, {
|
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(http_request_tool_exports);
|
|
25
25
|
var import_zod = require("zod");
|
|
26
|
-
var
|
|
26
|
+
var import_errors = require("@dexto/core/errors");
|
|
27
|
+
var import_tools = require("@dexto/core/tools");
|
|
27
28
|
var import_node_dns = require("node:dns");
|
|
28
29
|
var import_node_net = require("node:net");
|
|
29
30
|
var import_node_util = require("node:util");
|
|
@@ -116,10 +117,10 @@ function createSafeLookup(config) {
|
|
|
116
117
|
if (BLOCKED_HOSTNAMES.has(hostname) || hostname.endsWith(".localhost")) {
|
|
117
118
|
emitError(
|
|
118
119
|
toErrnoException(
|
|
119
|
-
new
|
|
120
|
+
new import_errors.DextoRuntimeError(
|
|
120
121
|
"HTTP_REQUEST_UNSAFE_TARGET",
|
|
121
|
-
|
|
122
|
-
|
|
122
|
+
import_errors.ErrorScope.TOOLS,
|
|
123
|
+
import_errors.ErrorType.FORBIDDEN,
|
|
123
124
|
`Blocked request to local hostname: ${hostname}`
|
|
124
125
|
)
|
|
125
126
|
)
|
|
@@ -135,10 +136,10 @@ function createSafeLookup(config) {
|
|
|
135
136
|
if (!records.length) {
|
|
136
137
|
emitError(
|
|
137
138
|
toErrnoException(
|
|
138
|
-
new
|
|
139
|
+
new import_errors.DextoRuntimeError(
|
|
139
140
|
"HTTP_REQUEST_DNS_FAILED",
|
|
140
|
-
|
|
141
|
-
|
|
141
|
+
import_errors.ErrorScope.TOOLS,
|
|
142
|
+
import_errors.ErrorType.THIRD_PARTY,
|
|
142
143
|
`Failed to resolve hostname: ${hostname}`
|
|
143
144
|
)
|
|
144
145
|
)
|
|
@@ -149,10 +150,10 @@ function createSafeLookup(config) {
|
|
|
149
150
|
if (isPrivateAddress(record.address)) {
|
|
150
151
|
emitError(
|
|
151
152
|
toErrnoException(
|
|
152
|
-
new
|
|
153
|
+
new import_errors.DextoRuntimeError(
|
|
153
154
|
"HTTP_REQUEST_UNSAFE_TARGET",
|
|
154
|
-
|
|
155
|
-
|
|
155
|
+
import_errors.ErrorScope.TOOLS,
|
|
156
|
+
import_errors.ErrorType.FORBIDDEN,
|
|
156
157
|
`Blocked request to private address: ${record.address}`
|
|
157
158
|
)
|
|
158
159
|
)
|
|
@@ -174,10 +175,10 @@ function createSafeLookup(config) {
|
|
|
174
175
|
if (!selected) {
|
|
175
176
|
emitError(
|
|
176
177
|
toErrnoException(
|
|
177
|
-
new
|
|
178
|
+
new import_errors.DextoRuntimeError(
|
|
178
179
|
"HTTP_REQUEST_DNS_FAILED",
|
|
179
|
-
|
|
180
|
-
|
|
180
|
+
import_errors.ErrorScope.TOOLS,
|
|
181
|
+
import_errors.ErrorType.THIRD_PARTY,
|
|
181
182
|
`Failed to resolve hostname: ${hostname}`
|
|
182
183
|
)
|
|
183
184
|
)
|
|
@@ -193,10 +194,10 @@ function createSafeLookup(config) {
|
|
|
193
194
|
} catch {
|
|
194
195
|
}
|
|
195
196
|
} catch (error) {
|
|
196
|
-
const err = error instanceof
|
|
197
|
+
const err = error instanceof import_errors.DextoRuntimeError ? error : new import_errors.DextoRuntimeError(
|
|
197
198
|
"HTTP_REQUEST_DNS_FAILED",
|
|
198
|
-
|
|
199
|
-
|
|
199
|
+
import_errors.ErrorScope.TOOLS,
|
|
200
|
+
import_errors.ErrorType.THIRD_PARTY,
|
|
200
201
|
`Failed to resolve hostname: ${hostname}`
|
|
201
202
|
);
|
|
202
203
|
emitError(toErrnoException(err));
|
|
@@ -210,35 +211,35 @@ function createSafeDispatcher() {
|
|
|
210
211
|
}
|
|
211
212
|
async function assertSafeUrl(requestUrl) {
|
|
212
213
|
if (!["http:", "https:"].includes(requestUrl.protocol)) {
|
|
213
|
-
throw new
|
|
214
|
+
throw new import_errors.DextoRuntimeError(
|
|
214
215
|
"HTTP_REQUEST_UNSUPPORTED_PROTOCOL",
|
|
215
|
-
|
|
216
|
-
|
|
216
|
+
import_errors.ErrorScope.TOOLS,
|
|
217
|
+
import_errors.ErrorType.USER,
|
|
217
218
|
`Unsupported URL protocol: ${requestUrl.protocol}`
|
|
218
219
|
);
|
|
219
220
|
}
|
|
220
221
|
const hostname = requestUrl.hostname.trim();
|
|
221
222
|
if (!hostname) {
|
|
222
|
-
throw new
|
|
223
|
+
throw new import_errors.DextoRuntimeError(
|
|
223
224
|
"HTTP_REQUEST_INVALID_TARGET",
|
|
224
|
-
|
|
225
|
-
|
|
225
|
+
import_errors.ErrorScope.TOOLS,
|
|
226
|
+
import_errors.ErrorType.USER,
|
|
226
227
|
"Request URL hostname is required"
|
|
227
228
|
);
|
|
228
229
|
}
|
|
229
230
|
if (BLOCKED_HOSTNAMES.has(hostname) || hostname.endsWith(".localhost")) {
|
|
230
|
-
throw new
|
|
231
|
+
throw new import_errors.DextoRuntimeError(
|
|
231
232
|
"HTTP_REQUEST_UNSAFE_TARGET",
|
|
232
|
-
|
|
233
|
-
|
|
233
|
+
import_errors.ErrorScope.TOOLS,
|
|
234
|
+
import_errors.ErrorType.FORBIDDEN,
|
|
234
235
|
`Blocked request to local hostname: ${hostname}`
|
|
235
236
|
);
|
|
236
237
|
}
|
|
237
238
|
if (isPrivateAddress(hostname)) {
|
|
238
|
-
throw new
|
|
239
|
+
throw new import_errors.DextoRuntimeError(
|
|
239
240
|
"HTTP_REQUEST_UNSAFE_TARGET",
|
|
240
|
-
|
|
241
|
-
|
|
241
|
+
import_errors.ErrorScope.TOOLS,
|
|
242
|
+
import_errors.ErrorType.FORBIDDEN,
|
|
242
243
|
`Blocked request to private address: ${hostname}`
|
|
243
244
|
);
|
|
244
245
|
}
|
|
@@ -248,10 +249,10 @@ async function readResponseTextWithLimit(response) {
|
|
|
248
249
|
if (contentLength) {
|
|
249
250
|
const parsed = Number.parseInt(contentLength, 10);
|
|
250
251
|
if (!Number.isNaN(parsed) && parsed > MAX_RESPONSE_BYTES) {
|
|
251
|
-
throw new
|
|
252
|
+
throw new import_errors.DextoRuntimeError(
|
|
252
253
|
"HTTP_REQUEST_RESPONSE_TOO_LARGE",
|
|
253
|
-
|
|
254
|
-
|
|
254
|
+
import_errors.ErrorScope.TOOLS,
|
|
255
|
+
import_errors.ErrorType.THIRD_PARTY,
|
|
255
256
|
`Response too large: ${parsed} bytes exceeds ${MAX_RESPONSE_BYTES} byte limit`
|
|
256
257
|
);
|
|
257
258
|
}
|
|
@@ -270,10 +271,10 @@ async function readResponseTextWithLimit(response) {
|
|
|
270
271
|
total += value.length;
|
|
271
272
|
if (total > MAX_RESPONSE_BYTES) {
|
|
272
273
|
await reader.cancel();
|
|
273
|
-
throw new
|
|
274
|
+
throw new import_errors.DextoRuntimeError(
|
|
274
275
|
"HTTP_REQUEST_RESPONSE_TOO_LARGE",
|
|
275
|
-
|
|
276
|
-
|
|
276
|
+
import_errors.ErrorScope.TOOLS,
|
|
277
|
+
import_errors.ErrorType.THIRD_PARTY,
|
|
277
278
|
`Response too large: exceeded ${MAX_RESPONSE_BYTES} byte limit`
|
|
278
279
|
);
|
|
279
280
|
}
|
|
@@ -283,14 +284,14 @@ async function readResponseTextWithLimit(response) {
|
|
|
283
284
|
return result;
|
|
284
285
|
}
|
|
285
286
|
function createHttpRequestTool() {
|
|
286
|
-
return (0,
|
|
287
|
+
return (0, import_tools.defineTool)({
|
|
287
288
|
id: "http_request",
|
|
288
289
|
description: "Make a direct HTTP request using fetch. Supports method, headers, query params, JSON bodies, and timeouts. Returns status, headers, raw body text, and parsed JSON when available.",
|
|
289
290
|
inputSchema: HttpRequestInputSchema,
|
|
290
291
|
presentation: {
|
|
291
|
-
describeHeader: (input) => (0,
|
|
292
|
+
describeHeader: (input) => (0, import_tools.createLocalToolCallHeader)({
|
|
292
293
|
title: "Fetch",
|
|
293
|
-
argsText: (0,
|
|
294
|
+
argsText: (0, import_tools.truncateForHeader)(input.url, 140)
|
|
294
295
|
})
|
|
295
296
|
},
|
|
296
297
|
async execute(input, _context) {
|
|
@@ -347,21 +348,21 @@ function createHttpRequestTool() {
|
|
|
347
348
|
};
|
|
348
349
|
return payload;
|
|
349
350
|
} catch (error) {
|
|
350
|
-
if (error instanceof
|
|
351
|
+
if (error instanceof import_errors.DextoRuntimeError) {
|
|
351
352
|
throw error;
|
|
352
353
|
}
|
|
353
354
|
if (error instanceof Error && error.name === "AbortError") {
|
|
354
|
-
throw new
|
|
355
|
+
throw new import_errors.DextoRuntimeError(
|
|
355
356
|
"HTTP_REQUEST_TIMEOUT",
|
|
356
|
-
|
|
357
|
-
|
|
357
|
+
import_errors.ErrorScope.TOOLS,
|
|
358
|
+
import_errors.ErrorType.TIMEOUT,
|
|
358
359
|
`HTTP request timed out after ${timeoutMs}ms`
|
|
359
360
|
);
|
|
360
361
|
}
|
|
361
|
-
throw new
|
|
362
|
+
throw new import_errors.DextoRuntimeError(
|
|
362
363
|
"HTTP_REQUEST_FAILED",
|
|
363
|
-
|
|
364
|
-
|
|
364
|
+
import_errors.ErrorScope.TOOLS,
|
|
365
|
+
import_errors.ErrorType.THIRD_PARTY,
|
|
365
366
|
`HTTP request failed: ${error instanceof Error ? error.message : String(error)}`
|
|
366
367
|
);
|
|
367
368
|
} finally {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import type { Tool } from '@dexto/core';
|
|
2
|
+
import type { Tool } from '@dexto/core/tools';
|
|
3
3
|
import { promises as dns, type LookupAddress, type LookupOptions } from 'node:dns';
|
|
4
4
|
declare const HttpRequestInputSchema: z.ZodObject<{
|
|
5
5
|
url: z.ZodString;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-request-tool.d.ts","sourceRoot":"","sources":["../../src/implementations/http-request-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,IAAI,EAAwB,MAAM,
|
|
1
|
+
{"version":3,"file":"http-request-tool.d.ts","sourceRoot":"","sources":["../../src/implementations/http-request-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,IAAI,EAAwB,MAAM,mBAAmB,CAAC;AAGpE,OAAO,EAAE,QAAQ,IAAI,GAAG,EAAE,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AAKnF,QAAA,MAAM,sBAAsB;;;;;;;;;;;;;kBA2Bf,CAAC;AA8Bd,KAAK,cAAc,GACb,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,cAAc,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC,GAC9E,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,cAAc,GAAG,IAAI,EAAE,SAAS,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC,CAAC;AAoDhF,wBAAgB,gBAAgB,CAAC,MAAM,CAAC,EAAE;IACtC,SAAS,CAAC,EAAE,OAAO,GAAG,CAAC,MAAM,CAAC;CACjC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,cAAc,KAAK,IAAI,CAyI/E;AA2FD;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAAC,OAAO,sBAAsB,CAAC,CAuG3E"}
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
ErrorScope,
|
|
5
|
-
ErrorType,
|
|
6
|
-
createLocalToolCallHeader,
|
|
7
|
-
defineTool,
|
|
8
|
-
truncateForHeader
|
|
9
|
-
} from "@dexto/core";
|
|
2
|
+
import { DextoRuntimeError, ErrorScope, ErrorType } from "@dexto/core/errors";
|
|
3
|
+
import { createLocalToolCallHeader, defineTool, truncateForHeader } from "@dexto/core/tools";
|
|
10
4
|
import { promises as dns } from "node:dns";
|
|
11
5
|
import { isIP } from "node:net";
|
|
12
6
|
import { TextDecoder } from "node:util";
|
|
@@ -22,140 +22,53 @@ __export(invoke_skill_tool_exports, {
|
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(invoke_skill_tool_exports);
|
|
24
24
|
var import_zod = require("zod");
|
|
25
|
-
var
|
|
25
|
+
var import_tools = require("@dexto/core/tools");
|
|
26
26
|
const InvokeSkillInputSchema = import_zod.z.object({
|
|
27
27
|
skill: import_zod.z.string().min(1, "Skill name is required").describe(
|
|
28
28
|
'The name of the skill to invoke (e.g., "plugin-name:skill-name" or "skill-name")'
|
|
29
29
|
),
|
|
30
30
|
args: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional().describe("Optional arguments to pass to the skill"),
|
|
31
|
-
taskContext: import_zod.z.string().optional().describe(
|
|
32
|
-
"Context about what task this skill should accomplish. Recommended for forked skills to provide context since they run in isolation without conversation history."
|
|
33
|
-
)
|
|
31
|
+
taskContext: import_zod.z.string().optional().describe("Context about what task this skill should accomplish")
|
|
34
32
|
}).strict();
|
|
35
33
|
function createInvokeSkillTool() {
|
|
36
|
-
return (0,
|
|
34
|
+
return (0, import_tools.defineTool)({
|
|
37
35
|
id: "invoke_skill",
|
|
38
36
|
description: buildToolDescription(),
|
|
39
37
|
inputSchema: InvokeSkillInputSchema,
|
|
40
38
|
presentation: {
|
|
41
39
|
describeHeader: (input) => {
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
return (0, import_core.createLocalToolCallHeader)({
|
|
40
|
+
const colonIndex = input.skill.indexOf(":");
|
|
41
|
+
const displaySkillName = colonIndex >= 0 ? input.skill.slice(colonIndex + 1) : input.skill;
|
|
42
|
+
return (0, import_tools.createLocalToolCallHeader)({
|
|
46
43
|
title: "Skill",
|
|
47
44
|
argsText: `/${displaySkillName}`
|
|
48
45
|
});
|
|
49
46
|
}
|
|
50
47
|
},
|
|
51
48
|
async execute(input, context) {
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"invoke_skill requires ToolExecutionContext.services.prompts"
|
|
49
|
+
const skillManager = context.services?.skills;
|
|
50
|
+
if (!skillManager) {
|
|
51
|
+
throw import_tools.ToolError.configInvalid(
|
|
52
|
+
"invoke_skill requires ToolExecutionContext.services.skills"
|
|
57
53
|
);
|
|
58
54
|
}
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (!info) continue;
|
|
65
|
-
if (key === skill || info.displayName === skill || info.commandName === skill || info.name === skill) {
|
|
66
|
-
skillKey = key;
|
|
67
|
-
matchedInfo = info;
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
if (!skillKey) {
|
|
72
|
-
return {
|
|
73
|
-
error: `Skill '${skill}' not found or not available for model invocation. Use a skill from the available list.`,
|
|
74
|
-
availableSkills: Object.keys(autoInvocable)
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
const toolkits = Array.isArray(matchedInfo?.metadata?.toolkits) ? (matchedInfo?.metadata?.toolkits).filter((toolkit) => typeof toolkit === "string").map((toolkit) => toolkit.trim()).filter((toolkit) => toolkit.length > 0) : [];
|
|
78
|
-
if (toolkits.length > 0) {
|
|
79
|
-
if (!context.agent?.loadToolkits) {
|
|
80
|
-
return {
|
|
81
|
-
error: `Skill '${skill}' requires toolkits (${toolkits.join(
|
|
82
|
-
", "
|
|
83
|
-
)}), but this agent does not support dynamic tool loading.`,
|
|
84
|
-
toolkits
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
try {
|
|
88
|
-
await context.agent.loadToolkits(toolkits);
|
|
89
|
-
} catch (error) {
|
|
90
|
-
return {
|
|
91
|
-
error: error instanceof Error ? error.message : "Failed to load required toolkits",
|
|
92
|
-
toolkits
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
const promptDef = await promptManager.getPromptDefinition(skillKey);
|
|
97
|
-
const taskForker = context.services?.taskForker;
|
|
98
|
-
if (promptDef?.context === "fork" && !taskForker) {
|
|
55
|
+
const invoked = await skillManager.invoke(input.skill, input.args);
|
|
56
|
+
if (!invoked) {
|
|
57
|
+
const availableSkills = (await skillManager.list()).map(
|
|
58
|
+
(availableSkill) => availableSkill.displayName
|
|
59
|
+
);
|
|
99
60
|
return {
|
|
100
|
-
error: `Skill '${skill}'
|
|
101
|
-
|
|
61
|
+
error: `Skill '${input.skill}' not found or not available for model invocation. Use a skill from the available list.`,
|
|
62
|
+
availableSkills
|
|
102
63
|
};
|
|
103
64
|
}
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
return skillMcpError;
|
|
107
|
-
}
|
|
108
|
-
if (promptDef?.context !== "fork" && promptDef?.allowedTools && promptDef.allowedTools.length > 0 && context.sessionId && context.agent?.toolManager) {
|
|
109
|
-
try {
|
|
110
|
-
context.agent.toolManager.addSessionAutoApproveTools(
|
|
111
|
-
context.sessionId,
|
|
112
|
-
promptDef.allowedTools
|
|
113
|
-
);
|
|
114
|
-
} catch (error) {
|
|
115
|
-
context.logger?.warn("Failed to add auto-approve tools for skill", {
|
|
116
|
-
tools: promptDef.allowedTools,
|
|
117
|
-
error: error instanceof Error ? error.message : String(error)
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
const promptResult = await promptManager.getPrompt(skillKey, args);
|
|
122
|
-
const flattened = (0, import_core.flattenPromptResult)(promptResult);
|
|
123
|
-
const content = flattened.text;
|
|
124
|
-
if (promptDef?.context === "fork") {
|
|
125
|
-
const activeTaskForker = taskForker;
|
|
126
|
-
if (!activeTaskForker) {
|
|
127
|
-
return {
|
|
128
|
-
error: `Skill '${skill}' requires fork execution (context: fork), but agent spawning is not available.`,
|
|
129
|
-
skill: skillKey
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
const instructions = taskContext ? `## Task Context
|
|
133
|
-
${taskContext}
|
|
65
|
+
const content = input.taskContext ? `## Task Context
|
|
66
|
+
${input.taskContext}
|
|
134
67
|
|
|
135
68
|
## Skill Instructions
|
|
136
|
-
${
|
|
137
|
-
const forkOptions = {
|
|
138
|
-
task: `Skill: ${skill}`,
|
|
139
|
-
instructions,
|
|
140
|
-
autoApprove: true
|
|
141
|
-
};
|
|
142
|
-
if (promptDef.agent) {
|
|
143
|
-
forkOptions.agentId = promptDef.agent;
|
|
144
|
-
}
|
|
145
|
-
if (context.toolCallId) {
|
|
146
|
-
forkOptions.toolCallId = context.toolCallId;
|
|
147
|
-
}
|
|
148
|
-
if (context.sessionId) {
|
|
149
|
-
forkOptions.sessionId = context.sessionId;
|
|
150
|
-
}
|
|
151
|
-
const result = await activeTaskForker.fork(forkOptions);
|
|
152
|
-
if (result.success) {
|
|
153
|
-
return result.response ?? "Task completed successfully.";
|
|
154
|
-
}
|
|
155
|
-
return `Error: ${result.error ?? "Unknown error during forked execution"}`;
|
|
156
|
-
}
|
|
69
|
+
${invoked.instructions}` : invoked.instructions;
|
|
157
70
|
return {
|
|
158
|
-
skill:
|
|
71
|
+
skill: invoked.id,
|
|
159
72
|
content,
|
|
160
73
|
instructions: "Follow the instructions in the skill content above to complete the task."
|
|
161
74
|
};
|
|
@@ -163,76 +76,15 @@ ${content}` : content;
|
|
|
163
76
|
});
|
|
164
77
|
}
|
|
165
78
|
function buildToolDescription() {
|
|
166
|
-
return `Invoke a skill to load
|
|
79
|
+
return `Invoke a skill to load specialized instructions for a task.
|
|
167
80
|
|
|
168
81
|
When to use:
|
|
169
82
|
- When you recognize a task that matches an available skill
|
|
170
83
|
- When you need specialized guidance for a complex operation
|
|
171
84
|
- When the user references a skill by name
|
|
172
85
|
|
|
173
|
-
Parameters:
|
|
174
|
-
- skill: The name of the skill to invoke
|
|
175
|
-
- args: Optional arguments to pass to the skill (e.g., for $ARGUMENTS substitution)
|
|
176
|
-
- taskContext: Context about what you're trying to accomplish (important for forked skills that run in isolation)
|
|
177
|
-
|
|
178
|
-
Execution modes:
|
|
179
|
-
- **Inline skills**: Return instructions for you to follow in the current conversation
|
|
180
|
-
- **Fork skills**: Automatically execute in an isolated subagent and return the result (no additional tool calls needed)
|
|
181
|
-
- **Bundled MCP skills**: Automatically connect any MCP servers carried inside the skill bundle when the skill is invoked
|
|
182
|
-
|
|
183
|
-
Fork skills run in complete isolation without access to conversation history. They're useful for tasks that should run independently.
|
|
184
|
-
|
|
185
86
|
Available skills are listed in your system prompt. Use the skill name exactly as shown.`;
|
|
186
87
|
}
|
|
187
|
-
function getSkillBundledMcpServers(promptInfo) {
|
|
188
|
-
const rawServers = promptInfo?.metadata?.mcpServers;
|
|
189
|
-
if (!rawServers || typeof rawServers !== "object" || Array.isArray(rawServers)) {
|
|
190
|
-
return {};
|
|
191
|
-
}
|
|
192
|
-
return Object.fromEntries(
|
|
193
|
-
Object.entries(rawServers).filter(
|
|
194
|
-
([, config]) => typeof config === "object" && config !== null && !Array.isArray(config)
|
|
195
|
-
)
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
|
-
async function ensureSkillMcpServersConnected(skill, promptInfo, context) {
|
|
199
|
-
const mcpServers = getSkillBundledMcpServers(promptInfo);
|
|
200
|
-
const serverNames = Object.keys(mcpServers);
|
|
201
|
-
if (serverNames.length === 0) {
|
|
202
|
-
return void 0;
|
|
203
|
-
}
|
|
204
|
-
if (!context.agent?.addMcpServer || !context.agent.getMcpServerStatus || !context.agent.enableMcpServer) {
|
|
205
|
-
return {
|
|
206
|
-
error: `Skill '${skill}' requires bundled MCP servers (${serverNames.join(", ")}), but this agent does not support dynamic MCP loading.`,
|
|
207
|
-
mcpServers: serverNames
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
try {
|
|
211
|
-
for (const [serverName, serverConfig] of Object.entries(mcpServers)) {
|
|
212
|
-
let serverStatus = context.agent.getMcpServerStatus(serverName);
|
|
213
|
-
if (!serverStatus) {
|
|
214
|
-
await context.agent.addMcpServer(serverName, serverConfig);
|
|
215
|
-
serverStatus = context.agent.getMcpServerStatus(serverName);
|
|
216
|
-
}
|
|
217
|
-
if (!serverStatus?.enabled || serverStatus.status !== "connected") {
|
|
218
|
-
await context.agent.enableMcpServer(serverName);
|
|
219
|
-
serverStatus = context.agent.getMcpServerStatus(serverName);
|
|
220
|
-
}
|
|
221
|
-
if (!serverStatus || serverStatus.status !== "connected") {
|
|
222
|
-
return {
|
|
223
|
-
error: `Skill '${skill}' requires MCP server '${serverName}', but it is currently ${serverStatus?.status ?? "unavailable"}${serverStatus?.error ? `: ${serverStatus.error}` : ""}.`,
|
|
224
|
-
mcpServers: serverNames
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
} catch (error) {
|
|
229
|
-
return {
|
|
230
|
-
error: error instanceof Error ? error.message : "Failed to connect bundled MCP servers for skill",
|
|
231
|
-
mcpServers: serverNames
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
return void 0;
|
|
235
|
-
}
|
|
236
88
|
// Annotate the CommonJS export names for ESM import in node:
|
|
237
89
|
0 && (module.exports = {
|
|
238
90
|
createInvokeSkillTool
|
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import type { Tool } from '@dexto/core';
|
|
2
|
+
import type { Tool } from '@dexto/core/tools';
|
|
3
3
|
declare const InvokeSkillInputSchema: z.ZodObject<{
|
|
4
4
|
skill: z.ZodString;
|
|
5
5
|
args: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
6
6
|
taskContext: z.ZodOptional<z.ZodString>;
|
|
7
7
|
}, z.core.$strict>;
|
|
8
|
-
/**
|
|
9
|
-
* Create the `invoke_skill` tool.
|
|
10
|
-
*
|
|
11
|
-
* Loads an auto-invocable prompt (“skill”) via the PromptManager and returns its content, or
|
|
12
|
-
* forks the skill into a sub-agent when the skill is marked as `context: fork`.
|
|
13
|
-
* Requires `ToolExecutionContext.services.prompts` and, for forked skills, `services.taskForker`.
|
|
14
|
-
*/
|
|
15
8
|
export declare function createInvokeSkillTool(): Tool<typeof InvokeSkillInputSchema>;
|
|
16
9
|
export {};
|
|
17
10
|
//# sourceMappingURL=invoke-skill-tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invoke-skill-tool.d.ts","sourceRoot":"","sources":["../../src/implementations/invoke-skill-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"invoke-skill-tool.d.ts","sourceRoot":"","sources":["../../src/implementations/invoke-skill-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,IAAI,EAAwB,MAAM,mBAAmB,CAAC;AAapE,QAAA,MAAM,sBAAsB;;;;kBAiBf,CAAC;AAEd,wBAAgB,qBAAqB,IAAI,IAAI,CAAC,OAAO,sBAAsB,CAAC,CAgD3E"}
|