deepagentsdk 0.11.1 → 0.13.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 (99) hide show
  1. package/dist/adapters/elements/index.cjs +274 -0
  2. package/dist/adapters/elements/index.cjs.map +1 -0
  3. package/dist/adapters/elements/index.d.cts +122 -0
  4. package/dist/adapters/elements/index.d.mts +122 -0
  5. package/dist/adapters/elements/index.mjs +268 -0
  6. package/dist/adapters/elements/index.mjs.map +1 -0
  7. package/dist/agent-BDM-PIu8.d.mts +1500 -0
  8. package/dist/agent-DToEVxs-.d.cts +1500 -0
  9. package/dist/chunk-C5azi7Hr.cjs +67 -0
  10. package/dist/cli/index.cjs +3162 -0
  11. package/dist/cli/index.cjs.map +1 -0
  12. package/dist/cli/index.d.cts +1 -0
  13. package/dist/cli/index.d.mts +1 -0
  14. package/dist/cli/index.mjs +3120 -0
  15. package/dist/cli/index.mjs.map +1 -0
  16. package/dist/file-saver-BYPKakT4.cjs +3990 -0
  17. package/dist/file-saver-BYPKakT4.cjs.map +1 -0
  18. package/dist/file-saver-Hj5so3dV.mjs +3568 -0
  19. package/dist/file-saver-Hj5so3dV.mjs.map +1 -0
  20. package/dist/index.cjs +1481 -0
  21. package/dist/index.cjs.map +1 -0
  22. package/dist/index.d.cts +1233 -0
  23. package/dist/index.d.mts +1233 -0
  24. package/dist/index.mjs +1381 -0
  25. package/dist/index.mjs.map +1 -0
  26. package/dist/load-BBYEnMwz.mjs +142 -0
  27. package/dist/load-BBYEnMwz.mjs.map +1 -0
  28. package/dist/load-BDxe6Cet.mjs +3 -0
  29. package/dist/load-BrRAKlO6.cjs +163 -0
  30. package/dist/load-BrRAKlO6.cjs.map +1 -0
  31. package/dist/load-DqllBbDc.cjs +4 -0
  32. package/package.json +26 -12
  33. package/src/adapters/elements/index.ts +0 -27
  34. package/src/adapters/elements/messageAdapter.ts +0 -165
  35. package/src/adapters/elements/statusAdapter.ts +0 -39
  36. package/src/adapters/elements/types.ts +0 -97
  37. package/src/adapters/elements/useElementsAdapter.ts +0 -261
  38. package/src/agent.ts +0 -1258
  39. package/src/backends/composite.ts +0 -273
  40. package/src/backends/filesystem.ts +0 -692
  41. package/src/backends/index.ts +0 -22
  42. package/src/backends/local-sandbox.ts +0 -175
  43. package/src/backends/persistent.ts +0 -593
  44. package/src/backends/sandbox.ts +0 -510
  45. package/src/backends/state.ts +0 -244
  46. package/src/backends/utils.ts +0 -287
  47. package/src/checkpointer/file-saver.ts +0 -98
  48. package/src/checkpointer/index.ts +0 -5
  49. package/src/checkpointer/kv-saver.ts +0 -82
  50. package/src/checkpointer/memory-saver.ts +0 -82
  51. package/src/checkpointer/types.ts +0 -125
  52. package/src/cli/components/ApiKeyInput.tsx +0 -300
  53. package/src/cli/components/FilePreview.tsx +0 -237
  54. package/src/cli/components/Input.tsx +0 -277
  55. package/src/cli/components/Message.tsx +0 -93
  56. package/src/cli/components/ModelSelection.tsx +0 -338
  57. package/src/cli/components/SlashMenu.tsx +0 -101
  58. package/src/cli/components/StatusBar.tsx +0 -89
  59. package/src/cli/components/Subagent.tsx +0 -91
  60. package/src/cli/components/TodoList.tsx +0 -133
  61. package/src/cli/components/ToolApproval.tsx +0 -70
  62. package/src/cli/components/ToolCall.tsx +0 -144
  63. package/src/cli/components/ToolCallSummary.tsx +0 -175
  64. package/src/cli/components/Welcome.tsx +0 -75
  65. package/src/cli/components/index.ts +0 -24
  66. package/src/cli/hooks/index.ts +0 -12
  67. package/src/cli/hooks/useAgent.ts +0 -933
  68. package/src/cli/index.tsx +0 -1066
  69. package/src/cli/theme.ts +0 -205
  70. package/src/cli/utils/model-list.ts +0 -365
  71. package/src/constants/errors.ts +0 -29
  72. package/src/constants/limits.ts +0 -195
  73. package/src/index.ts +0 -176
  74. package/src/middleware/agent-memory.ts +0 -330
  75. package/src/prompts.ts +0 -196
  76. package/src/skills/index.ts +0 -2
  77. package/src/skills/load.ts +0 -191
  78. package/src/skills/types.ts +0 -53
  79. package/src/tools/execute.ts +0 -167
  80. package/src/tools/filesystem.ts +0 -418
  81. package/src/tools/index.ts +0 -39
  82. package/src/tools/subagent.ts +0 -443
  83. package/src/tools/todos.ts +0 -101
  84. package/src/tools/web.ts +0 -567
  85. package/src/types/backend.ts +0 -177
  86. package/src/types/core.ts +0 -220
  87. package/src/types/events.ts +0 -430
  88. package/src/types/index.ts +0 -94
  89. package/src/types/structured-output.ts +0 -43
  90. package/src/types/subagent.ts +0 -96
  91. package/src/types.ts +0 -22
  92. package/src/utils/approval.ts +0 -213
  93. package/src/utils/events.ts +0 -416
  94. package/src/utils/eviction.ts +0 -181
  95. package/src/utils/index.ts +0 -34
  96. package/src/utils/model-parser.ts +0 -38
  97. package/src/utils/patch-tool-calls.ts +0 -233
  98. package/src/utils/project-detection.ts +0 -32
  99. package/src/utils/summarization.ts +0 -254
