@robota-sdk/agent-tools 3.0.0-beta.1 → 3.0.0-beta.11
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/README.md +39 -57
- package/dist/node/index.cjs +143 -1
- package/dist/node/index.d.cts +18 -1
- package/dist/node/index.d.ts +18 -1
- package/dist/node/index.js +141 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,90 +1,72 @@
|
|
|
1
1
|
# @robota-sdk/agent-tools
|
|
2
2
|
|
|
3
|
-
Tool registry, tool creation infrastructure, and built-in CLI tools for the Robota SDK.
|
|
3
|
+
Tool registry, tool creation infrastructure, and 8 built-in CLI tools for the Robota SDK.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install @robota-sdk/agent-tools
|
|
9
|
-
# or
|
|
10
|
-
pnpm add @robota-sdk/agent-tools
|
|
11
9
|
```
|
|
12
10
|
|
|
11
|
+
Peer dependency: `@robota-sdk/agent-core`
|
|
12
|
+
|
|
13
13
|
## Quick Start
|
|
14
14
|
|
|
15
|
-
Create a
|
|
15
|
+
### Create a Tool with Zod
|
|
16
16
|
|
|
17
17
|
```typescript
|
|
18
|
-
import { z } from 'zod';
|
|
19
18
|
import { createZodFunctionTool } from '@robota-sdk/agent-tools';
|
|
19
|
+
import { z } from 'zod';
|
|
20
20
|
|
|
21
21
|
const weatherTool = createZodFunctionTool({
|
|
22
|
-
name: '
|
|
22
|
+
name: 'get_weather',
|
|
23
23
|
description: 'Get current weather for a city',
|
|
24
24
|
schema: z.object({
|
|
25
25
|
city: z.string().describe('City name'),
|
|
26
|
-
unit: z.enum(['celsius', 'fahrenheit']).default('celsius'),
|
|
27
26
|
}),
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
},
|
|
27
|
+
handler: async ({ city }) => ({
|
|
28
|
+
data: JSON.stringify({ city, temperature: 22, condition: 'sunny' }),
|
|
29
|
+
}),
|
|
32
30
|
});
|
|
33
31
|
```
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
Six CLI tools are included for file system operations:
|
|
38
|
-
|
|
39
|
-
| Export | Tool Name | Description |
|
|
40
|
-
| ----------- | --------- | ---------------------------------------- |
|
|
41
|
-
| `bashTool` | `Bash` | Execute shell commands via child_process |
|
|
42
|
-
| `readTool` | `Read` | Read file contents with line numbers |
|
|
43
|
-
| `writeTool` | `Write` | Write content to a file |
|
|
44
|
-
| `editTool` | `Edit` | Replace a specific string in a file |
|
|
45
|
-
| `globTool` | `Glob` | Find files matching a glob pattern |
|
|
46
|
-
| `grepTool` | `Grep` | Search file contents with regex |
|
|
33
|
+
### Use Built-in Tools
|
|
47
34
|
|
|
48
35
|
```typescript
|
|
49
|
-
import {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
36
|
+
import { bashTool, readTool, globTool, grepTool } from '@robota-sdk/agent-tools';
|
|
37
|
+
import { Robota } from '@robota-sdk/agent-core';
|
|
38
|
+
|
|
39
|
+
const agent = new Robota({
|
|
40
|
+
name: 'DevAgent',
|
|
41
|
+
aiProviders: [provider],
|
|
42
|
+
defaultModel: { provider: 'anthropic', model: 'claude-sonnet-4-6' },
|
|
43
|
+
tools: [bashTool, readTool, globTool, grepTool],
|
|
44
|
+
});
|
|
57
45
|
```
|
|
58
46
|
|
|
59
|
-
|
|
47
|
+
## Built-in Tools (8)
|
|
60
48
|
|
|
61
|
-
|
|
49
|
+
| Export | Tool Name | Description |
|
|
50
|
+
| --------------- | --------- | ------------------------------------ |
|
|
51
|
+
| `bashTool` | Bash | Execute shell commands |
|
|
52
|
+
| `readTool` | Read | Read file contents with line numbers |
|
|
53
|
+
| `writeTool` | Write | Write content to a file |
|
|
54
|
+
| `editTool` | Edit | Replace a specific string in a file |
|
|
55
|
+
| `globTool` | Glob | Find files matching a glob pattern |
|
|
56
|
+
| `grepTool` | Grep | Search file contents with regex |
|
|
57
|
+
| `webFetchTool` | WebFetch | Fetch URL content (HTML-to-text) |
|
|
58
|
+
| `webSearchTool` | WebSearch | Web search via Brave Search API |
|
|
62
59
|
|
|
63
|
-
|
|
64
|
-
| ----------------------- | ------------------------------------------- |
|
|
65
|
-
| `ToolRegistry` | Central tool registration and schema lookup |
|
|
66
|
-
| `FunctionTool` | JS function tool with Zod schema validation |
|
|
67
|
-
| `createFunctionTool` | Factory for creating function tools |
|
|
68
|
-
| `createZodFunctionTool` | Factory with Zod validation and conversion |
|
|
69
|
-
| `OpenAPITool` | Tool generated from OpenAPI specification |
|
|
70
|
-
| `zodToJsonSchema` | Converts Zod schemas to JSON Schema format |
|
|
71
|
-
|
|
72
|
-
## TToolResult
|
|
73
|
-
|
|
74
|
-
Built-in tools return results using the `TToolResult` type:
|
|
75
|
-
|
|
76
|
-
```typescript
|
|
77
|
-
interface TToolResult {
|
|
78
|
-
success: boolean;
|
|
79
|
-
output: string;
|
|
80
|
-
error?: string;
|
|
81
|
-
exitCode?: number;
|
|
82
|
-
}
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## Documentation
|
|
60
|
+
## Tool Infrastructure
|
|
86
61
|
|
|
87
|
-
|
|
62
|
+
| Export | Description |
|
|
63
|
+
| ----------------------- | ------------------------------------------------------ |
|
|
64
|
+
| `ToolRegistry` | Central tool registration and schema lookup |
|
|
65
|
+
| `FunctionTool` | JS function tool with Zod schema validation |
|
|
66
|
+
| `createFunctionTool` | Factory for creating function tools |
|
|
67
|
+
| `createZodFunctionTool` | Factory with Zod validation and JSON Schema conversion |
|
|
68
|
+
| `OpenAPITool` | Tool generated from OpenAPI specification |
|
|
69
|
+
| `zodToJsonSchema` | Converts Zod schemas to JSON Schema format |
|
|
88
70
|
|
|
89
71
|
## License
|
|
90
72
|
|
package/dist/node/index.cjs
CHANGED
|
@@ -41,6 +41,8 @@ __export(index_exports, {
|
|
|
41
41
|
globTool: () => globTool,
|
|
42
42
|
grepTool: () => grepTool,
|
|
43
43
|
readTool: () => readTool,
|
|
44
|
+
webFetchTool: () => webFetchTool,
|
|
45
|
+
webSearchTool: () => webSearchTool,
|
|
44
46
|
writeTool: () => writeTool,
|
|
45
47
|
zodToJsonSchema: () => zodToJsonSchema
|
|
46
48
|
});
|
|
@@ -274,6 +276,12 @@ function convertZodTypeToProperty(typeObj) {
|
|
|
274
276
|
return { ...innerProperty, ...base };
|
|
275
277
|
}
|
|
276
278
|
throw new Error("ZodDefault is missing innerType; cannot convert to JSON schema.");
|
|
279
|
+
case "ZodRecord":
|
|
280
|
+
if (typeDef.valueType) {
|
|
281
|
+
const valueProperty = convertZodTypeToProperty(typeDef.valueType);
|
|
282
|
+
return { type: "object", additionalProperties: valueProperty, ...base };
|
|
283
|
+
}
|
|
284
|
+
return { type: "object", additionalProperties: { type: "string" }, ...base };
|
|
277
285
|
default:
|
|
278
286
|
throw new Error(`Unsupported Zod type: ${String(typeDef.typeName)}`);
|
|
279
287
|
}
|
|
@@ -1010,7 +1018,7 @@ async function writeFileTool(args) {
|
|
|
1010
1018
|
await (0, import_promises2.writeFile)(filePath, content, "utf8");
|
|
1011
1019
|
const result = {
|
|
1012
1020
|
success: true,
|
|
1013
|
-
output: `Written ${content
|
|
1021
|
+
output: `Written ${Buffer.byteLength(content, "utf8")} bytes to ${filePath}`
|
|
1014
1022
|
};
|
|
1015
1023
|
return JSON.stringify(result);
|
|
1016
1024
|
} catch (err) {
|
|
@@ -1334,6 +1342,138 @@ var grepTool = createZodFunctionTool(
|
|
|
1334
1342
|
return grepFileTool(params);
|
|
1335
1343
|
}
|
|
1336
1344
|
);
|
|
1345
|
+
|
|
1346
|
+
// src/builtins/web-fetch-tool.ts
|
|
1347
|
+
var import_zod7 = require("zod");
|
|
1348
|
+
var DEFAULT_TIMEOUT_MS2 = 3e4;
|
|
1349
|
+
var MAX_RESPONSE_BYTES = 5e6;
|
|
1350
|
+
var WebFetchSchema = import_zod7.z.object({
|
|
1351
|
+
url: import_zod7.z.string().describe("The URL to fetch"),
|
|
1352
|
+
headers: import_zod7.z.record(import_zod7.z.string()).optional().describe("Optional HTTP headers as key-value pairs")
|
|
1353
|
+
});
|
|
1354
|
+
function htmlToText(html) {
|
|
1355
|
+
return html.replace(/<script[\s\S]*?<\/script>/gi, "").replace(/<style[\s\S]*?<\/style>/gi, "").replace(/<[^>]+>/g, " ").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/ /g, " ").replace(/\s+/g, " ").trim();
|
|
1356
|
+
}
|
|
1357
|
+
async function runWebFetch(args) {
|
|
1358
|
+
const { url, headers } = args;
|
|
1359
|
+
try {
|
|
1360
|
+
new URL(url);
|
|
1361
|
+
} catch {
|
|
1362
|
+
const result = { success: false, output: "", error: `Invalid URL: ${url}` };
|
|
1363
|
+
return JSON.stringify(result);
|
|
1364
|
+
}
|
|
1365
|
+
try {
|
|
1366
|
+
const controller = new AbortController();
|
|
1367
|
+
const timeout = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS2);
|
|
1368
|
+
const response = await fetch(url, {
|
|
1369
|
+
headers: {
|
|
1370
|
+
"User-Agent": "Robota-CLI/3.0",
|
|
1371
|
+
...headers ?? {}
|
|
1372
|
+
},
|
|
1373
|
+
signal: controller.signal,
|
|
1374
|
+
redirect: "follow"
|
|
1375
|
+
});
|
|
1376
|
+
clearTimeout(timeout);
|
|
1377
|
+
if (!response.ok) {
|
|
1378
|
+
const result2 = {
|
|
1379
|
+
success: false,
|
|
1380
|
+
output: "",
|
|
1381
|
+
error: `HTTP ${response.status} ${response.statusText}`
|
|
1382
|
+
};
|
|
1383
|
+
return JSON.stringify(result2);
|
|
1384
|
+
}
|
|
1385
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
1386
|
+
const buffer = await response.arrayBuffer();
|
|
1387
|
+
if (buffer.byteLength > MAX_RESPONSE_BYTES) {
|
|
1388
|
+
const result2 = {
|
|
1389
|
+
success: false,
|
|
1390
|
+
output: "",
|
|
1391
|
+
error: `Response too large: ${buffer.byteLength} bytes (max ${MAX_RESPONSE_BYTES})`
|
|
1392
|
+
};
|
|
1393
|
+
return JSON.stringify(result2);
|
|
1394
|
+
}
|
|
1395
|
+
let text = new TextDecoder().decode(buffer);
|
|
1396
|
+
if (contentType.includes("html")) {
|
|
1397
|
+
text = htmlToText(text);
|
|
1398
|
+
}
|
|
1399
|
+
const result = { success: true, output: text };
|
|
1400
|
+
return JSON.stringify(result);
|
|
1401
|
+
} catch (err) {
|
|
1402
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1403
|
+
const result = { success: false, output: "", error: message };
|
|
1404
|
+
return JSON.stringify(result);
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
var webFetchTool = createZodFunctionTool(
|
|
1408
|
+
"WebFetch",
|
|
1409
|
+
"Fetch a URL and return its content as text. HTML pages are converted to plain text.",
|
|
1410
|
+
WebFetchSchema,
|
|
1411
|
+
async (params) => runWebFetch(params)
|
|
1412
|
+
);
|
|
1413
|
+
|
|
1414
|
+
// src/builtins/web-search-tool.ts
|
|
1415
|
+
var import_zod8 = require("zod");
|
|
1416
|
+
var DEFAULT_LIMIT2 = 10;
|
|
1417
|
+
var DEFAULT_TIMEOUT_MS3 = 15e3;
|
|
1418
|
+
var WebSearchSchema = import_zod8.z.object({
|
|
1419
|
+
query: import_zod8.z.string().describe("The search query"),
|
|
1420
|
+
limit: import_zod8.z.number().optional().describe(`Maximum number of results to return (default: ${DEFAULT_LIMIT2})`)
|
|
1421
|
+
});
|
|
1422
|
+
async function runWebSearch(args) {
|
|
1423
|
+
const { query, limit = DEFAULT_LIMIT2 } = args;
|
|
1424
|
+
const apiKey = process.env["BRAVE_API_KEY"];
|
|
1425
|
+
if (!apiKey) {
|
|
1426
|
+
const result = {
|
|
1427
|
+
success: false,
|
|
1428
|
+
output: "",
|
|
1429
|
+
error: "Web search requires BRAVE_API_KEY environment variable. Get a free API key at https://brave.com/search/api/ (2,000 queries/month free)."
|
|
1430
|
+
};
|
|
1431
|
+
return JSON.stringify(result);
|
|
1432
|
+
}
|
|
1433
|
+
try {
|
|
1434
|
+
const controller = new AbortController();
|
|
1435
|
+
const timeout = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS3);
|
|
1436
|
+
const params = new URLSearchParams({
|
|
1437
|
+
q: query,
|
|
1438
|
+
count: String(Math.min(limit, 20))
|
|
1439
|
+
});
|
|
1440
|
+
const response = await fetch(`https://api.search.brave.com/res/v1/web/search?${params}`, {
|
|
1441
|
+
headers: {
|
|
1442
|
+
Accept: "application/json",
|
|
1443
|
+
"Accept-Encoding": "gzip",
|
|
1444
|
+
"X-Subscription-Token": apiKey
|
|
1445
|
+
},
|
|
1446
|
+
signal: controller.signal
|
|
1447
|
+
});
|
|
1448
|
+
clearTimeout(timeout);
|
|
1449
|
+
if (!response.ok) {
|
|
1450
|
+
const result2 = {
|
|
1451
|
+
success: false,
|
|
1452
|
+
output: "",
|
|
1453
|
+
error: `Brave Search API error: HTTP ${response.status} ${response.statusText}`
|
|
1454
|
+
};
|
|
1455
|
+
return JSON.stringify(result2);
|
|
1456
|
+
}
|
|
1457
|
+
const data = await response.json();
|
|
1458
|
+
const results = (data.web?.results ?? []).map((r) => ({
|
|
1459
|
+
title: r.title,
|
|
1460
|
+
url: r.url,
|
|
1461
|
+
snippet: r.description
|
|
1462
|
+
}));
|
|
1463
|
+
const result = { success: true, output: JSON.stringify(results, null, 2) };
|
|
1464
|
+
return JSON.stringify(result);
|
|
1465
|
+
} catch (err) {
|
|
1466
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1467
|
+
const result = { success: false, output: "", error: message };
|
|
1468
|
+
return JSON.stringify(result);
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
var webSearchTool = createZodFunctionTool(
|
|
1472
|
+
"WebSearch",
|
|
1473
|
+
"Search the web and return results with title, URL, and snippet.",
|
|
1474
|
+
WebSearchSchema,
|
|
1475
|
+
async (params) => runWebSearch(params)
|
|
1476
|
+
);
|
|
1337
1477
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1338
1478
|
0 && (module.exports = {
|
|
1339
1479
|
FunctionTool,
|
|
@@ -1347,6 +1487,8 @@ var grepTool = createZodFunctionTool(
|
|
|
1347
1487
|
globTool,
|
|
1348
1488
|
grepTool,
|
|
1349
1489
|
readTool,
|
|
1490
|
+
webFetchTool,
|
|
1491
|
+
webSearchTool,
|
|
1350
1492
|
writeTool,
|
|
1351
1493
|
zodToJsonSchema
|
|
1352
1494
|
});
|
package/dist/node/index.d.cts
CHANGED
|
@@ -86,6 +86,7 @@ interface IZodParseResult {
|
|
|
86
86
|
interface IZodSchemaDef {
|
|
87
87
|
typeName?: string;
|
|
88
88
|
innerType?: IZodSchema;
|
|
89
|
+
valueType?: IZodSchema;
|
|
89
90
|
checks?: Array<{
|
|
90
91
|
kind: string;
|
|
91
92
|
value?: TUniversalValue;
|
|
@@ -350,4 +351,20 @@ declare const globTool: FunctionTool;
|
|
|
350
351
|
*/
|
|
351
352
|
declare const grepTool: FunctionTool;
|
|
352
353
|
|
|
353
|
-
|
|
354
|
+
/**
|
|
355
|
+
* WebFetchTool — fetch a URL and return its content as text.
|
|
356
|
+
*
|
|
357
|
+
* HTML is stripped to plain text for readability. Uses Node.js native fetch.
|
|
358
|
+
* Output is capped at 30K chars (same as other tools).
|
|
359
|
+
*/
|
|
360
|
+
declare const webFetchTool: FunctionTool;
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* WebSearchTool — search the web and return results.
|
|
364
|
+
*
|
|
365
|
+
* Uses Brave Search API when BRAVE_API_KEY is set.
|
|
366
|
+
* Returns an error with setup instructions otherwise.
|
|
367
|
+
*/
|
|
368
|
+
declare const webSearchTool: FunctionTool;
|
|
369
|
+
|
|
370
|
+
export { FunctionTool, type IFunctionToolExecutionMetadata, type IFunctionToolResult, type IFunctionToolValidationOptions, type ISchemaConversionOptions, type IZodParseResult, type IZodSchema, type IZodSchemaDef, OpenAPITool, type TToolResult, ToolRegistry, bashTool, createFunctionTool, createOpenAPITool, createZodFunctionTool, editTool, globTool, grepTool, readTool, webFetchTool, webSearchTool, writeTool, zodToJsonSchema };
|
package/dist/node/index.d.ts
CHANGED
|
@@ -86,6 +86,7 @@ interface IZodParseResult {
|
|
|
86
86
|
interface IZodSchemaDef {
|
|
87
87
|
typeName?: string;
|
|
88
88
|
innerType?: IZodSchema;
|
|
89
|
+
valueType?: IZodSchema;
|
|
89
90
|
checks?: Array<{
|
|
90
91
|
kind: string;
|
|
91
92
|
value?: TUniversalValue;
|
|
@@ -350,4 +351,20 @@ declare const globTool: FunctionTool;
|
|
|
350
351
|
*/
|
|
351
352
|
declare const grepTool: FunctionTool;
|
|
352
353
|
|
|
353
|
-
|
|
354
|
+
/**
|
|
355
|
+
* WebFetchTool — fetch a URL and return its content as text.
|
|
356
|
+
*
|
|
357
|
+
* HTML is stripped to plain text for readability. Uses Node.js native fetch.
|
|
358
|
+
* Output is capped at 30K chars (same as other tools).
|
|
359
|
+
*/
|
|
360
|
+
declare const webFetchTool: FunctionTool;
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* WebSearchTool — search the web and return results.
|
|
364
|
+
*
|
|
365
|
+
* Uses Brave Search API when BRAVE_API_KEY is set.
|
|
366
|
+
* Returns an error with setup instructions otherwise.
|
|
367
|
+
*/
|
|
368
|
+
declare const webSearchTool: FunctionTool;
|
|
369
|
+
|
|
370
|
+
export { FunctionTool, type IFunctionToolExecutionMetadata, type IFunctionToolResult, type IFunctionToolValidationOptions, type ISchemaConversionOptions, type IZodParseResult, type IZodSchema, type IZodSchemaDef, OpenAPITool, type TToolResult, ToolRegistry, bashTool, createFunctionTool, createOpenAPITool, createZodFunctionTool, editTool, globTool, grepTool, readTool, webFetchTool, webSearchTool, writeTool, zodToJsonSchema };
|
package/dist/node/index.js
CHANGED
|
@@ -226,6 +226,12 @@ function convertZodTypeToProperty(typeObj) {
|
|
|
226
226
|
return { ...innerProperty, ...base };
|
|
227
227
|
}
|
|
228
228
|
throw new Error("ZodDefault is missing innerType; cannot convert to JSON schema.");
|
|
229
|
+
case "ZodRecord":
|
|
230
|
+
if (typeDef.valueType) {
|
|
231
|
+
const valueProperty = convertZodTypeToProperty(typeDef.valueType);
|
|
232
|
+
return { type: "object", additionalProperties: valueProperty, ...base };
|
|
233
|
+
}
|
|
234
|
+
return { type: "object", additionalProperties: { type: "string" }, ...base };
|
|
229
235
|
default:
|
|
230
236
|
throw new Error(`Unsupported Zod type: ${String(typeDef.typeName)}`);
|
|
231
237
|
}
|
|
@@ -962,7 +968,7 @@ async function writeFileTool(args) {
|
|
|
962
968
|
await writeFile(filePath, content, "utf8");
|
|
963
969
|
const result = {
|
|
964
970
|
success: true,
|
|
965
|
-
output: `Written ${content
|
|
971
|
+
output: `Written ${Buffer.byteLength(content, "utf8")} bytes to ${filePath}`
|
|
966
972
|
};
|
|
967
973
|
return JSON.stringify(result);
|
|
968
974
|
} catch (err) {
|
|
@@ -1286,6 +1292,138 @@ var grepTool = createZodFunctionTool(
|
|
|
1286
1292
|
return grepFileTool(params);
|
|
1287
1293
|
}
|
|
1288
1294
|
);
|
|
1295
|
+
|
|
1296
|
+
// src/builtins/web-fetch-tool.ts
|
|
1297
|
+
import { z as z7 } from "zod";
|
|
1298
|
+
var DEFAULT_TIMEOUT_MS2 = 3e4;
|
|
1299
|
+
var MAX_RESPONSE_BYTES = 5e6;
|
|
1300
|
+
var WebFetchSchema = z7.object({
|
|
1301
|
+
url: z7.string().describe("The URL to fetch"),
|
|
1302
|
+
headers: z7.record(z7.string()).optional().describe("Optional HTTP headers as key-value pairs")
|
|
1303
|
+
});
|
|
1304
|
+
function htmlToText(html) {
|
|
1305
|
+
return html.replace(/<script[\s\S]*?<\/script>/gi, "").replace(/<style[\s\S]*?<\/style>/gi, "").replace(/<[^>]+>/g, " ").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/ /g, " ").replace(/\s+/g, " ").trim();
|
|
1306
|
+
}
|
|
1307
|
+
async function runWebFetch(args) {
|
|
1308
|
+
const { url, headers } = args;
|
|
1309
|
+
try {
|
|
1310
|
+
new URL(url);
|
|
1311
|
+
} catch {
|
|
1312
|
+
const result = { success: false, output: "", error: `Invalid URL: ${url}` };
|
|
1313
|
+
return JSON.stringify(result);
|
|
1314
|
+
}
|
|
1315
|
+
try {
|
|
1316
|
+
const controller = new AbortController();
|
|
1317
|
+
const timeout = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS2);
|
|
1318
|
+
const response = await fetch(url, {
|
|
1319
|
+
headers: {
|
|
1320
|
+
"User-Agent": "Robota-CLI/3.0",
|
|
1321
|
+
...headers ?? {}
|
|
1322
|
+
},
|
|
1323
|
+
signal: controller.signal,
|
|
1324
|
+
redirect: "follow"
|
|
1325
|
+
});
|
|
1326
|
+
clearTimeout(timeout);
|
|
1327
|
+
if (!response.ok) {
|
|
1328
|
+
const result2 = {
|
|
1329
|
+
success: false,
|
|
1330
|
+
output: "",
|
|
1331
|
+
error: `HTTP ${response.status} ${response.statusText}`
|
|
1332
|
+
};
|
|
1333
|
+
return JSON.stringify(result2);
|
|
1334
|
+
}
|
|
1335
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
1336
|
+
const buffer = await response.arrayBuffer();
|
|
1337
|
+
if (buffer.byteLength > MAX_RESPONSE_BYTES) {
|
|
1338
|
+
const result2 = {
|
|
1339
|
+
success: false,
|
|
1340
|
+
output: "",
|
|
1341
|
+
error: `Response too large: ${buffer.byteLength} bytes (max ${MAX_RESPONSE_BYTES})`
|
|
1342
|
+
};
|
|
1343
|
+
return JSON.stringify(result2);
|
|
1344
|
+
}
|
|
1345
|
+
let text = new TextDecoder().decode(buffer);
|
|
1346
|
+
if (contentType.includes("html")) {
|
|
1347
|
+
text = htmlToText(text);
|
|
1348
|
+
}
|
|
1349
|
+
const result = { success: true, output: text };
|
|
1350
|
+
return JSON.stringify(result);
|
|
1351
|
+
} catch (err) {
|
|
1352
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1353
|
+
const result = { success: false, output: "", error: message };
|
|
1354
|
+
return JSON.stringify(result);
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
var webFetchTool = createZodFunctionTool(
|
|
1358
|
+
"WebFetch",
|
|
1359
|
+
"Fetch a URL and return its content as text. HTML pages are converted to plain text.",
|
|
1360
|
+
WebFetchSchema,
|
|
1361
|
+
async (params) => runWebFetch(params)
|
|
1362
|
+
);
|
|
1363
|
+
|
|
1364
|
+
// src/builtins/web-search-tool.ts
|
|
1365
|
+
import { z as z8 } from "zod";
|
|
1366
|
+
var DEFAULT_LIMIT2 = 10;
|
|
1367
|
+
var DEFAULT_TIMEOUT_MS3 = 15e3;
|
|
1368
|
+
var WebSearchSchema = z8.object({
|
|
1369
|
+
query: z8.string().describe("The search query"),
|
|
1370
|
+
limit: z8.number().optional().describe(`Maximum number of results to return (default: ${DEFAULT_LIMIT2})`)
|
|
1371
|
+
});
|
|
1372
|
+
async function runWebSearch(args) {
|
|
1373
|
+
const { query, limit = DEFAULT_LIMIT2 } = args;
|
|
1374
|
+
const apiKey = process.env["BRAVE_API_KEY"];
|
|
1375
|
+
if (!apiKey) {
|
|
1376
|
+
const result = {
|
|
1377
|
+
success: false,
|
|
1378
|
+
output: "",
|
|
1379
|
+
error: "Web search requires BRAVE_API_KEY environment variable. Get a free API key at https://brave.com/search/api/ (2,000 queries/month free)."
|
|
1380
|
+
};
|
|
1381
|
+
return JSON.stringify(result);
|
|
1382
|
+
}
|
|
1383
|
+
try {
|
|
1384
|
+
const controller = new AbortController();
|
|
1385
|
+
const timeout = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS3);
|
|
1386
|
+
const params = new URLSearchParams({
|
|
1387
|
+
q: query,
|
|
1388
|
+
count: String(Math.min(limit, 20))
|
|
1389
|
+
});
|
|
1390
|
+
const response = await fetch(`https://api.search.brave.com/res/v1/web/search?${params}`, {
|
|
1391
|
+
headers: {
|
|
1392
|
+
Accept: "application/json",
|
|
1393
|
+
"Accept-Encoding": "gzip",
|
|
1394
|
+
"X-Subscription-Token": apiKey
|
|
1395
|
+
},
|
|
1396
|
+
signal: controller.signal
|
|
1397
|
+
});
|
|
1398
|
+
clearTimeout(timeout);
|
|
1399
|
+
if (!response.ok) {
|
|
1400
|
+
const result2 = {
|
|
1401
|
+
success: false,
|
|
1402
|
+
output: "",
|
|
1403
|
+
error: `Brave Search API error: HTTP ${response.status} ${response.statusText}`
|
|
1404
|
+
};
|
|
1405
|
+
return JSON.stringify(result2);
|
|
1406
|
+
}
|
|
1407
|
+
const data = await response.json();
|
|
1408
|
+
const results = (data.web?.results ?? []).map((r) => ({
|
|
1409
|
+
title: r.title,
|
|
1410
|
+
url: r.url,
|
|
1411
|
+
snippet: r.description
|
|
1412
|
+
}));
|
|
1413
|
+
const result = { success: true, output: JSON.stringify(results, null, 2) };
|
|
1414
|
+
return JSON.stringify(result);
|
|
1415
|
+
} catch (err) {
|
|
1416
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1417
|
+
const result = { success: false, output: "", error: message };
|
|
1418
|
+
return JSON.stringify(result);
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
var webSearchTool = createZodFunctionTool(
|
|
1422
|
+
"WebSearch",
|
|
1423
|
+
"Search the web and return results with title, URL, and snippet.",
|
|
1424
|
+
WebSearchSchema,
|
|
1425
|
+
async (params) => runWebSearch(params)
|
|
1426
|
+
);
|
|
1289
1427
|
export {
|
|
1290
1428
|
FunctionTool,
|
|
1291
1429
|
OpenAPITool,
|
|
@@ -1298,6 +1436,8 @@ export {
|
|
|
1298
1436
|
globTool,
|
|
1299
1437
|
grepTool,
|
|
1300
1438
|
readTool,
|
|
1439
|
+
webFetchTool,
|
|
1440
|
+
webSearchTool,
|
|
1301
1441
|
writeTool,
|
|
1302
1442
|
zodToJsonSchema
|
|
1303
1443
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robota-sdk/agent-tools",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.11",
|
|
4
4
|
"description": "Tool registry and implementations for Robota SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/node/index.js",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"zod": "^3.24.0"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
29
|
-
"@robota-sdk/agent-core": "3.0.0-beta.
|
|
29
|
+
"@robota-sdk/agent-core": "3.0.0-beta.11"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"openapi-types": "^12.1.3",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"tsup": "^8.0.1",
|
|
35
35
|
"typescript": "^5.3.3",
|
|
36
36
|
"vitest": "^1.6.1",
|
|
37
|
-
"@robota-sdk/agent-core": "3.0.0-beta.
|
|
37
|
+
"@robota-sdk/agent-core": "3.0.0-beta.11"
|
|
38
38
|
},
|
|
39
39
|
"license": "MIT",
|
|
40
40
|
"publishConfig": {
|