@dexto/tools-builtins 1.6.0 → 1.6.2

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.
Files changed (53) hide show
  1. package/dist/implementations/ask-user-tool.cjs +40 -9
  2. package/dist/implementations/ask-user-tool.d.ts +5 -5
  3. package/dist/implementations/ask-user-tool.d.ts.map +1 -1
  4. package/dist/implementations/ask-user-tool.js +41 -10
  5. package/dist/implementations/delegate-to-url-tool.cjs +6 -1
  6. package/dist/implementations/delegate-to-url-tool.d.ts.map +1 -1
  7. package/dist/implementations/delegate-to-url-tool.js +14 -2
  8. package/dist/implementations/delegate-to-url-tool.test.cjs +1 -0
  9. package/dist/implementations/delegate-to-url-tool.test.js +1 -0
  10. package/dist/implementations/exa-code-search-tool.cjs +6 -1
  11. package/dist/implementations/exa-code-search-tool.d.ts.map +1 -1
  12. package/dist/implementations/exa-code-search-tool.js +7 -2
  13. package/dist/implementations/exa-tools.test.cjs +1 -0
  14. package/dist/implementations/exa-tools.test.js +1 -0
  15. package/dist/implementations/exa-web-search-tool.cjs +6 -1
  16. package/dist/implementations/exa-web-search-tool.d.ts.map +1 -1
  17. package/dist/implementations/exa-web-search-tool.js +7 -2
  18. package/dist/implementations/get-resource-tool.cjs +9 -1
  19. package/dist/implementations/get-resource-tool.d.ts.map +1 -1
  20. package/dist/implementations/get-resource-tool.js +10 -2
  21. package/dist/implementations/http-request-tool.cjs +90 -40
  22. package/dist/implementations/http-request-tool.d.ts +5 -0
  23. package/dist/implementations/http-request-tool.d.ts.map +1 -1
  24. package/dist/implementations/http-request-tool.js +96 -40
  25. package/dist/implementations/http-request-tool.test.cjs +50 -0
  26. package/dist/implementations/http-request-tool.test.d.ts +2 -0
  27. package/dist/implementations/http-request-tool.test.d.ts.map +1 -0
  28. package/dist/implementations/http-request-tool.test.js +49 -0
  29. package/dist/implementations/invoke-skill-tool.cjs +45 -1
  30. package/dist/implementations/invoke-skill-tool.d.ts.map +1 -1
  31. package/dist/implementations/invoke-skill-tool.js +46 -2
  32. package/dist/implementations/list-resources-tool.cjs +12 -1
  33. package/dist/implementations/list-resources-tool.d.ts.map +1 -1
  34. package/dist/implementations/list-resources-tool.js +13 -2
  35. package/dist/implementations/sleep-tool.cjs +6 -1
  36. package/dist/implementations/sleep-tool.d.ts.map +1 -1
  37. package/dist/implementations/sleep-tool.js +7 -2
  38. package/dist/index.d.cts +19 -3
  39. package/package.json +4 -4
  40. package/dist/builtin-tools-factory.d.cts +0 -19
  41. package/dist/builtin-tools-factory.test.d.cts +0 -2
  42. package/dist/implementations/ask-user-tool.d.cts +0 -46
  43. package/dist/implementations/delegate-to-url-tool.d.cts +0 -27
  44. package/dist/implementations/delegate-to-url-tool.test.d.cts +0 -2
  45. package/dist/implementations/exa-code-search-tool.d.cts +0 -21
  46. package/dist/implementations/exa-mcp.d.cts +0 -24
  47. package/dist/implementations/exa-tools.test.d.cts +0 -2
  48. package/dist/implementations/exa-web-search-tool.d.cts +0 -30
  49. package/dist/implementations/get-resource-tool.d.cts +0 -22
  50. package/dist/implementations/http-request-tool.d.cts +0 -31
  51. package/dist/implementations/invoke-skill-tool.d.cts +0 -26
  52. package/dist/implementations/list-resources-tool.d.cts +0 -26
  53. package/dist/implementations/sleep-tool.d.cts +0 -16
@@ -24,21 +24,54 @@ module.exports = __toCommonJS(ask_user_tool_exports);
24
24
  var import_zod = require("zod");
25
25
  var import_core = require("@dexto/core");