@@ -0,0 +1,3990 @@
1
+ const require_chunk = require('./chunk-C5azi7Hr.cjs');
2
+ let ai = require("ai");
3
+ let zod = require("zod");
4
+ let micromatch = require("micromatch");
5
+ micromatch = require_chunk.__toESM(micromatch);
6
+ let path = require("path");
7
+ let _tavily_core = require("@tavily/core");
8
+ let turndown = require("turndown");
9
+ turndown = require_chunk.__toESM(turndown);
10
+ let _mozilla_readability = require("@mozilla/readability");
11
+ let jsdom = require("jsdom");
12
+ let child_process = require("child_process");
13
+ let _ai_sdk_anthropic = require("@ai-sdk/anthropic");
14
+ let _ai_sdk_openai = require("@ai-sdk/openai");
15
+ let node_fs = require("node:fs");
16
+ let node_path = require("node:path");
17
+
18
+ //#region src/constants/limits.ts
19
+ var DEFAULT_EVICTION_TOKEN_LIMIT$1, DEFAULT_SUMMARIZATION_THRESHOLD$1, CONTEXT_WINDOW, DEFAULT_KEEP_MESSAGES$1, DEFAULT_MAX_STEPS, DEFAULT_SUBAGENT_MAX_STEPS, DEFAULT_READ_LIMIT, MAX_LINE_LENGTH, MAX_FILE_SIZE_MB, DEFAULT_TIMEOUT_SECONDS, DEFAULT_TIMEOUT_MS, LINE_NUMBER_WIDTH;
20
+ var init_limits = require_chunk.__esmMin((() => {
21
+ DEFAULT_EVICTION_TOKEN_LIMIT$1 = 2e4;
22
+ DEFAULT_SUMMARIZATION_THRESHOLD$1 = 17e4;
23
+ CONTEXT_WINDOW = 2e5;
24
+ DEFAULT_KEEP_MESSAGES$1 = 6;
25
+ DEFAULT_MAX_STEPS = 100;
26
+ DEFAULT_SUBAGENT_MAX_STEPS = 50;
27
+ DEFAULT_READ_LIMIT = 2e3;
28
+ MAX_LINE_LENGTH = 1e4;
29
+ MAX_FILE_SIZE_MB = 10;
30
+ DEFAULT_TIMEOUT_SECONDS = 30;
31
+ DEFAULT_TIMEOUT_MS = DEFAULT_TIMEOUT_SECONDS * 1e3;
32
+ LINE_NUMBER_WIDTH = 6;
33
+ }));
34
+
35
+ //#endregion
36
+ //#region src/utils/events.ts
37
+ /**
38
+ * Create a todos-changed event.
39
+ */
40
+ function createTodosChangedEvent(todos) {
41
+ return {
42
+ type: "todos-changed",
43
+ todos
44
+ };
45
+ }
46
+ /**
47
+ * Create a file-write-start event (preview before write).
48
+ */
49
+ function createFileWriteStartEvent(path$1, content) {
50
+ return {
51
+ type: "file-write-start",
52
+ path: path$1,
53
+ content
54
+ };
55
+ }
56
+ /**
57
+ * Create a file-written event (after successful write).
58
+ */
59
+ function createFileWrittenEvent(path$1, content) {
60
+ return {
61
+ type: "file-written",
62
+ path: path$1,
63
+ content
64
+ };
65
+ }
66
+ /**
67
+ * Create a file-edited event.
68
+ */
69
+ function createFileEditedEvent(path$1, occurrences) {
70
+ return {
71
+ type: "file-edited",
72
+ path: path$1,
73
+ occurrences
74
+ };
75
+ }
76
+ /**
77
+ * Create a file-read event.
78
+ */
79
+ function createFileReadEvent(path$1, lines) {
80
+ return {
81
+ type: "file-read",
82
+ path: path$1,
83
+ lines
84
+ };
85
+ }
86
+ /**
87
+ * Create a web-search-start event.
88
+ */
89
+ function createWebSearchStartEvent(query) {
90
+ return {
91
+ type: "web-search-start",
92
+ query
93
+ };
94
+ }
95
+ /**
96
+ * Create a web-search-finish event.
97
+ */
98
+ function createWebSearchFinishEvent(query, resultCount) {
99
+ return {
100
+ type: "web-search-finish",
101
+ query,
102
+ resultCount
103
+ };
104
+ }
105
+ /**
106
+ * Create an http-request-start event.
107
+ */
108
+ function createHttpRequestStartEvent(url, method) {
109
+ return {
110
+ type: "http-request-start",
111
+ url,
112
+ method
113
+ };
114
+ }
115
+ /**
116
+ * Create an http-request-finish event.
117
+ */
118
+ function createHttpRequestFinishEvent(url, statusCode) {
119
+ return {
120
+ type: "http-request-finish",
121
+ url,
122
+ statusCode
123
+ };
124
+ }
125
+ /**
126
+ * Create a fetch-url-start event.
127
+ */
128
+ function createFetchUrlStartEvent(url) {
129
+ return {
130
+ type: "fetch-url-start",
131
+ url
132
+ };
133
+ }
134
+ /**
135
+ * Create a fetch-url-finish event.
136
+ */
137
+ function createFetchUrlFinishEvent(url, success) {
138
+ return {
139
+ type: "fetch-url-finish",
140
+ url,
141
+ success
142
+ };
143
+ }
144
+ /**
145
+ * Create a subagent-start event.
146
+ */
147
+ function createSubagentStartEvent(name, task) {
148
+ return {
149
+ type: "subagent-start",
150
+ name,
151
+ task
152
+ };
153
+ }
154
+ /**
155
+ * Create a subagent-finish event.
156
+ */
157
+ function createSubagentFinishEvent(name, result) {
158
+ return {
159
+ type: "subagent-finish",
160
+ name,
161
+ result
162
+ };
163
+ }
164
+ /**
165
+ * Create a subagent-step event.
166
+ */
167
+ function createSubagentStepEvent(stepIndex, toolCalls) {
168
+ return {
169
+ type: "subagent-step",
170
+ stepIndex,
171
+ toolCalls
172
+ };
173
+ }
174
+ /**
175
+ * Create a checkpoint-saved event.
176
+ */
177
+ function createCheckpointSavedEvent(threadId, step) {
178
+ return {
179
+ type: "checkpoint-saved",
180
+ threadId,
181
+ step
182
+ };
183
+ }
184
+ /**
185
+ * Create a checkpoint-loaded event.
186
+ */
187
+ function createCheckpointLoadedEvent(threadId, step, messagesCount) {
188
+ return {
189
+ type: "checkpoint-loaded",
190
+ threadId,
191
+ step,
192
+ messagesCount
193
+ };
194
+ }
195
+ var init_events = require_chunk.__esmMin((() => {}));
196
+
197
+ //#endregion
198
+ //#region src/types/backend.ts
199
+ /**
200
+ * Type guard to check if a backend is a SandboxBackendProtocol.
201
+ */
202
+ function isSandboxBackend(backend) {
203
+ return typeof backend.execute === "function" && typeof backend.id === "string";
204
+ }
205
+
206
+ //#endregion
207
+ //#region src/prompts.ts
208
+ /**
209
+ * System prompts for Deep Agent.
210
+ */
211
+ const BASE_PROMPT = `In order to complete the objective that the user asks of you, you have access to a number of standard tools.`;
212
+ const TODO_SYSTEM_PROMPT = `## \`write_todos\` (task planning)
213
+
214
+ You have access to a \`write_todos\` tool to help you manage and plan tasks. Use this tool whenever you are working on a complex task.
215
+
216
+ ### When to Use This Tool
217
+
218
+ Use proactively for:
219
+ 1. Complex multi-step tasks (3+ distinct steps)
220
+ 2. Non-trivial tasks requiring careful planning
221
+ 3. After receiving new instructions - capture requirements as todos
222
+ 4. After completing tasks - mark complete and add follow-ups
223
+ 5. When starting new tasks - mark as in_progress (ideally only one at a time)
224
+
225
+ ### When NOT to Use
226
+
227
+ Skip for:
228
+ 1. Single, straightforward tasks
229
+ 2. Trivial tasks with no organizational benefit
230
+ 3. Tasks completable in < 3 trivial steps
231
+ 4. Purely conversational/informational requests
232
+
233
+ ### Task States and Management
234
+
235
+ 1. **Task States:**
236
+ - pending: Not yet started
237
+ - in_progress: Currently working on
238
+ - completed: Finished successfully
239
+ - cancelled: No longer needed
240
+
241
+ 2. **Task Management:**
242
+ - Update status in real-time
243
+ - Mark complete IMMEDIATELY after finishing
244
+ - Only ONE task in_progress at a time
245
+ - Complete current tasks before starting new ones`;
246
+ const FILESYSTEM_SYSTEM_PROMPT = `## Virtual Filesystem
247
+
248
+ You have access to a virtual filesystem. All file paths must start with a /.
249
+
250
+ - ls: list files in a directory (requires absolute path)
251
+ - read_file: read a file from the filesystem
252
+ - write_file: write to a file in the filesystem
253
+ - edit_file: edit a file in the filesystem
254
+ - glob: find files matching a pattern (e.g., "**/*.py")
255
+ - grep: search for text within files`;
256
+ const TASK_SYSTEM_PROMPT = `## \`task\` (subagent spawner)
257
+
258
+ You have access to a \`task\` tool to launch short-lived subagents that handle isolated tasks. These agents are ephemeral — they live only for the duration of the task and return a single result.
259
+
260
+ When to use the task tool:
261
+ - When a task is complex and multi-step, and can be fully delegated in isolation
262
+ - When a task is independent of other tasks and can run in parallel
263
+ - When a task requires focused reasoning or heavy token/context usage that would bloat the orchestrator thread
264
+ - When sandboxing improves reliability (e.g. code execution, structured searches, data formatting)
265
+ - When you only care about the output of the subagent, and not the intermediate steps
266
+
267
+ Subagent lifecycle:
268
+ 1. **Spawn** → Provide clear role, instructions, and expected output
269
+ 2. **Run** → The subagent completes the task autonomously
270
+ 3. **Return** → The subagent provides a single structured result
271
+ 4. **Reconcile** → Incorporate or synthesize the result into the main thread
272
+
273
+ When NOT to use the task tool:
274
+ - If you need to see the intermediate reasoning or steps after the subagent has completed (the task tool hides them)
275
+ - If the task is trivial (a few tool calls or simple lookup)
276
+ - If delegating does not reduce token usage, complexity, or context switching
277
+ - If splitting would add latency without benefit
278
+
279
+ ## Important Task Tool Usage Notes
280
+ - Whenever possible, parallelize the work that you do. Whenever you have independent steps to complete - kick off tasks (subagents) in parallel to accomplish them faster.
281
+ - Remember to use the \`task\` tool to silo independent tasks within a multi-part objective.
282
+ - You should use the \`task\` tool whenever you have a complex task that will take multiple steps, and is independent from other tasks that the agent needs to complete.`;
283
+ /**
284
+ * Get the task tool description with available subagent types.
285
+ */
286
+ function getTaskToolDescription(subagentDescriptions) {
287
+ return `
288
+ Launch an ephemeral subagent to handle complex, multi-step independent tasks with isolated context windows.
289
+
290
+ Available agent types and the tools they have access to:
291
+ ${subagentDescriptions.join("\n")}
292
+
293
+ When using the Task tool, you must specify a subagent_type parameter to select which agent type to use.
294
+
295
+ ## Usage notes:
296
+ 1. Launch multiple agents concurrently whenever possible, to maximize performance; to do that, use a single message with multiple tool uses
297
+ 2. When the agent is done, it will return a single message back to you. The result returned by the agent is not visible to the user. To show the user the result, you should send a text message back to the user with a concise summary of the result.
298
+ 3. Each agent invocation is stateless. You will not be able to send additional messages to the agent, nor will the agent be able to communicate with you outside of its final report. Therefore, your prompt should contain a highly detailed task description for the agent to perform autonomously and you should specify exactly what information the agent should return back to you in its final and only message to you.
299
+ 4. The agent's outputs should generally be trusted
300
+ 5. Clearly tell the agent whether you expect it to create content, perform analysis, or just do research (search, file reads, web fetches, etc.), since it is not aware of the user's intent
301
+ 6. If the agent description mentions that it should be used proactively, then you should try your best to use it without the user having to ask for it first. Use your judgement.
302
+ 7. When only the general-purpose agent is provided, you should use it for all tasks. It is great for isolating context and token usage, and completing specific, complex tasks, as it has all the same capabilities as the main agent.
303
+
304
+ ### Example usage of the general-purpose agent:
305
+
306
+ <example_agent_descriptions>
307
+ "general-purpose": use this agent for general purpose tasks, it has access to all tools as the main agent.
308
+ </example_agent_descriptions>
309
+
310
+ <example>
311
+ User: "I want to conduct research on the accomplishments of Lebron James, Michael Jordan, and Kobe Bryant, and then compare them."
312
+ Assistant: *Uses the task tool in parallel to conduct isolated research on each of the three players*
313
+ Assistant: *Synthesizes the results of the three isolated research tasks and responds to the User*
314
+ <commentary>
315
+ Research is a complex, multi-step task in it of itself.
316
+ The research of each individual player is not dependent on the research of the other players.
317
+ The assistant uses the task tool to break down the complex objective into three isolated tasks.
318
+ Each research task only needs to worry about context and tokens about one player, then returns synthesized information about each player as the Tool Result.
319
+ This means each research task can dive deep and spend tokens and context deeply researching each player, but the final result is synthesized information, and saves us tokens in the long run when comparing the players to each other.
320
+ </commentary>
321
+ </example>
322
+
323
+ <example>
324
+ User: "Analyze a single large code repository for security vulnerabilities and generate a report."
325
+ Assistant: *Launches a single \`task\` subagent for the repository analysis*
326
+ Assistant: *Receives report and integrates results into final summary*
327
+ <commentary>
328
+ Subagent is used to isolate a large, context-heavy task, even though there is only one. This prevents the main thread from being overloaded with details.
329
+ If the user then asks followup questions, we have a concise report to reference instead of the entire history of analysis and tool calls, which is good and saves us time and money.
330
+ </commentary>
331
+ </example>
332
+ `.trim();
333
+ }
334
+ const DEFAULT_GENERAL_PURPOSE_DESCRIPTION = "General-purpose agent for researching complex questions, searching for files and content, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries use this agent to perform the search for you. This agent has access to all tools as the main agent.";
335
+ const DEFAULT_SUBAGENT_PROMPT = "In order to complete the objective that the user asks of you, you have access to a number of standard tools.";
336
+ const EXECUTE_SYSTEM_PROMPT = `## \`execute\` (shell command execution)
337
+
338
+ You have access to an \`execute\` tool to run shell commands in the sandbox environment.
339
+
340
+ ### When to Use This Tool
341
+
342
+ Use for:
343
+ - Running build commands (npm install, npm run build, bun install)
344
+ - Running tests (npm test, bun test, pytest)
345
+ - Executing scripts (node script.js, python script.py)
346
+ - Installing dependencies
347
+ - Checking system state (ls, cat, pwd, which)
348
+ - Any shell command that helps accomplish the task
349
+
350
+ ### Important Notes
351
+
352
+ 1. **Exit Codes**: Always check the exit code to determine success
353
+ - 0 = success
354
+ - non-zero = failure
355
+ - null = possibly timed out
356
+
357
+ 2. **Command Chaining**:
358
+ - Use \`&&\` to chain commands that depend on each other
359
+ - Use \`;\` to run commands sequentially regardless of success
360
+
361
+ 3. **Timeouts**: Long-running commands may timeout
362
+
363
+ 4. **Working Directory**: Commands run in the sandbox's working directory`;
364
+ /**
365
+ * Build skills section for system prompt with progressive disclosure.
366
+ */
367
+ function buildSkillsPrompt(skills) {
368
+ if (skills.length === 0) return "";
369
+ return `## Skills System
370
+
371
+ You have access to a skills library providing specialized domain knowledge and workflows.
372
+
373
+ **Available Skills:**
374
+
375
+ ${skills.map((skill) => `- **${skill.name}**: ${skill.description}\n → Read \`${skill.path}\` for full instructions`).join("\n")}
376
+
377
+ **How to Use Skills (Progressive Disclosure):**
378
+
379
+ 1. **Recognize when a skill applies**: Check if the user's task matches any skill's domain
380
+ 2. **Read the skill's full instructions**: Use read_file to load the SKILL.md content
381
+ 3. **Follow the skill's workflow**: Skills contain step-by-step instructions and examples
382
+ 4. **Access supporting files**: Skills may include helper scripts or configuration files in their directory
383
+
384
+ Skills provide expert knowledge for specialized tasks. Always read the full skill before using it.`;
385
+ }
386
+
387
+ //#endregion
388
+ //#region src/tools/todos.ts
389
+ /**
390
+ * Todo list tool for task planning and tracking.
391
+ */
392
+ init_events();
393
+ const TodoItemSchema = zod.z.object({
394
+ id: zod.z.string().describe("Unique identifier for the todo item"),
395
+ content: zod.z.string().max(100).describe("The description/content of the todo item (max 100 chars)"),
396
+ status: zod.z.enum([
397
+ "pending",
398
+ "in_progress",
399
+ "completed",
400
+ "cancelled"
401
+ ]).describe("The current status of the todo item")
402
+ });
403
+ /**
404
+ * Create the write_todos tool for task planning.
405
+ * @param state - The shared agent state
406
+ * @param onEvent - Optional callback for emitting events
407
+ */
408
+ function createTodosTool(state, onEvent) {
409
+ return (0, ai.tool)({
410
+ description: `Manage and plan tasks using a structured todo list. Use this tool for:
411
+ - Complex multi-step tasks (3+ steps)
412
+ - After receiving new instructions - capture requirements
413
+ - When starting tasks - mark as in_progress (only one at a time)
414
+ - After completing tasks - mark complete immediately
415
+
416
+ Task states: pending, in_progress, completed, cancelled
417
+
418
+ When merge=true, updates are merged with existing todos by id.
419
+ When merge=false, the new todos replace all existing todos.`,
420
+ inputSchema: zod.z.object({
421
+ todos: zod.z.array(TodoItemSchema).min(1).describe("Array of todo items to write"),
422
+ merge: zod.z.boolean().default(true).describe("Whether to merge with existing todos (true) or replace all (false)")
423
+ }),
424
+ execute: async ({ todos, merge }) => {
425
+ if (merge) {
426
+ const existingMap = /* @__PURE__ */ new Map();
427
+ for (const todo of state.todos) existingMap.set(todo.id, todo);
428
+ for (const newTodo of todos) {
429
+ const existing = existingMap.get(newTodo.id);
430
+ if (existing) existingMap.set(newTodo.id, {
431
+ ...existing,
432
+ ...newTodo
433
+ });
434
+ else existingMap.set(newTodo.id, newTodo);
435
+ }
436
+ state.todos = Array.from(existingMap.values());
437
+ } else state.todos = todos;
438
+ if (onEvent) onEvent(createTodosChangedEvent([...state.todos]));
439
+ return `Todo list updated successfully.\n\nCurrent todos:\n${state.todos.map((t) => `- [${t.status}] ${t.id}: ${t.content}`).join("\n")}`;
440
+ }
441
+ });
442
+ }
443
+ /**
444
+ * Individual builtin tool reference for selective subagent configuration.
445
+ * This is a reference to the creator function, not an instance.
446
+ */
447
+ const write_todos = createTodosTool;
448
+
449
+ //#endregion
450
+ //#region src/constants/errors.ts
451
+ var FILE_NOT_FOUND, FILE_ALREADY_EXISTS, STRING_NOT_FOUND, INVALID_REGEX, WEB_SEARCH_ERROR, REQUEST_TIMEOUT, SYSTEM_REMINDER_FILE_EMPTY;
452
+ var init_errors = require_chunk.__esmMin((() => {
453
+ FILE_NOT_FOUND = (path$1) => `Error: File '${path$1}' not found`;
454
+ FILE_ALREADY_EXISTS = (path$1) => `Cannot write to ${path$1} because it already exists. Read and then make an edit, or write to a new path.`;
455
+ STRING_NOT_FOUND = (path$1, string) => `Error: String not found in file: '${path$1}'\n\n${string}`;
456
+ INVALID_REGEX = (message) => `Invalid regex pattern: ${message}`;
457
+ WEB_SEARCH_ERROR = (message) => `Web search error: ${message}`;
458
+ REQUEST_TIMEOUT = (timeout) => `Request timed out after ${timeout} seconds`;
459
+ SYSTEM_REMINDER_FILE_EMPTY = "System reminder: File exists but has empty contents";
460
+ }));
461
+
462
+ //#endregion
463
+ //#region src/backends/utils.ts
464
+ /**
465
+ * Shared utility functions for memory backend implementations.
466
+ */
467
+ init_errors();
468
+ init_limits();
469
+ const EMPTY_CONTENT_WARNING = SYSTEM_REMINDER_FILE_EMPTY;
470
+ /**
471
+ * Format file content with line numbers (cat -n style).
472
+ */
473
+ function formatContentWithLineNumbers(content, startLine = 1) {
474
+ let lines;
475
+ if (typeof content === "string") {
476
+ lines = content.split("\n");
477
+ if (lines.length > 0 && lines[lines.length - 1] === "") lines = lines.slice(0, -1);
478
+ } else lines = content;
479
+ const resultLines = [];
480
+ for (let i = 0; i < lines.length; i++) {
481
+ const line = lines[i];
482
+ const lineNum = i + startLine;
483
+ if (line && line.length <= MAX_LINE_LENGTH) resultLines.push(`${lineNum.toString().padStart(LINE_NUMBER_WIDTH)}\t${line}`);
484
+ else if (line) {
485
+ const numChunks = Math.ceil(line.length / MAX_LINE_LENGTH);
486
+ for (let chunkIdx = 0; chunkIdx < numChunks; chunkIdx++) {
487
+ const start = chunkIdx * MAX_LINE_LENGTH;
488
+ const end = Math.min(start + MAX_LINE_LENGTH, line.length);
489
+ const chunk = line.substring(start, end);
490
+ if (chunkIdx === 0) resultLines.push(`${lineNum.toString().padStart(LINE_NUMBER_WIDTH)}\t${chunk}`);
491
+ else {
492
+ const continuationMarker = `${lineNum}.${chunkIdx}`;
493
+ resultLines.push(`${continuationMarker.padStart(LINE_NUMBER_WIDTH)}\t${chunk}`);
494
+ }
495
+ }
496
+ } else resultLines.push(`${lineNum.toString().padStart(LINE_NUMBER_WIDTH)}\t`);
497
+ }
498
+ return resultLines.join("\n");
499
+ }
500
+ /**
501
+ * Check if content is empty and return warning message.
502
+ */
503
+ function checkEmptyContent(content) {
504
+ if (!content || content.trim() === "") return EMPTY_CONTENT_WARNING;
505
+ return null;
506
+ }
507
+ /**
508
+ * Convert FileData to plain string content.
509
+ */
510
+ function fileDataToString(fileData) {
511
+ return fileData.content.join("\n");
512
+ }
513
+ /**
514
+ * Create a FileData object with timestamps.
515
+ */
516
+ function createFileData(content, createdAt) {
517
+ const lines = typeof content === "string" ? content.split("\n") : content;
518
+ const now = (/* @__PURE__ */ new Date()).toISOString();
519
+ return {
520
+ content: lines,
521
+ created_at: createdAt || now,
522
+ modified_at: now
523
+ };
524
+ }
525
+ /**
526
+ * Update FileData with new content, preserving creation timestamp.
527
+ */
528
+ function updateFileData(fileData, content) {
529
+ const lines = typeof content === "string" ? content.split("\n") : content;
530
+ const now = (/* @__PURE__ */ new Date()).toISOString();
531
+ return {
532
+ content: lines,
533
+ created_at: fileData.created_at,
534
+ modified_at: now
535
+ };
536
+ }
537
+ /**
538
+ * Format file data for read response with line numbers.
539
+ */
540
+ function formatReadResponse(fileData, offset, limit) {
541
+ const content = fileDataToString(fileData);
542
+ const emptyMsg = checkEmptyContent(content);
543
+ if (emptyMsg) return emptyMsg;
544
+ const lines = content.split("\n");
545
+ const startIdx = offset;
546
+ const endIdx = Math.min(startIdx + limit, lines.length);
547
+ if (startIdx >= lines.length) return `Error: Line offset ${offset} exceeds file length (${lines.length} lines)`;
548
+ return formatContentWithLineNumbers(lines.slice(startIdx, endIdx), startIdx + 1);
549
+ }
550
+ /**
551
+ * Perform string replacement with occurrence validation.
552
+ */
553
+ function performStringReplacement(content, oldString, newString, replaceAll) {
554
+ const occurrences = content.split(oldString).length - 1;
555
+ if (occurrences === 0) return `Error: String not found in file: '${oldString}'`;
556
+ if (occurrences > 1 && !replaceAll) return `Error: String '${oldString}' appears ${occurrences} times in file. Use replace_all=true to replace all instances, or provide a more specific string with surrounding context.`;
557
+ return [content.split(oldString).join(newString), occurrences];
558
+ }
559
+ /**
560
+ * Validate and normalize a path.
561
+ */
562
+ function validatePath(path$1) {
563
+ const pathStr = path$1 || "/";
564
+ if (!pathStr || pathStr.trim() === "") throw new Error("Path cannot be empty");
565
+ let normalized = pathStr.startsWith("/") ? pathStr : "/" + pathStr;
566
+ if (!normalized.endsWith("/")) normalized += "/";
567
+ return normalized;
568
+ }
569
+ /**
570
+ * Search files dict for paths matching glob pattern.
571
+ */
572
+ function globSearchFiles(files, pattern, path$1 = "/") {
573
+ let normalizedPath;
574
+ try {
575
+ normalizedPath = validatePath(path$1);
576
+ } catch {
577
+ return "No files found";
578
+ }
579
+ const filtered = Object.fromEntries(Object.entries(files).filter(([fp]) => fp.startsWith(normalizedPath)));
580
+ const matches = [];
581
+ for (const [filePath, fileData] of Object.entries(filtered)) {
582
+ let relative = filePath.substring(normalizedPath.length);
583
+ if (relative.startsWith("/")) relative = relative.substring(1);
584
+ if (!relative) {
585
+ const parts = filePath.split("/");
586
+ relative = parts[parts.length - 1] || "";
587
+ }
588
+ if (micromatch.default.isMatch(relative, pattern, {
589
+ dot: true,
590
+ nobrace: false
591
+ })) matches.push([filePath, fileData.modified_at]);
592
+ }
593
+ matches.sort((a, b) => b[1].localeCompare(a[1]));
594
+ if (matches.length === 0) return "No files found";
595
+ return matches.map(([fp]) => fp).join("\n");
596
+ }
597
+ /**
598
+ * Return structured grep matches from an in-memory files mapping.
599
+ */
600
+ function grepMatchesFromFiles(files, pattern, path$1 = null, glob$1 = null) {
601
+ let regex;
602
+ try {
603
+ regex = new RegExp(pattern);
604
+ } catch (e) {
605
+ return INVALID_REGEX(e.message);
606
+ }
607
+ let normalizedPath;
608
+ try {
609
+ normalizedPath = validatePath(path$1);
610
+ } catch {
611
+ return [];
612
+ }
613
+ let filtered = Object.fromEntries(Object.entries(files).filter(([fp]) => fp.startsWith(normalizedPath)));
614
+ if (glob$1) filtered = Object.fromEntries(Object.entries(filtered).filter(([fp]) => micromatch.default.isMatch((0, path.basename)(fp), glob$1, {
615
+ dot: true,
616
+ nobrace: false
617
+ })));
618
+ const matches = [];
619
+ for (const [filePath, fileData] of Object.entries(filtered)) for (let i = 0; i < fileData.content.length; i++) {
620
+ const line = fileData.content[i];
621
+ const lineNum = i + 1;
622
+ if (line && regex.test(line)) matches.push({
623
+ path: filePath,
624
+ line: lineNum,
625
+ text: line
626
+ });
627
+ }
628
+ return matches;
629
+ }
630
+
631
+ //#endregion
632
+ //#region src/backends/state.ts
633
+ init_errors();
634
+ /**
635
+ * Backend that stores files in shared state (ephemeral).
636
+ *
637
+ * Files persist within a single agent invocation but not across invocations.
638
+ * This is the default backend for Deep Agent when no backend is specified.
639
+ *
640
+ * Files are stored in memory as part of the `DeepAgentState`, making this backend
641
+ * fast but non-persistent. Use `FilesystemBackend` or `PersistentBackend` for
642
+ * cross-session persistence.
643
+ *
644
+ * @example Default usage (no backend specified)
645
+ * ```typescript
646
+ * const agent = createDeepAgent({
647
+ * model: anthropic('claude-sonnet-4-20250514'),
648
+ * // StateBackend is used by default
649
+ * });
650
+ * ```
651
+ *
652
+ * @example Explicit usage
653
+ * ```typescript
654
+ * const state: DeepAgentState = { todos: [], files: {} };
655
+ * const backend = new StateBackend(state);
656
+ * const agent = createDeepAgent({
657
+ * model: anthropic('claude-sonnet-4-20250514'),
658
+ * backend,
659
+ * });
660
+ * ```
661
+ */
662
+ var StateBackend = class {
663
+ state;
664
+ /**
665
+ * Create a new StateBackend instance.
666
+ *
667
+ * @param state - The DeepAgentState object that will store the files.
668
+ * Files are stored in `state.files` as a Record<string, FileData>.
669
+ */
670
+ constructor(state) {
671
+ this.state = state;
672
+ }
673
+ /**
674
+ * Get files from current state.
675
+ */
676
+ getFiles() {
677
+ return this.state.files || {};
678
+ }
679
+ /**
680
+ * List files and directories in the specified directory (non-recursive).
681
+ */
682
+ lsInfo(path$1) {
683
+ const files = this.getFiles();
684
+ const infos = [];
685
+ const subdirs = /* @__PURE__ */ new Set();
686
+ const normalizedPath = path$1.endsWith("/") ? path$1 : path$1 + "/";
687
+ for (const [k, fd] of Object.entries(files)) {
688
+ if (!k.startsWith(normalizedPath)) continue;
689
+ const relative = k.substring(normalizedPath.length);
690
+ if (relative.includes("/")) {
691
+ const subdirName = relative.split("/")[0];
692
+ subdirs.add(normalizedPath + subdirName + "/");
693
+ continue;
694
+ }
695
+ const size = fd.content.join("\n").length;
696
+ infos.push({
697
+ path: k,
698
+ is_dir: false,
699
+ size,
700
+ modified_at: fd.modified_at
701
+ });
702
+ }
703
+ for (const subdir of Array.from(subdirs).sort()) infos.push({
704
+ path: subdir,
705
+ is_dir: true,
706
+ size: 0,
707
+ modified_at: ""
708
+ });
709
+ infos.sort((a, b) => a.path.localeCompare(b.path));
710
+ return infos;
711
+ }
712
+ /**
713
+ * Read file content with line numbers.
714
+ */
715
+ read(filePath, offset = 0, limit = 2e3) {
716
+ const fileData = this.getFiles()[filePath];
717
+ if (!fileData) return FILE_NOT_FOUND(filePath);
718
+ return formatReadResponse(fileData, offset, limit);
719
+ }
720
+ /**
721
+ * Read file content as raw FileData.
722
+ */
723
+ readRaw(filePath) {
724
+ const fileData = this.getFiles()[filePath];
725
+ if (!fileData) throw new Error(`File '${filePath}' not found`);
726
+ return fileData;
727
+ }
728
+ /**
729
+ * Create a new file with content.
730
+ */
731
+ write(filePath, content) {
732
+ const files = this.getFiles();
733
+ if (!filePath || filePath.trim() === "") return {
734
+ success: false,
735
+ error: "File path cannot be empty"
736
+ };
737
+ if (filePath in files) return {
738
+ success: false,
739
+ error: FILE_ALREADY_EXISTS(filePath)
740
+ };
741
+ const newFileData = createFileData(content);
742
+ this.state.files[filePath] = newFileData;
743
+ return {
744
+ success: true,
745
+ path: filePath
746
+ };
747
+ }
748
+ /**
749
+ * Edit a file by replacing string occurrences.
750
+ */
751
+ edit(filePath, oldString, newString, replaceAll = false) {
752
+ const fileData = this.getFiles()[filePath];
753
+ if (!fileData) return {
754
+ success: false,
755
+ error: FILE_NOT_FOUND(filePath)
756
+ };
757
+ const result = performStringReplacement(fileDataToString(fileData), oldString, newString, replaceAll);
758
+ if (typeof result === "string") return {
759
+ success: false,
760
+ error: result
761
+ };
762
+ const [newContent, occurrences] = result;
763
+ const newFileData = updateFileData(fileData, newContent);
764
+ this.state.files[filePath] = newFileData;
765
+ return {
766
+ success: true,
767
+ path: filePath,
768
+ occurrences
769
+ };
770
+ }
771
+ /**
772
+ * Structured search results or error string for invalid input.
773
+ */
774
+ grepRaw(pattern, path$1 = "/", glob$1 = null) {
775
+ return grepMatchesFromFiles(this.getFiles(), pattern, path$1, glob$1);
776
+ }
777
+ /**
778
+ * Structured glob matching returning FileInfo objects.
779
+ */
780
+ globInfo(pattern, path$1 = "/") {
781
+ const files = this.getFiles();
782
+ const result = globSearchFiles(files, pattern, path$1);
783
+ if (result === "No files found") return [];
784
+ const paths = result.split("\n");
785
+ const infos = [];
786
+ for (const p of paths) {
787
+ const fd = files[p];
788
+ const size = fd ? fd.content.join("\n").length : 0;
789
+ infos.push({
790
+ path: p,
791
+ is_dir: false,
792
+ size,
793
+ modified_at: fd?.modified_at || ""
794
+ });
795
+ }
796
+ return infos;
797
+ }
798
+ };
799
+
800
+ //#endregion
801
+ //#region src/utils/eviction.ts
802
+ /**
803
+ * Sanitize a tool call ID for use as a filename.
804
+ * Removes or replaces characters that are invalid in file paths.
805
+ */
806
+ function sanitizeToolCallId(toolCallId) {
807
+ return toolCallId.replace(/[^a-zA-Z0-9_-]/g, "_").substring(0, 100);
808
+ }
809
+ /**
810
+ * Estimate the number of tokens in a string.
811
+ * Uses a simple character-based approximation.
812
+ */
813
+ function estimateTokens(text) {
814
+ return Math.ceil(text.length / CHARS_PER_TOKEN);
815
+ }
816
+ /**
817
+ * Check if a tool result should be evicted based on size.
818
+ */
819
+ function shouldEvict(result, tokenLimit = DEFAULT_EVICTION_TOKEN_LIMIT) {
820
+ return estimateTokens(result) > tokenLimit;
821
+ }
822
+ /**
823
+ * Evict a large tool result to the filesystem.
824
+ *
825
+ * If the result exceeds the token limit, writes it to a file and
826
+ * returns a truncated message with the file path.
827
+ *
828
+ * @param options - Eviction options
829
+ * @returns Eviction result with content and metadata
830
+ *
831
+ * @example
832
+ * ```typescript
833
+ * const result = await evictToolResult({
834
+ * result: veryLongString,
835
+ * toolCallId: "call_123",
836
+ * toolName: "grep",
837
+ * backend: filesystemBackend,
838
+ * });
839
+ *
840
+ * if (result.evicted) {
841
+ * console.log(`Content saved to ${result.evictedPath}`);
842
+ * }
843
+ * ```
844
+ */
845
+ async function evictToolResult(options) {
846
+ const { result, toolCallId, toolName, backend, tokenLimit = DEFAULT_EVICTION_TOKEN_LIMIT } = options;
847
+ if (!shouldEvict(result, tokenLimit)) return {
848
+ evicted: false,
849
+ content: result
850
+ };
851
+ const evictPath = `/large_tool_results/${toolName}_${sanitizeToolCallId(toolCallId)}.txt`;
852
+ const writeResult = await backend.write(evictPath, result);
853
+ if (writeResult.error) {
854
+ console.warn(`Failed to evict tool result: ${writeResult.error}`);
855
+ return {
856
+ evicted: false,
857
+ content: result
858
+ };
859
+ }
860
+ return {
861
+ evicted: true,
862
+ content: `Tool result too large (~${estimateTokens(result)} tokens). Content saved to ${evictPath}. Use read_file to access the full content.`,
863
+ evictedPath: evictPath
864
+ };
865
+ }
866
+ /**
867
+ * Create a tool result wrapper that automatically evicts large results.
868
+ *
869
+ * @param backend - Backend or factory for filesystem operations
870
+ * @param state - Current agent state (for factory backends)
871
+ * @param tokenLimit - Token limit before eviction
872
+ * @returns Function that wraps tool results with eviction
873
+ */
874
+ function createToolResultWrapper(backend, state, tokenLimit = DEFAULT_EVICTION_TOKEN_LIMIT) {
875
+ const resolvedBackend = typeof backend === "function" ? backend(state) : backend;
876
+ return async (result, toolCallId, toolName) => {
877
+ return (await evictToolResult({
878
+ result,
879
+ toolCallId,
880
+ toolName,
881
+ backend: resolvedBackend,
882
+ tokenLimit
883
+ })).content;
884
+ };
885
+ }
886
+ var DEFAULT_EVICTION_TOKEN_LIMIT, CHARS_PER_TOKEN;
887
+ var init_eviction = require_chunk.__esmMin((() => {
888
+ init_limits();
889
+ DEFAULT_EVICTION_TOKEN_LIMIT = DEFAULT_EVICTION_TOKEN_LIMIT$1;
890
+ CHARS_PER_TOKEN = 4;
891
+ }));
892
+
893
+ //#endregion
894
+ //#region src/tools/filesystem.ts
895
+ /**
896
+ * Filesystem tools for virtual file operations.
897
+ */
898
+ init_eviction();
899
+ init_events();
900
+ const LS_TOOL_DESCRIPTION = "List files and directories in a directory. Paths are relative to the working directory.";
901
+ const READ_FILE_TOOL_DESCRIPTION = "Read the contents of a file. Paths are relative to the working directory.";
902
+ const WRITE_FILE_TOOL_DESCRIPTION = "Write content to a new file. Returns an error if the file already exists. Paths are relative to the working directory.";
903
+ const EDIT_FILE_TOOL_DESCRIPTION = "Edit a file by replacing a specific string with a new string. Paths are relative to the working directory.";
904
+ const GLOB_TOOL_DESCRIPTION = "Find files matching a glob pattern (e.g., '**/*.py' for all Python files). Paths are relative to the working directory.";
905
+ const GREP_TOOL_DESCRIPTION = "Search for a regex pattern in files. Returns matching files and line numbers. Paths are relative to the working directory.";
906
+ /**
907
+ * Resolve backend from factory or instance.
908
+ */
909
+ function getBackend$1(backend, state) {
910
+ if (typeof backend === "function") return backend(state);
911
+ return backend;
912
+ }
913
+ /**
914
+ * Create the ls tool.
915
+ */
916
+ function createLsTool(state, backend, onEvent) {
917
+ return (0, ai.tool)({
918
+ description: LS_TOOL_DESCRIPTION,
919
+ inputSchema: zod.z.object({ path: zod.z.string().default(".").describe("Directory path to list (default: current directory)") }),
920
+ execute: async ({ path: path$1 }) => {
921
+ const infos = await getBackend$1(backend, state).lsInfo(path$1 || ".");
922
+ if (onEvent) onEvent({
923
+ type: "ls",
924
+ path: path$1 || ".",
925
+ count: infos.length
926
+ });
927
+ if (infos.length === 0) return `No files found in ${path$1}`;
928
+ const lines = [];
929
+ for (const info of infos) if (info.is_dir) lines.push(`${info.path} (directory)`);
930
+ else {
931
+ const size = info.size ? ` (${info.size} bytes)` : "";
932
+ lines.push(`${info.path}${size}`);
933
+ }
934
+ return lines.join("\n");
935
+ }
936
+ });
937
+ }
938
+ /**
939
+ * Create the read_file tool.
940
+ */
941
+ function createReadFileTool(state, backend, evictionLimit, onEvent) {
942
+ return (0, ai.tool)({
943
+ description: READ_FILE_TOOL_DESCRIPTION,
944
+ inputSchema: zod.z.object({
945
+ file_path: zod.z.string().describe("Path to the file to read (e.g., 'src/main.ts' or './main.ts')"),
946
+ offset: zod.z.number().default(0).describe("Line offset to start reading from (0-indexed)"),
947
+ limit: zod.z.number().default(2e3).describe("Maximum number of lines to read")
948
+ }),
949
+ execute: async ({ file_path, offset, limit }, { toolCallId }) => {
950
+ const resolvedBackend = getBackend$1(backend, state);
951
+ const content = await resolvedBackend.read(file_path, offset ?? 0, limit ?? 2e3);
952
+ if (onEvent) {
953
+ const lineCount = content.split("\n").length;
954
+ onEvent(createFileReadEvent(file_path, lineCount));
955
+ }
956
+ if (evictionLimit && evictionLimit > 0) return (await evictToolResult({
957
+ result: content,
958
+ toolCallId: toolCallId || `read_${Date.now()}`,
959
+ toolName: "read_file",
960
+ backend: resolvedBackend,
961
+ tokenLimit: evictionLimit
962
+ })).content;
963
+ return content;
964
+ }
965
+ });
966
+ }
967
+ /**
968
+ * Create the write_file tool.
969
+ */
970
+ function createWriteFileTool(state, backend, onEvent) {
971
+ return (0, ai.tool)({
972
+ description: WRITE_FILE_TOOL_DESCRIPTION,
973
+ inputSchema: zod.z.object({
974
+ file_path: zod.z.string().describe("Path to the file to write (e.g., 'src/main.ts' or './main.ts')"),
975
+ content: zod.z.string().describe("Content to write to the file")
976
+ }),
977
+ execute: async ({ file_path, content }) => {
978
+ if (onEvent) onEvent(createFileWriteStartEvent(file_path, content));
979
+ const result = await getBackend$1(backend, state).write(file_path, content);
980
+ if (result.error) return result.error;
981
+ if (onEvent) onEvent(createFileWrittenEvent(file_path, content));
982
+ return `Successfully wrote to '${file_path}'`;
983
+ }
984
+ });
985
+ }
986
+ /**
987
+ * Create the edit_file tool.
988
+ */
989
+ function createEditFileTool(state, backend, onEvent) {
990
+ return (0, ai.tool)({
991
+ description: EDIT_FILE_TOOL_DESCRIPTION,
992
+ inputSchema: zod.z.object({
993
+ file_path: zod.z.string().describe("Path to the file to edit (e.g., 'src/main.ts' or './main.ts')"),
994
+ old_string: zod.z.string().describe("String to be replaced (must match exactly)"),
995
+ new_string: zod.z.string().describe("String to replace with"),
996
+ replace_all: zod.z.boolean().default(false).describe("Whether to replace all occurrences")
997
+ }),
998
+ execute: async ({ file_path, old_string, new_string, replace_all }) => {
999
+ const result = await getBackend$1(backend, state).edit(file_path, old_string, new_string, replace_all ?? false);
1000
+ if (result.error) return result.error;
1001
+ if (onEvent) onEvent(createFileEditedEvent(file_path, result.occurrences ?? 0));
1002
+ return `Successfully replaced ${result.occurrences} occurrence(s) in '${file_path}'`;
1003
+ }
1004
+ });
1005
+ }
1006
+ /**
1007
+ * Create the glob tool.
1008
+ */
1009
+ function createGlobTool(state, backend, onEvent) {
1010
+ return (0, ai.tool)({
1011
+ description: GLOB_TOOL_DESCRIPTION,
1012
+ inputSchema: zod.z.object({
1013
+ pattern: zod.z.string().describe("Glob pattern (e.g., '*.py', '**/*.ts')"),
1014
+ path: zod.z.string().default(".").describe("Base path to search from (default: current directory)")
1015
+ }),
1016
+ execute: async ({ pattern, path: path$1 }) => {
1017
+ const infos = await getBackend$1(backend, state).globInfo(pattern, path$1 || ".");
1018
+ if (onEvent) onEvent({
1019
+ type: "glob",
1020
+ pattern,
1021
+ count: infos.length
1022
+ });
1023
+ if (infos.length === 0) return `No files found matching pattern '${pattern}'`;
1024
+ return infos.map((info) => info.path).join("\n");
1025
+ }
1026
+ });
1027
+ }
1028
+ /**
1029
+ * Create the grep tool.
1030
+ */
1031
+ function createGrepTool(state, backend, evictionLimit, onEvent) {
1032
+ return (0, ai.tool)({
1033
+ description: GREP_TOOL_DESCRIPTION,
1034
+ inputSchema: zod.z.object({
1035
+ pattern: zod.z.string().describe("Regex pattern to search for"),
1036
+ path: zod.z.string().default(".").describe("Base path to search from (default: current directory)"),
1037
+ glob: zod.z.string().optional().nullable().describe("Optional glob pattern to filter files (e.g., '*.py')")
1038
+ }),
1039
+ execute: async ({ pattern, path: path$1, glob: glob$1 }, { toolCallId }) => {
1040
+ const resolvedBackend = getBackend$1(backend, state);
1041
+ const result = await resolvedBackend.grepRaw(pattern, path$1 || ".", glob$1 ?? null);
1042
+ if (typeof result === "string") {
1043
+ if (onEvent) onEvent({
1044
+ type: "grep",
1045
+ pattern,
1046
+ count: 0
1047
+ });
1048
+ return result;
1049
+ }
1050
+ if (onEvent) onEvent({
1051
+ type: "grep",
1052
+ pattern,
1053
+ count: result.length
1054
+ });
1055
+ if (result.length === 0) return `No matches found for pattern '${pattern}'`;
1056
+ const lines = [];
1057
+ let currentFile = null;
1058
+ for (const match of result) {
1059
+ if (match.path !== currentFile) {
1060
+ currentFile = match.path;
1061
+ lines.push(`\n${currentFile}:`);
1062
+ }
1063
+ lines.push(` ${match.line}: ${match.text}`);
1064
+ }
1065
+ const content = lines.join("\n");
1066
+ if (evictionLimit && evictionLimit > 0) return (await evictToolResult({
1067
+ result: content,
1068
+ toolCallId: toolCallId || `grep_${Date.now()}`,
1069
+ toolName: "grep",
1070
+ backend: resolvedBackend,
1071
+ tokenLimit: evictionLimit
1072
+ })).content;
1073
+ return content;
1074
+ }
1075
+ });
1076
+ }
1077
+ /**
1078
+ * Create all filesystem tools.
1079
+ * @param state - The shared agent state
1080
+ * @param backendOrOptions - Backend or options object
1081
+ * @param onEvent - Optional callback for emitting events (deprecated, use options)
1082
+ */
1083
+ function createFilesystemTools(state, backendOrOptions, onEvent) {
1084
+ let backend;
1085
+ let eventCallback = onEvent;
1086
+ let evictionLimit;
1087
+ if (backendOrOptions && typeof backendOrOptions === "object" && "backend" in backendOrOptions) {
1088
+ const options = backendOrOptions;
1089
+ backend = options.backend;
1090
+ eventCallback = options.onEvent;
1091
+ evictionLimit = options.toolResultEvictionLimit;
1092
+ } else backend = backendOrOptions;
1093
+ const resolvedBackend = backend || ((s) => new StateBackend(s));
1094
+ return {
1095
+ ls: createLsTool(state, resolvedBackend, eventCallback),
1096
+ read_file: createReadFileTool(state, resolvedBackend, evictionLimit, eventCallback),
1097
+ write_file: createWriteFileTool(state, resolvedBackend, eventCallback),
1098
+ edit_file: createEditFileTool(state, resolvedBackend, eventCallback),
1099
+ glob: createGlobTool(state, resolvedBackend, eventCallback),
1100
+ grep: createGrepTool(state, resolvedBackend, evictionLimit, eventCallback)
1101
+ };
1102
+ }
1103
+ /**
1104
+ * Individual builtin tool references for selective subagent configuration.
1105
+ * These are references to the creator functions, not instances.
1106
+ */
1107
+ const ls = createLsTool;
1108
+ const read_file = createReadFileTool;
1109
+ const write_file = createWriteFileTool;
1110
+ const edit_file = createEditFileTool;
1111
+ const glob = createGlobTool;
1112
+ const grep = createGrepTool;
1113
+
1114
+ //#endregion
1115
+ //#region src/utils/approval.ts
1116
+ /**
1117
+ * Utilities for applying tool approval configuration.
1118
+ */
1119
+ /**
1120
+ * Check if approval is needed based on config.
1121
+ */
1122
+ async function checkNeedsApproval(config, args) {
1123
+ if (typeof config === "boolean") return config;
1124
+ if (config.shouldApprove) return config.shouldApprove(args);
1125
+ return true;
1126
+ }
1127
+ /**
1128
+ * Convert interruptOn config to needsApproval function for a tool.
1129
+ */
1130
+ function configToNeedsApproval(config) {
1131
+ if (typeof config === "boolean") return config;
1132
+ if (config.shouldApprove) return config.shouldApprove;
1133
+ return true;
1134
+ }
1135
+ let approvalCounter = 0;
1136
+ function generateApprovalId() {
1137
+ return `approval-${Date.now()}-${++approvalCounter}`;
1138
+ }
1139
+ /**
1140
+ * Apply interruptOn configuration to a toolset.
1141
+ *
1142
+ * This adds the `needsApproval` property to tools based on the config.
1143
+ *
1144
+ * @param tools - The original toolset
1145
+ * @param interruptOn - Configuration mapping tool names to approval settings
1146
+ * @returns New toolset with needsApproval applied
1147
+ *
1148
+ * @example
1149
+ * ```typescript
1150
+ * const approvedTools = applyInterruptConfig(tools, {
1151
+ * write_file: true,
1152
+ * execute: { shouldApprove: (args) => args.command.includes('rm') },
1153
+ * });
1154
+ * ```
1155
+ */
1156
+ function applyInterruptConfig(tools, interruptOn) {
1157
+ if (!interruptOn) return tools;
1158
+ const result = {};
1159
+ for (const [name, tool$6] of Object.entries(tools)) {
1160
+ const config = interruptOn[name];
1161
+ if (config === void 0 || config === false) result[name] = tool$6;
1162
+ else result[name] = {
1163
+ ...tool$6,
1164
+ needsApproval: configToNeedsApproval(config)
1165
+ };
1166
+ }
1167
+ return result;
1168
+ }
1169
+ /**
1170
+ * Wrap tools with approval checking that intercepts execution.
1171
+ *
1172
+ * Unlike applyInterruptConfig which just sets needsApproval metadata,
1173
+ * this actually wraps the execute function to request approval before running.
1174
+ *
1175
+ * If no approval callback is provided, tools requiring approval will be auto-denied.
1176
+ *
1177
+ * @param tools - The original toolset
1178
+ * @param interruptOn - Configuration mapping tool names to approval settings
1179
+ * @param onApprovalRequest - Callback to request approval from user (optional)
1180
+ * @returns New toolset with wrapped execute functions
1181
+ */
1182
+ function wrapToolsWithApproval(tools, interruptOn, onApprovalRequest) {
1183
+ if (!interruptOn) return tools;
1184
+ const result = {};
1185
+ for (const [name, existingTool] of Object.entries(tools)) {
1186
+ const config = interruptOn[name];
1187
+ if (config === void 0 || config === false) result[name] = existingTool;
1188
+ else {
1189
+ const originalExecute = existingTool.execute;
1190
+ if (!originalExecute) {
1191
+ result[name] = existingTool;
1192
+ continue;
1193
+ }
1194
+ result[name] = (0, ai.tool)({
1195
+ description: existingTool.description,
1196
+ inputSchema: existingTool.inputSchema,
1197
+ execute: async (args, options) => {
1198
+ if (await checkNeedsApproval(config, args)) {
1199
+ if (!onApprovalRequest) return `Tool execution denied. No approval callback provided. The ${name} tool was not executed.`;
1200
+ const approvalId = generateApprovalId();
1201
+ if (!await onApprovalRequest({
1202
+ approvalId,
1203
+ toolCallId: options?.toolCallId || approvalId,
1204
+ toolName: name,
1205
+ args
1206
+ })) return `Tool execution denied by user. The ${name} tool was not executed.`;
1207
+ }
1208
+ return originalExecute(args, options);
1209
+ }
1210
+ });
1211
+ }
1212
+ }
1213
+ return result;
1214
+ }
1215
+
1216
+ //#endregion
1217
+ //#region src/tools/web.ts
1218
+ /**
1219
+ * Web tools for search and HTTP requests.
1220
+ * Based on LangChain DeepAgents implementation.
1221
+ */
1222
+ var web_exports = /* @__PURE__ */ require_chunk.__exportAll({
1223
+ createFetchUrlTool: () => createFetchUrlTool,
1224
+ createHttpRequestTool: () => createHttpRequestTool,
1225
+ createWebSearchTool: () => createWebSearchTool,
1226
+ createWebTools: () => createWebTools,
1227
+ fetch_url: () => fetch_url,
1228
+ htmlToMarkdown: () => htmlToMarkdown,
1229
+ http_request: () => http_request,
1230
+ web_search: () => web_search
1231
+ });
1232
+ /**
1233
+ * Helper to resolve backend from factory or instance.
1234
+ */
1235
+ function getBackend(backend, state) {
1236
+ if (!backend) return null;
1237
+ if (typeof backend === "function") return backend(state);
1238
+ return backend;
1239
+ }
1240
+ /**
1241
+ * Convert HTML to Markdown with article extraction.
1242
+ * Uses Mozilla Readability to extract main content, then converts to Markdown.
1243
+ */
1244
+ function htmlToMarkdown(html, url) {
1245
+ try {
1246
+ const dom = new jsdom.JSDOM(html, { url });
1247
+ const article = new _mozilla_readability.Readability(dom.window.document).parse();
1248
+ if (!article) return (dom.window.document.body?.textContent || "").trim();
1249
+ const markdown = new turndown.default({
1250
+ headingStyle: "atx",
1251
+ codeBlockStyle: "fenced"
1252
+ }).turndown(article.content || "");
1253
+ if (article.title) return `# ${article.title}\n\n${markdown}`;
1254
+ return markdown;
1255
+ } catch (error) {
1256
+ return `Error converting HTML to Markdown: ${error instanceof Error ? error.message : String(error)}`;
1257
+ }
1258
+ }
1259
+ /**
1260
+ * Create the web_search tool.
1261
+ */
1262
+ function createWebSearchTool(state, options) {
1263
+ const { backend, onEvent, toolResultEvictionLimit, tavilyApiKey } = options;
1264
+ return (0, ai.tool)({
1265
+ description: WEB_SEARCH_TOOL_DESCRIPTION,
1266
+ inputSchema: zod.z.object({
1267
+ query: zod.z.string().describe("The search query (be specific and detailed for best results)"),
1268
+ max_results: zod.z.number().default(5).describe("Number of results to return (1-20)"),
1269
+ topic: zod.z.enum([
1270
+ "general",
1271
+ "news",
1272
+ "finance"
1273
+ ]).default("general").describe("Search topic category"),
1274
+ include_raw_content: zod.z.boolean().default(false).describe("Include full page content (warning: uses more tokens)")
1275
+ }),
1276
+ execute: async ({ query, max_results, topic, include_raw_content }, { toolCallId }) => {
1277
+ if (onEvent) onEvent(createWebSearchStartEvent(query));
1278
+ try {
1279
+ const results = (await (0, _tavily_core.tavily)({ apiKey: tavilyApiKey }).search(query, {
1280
+ maxResults: max_results,
1281
+ topic,
1282
+ includeRawContent: include_raw_content ? "text" : false
1283
+ })).results || [];
1284
+ const formattedResults = results.map((r, i) => `## Result ${i + 1}: ${r.title}\nURL: ${r.url}\nScore: ${r.score?.toFixed(2) || "N/A"}\nContent: ${r.content}\n`).join("\n---\n\n");
1285
+ const output = `Found ${results.length} results for query: "${query}"\n\n${formattedResults}`;
1286
+ if (onEvent) onEvent(createWebSearchFinishEvent(query, results.length));
1287
+ if (toolResultEvictionLimit && toolResultEvictionLimit > 0 && backend) {
1288
+ const resolvedBackend = getBackend(backend, state);
1289
+ if (resolvedBackend) return (await evictToolResult({
1290
+ result: output,
1291
+ toolCallId: toolCallId || `web_search_${Date.now()}`,
1292
+ toolName: "web_search",
1293
+ backend: resolvedBackend,
1294
+ tokenLimit: toolResultEvictionLimit
1295
+ })).content;
1296
+ }
1297
+ return output;
1298
+ } catch (error) {
1299
+ const errorMessage = WEB_SEARCH_ERROR(error.message);
1300
+ if (onEvent) onEvent(createWebSearchFinishEvent(query, 0));
1301
+ return errorMessage;
1302
+ }
1303
+ }
1304
+ });
1305
+ }
1306
+ /**
1307
+ * Create the http_request tool.
1308
+ */
1309
+ function createHttpRequestTool(state, options) {
1310
+ const { backend, onEvent, toolResultEvictionLimit, defaultTimeout } = options;
1311
+ return (0, ai.tool)({
1312
+ description: HTTP_REQUEST_TOOL_DESCRIPTION,
1313
+ inputSchema: zod.z.object({
1314
+ url: zod.z.string().url().describe("Target URL (must be valid HTTP/HTTPS URL)"),
1315
+ method: zod.z.enum([
1316
+ "GET",
1317
+ "POST",
1318
+ "PUT",
1319
+ "DELETE",
1320
+ "PATCH"
1321
+ ]).default("GET").describe("HTTP method"),
1322
+ headers: zod.z.record(zod.z.string()).optional().describe("HTTP headers as key-value pairs"),
1323
+ body: zod.z.union([zod.z.string(), zod.z.record(zod.z.any())]).optional().describe("Request body (string or JSON object)"),
1324
+ params: zod.z.record(zod.z.string()).optional().describe("URL query parameters as key-value pairs"),
1325
+ timeout: zod.z.number().default(defaultTimeout).describe("Request timeout in seconds")
1326
+ }),
1327
+ execute: async ({ url, method, headers, body, params, timeout }, { toolCallId }) => {
1328
+ if (onEvent) onEvent(createHttpRequestStartEvent(url, method));
1329
+ try {
1330
+ const urlObj = new URL(url);
1331
+ if (params) Object.entries(params).forEach(([key, value]) => {
1332
+ urlObj.searchParams.append(key, value);
1333
+ });
1334
+ const requestOptions = {
1335
+ method,
1336
+ headers: headers || {},
1337
+ signal: AbortSignal.timeout(timeout * 1e3)
1338
+ };
1339
+ if (body) if (typeof body === "string") requestOptions.body = body;
1340
+ else {
1341
+ requestOptions.body = JSON.stringify(body);
1342
+ requestOptions.headers["Content-Type"] = "application/json";
1343
+ }
1344
+ const response = await fetch(urlObj.toString(), requestOptions);
1345
+ const contentType = response.headers.get("content-type") || "";
1346
+ let content;
1347
+ if (contentType.includes("application/json")) try {
1348
+ content = await response.json();
1349
+ } catch {
1350
+ content = await response.text();
1351
+ }
1352
+ else content = await response.text();
1353
+ const formattedOutput = `HTTP ${method} ${url}\nStatus: ${response.status}\nSuccess: ${response.ok}\nContent:\n${typeof content === "string" ? content : JSON.stringify(content, null, 2)}`;
1354
+ if (onEvent) onEvent(createHttpRequestFinishEvent(response.url, response.status));
1355
+ if (toolResultEvictionLimit && toolResultEvictionLimit > 0 && backend) {
1356
+ const resolvedBackend = getBackend(backend, state);
1357
+ if (resolvedBackend) return (await evictToolResult({
1358
+ result: formattedOutput,
1359
+ toolCallId: toolCallId || `http_request_${Date.now()}`,
1360
+ toolName: "http_request",
1361
+ backend: resolvedBackend,
1362
+ tokenLimit: toolResultEvictionLimit
1363
+ })).content;
1364
+ }
1365
+ return formattedOutput;
1366
+ } catch (error) {
1367
+ const err = error;
1368
+ let errorMessage;
1369
+ if (err.name === "TimeoutError" || err.name === "AbortError") errorMessage = REQUEST_TIMEOUT(timeout);
1370
+ else errorMessage = `HTTP request error: ${err.message}`;
1371
+ if (onEvent) onEvent(createHttpRequestFinishEvent(url, 0));
1372
+ return errorMessage;
1373
+ }
1374
+ }
1375
+ });
1376
+ }
1377
+ /**
1378
+ * Create the fetch_url tool.
1379
+ */
1380
+ function createFetchUrlTool(state, options) {
1381
+ const { backend, onEvent, toolResultEvictionLimit, defaultTimeout } = options;
1382
+ return (0, ai.tool)({
1383
+ description: FETCH_URL_TOOL_DESCRIPTION,
1384
+ inputSchema: zod.z.object({
1385
+ url: zod.z.string().url().describe("The URL to fetch (must be valid HTTP/HTTPS URL)"),
1386
+ timeout: zod.z.number().default(defaultTimeout).describe("Request timeout in seconds"),
1387
+ extract_article: zod.z.boolean().default(true).describe("Extract main article content using Readability (disable for non-article pages)")
1388
+ }),
1389
+ execute: async ({ url, timeout, extract_article }, { toolCallId }) => {
1390
+ if (onEvent) onEvent(createFetchUrlStartEvent(url));
1391
+ try {
1392
+ const response = await fetch(url, {
1393
+ signal: AbortSignal.timeout(timeout * 1e3),
1394
+ headers: { "User-Agent": "Mozilla/5.0 (compatible; DeepAgents/1.0)" }
1395
+ });
1396
+ if (!response.ok) {
1397
+ const errorMsg = `HTTP error: ${response.status} ${response.statusText}`;
1398
+ if (onEvent) onEvent(createFetchUrlFinishEvent(response.url, false));
1399
+ return errorMsg;
1400
+ }
1401
+ const html = await response.text();
1402
+ const dom = new jsdom.JSDOM(html, { url });
1403
+ let contentToConvert = html;
1404
+ if (extract_article) try {
1405
+ const article = new _mozilla_readability.Readability(dom.window.document).parse();
1406
+ if (article && article.content) contentToConvert = article.content;
1407
+ } catch (readabilityError) {
1408
+ console.warn("Readability extraction failed, using full HTML");
1409
+ }
1410
+ const markdown = new turndown.default({
1411
+ headingStyle: "atx",
1412
+ codeBlockStyle: "fenced"
1413
+ }).turndown(contentToConvert);
1414
+ if (onEvent) onEvent(createFetchUrlFinishEvent(response.url, true));
1415
+ if (toolResultEvictionLimit && toolResultEvictionLimit > 0 && backend) {
1416
+ const resolvedBackend = getBackend(backend, state);
1417
+ if (resolvedBackend) return (await evictToolResult({
1418
+ result: markdown,
1419
+ toolCallId: toolCallId || `fetch_url_${Date.now()}`,
1420
+ toolName: "fetch_url",
1421
+ backend: resolvedBackend,
1422
+ tokenLimit: toolResultEvictionLimit
1423
+ })).content;
1424
+ }
1425
+ return markdown;
1426
+ } catch (error) {
1427
+ const err = error;
1428
+ let errorMessage;
1429
+ if (err.name === "TimeoutError" || err.name === "AbortError") errorMessage = REQUEST_TIMEOUT(timeout);
1430
+ else errorMessage = `Error fetching URL: ${err.message}`;
1431
+ if (onEvent) onEvent(createFetchUrlFinishEvent(url, false));
1432
+ return errorMessage;
1433
+ }
1434
+ }
1435
+ });
1436
+ }
1437
+ /**
1438
+ * Create all web tools (web_search, http_request, fetch_url).
1439
+ * Tools are only created if TAVILY_API_KEY is available.
1440
+ */
1441
+ function createWebTools(state, options) {
1442
+ const { backend, onEvent, toolResultEvictionLimit, tavilyApiKey = process.env.TAVILY_API_KEY, defaultTimeout = DEFAULT_TIMEOUT_SECONDS } = options || {};
1443
+ if (!tavilyApiKey) {
1444
+ console.warn("Tavily API key not found. Web tools (web_search, fetch_url, http_request) will not be available. Set TAVILY_API_KEY environment variable to enable web tools.");
1445
+ return {};
1446
+ }
1447
+ return {
1448
+ web_search: createWebSearchTool(state, {
1449
+ backend,
1450
+ onEvent,
1451
+ toolResultEvictionLimit,
1452
+ tavilyApiKey
1453
+ }),
1454
+ http_request: createHttpRequestTool(state, {
1455
+ backend,
1456
+ onEvent,
1457
+ toolResultEvictionLimit,
1458
+ defaultTimeout
1459
+ }),
1460
+ fetch_url: createFetchUrlTool(state, {
1461
+ backend,
1462
+ onEvent,
1463
+ toolResultEvictionLimit,
1464
+ defaultTimeout
1465
+ })
1466
+ };
1467
+ }
1468
+ var WEB_SEARCH_TOOL_DESCRIPTION, HTTP_REQUEST_TOOL_DESCRIPTION, FETCH_URL_TOOL_DESCRIPTION, web_search, http_request, fetch_url;
1469
+ var init_web = require_chunk.__esmMin((() => {
1470
+ init_eviction();
1471
+ init_errors();
1472
+ init_limits();
1473
+ init_events();
1474
+ WEB_SEARCH_TOOL_DESCRIPTION = `Search the web using Tavily API for current information, news, and documentation.
1475
+
1476
+ Returns an array of search results with titles, URLs, relevant excerpts, and relevance scores.
1477
+
1478
+ IMPORTANT AGENT INSTRUCTIONS:
1479
+ - You MUST synthesize information from search results into a coherent answer
1480
+ - NEVER show raw JSON or result objects to the user
1481
+ - Cite sources by including URLs in your response
1482
+ - If search fails or returns no results, explain this clearly to the user`;
1483
+ HTTP_REQUEST_TOOL_DESCRIPTION = `Make HTTP requests to APIs and web services.
1484
+
1485
+ Supports GET, POST, PUT, DELETE, PATCH methods with custom headers, query parameters, and request bodies.
1486
+
1487
+ Returns structured response with status code, headers, and parsed content (JSON or text).`;
1488
+ FETCH_URL_TOOL_DESCRIPTION = `Fetch web page content and convert HTML to clean Markdown format.
1489
+
1490
+ Uses Mozilla Readability to extract main article content and Turndown to convert to Markdown.
1491
+
1492
+ Returns the page content as formatted Markdown, suitable for analysis and summarization.
1493
+
1494
+ IMPORTANT AGENT INSTRUCTIONS:
1495
+ - Use this tool to read documentation, articles, and web pages
1496
+ - The content is already cleaned and formatted as Markdown
1497
+ - Cite the URL when referencing fetched content`;
1498
+ web_search = createWebSearchTool;
1499
+ http_request = createHttpRequestTool;
1500
+ fetch_url = createFetchUrlTool;
1501
+ }));
1502
+
1503
+ //#endregion
1504
+ //#region src/tools/execute.ts
1505
+ /**
1506
+ * Execute tool for running shell commands in sandbox backends.
1507
+ *
1508
+ * This tool is only available when the backend implements SandboxBackendProtocol.
1509
+ */
1510
+ /**
1511
+ * Tool description for the execute tool.
1512
+ */
1513
+ const EXECUTE_TOOL_DESCRIPTION = `Execute a shell command in the sandbox environment.
1514
+
1515
+ Use this tool to:
1516
+ - Run build commands (npm install, npm run build, bun install)
1517
+ - Run tests (npm test, bun test, pytest)
1518
+ - Execute scripts (node script.js, python script.py)
1519
+ - Check system state (ls, cat, pwd, which)
1520
+ - Install dependencies
1521
+ - Run any shell command
1522
+
1523
+ The command runs in the sandbox's working directory. Commands have a timeout limit.
1524
+
1525
+ IMPORTANT:
1526
+ - Always check the exit code to determine success (0 = success)
1527
+ - Long-running commands may timeout
1528
+ - Use && to chain commands that depend on each other
1529
+ - Use ; to run commands sequentially regardless of success`;
1530
+ /**
1531
+ * Create an execute tool for running shell commands.
1532
+ *
1533
+ * @param options - Options including the sandbox backend and optional event callback
1534
+ * @returns An AI SDK tool that executes shell commands
1535
+ *
1536
+ * @example Basic usage
1537
+ * ```typescript
1538
+ * import { LocalSandbox, createExecuteTool } from 'deepagentsdk';
1539
+ *
1540
+ * const sandbox = new LocalSandbox({ cwd: './workspace' });
1541
+ * const executeTool = createExecuteTool({ backend: sandbox });
1542
+ *
1543
+ * // Use with agent
1544
+ * const agent = createDeepAgent({
1545
+ * model: anthropic('claude-sonnet-4-20250514'),
1546
+ * backend: sandbox,
1547
+ * tools: { execute: executeTool },
1548
+ * });
1549
+ * ```
1550
+ *
1551
+ * @example With event streaming
1552
+ * ```typescript
1553
+ * const executeTool = createExecuteTool({
1554
+ * backend: sandbox,
1555
+ * onEvent: (event) => {
1556
+ * if (event.type === 'execute-start') {
1557
+ * console.log(`Running: ${event.command}`);
1558
+ * } else if (event.type === 'execute-finish') {
1559
+ * console.log(`Exit code: ${event.exitCode}`);
1560
+ * }
1561
+ * },
1562
+ * });
1563
+ * ```
1564
+ */
1565
+ function createExecuteTool(options) {
1566
+ const { backend, onEvent, description } = options;
1567
+ return (0, ai.tool)({
1568
+ description: description || EXECUTE_TOOL_DESCRIPTION,
1569
+ inputSchema: zod.z.object({ command: zod.z.string().describe("The shell command to execute (e.g., 'npm install', 'ls -la', 'cat file.txt')") }),
1570
+ execute: async ({ command }) => {
1571
+ if (onEvent) onEvent({
1572
+ type: "execute-start",
1573
+ command,
1574
+ sandboxId: backend.id
1575
+ });
1576
+ const result = await backend.execute(command);
1577
+ if (onEvent) onEvent({
1578
+ type: "execute-finish",
1579
+ command,
1580
+ exitCode: result.exitCode,
1581
+ truncated: result.truncated,
1582
+ sandboxId: backend.id
1583
+ });
1584
+ const parts = [];
1585
+ if (result.output) parts.push(result.output);
1586
+ if (result.exitCode === 0) parts.push(`\n[Exit code: 0 (success)]`);
1587
+ else if (result.exitCode !== null) parts.push(`\n[Exit code: ${result.exitCode} (failure)]`);
1588
+ else parts.push(`\n[Exit code: unknown (possibly timed out)]`);
1589
+ if (result.truncated) parts.push(`[Output truncated due to size limit]`);
1590
+ return parts.join("");
1591
+ }
1592
+ });
1593
+ }
1594
+ /**
1595
+ * Convenience function to create execute tool from just a backend.
1596
+ * Useful for simple cases without event handling.
1597
+ *
1598
+ * @param backend - The sandbox backend
1599
+ * @returns An AI SDK tool that executes shell commands
1600
+ *
1601
+ * @example
1602
+ * ```typescript
1603
+ * const sandbox = new LocalSandbox({ cwd: './workspace' });
1604
+ * const tools = {
1605
+ * execute: createExecuteToolFromBackend(sandbox),
1606
+ * };
1607
+ * ```
1608
+ */
1609
+ function createExecuteToolFromBackend(backend) {
1610
+ return createExecuteTool({ backend });
1611
+ }
1612
+ /**
1613
+ * Individual builtin tool reference for selective subagent configuration.
1614
+ * This is a reference to the creator function, not an instance.
1615
+ */
1616
+ const execute = createExecuteTool;
1617
+
1618
+ //#endregion
1619
+ //#region src/tools/subagent.ts
1620
+ /**
1621
+ * Subagent tool for task delegation using AI SDK v6 ToolLoopAgent.
1622
+ */
1623
+ init_limits();
1624
+ init_events();
1625
+ init_web();
1626
+ /**
1627
+ * Check if a value is a builtin tool creator function.
1628
+ */
1629
+ function isBuiltinToolCreator(value) {
1630
+ return typeof value === "function" && (value === createWebSearchTool || value === createHttpRequestTool || value === createFetchUrlTool || value === createLsTool || value === createReadFileTool || value === createWriteFileTool || value === createEditFileTool || value === createGlobTool || value === createGrepTool || value === createTodosTool || value === createExecuteTool);
1631
+ }
1632
+ /**
1633
+ * Instantiate a builtin tool creator with the given context.
1634
+ */
1635
+ function instantiateBuiltinTool(creator, state, options) {
1636
+ const { backend, onEvent, toolResultEvictionLimit } = options;
1637
+ const tavilyApiKey = process.env.TAVILY_API_KEY || "";
1638
+ const defaultTimeout = DEFAULT_TIMEOUT_SECONDS;
1639
+ if (creator === createWebSearchTool) {
1640
+ if (!tavilyApiKey) {
1641
+ console.warn("web_search tool requested but TAVILY_API_KEY not set");
1642
+ return {};
1643
+ }
1644
+ return { web_search: createWebSearchTool(state, {
1645
+ backend,
1646
+ onEvent,
1647
+ toolResultEvictionLimit,
1648
+ tavilyApiKey
1649
+ }) };
1650
+ }
1651
+ if (creator === createHttpRequestTool) return { http_request: createHttpRequestTool(state, {
1652
+ backend,
1653
+ onEvent,
1654
+ toolResultEvictionLimit,
1655
+ defaultTimeout
1656
+ }) };
1657
+ if (creator === createFetchUrlTool) return { fetch_url: createFetchUrlTool(state, {
1658
+ backend,
1659
+ onEvent,
1660
+ toolResultEvictionLimit,
1661
+ defaultTimeout
1662
+ }) };
1663
+ if (creator === createLsTool) return { ls: createLsTool(state, backend, onEvent) };
1664
+ if (creator === createReadFileTool) return { read_file: createReadFileTool(state, backend, toolResultEvictionLimit, onEvent) };
1665
+ if (creator === createWriteFileTool) return { write_file: createWriteFileTool(state, backend, onEvent) };
1666
+ if (creator === createEditFileTool) return { edit_file: createEditFileTool(state, backend, onEvent) };
1667
+ if (creator === createGlobTool) return { glob: createGlobTool(state, backend, onEvent) };
1668
+ if (creator === createGrepTool) return { grep: createGrepTool(state, backend, toolResultEvictionLimit, onEvent) };
1669
+ if (creator === createTodosTool) return { write_todos: createTodosTool(state, onEvent) };
1670
+ if (creator === createExecuteTool) throw new Error("execute tool cannot be used via selective tools - it requires a SandboxBackendProtocol");
1671
+ throw new Error(`Unknown builtin tool creator: ${creator}`);
1672
+ }
1673
+ /**
1674
+ * Process subagent tool configuration (array or ToolSet) into a ToolSet.
1675
+ */
1676
+ function processSubagentTools(toolConfig, state, options) {
1677
+ if (!toolConfig) return {};
1678
+ if (!Array.isArray(toolConfig)) return toolConfig;
1679
+ let result = {};
1680
+ for (const item of toolConfig) if (isBuiltinToolCreator(item)) {
1681
+ const instantiated = instantiateBuiltinTool(item, state, options);
1682
+ result = {
1683
+ ...result,
1684
+ ...instantiated
1685
+ };
1686
+ } else if (typeof item === "object" && item !== null) result = {
1687
+ ...result,
1688
+ ...item
1689
+ };
1690
+ return result;
1691
+ }
1692
+ /**
1693
+ * Build the system prompt for a subagent.
1694
+ */
1695
+ function buildSubagentSystemPrompt(customPrompt) {
1696
+ return `${customPrompt}
1697
+
1698
+ ${BASE_PROMPT}
1699
+
1700
+ ${TODO_SYSTEM_PROMPT}
1701
+
1702
+ ${FILESYSTEM_SYSTEM_PROMPT}`;
1703
+ }
1704
+ /**
1705
+ * Create the task tool for spawning subagents using ToolLoopAgent.
1706
+ */
1707
+ function createSubagentTool(state, options) {
1708
+ const { defaultModel, defaultTools = {}, subagents = [], includeGeneralPurposeAgent = true, backend, taskDescription = null, onEvent, interruptOn, parentGenerationOptions, parentAdvancedOptions } = options;
1709
+ const subagentRegistry = {};
1710
+ const subagentDescriptions = [];
1711
+ if (includeGeneralPurposeAgent) {
1712
+ subagentRegistry["general-purpose"] = {
1713
+ systemPrompt: buildSubagentSystemPrompt(DEFAULT_SUBAGENT_PROMPT),
1714
+ toolConfig: defaultTools,
1715
+ model: defaultModel
1716
+ };
1717
+ subagentDescriptions.push(`- general-purpose: ${DEFAULT_GENERAL_PURPOSE_DESCRIPTION}`);
1718
+ }
1719
+ for (const subagent of subagents) {
1720
+ subagentRegistry[subagent.name] = {
1721
+ systemPrompt: buildSubagentSystemPrompt(subagent.systemPrompt),
1722
+ toolConfig: subagent.tools || defaultTools,
1723
+ model: subagent.model || defaultModel,
1724
+ output: subagent.output
1725
+ };
1726
+ subagentDescriptions.push(`- ${subagent.name}: ${subagent.description}`);
1727
+ }
1728
+ return (0, ai.tool)({
1729
+ description: taskDescription || getTaskToolDescription(subagentDescriptions),
1730
+ inputSchema: zod.z.object({
1731
+ description: zod.z.string().describe("The task to execute with the selected agent"),
1732
+ subagent_type: zod.z.string().describe(`Name of the agent to use. Available: ${Object.keys(subagentRegistry).join(", ")}`)
1733
+ }),
1734
+ execute: async ({ description, subagent_type }) => {
1735
+ if (!(subagent_type in subagentRegistry)) return `Error: invoked agent of type ${subagent_type}, the only allowed types are ${Object.keys(subagentRegistry).map((k) => `\`${k}\``).join(", ")}`;
1736
+ const subagentConfig = subagentRegistry[subagent_type];
1737
+ const subagentSpec = subagents.find((sa) => sa.name === subagent_type);
1738
+ const subagentInterruptOn = subagentSpec?.interruptOn ?? interruptOn;
1739
+ const mergedGenerationOptions = {
1740
+ ...parentGenerationOptions,
1741
+ ...subagentSpec?.generationOptions
1742
+ };
1743
+ const mergedAdvancedOptions = {
1744
+ ...parentAdvancedOptions,
1745
+ ...subagentSpec?.advancedOptions
1746
+ };
1747
+ if (onEvent) onEvent(createSubagentStartEvent(subagent_type, description));
1748
+ const subagentState = {
1749
+ todos: [],
1750
+ files: state.files
1751
+ };
1752
+ const customTools = processSubagentTools(subagentConfig.toolConfig, subagentState, {
1753
+ backend,
1754
+ onEvent
1755
+ });
1756
+ let allTools = {
1757
+ write_todos: createTodosTool(subagentState, onEvent),
1758
+ ...createFilesystemTools(subagentState, backend, onEvent),
1759
+ ...customTools
1760
+ };
1761
+ allTools = applyInterruptConfig(allTools, subagentInterruptOn);
1762
+ try {
1763
+ const subagentSettings = {
1764
+ model: subagentConfig.model,
1765
+ instructions: subagentConfig.systemPrompt,
1766
+ tools: allTools,
1767
+ stopWhen: (0, ai.stepCountIs)(DEFAULT_SUBAGENT_MAX_STEPS),
1768
+ ...subagentConfig.output ? { output: ai.Output.object(subagentConfig.output) } : {}
1769
+ };
1770
+ if (Object.keys(mergedGenerationOptions).length > 0) Object.assign(subagentSettings, mergedGenerationOptions);
1771
+ if (mergedAdvancedOptions) {
1772
+ const { toolChoice, activeTools, ...safeAdvancedOptions } = mergedAdvancedOptions;
1773
+ Object.assign(subagentSettings, safeAdvancedOptions);
1774
+ }
1775
+ let subagentStepCount = 0;
1776
+ subagentSettings.onStepFinish = async ({ toolCalls, toolResults }) => {
1777
+ if (onEvent && toolCalls && toolCalls.length > 0) {
1778
+ const toolCallsWithResults = toolCalls.map((tc, index) => ({
1779
+ toolName: tc.toolName,
1780
+ args: tc.args,
1781
+ result: toolResults[index]
1782
+ }));
1783
+ onEvent(createSubagentStepEvent(subagentStepCount++, toolCallsWithResults));
1784
+ }
1785
+ };
1786
+ const result = await new ai.ToolLoopAgent(subagentSettings).generate({ prompt: description });
1787
+ state.files = {
1788
+ ...state.files,
1789
+ ...subagentState.files
1790
+ };
1791
+ const resultText = result.text || "Task completed successfully.";
1792
+ let formattedResult = resultText;
1793
+ if (subagentConfig.output && "output" in result && result.output) formattedResult = `${resultText}\n\n[Structured Output]\n${JSON.stringify(result.output, null, 2)}`;
1794
+ if (onEvent) onEvent(createSubagentFinishEvent(subagent_type, formattedResult));
1795
+ return formattedResult;
1796
+ } catch (error) {
1797
+ const errorMessage = `Error executing subagent: ${error.message}`;
1798
+ if (onEvent) onEvent(createSubagentFinishEvent(subagent_type, errorMessage));
1799
+ return errorMessage;
1800
+ }
1801
+ }
1802
+ });
1803
+ }
1804
+
1805
+ //#endregion
1806
+ //#region src/utils/patch-tool-calls.ts
1807
+ /**
1808
+ * Check if a message is an assistant message with tool calls.
1809
+ */
1810
+ function hasToolCalls(message) {
1811
+ if (message.role !== "assistant") return false;
1812
+ const content = message.content;
1813
+ if (Array.isArray(content)) return content.some((part) => typeof part === "object" && part !== null && "type" in part && part.type === "tool-call");
1814
+ return false;
1815
+ }
1816
+ /**
1817
+ * Extract tool call IDs from an assistant message.
1818
+ */
1819
+ function getToolCallIds(message) {
1820
+ if (message.role !== "assistant") return [];
1821
+ const content = message.content;
1822
+ if (!Array.isArray(content)) return [];
1823
+ const ids = [];
1824
+ for (const part of content) if (typeof part === "object" && part !== null && "type" in part && part.type === "tool-call" && "toolCallId" in part) ids.push(part.toolCallId);
1825
+ return ids;
1826
+ }
1827
+ /**
1828
+ * Check if a message is a tool result for a specific tool call ID.
1829
+ */
1830
+ function isToolResultFor(message, toolCallId) {
1831
+ if (message.role !== "tool") return false;
1832
+ if ("toolCallId" in message && message.toolCallId === toolCallId) return true;
1833
+ const content = message.content;
1834
+ if (Array.isArray(content)) return content.some((part) => typeof part === "object" && part !== null && "type" in part && part.type === "tool-result" && "toolCallId" in part && part.toolCallId === toolCallId);
1835
+ return false;
1836
+ }
1837
+ /**
1838
+ * Create a synthetic tool result message for a cancelled tool call.
1839
+ */
1840
+ function createCancelledToolResult(toolCallId, toolName) {
1841
+ return {
1842
+ role: "tool",
1843
+ content: [{
1844
+ type: "tool-result",
1845
+ toolCallId,
1846
+ toolName,
1847
+ output: {
1848
+ type: "text",
1849
+ value: `Tool call ${toolName} with id ${toolCallId} was cancelled - another message came in before it could be completed.`
1850
+ }
1851
+ }]
1852
+ };
1853
+ }
1854
+ /**
1855
+ * Get tool name from a tool call part.
1856
+ */
1857
+ function getToolName(message, toolCallId) {
1858
+ if (message.role !== "assistant") return "unknown";
1859
+ const content = message.content;
1860
+ if (!Array.isArray(content)) return "unknown";
1861
+ for (const part of content) if (typeof part === "object" && part !== null && "type" in part && part.type === "tool-call" && "toolCallId" in part && part.toolCallId === toolCallId && "toolName" in part) return part.toolName;
1862
+ return "unknown";
1863
+ }
1864
+ /**
1865
+ * Patch dangling tool calls in a message array.
1866
+ *
1867
+ * Scans for assistant messages with tool_calls that don't have corresponding
1868
+ * tool result messages, and adds synthetic "cancelled" responses.
1869
+ *
1870
+ * @param messages - Array of messages to patch
1871
+ * @returns New array with patched messages (original array is not modified)
1872
+ *
1873
+ * @example
1874
+ * ```typescript
1875
+ * const messages = [
1876
+ * { role: "user", content: "Hello" },
1877
+ * { role: "assistant", content: [{ type: "tool-call", toolCallId: "1", toolName: "search" }] },
1878
+ * // Missing tool result for tool call "1"
1879
+ * { role: "user", content: "Never mind" },
1880
+ * ];
1881
+ *
1882
+ * const patched = patchToolCalls(messages);
1883
+ * // patched now includes a synthetic tool result for the dangling call
1884
+ * ```
1885
+ */
1886
+ function patchToolCalls(messages) {
1887
+ if (!messages || messages.length === 0) return messages;
1888
+ const result = [];
1889
+ for (let i = 0; i < messages.length; i++) {
1890
+ const message = messages[i];
1891
+ if (!message) continue;
1892
+ result.push(message);
1893
+ if (hasToolCalls(message)) {
1894
+ const toolCallIds = getToolCallIds(message);
1895
+ for (const toolCallId of toolCallIds) {
1896
+ let hasResult = false;
1897
+ for (let j = i + 1; j < messages.length; j++) {
1898
+ const subsequentMsg = messages[j];
1899
+ if (subsequentMsg && isToolResultFor(subsequentMsg, toolCallId)) {
1900
+ hasResult = true;
1901
+ break;
1902
+ }
1903
+ }
1904
+ if (!hasResult) {
1905
+ const toolName = getToolName(message, toolCallId);
1906
+ result.push(createCancelledToolResult(toolCallId, toolName));
1907
+ }
1908
+ }
1909
+ }
1910
+ }
1911
+ return result;
1912
+ }
1913
+ /**
1914
+ * Check if messages have any dangling tool calls.
1915
+ *
1916
+ * @param messages - Array of messages to check
1917
+ * @returns True if there are dangling tool calls
1918
+ */
1919
+ function hasDanglingToolCalls(messages) {
1920
+ if (!messages || messages.length === 0) return false;
1921
+ for (let i = 0; i < messages.length; i++) {
1922
+ const message = messages[i];
1923
+ if (!message) continue;
1924
+ if (hasToolCalls(message)) {
1925
+ const toolCallIds = getToolCallIds(message);
1926
+ for (const toolCallId of toolCallIds) {
1927
+ let hasResult = false;
1928
+ for (let j = i + 1; j < messages.length; j++) {
1929
+ const subsequentMsg = messages[j];
1930
+ if (subsequentMsg && isToolResultFor(subsequentMsg, toolCallId)) {
1931
+ hasResult = true;
1932
+ break;
1933
+ }
1934
+ }
1935
+ if (!hasResult) return true;
1936
+ }
1937
+ }
1938
+ }
1939
+ return false;
1940
+ }
1941
+
1942
+ //#endregion
1943
+ //#region src/utils/summarization.ts
1944
+ /**
1945
+ * Conversation summarization utility.
1946
+ *
1947
+ * Automatically summarizes older messages when approaching token limits
1948
+ * to prevent context overflow while preserving important context.
1949
+ */
1950
+ init_eviction();
1951
+ init_limits();
1952
+ /**
1953
+ * Default token threshold before triggering summarization.
1954
+ * 170k tokens is a safe threshold for most models.
1955
+ */
1956
+ const DEFAULT_SUMMARIZATION_THRESHOLD = DEFAULT_SUMMARIZATION_THRESHOLD$1;
1957
+ /**
1958
+ * Default number of recent messages to keep intact.
1959
+ */
1960
+ const DEFAULT_KEEP_MESSAGES = DEFAULT_KEEP_MESSAGES$1;
1961
+ /**
1962
+ * Estimate total tokens in a messages array.
1963
+ */
1964
+ function estimateMessagesTokens(messages) {
1965
+ let total = 0;
1966
+ for (const message of messages) if (typeof message.content === "string") total += estimateTokens(message.content);
1967
+ else if (Array.isArray(message.content)) {
1968
+ for (const part of message.content) if (typeof part === "object" && part !== null && "text" in part) total += estimateTokens(String(part.text));
1969
+ }
1970
+ return total;
1971
+ }
1972
+ /**
1973
+ * Extract text content from a message.
1974
+ */
1975
+ function getMessageText(message) {
1976
+ if (typeof message.content === "string") return message.content;
1977
+ if (Array.isArray(message.content)) return message.content.map((part) => {
1978
+ if (typeof part === "object" && part !== null && "text" in part) return String(part.text);
1979
+ if (typeof part === "object" && part !== null && "type" in part) {
1980
+ if (part.type === "tool-call") return `[Tool call: ${part.toolName || "unknown"}]`;
1981
+ if (part.type === "tool-result") return `[Tool result]`;
1982
+ }
1983
+ return "";
1984
+ }).filter(Boolean).join("\n");
1985
+ return "";
1986
+ }
1987
+ /**
1988
+ * Format messages for summarization prompt.
1989
+ */
1990
+ function formatMessagesForSummary(messages) {
1991
+ return messages.map((msg) => {
1992
+ return `${msg.role === "user" ? "User" : msg.role === "assistant" ? "Assistant" : "System"}: ${getMessageText(msg)}`;
1993
+ }).join("\n\n");
1994
+ }
1995
+ /**
1996
+ * Generate a summary of conversation messages.
1997
+ */
1998
+ async function generateSummary(messages, model, generationOptions, advancedOptions) {
1999
+ const generateTextOptions = {
2000
+ model,
2001
+ system: `You are a conversation summarizer. Your task is to create a concise but comprehensive summary of the conversation that preserves:
2002
+ 1. Key decisions and conclusions
2003
+ 2. Important context and background information
2004
+ 3. Any tasks or todos mentioned
2005
+ 4. Technical details that may be referenced later
2006
+ 5. The overall flow and progression of the conversation
2007
+
2008
+ Keep the summary focused and avoid redundancy. The summary should allow someone to understand the conversation context without reading the full history.`,
2009
+ prompt: `Please summarize the following conversation:\n\n${formatMessagesForSummary(messages)}`
2010
+ };
2011
+ if (generationOptions) Object.assign(generateTextOptions, generationOptions);
2012
+ if (advancedOptions) Object.assign(generateTextOptions, advancedOptions);
2013
+ return (await (0, ai.generateText)(generateTextOptions)).text;
2014
+ }
2015
+ /**
2016
+ * Summarize older messages when approaching token limits.
2017
+ *
2018
+ * This function checks if the total tokens in the messages exceed the threshold.
2019
+ * If so, it summarizes older messages while keeping recent ones intact.
2020
+ *
2021
+ * @param messages - Array of conversation messages
2022
+ * @param options - Summarization options
2023
+ * @returns Processed messages with optional summary
2024
+ *
2025
+ * @example
2026
+ * ```typescript
2027
+ * import { anthropic } from '@ai-sdk/anthropic';
2028
+ *
2029
+ * const result = await summarizeIfNeeded(messages, {
2030
+ * model: anthropic('claude-haiku-4-5-20251001'),
2031
+ * tokenThreshold: 170000,
2032
+ * keepMessages: 6,
2033
+ * });
2034
+ *
2035
+ * if (result.summarized) {
2036
+ * console.log(`Reduced from ${result.tokensBefore} to ${result.tokensAfter} tokens`);
2037
+ * }
2038
+ * ```
2039
+ */
2040
+ async function summarizeIfNeeded(messages, options) {
2041
+ const { model, tokenThreshold = DEFAULT_SUMMARIZATION_THRESHOLD, keepMessages = DEFAULT_KEEP_MESSAGES } = options;
2042
+ const tokensBefore = estimateMessagesTokens(messages);
2043
+ if (tokensBefore < tokenThreshold) return {
2044
+ summarized: false,
2045
+ messages,
2046
+ tokensBefore
2047
+ };
2048
+ if (messages.length <= keepMessages) return {
2049
+ summarized: false,
2050
+ messages,
2051
+ tokensBefore
2052
+ };
2053
+ const messagesToSummarize = messages.slice(0, -keepMessages);
2054
+ const messagesToKeep = messages.slice(-keepMessages);
2055
+ const newMessages = [{
2056
+ role: "system",
2057
+ content: `[Previous conversation summary]\n${await generateSummary(messagesToSummarize, model, options.generationOptions, options.advancedOptions)}\n\n[End of summary - recent messages follow]`
2058
+ }, ...messagesToKeep];
2059
+ return {
2060
+ summarized: true,
2061
+ messages: newMessages,
2062
+ tokensBefore,
2063
+ tokensAfter: estimateMessagesTokens(newMessages)
2064
+ };
2065
+ }
2066
+ /**
2067
+ * Check if messages need summarization without performing it.
2068
+ */
2069
+ function needsSummarization(messages, tokenThreshold = DEFAULT_SUMMARIZATION_THRESHOLD) {
2070
+ return estimateMessagesTokens(messages) >= tokenThreshold;
2071
+ }
2072
+
2073
+ //#endregion
2074
+ //#region src/agent.ts
2075
+ /**
2076
+ * Deep Agent implementation using Vercel AI SDK v6 ToolLoopAgent.
2077
+ */
2078
+ init_limits();
2079
+ init_events();
2080
+ /**
2081
+ * Build the full system prompt from components.
2082
+ */
2083
+ function buildSystemPrompt(customPrompt, hasSubagents, hasSandbox, skills) {
2084
+ const parts = [
2085
+ customPrompt || "",
2086
+ BASE_PROMPT,
2087
+ TODO_SYSTEM_PROMPT,
2088
+ FILESYSTEM_SYSTEM_PROMPT
2089
+ ];
2090
+ if (hasSandbox) parts.push(EXECUTE_SYSTEM_PROMPT);
2091
+ if (hasSubagents) parts.push(TASK_SYSTEM_PROMPT);
2092
+ if (skills && skills.length > 0) parts.push(buildSkillsPrompt(skills));
2093
+ return parts.filter(Boolean).join("\n\n");
2094
+ }
2095
+ /**
2096
+ * Deep Agent wrapper class that provides generate() and stream() methods.
2097
+ * Uses ToolLoopAgent from AI SDK v6 for the agent loop.
2098
+ */
2099
+ var DeepAgent = class {
2100
+ model;
2101
+ systemPrompt;
2102
+ userTools;
2103
+ maxSteps;
2104
+ backend;
2105
+ subagentOptions;
2106
+ toolResultEvictionLimit;
2107
+ enablePromptCaching;
2108
+ summarizationConfig;
2109
+ hasSandboxBackend;
2110
+ interruptOn;
2111
+ checkpointer;
2112
+ skillsMetadata = [];
2113
+ outputConfig;
2114
+ loopControl;
2115
+ generationOptions;
2116
+ advancedOptions;
2117
+ constructor(params) {
2118
+ const { model, middleware, tools = {}, systemPrompt, subagents = [], backend, maxSteps = DEFAULT_MAX_STEPS, includeGeneralPurposeAgent = true, toolResultEvictionLimit, enablePromptCaching = false, summarization, interruptOn, checkpointer, skillsDir, agentId, output, loopControl, generationOptions, advancedOptions } = params;
2119
+ if (middleware) this.model = (0, ai.wrapLanguageModel)({
2120
+ model,
2121
+ middleware: Array.isArray(middleware) ? middleware : [middleware]
2122
+ });
2123
+ else this.model = model;
2124
+ this.maxSteps = maxSteps;
2125
+ this.backend = backend || ((state) => new StateBackend(state));
2126
+ this.toolResultEvictionLimit = toolResultEvictionLimit;
2127
+ this.enablePromptCaching = enablePromptCaching;
2128
+ this.summarizationConfig = summarization;
2129
+ this.interruptOn = interruptOn;
2130
+ this.checkpointer = checkpointer;
2131
+ this.outputConfig = output;
2132
+ this.loopControl = loopControl;
2133
+ this.generationOptions = generationOptions;
2134
+ this.advancedOptions = advancedOptions;
2135
+ if (agentId) {
2136
+ if (skillsDir) console.warn("[DeepAgent] agentId parameter takes precedence over skillsDir. skillsDir is deprecated and will be ignored.");
2137
+ this.loadSkills({ agentId }).catch((error) => {
2138
+ console.warn("[DeepAgent] Failed to load skills:", error);
2139
+ });
2140
+ } else if (skillsDir) this.loadSkills({ skillsDir }).catch((error) => {
2141
+ console.warn("[DeepAgent] Failed to load skills:", error);
2142
+ });
2143
+ this.hasSandboxBackend = typeof backend !== "function" && backend !== void 0 && isSandboxBackend(backend);
2144
+ this.systemPrompt = buildSystemPrompt(systemPrompt, includeGeneralPurposeAgent || subagents && subagents.length > 0, this.hasSandboxBackend, this.skillsMetadata);
2145
+ this.userTools = tools;
2146
+ this.subagentOptions = {
2147
+ defaultModel: model,
2148
+ defaultTools: tools,
2149
+ subagents,
2150
+ includeGeneralPurposeAgent
2151
+ };
2152
+ }
2153
+ /**
2154
+ * Create core tools (todos and filesystem).
2155
+ * @private
2156
+ */
2157
+ createCoreTools(state, onEvent) {
2158
+ return {
2159
+ write_todos: createTodosTool(state, onEvent),
2160
+ ...createFilesystemTools(state, {
2161
+ backend: this.backend,
2162
+ onEvent,
2163
+ toolResultEvictionLimit: this.toolResultEvictionLimit
2164
+ }),
2165
+ ...this.userTools
2166
+ };
2167
+ }
2168
+ /**
2169
+ * Create web tools if TAVILY_API_KEY is available.
2170
+ * Uses dynamic import to avoid bundling Node.js dependencies in client builds.
2171
+ * @private
2172
+ */
2173
+ createWebToolSet(state, onEvent) {
2174
+ if (!process.env.TAVILY_API_KEY) return {};
2175
+ try {
2176
+ return (init_web(), require_chunk.__toCommonJS(web_exports)).createWebTools(state, {
2177
+ backend: this.backend,
2178
+ onEvent,
2179
+ toolResultEvictionLimit: this.toolResultEvictionLimit
2180
+ });
2181
+ } catch (error) {
2182
+ console.warn("Web tools not available in this environment:", error);
2183
+ return {};
2184
+ }
2185
+ }
2186
+ /**
2187
+ * Create execute tool if backend is a sandbox.
2188
+ * @private
2189
+ */
2190
+ createExecuteToolSet(onEvent) {
2191
+ if (!this.hasSandboxBackend) return {};
2192
+ const sandboxBackend = this.backend;
2193
+ return { execute: createExecuteTool({
2194
+ backend: sandboxBackend,
2195
+ onEvent
2196
+ }) };
2197
+ }
2198
+ /**
2199
+ * Create subagent tool if configured.
2200
+ * @private
2201
+ */
2202
+ createSubagentToolSet(state, onEvent) {
2203
+ if (!this.subagentOptions.includeGeneralPurposeAgent && (!this.subagentOptions.subagents || this.subagentOptions.subagents.length === 0)) return {};
2204
+ return { task: createSubagentTool(state, {
2205
+ defaultModel: this.subagentOptions.defaultModel,
2206
+ defaultTools: this.userTools,
2207
+ subagents: this.subagentOptions.subagents,
2208
+ includeGeneralPurposeAgent: this.subagentOptions.includeGeneralPurposeAgent,
2209
+ backend: this.backend,
2210
+ onEvent,
2211
+ interruptOn: this.interruptOn,
2212
+ parentGenerationOptions: this.generationOptions,
2213
+ parentAdvancedOptions: this.advancedOptions
2214
+ }) };
2215
+ }
2216
+ /**
2217
+ * Create all tools for the agent, combining core, web, execute, and subagent tools.
2218
+ * @private
2219
+ */
2220
+ createTools(state, onEvent) {
2221
+ let allTools = this.createCoreTools(state, onEvent);
2222
+ const webTools = this.createWebToolSet(state, onEvent);
2223
+ if (Object.keys(webTools).length > 0) allTools = {
2224
+ ...allTools,
2225
+ ...webTools
2226
+ };
2227
+ const executeTools = this.createExecuteToolSet(onEvent);
2228
+ if (Object.keys(executeTools).length > 0) allTools = {
2229
+ ...allTools,
2230
+ ...executeTools
2231
+ };
2232
+ const subagentTools = this.createSubagentToolSet(state, onEvent);
2233
+ if (Object.keys(subagentTools).length > 0) allTools = {
2234
+ ...allTools,
2235
+ ...subagentTools
2236
+ };
2237
+ allTools = applyInterruptConfig(allTools, this.interruptOn);
2238
+ return allTools;
2239
+ }
2240
+ /**
2241
+ * Build stop conditions with maxSteps safety limit.
2242
+ * Combines user-provided stop conditions with the maxSteps limit.
2243
+ */
2244
+ buildStopConditions(maxSteps) {
2245
+ const conditions = [];
2246
+ conditions.push((0, ai.stepCountIs)(maxSteps ?? this.maxSteps));
2247
+ if (this.loopControl?.stopWhen) if (Array.isArray(this.loopControl.stopWhen)) conditions.push(...this.loopControl.stopWhen);
2248
+ else conditions.push(this.loopControl.stopWhen);
2249
+ return conditions;
2250
+ }
2251
+ /**
2252
+ * Build agent settings by combining passthrough options with defaults.
2253
+ */
2254
+ buildAgentSettings(onEvent) {
2255
+ const settings = {
2256
+ model: this.model,
2257
+ instructions: this.systemPrompt,
2258
+ tools: void 0
2259
+ };
2260
+ if (this.generationOptions) Object.assign(settings, this.generationOptions);
2261
+ if (this.advancedOptions) Object.assign(settings, this.advancedOptions);
2262
+ if (this.loopControl) {
2263
+ if (this.loopControl.prepareStep) settings.prepareStep = this.composePrepareStep(this.loopControl.prepareStep);
2264
+ if (this.loopControl.onStepFinish) settings.onStepFinish = this.composeOnStepFinish(this.loopControl.onStepFinish);
2265
+ if (this.loopControl.onFinish) settings.onFinish = this.composeOnFinish(this.loopControl.onFinish);
2266
+ }
2267
+ if (this.outputConfig) settings.output = ai.Output.object(this.outputConfig);
2268
+ return settings;
2269
+ }
2270
+ /**
2271
+ * Create a ToolLoopAgent for a given state.
2272
+ * @param state - The shared agent state
2273
+ * @param maxSteps - Optional max steps override
2274
+ * @param onEvent - Optional callback for emitting events
2275
+ */
2276
+ createAgent(state, maxSteps, onEvent) {
2277
+ const tools = this.createTools(state, onEvent);
2278
+ const settings = this.buildAgentSettings(onEvent);
2279
+ const stopConditions = this.buildStopConditions(maxSteps);
2280
+ return new ai.ToolLoopAgent({
2281
+ ...settings,
2282
+ tools,
2283
+ stopWhen: stopConditions
2284
+ });
2285
+ }
2286
+ /**
2287
+ * Load skills from directory asynchronously.
2288
+ * Supports both legacy skillsDir and new agentId modes.
2289
+ */
2290
+ async loadSkills(options) {
2291
+ const { listSkills } = await Promise.resolve().then(() => require("./load-DqllBbDc.cjs"));
2292
+ this.skillsMetadata = (await listSkills(options.agentId ? { agentId: options.agentId } : { projectSkillsDir: options.skillsDir })).map((s) => ({
2293
+ name: s.name,
2294
+ description: s.description,
2295
+ path: s.path
2296
+ }));
2297
+ }
2298
+ /**
2299
+ * Generate a response (non-streaming).
2300
+ */
2301
+ async generate(options) {
2302
+ const state = {
2303
+ todos: [],
2304
+ files: {}
2305
+ };
2306
+ const result = await this.createAgent(state, options.maxSteps).generate({ prompt: options.prompt });
2307
+ Object.defineProperty(result, "state", {
2308
+ value: state,
2309
+ enumerable: true,
2310
+ writable: false
2311
+ });
2312
+ return result;
2313
+ }
2314
+ /**
2315
+ * Stream a response.
2316
+ */
2317
+ async stream(options) {
2318
+ const state = {
2319
+ todos: [],
2320
+ files: {}
2321
+ };
2322
+ const result = await this.createAgent(state, options.maxSteps).stream({ prompt: options.prompt });
2323
+ Object.defineProperty(result, "state", {
2324
+ value: state,
2325
+ enumerable: true,
2326
+ writable: false
2327
+ });
2328
+ return result;
2329
+ }
2330
+ /**
2331
+ * Generate with an existing state (for continuing conversations).
2332
+ */
2333
+ async generateWithState(options) {
2334
+ const result = await this.createAgent(options.state, options.maxSteps).generate({ prompt: options.prompt });
2335
+ Object.defineProperty(result, "state", {
2336
+ value: options.state,
2337
+ enumerable: true,
2338
+ writable: false
2339
+ });
2340
+ return result;
2341
+ }
2342
+ /**
2343
+ * Get the underlying ToolLoopAgent for advanced usage.
2344
+ * This allows using AI SDK's createAgentUIStream and other utilities.
2345
+ */
2346
+ getAgent(state) {
2347
+ const agentState = state || {
2348
+ todos: [],
2349
+ files: {}
2350
+ };
2351
+ return this.createAgent(agentState);
2352
+ }
2353
+ /**
2354
+ * Stream a response with real-time events.
2355
+ * This is an async generator that yields DeepAgentEvent objects.
2356
+ *
2357
+ * Supports conversation history via the `messages` option for multi-turn conversations.
2358
+ *
2359
+ * @example
2360
+ * ```typescript
2361
+ * // Single turn
2362
+ * for await (const event of agent.streamWithEvents({ prompt: "..." })) {
2363
+ * switch (event.type) {
2364
+ * case 'text':
2365
+ * process.stdout.write(event.text);
2366
+ * break;
2367
+ * case 'done':
2368
+ * // event.messages contains the updated conversation history
2369
+ * console.log('Messages:', event.messages);
2370
+ * break;
2371
+ * }
2372
+ * }
2373
+ *
2374
+ * // Multi-turn conversation
2375
+ * let messages = [];
2376
+ * for await (const event of agent.streamWithEvents({ prompt: "Hello", messages })) {
2377
+ * if (event.type === 'done') {
2378
+ * messages = event.messages; // Save for next turn
2379
+ * }
2380
+ * }
2381
+ * for await (const event of agent.streamWithEvents({ prompt: "Follow up", messages })) {
2382
+ * // Agent now has context from previous turn
2383
+ * }
2384
+ * ```
2385
+ */
2386
+ /**
2387
+ * Compose user's onStepFinish callback with DeepAgent's internal checkpointing logic.
2388
+ * User callback executes first, errors are caught to prevent breaking checkpointing.
2389
+ */
2390
+ composeOnStepFinish(userOnStepFinish) {
2391
+ return async (params) => {
2392
+ if (userOnStepFinish) try {
2393
+ await userOnStepFinish(params);
2394
+ } catch (error) {
2395
+ console.error("[DeepAgent] User onStepFinish callback failed:", error);
2396
+ }
2397
+ };
2398
+ }
2399
+ /**
2400
+ * Compose user's onFinish callback with DeepAgent's internal cleanup logic.
2401
+ */
2402
+ composeOnFinish(userOnFinish) {
2403
+ return async (params) => {
2404
+ if (userOnFinish) try {
2405
+ await userOnFinish(params);
2406
+ } catch (error) {
2407
+ console.error("[DeepAgent] User onFinish callback failed:", error);
2408
+ }
2409
+ };
2410
+ }
2411
+ /**
2412
+ * Compose user's prepareStep callback with DeepAgent's internal step preparation.
2413
+ * Returns a function typed as `any` to avoid AI SDK's strict toolName inference.
2414
+ */
2415
+ composePrepareStep(userPrepareStep) {
2416
+ return async (params) => {
2417
+ if (userPrepareStep) try {
2418
+ return { ...await userPrepareStep(params) };
2419
+ } catch (error) {
2420
+ console.error("[DeepAgent] User prepareStep callback failed:", error);
2421
+ return params;
2422
+ }
2423
+ return params;
2424
+ };
2425
+ }
2426
+ /**
2427
+ * Build streamText options with callbacks for step tracking and checkpointing.
2428
+ *
2429
+ * @private
2430
+ */
2431
+ buildStreamTextOptions(inputMessages, tools, options, state, baseStep, pendingInterrupt, eventQueue, stepNumberRef) {
2432
+ const { threadId } = options;
2433
+ const streamOptions = {
2434
+ model: this.model,
2435
+ messages: inputMessages,
2436
+ tools,
2437
+ stopWhen: this.buildStopConditions(options.maxSteps),
2438
+ abortSignal: options.abortSignal,
2439
+ onStepFinish: async ({ toolCalls, toolResults }) => {
2440
+ if (this.loopControl?.onStepFinish) await this.composeOnStepFinish(this.loopControl.onStepFinish)({
2441
+ toolCalls,
2442
+ toolResults
2443
+ });
2444
+ stepNumberRef.value++;
2445
+ const cumulativeStep = baseStep + stepNumberRef.value;
2446
+ const stepEvent = {
2447
+ type: "step-finish",
2448
+ stepNumber: stepNumberRef.value,
2449
+ toolCalls: toolCalls.map((tc, i) => ({
2450
+ toolName: tc.toolName,
2451
+ args: "input" in tc ? tc.input : void 0,
2452
+ result: toolResults[i] ? "output" in toolResults[i] ? toolResults[i].output : void 0 : void 0
2453
+ }))
2454
+ };
2455
+ eventQueue.push(stepEvent);
2456
+ if (threadId && this.checkpointer) {
2457
+ const checkpoint = {
2458
+ threadId,
2459
+ step: cumulativeStep,
2460
+ messages: inputMessages,
2461
+ state: { ...state },
2462
+ interrupt: pendingInterrupt,
2463
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2464
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2465
+ };
2466
+ await this.checkpointer.save(checkpoint);
2467
+ eventQueue.push(createCheckpointSavedEvent(threadId, cumulativeStep));
2468
+ }
2469
+ }
2470
+ };
2471
+ if (this.generationOptions) Object.assign(streamOptions, this.generationOptions);
2472
+ if (this.advancedOptions) Object.assign(streamOptions, this.advancedOptions);
2473
+ if (this.outputConfig) streamOptions.output = ai.Output.object(this.outputConfig);
2474
+ if (this.loopControl) {
2475
+ if (this.loopControl.prepareStep) streamOptions.prepareStep = this.composePrepareStep(this.loopControl.prepareStep);
2476
+ if (this.loopControl.onFinish) streamOptions.onFinish = this.composeOnFinish(this.loopControl.onFinish);
2477
+ }
2478
+ if (this.enablePromptCaching) streamOptions.messages = [{
2479
+ role: "system",
2480
+ content: this.systemPrompt,
2481
+ providerOptions: { anthropic: { cacheControl: { type: "ephemeral" } } }
2482
+ }, ...inputMessages];
2483
+ else streamOptions.system = this.systemPrompt;
2484
+ return streamOptions;
2485
+ }
2486
+ /**
2487
+ * Build message array from options, handling validation and priority logic.
2488
+ * Priority: explicit messages > prompt > checkpoint history.
2489
+ *
2490
+ * @private
2491
+ */
2492
+ async buildMessageArray(options, patchedHistory) {
2493
+ const { resume } = options;
2494
+ if (!options.prompt && !options.messages && !resume && !options.threadId) return {
2495
+ messages: [],
2496
+ patchedHistory,
2497
+ error: {
2498
+ type: "error",
2499
+ error: /* @__PURE__ */ new Error("Either 'prompt', 'messages', 'resume', or 'threadId' is required")
2500
+ }
2501
+ };
2502
+ let userMessages = [];
2503
+ let shouldUseCheckpointHistory = true;
2504
+ if (options.messages && options.messages.length > 0) {
2505
+ userMessages = options.messages;
2506
+ shouldUseCheckpointHistory = false;
2507
+ if (options.prompt && process.env.NODE_ENV !== "production") console.warn("prompt parameter is deprecated when messages are provided, using messages instead");
2508
+ } else if (options.messages) {
2509
+ shouldUseCheckpointHistory = false;
2510
+ patchedHistory = [];
2511
+ if (options.prompt && process.env.NODE_ENV !== "production") console.warn("prompt parameter is deprecated when empty messages are provided, prompt ignored");
2512
+ } else if (options.prompt) {
2513
+ userMessages = [{
2514
+ role: "user",
2515
+ content: options.prompt
2516
+ }];
2517
+ if (process.env.NODE_ENV !== "production") console.warn("prompt parameter is deprecated, use messages instead");
2518
+ }
2519
+ if (shouldUseCheckpointHistory && patchedHistory.length > 0) {
2520
+ patchedHistory = patchToolCalls(patchedHistory);
2521
+ if (this.summarizationConfig?.enabled && patchedHistory.length > 0) patchedHistory = (await summarizeIfNeeded(patchedHistory, {
2522
+ model: this.summarizationConfig.model || this.model,
2523
+ tokenThreshold: this.summarizationConfig.tokenThreshold,
2524
+ keepMessages: this.summarizationConfig.keepMessages,
2525
+ generationOptions: this.generationOptions,
2526
+ advancedOptions: this.advancedOptions
2527
+ })).messages;
2528
+ } else if (!shouldUseCheckpointHistory) patchedHistory = [];
2529
+ const hasEmptyMessages = options.messages && options.messages.length === 0;
2530
+ const hasValidInput = userMessages.length > 0 || patchedHistory.length > 0;
2531
+ if (hasEmptyMessages && !hasValidInput && !resume) return {
2532
+ messages: [],
2533
+ patchedHistory,
2534
+ shouldReturnEmpty: true
2535
+ };
2536
+ if (!hasValidInput && !resume) return {
2537
+ messages: [],
2538
+ patchedHistory,
2539
+ error: {
2540
+ type: "error",
2541
+ error: /* @__PURE__ */ new Error("No valid input: provide either non-empty messages, prompt, or threadId with existing checkpoint")
2542
+ }
2543
+ };
2544
+ return {
2545
+ messages: [...patchedHistory, ...userMessages],
2546
+ patchedHistory
2547
+ };
2548
+ }
2549
+ /**
2550
+ * Load checkpoint context if threadId is provided.
2551
+ * Handles checkpoint restoration and resume from interrupt.
2552
+ *
2553
+ * @private
2554
+ */
2555
+ async loadCheckpointContext(options) {
2556
+ const { threadId, resume } = options;
2557
+ let state = options.state || {
2558
+ todos: [],
2559
+ files: {}
2560
+ };
2561
+ let patchedHistory = [];
2562
+ let currentStep = 0;
2563
+ let pendingInterrupt;
2564
+ let checkpointEvent;
2565
+ if (threadId && this.checkpointer) {
2566
+ const checkpoint = await this.checkpointer.load(threadId);
2567
+ if (checkpoint) {
2568
+ state = checkpoint.state;
2569
+ patchedHistory = checkpoint.messages;
2570
+ currentStep = checkpoint.step;
2571
+ pendingInterrupt = checkpoint.interrupt;
2572
+ checkpointEvent = createCheckpointLoadedEvent(threadId, checkpoint.step, checkpoint.messages.length);
2573
+ }
2574
+ }
2575
+ if (resume && pendingInterrupt) if (resume.decisions[0]?.type === "approve") pendingInterrupt = void 0;
2576
+ else pendingInterrupt = void 0;
2577
+ return {
2578
+ state,
2579
+ patchedHistory,
2580
+ currentStep,
2581
+ pendingInterrupt,
2582
+ checkpointEvent
2583
+ };
2584
+ }
2585
+ async *streamWithEvents(options) {
2586
+ const { threadId, resume } = options;
2587
+ const context = await this.loadCheckpointContext(options);
2588
+ const { state, currentStep, pendingInterrupt, checkpointEvent } = context;
2589
+ let patchedHistory = context.patchedHistory;
2590
+ if (checkpointEvent) yield checkpointEvent;
2591
+ const messageResult = await this.buildMessageArray(options, patchedHistory);
2592
+ if (messageResult.error) {
2593
+ yield messageResult.error;
2594
+ return;
2595
+ }
2596
+ if (messageResult.shouldReturnEmpty) {
2597
+ yield {
2598
+ type: "done",
2599
+ text: "",
2600
+ messages: [],
2601
+ state
2602
+ };
2603
+ return;
2604
+ }
2605
+ const inputMessages = messageResult.messages;
2606
+ patchedHistory = messageResult.patchedHistory;
2607
+ const eventQueue = [];
2608
+ const stepNumberRef = { value: 0 };
2609
+ const baseStep = currentStep;
2610
+ const onEvent = (event) => {
2611
+ eventQueue.push(event);
2612
+ };
2613
+ let tools = this.createTools(state, onEvent);
2614
+ const hasInterruptOn = !!this.interruptOn;
2615
+ const hasApprovalCallback = !!options.onApprovalRequest;
2616
+ if (hasInterruptOn && hasApprovalCallback) tools = wrapToolsWithApproval(tools, this.interruptOn, options.onApprovalRequest);
2617
+ try {
2618
+ const result = (0, ai.streamText)(this.buildStreamTextOptions(inputMessages, tools, options, state, baseStep, pendingInterrupt, eventQueue, stepNumberRef));
2619
+ yield {
2620
+ type: "step-start",
2621
+ stepNumber: 1
2622
+ };
2623
+ for await (const chunk of result.fullStream) {
2624
+ while (eventQueue.length > 0) {
2625
+ const event = eventQueue.shift();
2626
+ yield event;
2627
+ if (event.type === "step-finish") yield {
2628
+ type: "step-start",
2629
+ stepNumber: event.stepNumber + 1
2630
+ };
2631
+ }
2632
+ if (chunk.type === "text-delta") yield {
2633
+ type: "text",
2634
+ text: chunk.text
2635
+ };
2636
+ else if (chunk.type === "tool-call") yield {
2637
+ type: "tool-call",
2638
+ toolName: chunk.toolName,
2639
+ toolCallId: chunk.toolCallId,
2640
+ args: chunk.input
2641
+ };
2642
+ else if (chunk.type === "tool-result") yield {
2643
+ type: "tool-result",
2644
+ toolName: chunk.toolName,
2645
+ toolCallId: chunk.toolCallId,
2646
+ result: chunk.output,
2647
+ isError: false
2648
+ };
2649
+ else if (chunk.type === "tool-error") yield {
2650
+ type: "tool-result",
2651
+ toolName: chunk.toolName,
2652
+ toolCallId: chunk.toolCallId,
2653
+ result: chunk.error,
2654
+ isError: true
2655
+ };
2656
+ }
2657
+ while (eventQueue.length > 0) yield eventQueue.shift();
2658
+ const finalText = await result.text;
2659
+ const updatedMessages = [...inputMessages, ...finalText ? [{
2660
+ role: "assistant",
2661
+ content: finalText
2662
+ }] : []];
2663
+ const output = "output" in result ? result.output : void 0;
2664
+ yield {
2665
+ type: "done",
2666
+ state,
2667
+ text: finalText,
2668
+ messages: updatedMessages,
2669
+ ...output !== void 0 ? { output } : {}
2670
+ };
2671
+ if (threadId && this.checkpointer) {
2672
+ const finalCheckpoint = {
2673
+ threadId,
2674
+ step: baseStep + stepNumberRef.value,
2675
+ messages: updatedMessages,
2676
+ state,
2677
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2678
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2679
+ };
2680
+ await this.checkpointer.save(finalCheckpoint);
2681
+ yield createCheckpointSavedEvent(threadId, baseStep + stepNumberRef.value);
2682
+ }
2683
+ } catch (error) {
2684
+ yield {
2685
+ type: "error",
2686
+ error: error instanceof Error ? error : new Error(String(error))
2687
+ };
2688
+ }
2689
+ }
2690
+ /**
2691
+ * Stream with a simple callback interface.
2692
+ * This is a convenience wrapper around streamWithEvents.
2693
+ */
2694
+ async streamWithCallback(options, onEvent) {
2695
+ let finalState = options.state || {
2696
+ todos: [],
2697
+ files: {}
2698
+ };
2699
+ let finalText;
2700
+ let finalMessages;
2701
+ for await (const event of this.streamWithEvents(options)) {
2702
+ onEvent(event);
2703
+ if (event.type === "done") {
2704
+ finalState = event.state;
2705
+ finalText = event.text;
2706
+ finalMessages = event.messages;
2707
+ }
2708
+ }
2709
+ return {
2710
+ state: finalState,
2711
+ text: finalText,
2712
+ messages: finalMessages
2713
+ };
2714
+ }
2715
+ };
2716
+ /**
2717
+ * Create a Deep Agent with planning, filesystem, and subagent capabilities.
2718
+ *
2719
+ * @param params - Configuration object for the Deep Agent
2720
+ * @param params.model - **Required.** AI SDK LanguageModel instance (e.g., `anthropic('claude-sonnet-4-20250514')`, `openai('gpt-4o')`)
2721
+ * @param params.systemPrompt - Optional custom system prompt for the agent
2722
+ * @param params.tools - Optional custom tools to add to the agent (AI SDK ToolSet)
2723
+ * @param params.subagents - Optional array of specialized subagent configurations for task delegation
2724
+ * @param params.backend - Optional backend for filesystem operations (default: StateBackend for in-memory storage)
2725
+ * @param params.maxSteps - Optional maximum number of steps for the agent loop (default: 100)
2726
+ * @param params.includeGeneralPurposeAgent - Optional flag to include general-purpose subagent (default: true)
2727
+ * @param params.toolResultEvictionLimit - Optional token limit before evicting large tool results to filesystem (default: disabled)
2728
+ * @param params.enablePromptCaching - Optional flag to enable prompt caching for improved performance (Anthropic only, default: false)
2729
+ * @param params.summarization - Optional summarization configuration for automatic conversation summarization
2730
+ * @returns A configured DeepAgent instance
2731
+ *
2732
+ * @see {@link CreateDeepAgentParams} for detailed parameter types
2733
+ *
2734
+ * @example Basic usage
2735
+ * ```typescript
2736
+ * import { createDeepAgent } from 'deepagentsdk';
2737
+ * import { anthropic } from '@ai-sdk/anthropic';
2738
+ *
2739
+ * const agent = createDeepAgent({
2740
+ * model: anthropic('claude-sonnet-4-20250514'),
2741
+ * systemPrompt: 'You are a research assistant...',
2742
+ * });
2743
+ *
2744
+ * const result = await agent.generate({
2745
+ * prompt: 'Research the topic and write a report',
2746
+ * });
2747
+ * ```
2748
+ *
2749
+ * @example With custom tools
2750
+ * ```typescript
2751
+ * import { tool } from 'ai';
2752
+ * import { z } from 'zod';
2753
+ *
2754
+ * const customTool = tool({
2755
+ * description: 'Get current time',
2756
+ * inputSchema: z.object({}),
2757
+ * execute: async () => new Date().toISOString(),
2758
+ * });
2759
+ *
2760
+ * const agent = createDeepAgent({
2761
+ * model: anthropic('claude-sonnet-4-20250514'),
2762
+ * tools: { get_time: customTool },
2763
+ * });
2764
+ * ```
2765
+ *
2766
+ * @example With subagents
2767
+ * ```typescript
2768
+ * const agent = createDeepAgent({
2769
+ * model: anthropic('claude-sonnet-4-20250514'),
2770
+ * subagents: [{
2771
+ * name: 'research-agent',
2772
+ * description: 'Specialized for research tasks',
2773
+ * systemPrompt: 'You are a research specialist...',
2774
+ * }],
2775
+ * });
2776
+ * ```
2777
+ *
2778
+ * @example With StateBackend (default, explicit)
2779
+ * ```typescript
2780
+ * import { StateBackend } from 'deepagentsdk';
2781
+ *
2782
+ * const state = { todos: [], files: {} };
2783
+ * const agent = createDeepAgent({
2784
+ * model: anthropic('claude-sonnet-4-20250514'),
2785
+ * backend: new StateBackend(state), // Ephemeral in-memory storage
2786
+ * });
2787
+ * ```
2788
+ *
2789
+ * @example With FilesystemBackend
2790
+ * ```typescript
2791
+ * import { FilesystemBackend } from 'deepagentsdk';
2792
+ *
2793
+ * const agent = createDeepAgent({
2794
+ * model: anthropic('claude-sonnet-4-20250514'),
2795
+ * backend: new FilesystemBackend({ rootDir: './workspace' }), // Persist to disk
2796
+ * });
2797
+ * ```
2798
+ *
2799
+ * @example With PersistentBackend
2800
+ * ```typescript
2801
+ * import { PersistentBackend, InMemoryStore } from 'deepagentsdk';
2802
+ *
2803
+ * const store = new InMemoryStore();
2804
+ * const agent = createDeepAgent({
2805
+ * model: anthropic('claude-sonnet-4-20250514'),
2806
+ * backend: new PersistentBackend({ store, namespace: 'project-1' }), // Cross-session persistence
2807
+ * });
2808
+ * ```
2809
+ *
2810
+ * @example With CompositeBackend
2811
+ * ```typescript
2812
+ * import { CompositeBackend, FilesystemBackend, StateBackend } from 'deepagentsdk';
2813
+ *
2814
+ * const state = { todos: [], files: {} };
2815
+ * const agent = createDeepAgent({
2816
+ * model: anthropic('claude-sonnet-4-20250514'),
2817
+ * backend: new CompositeBackend(
2818
+ * new StateBackend(state),
2819
+ * { '/persistent/': new FilesystemBackend({ rootDir: './persistent' }) }
2820
+ * ), // Route files by path prefix
2821
+ * });
2822
+ * ```
2823
+ *
2824
+ * @example With middleware for logging and caching
2825
+ * ```typescript
2826
+ * import { createDeepAgent } from 'deepagentsdk';
2827
+ * import { anthropic } from '@ai-sdk/anthropic';
2828
+ *
2829
+ * const loggingMiddleware = {
2830
+ * wrapGenerate: async ({ doGenerate, params }) => {
2831
+ * console.log('Model called with:', params.prompt);
2832
+ * const result = await doGenerate();
2833
+ * console.log('Model returned:', result.text);
2834
+ * return result;
2835
+ * },
2836
+ * };
2837
+ *
2838
+ * const agent = createDeepAgent({
2839
+ * model: anthropic('claude-sonnet-4-20250514'),
2840
+ * middleware: [loggingMiddleware],
2841
+ * });
2842
+ * ```
2843
+ *
2844
+ * @example With middleware factory for context access
2845
+ * ```typescript
2846
+ * import { FilesystemBackend } from 'deepagentsdk';
2847
+ *
2848
+ * function createContextMiddleware(backend: BackendProtocol) {
2849
+ * return {
2850
+ * wrapGenerate: async ({ doGenerate }) => {
2851
+ * const state = await backend.read('state');
2852
+ * const result = await doGenerate();
2853
+ * await backend.write('state', { ...state, lastCall: result });
2854
+ * return result;
2855
+ * },
2856
+ * };
2857
+ * }
2858
+ *
2859
+ * const backend = new FilesystemBackend({ rootDir: './workspace' });
2860
+ * const agent = createDeepAgent({
2861
+ * model: anthropic('claude-sonnet-4-20250514'),
2862
+ * backend,
2863
+ * middleware: createContextMiddleware(backend),
2864
+ * });
2865
+ * ```
2866
+ *
2867
+ * @example With performance optimizations
2868
+ * ```typescript
2869
+ * const agent = createDeepAgent({
2870
+ * model: anthropic('claude-sonnet-4-20250514'),
2871
+ * enablePromptCaching: true,
2872
+ * toolResultEvictionLimit: 20000,
2873
+ * summarization: {
2874
+ * enabled: true,
2875
+ * tokenThreshold: 170000,
2876
+ * keepMessages: 6,
2877
+ * },
2878
+ * });
2879
+ * ```
2880
+ */
2881
+ function createDeepAgent(params) {
2882
+ return new DeepAgent(params);
2883
+ }
2884
+
2885
+ //#endregion
2886
+ //#region src/backends/sandbox.ts
2887
+ init_errors();
2888
+ init_limits();
2889
+ /**
2890
+ * Encode string to base64 for safe shell transmission.
2891
+ */
2892
+ function toBase64(str) {
2893
+ return Buffer.from(str, "utf-8").toString("base64");
2894
+ }
2895
+ /**
2896
+ * Build a Node.js script command with embedded base64 arguments.
2897
+ * This avoids shell argument parsing issues by embedding values directly in the script.
2898
+ */
2899
+ function buildNodeScript(script, args) {
2900
+ let result = script;
2901
+ for (const [key, value] of Object.entries(args)) result = result.replace(new RegExp(`__${key}__`, "g"), value);
2902
+ return `node -e '${result}'`;
2903
+ }
2904
+ /**
2905
+ * Abstract base class for sandbox backends.
2906
+ *
2907
+ * Implements all file operations using shell commands via execute().
2908
+ * Subclasses only need to implement execute() and id.
2909
+ *
2910
+ * @example Creating a custom sandbox backend
2911
+ * ```typescript
2912
+ * class MyCloudSandbox extends BaseSandbox {
2913
+ * readonly id = 'my-cloud-123';
2914
+ *
2915
+ * async execute(command: string): Promise<ExecuteResponse> {
2916
+ * // Call your cloud provider's API
2917
+ * const result = await myCloudApi.runCommand(command);
2918
+ * return {
2919
+ * output: result.stdout + result.stderr,
2920
+ * exitCode: result.exitCode,
2921
+ * truncated: false,
2922
+ * };
2923
+ * }
2924
+ * }
2925
+ * ```
2926
+ */
2927
+ var BaseSandbox = class {
2928
+ /**
2929
+ * List files and directories in a path.
2930
+ */
2931
+ async lsInfo(path$1) {
2932
+ const pathB64 = toBase64(path$1);
2933
+ const result = await this.execute(buildNodeScript(`
2934
+ const fs = require("fs");
2935
+ const path = require("path");
2936
+
2937
+ const dirPath = Buffer.from("__PATH__", "base64").toString("utf-8");
2938
+
2939
+ try {
2940
+ const entries = fs.readdirSync(dirPath, { withFileTypes: true });
2941
+ for (const entry of entries) {
2942
+ const fullPath = path.join(dirPath, entry.name);
2943
+ try {
2944
+ const stat = fs.statSync(fullPath);
2945
+ console.log(JSON.stringify({
2946
+ path: entry.name,
2947
+ is_dir: entry.isDirectory(),
2948
+ size: stat.size,
2949
+ modified_at: stat.mtime.toISOString()
2950
+ }));
2951
+ } catch (e) {}
2952
+ }
2953
+ } catch (e) {}
2954
+ `, { PATH: pathB64 }));
2955
+ const infos = [];
2956
+ for (const line of result.output.trim().split("\n")) {
2957
+ if (!line) continue;
2958
+ try {
2959
+ const data = JSON.parse(line);
2960
+ infos.push({
2961
+ path: data.path,
2962
+ is_dir: data.is_dir,
2963
+ size: data.size,
2964
+ modified_at: data.modified_at
2965
+ });
2966
+ } catch {}
2967
+ }
2968
+ return infos;
2969
+ }
2970
+ /**
2971
+ * Read file content with line numbers.
2972
+ */
2973
+ async read(filePath, offset = 0, limit = DEFAULT_READ_LIMIT) {
2974
+ const pathB64 = toBase64(filePath);
2975
+ const script = `
2976
+ const fs = require("fs");
2977
+ const filePath = Buffer.from("__PATH__", "base64").toString("utf-8");
2978
+ const offset = __OFFSET__;
2979
+ const limit = __LIMIT__;
2980
+
2981
+ if (!fs.existsSync(filePath)) {
2982
+ console.error("Error: File not found");
2983
+ process.exit(1);
2984
+ }
2985
+
2986
+ const stat = fs.statSync(filePath);
2987
+ if (stat.size === 0) {
2988
+ console.log("${SYSTEM_REMINDER_FILE_EMPTY}");
2989
+ process.exit(0);
2990
+ }
2991
+
2992
+ const content = fs.readFileSync(filePath, "utf-8");
2993
+ const lines = content.split("\\n");
2994
+ const selected = lines.slice(offset, offset + limit);
2995
+
2996
+ for (let i = 0; i < selected.length; i++) {
2997
+ const lineNum = (offset + i + 1).toString().padStart(6, " ");
2998
+ console.log(lineNum + "\\t" + selected[i]);
2999
+ }
3000
+ `;
3001
+ const result = await this.execute(buildNodeScript(script, {
3002
+ PATH: pathB64,
3003
+ OFFSET: String(offset),
3004
+ LIMIT: String(limit)
3005
+ }));
3006
+ if (result.exitCode !== 0) {
3007
+ if (result.output.includes("Error: File not found")) return FILE_NOT_FOUND(filePath);
3008
+ return result.output.trim();
3009
+ }
3010
+ return result.output.trimEnd();
3011
+ }
3012
+ /**
3013
+ * Read raw file data.
3014
+ */
3015
+ async readRaw(filePath) {
3016
+ const pathB64 = toBase64(filePath);
3017
+ const result = await this.execute(buildNodeScript(`
3018
+ const fs = require("fs");
3019
+ const filePath = Buffer.from("__PATH__", "base64").toString("utf-8");
3020
+
3021
+ if (!fs.existsSync(filePath)) {
3022
+ console.error("Error: File not found");
3023
+ process.exit(1);
3024
+ }
3025
+
3026
+ const stat = fs.statSync(filePath);
3027
+ const content = fs.readFileSync(filePath, "utf-8");
3028
+
3029
+ console.log(JSON.stringify({
3030
+ content: content.split("\\n"),
3031
+ created_at: stat.birthtime.toISOString(),
3032
+ modified_at: stat.mtime.toISOString()
3033
+ }));
3034
+ `, { PATH: pathB64 }));
3035
+ if (result.exitCode !== 0) throw new Error(`File '${filePath}' not found`);
3036
+ try {
3037
+ const data = JSON.parse(result.output.trim());
3038
+ return {
3039
+ content: data.content,
3040
+ created_at: data.created_at,
3041
+ modified_at: data.modified_at
3042
+ };
3043
+ } catch {
3044
+ throw new Error(`Failed to parse file data for '${filePath}'`);
3045
+ }
3046
+ }
3047
+ /**
3048
+ * Write content to a new file.
3049
+ */
3050
+ async write(filePath, content) {
3051
+ const pathB64 = toBase64(filePath);
3052
+ const contentB64 = toBase64(content);
3053
+ const result = await this.execute(buildNodeScript(`
3054
+ const fs = require("fs");
3055
+ const path = require("path");
3056
+
3057
+ const filePath = Buffer.from("__PATH__", "base64").toString("utf-8");
3058
+ const content = Buffer.from("__CONTENT__", "base64").toString("utf-8");
3059
+
3060
+ if (fs.existsSync(filePath)) {
3061
+ console.error("Error: File already exists");
3062
+ process.exit(1);
3063
+ }
3064
+
3065
+ const dir = path.dirname(filePath);
3066
+ if (dir && dir !== ".") {
3067
+ fs.mkdirSync(dir, { recursive: true });
3068
+ }
3069
+
3070
+ fs.writeFileSync(filePath, content, "utf-8");
3071
+ `, {
3072
+ PATH: pathB64,
3073
+ CONTENT: contentB64
3074
+ }));
3075
+ if (result.exitCode !== 0) {
3076
+ if (result.output.includes("already exists")) return {
3077
+ success: false,
3078
+ error: `Cannot write to ${filePath} because it already exists. Read and then make an edit, or write to a new path.`
3079
+ };
3080
+ return {
3081
+ success: false,
3082
+ error: result.output.trim() || `Failed to write '${filePath}'`
3083
+ };
3084
+ }
3085
+ return {
3086
+ success: true,
3087
+ path: filePath
3088
+ };
3089
+ }
3090
+ /**
3091
+ * Edit a file by replacing string occurrences.
3092
+ */
3093
+ async edit(filePath, oldString, newString, replaceAll = false) {
3094
+ const pathB64 = toBase64(filePath);
3095
+ const oldB64 = toBase64(oldString);
3096
+ const newB64 = toBase64(newString);
3097
+ const result = await this.execute(buildNodeScript(`
3098
+ const fs = require("fs");
3099
+
3100
+ const filePath = Buffer.from("__PATH__", "base64").toString("utf-8");
3101
+ const oldStr = Buffer.from("__OLD__", "base64").toString("utf-8");
3102
+ const newStr = Buffer.from("__NEW__", "base64").toString("utf-8");
3103
+ const replaceAll = __REPLACE_ALL__;
3104
+
3105
+ if (!fs.existsSync(filePath)) {
3106
+ console.error("Error: File not found");
3107
+ process.exit(1);
3108
+ }
3109
+
3110
+ let content = fs.readFileSync(filePath, "utf-8");
3111
+ const count = content.split(oldStr).length - 1;
3112
+
3113
+ if (count === 0) {
3114
+ process.exit(2);
3115
+ }
3116
+ if (count > 1 && !replaceAll) {
3117
+ process.exit(3);
3118
+ }
3119
+
3120
+ if (replaceAll) {
3121
+ content = content.split(oldStr).join(newStr);
3122
+ } else {
3123
+ content = content.replace(oldStr, newStr);
3124
+ }
3125
+
3126
+ fs.writeFileSync(filePath, content, "utf-8");
3127
+ console.log(count);
3128
+ `, {
3129
+ PATH: pathB64,
3130
+ OLD: oldB64,
3131
+ NEW: newB64,
3132
+ REPLACE_ALL: String(replaceAll)
3133
+ }));
3134
+ if (result.exitCode === 1) return {
3135
+ success: false,
3136
+ error: FILE_NOT_FOUND(filePath)
3137
+ };
3138
+ if (result.exitCode === 2) return {
3139
+ success: false,
3140
+ error: STRING_NOT_FOUND(filePath, oldString)
3141
+ };
3142
+ if (result.exitCode === 3) return {
3143
+ success: false,
3144
+ error: `Error: String '${oldString}' appears multiple times. Use replaceAll=true to replace all occurrences.`
3145
+ };
3146
+ return {
3147
+ success: true,
3148
+ path: filePath,
3149
+ occurrences: parseInt(result.output.trim(), 10) || 1
3150
+ };
3151
+ }
3152
+ /**
3153
+ * Search for pattern in files.
3154
+ */
3155
+ async grepRaw(pattern, path$1 = "/", glob$1 = null) {
3156
+ const patternB64 = toBase64(pattern);
3157
+ const pathB64 = toBase64(path$1);
3158
+ const globB64 = glob$1 ? toBase64(glob$1) : toBase64("**/*");
3159
+ const result = await this.execute(buildNodeScript(`
3160
+ const fs = require("fs");
3161
+ const path = require("path");
3162
+
3163
+ const pattern = Buffer.from("__PATTERN__", "base64").toString("utf-8");
3164
+ const basePath = Buffer.from("__PATH__", "base64").toString("utf-8");
3165
+ const fileGlob = Buffer.from("__GLOB__", "base64").toString("utf-8");
3166
+
3167
+ function walkDir(dir, baseDir) {
3168
+ const results = [];
3169
+ try {
3170
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
3171
+ for (const entry of entries) {
3172
+ const fullPath = path.join(dir, entry.name);
3173
+ const relativePath = path.relative(baseDir, fullPath);
3174
+
3175
+ if (entry.isDirectory()) {
3176
+ results.push(...walkDir(fullPath, baseDir));
3177
+ } else {
3178
+ results.push(relativePath);
3179
+ }
3180
+ }
3181
+ } catch (e) {}
3182
+ return results;
3183
+ }
3184
+
3185
+ function matchGlob(filepath, pattern) {
3186
+ if (!pattern || pattern === "**/*") return true;
3187
+ const regex = pattern
3188
+ .replace(/\\./g, "\\\\.")
3189
+ .replace(/\\*\\*/g, "<<<GLOBSTAR>>>")
3190
+ .replace(/\\*/g, "[^/]*")
3191
+ .replace(/<<<GLOBSTAR>>>/g, ".*")
3192
+ .replace(/\\?/g, ".");
3193
+ return new RegExp("^" + regex + "$").test(filepath);
3194
+ }
3195
+
3196
+ const allFiles = walkDir(basePath, basePath);
3197
+ const files = allFiles.filter(f => matchGlob(f, fileGlob)).sort();
3198
+
3199
+ for (const file of files) {
3200
+ try {
3201
+ const fullPath = path.join(basePath, file);
3202
+ const content = fs.readFileSync(fullPath, "utf-8");
3203
+ const lines = content.split("\\n");
3204
+
3205
+ for (let i = 0; i < lines.length; i++) {
3206
+ if (lines[i].includes(pattern)) {
3207
+ console.log(JSON.stringify({
3208
+ path: file,
3209
+ line: i + 1,
3210
+ text: lines[i]
3211
+ }));
3212
+ }
3213
+ }
3214
+ } catch (e) {}
3215
+ }
3216
+ `, {
3217
+ PATTERN: patternB64,
3218
+ PATH: pathB64,
3219
+ GLOB: globB64
3220
+ }));
3221
+ const matches = [];
3222
+ for (const line of result.output.trim().split("\n")) {
3223
+ if (!line) continue;
3224
+ try {
3225
+ const data = JSON.parse(line);
3226
+ matches.push({
3227
+ path: data.path,
3228
+ line: data.line,
3229
+ text: data.text
3230
+ });
3231
+ } catch {}
3232
+ }
3233
+ return matches;
3234
+ }
3235
+ /**
3236
+ * Find files matching glob pattern.
3237
+ */
3238
+ async globInfo(pattern, path$1 = "/") {
3239
+ const pathB64 = toBase64(path$1);
3240
+ const patternB64 = toBase64(pattern);
3241
+ const result = await this.execute(buildNodeScript(`
3242
+ const fs = require("fs");
3243
+ const path = require("path");
3244
+
3245
+ const basePath = Buffer.from("__PATH__", "base64").toString("utf-8");
3246
+ const pattern = Buffer.from("__PATTERN__", "base64").toString("utf-8");
3247
+
3248
+ function walkDir(dir, baseDir) {
3249
+ const results = [];
3250
+ try {
3251
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
3252
+ for (const entry of entries) {
3253
+ const fullPath = path.join(dir, entry.name);
3254
+ const relativePath = path.relative(baseDir, fullPath);
3255
+
3256
+ if (entry.isDirectory()) {
3257
+ results.push(...walkDir(fullPath, baseDir));
3258
+ } else {
3259
+ results.push(relativePath);
3260
+ }
3261
+ }
3262
+ } catch (e) {}
3263
+ return results;
3264
+ }
3265
+
3266
+ function matchGlob(filepath, pattern) {
3267
+ const regex = pattern
3268
+ .replace(/\\./g, "\\\\.")
3269
+ .replace(/\\*\\*/g, "<<<GLOBSTAR>>>")
3270
+ .replace(/\\*/g, "[^/]*")
3271
+ .replace(/<<<GLOBSTAR>>>/g, ".*")
3272
+ .replace(/\\?/g, ".");
3273
+ return new RegExp("^" + regex + "$").test(filepath);
3274
+ }
3275
+
3276
+ const allFiles = walkDir(basePath, basePath);
3277
+ const matches = allFiles.filter(f => matchGlob(f, pattern)).sort();
3278
+
3279
+ for (const m of matches) {
3280
+ try {
3281
+ const fullPath = path.join(basePath, m);
3282
+ const stat = fs.statSync(fullPath);
3283
+ console.log(JSON.stringify({
3284
+ path: m,
3285
+ is_dir: stat.isDirectory(),
3286
+ size: stat.size,
3287
+ modified_at: stat.mtime.toISOString()
3288
+ }));
3289
+ } catch (e) {}
3290
+ }
3291
+ `, {
3292
+ PATH: pathB64,
3293
+ PATTERN: patternB64
3294
+ }));
3295
+ const infos = [];
3296
+ for (const line of result.output.trim().split("\n")) {
3297
+ if (!line) continue;
3298
+ try {
3299
+ const data = JSON.parse(line);
3300
+ infos.push({
3301
+ path: data.path,
3302
+ is_dir: data.is_dir,
3303
+ size: data.size,
3304
+ modified_at: data.modified_at
3305
+ });
3306
+ } catch {}
3307
+ }
3308
+ return infos;
3309
+ }
3310
+ };
3311
+
3312
+ //#endregion
3313
+ //#region src/backends/local-sandbox.ts
3314
+ /**
3315
+ * LocalSandbox: Execute commands locally using child_process.
3316
+ *
3317
+ * Useful for local development and testing without cloud sandboxes.
3318
+ * All file operations are inherited from BaseSandbox and executed
3319
+ * via shell commands in the local filesystem.
3320
+ */
3321
+ /**
3322
+ * Local sandbox that executes commands using Node.js child_process.
3323
+ *
3324
+ * All commands are executed in a bash shell with the specified working directory.
3325
+ * Inherits all file operations (read, write, edit, ls, grep, glob) from BaseSandbox.
3326
+ *
3327
+ * @example Basic usage
3328
+ * ```typescript
3329
+ * import { LocalSandbox } from 'deepagentsdk';
3330
+ *
3331
+ * const sandbox = new LocalSandbox({ cwd: './workspace' });
3332
+ *
3333
+ * // Execute commands
3334
+ * const result = await sandbox.execute('ls -la');
3335
+ * console.log(result.output);
3336
+ *
3337
+ * // File operations
3338
+ * await sandbox.write('./src/index.ts', 'console.log("hello")');
3339
+ * const content = await sandbox.read('./src/index.ts');
3340
+ * ```
3341
+ *
3342
+ * @example With timeout and environment
3343
+ * ```typescript
3344
+ * const sandbox = new LocalSandbox({
3345
+ * cwd: './workspace',
3346
+ * timeout: 60000, // 60 seconds
3347
+ * env: {
3348
+ * NODE_ENV: 'development',
3349
+ * DEBUG: '*',
3350
+ * },
3351
+ * });
3352
+ * ```
3353
+ *
3354
+ * @example Error handling
3355
+ * ```typescript
3356
+ * const result = await sandbox.execute('npm test');
3357
+ * if (result.exitCode !== 0) {
3358
+ * console.error('Tests failed:', result.output);
3359
+ * }
3360
+ * ```
3361
+ */
3362
+ var LocalSandbox = class extends BaseSandbox {
3363
+ cwd;
3364
+ timeout;
3365
+ env;
3366
+ maxOutputSize;
3367
+ _id;
3368
+ /**
3369
+ * Create a new LocalSandbox instance.
3370
+ *
3371
+ * @param options - Configuration options for the sandbox
3372
+ */
3373
+ constructor(options = {}) {
3374
+ super();
3375
+ this.cwd = options.cwd || process.cwd();
3376
+ this.timeout = options.timeout || 3e4;
3377
+ this.env = options.env || {};
3378
+ this.maxOutputSize = options.maxOutputSize || 1024 * 1024;
3379
+ this._id = `local-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
3380
+ }
3381
+ /**
3382
+ * Unique identifier for this sandbox instance.
3383
+ * Format: `local-{timestamp}-{random}`
3384
+ */
3385
+ get id() {
3386
+ return this._id;
3387
+ }
3388
+ /**
3389
+ * Execute a shell command in the local filesystem.
3390
+ *
3391
+ * Commands are executed using bash with the configured working directory
3392
+ * and environment variables. Output is captured from both stdout and stderr.
3393
+ *
3394
+ * @param command - Shell command to execute
3395
+ * @returns ExecuteResponse with output, exit code, and truncation status
3396
+ *
3397
+ * @example
3398
+ * ```typescript
3399
+ * const result = await sandbox.execute('echo "Hello" && ls -la');
3400
+ * console.log(result.output);
3401
+ * console.log('Exit code:', result.exitCode);
3402
+ * ```
3403
+ */
3404
+ async execute(command) {
3405
+ return new Promise((resolve) => {
3406
+ const child = (0, child_process.spawn)("bash", ["-c", command], {
3407
+ cwd: this.cwd,
3408
+ env: {
3409
+ ...process.env,
3410
+ ...this.env
3411
+ },
3412
+ timeout: this.timeout
3413
+ });
3414
+ let output = "";
3415
+ let truncated = false;
3416
+ child.stdout.on("data", (data) => {
3417
+ if (output.length < this.maxOutputSize) output += data.toString();
3418
+ else truncated = true;
3419
+ });
3420
+ child.stderr.on("data", (data) => {
3421
+ if (output.length < this.maxOutputSize) output += data.toString();
3422
+ else truncated = true;
3423
+ });
3424
+ child.on("close", (code) => {
3425
+ resolve({
3426
+ output,
3427
+ exitCode: code,
3428
+ truncated
3429
+ });
3430
+ });
3431
+ child.on("error", (err) => {
3432
+ resolve({
3433
+ output: `Error: ${err.message}`,
3434
+ exitCode: 1,
3435
+ truncated: false
3436
+ });
3437
+ });
3438
+ });
3439
+ }
3440
+ };
3441
+
3442
+ //#endregion
3443
+ //#region src/utils/model-parser.ts
3444
+ /**
3445
+ * Utility to parse model strings into LanguageModel instances.
3446
+ * Provides backward compatibility for CLI and other string-based model specifications.
3447
+ */
3448
+ /**
3449
+ * Parse a model string into a LanguageModel instance.
3450
+ *
3451
+ * Supports formats like:
3452
+ * - "anthropic/claude-sonnet-4-20250514"
3453
+ * - "openai/gpt-4o"
3454
+ * - "claude-sonnet-4-20250514" (defaults to Anthropic)
3455
+ *
3456
+ * @param modelString - The model string to parse
3457
+ * @returns A LanguageModel instance
3458
+ *
3459
+ * @example
3460
+ * ```typescript
3461
+ * const model = parseModelString("anthropic/claude-sonnet-4-20250514");
3462
+ * const agent = createDeepAgent({ model });
3463
+ * ```
3464
+ */
3465
+ function parseModelString(modelString) {
3466
+ const [provider, modelName] = modelString.split("/");
3467
+ if (provider === "anthropic") return (0, _ai_sdk_anthropic.anthropic)(modelName || "claude-sonnet-4-20250514");
3468
+ else if (provider === "openai") return (0, _ai_sdk_openai.openai)(modelName || "gpt-5-mini");
3469
+ return (0, _ai_sdk_anthropic.anthropic)(modelString);
3470
+ }
3471
+
3472
+ //#endregion
3473
+ //#region src/checkpointer/file-saver.ts
3474
+ /**
3475
+ * File-based checkpoint saver for local development.
3476
+ */
3477
+ /**
3478
+ * File-based checkpoint saver.
3479
+ *
3480
+ * Stores checkpoints as JSON files in a directory. Each thread gets
3481
+ * its own file named `{threadId}.json`.
3482
+ *
3483
+ * @example
3484
+ * ```typescript
3485
+ * const saver = new FileSaver({ dir: './.checkpoints' });
3486
+ * const agent = createDeepAgent({
3487
+ * model: anthropic('claude-sonnet-4-20250514'),
3488
+ * checkpointer: saver,
3489
+ * });
3490
+ * ```
3491
+ */
3492
+ var FileSaver = class {
3493
+ dir;
3494
+ constructor(options) {
3495
+ this.dir = options.dir;
3496
+ if (!(0, node_fs.existsSync)(this.dir)) (0, node_fs.mkdirSync)(this.dir, { recursive: true });
3497
+ }
3498
+ getFilePath(threadId) {
3499
+ const safeId = threadId.replace(/[^a-zA-Z0-9_-]/g, "_");
3500
+ return (0, node_path.join)(this.dir, `${safeId}.json`);
3501
+ }
3502
+ async save(checkpoint) {
3503
+ const filePath = this.getFilePath(checkpoint.threadId);
3504
+ const data = {
3505
+ ...checkpoint,
3506
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
3507
+ };
3508
+ (0, node_fs.writeFileSync)(filePath, JSON.stringify(data, null, 2), "utf-8");
3509
+ }
3510
+ async load(threadId) {
3511
+ const filePath = this.getFilePath(threadId);
3512
+ if (!(0, node_fs.existsSync)(filePath)) return;
3513
+ try {
3514
+ const content = (0, node_fs.readFileSync)(filePath, "utf-8");
3515
+ return JSON.parse(content);
3516
+ } catch {
3517
+ return;
3518
+ }
3519
+ }
3520
+ async list() {
3521
+ if (!(0, node_fs.existsSync)(this.dir)) return [];
3522
+ return (0, node_fs.readdirSync)(this.dir).filter((f) => f.endsWith(".json")).map((f) => f.replace(".json", ""));
3523
+ }
3524
+ async delete(threadId) {
3525
+ const filePath = this.getFilePath(threadId);
3526
+ if ((0, node_fs.existsSync)(filePath)) (0, node_fs.unlinkSync)(filePath);
3527
+ }
3528
+ async exists(threadId) {
3529
+ return (0, node_fs.existsSync)(this.getFilePath(threadId));
3530
+ }
3531
+ };
3532
+
3533
+ //#endregion
3534
+ Object.defineProperty(exports, 'BASE_PROMPT', {
3535
+ enumerable: true,
3536
+ get: function () {
3537
+ return BASE_PROMPT;
3538
+ }
3539
+ });
3540
+ Object.defineProperty(exports, 'BaseSandbox', {
3541
+ enumerable: true,
3542
+ get: function () {
3543
+ return BaseSandbox;
3544
+ }
3545
+ });
3546
+ Object.defineProperty(exports, 'CONTEXT_WINDOW', {
3547
+ enumerable: true,
3548
+ get: function () {
3549
+ return CONTEXT_WINDOW;
3550
+ }
3551
+ });
3552
+ Object.defineProperty(exports, 'DEFAULT_EVICTION_TOKEN_LIMIT', {
3553
+ enumerable: true,
3554
+ get: function () {
3555
+ return DEFAULT_EVICTION_TOKEN_LIMIT;
3556
+ }
3557
+ });
3558
+ Object.defineProperty(exports, 'DEFAULT_EVICTION_TOKEN_LIMIT$1', {
3559
+ enumerable: true,
3560
+ get: function () {
3561
+ return DEFAULT_EVICTION_TOKEN_LIMIT$1;
3562
+ }
3563
+ });
3564
+ Object.defineProperty(exports, 'DEFAULT_GENERAL_PURPOSE_DESCRIPTION', {
3565
+ enumerable: true,
3566
+ get: function () {
3567
+ return DEFAULT_GENERAL_PURPOSE_DESCRIPTION;
3568
+ }
3569
+ });
3570
+ Object.defineProperty(exports, 'DEFAULT_KEEP_MESSAGES', {
3571
+ enumerable: true,
3572
+ get: function () {
3573
+ return DEFAULT_KEEP_MESSAGES;
3574
+ }
3575
+ });
3576
+ Object.defineProperty(exports, 'DEFAULT_KEEP_MESSAGES$1', {
3577
+ enumerable: true,
3578
+ get: function () {
3579
+ return DEFAULT_KEEP_MESSAGES$1;
3580
+ }
3581
+ });
3582
+ Object.defineProperty(exports, 'DEFAULT_READ_LIMIT', {
3583
+ enumerable: true,
3584
+ get: function () {
3585
+ return DEFAULT_READ_LIMIT;
3586
+ }
3587
+ });
3588
+ Object.defineProperty(exports, 'DEFAULT_SUBAGENT_PROMPT', {
3589
+ enumerable: true,
3590
+ get: function () {
3591
+ return DEFAULT_SUBAGENT_PROMPT;
3592
+ }
3593
+ });
3594
+ Object.defineProperty(exports, 'DEFAULT_SUMMARIZATION_THRESHOLD', {
3595
+ enumerable: true,
3596
+ get: function () {
3597
+ return DEFAULT_SUMMARIZATION_THRESHOLD;
3598
+ }
3599
+ });
3600
+ Object.defineProperty(exports, 'DEFAULT_SUMMARIZATION_THRESHOLD$1', {
3601
+ enumerable: true,
3602
+ get: function () {
3603
+ return DEFAULT_SUMMARIZATION_THRESHOLD$1;
3604
+ }
3605
+ });
3606
+ Object.defineProperty(exports, 'DeepAgent', {
3607
+ enumerable: true,
3608
+ get: function () {
3609
+ return DeepAgent;
3610
+ }
3611
+ });
3612
+ Object.defineProperty(exports, 'EXECUTE_SYSTEM_PROMPT', {
3613
+ enumerable: true,
3614
+ get: function () {
3615
+ return EXECUTE_SYSTEM_PROMPT;
3616
+ }
3617
+ });
3618
+ Object.defineProperty(exports, 'FILESYSTEM_SYSTEM_PROMPT', {
3619
+ enumerable: true,
3620
+ get: function () {
3621
+ return FILESYSTEM_SYSTEM_PROMPT;
3622
+ }
3623
+ });
3624
+ Object.defineProperty(exports, 'FILE_ALREADY_EXISTS', {
3625
+ enumerable: true,
3626
+ get: function () {
3627
+ return FILE_ALREADY_EXISTS;
3628
+ }
3629
+ });
3630
+ Object.defineProperty(exports, 'FILE_NOT_FOUND', {
3631
+ enumerable: true,
3632
+ get: function () {
3633
+ return FILE_NOT_FOUND;
3634
+ }
3635
+ });
3636
+ Object.defineProperty(exports, 'FileSaver', {
3637
+ enumerable: true,
3638
+ get: function () {
3639
+ return FileSaver;
3640
+ }
3641
+ });
3642
+ Object.defineProperty(exports, 'LocalSandbox', {
3643
+ enumerable: true,
3644
+ get: function () {
3645
+ return LocalSandbox;
3646
+ }
3647
+ });
3648
+ Object.defineProperty(exports, 'MAX_FILE_SIZE_MB', {
3649
+ enumerable: true,
3650
+ get: function () {
3651
+ return MAX_FILE_SIZE_MB;
3652
+ }
3653
+ });
3654
+ Object.defineProperty(exports, 'StateBackend', {
3655
+ enumerable: true,
3656
+ get: function () {
3657
+ return StateBackend;
3658
+ }
3659
+ });
3660
+ Object.defineProperty(exports, 'TASK_SYSTEM_PROMPT', {
3661
+ enumerable: true,
3662
+ get: function () {
3663
+ return TASK_SYSTEM_PROMPT;
3664
+ }
3665
+ });
3666
+ Object.defineProperty(exports, 'TODO_SYSTEM_PROMPT', {
3667
+ enumerable: true,
3668
+ get: function () {
3669
+ return TODO_SYSTEM_PROMPT;
3670
+ }
3671
+ });
3672
+ Object.defineProperty(exports, 'checkEmptyContent', {
3673
+ enumerable: true,
3674
+ get: function () {
3675
+ return checkEmptyContent;
3676
+ }
3677
+ });
3678
+ Object.defineProperty(exports, 'createDeepAgent', {
3679
+ enumerable: true,
3680
+ get: function () {
3681
+ return createDeepAgent;
3682
+ }
3683
+ });
3684
+ Object.defineProperty(exports, 'createEditFileTool', {
3685
+ enumerable: true,
3686
+ get: function () {
3687
+ return createEditFileTool;
3688
+ }
3689
+ });
3690
+ Object.defineProperty(exports, 'createExecuteTool', {
3691
+ enumerable: true,
3692
+ get: function () {
3693
+ return createExecuteTool;
3694
+ }
3695
+ });
3696
+ Object.defineProperty(exports, 'createExecuteToolFromBackend', {
3697
+ enumerable: true,
3698
+ get: function () {
3699
+ return createExecuteToolFromBackend;
3700
+ }
3701
+ });
3702
+ Object.defineProperty(exports, 'createFetchUrlTool', {
3703
+ enumerable: true,
3704
+ get: function () {
3705
+ return createFetchUrlTool;
3706
+ }
3707
+ });
3708
+ Object.defineProperty(exports, 'createFileData', {
3709
+ enumerable: true,
3710
+ get: function () {
3711
+ return createFileData;
3712
+ }
3713
+ });
3714
+ Object.defineProperty(exports, 'createFilesystemTools', {
3715
+ enumerable: true,
3716
+ get: function () {
3717
+ return createFilesystemTools;
3718
+ }
3719
+ });
3720
+ Object.defineProperty(exports, 'createGlobTool', {
3721
+ enumerable: true,
3722
+ get: function () {
3723
+ return createGlobTool;
3724
+ }
3725
+ });
3726
+ Object.defineProperty(exports, 'createGrepTool', {
3727
+ enumerable: true,
3728
+ get: function () {
3729
+ return createGrepTool;
3730
+ }
3731
+ });
3732
+ Object.defineProperty(exports, 'createHttpRequestTool', {
3733
+ enumerable: true,
3734
+ get: function () {
3735
+ return createHttpRequestTool;
3736
+ }
3737
+ });
3738
+ Object.defineProperty(exports, 'createLsTool', {
3739
+ enumerable: true,
3740
+ get: function () {
3741
+ return createLsTool;
3742
+ }
3743
+ });
3744
+ Object.defineProperty(exports, 'createReadFileTool', {
3745
+ enumerable: true,
3746
+ get: function () {
3747
+ return createReadFileTool;
3748
+ }
3749
+ });
3750
+ Object.defineProperty(exports, 'createSubagentTool', {
3751
+ enumerable: true,
3752
+ get: function () {
3753
+ return createSubagentTool;
3754
+ }
3755
+ });
3756
+ Object.defineProperty(exports, 'createTodosTool', {
3757
+ enumerable: true,
3758
+ get: function () {
3759
+ return createTodosTool;
3760
+ }
3761
+ });
3762
+ Object.defineProperty(exports, 'createToolResultWrapper', {
3763
+ enumerable: true,
3764
+ get: function () {
3765
+ return createToolResultWrapper;
3766
+ }
3767
+ });
3768
+ Object.defineProperty(exports, 'createWebSearchTool', {
3769
+ enumerable: true,
3770
+ get: function () {
3771
+ return createWebSearchTool;
3772
+ }
3773
+ });
3774
+ Object.defineProperty(exports, 'createWebTools', {
3775
+ enumerable: true,
3776
+ get: function () {
3777
+ return createWebTools;
3778
+ }
3779
+ });
3780
+ Object.defineProperty(exports, 'createWriteFileTool', {
3781
+ enumerable: true,
3782
+ get: function () {
3783
+ return createWriteFileTool;
3784
+ }
3785
+ });
3786
+ Object.defineProperty(exports, 'edit_file', {
3787
+ enumerable: true,
3788
+ get: function () {
3789
+ return edit_file;
3790
+ }
3791
+ });
3792
+ Object.defineProperty(exports, 'estimateMessagesTokens', {
3793
+ enumerable: true,
3794
+ get: function () {
3795
+ return estimateMessagesTokens;
3796
+ }
3797
+ });
3798
+ Object.defineProperty(exports, 'estimateTokens', {
3799
+ enumerable: true,
3800
+ get: function () {
3801
+ return estimateTokens;
3802
+ }
3803
+ });
3804
+ Object.defineProperty(exports, 'evictToolResult', {
3805
+ enumerable: true,
3806
+ get: function () {
3807
+ return evictToolResult;
3808
+ }
3809
+ });
3810
+ Object.defineProperty(exports, 'execute', {
3811
+ enumerable: true,
3812
+ get: function () {
3813
+ return execute;
3814
+ }
3815
+ });
3816
+ Object.defineProperty(exports, 'fetch_url', {
3817
+ enumerable: true,
3818
+ get: function () {
3819
+ return fetch_url;
3820
+ }
3821
+ });
3822
+ Object.defineProperty(exports, 'fileDataToString', {
3823
+ enumerable: true,
3824
+ get: function () {
3825
+ return fileDataToString;
3826
+ }
3827
+ });
3828
+ Object.defineProperty(exports, 'formatContentWithLineNumbers', {
3829
+ enumerable: true,
3830
+ get: function () {
3831
+ return formatContentWithLineNumbers;
3832
+ }
3833
+ });
3834
+ Object.defineProperty(exports, 'formatReadResponse', {
3835
+ enumerable: true,
3836
+ get: function () {
3837
+ return formatReadResponse;
3838
+ }
3839
+ });
3840
+ Object.defineProperty(exports, 'getTaskToolDescription', {
3841
+ enumerable: true,
3842
+ get: function () {
3843
+ return getTaskToolDescription;
3844
+ }
3845
+ });
3846
+ Object.defineProperty(exports, 'glob', {
3847
+ enumerable: true,
3848
+ get: function () {
3849
+ return glob;
3850
+ }
3851
+ });
3852
+ Object.defineProperty(exports, 'globSearchFiles', {
3853
+ enumerable: true,
3854
+ get: function () {
3855
+ return globSearchFiles;
3856
+ }
3857
+ });
3858
+ Object.defineProperty(exports, 'grep', {
3859
+ enumerable: true,
3860
+ get: function () {
3861
+ return grep;
3862
+ }
3863
+ });
3864
+ Object.defineProperty(exports, 'grepMatchesFromFiles', {
3865
+ enumerable: true,
3866
+ get: function () {
3867
+ return grepMatchesFromFiles;
3868
+ }
3869
+ });
3870
+ Object.defineProperty(exports, 'hasDanglingToolCalls', {
3871
+ enumerable: true,
3872
+ get: function () {
3873
+ return hasDanglingToolCalls;
3874
+ }
3875
+ });
3876
+ Object.defineProperty(exports, 'htmlToMarkdown', {
3877
+ enumerable: true,
3878
+ get: function () {
3879
+ return htmlToMarkdown;
3880
+ }
3881
+ });
3882
+ Object.defineProperty(exports, 'http_request', {
3883
+ enumerable: true,
3884
+ get: function () {
3885
+ return http_request;
3886
+ }
3887
+ });
3888
+ Object.defineProperty(exports, 'init_errors', {
3889
+ enumerable: true,
3890
+ get: function () {
3891
+ return init_errors;
3892
+ }
3893
+ });
3894
+ Object.defineProperty(exports, 'init_eviction', {
3895
+ enumerable: true,
3896
+ get: function () {
3897
+ return init_eviction;
3898
+ }
3899
+ });
3900
+ Object.defineProperty(exports, 'init_limits', {
3901
+ enumerable: true,
3902
+ get: function () {
3903
+ return init_limits;
3904
+ }
3905
+ });
3906
+ Object.defineProperty(exports, 'init_web', {
3907
+ enumerable: true,
3908
+ get: function () {
3909
+ return init_web;
3910
+ }
3911
+ });
3912
+ Object.defineProperty(exports, 'isSandboxBackend', {
3913
+ enumerable: true,
3914
+ get: function () {
3915
+ return isSandboxBackend;
3916
+ }
3917
+ });
3918
+ Object.defineProperty(exports, 'ls', {
3919
+ enumerable: true,
3920
+ get: function () {
3921
+ return ls;
3922
+ }
3923
+ });
3924
+ Object.defineProperty(exports, 'needsSummarization', {
3925
+ enumerable: true,
3926
+ get: function () {
3927
+ return needsSummarization;
3928
+ }
3929
+ });
3930
+ Object.defineProperty(exports, 'parseModelString', {
3931
+ enumerable: true,
3932
+ get: function () {
3933
+ return parseModelString;
3934
+ }
3935
+ });
3936
+ Object.defineProperty(exports, 'patchToolCalls', {
3937
+ enumerable: true,
3938
+ get: function () {
3939
+ return patchToolCalls;
3940
+ }
3941
+ });
3942
+ Object.defineProperty(exports, 'performStringReplacement', {
3943
+ enumerable: true,
3944
+ get: function () {
3945
+ return performStringReplacement;
3946
+ }
3947
+ });
3948
+ Object.defineProperty(exports, 'read_file', {
3949
+ enumerable: true,
3950
+ get: function () {
3951
+ return read_file;
3952
+ }
3953
+ });
3954
+ Object.defineProperty(exports, 'shouldEvict', {
3955
+ enumerable: true,
3956
+ get: function () {
3957
+ return shouldEvict;
3958
+ }
3959
+ });
3960
+ Object.defineProperty(exports, 'summarizeIfNeeded', {
3961
+ enumerable: true,
3962
+ get: function () {
3963
+ return summarizeIfNeeded;
3964
+ }
3965
+ });
3966
+ Object.defineProperty(exports, 'updateFileData', {
3967
+ enumerable: true,
3968
+ get: function () {
3969
+ return updateFileData;
3970
+ }
3971
+ });
3972
+ Object.defineProperty(exports, 'web_search', {
3973
+ enumerable: true,
3974
+ get: function () {
3975
+ return web_search;
3976
+ }
3977
+ });
3978
+ Object.defineProperty(exports, 'write_file', {
3979
+ enumerable: true,
3980
+ get: function () {
3981
+ return write_file;
3982
+ }
3983
+ });
3984
+ Object.defineProperty(exports, 'write_todos', {
3985
+ enumerable: true,
3986
+ get: function () {
3987
+ return write_todos;
3988
+ }
3989
+ });
3990
+ //# sourceMappingURL=file-saver-BYPKakT4.cjs.map