@deepagents/toolbox 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +150 -777
- package/dist/index.js.map +4 -4
- package/dist/lib/web-search.d.ts +1 -1
- package/dist/lib/web-search.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -174,640 +174,10 @@ var duckStocks = tool3({
|
|
|
174
174
|
});
|
|
175
175
|
|
|
176
176
|
// packages/toolbox/src/lib/scratchbad.ts
|
|
177
|
-
import { tool as
|
|
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";
|
|
177
|
+
import { tool as tool4 } from "ai";
|
|
191
178
|
import z4 from "zod";
|
|
192
|
-
import
|
|
193
|
-
|
|
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
|
-
providerOptions;
|
|
507
|
-
constructor(config) {
|
|
508
|
-
this.model = config.model;
|
|
509
|
-
this.toolChoice = config.toolChoice || "auto";
|
|
510
|
-
this.handoffs = config.handoffs ?? [];
|
|
511
|
-
this.prepareHandoff = config.prepareHandoff;
|
|
512
|
-
this.prepareEnd = config.prepareEnd;
|
|
513
|
-
this.output = config.output;
|
|
514
|
-
this.temperature = config.temperature;
|
|
515
|
-
this.internalName = snakecase(config.name);
|
|
516
|
-
this.providerOptions = config.providerOptions;
|
|
517
|
-
this.handoff = {
|
|
518
|
-
name: this.internalName,
|
|
519
|
-
instructions: config.prompt,
|
|
520
|
-
tools: config.tools ?? {},
|
|
521
|
-
handoffDescription: config.handoffDescription
|
|
522
|
-
};
|
|
523
|
-
this.handoffToolName = `transfer_to_${this.internalName}`;
|
|
524
|
-
this.handoffTool = {
|
|
525
|
-
[this.handoffToolName]: dynamicTool({
|
|
526
|
-
description: [
|
|
527
|
-
`An input/parameter/argument less tool to transfer control to the ${this.internalName} agent.`,
|
|
528
|
-
// `Handoff to the ${this.internalName} agent to handle the request`,
|
|
529
|
-
// `Do not include any parameters/inputs. The agent have access to all the context it needs.`,
|
|
530
|
-
config.handoffDescription
|
|
531
|
-
].filter(Boolean).join(" "),
|
|
532
|
-
inputSchema: jsonSchema({
|
|
533
|
-
type: "object",
|
|
534
|
-
properties: {},
|
|
535
|
-
additionalProperties: true
|
|
536
|
-
}),
|
|
537
|
-
execute: async (_, options) => {
|
|
538
|
-
const state = toState(options);
|
|
539
|
-
state.currentActiveAgent = this.internalName;
|
|
540
|
-
return `Transfer successful to ${this.internalName}.`;
|
|
541
|
-
}
|
|
542
|
-
})
|
|
543
|
-
};
|
|
544
|
-
}
|
|
545
|
-
get transfer_tools() {
|
|
546
|
-
return Object.fromEntries(
|
|
547
|
-
this.toHandoffs().flatMap((it) => Object.entries(it.handoffTool))
|
|
548
|
-
);
|
|
549
|
-
}
|
|
550
|
-
get toolsNames() {
|
|
551
|
-
return [
|
|
552
|
-
// Note: do not add the handoff tool itself otherwise it'd create a agent recursion/loop
|
|
553
|
-
...Object.keys(this.transfer_tools),
|
|
554
|
-
...Object.keys(this.handoff.tools)
|
|
555
|
-
];
|
|
556
|
-
}
|
|
557
|
-
#prepareInstructions(contextVariables) {
|
|
558
|
-
return [
|
|
559
|
-
typeof this.handoff.instructions === "function" ? this.handoff.instructions(contextVariables) : Array.isArray(this.handoff.instructions) ? this.handoff.instructions.join("\n") : this.handoff.instructions,
|
|
560
|
-
"",
|
|
561
|
-
""
|
|
562
|
-
].join("\n");
|
|
563
|
-
}
|
|
564
|
-
instructions(contextVariables) {
|
|
565
|
-
const text = this.#prepareInstructions(contextVariables);
|
|
566
|
-
const handoffsData = this.toHandoffs();
|
|
567
|
-
if (handoffsData.length === 0) {
|
|
568
|
-
return text.replace("<specialized_agents_placeholder>", " ");
|
|
569
|
-
}
|
|
570
|
-
const handoffs = [
|
|
571
|
-
"## Specialized Agents",
|
|
572
|
-
"| Agent Name | Agent Description |",
|
|
573
|
-
"| --- | --- |",
|
|
574
|
-
...handoffsData.map(
|
|
575
|
-
(hf) => `| ${hf.handoff.name} | ${hf.handoff.handoffDescription || "No description available"} |`
|
|
576
|
-
),
|
|
577
|
-
"",
|
|
578
|
-
""
|
|
579
|
-
].join("\n");
|
|
580
|
-
return text.replace("<specialized_agents_placeholder>", handoffs);
|
|
581
|
-
}
|
|
582
|
-
toHandoffs() {
|
|
583
|
-
const hfs = [];
|
|
584
|
-
for (const it of this.handoffs ?? []) {
|
|
585
|
-
const hf = typeof it === "function" ? it() : it;
|
|
586
|
-
hf.parent = this;
|
|
587
|
-
hfs.push(hf);
|
|
588
|
-
}
|
|
589
|
-
return hfs;
|
|
590
|
-
}
|
|
591
|
-
asTool(props) {
|
|
592
|
-
return tool4({
|
|
593
|
-
description: props?.toolDescription || this.handoff.handoffDescription,
|
|
594
|
-
inputSchema: z4.object({
|
|
595
|
-
input: z4.string(),
|
|
596
|
-
output: z4.string().optional().describe(
|
|
597
|
-
"Optional instructions on how the final output should be formatted. this would be passed to the underlying llm as part of the prompt."
|
|
598
|
-
)
|
|
599
|
-
}),
|
|
600
|
-
execute: async ({ input: input2, output }, options) => {
|
|
601
|
-
try {
|
|
602
|
-
const result = await generateText2({
|
|
603
|
-
model: this.model,
|
|
604
|
-
system: this.#prepareInstructions(),
|
|
605
|
-
prompt: `
|
|
606
|
-
<Input>
|
|
607
|
-
${input2}
|
|
608
|
-
</Input>
|
|
609
|
-
${output ? `<OutputInstructions>
|
|
610
|
-
${output}
|
|
611
|
-
</OutputInstructions>` : ""}
|
|
612
|
-
`,
|
|
613
|
-
temperature: 0,
|
|
614
|
-
tools: this.handoff.tools,
|
|
615
|
-
abortSignal: options.abortSignal,
|
|
616
|
-
stopWhen: stepCountIs2(25),
|
|
617
|
-
experimental_context: options.experimental_context,
|
|
618
|
-
experimental_output: this.output ? Output2.object({ schema: this.output }) : void 0,
|
|
619
|
-
onStepFinish: (step) => {
|
|
620
|
-
const toolCall = step.toolCalls.at(-1);
|
|
621
|
-
if (toolCall) {
|
|
622
|
-
console.log(
|
|
623
|
-
`Debug: ${chalk2.yellow("ToolCalled")}: ${toolCall.toolName}(${JSON.stringify(toolCall.input)})`
|
|
624
|
-
);
|
|
625
|
-
}
|
|
626
|
-
},
|
|
627
|
-
prepareStep: prepareStep(
|
|
628
|
-
this,
|
|
629
|
-
this.model,
|
|
630
|
-
options.experimental_context
|
|
631
|
-
)
|
|
632
|
-
});
|
|
633
|
-
if (props?.outputExtractor) {
|
|
634
|
-
return await props.outputExtractor(result);
|
|
635
|
-
}
|
|
636
|
-
return result.steps.map((it) => it.toolResults).flat();
|
|
637
|
-
} catch (error) {
|
|
638
|
-
console.error(error);
|
|
639
|
-
return `An error thrown from a tool call.
|
|
640
|
-
<ErrorDetails>
|
|
641
|
-
${JSON.stringify(error)}
|
|
642
|
-
</ErrorDetails>`;
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
});
|
|
646
|
-
}
|
|
647
|
-
toTool(props) {
|
|
648
|
-
return { [this.handoffToolName]: this.asTool(props) };
|
|
649
|
-
}
|
|
650
|
-
debug(prefix = "") {
|
|
651
|
-
console.log(
|
|
652
|
-
`Debug: ${chalk2.bgMagenta("Agent")}: ${chalk2.dim.black(this.handoff.name)}`
|
|
653
|
-
);
|
|
654
|
-
const transferTools = this.toolsNames.filter((toolName) => toolName.startsWith("transfer_to")).map((toolName) => toolName.replace("transfer_to_", ""));
|
|
655
|
-
const agentTools = this.toolsNames.filter(
|
|
656
|
-
(toolName) => !toolName.startsWith("transfer_to")
|
|
657
|
-
);
|
|
658
|
-
console.log(
|
|
659
|
-
`Debug: ${chalk2.blue("TransferTools")}: ${transferTools.length ? transferTools : "None"}`
|
|
660
|
-
);
|
|
661
|
-
console.log(
|
|
662
|
-
`Debug: ${chalk2.blue("Agent Tools")}: ${agentTools.length ? agentTools : "None"}`
|
|
663
|
-
);
|
|
664
|
-
}
|
|
665
|
-
toToolset(options) {
|
|
666
|
-
const tools = flattenTools(
|
|
667
|
-
this,
|
|
668
|
-
(node) => node.toHandoffs(),
|
|
669
|
-
(node) => node.handoff.tools
|
|
670
|
-
);
|
|
671
|
-
return {
|
|
672
|
-
...Object.fromEntries(tools.flatMap((it) => Object.entries(it))),
|
|
673
|
-
...options?.includeTransferTool !== false ? this.transfer_tools : {},
|
|
674
|
-
...options?.includeHandoffs !== false ? this.handoffTool : {}
|
|
675
|
-
};
|
|
676
|
-
}
|
|
677
|
-
clone(agent2) {
|
|
678
|
-
return new _Agent({
|
|
679
|
-
prepareHandoff: (messages) => {
|
|
680
|
-
this.prepareHandoff?.(messages);
|
|
681
|
-
},
|
|
682
|
-
model: agent2?.model ?? this.model,
|
|
683
|
-
toolChoice: agent2?.toolChoice ?? this.toolChoice,
|
|
684
|
-
prompt: agent2?.prompt ?? this.handoff.instructions,
|
|
685
|
-
tools: agent2?.tools ?? this.handoff.tools,
|
|
686
|
-
name: agent2?.name ?? this.handoff.name,
|
|
687
|
-
handoffDescription: agent2?.handoffDescription ?? this.handoff.handoffDescription,
|
|
688
|
-
handoffs: [...this.handoffs],
|
|
689
|
-
output: agent2?.output ?? this.output
|
|
690
|
-
});
|
|
691
|
-
}
|
|
692
|
-
};
|
|
693
|
-
function flattenTools(root, getChildren, extract) {
|
|
694
|
-
const stack = [root];
|
|
695
|
-
const visited = /* @__PURE__ */ new Set();
|
|
696
|
-
const result = [];
|
|
697
|
-
while (stack.length) {
|
|
698
|
-
const node = stack.pop();
|
|
699
|
-
if (visited.has(node)) continue;
|
|
700
|
-
visited.add(node);
|
|
701
|
-
result.push(extract(node));
|
|
702
|
-
stack.push(...getChildren(node));
|
|
703
|
-
}
|
|
704
|
-
return result;
|
|
705
|
-
}
|
|
706
|
-
function instructions({ purpose, routine }) {
|
|
707
|
-
const lines = [
|
|
708
|
-
"# Agent Context",
|
|
709
|
-
...Array.isArray(purpose) ? purpose : [purpose],
|
|
710
|
-
"",
|
|
711
|
-
"",
|
|
712
|
-
"<specialized_agents_placeholder>"
|
|
713
|
-
];
|
|
714
|
-
if (routine.length) {
|
|
715
|
-
lines.push(
|
|
716
|
-
`Use the following routine to fulfill the task.`,
|
|
717
|
-
`# Routine`,
|
|
718
|
-
...routine.map((it, i) => `${i + 1}. ${it}`)
|
|
719
|
-
);
|
|
720
|
-
}
|
|
721
|
-
return lines.join("\n");
|
|
722
|
-
}
|
|
723
|
-
instructions.swarm = ({ purpose, routine }) => {
|
|
724
|
-
const lines = [
|
|
725
|
-
RECOMMENDED_PROMPT_PREFIX,
|
|
726
|
-
"",
|
|
727
|
-
"",
|
|
728
|
-
"# Agent Context",
|
|
729
|
-
...Array.isArray(purpose) ? purpose : [purpose],
|
|
730
|
-
"",
|
|
731
|
-
"",
|
|
732
|
-
"<specialized_agents_placeholder>"
|
|
733
|
-
];
|
|
734
|
-
if (routine.length) {
|
|
735
|
-
lines.push(
|
|
736
|
-
`Use the following routine to fulfill the task.`,
|
|
737
|
-
`# Routine`,
|
|
738
|
-
...routine.map((it, i) => `${i + 1}. ${it}`)
|
|
739
|
-
);
|
|
740
|
-
}
|
|
741
|
-
return lines.join("\n");
|
|
742
|
-
};
|
|
743
|
-
instructions.supervisor = ({
|
|
744
|
-
purpose,
|
|
745
|
-
routine
|
|
746
|
-
}) => {
|
|
747
|
-
const lines = [
|
|
748
|
-
SUPERVISOR_PROMPT_PREFIX,
|
|
749
|
-
"",
|
|
750
|
-
"",
|
|
751
|
-
"# Agent Context",
|
|
752
|
-
...Array.isArray(purpose) ? purpose : [purpose],
|
|
753
|
-
"",
|
|
754
|
-
"",
|
|
755
|
-
"<specialized_agents_placeholder>"
|
|
756
|
-
];
|
|
757
|
-
if (routine.length) {
|
|
758
|
-
lines.push(
|
|
759
|
-
`Use the following routine to fulfill the task.`,
|
|
760
|
-
`# Routine`,
|
|
761
|
-
...routine.filter(Boolean).map((it, i) => `${i + 1}. ${it}`)
|
|
762
|
-
);
|
|
763
|
-
}
|
|
764
|
-
return lines.join("\n");
|
|
765
|
-
};
|
|
766
|
-
instructions.supervisor_subagent = ({
|
|
767
|
-
purpose,
|
|
768
|
-
routine
|
|
769
|
-
}) => {
|
|
770
|
-
const lines = [
|
|
771
|
-
SUPERVISOR_PROMPT_PREFIX,
|
|
772
|
-
"",
|
|
773
|
-
"",
|
|
774
|
-
"# Agent Context",
|
|
775
|
-
...Array.isArray(purpose) ? purpose : [purpose],
|
|
776
|
-
""
|
|
777
|
-
];
|
|
778
|
-
if (routine.length) {
|
|
779
|
-
lines.push(
|
|
780
|
-
`Use the following routine to fulfill the task. Execute ALL steps immediately.`,
|
|
781
|
-
`# Routine`,
|
|
782
|
-
...routine.map((it, i) => `${i + 1}. ${it}`),
|
|
783
|
-
`${routine.length + 1}. transfer_to_supervisor_agent`
|
|
784
|
-
// `1. IMMEDIATELY START: ${routine[0]}`,
|
|
785
|
-
// ...routine.slice(1).map((it, i) => `${i + 2}. ${it}`),
|
|
786
|
-
// `${routine.length + 1}. STOP HERE - Do not do any other agent's work`,
|
|
787
|
-
// `${routine.length + 2}. MANDATORY: You MUST call transfer_to_supervisor_agent function RIGHT NOW to return control`,
|
|
788
|
-
// `${routine.length + 3}. DO NOT END YOUR RESPONSE WITHOUT CALLING THE TRANSFER FUNCTION`,
|
|
789
|
-
);
|
|
790
|
-
} else {
|
|
791
|
-
lines.push(
|
|
792
|
-
"CRITICAL: end the generation by calling transfer_to_supervisor_agent tool"
|
|
793
|
-
);
|
|
794
|
-
}
|
|
795
|
-
return lines.join("\n");
|
|
796
|
-
};
|
|
797
|
-
var lmstudio = createOpenAICompatible({
|
|
798
|
-
name: "lmstudio",
|
|
799
|
-
baseURL: "http://127.0.0.1:1234/v1",
|
|
800
|
-
supportsStructuredOutputs: true,
|
|
801
|
-
includeUsage: true
|
|
802
|
-
});
|
|
803
|
-
var glm = createOpenAICompatible({
|
|
804
|
-
name: "z.ai",
|
|
805
|
-
baseURL: "https://api.z.ai/api/paas/v4/",
|
|
806
|
-
apiKey: process.env.ZAI_API_KEY
|
|
807
|
-
});
|
|
808
|
-
|
|
809
|
-
// packages/toolbox/src/lib/scratchbad.ts
|
|
810
|
-
var scratchpad_tool = tool5({
|
|
179
|
+
import { toState } from "@deepagents/agent";
|
|
180
|
+
var scratchpad_tool = tool4({
|
|
811
181
|
description: `Tool for strategic reflection on research progress and decision-making.
|
|
812
182
|
|
|
813
183
|
Use this tool after each search to analyze results and plan next steps systematically.
|
|
@@ -825,8 +195,8 @@ var scratchpad_tool = tool5({
|
|
|
825
195
|
3. Quality evaluation - Do I have sufficient evidence/examples for a good answer?
|
|
826
196
|
4. Strategic decision - Should I continue searching or provide my answer?
|
|
827
197
|
`,
|
|
828
|
-
inputSchema:
|
|
829
|
-
reflection:
|
|
198
|
+
inputSchema: z4.object({
|
|
199
|
+
reflection: z4.string().describe("Your detailed reflection on research progress.")
|
|
830
200
|
}),
|
|
831
201
|
execute: async ({ reflection }, options) => {
|
|
832
202
|
const context = toState(options);
|
|
@@ -839,25 +209,25 @@ ${context.scratchpad}`;
|
|
|
839
209
|
});
|
|
840
210
|
|
|
841
211
|
// packages/toolbox/src/lib/weather.ts
|
|
842
|
-
import { tool as
|
|
843
|
-
import { z as
|
|
844
|
-
var GetWeatherSchema =
|
|
845
|
-
location:
|
|
846
|
-
unit:
|
|
847
|
-
temperature:
|
|
848
|
-
condition:
|
|
849
|
-
high:
|
|
850
|
-
low:
|
|
851
|
-
humidity:
|
|
852
|
-
windKph:
|
|
853
|
-
icon:
|
|
212
|
+
import { tool as tool5 } from "ai";
|
|
213
|
+
import { z as z5 } from "zod";
|
|
214
|
+
var GetWeatherSchema = z5.object({
|
|
215
|
+
location: z5.string(),
|
|
216
|
+
unit: z5.enum(["C", "F"]),
|
|
217
|
+
temperature: z5.number(),
|
|
218
|
+
condition: z5.string(),
|
|
219
|
+
high: z5.number(),
|
|
220
|
+
low: z5.number(),
|
|
221
|
+
humidity: z5.number(),
|
|
222
|
+
windKph: z5.number(),
|
|
223
|
+
icon: z5.string().optional()
|
|
854
224
|
});
|
|
855
|
-
var getWeatherTool =
|
|
225
|
+
var getWeatherTool = tool5({
|
|
856
226
|
name: "weather",
|
|
857
227
|
description: "Get the current weather for a location.",
|
|
858
|
-
inputSchema:
|
|
859
|
-
location:
|
|
860
|
-
unit:
|
|
228
|
+
inputSchema: z5.object({
|
|
229
|
+
location: z5.string().describe("City name, address or coordinates"),
|
|
230
|
+
unit: z5.enum(["C", "F"]).default("C")
|
|
861
231
|
}),
|
|
862
232
|
outputSchema: GetWeatherSchema,
|
|
863
233
|
execute: async ({ location, unit }) => {
|
|
@@ -977,11 +347,12 @@ function mapWeatherCode(code) {
|
|
|
977
347
|
}
|
|
978
348
|
|
|
979
349
|
// packages/toolbox/src/lib/web-search.ts
|
|
980
|
-
import { groq
|
|
350
|
+
import { groq } from "@ai-sdk/groq";
|
|
351
|
+
import { agent } from "@deepagents/agent";
|
|
981
352
|
var web_search_tool = duckDuckGoSearch;
|
|
982
353
|
var searchAgent = agent({
|
|
983
354
|
name: "research_agent",
|
|
984
|
-
model:
|
|
355
|
+
model: groq("openai/gpt-oss-20b"),
|
|
985
356
|
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.",
|
|
986
357
|
tools: {
|
|
987
358
|
browser_search: duckDuckGoSearch
|
|
@@ -989,25 +360,26 @@ var searchAgent = agent({
|
|
|
989
360
|
});
|
|
990
361
|
|
|
991
362
|
// packages/toolbox/src/lib/user-story-formatter.ts
|
|
992
|
-
import { tool as
|
|
993
|
-
import
|
|
994
|
-
|
|
995
|
-
|
|
363
|
+
import { tool as tool6 } from "ai";
|
|
364
|
+
import z6 from "zod";
|
|
365
|
+
import { toState as toState2 } from "@deepagents/agent";
|
|
366
|
+
var AcceptanceCriteriaSchema = z6.object({
|
|
367
|
+
criterion: z6.string().describe("A specific, testable acceptance criterion")
|
|
996
368
|
});
|
|
997
|
-
var UserStorySchema =
|
|
998
|
-
title:
|
|
999
|
-
userRole:
|
|
1000
|
-
action:
|
|
1001
|
-
benefit:
|
|
1002
|
-
acceptanceCriteria:
|
|
1003
|
-
technicalNotes:
|
|
369
|
+
var UserStorySchema = z6.object({
|
|
370
|
+
title: z6.string().describe("Clear, concise title for the user story"),
|
|
371
|
+
userRole: z6.string().describe('The user role or persona (e.g., "developer", "end user")'),
|
|
372
|
+
action: z6.string().describe("What the user wants to do"),
|
|
373
|
+
benefit: z6.string().describe("The value or benefit the user gets"),
|
|
374
|
+
acceptanceCriteria: z6.array(AcceptanceCriteriaSchema).describe("List of specific, testable conditions that must be met"),
|
|
375
|
+
technicalNotes: z6.string().optional().describe(
|
|
1004
376
|
"Relevant files, components, or dependencies from the repository"
|
|
1005
377
|
),
|
|
1006
|
-
priority:
|
|
1007
|
-
storyPoints:
|
|
1008
|
-
epicOrFeature:
|
|
378
|
+
priority: z6.enum(["High", "Medium", "Low"]).describe("Priority level based on complexity and dependencies"),
|
|
379
|
+
storyPoints: z6.enum(["1", "2", "3", "5", "8", "13"]).describe("Estimated complexity using Fibonacci sequence"),
|
|
380
|
+
epicOrFeature: z6.string().optional().describe("The epic or feature group this story belongs to")
|
|
1009
381
|
});
|
|
1010
|
-
var user_story_formatter_tool =
|
|
382
|
+
var user_story_formatter_tool = tool6({
|
|
1011
383
|
description: `Tool for formatting and recording user stories in a standardized format.
|
|
1012
384
|
|
|
1013
385
|
Use this tool to create well-structured user stories following product management best practices.
|
|
@@ -1026,7 +398,7 @@ var user_story_formatter_tool = tool7({
|
|
|
1026
398
|
`,
|
|
1027
399
|
inputSchema: UserStorySchema,
|
|
1028
400
|
execute: async (story, options) => {
|
|
1029
|
-
const context =
|
|
401
|
+
const context = toState2(options);
|
|
1030
402
|
context.userStories ??= [];
|
|
1031
403
|
context.userStories.push(story);
|
|
1032
404
|
const formatted = `
|
|
@@ -1056,8 +428,9 @@ Total stories recorded: ${context.userStories.length}`;
|
|
|
1056
428
|
});
|
|
1057
429
|
|
|
1058
430
|
// packages/toolbox/src/lib/hackernews-search.ts
|
|
1059
|
-
import { tool as
|
|
1060
|
-
import { z as
|
|
431
|
+
import { tool as tool7 } from "ai";
|
|
432
|
+
import { z as z7 } from "zod";
|
|
433
|
+
import { toState as toState3 } from "@deepagents/agent";
|
|
1061
434
|
function buildTags(options) {
|
|
1062
435
|
const tags = [];
|
|
1063
436
|
if (options.type && options.type !== "all") {
|
|
@@ -1371,21 +744,21 @@ function formatJobResults(response) {
|
|
|
1371
744
|
`;
|
|
1372
745
|
return header + results.join("\n");
|
|
1373
746
|
}
|
|
1374
|
-
var search_by_query =
|
|
747
|
+
var search_by_query = tool7({
|
|
1375
748
|
description: "Tool to search HackerNews stories by keywords and filters. Use when you need to find HN stories matching specific search criteria, time periods, or popularity thresholds.",
|
|
1376
|
-
inputSchema:
|
|
1377
|
-
query:
|
|
749
|
+
inputSchema: z7.object({
|
|
750
|
+
query: z7.string().describe(
|
|
1378
751
|
'Search query for story titles and content. Examples: "artificial intelligence", "python"'
|
|
1379
752
|
),
|
|
1380
|
-
timeFilter:
|
|
1381
|
-
minPoints:
|
|
1382
|
-
minComments:
|
|
1383
|
-
sortBy:
|
|
1384
|
-
page:
|
|
1385
|
-
hitsPerPage:
|
|
753
|
+
timeFilter: z7.enum(["d", "w", "m", "y", "all"]).default("all").describe("Time filter: d=day, w=week, m=month, y=year, all=no filter"),
|
|
754
|
+
minPoints: z7.number().int().min(0).optional().describe("Minimum points threshold"),
|
|
755
|
+
minComments: z7.number().int().min(0).optional().describe("Minimum comments threshold"),
|
|
756
|
+
sortBy: z7.enum(["relevance", "date"]).default("relevance").describe("Sort results by relevance or date"),
|
|
757
|
+
page: z7.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
758
|
+
hitsPerPage: z7.number().int().min(1).max(1e3).default(20).describe("Results per page (max 1000)")
|
|
1386
759
|
}),
|
|
1387
760
|
execute: async (input, options) => {
|
|
1388
|
-
const context =
|
|
761
|
+
const context = toState3(options);
|
|
1389
762
|
context.hackernews_sources ??= [];
|
|
1390
763
|
const numericFilters = buildNumericFilters({
|
|
1391
764
|
timeFilter: input.timeFilter,
|
|
@@ -1404,19 +777,19 @@ var search_by_query = tool8({
|
|
|
1404
777
|
return formatStoryResults(response);
|
|
1405
778
|
}
|
|
1406
779
|
});
|
|
1407
|
-
var search_by_author =
|
|
780
|
+
var search_by_author = tool7({
|
|
1408
781
|
description: "Tool to search HackerNews content by author username. Use when you need to find all stories, comments, or both by a specific HN user.",
|
|
1409
|
-
inputSchema:
|
|
1410
|
-
author:
|
|
1411
|
-
type:
|
|
1412
|
-
timeFilter:
|
|
1413
|
-
minComments:
|
|
1414
|
-
sortBy:
|
|
1415
|
-
page:
|
|
1416
|
-
hitsPerPage:
|
|
782
|
+
inputSchema: z7.object({
|
|
783
|
+
author: z7.string().describe('HackerNews username to search for. Examples: "pg", "tptacek"'),
|
|
784
|
+
type: z7.enum(["story", "comment", "all"]).default("all").describe("Type of content: story, comment, or all"),
|
|
785
|
+
timeFilter: z7.enum(["d", "w", "m", "y", "all"]).default("all").describe("Time filter: d=day, w=week, m=month, y=year, all=no filter"),
|
|
786
|
+
minComments: z7.number().int().min(0).optional().describe("Minimum comments threshold (for stories only)"),
|
|
787
|
+
sortBy: z7.enum(["relevance", "date"]).default("date").describe("Sort results by relevance or date"),
|
|
788
|
+
page: z7.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
789
|
+
hitsPerPage: z7.number().int().min(1).max(1e3).default(20).describe("Results per page (max 1000)")
|
|
1417
790
|
}),
|
|
1418
791
|
execute: async (input, options) => {
|
|
1419
|
-
const context =
|
|
792
|
+
const context = toState3(options);
|
|
1420
793
|
context.hackernews_sources ??= [];
|
|
1421
794
|
const tags = buildTags({ type: input.type, author: input.author });
|
|
1422
795
|
const numericFilters = buildNumericFilters({
|
|
@@ -1434,13 +807,13 @@ var search_by_author = tool8({
|
|
|
1434
807
|
return formatAuthorResults(response);
|
|
1435
808
|
}
|
|
1436
809
|
});
|
|
1437
|
-
var get_story_item =
|
|
810
|
+
var get_story_item = tool7({
|
|
1438
811
|
description: "Tool to get detailed information about a specific HackerNews story by ID. Use when you need full details about a particular HN story including title, URL, author, points, and comments.",
|
|
1439
|
-
inputSchema:
|
|
1440
|
-
storyId:
|
|
812
|
+
inputSchema: z7.object({
|
|
813
|
+
storyId: z7.string().describe('HackerNews story ID. Example: "38709478"')
|
|
1441
814
|
}),
|
|
1442
815
|
execute: async (input, options) => {
|
|
1443
|
-
const context =
|
|
816
|
+
const context = toState3(options);
|
|
1444
817
|
context.hackernews_sources ??= [];
|
|
1445
818
|
const item = await fetchHNItem(input.storyId);
|
|
1446
819
|
if (item.type !== "story") {
|
|
@@ -1456,10 +829,10 @@ var get_story_item = tool8({
|
|
|
1456
829
|
return formatItemDetails(item);
|
|
1457
830
|
}
|
|
1458
831
|
});
|
|
1459
|
-
var get_story_comment =
|
|
832
|
+
var get_story_comment = tool7({
|
|
1460
833
|
description: "Tool to get detailed information about a specific HackerNews comment by ID. Use when you need full details about a particular comment including text, author, and parent story information.",
|
|
1461
|
-
inputSchema:
|
|
1462
|
-
commentId:
|
|
834
|
+
inputSchema: z7.object({
|
|
835
|
+
commentId: z7.string().describe('HackerNews comment ID. Example: "38710123"')
|
|
1463
836
|
}),
|
|
1464
837
|
execute: async (input) => {
|
|
1465
838
|
const item = await fetchHNItem(input.commentId);
|
|
@@ -1471,14 +844,14 @@ var get_story_comment = tool8({
|
|
|
1471
844
|
return formatItemDetails(item);
|
|
1472
845
|
}
|
|
1473
846
|
});
|
|
1474
|
-
var get_front_page_stories =
|
|
847
|
+
var get_front_page_stories = tool7({
|
|
1475
848
|
description: "Tool to get current HackerNews front page stories. Use when you need to see the latest trending and popular stories on HN.",
|
|
1476
|
-
inputSchema:
|
|
1477
|
-
page:
|
|
1478
|
-
hitsPerPage:
|
|
849
|
+
inputSchema: z7.object({
|
|
850
|
+
page: z7.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
851
|
+
hitsPerPage: z7.number().int().min(1).max(50).default(30).describe("Results per page (max 50)")
|
|
1479
852
|
}),
|
|
1480
853
|
execute: async (input, options) => {
|
|
1481
|
-
const context =
|
|
854
|
+
const context = toState3(options);
|
|
1482
855
|
context.hackernews_sources ??= [];
|
|
1483
856
|
const response = await searchHackerNewsAPI({
|
|
1484
857
|
tags: "front_page",
|
|
@@ -1490,13 +863,13 @@ var get_front_page_stories = tool8({
|
|
|
1490
863
|
return formatStoryResults(response);
|
|
1491
864
|
}
|
|
1492
865
|
});
|
|
1493
|
-
var get_story_comments =
|
|
866
|
+
var get_story_comments = tool7({
|
|
1494
867
|
description: "Tool to get all comments for a specific HackerNews story. Use when you need to read the discussion and comments on a particular HN story.",
|
|
1495
|
-
inputSchema:
|
|
1496
|
-
storyId:
|
|
1497
|
-
sortBy:
|
|
1498
|
-
page:
|
|
1499
|
-
hitsPerPage:
|
|
868
|
+
inputSchema: z7.object({
|
|
869
|
+
storyId: z7.string().describe('HackerNews story ID. Example: "38709478"'),
|
|
870
|
+
sortBy: z7.enum(["relevance", "date"]).default("date").describe("Sort comments by relevance or date"),
|
|
871
|
+
page: z7.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
872
|
+
hitsPerPage: z7.number().int().min(1).max(1e3).default(50).describe("Results per page (max 1000)")
|
|
1500
873
|
}),
|
|
1501
874
|
execute: async (input) => {
|
|
1502
875
|
const response = await searchHackerNewsAPI({
|
|
@@ -1508,21 +881,21 @@ var get_story_comments = tool8({
|
|
|
1508
881
|
return formatCommentResults(response);
|
|
1509
882
|
}
|
|
1510
883
|
});
|
|
1511
|
-
var search_ask_hn =
|
|
884
|
+
var search_ask_hn = tool7({
|
|
1512
885
|
description: "Tool to search Ask HN posts - questions posed to the HackerNews community. Use when you need to find community questions and discussions on specific topics.",
|
|
1513
|
-
inputSchema:
|
|
1514
|
-
query:
|
|
886
|
+
inputSchema: z7.object({
|
|
887
|
+
query: z7.string().default("").describe(
|
|
1515
888
|
'Search query for Ask HN posts. Examples: "artificial intelligence", "career"'
|
|
1516
889
|
),
|
|
1517
|
-
timeFilter:
|
|
1518
|
-
minPoints:
|
|
1519
|
-
minComments:
|
|
1520
|
-
sortBy:
|
|
1521
|
-
page:
|
|
1522
|
-
hitsPerPage:
|
|
890
|
+
timeFilter: z7.enum(["d", "w", "m", "y", "all"]).default("all").describe("Time filter: d=day, w=week, m=month, y=year, all=no filter"),
|
|
891
|
+
minPoints: z7.number().int().min(0).optional().describe("Minimum points threshold"),
|
|
892
|
+
minComments: z7.number().int().min(0).optional().describe("Minimum comments threshold"),
|
|
893
|
+
sortBy: z7.enum(["relevance", "date"]).default("relevance").describe("Sort by relevance or date"),
|
|
894
|
+
page: z7.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
895
|
+
hitsPerPage: z7.number().int().min(1).max(1e3).default(20).describe("Results per page (max 1000)")
|
|
1523
896
|
}),
|
|
1524
897
|
execute: async (input, options) => {
|
|
1525
|
-
const context =
|
|
898
|
+
const context = toState3(options);
|
|
1526
899
|
context.hackernews_sources ??= [];
|
|
1527
900
|
const numericFilters = buildNumericFilters({
|
|
1528
901
|
timeFilter: input.timeFilter,
|
|
@@ -1541,21 +914,21 @@ var search_ask_hn = tool8({
|
|
|
1541
914
|
return formatStoryResults(response);
|
|
1542
915
|
}
|
|
1543
916
|
});
|
|
1544
|
-
var search_show_hn =
|
|
917
|
+
var search_show_hn = tool7({
|
|
1545
918
|
description: "Tool to search Show HN posts - projects and products shared with the HackerNews community. Use when you need to discover community projects, demos, or products on specific topics.",
|
|
1546
|
-
inputSchema:
|
|
1547
|
-
query:
|
|
919
|
+
inputSchema: z7.object({
|
|
920
|
+
query: z7.string().default("").describe(
|
|
1548
921
|
'Search query for Show HN posts. Examples: "web app", "open source"'
|
|
1549
922
|
),
|
|
1550
|
-
timeFilter:
|
|
1551
|
-
minPoints:
|
|
1552
|
-
minComments:
|
|
1553
|
-
sortBy:
|
|
1554
|
-
page:
|
|
1555
|
-
hitsPerPage:
|
|
923
|
+
timeFilter: z7.enum(["d", "w", "m", "y", "all"]).default("all").describe("Time filter: d=day, w=week, m=month, y=year, all=no filter"),
|
|
924
|
+
minPoints: z7.number().int().min(0).optional().describe("Minimum points threshold"),
|
|
925
|
+
minComments: z7.number().int().min(0).optional().describe("Minimum comments threshold"),
|
|
926
|
+
sortBy: z7.enum(["relevance", "date"]).default("relevance").describe("Sort by relevance or date"),
|
|
927
|
+
page: z7.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
928
|
+
hitsPerPage: z7.number().int().min(1).max(1e3).default(20).describe("Results per page (max 1000)")
|
|
1556
929
|
}),
|
|
1557
930
|
execute: async (input, options) => {
|
|
1558
|
-
const context =
|
|
931
|
+
const context = toState3(options);
|
|
1559
932
|
context.hackernews_sources ??= [];
|
|
1560
933
|
const numericFilters = buildNumericFilters({
|
|
1561
934
|
timeFilter: input.timeFilter,
|
|
@@ -1574,19 +947,19 @@ var search_show_hn = tool8({
|
|
|
1574
947
|
return formatStoryResults(response);
|
|
1575
948
|
}
|
|
1576
949
|
});
|
|
1577
|
-
var search_jobs =
|
|
950
|
+
var search_jobs = tool7({
|
|
1578
951
|
description: "Tool to search HackerNews job postings. Use when you need to find tech job opportunities posted on HN.",
|
|
1579
|
-
inputSchema:
|
|
1580
|
-
query:
|
|
952
|
+
inputSchema: z7.object({
|
|
953
|
+
query: z7.string().default("").describe(
|
|
1581
954
|
'Search query for job postings. Examples: "remote", "machine learning"'
|
|
1582
955
|
),
|
|
1583
|
-
timeFilter:
|
|
1584
|
-
sortBy:
|
|
1585
|
-
page:
|
|
1586
|
-
hitsPerPage:
|
|
956
|
+
timeFilter: z7.enum(["d", "w", "m", "y", "all"]).default("all").describe("Time filter: d=day, w=week, m=month, y=year, all=no filter"),
|
|
957
|
+
sortBy: z7.enum(["relevance", "date"]).default("date").describe("Sort by relevance or date"),
|
|
958
|
+
page: z7.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
959
|
+
hitsPerPage: z7.number().int().min(1).max(1e3).default(20).describe("Results per page (max 1000)")
|
|
1587
960
|
}),
|
|
1588
961
|
execute: async (input, options) => {
|
|
1589
|
-
const context =
|
|
962
|
+
const context = toState3(options);
|
|
1590
963
|
context.hackernews_sources ??= [];
|
|
1591
964
|
const numericFilters = buildNumericFilters({
|
|
1592
965
|
timeFilter: input.timeFilter
|
|
@@ -1603,17 +976,17 @@ var search_jobs = tool8({
|
|
|
1603
976
|
return formatJobResults(response);
|
|
1604
977
|
}
|
|
1605
978
|
});
|
|
1606
|
-
var search_polls =
|
|
979
|
+
var search_polls = tool7({
|
|
1607
980
|
description: "Tool to search HackerNews polls - community surveys and voting. Use when you need to find community polls on various topics.",
|
|
1608
|
-
inputSchema:
|
|
1609
|
-
query:
|
|
1610
|
-
timeFilter:
|
|
1611
|
-
sortBy:
|
|
1612
|
-
page:
|
|
1613
|
-
hitsPerPage:
|
|
981
|
+
inputSchema: z7.object({
|
|
982
|
+
query: z7.string().default("").describe('Search query for polls. Example: "programming language"'),
|
|
983
|
+
timeFilter: z7.enum(["d", "w", "m", "y", "all"]).default("all").describe("Time filter: d=day, w=week, m=month, y=year, all=no filter"),
|
|
984
|
+
sortBy: z7.enum(["relevance", "date"]).default("date").describe("Sort by relevance or date"),
|
|
985
|
+
page: z7.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
986
|
+
hitsPerPage: z7.number().int().min(1).max(1e3).default(20).describe("Results per page (max 1000)")
|
|
1614
987
|
}),
|
|
1615
988
|
execute: async (input, options) => {
|
|
1616
|
-
const context =
|
|
989
|
+
const context = toState3(options);
|
|
1617
990
|
context.hackernews_sources ??= [];
|
|
1618
991
|
const numericFilters = buildNumericFilters({
|
|
1619
992
|
timeFilter: input.timeFilter
|
|
@@ -1630,29 +1003,29 @@ var search_polls = tool8({
|
|
|
1630
1003
|
return formatStoryResults(response);
|
|
1631
1004
|
}
|
|
1632
1005
|
});
|
|
1633
|
-
var get_user_profile =
|
|
1006
|
+
var get_user_profile = tool7({
|
|
1634
1007
|
description: "Tool to get HackerNews user profile information. Use when you need to view a user's karma, account creation date, and bio.",
|
|
1635
|
-
inputSchema:
|
|
1636
|
-
username:
|
|
1008
|
+
inputSchema: z7.object({
|
|
1009
|
+
username: z7.string().describe('HackerNews username. Example: "pg"')
|
|
1637
1010
|
}),
|
|
1638
1011
|
execute: async (input) => {
|
|
1639
1012
|
const user = await fetchHNUser(input.username);
|
|
1640
1013
|
return formatUserProfile(user);
|
|
1641
1014
|
}
|
|
1642
1015
|
});
|
|
1643
|
-
var search_by_domain =
|
|
1016
|
+
var search_by_domain = tool7({
|
|
1644
1017
|
description: "Tool to search HackerNews stories from a specific domain or website. Use when you need to find all HN posts from a particular domain or track discussions about content from specific websites.",
|
|
1645
|
-
inputSchema:
|
|
1646
|
-
domain:
|
|
1647
|
-
timeFilter:
|
|
1648
|
-
minPoints:
|
|
1649
|
-
minComments:
|
|
1650
|
-
sortBy:
|
|
1651
|
-
page:
|
|
1652
|
-
hitsPerPage:
|
|
1018
|
+
inputSchema: z7.object({
|
|
1019
|
+
domain: z7.string().describe('Domain to search. Examples: "github.com", "arxiv.org"'),
|
|
1020
|
+
timeFilter: z7.enum(["d", "w", "m", "y", "all"]).default("all").describe("Time filter: d=day, w=week, m=month, y=year, all=no filter"),
|
|
1021
|
+
minPoints: z7.number().int().min(0).optional().describe("Minimum points threshold"),
|
|
1022
|
+
minComments: z7.number().int().min(0).optional().describe("Minimum comments threshold"),
|
|
1023
|
+
sortBy: z7.enum(["relevance", "date"]).default("date").describe("Sort by relevance or date"),
|
|
1024
|
+
page: z7.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
1025
|
+
hitsPerPage: z7.number().int().min(1).max(1e3).default(20).describe("Results per page (max 1000)")
|
|
1653
1026
|
}),
|
|
1654
1027
|
execute: async (input, options) => {
|
|
1655
|
-
const context =
|
|
1028
|
+
const context = toState3(options);
|
|
1656
1029
|
context.hackernews_sources ??= [];
|
|
1657
1030
|
const numericFilters = buildNumericFilters({
|
|
1658
1031
|
timeFilter: input.timeFilter,
|
|
@@ -1683,21 +1056,21 @@ var search_by_domain = tool8({
|
|
|
1683
1056
|
return formatStoryResults(data);
|
|
1684
1057
|
}
|
|
1685
1058
|
});
|
|
1686
|
-
var search_highly_discussed =
|
|
1059
|
+
var search_highly_discussed = tool7({
|
|
1687
1060
|
description: "Tool to search for highly discussed HackerNews stories with many comments. Use when you need to find engaging or controversial discussions with significant community participation.",
|
|
1688
|
-
inputSchema:
|
|
1689
|
-
minComments:
|
|
1061
|
+
inputSchema: z7.object({
|
|
1062
|
+
minComments: z7.number().int().min(1).describe(
|
|
1690
1063
|
"Minimum number of comments (required). Example: 100 for highly discussed stories"
|
|
1691
1064
|
),
|
|
1692
|
-
query:
|
|
1693
|
-
timeFilter:
|
|
1694
|
-
minPoints:
|
|
1695
|
-
sortBy:
|
|
1696
|
-
page:
|
|
1697
|
-
hitsPerPage:
|
|
1065
|
+
query: z7.string().default("").describe('Optional search query. Example: "AI"'),
|
|
1066
|
+
timeFilter: z7.enum(["d", "w", "m", "y", "all"]).default("all").describe("Time filter: d=day, w=week, m=month, y=year, all=no filter"),
|
|
1067
|
+
minPoints: z7.number().int().min(0).optional().describe("Minimum points threshold"),
|
|
1068
|
+
sortBy: z7.enum(["relevance", "date"]).default("date").describe("Sort by relevance or date"),
|
|
1069
|
+
page: z7.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
1070
|
+
hitsPerPage: z7.number().int().min(1).max(1e3).default(20).describe("Results per page (max 1000)")
|
|
1698
1071
|
}),
|
|
1699
1072
|
execute: async (input, options) => {
|
|
1700
|
-
const context =
|
|
1073
|
+
const context = toState3(options);
|
|
1701
1074
|
context.hackernews_sources ??= [];
|
|
1702
1075
|
const numericFilters = buildNumericFilters({
|
|
1703
1076
|
timeFilter: input.timeFilter,
|
|
@@ -1716,20 +1089,20 @@ var search_highly_discussed = tool8({
|
|
|
1716
1089
|
return formatStoryResults(response);
|
|
1717
1090
|
}
|
|
1718
1091
|
});
|
|
1719
|
-
var search_trending =
|
|
1092
|
+
var search_trending = tool7({
|
|
1720
1093
|
description: "Tool to find currently trending HackerNews stories - recent posts with high engagement. Use when you need to discover what's hot right now on HN by combining recency with high points and comments.",
|
|
1721
|
-
inputSchema:
|
|
1722
|
-
minPoints:
|
|
1094
|
+
inputSchema: z7.object({
|
|
1095
|
+
minPoints: z7.number().int().min(10).default(50).describe(
|
|
1723
1096
|
"Minimum points threshold. Example: 100 for highly upvoted stories"
|
|
1724
1097
|
),
|
|
1725
|
-
maxAgeHours:
|
|
1726
|
-
minComments:
|
|
1727
|
-
sortBy:
|
|
1728
|
-
page:
|
|
1729
|
-
hitsPerPage:
|
|
1098
|
+
maxAgeHours: z7.number().int().min(1).max(72).default(24).describe("Maximum age in hours. Example: 24 for stories from today"),
|
|
1099
|
+
minComments: z7.number().int().min(0).default(10).describe("Minimum comments threshold"),
|
|
1100
|
+
sortBy: z7.enum(["relevance", "date"]).default("date").describe("Sort by relevance or date"),
|
|
1101
|
+
page: z7.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
1102
|
+
hitsPerPage: z7.number().int().min(1).max(100).default(30).describe("Results per page (max 100)")
|
|
1730
1103
|
}),
|
|
1731
1104
|
execute: async (input, options) => {
|
|
1732
|
-
const context =
|
|
1105
|
+
const context = toState3(options);
|
|
1733
1106
|
context.hackernews_sources ??= [];
|
|
1734
1107
|
const numericFilters = buildNumericFilters({
|
|
1735
1108
|
maxAgeHours: input.maxAgeHours,
|