26
26
  const AskUserInputSchema = import_zod.z.object({
27
- question: import_zod.z.string().describe("The question or prompt to display to the user"),
27
+ question: import_zod.z.string().describe(
28
+ "High-level prompt/title for the form. Keep this short; clients may display or ignore it."
29
+ ),
28
30
  schema: import_zod.z.object({
29
31
  type: import_zod.z.literal("object"),
30
- properties: import_zod.z.record(import_zod.z.unknown()),
32
+ properties: import_zod.z.record(import_zod.z.string(), import_zod.z.record(import_zod.z.unknown())),
31
33
  required: import_zod.z.array(import_zod.z.string()).optional()
32
34
  }).passthrough().describe(
33
- 'JSON Schema defining form fields. Use descriptive property names as labels (e.g., "favorite_team", "World Cup winner country") - NOT generic names like "q1". Use "enum" for dropdowns, "boolean" for yes/no, "number" for numeric inputs, "string" for text. Include "required" array for mandatory fields.'
35
+ [
36
+ "JSON Schema defining form fields (object schema only).",
37
+ "Deterministic UI mapping (recommended):",
38
+ "- `properties[field].title`: main question/label shown prominently (keep \u2272 80 chars).",
39
+ "- `properties[field].description`: optional help text (keep \u2272 120 chars).",
40
+ '- `properties[field]["x-dexto"].stepLabel`: short wizard/step label (keep \u2272 16 chars).',
41
+ 'Use stable, descriptive property keys (avoid generic names like "q1").',
42
+ "Use `enum` for single-choice lists, `boolean` for yes/no, `number` for numeric inputs, `string` for text.",
43
+ 'For multi-select, use `type: "array"` with `items: { enum: [...] }`.',
44
+ "Include a top-level `required` array for mandatory fields."
45
+ ].join(" ")
34
46
  )
35
47
  }).strict();
48
+ function toTitleCase(value) {
49
+ return value.trim().replace(/[_-]+/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/\s+/g, " ").split(" ").map((part) => part ? part.charAt(0).toUpperCase() + part.slice(1) : part).join(" ");
50
+ }
51
+ function enrichSchemaTitles(schema) {
52
+ if (schema.type !== "object") return schema;
53
+ const properties = schema.properties;
54
+ if (!properties) return schema;
55
+ const nextProperties = { ...properties };
56
+ for (const [key, value] of Object.entries(nextProperties)) {
57
+ if (!value || typeof value !== "object" || Array.isArray(value)) continue;
58
+ const title = typeof value.title === "string" ? value.title.trim() : "";
59
+ if (title) continue;
60
+ nextProperties[key] = { ...value, title: toTitleCase(key) };
61
+ }
62
+ return { ...schema, properties: nextProperties };
63
+ }
36
64
  function createAskUserTool() {
37
65
  return (0, import_core.defineTool)({
38
66
  id: "ask_user",
39
- displayName: "Ask",
40
67
  description: 'Collect structured input from the user through a form interface. ONLY use this tool when you need: 1) Multiple fields at once (e.g., name + email + preferences), 2) Pre-defined options/choices (use enum for dropdowns like ["small","medium","large"]), 3) Specific data types with validation (boolean for yes/no, number for quantities). DO NOT use for simple conversational questions - just ask those naturally in your response. This tool is for form-like data collection, not chat. Examples: collecting user profile info, configuration settings, or selecting from preset options.',
41
68
  inputSchema: AskUserInputSchema,
69
+ presentation: {
70
+ describeHeader: (input) => (0, import_core.createLocalToolCallHeader)({
71
+ title: "Ask",
72
+ argsText: (0, import_core.truncateForHeader)(input.question, 140)
73
+ })
74
+ },
42
75
  async execute(input, context) {
43
76
  const { question, schema } = input;
44
77
  const approvalManager = context.services?.approval;
@@ -48,13 +81,11 @@ function createAskUserTool() {
48
81
  );
49
82
  }
50
83
  const elicitationRequest = {
51
- schema,
84
+ schema: enrichSchemaTitles(input.schema),
52
85
  prompt: question,
53
- serverName: "Dexto Agent"
86
+ serverName: "Dexto Agent",
87
+ ...context.sessionId && { sessionId: context.sessionId }
54
88
  };
55
- if (context.sessionId !== void 0) {
56
- elicitationRequest.sessionId = context.sessionId;
57
- }
58
89
  return approvalManager.getElicitationData(elicitationRequest);
59
90
  }
60
91
  });
@@ -4,22 +4,22 @@ declare const AskUserInputSchema: z.ZodObject<{
4
4
  question: z.ZodString;
5
5
  schema: z.ZodObject<{
6
6
  type: z.ZodLiteral<"object">;
7
- properties: z.ZodRecord<z.ZodString, z.ZodUnknown>;
7
+ properties: z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>;
8
8
  required: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
9
9
  }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
10
10
  type: z.ZodLiteral<"object">;
11
- properties: z.ZodRecord<z.ZodString, z.ZodUnknown>;
11
+ properties: z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>;
12
12
  required: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
13
13
  }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
14
14
  type: z.ZodLiteral<"object">;
15
- properties: z.ZodRecord<z.ZodString, z.ZodUnknown>;
15
+ properties: z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>;
16
16
  required: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
17
17
  }, z.ZodTypeAny, "passthrough">>;
