fourmis-agents-sdk 0.3.1 → 0.4.1

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 (84) hide show
  1. package/README.md +126 -198
  2. package/dist/agent-loop.d.ts +21 -3
  3. package/dist/agent-loop.d.ts.map +1 -1
  4. package/dist/agent-loop.js +279 -90
  5. package/dist/agents/index.js +1079 -124
  6. package/dist/agents/tools.d.ts.map +1 -1
  7. package/dist/agents/tools.js +1079 -124
  8. package/dist/agents/types.d.ts +4 -0
  9. package/dist/agents/types.d.ts.map +1 -1
  10. package/dist/api.d.ts +8 -5
  11. package/dist/api.d.ts.map +1 -1
  12. package/dist/api.js +1663 -430
  13. package/dist/hooks.d.ts +19 -1
  14. package/dist/hooks.d.ts.map +1 -1
  15. package/dist/hooks.js +27 -2
  16. package/dist/index.d.ts +8 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +1671 -431
  19. package/dist/mcp/client.d.ts +8 -1
  20. package/dist/mcp/client.d.ts.map +1 -1
  21. package/dist/mcp/client.js +134 -13
  22. package/dist/mcp/index.js +134 -13
  23. package/dist/mcp/types.d.ts +21 -1
  24. package/dist/mcp/types.d.ts.map +1 -1
  25. package/dist/permissions.d.ts.map +1 -1
  26. package/dist/permissions.js +7 -3
  27. package/dist/providers/anthropic.d.ts.map +1 -1
  28. package/dist/providers/anthropic.js +41 -2
  29. package/dist/providers/openai.d.ts +6 -0
  30. package/dist/providers/openai.d.ts.map +1 -1
  31. package/dist/providers/openai.js +36 -6
  32. package/dist/providers/registry.js +76 -8
  33. package/dist/providers/types.d.ts +4 -1
  34. package/dist/providers/types.d.ts.map +1 -1
  35. package/dist/query.d.ts +21 -2
  36. package/dist/query.d.ts.map +1 -1
  37. package/dist/query.js +69 -1
  38. package/dist/skills/index.js +23 -1
  39. package/dist/skills/skills.d.ts +16 -0
  40. package/dist/skills/skills.d.ts.map +1 -1
  41. package/dist/skills/skills.js +23 -1
  42. package/dist/tools/ask-user-question.d.ts +7 -0
  43. package/dist/tools/ask-user-question.d.ts.map +1 -0
  44. package/dist/tools/ask-user-question.js +48 -0
  45. package/dist/tools/bash.d.ts.map +1 -1
  46. package/dist/tools/bash.js +47 -2
  47. package/dist/tools/config.d.ts +7 -0
  48. package/dist/tools/config.d.ts.map +1 -0
  49. package/dist/tools/config.js +114 -0
  50. package/dist/tools/exit-plan-mode.d.ts +7 -0
  51. package/dist/tools/exit-plan-mode.d.ts.map +1 -0
  52. package/dist/tools/exit-plan-mode.js +34 -0
  53. package/dist/tools/index.d.ts +7 -0
  54. package/dist/tools/index.d.ts.map +1 -1
  55. package/dist/tools/index.js +506 -9
  56. package/dist/tools/notebook-edit.d.ts +7 -0
  57. package/dist/tools/notebook-edit.d.ts.map +1 -0
  58. package/dist/tools/notebook-edit.js +83 -0
  59. package/dist/tools/presets.d.ts +2 -1
  60. package/dist/tools/presets.d.ts.map +1 -1
  61. package/dist/tools/presets.js +22 -4
  62. package/dist/tools/read.d.ts.map +1 -1
  63. package/dist/tools/read.js +12 -1
  64. package/dist/tools/registry.d.ts +2 -0
  65. package/dist/tools/registry.d.ts.map +1 -1
  66. package/dist/tools/registry.js +10 -0
  67. package/dist/tools/todo-write.d.ts +7 -0
  68. package/dist/tools/todo-write.d.ts.map +1 -0
  69. package/dist/tools/todo-write.js +69 -0
  70. package/dist/tools/web-fetch.d.ts +6 -0
  71. package/dist/tools/web-fetch.d.ts.map +1 -0
  72. package/dist/tools/web-fetch.js +85 -0
  73. package/dist/tools/web-search.d.ts +7 -0
  74. package/dist/tools/web-search.d.ts.map +1 -0
  75. package/dist/tools/web-search.js +78 -0
  76. package/dist/types.d.ts +344 -42
  77. package/dist/types.d.ts.map +1 -1
  78. package/dist/utils/session-store.d.ts +1 -1
  79. package/dist/utils/session-store.d.ts.map +1 -1
  80. package/dist/utils/session-store.js +49 -2
  81. package/dist/utils/system-prompt.d.ts +2 -0
  82. package/dist/utils/system-prompt.d.ts.map +1 -1
  83. package/dist/utils/system-prompt.js +33 -4
  84. package/package.json +3 -2
