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