18
18
  }, "strict", z.ZodTypeAny, {
19
19
  question: string;
20
20
  schema: {
21
21
  type: "object";
22
- properties: Record<string, unknown>;
22
+ properties: Record<string, Record<string, unknown>>;
23
23
  required?: string[] | undefined;
24
24
  } & {
25
25
  [k: string]: unknown;
@@ -28,7 +28,7 @@ declare const AskUserInputSchema: z.ZodObject<{
28
28
  question: string;
29
29
  schema: {
30
30
  type: "object";
31
- properties: Record<string, unknown>;
31
+ properties: Record<string, Record<string, unknown>>;
32
32
  required?: string[] | undefined;
33
33
  } & {
34
34
  [k: string]: unknown;
@@ -1 +1 @@
1
- {"version":3,"file":"ask-user-tool.d.ts","sourceRoot":"","sources":["../../src/implementations/ask-user-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,IAAI,EAAwB,MAAM,aAAa,CAAC;AAE9D,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAcX,CAAC;AAEd;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAAC,OAAO,kBAAkB,CAAC,CAmCnE"}
1
+ {"version":3,"file":"ask-user-tool.d.ts","sourceRoot":"","sources":["../../src/implementations/ask-user-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,IAAI,EAAwB,MAAM,aAAa,CAAC;AAE9D,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4BX,CAAC;AAiCd;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAAC,OAAO,kBAAkB,CAAC,CAiCnE"}
@@ -1,21 +1,54 @@
1
1
  import { z } from "zod";
2
- import { ToolError, defineTool } from "@dexto/core";
2
+ import { ToolError, createLocalToolCallHeader, defineTool, truncateForHeader } from "@dexto/core";
3
3
  const AskUserInputSchema = z.object({
4
- question: z.string().describe("The question or prompt to display to the user"),
4
+ question: z.string().describe(
5
+ "High-level prompt/title for the form. Keep this short; clients may display or ignore it."
6
+ ),
5
7
  schema: z.object({
6
8
  type: z.literal("object"),
7
- properties: z.record(z.unknown()),
9
+ properties: z.record(z.string(), z.record(z.unknown())),
8
10
  required: z.array(z.string()).optional()
9
11
  }).passthrough().describe(
10
- 'JSON Schema defining form fields. Use descriptive property names as labels (e.g., "favorite_team", "World Cup winner country") - NOT generic names like "q1". Use "enum" for dropdowns, "boolean" for yes/no, "number" for numeric inputs, "string" for text. Include "required" array for mandatory fields.'
12
+ [
13
+ "JSON Schema defining form fields (object schema only).",
14
+ "Deterministic UI mapping (recommended):",
15
+ "- `properties[field].title`: main question/label shown prominently (keep \u2272 80 chars).",
16
+ "- `properties[field].description`: optional help text (keep \u2272 120 chars).",
17
+ '- `properties[field]["x-dexto"].stepLabel`: short wizard/step label (keep \u2272 16 chars).',
18
+ 'Use stable, descriptive property keys (avoid generic names like "q1").',
19
+ "Use `enum` for single-choice lists, `boolean` for yes/no, `number` for numeric inputs, `string` for text.",
20
+ 'For multi-select, use `type: "array"` with `items: { enum: [...] }`.',
21
+ "Include a top-level `required` array for mandatory fields."
22
+ ].join(" ")
11
23
  )
12
24
  }).strict();
25
+ function toTitleCase(value) {
26
+ return value.trim().replace(/[_-]+/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/\s+/g, " ").split(" ").map((part) => part ? part.charAt(0).toUpperCase() + part.slice(1) : part).join(" ");
27
+ }
28
+ function enrichSchemaTitles(schema) {
29
+ if (schema.type !== "object") return schema;
30
+ const properties = schema.properties;
31
+ if (!properties) return schema;
32
+ const nextProperties = { ...properties };
33
+ for (const [key, value] of Object.entries(nextProperties)) {
34
+ if (!value || typeof value !== "object" || Array.isArray(value)) continue;
35
+ const title = typeof value.title === "string" ? value.title.trim() : "";
36
+ if (title) continue;
37
+ nextProperties[key] = { ...value, title: toTitleCase(key) };
38
+ }
39
+ return { ...schema, properties: nextProperties };
40
+ }
13
41
  function createAskUserTool() {
14
42
  return defineTool({
15
43
  id: "ask_user",
16
- displayName: "Ask",
17
44
  description: 'Collect structured input from the user through a form interface. ONLY use this tool when you need: 1) Multiple fields at once (e.g., name + email + preferences), 2) Pre-defined options/choices (use enum for dropdowns like ["small","medium","large"]), 3) Specific data types with validation (boolean for yes/no, number for quantities). DO NOT use for simple conversational questions - just ask those naturally in your response. This tool is for form-like data collection, not chat. Examples: collecting user profile info, configuration settings, or selecting from preset options.',
18
45
  inputSchema: AskUserInputSchema,
46
+ presentation: {
47
+ describeHeader: (input) => createLocalToolCallHeader({
48
+ title: "Ask",
49
+ argsText: truncateForHeader(input.question, 140)
50
+ })
51
+ },
19
52
  async execute(input, context) {
20
53
  const { question, schema } = input;
21
54
  const approvalManager = context.services?.approval;
@@ -25,13 +58,11 @@ function createAskUserTool() {
25
58
  );
26
59
  }
27
60
  const elicitationRequest = {
28
- schema,
61
+ schema: enrichSchemaTitles(input.schema),
29
62
  prompt: question,
30
- serverName: "Dexto Agent"
63
+ serverName: "Dexto Agent",
64
+ ...context.sessionId && { sessionId: context.sessionId }
31
65
  };
32
- if (context.sessionId !== void 0) {
33
- elicitationRequest.sessionId = context.sessionId;
34
- }
35
66
  return approvalManager.getElicitationData(elicitationRequest);
36
67
  }
37
68
  });
@@ -147,9 +147,14 @@ class SimpleA2AClient {
147
147
  function createDelegateToUrlTool() {
148
148
  return (0, import_core.defineTool)({
149
149
  id: "delegate_to_url",
150
- displayName: "Delegate",
151
150
  description: 'Delegate a task to another A2A-compliant agent at a specific URL. Supports STATEFUL multi-turn conversations via sessionId parameter. USAGE: (1) First delegation: provide url + message. Tool returns a response AND a sessionId. (2) Follow-up: use the SAME sessionId to continue the conversation with that agent. The agent remembers previous context. EXAMPLE: First call {url: "http://agent:3001", message: "Analyze data X"} returns {sessionId: "xyz", response: "..."}. Second call {url: "http://agent:3001", message: "What was the top insight?", sessionId: "xyz"}. The agent will remember the first analysis and can answer specifically.',
152
151
  inputSchema: DelegateToUrlInputSchema,
152
+ presentation: {
153
+ describeHeader: (input) => (0, import_core.createLocalToolCallHeader)({
154
+ title: "Delegate",
155
+ argsText: (0, import_core.truncateForHeader)(`${input.url} ${input.message}`, 140)
156
+ })
157
+ },
153
158
  async execute(input, _context) {
154
159
  const { url, message, sessionId, timeout } = input;
155
160
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"delegate-to-url-tool.d.ts","sourceRoot":"","sources":["../../src/implementations/delegate-to-url-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,IAAI,EAAwB,MAAM,aAAa,CAAC;AAG9D,QAAA,MAAM,wBAAwB;;;;;;;;;;;;;;;EA0BjB,CAAC;AAsJd;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAAC,OAAO,wBAAwB,CAAC,CAyC/E"}
1
+ {"version":3,"file":"delegate-to-url-tool.d.ts","sourceRoot":"","sources":["../../src/implementations/delegate-to-url-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,IAAI,EAAwB,MAAM,aAAa,CAAC;AAU9D,QAAA,MAAM,wBAAwB;;;;;;;;;;;;;;;EA0BjB,CAAC;AAsJd;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAAC,OAAO,wBAAwB,CAAC,CA+C/E"}
@@ -1,5 +1,12 @@
1
1
  import { z } from "zod";
2
- import { DextoRuntimeError, ErrorScope, ErrorType, defineTool } from "@dexto/core";
2
+ import {
3
+ DextoRuntimeError,
4
+ ErrorScope,
5
+ ErrorType,
6
+ createLocalToolCallHeader,
7
+ defineTool,
8
+ truncateForHeader
9
+ } from "@dexto/core";
3
10
  const DelegateToUrlInputSchema = z.object({
4
11
  url: z.string().url().describe(
5
12
  'The A2A-compliant agent URL (e.g., "http://localhost:3001" or "https://agent.example.com"). The tool will automatically append the correct JSON-RPC endpoint.'
@@ -124,9 +131,14 @@ class SimpleA2AClient {
124
131
  function createDelegateToUrlTool() {
125
132
  return defineTool({
126
133
  id: "delegate_to_url",
127
- displayName: "Delegate",
128
134
  description: 'Delegate a task to another A2A-compliant agent at a specific URL. Supports STATEFUL multi-turn conversations via sessionId parameter. USAGE: (1) First delegation: provide url + message. Tool returns a response AND a sessionId. (2) Follow-up: use the SAME sessionId to continue the conversation with that agent. The agent remembers previous context. EXAMPLE: First call {url: "http://agent:3001", message: "Analyze data X"} returns {sessionId: "xyz", response: "..."}. Second call {url: "http://agent:3001", message: "What was the top insight?", sessionId: "xyz"}. The agent will remember the first analysis and can answer specifically.',
129
135
  inputSchema: DelegateToUrlInputSchema,
136
+ presentation: {
137
+ describeHeader: (input) => createLocalToolCallHeader({
138
+ title: "Delegate",
139
+ argsText: truncateForHeader(`${input.url} ${input.message}`, 140)
140
+ })
141
+ },
130
142
  async execute(input, _context) {
131
143
  const { url, message, sessionId, timeout } = input;
132
144
  try {
@@ -11,6 +11,7 @@ function createMockLogger() {
11
11
  error: import_vitest.vi.fn(),
12
12
  trackException: import_vitest.vi.fn(),
13
13
  createChild: import_vitest.vi.fn(() => logger),
14
+ createFileOnlyChild: import_vitest.vi.fn(() => logger),
14
15
  setLevel: import_vitest.vi.fn(),
15
16
  getLevel: import_vitest.vi.fn(() => "debug"),
16
17
  getLogFilePath: import_vitest.vi.fn(() => null),
@@ -10,6 +10,7 @@ function createMockLogger() {
10
10
  error: vi.fn(),
11
11
  trackException: vi.fn(),
12
12
  createChild: vi.fn(() => logger),
13
+ createFileOnlyChild: vi.fn(() => logger),
13
14
  setLevel: vi.fn(),
14
15
  getLevel: vi.fn(() => "debug"),
15
16
  getLogFilePath: vi.fn(() => null),
@@ -33,9 +33,14 @@ const CodeSearchInputSchema = import_zod.z.object({
33
33
  function createCodeSearchTool() {
34
34
  return (0, import_core.defineTool)({
35
35
  id: "code_search",
36
- displayName: "Code Search",
37
36
  description: "Search for code examples and documentation across sources like official docs, GitHub, and Stack Overflow. Returns formatted text context.",
38
37
  inputSchema: CodeSearchInputSchema,
38
+ presentation: {
39
+ describeHeader: (input) => (0, import_core.createLocalToolCallHeader)({
40
+ title: "Code Search",
41
+ argsText: (0, import_core.truncateForHeader)(input.query, 140)
42
+ })
43
+ },
39
44
  async execute(input, context) {
40
45
  const { query, tokensNum } = input;
41
46
  return await (0, import_exa_mcp.callExaTool)({
@@ -1 +1 @@
1
- {"version":3,"file":"exa-code-search-tool.d.ts","sourceRoot":"","sources":["../../src/implementations/exa-code-search-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,IAAI,EAAwB,MAAM,aAAa,CAAC;AAG9D,QAAA,MAAM,qBAAqB;;;;;;;;;EAiBd,CAAC;AACd;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAAC,OAAO,qBAAqB,CAAC,CAsBzE"}
1
+ {"version":3,"file":"exa-code-search-tool.d.ts","sourceRoot":"","sources":["../../src/implementations/exa-code-search-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,IAAI,EAAwB,MAAM,aAAa,CAAC;AAG9D,QAAA,MAAM,qBAAqB;;;;;;;;;EAiBd,CAAC;AACd;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAAC,OAAO,qBAAqB,CAAC,CA4BzE"}
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { defineTool } from "@dexto/core";
2
+ import { createLocalToolCallHeader, defineTool, truncateForHeader } from "@dexto/core";
3
3
  import { callExaTool } from "./exa-mcp.js";
4
4
  const CodeSearchInputSchema = z.object({
5
5
  query: z.string().min(1).describe(
@@ -10,9 +10,14 @@ const CodeSearchInputSchema = z.object({
10
10
  function createCodeSearchTool() {
11
11
  return defineTool({
12
12
  id: "code_search",
13
- displayName: "Code Search",
14
13
  description: "Search for code examples and documentation across sources like official docs, GitHub, and Stack Overflow. Returns formatted text context.",
15
14
  inputSchema: CodeSearchInputSchema,
15
+ presentation: {
16
+ describeHeader: (input) => createLocalToolCallHeader({
17
+ title: "Code Search",
18
+ argsText: truncateForHeader(input.query, 140)
19
+ })
20
+ },
16
21
  async execute(input, context) {
17
22
  const { query, tokensNum } = input;
18
23
  return await callExaTool({
@@ -12,6 +12,7 @@ function createMockLogger() {
12
12
  error: import_vitest.vi.fn(),
13
13
  trackException: import_vitest.vi.fn(),
14
14
  createChild: import_vitest.vi.fn(() => logger),
15
+ createFileOnlyChild: import_vitest.vi.fn(() => logger),
15
16
  setLevel: import_vitest.vi.fn(),
16
17
  getLevel: import_vitest.vi.fn(() => "debug"),
17
18
  getLogFilePath: import_vitest.vi.fn(() => null),
@@ -11,6 +11,7 @@ function createMockLogger() {
11
11
  error: vi.fn(),
12
12
  trackException: vi.fn(),
13
13
  createChild: vi.fn(() => logger),
14
+ createFileOnlyChild: vi.fn(() => logger),
14
15
  setLevel: vi.fn(),
15
16
  getLevel: vi.fn(() => "debug"),
16
17
  getLogFilePath: vi.fn(() => null),
@@ -36,9 +36,14 @@ const WebSearchInputSchema = import_zod.z.object({
36
36
  function createWebSearchTool() {
37
37
  return (0, import_core.defineTool)({
38
38
  id: "web_search",
39
- displayName: "Web Search",
40
39
  description: "Search the web for current information and return clean, ready-to-use text. Use for news, facts, and up-to-date context.",
41
40
  inputSchema: WebSearchInputSchema,
41
+ presentation: {
42
+ describeHeader: (input) => (0, import_core.createLocalToolCallHeader)({
43
+ title: "Web Search",
44
+ argsText: (0, import_core.truncateForHeader)(input.query, 140)
45
+ })
46
+ },
42
47
  async execute(input, context) {
43
48
  const { query, numResults, livecrawl, type, contextMaxCharacters } = input;
44
49
  return await (0, import_exa_mcp.callExaTool)({
@@ -1 +1 @@
1
- {"version":3,"file":"exa-web-search-tool.d.ts","sourceRoot":"","sources":["../../src/implementations/exa-web-search-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,IAAI,EAAwB,MAAM,aAAa,CAAC;AAG9D,QAAA,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;EA8Bb,CAAC;AACd;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAAC,OAAO,oBAAoB,CAAC,CAyBvE"}
1
+ {"version":3,"file":"exa-web-search-tool.d.ts","sourceRoot":"","sources":["../../src/implementations/exa-web-search-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,IAAI,EAAwB,MAAM,aAAa,CAAC;AAG9D,QAAA,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;EA8Bb,CAAC;AACd;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAAC,OAAO,oBAAoB,CAAC,CA+BvE"}
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { defineTool } from "@dexto/core";
2
+ import { createLocalToolCallHeader, defineTool, truncateForHeader } from "@dexto/core";
3
3
  import { callExaTool } from "./exa-mcp.js";
4
4
  const WebSearchInputSchema = z.object({
5
5
  query: z.string().min(1).describe("Web search query"),
@@ -13,9 +13,14 @@ const WebSearchInputSchema = z.object({
13
13
  function createWebSearchTool() {
14
14
  return defineTool({
15
15
  id: "web_search",
16
- displayName: "Web Search",
17
16
  description: "Search the web for current information and return clean, ready-to-use text. Use for news, facts, and up-to-date context.",
18
17
  inputSchema: WebSearchInputSchema,
18
+ presentation: {
19
+ describeHeader: (input) => createLocalToolCallHeader({
20
+ title: "Web Search",
21
+ argsText: truncateForHeader(input.query, 140)
22
+ })
23
+ },
19
24
  async execute(input, context) {
20
25
  const { query, numResults, livecrawl, type, contextMaxCharacters } = input;
21
26
  return await callExaTool({
@@ -34,9 +34,17 @@ const GetResourceInputSchema = import_zod.z.object({
34
34
  function createGetResourceTool() {
35
35
  return (0, import_core.defineTool)({
36
36
  id: "get_resource",
37
- displayName: "Get Resource",
38
37
  description: 'Access a stored resource. Use format "url" to get a shareable URL for other agents or external systems (requires remote storage like Supabase). Use format "metadata" to get resource information without loading data. References can be obtained from tool result annotations or list_resources.',
39
38
  inputSchema: GetResourceInputSchema,
39
+ presentation: {
40
+ describeHeader: (input) => (0, import_core.createLocalToolCallHeader)({
41
+ title: "Get Resource",
42
+ argsText: (0, import_core.truncateForHeader)(
43
+ input.format === "metadata" ? `${input.reference} (metadata)` : input.reference,
44
+ 140
45
+ )
46
+ })
47
+ },
40
48
  async execute(input, context) {
41
49
  const { reference, format } = input;
42
50
  const resourceManager = context.services?.resources;
@@ -1 +1 @@
1
- {"version":3,"file":"get-resource-tool.d.ts","sourceRoot":"","sources":["../../src/implementations/get-resource-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,IAAI,EAAwB,MAAM,aAAa,CAAC;AAE9D,QAAA,MAAM,sBAAsB;;;;;;;;;EAgBf,CAAC;AAEd;;;;;GAKG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAAC,OAAO,sBAAsB,CAAC,CAsG3E"}
1
+ {"version":3,"file":"get-resource-tool.d.ts","sourceRoot":"","sources":["../../src/implementations/get-resource-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,IAAI,EAAwB,MAAM,aAAa,CAAC;AAE9D,QAAA,MAAM,sBAAsB;;;;;;;;;EAgBf,CAAC;AAEd;;;;;GAKG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAAC,OAAO,sBAAsB,CAAC,CAiH3E"}
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { ToolError, defineTool } from "@dexto/core";
2
+ import { ToolError, createLocalToolCallHeader, defineTool, truncateForHeader } from "@dexto/core";
3
3
  const GetResourceInputSchema = z.object({
4
4
  reference: z.string().describe(
5
5
  'The resource reference to access. Formats: "blob:abc123" (from list_resources), "resource_ref:blob:abc123" (from tool annotations)'
@@ -11,9 +11,17 @@ const GetResourceInputSchema = z.object({
11
11
  function createGetResourceTool() {
12
12
  return defineTool({
13
13
  id: "get_resource",
14
- displayName: "Get Resource",
15
14
  description: 'Access a stored resource. Use format "url" to get a shareable URL for other agents or external systems (requires remote storage like Supabase). Use format "metadata" to get resource information without loading data. References can be obtained from tool result annotations or list_resources.',
16
15
  inputSchema: GetResourceInputSchema,
16
+ presentation: {
17
+ describeHeader: (input) => createLocalToolCallHeader({
18
+ title: "Get Resource",
19
+ argsText: truncateForHeader(
20
+ input.format === "metadata" ? `${input.reference} (metadata)` : input.reference,
21
+ 140
22
+ )
23
+ })
24
+ },
17
25
  async execute(input, context) {
18
26
  const { reference, format } = input;
19
27
  const resourceManager = context.services?.resources;
@@ -18,7 +18,8 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var http_request_tool_exports = {};
20
20
  __export(http_request_tool_exports, {
21
- createHttpRequestTool: () => createHttpRequestTool
21
+ createHttpRequestTool: () => createHttpRequestTool,
22
+ createSafeLookup: () => createSafeLookup
22
23
  });
23
24
  module.exports = __toCommonJS(http_request_tool_exports);
24
25
  var import_zod = require("zod");
@@ -96,61 +97,101 @@ function isPrivateAddress(ip) {
96
97
  if (version === 6) return isPrivateIpv6(ip);
97
98
  return false;
98
99
  }
99
- function createSafeDispatcher() {
100
- const lookup = (hostname, _options, callback) => {
100
+ function createSafeLookup(config) {
101
+ const dnsLookup = config?.dnsLookup ?? import_node_dns.promises.lookup;
102
+ return (hostname, options, callback) => {
101
103
  void (async () => {
104
+ const toErrnoException = (err) => err;
105
+ const emitError = (err) => {
106
+ try {
107
+ if (options.all) {
108
+ callback(err, []);
109
+ return;
110
+ }
111
+ callback(err, "", 0);
112
+ } catch {
113
+ }
114
+ };
102
115
  try {
103
116
  if (BLOCKED_HOSTNAMES.has(hostname) || hostname.endsWith(".localhost")) {
104
- callback(
105
- new import_core.DextoRuntimeError(
106
- "HTTP_REQUEST_UNSAFE_TARGET",
107
- import_core.ErrorScope.TOOLS,
108
- import_core.ErrorType.FORBIDDEN,
109
- `Blocked request to local hostname: ${hostname}`
110
- ),
111
- "",
112
- 0
117
+ emitError(
118
+ toErrnoException(
119
+ new import_core.DextoRuntimeError(
120
+ "HTTP_REQUEST_UNSAFE_TARGET",
121
+ import_core.ErrorScope.TOOLS,
122
+ import_core.ErrorType.FORBIDDEN,
123
+ `Blocked request to local hostname: ${hostname}`
124
+ )
125
+ )
113
126
  );
114
127
  return;
115
128
  }
116
- const records = await import_node_dns.promises.lookup(hostname, {
129
+ const records = await dnsLookup(hostname, {
117
130
  all: true,
118
- verbatim: true
131
+ verbatim: true,
132
+ family: options.family,
133
+ hints: options.hints
119
134
  });
120
135
  if (!records.length) {
121
- callback(
122
- new import_core.DextoRuntimeError(
123
- "HTTP_REQUEST_DNS_FAILED",
124
- import_core.ErrorScope.TOOLS,
125
- import_core.ErrorType.THIRD_PARTY,
126
- `Failed to resolve hostname: ${hostname}`
127
- ),
128
- "",
129
- 0
136
+ emitError(
137
+ toErrnoException(
138
+ new import_core.DextoRuntimeError(
139
+ "HTTP_REQUEST_DNS_FAILED",
140
+ import_core.ErrorScope.TOOLS,
141
+ import_core.ErrorType.THIRD_PARTY,
142
+ `Failed to resolve hostname: ${hostname}`
143
+ )
144
+ )
130
145
  );
131
146
  return;
132
147
  }
133
148
  for (const record of records) {
134
149
  if (isPrivateAddress(record.address)) {
135
- callback(
136
- new import_core.DextoRuntimeError(
137
- "HTTP_REQUEST_UNSAFE_TARGET",
138
- import_core.ErrorScope.TOOLS,
139
- import_core.ErrorType.FORBIDDEN,
140
- `Blocked request to private address: ${record.address}`
141
- ),
142
- "",
143
- 0
150
+ emitError(
151
+ toErrnoException(
152
+ new import_core.DextoRuntimeError(
153
+ "HTTP_REQUEST_UNSAFE_TARGET",
154
+ import_core.ErrorScope.TOOLS,
155
+ import_core.ErrorType.FORBIDDEN,
156
+ `Blocked request to private address: ${record.address}`
157
+ )
158
+ )
144
159
  );
145
160
  return;
146
161
  }
147
162
  }
163
+ if (options.all) {
164
+ try {
165
+ callback(
166
+ null,
167
+ records
168
+ );
169
+ } catch {
170
+ }
171
+ return;
172
+ }
148
173
  const selected = records[0];
149
- callback(
150
- null,
151
- selected.address,
152
- selected.family ?? ((0, import_node_net.isIP)(selected.address) === 6 ? 6 : 4)
153
- );
174
+ if (!selected) {
175
+ emitError(
176
+ toErrnoException(
177
+ new import_core.DextoRuntimeError(
178
+ "HTTP_REQUEST_DNS_FAILED",
179
+ import_core.ErrorScope.TOOLS,
180
+ import_core.ErrorType.THIRD_PARTY,
181
+ `Failed to resolve hostname: ${hostname}`
182
+ )
183
+ )
184
+ );
185
+ return;
186
+ }
187
+ try {
188
+ callback(
189
+ null,
190
+ selected.address,
191
+ selected.family ?? ((0, import_node_net.isIP)(selected.address) === 6 ? 6 : 4)
192
+ );
193
+ } catch {
194
+ }
154
195
  } catch (error) {
155
196
  const err = error instanceof import_core.DextoRuntimeError ? error : new import_core.DextoRuntimeError(
156
197
  "HTTP_REQUEST_DNS_FAILED",
@@ -158,10 +199,13 @@ function createSafeDispatcher() {
158
199
  import_core.ErrorType.THIRD_PARTY,
159
200
  `Failed to resolve hostname: ${hostname}`
160
201
  );
161
- callback(err, "", 0);
202
+ emitError(toErrnoException(err));
162
203
  }
163
204
  })();
164
205
  };
206
+ }
207
+ function createSafeDispatcher() {
208
+ const lookup = createSafeLookup();
165
209
  return new import_undici.Agent({ connect: { lookup } });
166
210
  }
167
211
  async function assertSafeUrl(requestUrl) {
@@ -241,9 +285,14 @@ async function readResponseTextWithLimit(response) {
241
285
  function createHttpRequestTool() {
242
286
  return (0, import_core.defineTool)({
243
287
  id: "http_request",
244
- displayName: "Fetch",
245
288
  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.",
246
289
  inputSchema: HttpRequestInputSchema,
290
+ presentation: {
291
+ describeHeader: (input) => (0, import_core.createLocalToolCallHeader)({
292
+ title: "Fetch",
293
+ argsText: (0, import_core.truncateForHeader)(input.url, 140)
294
+ })
295
+ },
247
296
  async execute(input, _context) {
248
297
  const { url, method, headers, query, body, timeoutMs } = input;
249
298
  const requestUrl = new URL(url);
@@ -323,5 +372,6 @@ function createHttpRequestTool() {
323
372
  }
324
373
  // Annotate the CommonJS export names for ESM import in node:
325
374
  0 && (module.exports = {
326
- createHttpRequestTool
375
+ createHttpRequestTool,
376
+ createSafeLookup
327
377
  });
@@ -1,5 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  import type { Tool } from '@dexto/core';
3
+ import { promises as dns, type LookupAddress, type LookupOptions } from 'node:dns';
3
4
  declare const HttpRequestInputSchema: z.ZodObject<{
4
5
  url: z.ZodString;
5
6
  method: z.ZodDefault<z.ZodEnum<["GET", "POST", "PUT", "PATCH", "DELETE"]>>;
@@ -22,6 +23,10 @@ declare const HttpRequestInputSchema: z.ZodObject<{
22
23
  body?: string | unknown[] | Record<string, unknown> | undefined;
23
24
  timeoutMs?: number | undefined;
24
25
  }>;
26
+ type LookupCallback = ((err: NodeJS.ErrnoException | null, address: string, family: number) => void) | ((err: NodeJS.ErrnoException | null, addresses: LookupAddress[]) => void);
27
+ export declare function createSafeLookup(config?: {
28
+ dnsLookup?: typeof dns.lookup;
29
+ }): (hostname: string, options: LookupOptions, callback: LookupCallback) => void;
25
30
  /**
26
31
  * Internal tool for basic HTTP requests.
27
32
  */
@@ -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,aAAa,CAAC;AAO9D,QAAA,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;EA2Bf,CAAC;AAmPd;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAAC,OAAO,sBAAsB,CAAC,CAiG3E"}
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,aAAa,CAAC;AAS9D,OAAO,EAAE,QAAQ,IAAI,GAAG,EAAE,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AAKnF,QAAA,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;EA2Bf,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"}