@@ -15,16 +15,34 @@ var __require = import.meta.require;
15
15
  // src/tools/presets.ts
16
16
  var PRESETS = {
17
17
  coding: ["Bash", "Read", "Write", "Edit", "Glob", "Grep"],
18
+ claude_code: [
19
+ "Bash",
20
+ "Read",
21
+ "Write",
22
+ "Edit",
23
+ "Glob",
24
+ "Grep",
25
+ "NotebookEdit",
26
+ "WebFetch",
27
+ "WebSearch",
28
+ "TodoWrite",
29
+ "Config",
30
+ "AskUserQuestion",
31
+ "ExitPlanMode"
32
+ ],
18
33
  readonly: ["Read", "Glob", "Grep"],
19
34
  minimal: ["Read", "Write", "Edit", "Glob", "Grep"]
20
35
  };
21
36
  function resolveToolNames(tools) {
22
37
  if (!tools)
23
- return PRESETS.coding;
24
- if (typeof tools === "string") {
25
- return PRESETS[tools] ?? [tools];
38
+ return PRESETS.claude_code;
39
+ if (Array.isArray(tools)) {
40
+ return tools;
26
41
  }
27
- return tools;
42
+ if (tools.type === "preset") {
43
+ return PRESETS[tools.preset] ?? PRESETS.claude_code;
44
+ }
45
+ throw new Error("Invalid tools option. Expected string[] or { type: 'preset', preset: 'claude_code' }.");
28
46
  }
29
47
  export {
30
48
  resolveToolNames,
@@ -1 +1 @@
1
- {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/tools/read.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAA2B,MAAM,eAAe,CAAC;AAKjF,eAAO,MAAM,QAAQ,EAAE,kBAoEtB,CAAC"}
1
+ {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/tools/read.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAA2B,MAAM,eAAe,CAAC;AAKjF,eAAO,MAAM,QAAQ,EAAE,kBAiFtB,CAAC"}
@@ -32,12 +32,17 @@ var ReadTool = {
32
32
  limit: {
33
33
  type: "number",
34
34
  description: "Number of lines to read"
35
+ },
36
+ pages: {
37
+ type: "array",
38
+ items: { type: "number" },
39
+ description: "Optional PDF page numbers (1-based)."
35
40
  }
36
41
  },
37
42
  required: ["file_path"]
38
43
  },
39
44
  async execute(input, ctx) {
40
- const { file_path, offset, limit } = input;
45
+ const { file_path, offset, limit, pages } = input;
41
46
  if (!file_path) {
42
47
  return { content: "Error: file_path is required", isError: true };
43
48
  }
@@ -48,6 +53,12 @@ var ReadTool = {
48
53
  if (!exists) {
49
54
  return { content: `Error: File not found: ${resolvedPath}`, isError: true };
50
55
  }
56
+ if (Array.isArray(pages) && pages.length > 0 && resolvedPath.toLowerCase().endsWith(".pdf")) {
57
+ return {
58
+ content: "Error: PDF page extraction is not implemented in this runtime.",
59
+ isError: true
60
+ };
61
+ }
51
62
  const text = await file.text();
52
63
  const lines = text.split(`
53
64
  `);
@@ -22,6 +22,8 @@ export type ToolImplementation = {
22
22
  export declare class ToolRegistry {
23
23
  private tools;
24
24
  register(tool: ToolImplementation): void;
25
+ unregister(name: string): void;
26
+ clearByPrefix(prefix: string): void;
25
27
  get(name: string): ToolImplementation | undefined;
26
28
  has(name: string): boolean;
27
29
  getDefinitions(): ToolDefinition[];
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/tools/registry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAI5D,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CAChE,CAAC;AAIF,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAyC;IAEtD,QAAQ,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI;IAIxC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAIjD,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B,cAAc,IAAI,cAAc,EAAE;IAQ5B,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAclF,IAAI,IAAI,MAAM,EAAE;CAGjB"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/tools/registry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAI5D,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CAChE,CAAC;AAIF,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAyC;IAEtD,QAAQ,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI;IAIxC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI9B,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAQnC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAIjD,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B,cAAc,IAAI,cAAc,EAAE;IAQ5B,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAclF,IAAI,IAAI,MAAM,EAAE;CAGjB"}
@@ -18,6 +18,16 @@ class ToolRegistry {
18
18
  register(tool) {
19
19
  this.tools.set(tool.name, tool);
20
20
  }
21
+ unregister(name) {
22
+ this.tools.delete(name);
23
+ }
24
+ clearByPrefix(prefix) {
25
+ for (const name of this.tools.keys()) {
26
+ if (name.startsWith(prefix)) {
27
+ this.tools.delete(name);
28
+ }
29
+ }
30
+ }
21
31
  get(name) {
22
32
  return this.tools.get(name);
23
33
  }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * TodoWrite tool.
3
+ * Persists structured task todos to .claude/todos.json in cwd.
4
+ */
5
+ import type { ToolImplementation } from "./registry.js";
6
+ export declare const TodoWriteTool: ToolImplementation;
7
+ //# sourceMappingURL=todo-write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"todo-write.d.ts","sourceRoot":"","sources":["../../src/tools/todo-write.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,kBAAkB,EAA2B,MAAM,eAAe,CAAC;AAQjF,eAAO,MAAM,aAAa,EAAE,kBAuD3B,CAAC"}
@@ -0,0 +1,69 @@
1
+ // @bun
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true,
8
+ configurable: true,
9
+ set: (newValue) => all[name] = () => newValue
10
+ });
11
+ };
12
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
13
+ var __require = import.meta.require;
14
+
15
+ // src/tools/todo-write.ts
16
+ import { mkdir, writeFile } from "fs/promises";
17
+ import { dirname, join } from "path";
18
+ var TodoWriteTool = {
19
+ name: "TodoWrite",
20
+ description: "Write/update task todo items for the current session.",
21
+ inputSchema: {
22
+ type: "object",
23
+ properties: {
24
+ todos: {
25
+ type: "array",
26
+ items: {
27
+ type: "object",
28
+ properties: {
29
+ content: { type: "string" },
30
+ status: { type: "string", enum: ["pending", "in_progress", "completed"] },
31
+ activeForm: { type: "string" }
32
+ },
33
+ required: ["content", "status"]
34
+ }
35
+ }
36
+ },
37
+ required: ["todos"]
38
+ },
39
+ async execute(input, ctx) {
40
+ const { todos } = input ?? {};
41
+ if (!Array.isArray(todos)) {
42
+ return { content: "Error: todos must be an array", isError: true };
43
+ }
44
+ for (const todo of todos) {
45
+ if (!todo?.content || !todo?.status) {
46
+ return { content: "Error: each todo requires content and status", isError: true };
47
+ }
48
+ }
49
+ const filePath = join(ctx.cwd, ".claude", "todos.json");
50
+ try {
51
+ await mkdir(dirname(filePath), { recursive: true });
52
+ const payload = {
53
+ updatedAt: new Date().toISOString(),
54
+ todos
55
+ };
56
+ await writeFile(filePath, JSON.stringify(payload, null, 2) + `
57
+ `, "utf-8");
58
+ return {
59
+ content: `Saved ${todos.length} todo item(s) to ${filePath}`
60
+ };
61
+ } catch (err) {
62
+ const message = err instanceof Error ? err.message : String(err);
63
+ return { content: `Error writing todos: ${message}`, isError: true };
64
+ }
65
+ }
66
+ };
67
+ export {
68
+ TodoWriteTool
69
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * WebFetch tool.
3
+ */
4
+ import type { ToolImplementation } from "./registry.js";
5
+ export declare const WebFetchTool: ToolImplementation;
6
+ //# sourceMappingURL=web-fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-fetch.d.ts","sourceRoot":"","sources":["../../src/tools/web-fetch.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAc,MAAM,eAAe,CAAC;AAKpE,eAAO,MAAM,YAAY,EAAE,kBAwE1B,CAAC"}
@@ -0,0 +1,85 @@
1
+ // @bun
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true,
8
+ configurable: true,
9
+ set: (newValue) => all[name] = () => newValue
10
+ });
11
+ };
12
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
13
+ var __require = import.meta.require;
14
+
15
+ // src/tools/web-fetch.ts
16
+ var DEFAULT_TIMEOUT_MS = 20000;
17
+ var MAX_OUTPUT = 80000;
18
+ var WebFetchTool = {
19
+ name: "WebFetch",
20
+ description: "Fetches a URL and returns response text.",
21
+ inputSchema: {
22
+ type: "object",
23
+ properties: {
24
+ url: {
25
+ type: "string",
26
+ description: "The URL to fetch."
27
+ },
28
+ prompt: {
29
+ type: "string",
30
+ description: "Optional fetch intent/instructions."
31
+ },
32
+ timeout_ms: {
33
+ type: "number",
34
+ description: "Timeout in milliseconds (default 20000)."
35
+ },
36
+ max_length: {
37
+ type: "number",
38
+ description: "Maximum output length (default 80000)."
39
+ }
40
+ },
41
+ required: ["url"]
42
+ },
43
+ async execute(input) {
44
+ const { url, timeout_ms, max_length } = input ?? {};
45
+ if (!url)
46
+ return { content: "Error: url is required", isError: true };
47
+ const timeout = Math.max(1000, timeout_ms ?? DEFAULT_TIMEOUT_MS);
48
+ const outLimit = Math.max(1000, max_length ?? MAX_OUTPUT);
49
+ const controller = new AbortController;
50
+ const timer = setTimeout(() => controller.abort(), timeout);
51
+ try {
52
+ const res = await fetch(url, {
53
+ method: "GET",
54
+ signal: controller.signal,
55
+ headers: {
56
+ "user-agent": "fourmis-agent-sdk/1.0"
57
+ }
58
+ });
59
+ const contentType = res.headers.get("content-type") ?? "unknown";
60
+ let body = await res.text();
61
+ if (body.length > outLimit) {
62
+ body = body.slice(0, outLimit) + `
63
+ ... (truncated)`;
64
+ }
65
+ return {
66
+ content: [
67
+ `Status: ${res.status} ${res.statusText}`,
68
+ `Content-Type: ${contentType}`,
69
+ "",
70
+ body
71
+ ].join(`
72
+ `),
73
+ isError: res.ok ? undefined : true
74
+ };
75
+ } catch (err) {
76
+ const message = err instanceof Error ? err.message : String(err);
77
+ return { content: `Error fetching URL: ${message}`, isError: true };
78
+ } finally {
79
+ clearTimeout(timer);
80
+ }
81
+ }
82
+ };
83
+ export {
84
+ WebFetchTool
85
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * WebSearch tool.
3
+ * Uses DuckDuckGo HTML endpoint for lightweight public web search.
4
+ */
5
+ import type { ToolImplementation } from "./registry.js";
6
+ export declare const WebSearchTool: ToolImplementation;
7
+ //# sourceMappingURL=web-search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-search.d.ts","sourceRoot":"","sources":["../../src/tools/web-search.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAc,MAAM,eAAe,CAAC;AAepE,eAAO,MAAM,aAAa,EAAE,kBAiE3B,CAAC"}
@@ -0,0 +1,78 @@
1
+ // @bun
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true,
8
+ configurable: true,
9
+ set: (newValue) => all[name] = () => newValue
10
+ });
11
+ };
12
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
13
+ var __require = import.meta.require;
14
+
15
+ // src/tools/web-search.ts
16
+ var SEARCH_ENDPOINT = "https://duckduckgo.com/html/";
17
+ function stripTags(input) {
18
+ return input.replace(/<[^>]+>/g, "").replace(/&amp;/g, "&").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&lt;/g, "<").replace(/&gt;/g, ">").trim();
19
+ }
20
+ var WebSearchTool = {
21
+ name: "WebSearch",
22
+ description: "Searches the web and returns top result links.",
23
+ inputSchema: {
24
+ type: "object",
25
+ properties: {
26
+ query: {
27
+ type: "string",
28
+ description: "Search query."
29
+ },
30
+ max_results: {
31
+ type: "number",
32
+ description: "Maximum results to return (default 5)."
33
+ }
34
+ },
35
+ required: ["query"]
36
+ },
37
+ async execute(input) {
38
+ const { query, max_results } = input ?? {};
39
+ if (!query) {
40
+ return { content: "Error: query is required", isError: true };
41
+ }
42
+ const limit = Math.max(1, Math.min(20, max_results ?? 5));
43
+ try {
44
+ const url = `${SEARCH_ENDPOINT}?q=${encodeURIComponent(query)}`;
45
+ const res = await fetch(url, {
46
+ headers: {
47
+ "user-agent": "fourmis-agent-sdk/1.0"
48
+ }
49
+ });
50
+ if (!res.ok) {
51
+ return {
52
+ content: `Error searching web: ${res.status} ${res.statusText}`,
53
+ isError: true
54
+ };
55
+ }
56
+ const html = await res.text();
57
+ const matches = [...html.matchAll(/<a[^>]*class="result__a"[^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/g)];
58
+ if (matches.length === 0) {
59
+ return { content: "No search results found." };
60
+ }
61
+ const lines = [];
62
+ for (let i = 0;i < Math.min(limit, matches.length); i++) {
63
+ const href = stripTags(matches[i][1]);
64
+ const title = stripTags(matches[i][2]);
65
+ lines.push(`${i + 1}. ${title}
66
+ ${href}`);
67
+ }
68
+ return { content: lines.join(`
69
+ `) };
70
+ } catch (err) {
71
+ const message = err instanceof Error ? err.message : String(err);
72
+ return { content: `Error searching web: ${message}`, isError: true };
73
+ }
74
+ }
75
+ };
76
+ export {
77
+ WebSearchTool
78
+ };