@deepagents/toolbox 0.1.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.
package/dist/index.js ADDED
@@ -0,0 +1,1055 @@
1
+ // packages/toolbox/src/lib/container.ts
2
+ import { tool } from "ai";
3
+ import spawn from "nano-spawn";
4
+ import { z } from "zod";
5
+ var execute_os_command = tool({
6
+ description: "Tool to execute Linux commands in an isolated Docker container with Node.js runtime. Use when you need OS operations like file management, package installation, network requests, or system commands.",
7
+ inputSchema: z.object({
8
+ command: z.array(z.string().min(1, "Command parts cannot be empty")).min(1, "At least one command part is required").max(20, "Command cannot exceed 20 parts for security").describe(
9
+ 'Command and arguments as array. Examples: ["ls", "-la"], ["npm", "install", "lodash"], ["curl", "-s", "https://api.github.com"], ["node", "--version"]'
10
+ ),
11
+ working_directory: z.string().regex(/^\/[a-zA-Z0-9_/.,-]*$/, "Must be a valid absolute Linux path").optional().describe(
12
+ 'Absolute working directory path. Examples: "/tmp", "/workspace", "/app". Defaults to container root.'
13
+ ),
14
+ environment_vars: z.record(
15
+ z.string().min(1, "Environment variable values cannot be empty"),
16
+ z.string()
17
+ ).optional().describe(
18
+ 'Environment variables as key-value pairs. Examples: {"NODE_ENV": "development", "API_KEY": "secret123"}'
19
+ )
20
+ }),
21
+ execute: ({ command, working_directory, environment_vars }) => {
22
+ return exec(command, working_directory, environment_vars);
23
+ }
24
+ });
25
+ function exec(command, working_directory, environment_vars) {
26
+ const args = ["exec", "-i"];
27
+ if (working_directory) {
28
+ args.push("-w", working_directory);
29
+ }
30
+ if (environment_vars) {
31
+ Object.entries(environment_vars).forEach(([key, value]) => {
32
+ args.push("-e", `${key}=${value}`);
33
+ });
34
+ }
35
+ args.push("toolos", ...command);
36
+ return spawn("docker", args, {
37
+ stdio: "pipe"
38
+ });
39
+ }
40
+
41
+ // packages/toolbox/src/lib/ddg-search.ts
42
+ import { tool as tool2 } from "ai";
43
+ import * as ddg from "duck-duck-scrape";
44
+ import { uniqBy } from "lodash-es";
45
+ import { z as z2 } from "zod";
46
+ async function serp({
47
+ query,
48
+ source,
49
+ locale = "en-us",
50
+ maxResults = 50,
51
+ ...input
52
+ }) {
53
+ const safeSearch = ddg.SafeSearchType[
54
+ "STRICT"
55
+ // input.safesearch.toUpperCase() as keyof typeof ddg.SafeSearchType
56
+ ];
57
+ const time = ddg.SearchTimeType[(input.time || "y")?.toUpperCase()];
58
+ if (source === "text") {
59
+ const res2 = await ddg.search(
60
+ query,
61
+ {
62
+ region: "wt-wt",
63
+ safeSearch,
64
+ time,
65
+ locale
66
+ },
67
+ {
68
+ uri_modifier: (rawUrl) => {
69
+ const url = new URL(rawUrl);
70
+ url.searchParams.delete("ss_mkt");
71
+ return url.toString();
72
+ }
73
+ }
74
+ );
75
+ const items2 = res2.results.slice(0, maxResults).map((r) => ({
76
+ snippet: r.description,
77
+ title: r.title,
78
+ link: r.url,
79
+ hostname: r.hostname
80
+ }));
81
+ return { items: items2, total: res2.results.length, vqd: res2.vqd };
82
+ }
83
+ if (source === "news") {
84
+ const res2 = await ddg.searchNews(query, {
85
+ safeSearch,
86
+ time
87
+ });
88
+ const items2 = res2.results.slice(0, maxResults).map((r) => ({
89
+ snippet: r.excerpt,
90
+ title: r.title,
91
+ link: r.url,
92
+ date: r.date,
93
+ // epoch ms
94
+ source: r.syndicate,
95
+ image: r.image,
96
+ relativeTime: r.relativeTime
97
+ }));
98
+ return { items: items2, total: res2.results.length, vqd: res2.vqd };
99
+ }
100
+ const res = await ddg.searchImages(query, { safeSearch });
101
+ const items = res.results.slice(0, maxResults).map((r) => ({
102
+ title: r.title,
103
+ thumbnail: r.thumbnail,
104
+ image: r.image,
105
+ link: r.url,
106
+ height: r.height,
107
+ width: r.width,
108
+ source: r.source
109
+ }));
110
+ return { items, total: res.results.length, vqd: res.vqd };
111
+ }
112
+ var ddgSearchSchema = z2.object({
113
+ query: z2.string().min(1),
114
+ source: z2.enum(["text", "news", "images"]).default("text"),
115
+ locale: z2.string().optional().default("en-us"),
116
+ // region: z.string().default('wt-wt'),
117
+ // safesearch: z.enum(['strict', 'moderate', 'off']).default('moderate'),
118
+ time: z2.enum(["d", "w", "m", "y"]).optional().default("y"),
119
+ maxResults: z2.number().int().positive().max(50).default(5)
120
+ });
121
+ var duckDuckGoSearch = tool2({
122
+ description: "A tool for searching the web. Useful for when you need to find information about current events or topics that are not covered in your training data.",
123
+ inputSchema: ddgSearchSchema,
124
+ execute: serp
125
+ });
126
+
127
+ // packages/toolbox/src/lib/ddg-stocks.ts
128
+ import { tool as tool3 } from "ai";
129
+ import { stocks as ddgStocks } from "duck-duck-scrape";
130
+ import { z as z3 } from "zod";
131
+ var toQuote = (r) => ({
132
+ symbol: r?.Security?.Symbol ?? null,
133
+ name: r?.Security?.Name ?? null,
134
+ exchange: r?.Security?.Market ?? null,
135
+ currency: r?.Currency ?? null,
136
+ last: r?.Last ?? null,
137
+ change: r?.ChangeFromPreviousClose ?? null,
138
+ percentChange: r?.PercentChangeFromPreviousClose ?? null,
139
+ open: r?.Open ?? null,
140
+ high: r?.High ?? null,
141
+ low: r?.Low ?? null,
142
+ prevClose: r?.PreviousClose ?? null,
143
+ volume: r?.Volume ?? null,
144
+ date: r?.Date ?? null,
145
+ time: r?.Time ?? null,
146
+ halted: r?.TradingHalted ?? null,
147
+ source: "DuckDuckGo/Xignite",
148
+ raw: r
149
+ });
150
+ var duckStocks = tool3({
151
+ description: "A tool for fetching stock market quotes. Useful for when you need to get the latest stock price and related information for one or more stock symbols.",
152
+ inputSchema: z3.object({
153
+ symbols: z3.union([z3.string().min(1), z3.array(z3.string().min(1)).min(1)]).transform((s) => Array.isArray(s) ? s : [s]),
154
+ includeRaw: z3.boolean().default(false)
155
+ }),
156
+ execute: async ({ symbols, includeRaw }) => {
157
+ const tasks = symbols.map(async (s) => {
158
+ const sym = s.trim().toUpperCase();
159
+ try {
160
+ const r = await ddgStocks(sym);
161
+ if (!r || r.Outcome && r.Outcome !== "Success") {
162
+ return { symbol: sym, error: r?.Message || "No quote" };
163
+ }
164
+ const q = toQuote(r);
165
+ if (!includeRaw) delete q.raw;
166
+ return q;
167
+ } catch (e) {
168
+ return { symbol: sym, error: e?.message || "fetch_failed" };
169
+ }
170
+ });
171
+ const results = await Promise.all(tasks);
172
+ return { results };
173
+ }
174
+ });
175
+
176
+ // packages/toolbox/src/lib/scratchbad.ts
177
+ import { tool as tool5 } from "ai";
178
+ import z5 from "zod";
179
+
180
+ // packages/agent/dist/index.js
181
+ import {
182
+ Output as Output2,
183
+ dynamicTool,
184
+ generateText as generateText2,
185
+ jsonSchema,
186
+ stepCountIs as stepCountIs2,
187
+ tool as tool4
188
+ } from "ai";
189
+ import chalk2 from "chalk";
190
+ import { snakecase } from "stringcase";
191
+ import z4 from "zod";
192
+ import dedent from "dedent";
193
+ import {
194
+ generateId
195
+ } from "ai";
196
+ import { flow } from "lodash-es";
197
+ import { createInterface } from "node:readline/promises";
198
+ import { titlecase } from "stringcase";
199
+ import { groq } from "@ai-sdk/groq";
200
+ import {
201
+ NoSuchToolError,
202
+ Output,
203
+ convertToModelMessages,
204
+ createUIMessageStream,
205
+ generateId as generateId2,
206
+ generateText,
207
+ smoothStream,
208
+ stepCountIs,
209
+ streamText,
210
+ wrapLanguageModel
211
+ } from "ai";
212
+ import chalk from "chalk";
213
+ import dedent2 from "dedent";
214
+ import { zodToJsonSchema } from "zod-to-json-schema";
215
+ import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
216
+ import { embedMany } from "ai";
217
+ var RECOMMENDED_PROMPT_PREFIX = [
218
+ `# System context`,
219
+ `You are part of a multi-agent system called the DeepAgents SDK, designed to make agent coordination and execution easy.`,
220
+ `Agents uses two primary abstraction: **Agents** and **Handoffs**.`,
221
+ `An agent encompasses instructions and tools and can hand off a conversation to another agent when appropriate.`,
222
+ `Handoffs are achieved by calling a handoff function, generally named \`transfer_to_<agent_name>\`.`,
223
+ `Transfers between agents are handled seamlessly in the background; do not mention or draw attention to these transfers in your conversation with the user.`
224
+ // 'Do not pass context between agents. the agents already have the complete context without agent to agent communication.',
225
+ // From 4.1 beast mode
226
+ // `Please keep going until the user’s query is completely resolved, before ending your turn and yielding back to the user.`,
227
+ // `Your thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.`,
228
+ // `You MUST iterate and keep going until the problem is solved.`,
229
+ // `You have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.`,
230
+ // `Only terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.`,
231
+ // `Always tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.`,
232
+ // `If the user request is "resume" or "continue" or "try again", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.`,
233
+ // `Take your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.`,
234
+ // `You MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.`,
235
+ // `You MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say "Next I will do X" or "Now I will do Y" or "I will do X", you MUST actually do X or Y instead just saying that you will do it.`,
236
+ // `You are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.`,
237
+ ].join("\n");
238
+ var SUPERVISOR_PROMPT_PREFIX = dedent`
239
+ # System Context
240
+ You are part of a multi-agent system called the DeepAgents SDK, designed to facilitate agent coordination and execution.
241
+
242
+ - The primary agent, known as the "Supervisor Agent," coordinates communication between specialized agents. The Supervisor Agent does not perform specialized tasks but acts as the central point for communication.
243
+ - Specialized agents must transfer control back to the Supervisor Agent upon completing their tasks.
244
+
245
+ **Core Directives:**
246
+ - Begin with a concise checklist (3-7 bullets) of what you will do for each user query; items should be conceptual, not implementation-level.
247
+ - Continue working until the user's query is completely resolved; only then yield control back to the user.
248
+ - Your thinking must be thorough and step-by-step. Aim for completeness and rigor while avoiding unnecessary repetition and verbosity.
249
+ - You must iterate and keep working until the problem is fully solved. You have all the requirements and information needed; solve the problem autonomously without user intervention.
250
+ - Do not terminate your turn unless you are certain all issues are resolved and the entire todo list is complete and verified.
251
+ - When making tool calls, explicitly state, in a single concise sentence, the purpose and minimal inputs for the action before executing it.
252
+ - After each tool call or code edit, validate the result in 1-2 lines and proceed or self-correct if validation fails.
253
+ - For requests such as "resume", "continue", or "try again":
254
+ - Check previous conversation history to determine the next incomplete todo step, continue from there, and do not return control until all items are complete.
255
+ - Inform the user you are resuming from the last incomplete step, and specify what that step is.
256
+ - Take your time and rigorously check your solution, especially edge and boundary cases. Use sequential thinking tools when available. Your solution must be robust and perfect; continue iterating and retesting as needed.
257
+ - Always test your code using all available tools and provided tests, with repetition as necessary to catch edge cases.
258
+ - Plan extensively before each function/tool call and reflect thoroughly on previous actions before proceeding. Do not proceed solely by chaining function calls—use stepwise planning and reflection.
259
+ - Explicitly complete every todo list item and confirm all steps are working before ending your turn. Always follow through on stated actions.
260
+ - You are a highly capable, autonomous agent, and should not require additional user input to fully solve the task.
261
+ `;
262
+ function visualizeMermaid(root, options = {}) {
263
+ const { direction = "LR", showTools = true } = options;
264
+ const nodes = [];
265
+ const edges = [];
266
+ const seen = /* @__PURE__ */ new Set();
267
+ const nameToId = /* @__PURE__ */ new Map();
268
+ const sanitizeId = (name) => name.toLowerCase().replace(/[^a-z0-9]+/gi, "_").replace(/^_+|_+$/g, "");
269
+ const ensureNode = (agent2) => {
270
+ const name = agent2.handoff.name;
271
+ if (!nameToId.has(name)) {
272
+ const base = sanitizeId(name) || "agent";
273
+ let id = base;
274
+ let i = 1;
275
+ while (nodes.some((n) => n.id === id)) id = `${base}_${i++}`;
276
+ nameToId.set(name, id);
277
+ nodes.push({
278
+ id,
279
+ name,
280
+ tools: Object.keys(agent2.handoff.tools ?? {})
281
+ });
282
+ }
283
+ return nameToId.get(name);
284
+ };
285
+ const stack = [root];
286
+ while (stack.length) {
287
+ const current = stack.pop();
288
+ const currentName = current.handoff.name;
289
+ if (seen.has(currentName)) continue;
290
+ seen.add(currentName);
291
+ const fromId = ensureNode(current);
292
+ for (const child of current.toHandoffs()) {
293
+ const toId = ensureNode(child);
294
+ const label = Object.keys(child.handoffTool)[0].replace(
295
+ /transfer_to_/g,
296
+ ""
297
+ );
298
+ edges.push({ from: fromId, to: toId, label });
299
+ stack.push(child);
300
+ }
301
+ }
302
+ const lines = [];
303
+ lines.push(`flowchart ${direction}`);
304
+ for (const n of nodes) {
305
+ const name = titlecase(n.name.replace(/_agent/g, "").replace(/_/g, " "));
306
+ const toolLine = showTools && n.tools.length ? `<br/>tools: ${n.tools.map((it) => it.replace(/transfer_to_/g, "")).join(", ")}` : "";
307
+ lines.push(`${n.id}["${escapeLabel(`Agent: ${name}${toolLine}`)}"]`);
308
+ }
309
+ for (const e of edges) {
310
+ lines.push(`${e.from} -- ${escapeLabel(e.label)} --> ${e.to}`);
311
+ }
312
+ return lines.join("\n");
313
+ }
314
+ function escapeLabel(s) {
315
+ return s.replace(/"/g, '\\"');
316
+ }
317
+ function visualizeSemantic(root) {
318
+ const lines = [];
319
+ const seen = /* @__PURE__ */ new Set();
320
+ const stack = [root];
321
+ while (stack.length) {
322
+ const current = stack.pop();
323
+ const currentName = current.handoff.name;
324
+ if (seen.has(currentName)) continue;
325
+ seen.add(currentName);
326
+ const from = current.handoff.name;
327
+ const transfers = current.toHandoffs().map((h) => h.handoff.name);
328
+ const uniqueTransfers = Array.from(new Set(transfers));
329
+ const rhs = uniqueTransfers.length ? uniqueTransfers.join(", ") : "none";
330
+ lines.push(`${from} transfers to: ${rhs}`);
331
+ for (const child of current.toHandoffs()) stack.push(child);
332
+ }
333
+ return lines.join("\n");
334
+ }
335
+ function visualizeRichSemantic(root) {
336
+ const stack = [root];
337
+ const seen = /* @__PURE__ */ new Set();
338
+ const edgeSet = /* @__PURE__ */ new Set();
339
+ const edges = [];
340
+ while (stack.length) {
341
+ const current = stack.pop();
342
+ const from = current.handoff.name;
343
+ if (!seen.has(from)) {
344
+ seen.add(from);
345
+ for (const child of current.toHandoffs()) {
346
+ const to = child.handoff.name;
347
+ const key = `${from}->${to}`;
348
+ if (!edgeSet.has(key)) {
349
+ edgeSet.add(key);
350
+ edges.push({ from, to });
351
+ }
352
+ stack.push(child);
353
+ }
354
+ }
355
+ }
356
+ if (edges.length === 0) return `${root.handoff.name} \u2500\u2500\u25B6 none`;
357
+ return edges.map(({ from, to }) => `${from} \u2500\u2500\u25B6 ${to}`).join("\n");
358
+ }
359
+ function printChunk(chunk, options) {
360
+ const {
361
+ reasoning: includeReasoning,
362
+ wrapInTags,
363
+ text: includeText
364
+ } = options;
365
+ if (includeReasoning) {
366
+ if (chunk.type === "reasoning-start") {
367
+ process.stdout.write(`
368
+ ${wrapInTags ? "<reasoning>" : ""}
369
+ `);
370
+ }
371
+ if (chunk.type === "reasoning-delta") {
372
+ process.stdout.write(chunk.delta);
373
+ }
374
+ if (chunk.type === "reasoning-end") {
375
+ process.stdout.write(`
376
+ ${wrapInTags ? "</reasoning>" : ""}
377
+ `);
378
+ }
379
+ }
380
+ if (includeText) {
381
+ if (chunk.type === "text-start") {
382
+ process.stdout.write(`
383
+ ${wrapInTags ? "<text>" : ""}
384
+ `);
385
+ }
386
+ if (chunk.type === "text-delta") {
387
+ process.stdout.write(chunk.delta);
388
+ }
389
+ if (chunk.type === "text-end") {
390
+ process.stdout.write(`
391
+ ${wrapInTags ? "</text>" : ""}
392
+ `);
393
+ }
394
+ }
395
+ }
396
+ var printer = {
397
+ readableStream: async (stream2, options) => {
398
+ const includeReasoning = options?.reasoning ?? true;
399
+ const wrapInTags = options?.wrapInTags ?? true;
400
+ const includeText = options?.text ?? true;
401
+ for await (const chunk of stream2) {
402
+ printChunk(chunk, {
403
+ reasoning: includeReasoning,
404
+ wrapInTags,
405
+ text: includeText
406
+ });
407
+ }
408
+ },
409
+ stdout: async (response, options) => {
410
+ const includeReasoning = options?.reasoning ?? true;
411
+ const includeText = options?.text ?? true;
412
+ const wrapInTags = options?.wrapInTags ?? true;
413
+ for await (const chunk of response.toUIMessageStream()) {
414
+ printChunk(chunk, {
415
+ reasoning: includeReasoning,
416
+ text: includeText,
417
+ wrapInTags
418
+ });
419
+ }
420
+ console.log(await response.totalUsage);
421
+ },
422
+ mermaid: flow(visualizeMermaid, console.log),
423
+ semantic: flow(visualizeSemantic, console.log),
424
+ richSemantic: flow(visualizeRichSemantic, console.log)
425
+ };
426
+ function toState(options) {
427
+ return options.experimental_context;
428
+ }
429
+ var prepareStep = (agent2, model, contextVariables) => {
430
+ return async ({ steps, messages }) => {
431
+ const step = steps.at(-1);
432
+ const agentName = contextVariables.currentActiveAgent;
433
+ if (!step) {
434
+ return await prepareAgent(model, agent2, messages, contextVariables);
435
+ }
436
+ if (!agentName) {
437
+ return await prepareAgent(model, agent2, messages, contextVariables);
438
+ }
439
+ const nextAgent = findAgent(agent2, agentName);
440
+ if (!nextAgent) {
441
+ console.error(`Debug: ${chalk.red("NotFound")}: Agent ${agentName}`);
442
+ console.dir(
443
+ {
444
+ steps: steps.map(({ request, response, ...etc }) => etc),
445
+ messages
446
+ },
447
+ { depth: null }
448
+ );
449
+ return void 0;
450
+ }
451
+ return await prepareAgent(model, nextAgent, messages, contextVariables);
452
+ };
453
+ };
454
+ async function prepareAgent(defaultModel, agent2, messages, contextVariables) {
455
+ agent2.debug();
456
+ await agent2.prepareHandoff?.(messages);
457
+ let stepModel = agent2.model ?? defaultModel;
458
+ if (agent2.output) {
459
+ const json_schema = zodToJsonSchema(agent2.output, {
460
+ $refStrategy: "root"
461
+ });
462
+ stepModel = wrapLanguageModel({
463
+ model: stepModel,
464
+ middleware: {
465
+ transformParams: async ({ params }) => ({
466
+ ...params,
467
+ response_format: {
468
+ type: "json_schema",
469
+ json_schema,
470
+ name: `${agent2.handoff.name}_output`
471
+ }
472
+ })
473
+ }
474
+ });
475
+ }
476
+ return {
477
+ system: agent2.instructions(contextVariables),
478
+ activeTools: agent2.toolsNames,
479
+ model: stepModel,
480
+ messages,
481
+ // messages: removeTransferCalls(messages),
482
+ toolChoice: agent2.toolChoice
483
+ };
484
+ }
485
+ function findAgent(agent2, agentName) {
486
+ return [...agent2.toHandoffs(), agent2].find(
487
+ (it) => it.handoff.name === agentName
488
+ );
489
+ }
490
+ function agent(config) {
491
+ return new Agent(config);
492
+ }
493
+ var Agent = class _Agent {
494
+ model;
495
+ toolChoice;
496
+ parent;
497
+ handoffs;
498
+ prepareHandoff;
499
+ prepareEnd;
500
+ internalName;
501
+ handoff;
502
+ handoffToolName;
503
+ handoffTool;
504
+ output;
505
+ temperature;
506
+ constructor(config) {
507
+ this.model = config.model;
508
+ this.toolChoice = config.toolChoice || "auto";
509
+ this.handoffs = config.handoffs ?? [];
510
+ this.prepareHandoff = config.prepareHandoff;
511
+ this.prepareEnd = config.prepareEnd;
512
+ this.output = config.output;
513
+ this.temperature = config.temperature;
514
+ this.internalName = snakecase(config.name);
515
+ this.handoff = {
516
+ name: this.internalName,
517
+ instructions: config.prompt,
518
+ tools: config.tools ?? {},
519
+ handoffDescription: config.handoffDescription
520
+ };
521
+ this.handoffToolName = `transfer_to_${this.internalName}`;
522
+ this.handoffTool = {
523
+ [this.handoffToolName]: dynamicTool({
524
+ description: [
525
+ `An input/parameter/argument less tool to transfer control to the ${this.internalName} agent.`,
526
+ // `Handoff to the ${this.internalName} agent to handle the request`,
527
+ // `Do not include any parameters/inputs. The agent have access to all the context it needs.`,
528
+ config.handoffDescription
529
+ ].filter(Boolean).join(" "),
530
+ inputSchema: jsonSchema({
531
+ type: "object",
532
+ properties: {},
533
+ additionalProperties: true
534
+ }),
535
+ execute: async (_, options) => {
536
+ const state = toState(options);
537
+ state.currentActiveAgent = this.internalName;
538
+ return `Transfer successful to ${this.internalName}.`;
539
+ }
540
+ })
541
+ };
542
+ }
543
+ get transfer_tools() {
544
+ return Object.fromEntries(
545
+ this.toHandoffs().flatMap((it) => Object.entries(it.handoffTool))
546
+ );
547
+ }
548
+ get toolsNames() {
549
+ return [
550
+ // Note: do not add the handoff tool itself otherwise it'd create a agent recursion/loop
551
+ ...Object.keys(this.transfer_tools),
552
+ ...Object.keys(this.handoff.tools)
553
+ ];
554
+ }
555
+ #prepareInstructions(contextVariables) {
556
+ return [
557
+ typeof this.handoff.instructions === "function" ? this.handoff.instructions(contextVariables) : Array.isArray(this.handoff.instructions) ? this.handoff.instructions.join("\n") : this.handoff.instructions,
558
+ "",
559
+ ""
560
+ ].join("\n");
561
+ }
562
+ instructions(contextVariables) {
563
+ const text = this.#prepareInstructions(contextVariables);
564
+ const handoffsData = this.toHandoffs();
565
+ if (handoffsData.length === 0) {
566
+ return text.replace("<specialized_agents_placeholder>", " ");
567
+ }
568
+ const handoffs = [
569
+ "## Specialized Agents",
570
+ "| Agent Name | Agent Description |",
571
+ "| --- | --- |",
572
+ ...handoffsData.map(
573
+ (hf) => `| ${hf.handoff.name} | ${hf.handoff.handoffDescription || "No description available"} |`
574
+ ),
575
+ "",
576
+ ""
577
+ ].join("\n");
578
+ return text.replace("<specialized_agents_placeholder>", handoffs);
579
+ }
580
+ toHandoffs() {
581
+ const hfs = [];
582
+ for (const it of this.handoffs ?? []) {
583
+ const hf = typeof it === "function" ? it() : it;
584
+ hf.parent = this;
585
+ hfs.push(hf);
586
+ }
587
+ return hfs;
588
+ }
589
+ asTool(props) {
590
+ return tool4({
591
+ description: props?.toolDescription || this.handoff.handoffDescription,
592
+ inputSchema: z4.object({
593
+ input: z4.string()
594
+ }),
595
+ execute: async ({ input: input2 }, options) => {
596
+ try {
597
+ const result = await generateText2({
598
+ model: this.model,
599
+ system: this.#prepareInstructions(),
600
+ prompt: input2,
601
+ temperature: 0,
602
+ tools: this.handoff.tools,
603
+ abortSignal: options.abortSignal,
604
+ stopWhen: stepCountIs2(25),
605
+ experimental_context: options.experimental_context,
606
+ experimental_output: this.output ? Output2.object({ schema: this.output }) : void 0,
607
+ onStepFinish: (step) => {
608
+ const toolCall = step.toolCalls.at(-1);
609
+ if (toolCall) {
610
+ console.log(
611
+ `Debug: ${chalk2.yellow("ToolCalled")}: ${toolCall.toolName}(${JSON.stringify(toolCall.input)})`
612
+ );
613
+ }
614
+ },
615
+ prepareStep: prepareStep(
616
+ this,
617
+ this.model,
618
+ options.experimental_context
619
+ )
620
+ });
621
+ if (props?.outputExtractor) {
622
+ return await props.outputExtractor(result);
623
+ }
624
+ return result.steps.map((it) => it.toolResults).flat();
625
+ } catch (error) {
626
+ console.error(error);
627
+ return `Error: ${JSON.stringify(error)}`;
628
+ }
629
+ }
630
+ });
631
+ }
632
+ toTool(props) {
633
+ return { [this.handoffToolName]: this.asTool(props) };
634
+ }
635
+ debug(prefix = "") {
636
+ console.log(
637
+ `Debug: ${chalk2.bgMagenta("Agent")}: ${chalk2.bold(this.handoff.name)}`
638
+ );
639
+ const transferTools = this.toolsNames.filter((toolName) => toolName.startsWith("transfer_to")).map((toolName) => toolName.replace("transfer_to_", ""));
640
+ const agentTools = this.toolsNames.filter(
641
+ (toolName) => !toolName.startsWith("transfer_to")
642
+ );
643
+ console.log(
644
+ `Debug: ${chalk2.blue("TransferTools")}: ${transferTools.length ? transferTools : "None"}`
645
+ );
646
+ console.log(
647
+ `Debug: ${chalk2.blue("Agent Tools")}: ${agentTools.length ? agentTools : "None"}`
648
+ );
649
+ }
650
+ toToolset(options) {
651
+ const tools = flattenTools(
652
+ this,
653
+ (node) => node.toHandoffs(),
654
+ (node) => node.handoff.tools
655
+ );
656
+ return {
657
+ ...Object.fromEntries(tools.flatMap((it) => Object.entries(it))),
658
+ ...options?.includeTransferTool !== false ? this.transfer_tools : {},
659
+ ...options?.includeHandoffs !== false ? this.handoffTool : {}
660
+ };
661
+ }
662
+ clone(agent2) {
663
+ return new _Agent({
664
+ prepareHandoff: (messages) => {
665
+ this.prepareHandoff?.(messages);
666
+ },
667
+ model: agent2?.model ?? this.model,
668
+ toolChoice: agent2?.toolChoice ?? this.toolChoice,
669
+ prompt: agent2?.prompt ?? this.handoff.instructions,
670
+ tools: agent2?.tools ?? this.handoff.tools,
671
+ name: agent2?.name ?? this.handoff.name,
672
+ handoffDescription: agent2?.handoffDescription ?? this.handoff.handoffDescription,
673
+ handoffs: [...this.handoffs],
674
+ output: agent2?.output ?? this.output
675
+ });
676
+ }
677
+ };
678
+ function flattenTools(root, getChildren, extract) {
679
+ const stack = [root];
680
+ const visited = /* @__PURE__ */ new Set();
681
+ const result = [];
682
+ while (stack.length) {
683
+ const node = stack.pop();
684
+ if (visited.has(node)) continue;
685
+ visited.add(node);
686
+ result.push(extract(node));
687
+ stack.push(...getChildren(node));
688
+ }
689
+ return result;
690
+ }
691
+ function instructions({ purpose, routine }) {
692
+ const lines = [
693
+ "# Agent Context",
694
+ ...Array.isArray(purpose) ? purpose : [purpose],
695
+ "",
696
+ "",
697
+ "<specialized_agents_placeholder>"
698
+ ];
699
+ if (routine.length) {
700
+ lines.push(
701
+ `Use the following routine to fulfill the task.`,
702
+ `# Routine`,
703
+ ...routine.map((it, i) => `${i + 1}. ${it}`)
704
+ );
705
+ }
706
+ return lines.join("\n");
707
+ }
708
+ instructions.swarm = ({ purpose, routine }) => {
709
+ const lines = [
710
+ RECOMMENDED_PROMPT_PREFIX,
711
+ "",
712
+ "",
713
+ "# Agent Context",
714
+ ...Array.isArray(purpose) ? purpose : [purpose],
715
+ "",
716
+ "",
717
+ "<specialized_agents_placeholder>"
718
+ ];
719
+ if (routine.length) {
720
+ lines.push(
721
+ `Use the following routine to fulfill the task.`,
722
+ `# Routine`,
723
+ ...routine.map((it, i) => `${i + 1}. ${it}`)
724
+ );
725
+ }
726
+ return lines.join("\n");
727
+ };
728
+ instructions.supervisor = ({
729
+ purpose,
730
+ routine
731
+ }) => {
732
+ const lines = [
733
+ SUPERVISOR_PROMPT_PREFIX,
734
+ "",
735
+ "",
736
+ "# Agent Context",
737
+ ...Array.isArray(purpose) ? purpose : [purpose],
738
+ "",
739
+ "",
740
+ "<specialized_agents_placeholder>"
741
+ ];
742
+ if (routine.length) {
743
+ lines.push(
744
+ `Use the following routine to fulfill the task.`,
745
+ `# Routine`,
746
+ ...routine.filter(Boolean).map((it, i) => `${i + 1}. ${it}`)
747
+ );
748
+ }
749
+ return lines.join("\n");
750
+ };
751
+ instructions.supervisor_subagent = ({
752
+ purpose,
753
+ routine
754
+ }) => {
755
+ const lines = [
756
+ SUPERVISOR_PROMPT_PREFIX,
757
+ "",
758
+ "",
759
+ "# Agent Context",
760
+ ...Array.isArray(purpose) ? purpose : [purpose],
761
+ ""
762
+ ];
763
+ if (routine.length) {
764
+ lines.push(
765
+ `Use the following routine to fulfill the task. Execute ALL steps immediately.`,
766
+ `# Routine`,
767
+ ...routine.map((it, i) => `${i + 1}. ${it}`),
768
+ `${routine.length + 1}. transfer_to_supervisor_agent`
769
+ // `1. IMMEDIATELY START: ${routine[0]}`,
770
+ // ...routine.slice(1).map((it, i) => `${i + 2}. ${it}`),
771
+ // `${routine.length + 1}. STOP HERE - Do not do any other agent's work`,
772
+ // `${routine.length + 2}. MANDATORY: You MUST call transfer_to_supervisor_agent function RIGHT NOW to return control`,
773
+ // `${routine.length + 3}. DO NOT END YOUR RESPONSE WITHOUT CALLING THE TRANSFER FUNCTION`,
774
+ );
775
+ } else {
776
+ lines.push(
777
+ "CRITICAL: end the generation by calling transfer_to_supervisor_agent tool"
778
+ );
779
+ }
780
+ return lines.join("\n");
781
+ };
782
+ var lmstudio = createOpenAICompatible({
783
+ name: "lmstudio",
784
+ baseURL: "http://127.0.0.1:1234/v1",
785
+ supportsStructuredOutputs: true,
786
+ includeUsage: true
787
+ });
788
+ var glm = createOpenAICompatible({
789
+ name: "z.ai",
790
+ baseURL: "https://api.z.ai/api/paas/v4/",
791
+ apiKey: process.env.ZAI_API_KEY
792
+ });
793
+
794
+ // packages/toolbox/src/lib/scratchbad.ts
795
+ var scratchpad_tool = tool5({
796
+ description: `Tool for strategic reflection on research progress and decision-making.
797
+
798
+ Use this tool after each search to analyze results and plan next steps systematically.
799
+ This creates a deliberate pause in the research workflow for quality decision-making.
800
+
801
+ When to use:
802
+ - After receiving search results: What key information did I find?
803
+ - Before deciding next steps: Do I have enough to answer comprehensively?
804
+ - When assessing research gaps: What specific information am I still missing?
805
+ - Before concluding research: Can I provide a complete answer now?
806
+
807
+ Reflection should address:
808
+ 1. Analysis of current findings - What concrete information have I gathered?
809
+ 2. Gap assessment - What crucial information is still missing?
810
+ 3. Quality evaluation - Do I have sufficient evidence/examples for a good answer?
811
+ 4. Strategic decision - Should I continue searching or provide my answer?
812
+ `,
813
+ inputSchema: z5.object({
814
+ reflection: z5.string().describe("Your detailed reflection on research progress.")
815
+ }),
816
+ execute: async ({ reflection }, options) => {
817
+ const context = toState(options);
818
+ context.scratchpad += `- ${reflection}
819
+ `;
820
+ return `Reflection recorded. Current scratchpad now:
821
+ ---
822
+ ${context.scratchpad}`;
823
+ }
824
+ });
825
+
826
+ // packages/toolbox/src/lib/weather.ts
827
+ import { tool as tool6 } from "ai";
828
+ import { z as z6 } from "zod";
829
+ var GetWeatherSchema = z6.object({
830
+ location: z6.string(),
831
+ unit: z6.enum(["C", "F"]),
832
+ temperature: z6.number(),
833
+ condition: z6.string(),
834
+ high: z6.number(),
835
+ low: z6.number(),
836
+ humidity: z6.number(),
837
+ windKph: z6.number(),
838
+ icon: z6.string().optional()
839
+ });
840
+ var getWeatherTool = tool6({
841
+ name: "weather",
842
+ description: "Get the current weather for a location.",
843
+ inputSchema: z6.object({
844
+ location: z6.string().describe("City name, address or coordinates"),
845
+ unit: z6.enum(["C", "F"]).default("C")
846
+ }),
847
+ outputSchema: GetWeatherSchema,
848
+ execute: async ({ location, unit }) => {
849
+ const { latitude, longitude, name } = await geocodeLocation(location);
850
+ const params = new URLSearchParams({
851
+ latitude: String(latitude),
852
+ longitude: String(longitude),
853
+ current: [
854
+ "temperature_2m",
855
+ "relative_humidity_2m",
856
+ "wind_speed_10m",
857
+ "weather_code"
858
+ ].join(","),
859
+ daily: ["temperature_2m_max", "temperature_2m_min"].join(","),
860
+ timezone: "auto",
861
+ temperature_unit: unit === "F" ? "fahrenheit" : "celsius",
862
+ wind_speed_unit: "kmh"
863
+ });
864
+ const url = `https://api.open-meteo.com/v1/forecast?${params.toString()}`;
865
+ const res = await fetch(url);
866
+ if (!res.ok) throw new Error(`Weather API failed: ${res.status}`);
867
+ const data = await res.json();
868
+ const current = data?.current;
869
+ const daily = data?.daily;
870
+ if (!current || !daily) throw new Error("Malformed weather API response");
871
+ const weatherCode = Number(current.weather_code);
872
+ const mapped = mapWeatherCode(weatherCode);
873
+ const result = {
874
+ location: name,
875
+ unit,
876
+ temperature: Math.round(Number(current.temperature_2m)),
877
+ condition: mapped.condition,
878
+ high: Math.round(Number(daily.temperature_2m_max?.[0])),
879
+ low: Math.round(Number(daily.temperature_2m_min?.[0])),
880
+ humidity: Math.max(
881
+ 0,
882
+ Math.min(1, Number(current.relative_humidity_2m) / 100)
883
+ ),
884
+ windKph: Math.round(Number(current.wind_speed_10m)),
885
+ icon: mapped.icon
886
+ };
887
+ return result;
888
+ }
889
+ });
890
+ async function geocodeLocation(location) {
891
+ const coordMatch = location.trim().match(/^\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)\s*$/);
892
+ if (coordMatch) {
893
+ const latitude = parseFloat(coordMatch[1]);
894
+ const longitude = parseFloat(coordMatch[2]);
895
+ return {
896
+ latitude,
897
+ longitude,
898
+ name: `${latitude.toFixed(3)}, ${longitude.toFixed(3)}`
899
+ };
900
+ }
901
+ const url = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(
902
+ location
903
+ )}&count=1&language=en&format=json`;
904
+ const res = await fetch(url);
905
+ if (!res.ok) throw new Error(`Geocoding failed: ${res.status}`);
906
+ const data = await res.json();
907
+ const first = data?.results?.[0];
908
+ if (!first) throw new Error(`Location not found: ${location}`);
909
+ const nameParts = [first.name, first.admin1, first.country_code].filter(
910
+ Boolean
911
+ );
912
+ return {
913
+ latitude: first.latitude,
914
+ longitude: first.longitude,
915
+ name: nameParts.join(", ")
916
+ };
917
+ }
918
+ function mapWeatherCode(code) {
919
+ switch (code) {
920
+ case 0:
921
+ return { condition: "Clear sky", icon: "weather-sun" };
922
+ case 1:
923
+ return { condition: "Mainly clear", icon: "weather-sun" };
924
+ case 2:
925
+ return { condition: "Partly cloudy", icon: "weather-partly" };
926
+ case 3:
927
+ return { condition: "Overcast", icon: "weather-cloud" };
928
+ case 45:
929
+ case 48:
930
+ return { condition: "Fog", icon: "weather-fog" };
931
+ case 51:
932
+ case 53:
933
+ case 55:
934
+ case 56:
935
+ case 57:
936
+ return { condition: "Drizzle", icon: "weather-drizzle" };
937
+ case 61:
938
+ case 63:
939
+ case 65:
940
+ case 66:
941
+ case 67:
942
+ return { condition: "Rain", icon: "weather-rain" };
943
+ case 71:
944
+ case 73:
945
+ case 75:
946
+ case 77:
947
+ return { condition: "Snow", icon: "weather-snow" };
948
+ case 80:
949
+ case 81:
950
+ case 82:
951
+ return { condition: "Showers", icon: "weather-showers" };
952
+ case 85:
953
+ case 86:
954
+ return { condition: "Snow showers", icon: "weather-snow" };
955
+ case 95:
956
+ case 96:
957
+ case 99:
958
+ return { condition: "Thunderstorm", icon: "weather-thunder" };
959
+ default:
960
+ return { condition: "Unknown" };
961
+ }
962
+ }
963
+
964
+ // packages/toolbox/src/lib/web-search.ts
965
+ import { groq as groq2 } from "@ai-sdk/groq";
966
+ var web_search_tool = duckDuckGoSearch;
967
+ var searchAgent = agent({
968
+ name: "research_agent",
969
+ model: groq2("openai/gpt-oss-20b"),
970
+ prompt: "You are a diligent research assistant. Your task is to gather accurate and relevant information on a given topic using web search. Use the browser_search tool to find up-to-date information, and synthesize your findings into a concise summary.",
971
+ tools: {
972
+ browser_search: duckDuckGoSearch
973
+ }
974
+ });
975
+
976
+ // packages/toolbox/src/lib/user-story-formatter.ts
977
+ import { tool as tool7 } from "ai";
978
+ import z7 from "zod";
979
+ var AcceptanceCriteriaSchema = z7.object({
980
+ criterion: z7.string().describe("A specific, testable acceptance criterion")
981
+ });
982
+ var UserStorySchema = z7.object({
983
+ title: z7.string().describe("Clear, concise title for the user story"),
984
+ userRole: z7.string().describe('The user role or persona (e.g., "developer", "end user")'),
985
+ action: z7.string().describe("What the user wants to do"),
986
+ benefit: z7.string().describe("The value or benefit the user gets"),
987
+ acceptanceCriteria: z7.array(AcceptanceCriteriaSchema).describe("List of specific, testable conditions that must be met"),
988
+ technicalNotes: z7.string().optional().describe(
989
+ "Relevant files, components, or dependencies from the repository"
990
+ ),
991
+ priority: z7.enum(["High", "Medium", "Low"]).describe("Priority level based on complexity and dependencies"),
992
+ storyPoints: z7.enum(["1", "2", "3", "5", "8", "13"]).describe("Estimated complexity using Fibonacci sequence"),
993
+ epicOrFeature: z7.string().optional().describe("The epic or feature group this story belongs to")
994
+ });
995
+ var user_story_formatter_tool = tool7({
996
+ description: `Tool for formatting and recording user stories in a standardized format.
997
+
998
+ Use this tool to create well-structured user stories following product management best practices.
999
+ Each story should follow the format: "As a [role], I want to [action], so that [benefit]"
1000
+
1001
+ When to use:
1002
+ - After analyzing a feature or component in the codebase
1003
+ - When you've gathered enough information to write a complete user story
1004
+ - To document findings in a structured, actionable format
1005
+ - To maintain consistency across all generated user stories
1006
+
1007
+ The tool will:
1008
+ 1. Format the story in the standard user story template
1009
+ 2. Store it in the context for later synthesis
1010
+ 3. Return a formatted version for immediate review
1011
+ `,
1012
+ inputSchema: UserStorySchema,
1013
+ execute: async (story, options) => {
1014
+ const context = toState(options);
1015
+ context.userStories ??= [];
1016
+ context.userStories.push(story);
1017
+ const formatted = `
1018
+ ## ${story.title}
1019
+
1020
+ **User Story:**
1021
+ As a **${story.userRole}**, I want to **${story.action}**, so that **${story.benefit}**.
1022
+
1023
+ **Acceptance Criteria:**
1024
+ ${story.acceptanceCriteria.map((ac, i) => `${i + 1}. ${ac.criterion}`).join("\n")}
1025
+
1026
+ **Technical Notes:**
1027
+ ${story.technicalNotes || "N/A"}
1028
+
1029
+ **Priority:** ${story.priority}
1030
+ **Story Points:** ${story.storyPoints}
1031
+ ${story.epicOrFeature ? `**Epic/Feature:** ${story.epicOrFeature}` : ""}
1032
+
1033
+ ---
1034
+ `.trim();
1035
+ return `User story recorded successfully!
1036
+
1037
+ ${formatted}
1038
+
1039
+ Total stories recorded: ${context.userStories.length}`;
1040
+ }
1041
+ });
1042
+ export {
1043
+ GetWeatherSchema,
1044
+ ddgSearchSchema,
1045
+ duckDuckGoSearch,
1046
+ duckStocks,
1047
+ execute_os_command,
1048
+ getWeatherTool,
1049
+ scratchpad_tool,
1050
+ searchAgent,
1051
+ serp,
1052
+ user_story_formatter_tool,
1053
+ web_search_tool
1054
+ };
1055
+ //# sourceMappingURL=index.js.map