@dexto/tools-builtins 1.6.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.
Files changed (77) hide show
  1. package/LICENSE +44 -0
  2. package/dist/builtin-tools-factory.cjs +95 -0
  3. package/dist/builtin-tools-factory.d.cts +19 -0
  4. package/dist/builtin-tools-factory.d.ts +17 -0
  5. package/dist/builtin-tools-factory.d.ts.map +1 -0
  6. package/dist/builtin-tools-factory.js +69 -0
  7. package/dist/builtin-tools-factory.test.cjs +26 -0
  8. package/dist/builtin-tools-factory.test.d.cts +2 -0
  9. package/dist/builtin-tools-factory.test.d.ts +2 -0
  10. package/dist/builtin-tools-factory.test.d.ts.map +1 -0
  11. package/dist/builtin-tools-factory.test.js +25 -0
  12. package/dist/implementations/ask-user-tool.cjs +65 -0
  13. package/dist/implementations/ask-user-tool.d.cts +46 -0
  14. package/dist/implementations/ask-user-tool.d.ts +45 -0
  15. package/dist/implementations/ask-user-tool.d.ts.map +1 -0
  16. package/dist/implementations/ask-user-tool.js +41 -0
  17. package/dist/implementations/delegate-to-url-tool.cjs +183 -0
  18. package/dist/implementations/delegate-to-url-tool.d.cts +27 -0
  19. package/dist/implementations/delegate-to-url-tool.d.ts +26 -0
  20. package/dist/implementations/delegate-to-url-tool.d.ts.map +1 -0
  21. package/dist/implementations/delegate-to-url-tool.js +159 -0
  22. package/dist/implementations/delegate-to-url-tool.test.cjs +75 -0
  23. package/dist/implementations/delegate-to-url-tool.test.d.cts +2 -0
  24. package/dist/implementations/delegate-to-url-tool.test.d.ts +2 -0
  25. package/dist/implementations/delegate-to-url-tool.test.d.ts.map +1 -0
  26. package/dist/implementations/delegate-to-url-tool.test.js +74 -0
  27. package/dist/implementations/exa-code-search-tool.cjs +57 -0
  28. package/dist/implementations/exa-code-search-tool.d.cts +21 -0
  29. package/dist/implementations/exa-code-search-tool.d.ts +20 -0
  30. package/dist/implementations/exa-code-search-tool.d.ts.map +1 -0
  31. package/dist/implementations/exa-code-search-tool.js +33 -0
  32. package/dist/implementations/exa-mcp.cjs +98 -0
  33. package/dist/implementations/exa-mcp.d.cts +24 -0
  34. package/dist/implementations/exa-mcp.d.ts +23 -0
  35. package/dist/implementations/exa-mcp.d.ts.map +1 -0
  36. package/dist/implementations/exa-mcp.js +74 -0
  37. package/dist/implementations/exa-tools.test.cjs +91 -0
  38. package/dist/implementations/exa-tools.test.d.cts +2 -0
  39. package/dist/implementations/exa-tools.test.d.ts +2 -0
  40. package/dist/implementations/exa-tools.test.d.ts.map +1 -0
  41. package/dist/implementations/exa-tools.test.js +90 -0
  42. package/dist/implementations/exa-web-search-tool.cjs +63 -0
  43. package/dist/implementations/exa-web-search-tool.d.cts +30 -0
  44. package/dist/implementations/exa-web-search-tool.d.ts +29 -0
  45. package/dist/implementations/exa-web-search-tool.d.ts.map +1 -0
  46. package/dist/implementations/exa-web-search-tool.js +39 -0
  47. package/dist/implementations/get-resource-tool.cjs +121 -0
  48. package/dist/implementations/get-resource-tool.d.cts +22 -0
  49. package/dist/implementations/get-resource-tool.d.ts +21 -0
  50. package/dist/implementations/get-resource-tool.d.ts.map +1 -0
  51. package/dist/implementations/get-resource-tool.js +97 -0
  52. package/dist/implementations/http-request-tool.cjs +327 -0
  53. package/dist/implementations/http-request-tool.d.cts +31 -0
  54. package/dist/implementations/http-request-tool.d.ts +30 -0
  55. package/dist/implementations/http-request-tool.d.ts.map +1 -0
  56. package/dist/implementations/http-request-tool.js +303 -0
  57. package/dist/implementations/invoke-skill-tool.cjs +134 -0
  58. package/dist/implementations/invoke-skill-tool.d.cts +26 -0
  59. package/dist/implementations/invoke-skill-tool.d.ts +25 -0
  60. package/dist/implementations/invoke-skill-tool.d.ts.map +1 -0
  61. package/dist/implementations/invoke-skill-tool.js +110 -0
  62. package/dist/implementations/list-resources-tool.cjs +99 -0
  63. package/dist/implementations/list-resources-tool.d.cts +26 -0
  64. package/dist/implementations/list-resources-tool.d.ts +25 -0
  65. package/dist/implementations/list-resources-tool.d.ts.map +1 -0
  66. package/dist/implementations/list-resources-tool.js +75 -0
  67. package/dist/implementations/sleep-tool.cjs +45 -0
  68. package/dist/implementations/sleep-tool.d.cts +16 -0
  69. package/dist/implementations/sleep-tool.d.ts +15 -0
  70. package/dist/implementations/sleep-tool.d.ts.map +1 -0
  71. package/dist/implementations/sleep-tool.js +21 -0
  72. package/dist/index.cjs +33 -0
  73. package/dist/index.d.cts +3 -0
  74. package/dist/index.d.ts +17 -0
  75. package/dist/index.d.ts.map +1 -0
  76. package/dist/index.js +7 -0
  77. package/package.json +38 -0
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var get_resource_tool_exports = {};
20
+ __export(get_resource_tool_exports, {
21
+ createGetResourceTool: () => createGetResourceTool
22
+ });
23
+ module.exports = __toCommonJS(get_resource_tool_exports);
24
+ var import_zod = require("zod");
25
+ var import_core = require("@dexto/core");
26
+ const GetResourceInputSchema = import_zod.z.object({
27
+ reference: import_zod.z.string().describe(
28
+ 'The resource reference to access. Formats: "blob:abc123" (from list_resources), "resource_ref:blob:abc123" (from tool annotations)'
29
+ ),
30
+ format: import_zod.z.enum(["url", "metadata"]).default("url").describe(
31
+ 'Output format: "url" for a shareable URL (requires remote storage like Supabase), "metadata" for resource information without loading the data'
32
+ )
33
+ }).strict();
34
+ function createGetResourceTool() {
35
+ return (0, import_core.defineTool)({
36
+ id: "get_resource",
37
+ displayName: "Get Resource",
38
+ 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
+ inputSchema: GetResourceInputSchema,
40
+ async execute(input, context) {
41
+ const { reference, format } = input;
42
+ const resourceManager = context.services?.resources;
43
+ if (!resourceManager) {
44
+ throw import_core.ToolError.configInvalid(
45
+ "get_resource requires ToolExecutionContext.services.resources"
46
+ );
47
+ }
48
+ try {
49
+ const blobStore = resourceManager.getBlobStore();
50
+ const storeType = blobStore.getStoreType();
51
+ let blobUri = reference;
52
+ if (blobUri.startsWith("resource_ref:")) {
53
+ blobUri = blobUri.substring("resource_ref:".length);
54
+ }
55
+ if (blobUri.startsWith("@")) {
56
+ blobUri = blobUri.substring(1);
57
+ }
58
+ if (!blobUri.startsWith("blob:")) {
59
+ blobUri = `blob:${blobUri}`;
60
+ }
61
+ const exists = await blobStore.exists(blobUri);
62
+ if (!exists) {
63
+ return {
64
+ success: false,
65
+ error: `Resource not found: ${reference}`,
66
+ _hint: "Use list_resources to see available resources"
67
+ };
68
+ }
69
+ if (format === "metadata") {
70
+ const allBlobs = await blobStore.listBlobs();
71
+ const blobRef = allBlobs.find((b) => b.uri === blobUri);
72
+ if (!blobRef) {
73
+ return {
74
+ success: false,
75
+ error: `Resource metadata not found: ${reference}`,
76
+ _hint: "Use list_resources to see available resources"
77
+ };
78
+ }
79
+ return {
80
+ success: true,
81
+ format: "metadata",
82
+ reference: blobUri,
83
+ mimeType: blobRef.metadata.mimeType,
84
+ size: blobRef.metadata.size,
85
+ filename: blobRef.metadata.originalName,
86
+ source: blobRef.metadata.source,
87
+ createdAt: blobRef.metadata.createdAt.toISOString()
88
+ };
89
+ }
90
+ if (storeType === "memory" || storeType === "local") {
91
+ return {
92
+ success: false,
93
+ error: "URL generation not available with local/memory storage",
94
+ _hint: "Configure remote storage (e.g., Supabase) in your agent config to enable URL sharing. Local storage cannot generate shareable URLs.",
95
+ storeType
96
+ };
97
+ }
98
+ const blob = await blobStore.retrieve(blobUri, "url");
99
+ return {
100
+ success: true,
101
+ format: "url",
102
+ url: blob.data,
103
+ reference: blobUri,
104
+ mimeType: blob.metadata.mimeType,
105
+ size: blob.metadata.size,
106
+ filename: blob.metadata.originalName
107
+ };
108
+ } catch (error) {
109
+ const message = error instanceof Error ? error.message : String(error);
110
+ return {
111
+ success: false,
112
+ error: `Failed to access resource: ${message}`
113
+ };
114
+ }
115
+ }
116
+ });
117
+ }
118
+ // Annotate the CommonJS export names for ESM import in node:
119
+ 0 && (module.exports = {
120
+ createGetResourceTool
121
+ });
@@ -0,0 +1,22 @@
1
+ import { z } from 'zod';
2
+ import { Tool } from '@dexto/core';
3
+
4
+ declare const GetResourceInputSchema: z.ZodObject<{
5
+ reference: z.ZodString;
6
+ format: z.ZodDefault<z.ZodEnum<["url", "metadata"]>>;
7
+ }, "strict", z.ZodTypeAny, {
8
+ reference: string;
9
+ format: "url" | "metadata";
10
+ }, {
11
+ reference: string;
12
+ format?: "url" | "metadata" | undefined;
13
+ }>;
14
+ /**
15
+ * Create the `get_resource` tool.
16
+ *
17
+ * Retrieves resource metadata or a shareable URL for a stored blob resource.
18
+ * Requires `ToolExecutionContext.services.resources`.
19
+ */
20
+ declare function createGetResourceTool(): Tool<typeof GetResourceInputSchema>;
21
+
22
+ export { createGetResourceTool };
@@ -0,0 +1,21 @@
1
+ import { z } from 'zod';
2
+ import type { Tool } from '@dexto/core';
3
+ declare const GetResourceInputSchema: z.ZodObject<{
4
+ reference: z.ZodString;
5
+ format: z.ZodDefault<z.ZodEnum<["url", "metadata"]>>;
6
+ }, "strict", z.ZodTypeAny, {
7
+ reference: string;
8
+ format: "url" | "metadata";
9
+ }, {
10
+ reference: string;
11
+ format?: "url" | "metadata" | undefined;
12
+ }>;
13
+ /**
14
+ * Create the `get_resource` tool.
15
+ *
16
+ * Retrieves resource metadata or a shareable URL for a stored blob resource.
17
+ * Requires `ToolExecutionContext.services.resources`.
18
+ */
19
+ export declare function createGetResourceTool(): Tool<typeof GetResourceInputSchema>;
20
+ export {};
21
+ //# sourceMappingURL=get-resource-tool.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,97 @@
1
+ import { z } from "zod";
2
+ import { ToolError, defineTool } from "@dexto/core";
3
+ const GetResourceInputSchema = z.object({
4
+ reference: z.string().describe(
5
+ 'The resource reference to access. Formats: "blob:abc123" (from list_resources), "resource_ref:blob:abc123" (from tool annotations)'
6
+ ),
7
+ format: z.enum(["url", "metadata"]).default("url").describe(
8
+ 'Output format: "url" for a shareable URL (requires remote storage like Supabase), "metadata" for resource information without loading the data'
9
+ )
10
+ }).strict();
11
+ function createGetResourceTool() {
12
+ return defineTool({
13
+ id: "get_resource",
14
+ displayName: "Get Resource",
15
+ 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
+ inputSchema: GetResourceInputSchema,
17
+ async execute(input, context) {
18
+ const { reference, format } = input;
19
+ const resourceManager = context.services?.resources;
20
+ if (!resourceManager) {
21
+ throw ToolError.configInvalid(
22
+ "get_resource requires ToolExecutionContext.services.resources"
23
+ );
24
+ }
25
+ try {
26
+ const blobStore = resourceManager.getBlobStore();
27
+ const storeType = blobStore.getStoreType();
28
+ let blobUri = reference;
29
+ if (blobUri.startsWith("resource_ref:")) {
30
+ blobUri = blobUri.substring("resource_ref:".length);
31
+ }
32
+ if (blobUri.startsWith("@")) {
33
+ blobUri = blobUri.substring(1);
34
+ }
35
+ if (!blobUri.startsWith("blob:")) {
36
+ blobUri = `blob:${blobUri}`;
37
+ }
38
+ const exists = await blobStore.exists(blobUri);
39
+ if (!exists) {
40
+ return {
41
+ success: false,
42
+ error: `Resource not found: ${reference}`,
43
+ _hint: "Use list_resources to see available resources"
44
+ };
45
+ }
46
+ if (format === "metadata") {
47
+ const allBlobs = await blobStore.listBlobs();
48
+ const blobRef = allBlobs.find((b) => b.uri === blobUri);
49
+ if (!blobRef) {
50
+ return {
51
+ success: false,
52
+ error: `Resource metadata not found: ${reference}`,
53
+ _hint: "Use list_resources to see available resources"
54
+ };
55
+ }
56
+ return {
57
+ success: true,
58
+ format: "metadata",
59
+ reference: blobUri,
60
+ mimeType: blobRef.metadata.mimeType,
61
+ size: blobRef.metadata.size,
62
+ filename: blobRef.metadata.originalName,
63
+ source: blobRef.metadata.source,
64
+ createdAt: blobRef.metadata.createdAt.toISOString()
65
+ };
66
+ }
67
+ if (storeType === "memory" || storeType === "local") {
68
+ return {
69
+ success: false,
70
+ error: "URL generation not available with local/memory storage",
71
+ _hint: "Configure remote storage (e.g., Supabase) in your agent config to enable URL sharing. Local storage cannot generate shareable URLs.",
72
+ storeType
73
+ };
74
+ }
75
+ const blob = await blobStore.retrieve(blobUri, "url");
76
+ return {
77
+ success: true,
78
+ format: "url",
79
+ url: blob.data,
80
+ reference: blobUri,
81
+ mimeType: blob.metadata.mimeType,
82
+ size: blob.metadata.size,
83
+ filename: blob.metadata.originalName
84
+ };
85
+ } catch (error) {
86
+ const message = error instanceof Error ? error.message : String(error);
87
+ return {
88
+ success: false,
89
+ error: `Failed to access resource: ${message}`
90
+ };
91
+ }
92
+ }
93
+ });
94
+ }
95
+ export {
96
+ createGetResourceTool
97
+ };
@@ -0,0 +1,327 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var http_request_tool_exports = {};
20
+ __export(http_request_tool_exports, {
21
+ createHttpRequestTool: () => createHttpRequestTool
22
+ });
23
+ module.exports = __toCommonJS(http_request_tool_exports);
24
+ var import_zod = require("zod");
25
+ var import_core = require("@dexto/core");
26
+ var import_node_dns = require("node:dns");
27
+ var import_node_net = require("node:net");
28
+ var import_node_util = require("node:util");
29
+ var import_undici = require("undici");
30
+ const HttpRequestInputSchema = import_zod.z.object({
31
+ url: import_zod.z.string().url().describe("Absolute URL to request"),
32
+ method: import_zod.z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]).default("GET").describe("HTTP method to use"),
33
+ headers: import_zod.z.record(import_zod.z.string()).optional().describe("Optional request headers (string values only)"),
34
+ query: import_zod.z.record(import_zod.z.string()).optional().describe("Optional query parameters to append to the URL"),
35
+ body: import_zod.z.union([import_zod.z.string(), import_zod.z.record(import_zod.z.unknown()), import_zod.z.array(import_zod.z.unknown())]).optional().describe("Optional request body (string or JSON-serializable value)"),
36
+ timeoutMs: import_zod.z.number().int().positive().optional().default(3e4).describe("Request timeout in milliseconds (default: 30000)")
37
+ }).strict();
38
+ function isJsonContentType(contentType) {
39
+ return Boolean(contentType && contentType.toLowerCase().includes("application/json"));
40
+ }
41
+ function safeJsonParse(text) {
42
+ if (!text.trim()) {
43
+ return void 0;
44
+ }
45
+ try {
46
+ return JSON.parse(text);
47
+ } catch {
48
+ return void 0;
49
+ }
50
+ }
51
+ const BLOCKED_HOSTNAMES = /* @__PURE__ */ new Set(["localhost"]);
52
+ const MAX_RESPONSE_BYTES = 5 * 1024 * 1024;
53
+ const SAFE_DISPATCHER = createSafeDispatcher();
54
+ function isPrivateIpv4(ip) {
55
+ const parts = ip.split(".").map((part) => Number(part));
56
+ if (parts.length !== 4 || parts.some((part) => Number.isNaN(part))) {
57
+ return false;
58
+ }
59
+ const a = parts[0];
60
+ const b = parts[1];
61
+ const c = parts[2];
62
+ const d = parts[3];
63
+ if (a === void 0 || b === void 0 || c === void 0 || d === void 0) {
64
+ return false;
65
+ }
66
+ if (a === 0) return true;
67
+ if (a === 10) return true;
68
+ if (a === 127) return true;
69
+ if (a === 169 && b === 254) return true;
70
+ if (a === 172 && b >= 16 && b <= 31) return true;
71
+ if (a === 192 && b === 168) return true;
72
+ if (a === 100 && b >= 64 && b <= 127) return true;
73
+ if (a === 192 && b === 0 && c === 0) return true;
74
+ if (a === 192 && b === 0 && c === 2) return true;
75
+ if (a === 198 && b === 51 && c === 100) return true;
76
+ if (a === 203 && b === 0 && c === 113) return true;
77
+ if (a === 198 && (b === 18 || b === 19)) return true;
78
+ if (a >= 224 && a <= 239) return true;
79
+ if (a >= 240) return true;
80
+ return false;
81
+ }
82
+ function isPrivateIpv6(ip) {
83
+ const normalized = ip.toLowerCase();
84
+ if (normalized === "::" || normalized === "::1") return true;
85
+ if (normalized.startsWith("fe80:")) return true;
86
+ if (normalized.startsWith("fc") || normalized.startsWith("fd")) return true;
87
+ if (normalized.startsWith("::ffff:")) {
88
+ const ipv4Part = normalized.slice("::ffff:".length);
89
+ return isPrivateIpv4(ipv4Part);
90
+ }
91
+ return false;
92
+ }
93
+ function isPrivateAddress(ip) {
94
+ const version = (0, import_node_net.isIP)(ip);
95
+ if (version === 4) return isPrivateIpv4(ip);
96
+ if (version === 6) return isPrivateIpv6(ip);
97
+ return false;
98
+ }
99
+ function createSafeDispatcher() {
100
+ const lookup = (hostname, _options, callback) => {
101
+ void (async () => {
102
+ try {
103
+ 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
113
+ );
114
+ return;
115
+ }
116
+ const records = await import_node_dns.promises.lookup(hostname, {
117
+ all: true,
118
+ verbatim: true
119
+ });
120
+ 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
130
+ );
131
+ return;
132
+ }
133
+ for (const record of records) {
134
+ 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
144
+ );
145
+ return;
146
+ }
147
+ }
148
+ 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
+ );
154
+ } catch (error) {
155
+ const err = error instanceof import_core.DextoRuntimeError ? error : new import_core.DextoRuntimeError(
156
+ "HTTP_REQUEST_DNS_FAILED",
157
+ import_core.ErrorScope.TOOLS,
158
+ import_core.ErrorType.THIRD_PARTY,
159
+ `Failed to resolve hostname: ${hostname}`
160
+ );
161
+ callback(err, "", 0);
162
+ }
163
+ })();
164
+ };
165
+ return new import_undici.Agent({ connect: { lookup } });
166
+ }
167
+ async function assertSafeUrl(requestUrl) {
168
+ if (!["http:", "https:"].includes(requestUrl.protocol)) {
169
+ throw new import_core.DextoRuntimeError(
170
+ "HTTP_REQUEST_UNSUPPORTED_PROTOCOL",
171
+ import_core.ErrorScope.TOOLS,
172
+ import_core.ErrorType.USER,
173
+ `Unsupported URL protocol: ${requestUrl.protocol}`
174
+ );
175
+ }
176
+ const hostname = requestUrl.hostname.trim();
177
+ if (!hostname) {
178
+ throw new import_core.DextoRuntimeError(
179
+ "HTTP_REQUEST_INVALID_TARGET",
180
+ import_core.ErrorScope.TOOLS,
181
+ import_core.ErrorType.USER,
182
+ "Request URL hostname is required"
183
+ );
184
+ }
185
+ if (BLOCKED_HOSTNAMES.has(hostname) || hostname.endsWith(".localhost")) {
186
+ throw new import_core.DextoRuntimeError(
187
+ "HTTP_REQUEST_UNSAFE_TARGET",
188
+ import_core.ErrorScope.TOOLS,
189
+ import_core.ErrorType.FORBIDDEN,
190
+ `Blocked request to local hostname: ${hostname}`
191
+ );
192
+ }
193
+ if (isPrivateAddress(hostname)) {
194
+ throw new import_core.DextoRuntimeError(
195
+ "HTTP_REQUEST_UNSAFE_TARGET",
196
+ import_core.ErrorScope.TOOLS,
197
+ import_core.ErrorType.FORBIDDEN,
198
+ `Blocked request to private address: ${hostname}`
199
+ );
200
+ }
201
+ }
202
+ async function readResponseTextWithLimit(response) {
203
+ const contentLength = response.headers.get("content-length");
204
+ if (contentLength) {
205
+ const parsed = Number.parseInt(contentLength, 10);
206
+ if (!Number.isNaN(parsed) && parsed > MAX_RESPONSE_BYTES) {
207
+ throw new import_core.DextoRuntimeError(
208
+ "HTTP_REQUEST_RESPONSE_TOO_LARGE",
209
+ import_core.ErrorScope.TOOLS,
210
+ import_core.ErrorType.THIRD_PARTY,
211
+ `Response too large: ${parsed} bytes exceeds ${MAX_RESPONSE_BYTES} byte limit`
212
+ );
213
+ }
214
+ }
215
+ if (!response.body) {
216
+ return "";
217
+ }
218
+ const reader = response.body.getReader();
219
+ const decoder = new import_node_util.TextDecoder();
220
+ let total = 0;
221
+ let result = "";
222
+ while (true) {
223
+ const { done, value } = await reader.read();
224
+ if (done) break;
225
+ if (!value) continue;
226
+ total += value.length;
227
+ if (total > MAX_RESPONSE_BYTES) {
228
+ await reader.cancel();
229
+ throw new import_core.DextoRuntimeError(
230
+ "HTTP_REQUEST_RESPONSE_TOO_LARGE",
231
+ import_core.ErrorScope.TOOLS,
232
+ import_core.ErrorType.THIRD_PARTY,
233
+ `Response too large: exceeded ${MAX_RESPONSE_BYTES} byte limit`
234
+ );
235
+ }
236
+ result += decoder.decode(value, { stream: true });
237
+ }
238
+ result += decoder.decode();
239
+ return result;
240
+ }
241
+ function createHttpRequestTool() {
242
+ return (0, import_core.defineTool)({
243
+ id: "http_request",
244
+ displayName: "Fetch",
245
+ 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
+ inputSchema: HttpRequestInputSchema,
247
+ async execute(input, _context) {
248
+ const { url, method, headers, query, body, timeoutMs } = input;
249
+ const requestUrl = new URL(url);
250
+ if (query) {
251
+ for (const [key, value] of Object.entries(query)) {
252
+ requestUrl.searchParams.set(key, value);
253
+ }
254
+ }
255
+ await assertSafeUrl(requestUrl);
256
+ const requestHeaders = headers ? { ...headers } : {};
257
+ let requestBody;
258
+ if (body !== void 0) {
259
+ if (typeof body === "string") {
260
+ requestBody = body;
261
+ } else {
262
+ requestBody = JSON.stringify(body);
263
+ const hasContentType = Object.keys(requestHeaders).some(
264
+ (key) => key.toLowerCase() === "content-type"
265
+ );
266
+ if (!hasContentType) {
267
+ requestHeaders["Content-Type"] = "application/json";
268
+ }
269
+ }
270
+ }
271
+ const controller = new AbortController();
272
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
273
+ try {
274
+ const requestInit = {
275
+ method,
276
+ headers: requestHeaders,
277
+ signal: controller.signal
278
+ };
279
+ requestInit.dispatcher = SAFE_DISPATCHER;
280
+ if (requestBody !== void 0) {
281
+ requestInit.body = requestBody;
282
+ }
283
+ const response = await fetch(requestUrl.toString(), requestInit);
284
+ const responseText = await readResponseTextWithLimit(response);
285
+ const contentType = response.headers.get("content-type");
286
+ const json = isJsonContentType(contentType) ? safeJsonParse(responseText) : void 0;
287
+ const responseHeaders = {};
288
+ response.headers.forEach((value, key) => {
289
+ responseHeaders[key] = value;
290
+ });
291
+ const payload = {
292
+ ok: response.ok,
293
+ status: response.status,
294
+ statusText: response.statusText,
295
+ headers: responseHeaders,
296
+ body: responseText,
297
+ ...json !== void 0 ? { json } : {}
298
+ };
299
+ return payload;
300
+ } catch (error) {
301
+ if (error instanceof import_core.DextoRuntimeError) {
302
+ throw error;
303
+ }
304
+ if (error instanceof Error && error.name === "AbortError") {
305
+ throw new import_core.DextoRuntimeError(
306
+ "HTTP_REQUEST_TIMEOUT",
307
+ import_core.ErrorScope.TOOLS,
308
+ import_core.ErrorType.TIMEOUT,
309
+ `HTTP request timed out after ${timeoutMs}ms`
310
+ );
311
+ }
312
+ throw new import_core.DextoRuntimeError(
313
+ "HTTP_REQUEST_FAILED",
314
+ import_core.ErrorScope.TOOLS,
315
+ import_core.ErrorType.THIRD_PARTY,
316
+ `HTTP request failed: ${error instanceof Error ? error.message : String(error)}`
317
+ );
318
+ } finally {
319
+ clearTimeout(timeoutId);
320
+ }
321
+ }
322
+ });
323
+ }
324
+ // Annotate the CommonJS export names for ESM import in node:
325
+ 0 && (module.exports = {
326
+ createHttpRequestTool
327
+ });
@@ -0,0 +1,31 @@
1
+ import { z } from 'zod';
2
+ import { Tool } from '@dexto/core';
3
+
4
+ declare const HttpRequestInputSchema: z.ZodObject<{
5
+ url: z.ZodString;
6
+ method: z.ZodDefault<z.ZodEnum<["GET", "POST", "PUT", "PATCH", "DELETE"]>>;
7
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
8
+ query: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
9
+ body: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodArray<z.ZodUnknown, "many">]>>;
10
+ timeoutMs: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
11
+ }, "strict", z.ZodTypeAny, {
12
+ url: string;
13
+ method: "POST" | "GET" | "PUT" | "PATCH" | "DELETE";
14
+ timeoutMs: number;
15
+ headers?: Record<string, string> | undefined;
16
+ query?: Record<string, string> | undefined;
17
+ body?: string | unknown[] | Record<string, unknown> | undefined;
18
+ }, {
19
+ url: string;
20
+ method?: "POST" | "GET" | "PUT" | "PATCH" | "DELETE" | undefined;
21
+ headers?: Record<string, string> | undefined;
22
+ query?: Record<string, string> | undefined;
23
+ body?: string | unknown[] | Record<string, unknown> | undefined;
24
+ timeoutMs?: number | undefined;
25
+ }>;
26
+ /**
27
+ * Internal tool for basic HTTP requests.
28
+ */
29
+ declare function createHttpRequestTool(): Tool<typeof HttpRequestInputSchema>;
30
+
31
+ export { createHttpRequestTool };
@@ -0,0 +1,30 @@
1
+ import { z } from 'zod';
2
+ import type { Tool } from '@dexto/core';
3
+ declare const HttpRequestInputSchema: z.ZodObject<{
4
+ url: z.ZodString;
5
+ method: z.ZodDefault<z.ZodEnum<["GET", "POST", "PUT", "PATCH", "DELETE"]>>;
6
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
7
+ query: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
8
+ body: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodArray<z.ZodUnknown, "many">]>>;
9
+ timeoutMs: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
10
+ }, "strict", z.ZodTypeAny, {
11
+ url: string;
12
+ method: "POST" | "GET" | "PUT" | "PATCH" | "DELETE";
13
+ timeoutMs: number;
14
+ headers?: Record<string, string> | undefined;
15
+ query?: Record<string, string> | undefined;
16
+ body?: string | unknown[] | Record<string, unknown> | undefined;
17
+ }, {
18
+ url: string;
19
+ method?: "POST" | "GET" | "PUT" | "PATCH" | "DELETE" | undefined;
20
+ headers?: Record<string, string> | undefined;
21
+ query?: Record<string, string> | undefined;
22
+ body?: string | unknown[] | Record<string, unknown> | undefined;
23
+ timeoutMs?: number | undefined;
24
+ }>;
25
+ /**
26
+ * Internal tool for basic HTTP requests.
27
+ */
28
+ export declare function createHttpRequestTool(): Tool<typeof HttpRequestInputSchema>;
29
+ export {};
30
+ //# sourceMappingURL=http-request-tool.d.ts.map
@@ -0,0 +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"}