@clinebot/agents 0.0.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/README.md +145 -0
- package/dist/agent-input.d.ts +2 -0
- package/dist/agent.d.ts +56 -0
- package/dist/extensions.d.ts +21 -0
- package/dist/hooks/engine.d.ts +42 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/lifecycle.d.ts +5 -0
- package/dist/hooks/node.d.ts +2 -0
- package/dist/hooks/subprocess-runner.d.ts +16 -0
- package/dist/hooks/subprocess.d.ts +268 -0
- package/dist/index.browser.d.ts +1 -0
- package/dist/index.browser.js +49 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +49 -0
- package/dist/index.node.d.ts +5 -0
- package/dist/index.node.js +49 -0
- package/dist/mcp/index.d.ts +4 -0
- package/dist/mcp/policies.d.ts +14 -0
- package/dist/mcp/tools.d.ts +9 -0
- package/dist/mcp/types.d.ts +35 -0
- package/dist/message-builder.d.ts +31 -0
- package/dist/prompts/cline.d.ts +1 -0
- package/dist/prompts/index.d.ts +1 -0
- package/dist/runtime/agent-runtime-bus.d.ts +13 -0
- package/dist/runtime/conversation-store.d.ts +16 -0
- package/dist/runtime/lifecycle-orchestrator.d.ts +28 -0
- package/dist/runtime/tool-orchestrator.d.ts +39 -0
- package/dist/runtime/turn-processor.d.ts +21 -0
- package/dist/teams/index.d.ts +3 -0
- package/dist/teams/multi-agent.d.ts +566 -0
- package/dist/teams/spawn-agent-tool.d.ts +85 -0
- package/dist/teams/team-tools.d.ts +51 -0
- package/dist/tools/ask-question.d.ts +12 -0
- package/dist/tools/create.d.ts +59 -0
- package/dist/tools/execution.d.ts +61 -0
- package/dist/tools/formatting.d.ts +20 -0
- package/dist/tools/index.d.ts +11 -0
- package/dist/tools/registry.d.ts +26 -0
- package/dist/tools/validation.d.ts +27 -0
- package/dist/types.d.ts +826 -0
- package/package.json +54 -0
- package/src/agent-input.ts +116 -0
- package/src/agent.test.ts +931 -0
- package/src/agent.ts +1050 -0
- package/src/example.test.ts +564 -0
- package/src/extensions.ts +337 -0
- package/src/hooks/engine.test.ts +163 -0
- package/src/hooks/engine.ts +537 -0
- package/src/hooks/index.ts +6 -0
- package/src/hooks/lifecycle.ts +239 -0
- package/src/hooks/node.ts +18 -0
- package/src/hooks/subprocess-runner.ts +140 -0
- package/src/hooks/subprocess.test.ts +180 -0
- package/src/hooks/subprocess.ts +620 -0
- package/src/index.browser.ts +1 -0
- package/src/index.node.ts +21 -0
- package/src/index.ts +133 -0
- package/src/mcp/index.ts +17 -0
- package/src/mcp/policies.test.ts +51 -0
- package/src/mcp/policies.ts +53 -0
- package/src/mcp/tools.test.ts +76 -0
- package/src/mcp/tools.ts +60 -0
- package/src/mcp/types.ts +41 -0
- package/src/message-builder.test.ts +175 -0
- package/src/message-builder.ts +429 -0
- package/src/prompts/cline.ts +49 -0
- package/src/prompts/index.ts +1 -0
- package/src/runtime/agent-runtime-bus.ts +53 -0
- package/src/runtime/conversation-store.ts +61 -0
- package/src/runtime/lifecycle-orchestrator.ts +90 -0
- package/src/runtime/tool-orchestrator.ts +177 -0
- package/src/runtime/turn-processor.ts +250 -0
- package/src/streaming.test.ts +197 -0
- package/src/streaming.ts +307 -0
- package/src/teams/index.ts +63 -0
- package/src/teams/multi-agent.lifecycle.test.ts +48 -0
- package/src/teams/multi-agent.ts +1866 -0
- package/src/teams/spawn-agent-tool.test.ts +172 -0
- package/src/teams/spawn-agent-tool.ts +223 -0
- package/src/teams/team-tools.test.ts +448 -0
- package/src/teams/team-tools.ts +929 -0
- package/src/tools/ask-question.ts +78 -0
- package/src/tools/create.ts +104 -0
- package/src/tools/execution.ts +311 -0
- package/src/tools/formatting.ts +73 -0
- package/src/tools/index.ts +45 -0
- package/src/tools/registry.ts +52 -0
- package/src/tools/tools.test.ts +292 -0
- package/src/tools/validation.ts +73 -0
- package/src/types.ts +966 -0
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example: Building Agentic Loops with Sub-Agent Spawning
|
|
3
|
+
*
|
|
4
|
+
* This example demonstrates how to use the @clinebot/agents, @clinebot/llms,
|
|
5
|
+
* and @clinebot/llms packages together to build an agentic loop where the
|
|
6
|
+
* main agent can spawn sub-agents to handle specialized tasks.
|
|
7
|
+
*
|
|
8
|
+
* Features demonstrated:
|
|
9
|
+
* - Creating an Agent with a user-provided system prompt
|
|
10
|
+
* - Defining custom tools
|
|
11
|
+
* - Spawning sub-agents via tool calls (LLM can create new agents)
|
|
12
|
+
* - Handling agent events for streaming output
|
|
13
|
+
* - Using the models package to query available models
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { providers } from "@clinebot/llms";
|
|
17
|
+
import { Agent, type AgentEvent, createTool, type Tool } from "./index.js";
|
|
18
|
+
|
|
19
|
+
// Note: When workspace is linked, you can also import from @clinebot/llms:
|
|
20
|
+
// import { getModel, queryModels } from "@clinebot/llms"
|
|
21
|
+
|
|
22
|
+
// =============================================================================
|
|
23
|
+
// Configuration
|
|
24
|
+
// =============================================================================
|
|
25
|
+
|
|
26
|
+
interface AgentSpawnerConfig {
|
|
27
|
+
/** Provider ID (e.g., "anthropic", "openai", "gemini") */
|
|
28
|
+
providerId: string;
|
|
29
|
+
/** Model ID to use */
|
|
30
|
+
modelId: string;
|
|
31
|
+
/** API key for the provider */
|
|
32
|
+
apiKey: string;
|
|
33
|
+
/** Optional base URL for the API */
|
|
34
|
+
baseUrl?: string;
|
|
35
|
+
/** Maximum iterations for spawned sub-agents */
|
|
36
|
+
subAgentMaxIterations?: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// =============================================================================
|
|
40
|
+
// Sub-Agent Tool
|
|
41
|
+
// =============================================================================
|
|
42
|
+
|
|
43
|
+
interface SpawnAgentInput {
|
|
44
|
+
systemPrompt: string;
|
|
45
|
+
task: string;
|
|
46
|
+
maxIterations?: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface SpawnAgentOutput {
|
|
50
|
+
text: string;
|
|
51
|
+
iterations: number;
|
|
52
|
+
finishReason: string;
|
|
53
|
+
usage: {
|
|
54
|
+
inputTokens: number;
|
|
55
|
+
outputTokens: number;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Creates a tool that allows the LLM to spawn new agents with custom system prompts.
|
|
61
|
+
*
|
|
62
|
+
* This enables patterns like:
|
|
63
|
+
* - Task delegation: Main agent spawns specialists for specific tasks
|
|
64
|
+
* - Parallel execution: Multiple sub-agents working on different aspects
|
|
65
|
+
* - Chain-of-thought delegation: Breaking complex problems into sub-problems
|
|
66
|
+
*/
|
|
67
|
+
function createSpawnAgentTool(
|
|
68
|
+
config: AgentSpawnerConfig,
|
|
69
|
+
): Tool<SpawnAgentInput, SpawnAgentOutput> {
|
|
70
|
+
return createTool<SpawnAgentInput, SpawnAgentOutput>({
|
|
71
|
+
name: "spawn_agent",
|
|
72
|
+
description: `Spawn a new AI agent with a custom system prompt to handle a specific task.
|
|
73
|
+
The spawned agent will run independently and return its final result.
|
|
74
|
+
Use this when you need to delegate a specialized task that benefits from a focused system prompt.
|
|
75
|
+
|
|
76
|
+
Examples of when to use:
|
|
77
|
+
- Complex code analysis that needs a specialized reviewer persona
|
|
78
|
+
- Creative writing that benefits from a specific author's style
|
|
79
|
+
- Technical explanations that need domain expertise
|
|
80
|
+
- Multi-step tasks that benefit from focused attention`,
|
|
81
|
+
inputSchema: {
|
|
82
|
+
type: "object",
|
|
83
|
+
properties: {
|
|
84
|
+
systemPrompt: {
|
|
85
|
+
type: "string",
|
|
86
|
+
description:
|
|
87
|
+
"The system prompt for the spawned agent. This defines the agent's persona, capabilities, and behavior.",
|
|
88
|
+
},
|
|
89
|
+
task: {
|
|
90
|
+
type: "string",
|
|
91
|
+
description:
|
|
92
|
+
"The specific task or question for the spawned agent to handle.",
|
|
93
|
+
},
|
|
94
|
+
maxIterations: {
|
|
95
|
+
type: "integer",
|
|
96
|
+
description:
|
|
97
|
+
"Maximum number of iterations for the sub-agent (default: 10)",
|
|
98
|
+
minimum: 1,
|
|
99
|
+
maximum: 50,
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
required: ["systemPrompt", "task"],
|
|
103
|
+
},
|
|
104
|
+
execute: async (input, context) => {
|
|
105
|
+
const { systemPrompt, task, maxIterations } = input;
|
|
106
|
+
|
|
107
|
+
// Create the sub-agent with the provided system prompt
|
|
108
|
+
const subAgent = new Agent({
|
|
109
|
+
providerId: config.providerId,
|
|
110
|
+
modelId: config.modelId,
|
|
111
|
+
apiKey: config.apiKey,
|
|
112
|
+
baseUrl: config.baseUrl,
|
|
113
|
+
systemPrompt,
|
|
114
|
+
tools: [], // Sub-agents don't get the spawn tool to prevent infinite recursion
|
|
115
|
+
maxIterations: maxIterations ?? config.subAgentMaxIterations ?? 10,
|
|
116
|
+
abortSignal: context.abortSignal,
|
|
117
|
+
onEvent: (event) => {
|
|
118
|
+
// Log sub-agent events with prefix for debugging
|
|
119
|
+
if (event.type === "content_start" && event.contentType === "text") {
|
|
120
|
+
console.log(`[SubAgent] ${event.text ?? ""}`);
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Run the sub-agent
|
|
126
|
+
const result = await subAgent.run(task);
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
text: result.text,
|
|
130
|
+
iterations: result.iterations,
|
|
131
|
+
finishReason: result.finishReason,
|
|
132
|
+
usage: {
|
|
133
|
+
inputTokens: result.usage.inputTokens,
|
|
134
|
+
outputTokens: result.usage.outputTokens,
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
},
|
|
138
|
+
timeoutMs: 300000, // 5 minutes for sub-agent execution
|
|
139
|
+
retryable: false, // Don't retry sub-agent spawns
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// =============================================================================
|
|
144
|
+
// Additional Example Tools
|
|
145
|
+
// =============================================================================
|
|
146
|
+
|
|
147
|
+
interface CalculateInput {
|
|
148
|
+
expression: string;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* A simple calculation tool for demonstration
|
|
153
|
+
*/
|
|
154
|
+
const calculatorTool = createTool<
|
|
155
|
+
CalculateInput,
|
|
156
|
+
{ result: number; expression: string }
|
|
157
|
+
>({
|
|
158
|
+
name: "calculate",
|
|
159
|
+
description:
|
|
160
|
+
"Perform basic mathematical calculations. Supports +, -, *, /, and ** (power).",
|
|
161
|
+
inputSchema: {
|
|
162
|
+
type: "object",
|
|
163
|
+
properties: {
|
|
164
|
+
expression: {
|
|
165
|
+
type: "string",
|
|
166
|
+
description:
|
|
167
|
+
"The mathematical expression to evaluate (e.g., '2 + 2', '10 * 5', '2 ** 8')",
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
required: ["expression"],
|
|
171
|
+
},
|
|
172
|
+
execute: async ({ expression }) => {
|
|
173
|
+
// Basic sanitization - only allow numbers and operators
|
|
174
|
+
const sanitized = expression.replace(/[^0-9+\-*/.()\s^]/g, "");
|
|
175
|
+
// Replace ^ with ** for power operations
|
|
176
|
+
const jsExpression = sanitized.replace(/\^/g, "**");
|
|
177
|
+
|
|
178
|
+
// Simple and safe math evaluation using basic parsing
|
|
179
|
+
const result = evaluateMathExpression(jsExpression);
|
|
180
|
+
return { result, expression: jsExpression };
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Simple math expression evaluator (safer than eval/Function)
|
|
186
|
+
*/
|
|
187
|
+
function evaluateMathExpression(expr: string): number {
|
|
188
|
+
// Remove whitespace
|
|
189
|
+
const cleaned = expr.replace(/\s/g, "");
|
|
190
|
+
|
|
191
|
+
// Basic recursive descent parser for safety
|
|
192
|
+
let pos = 0;
|
|
193
|
+
|
|
194
|
+
function parseNumber(): number {
|
|
195
|
+
let numStr = "";
|
|
196
|
+
while (pos < cleaned.length) {
|
|
197
|
+
const char = cleaned[pos];
|
|
198
|
+
if (char === undefined || !/[0-9.]/.test(char)) {
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
numStr += char;
|
|
202
|
+
pos++;
|
|
203
|
+
}
|
|
204
|
+
return Number.parseFloat(numStr);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function parseFactor(): number {
|
|
208
|
+
if (cleaned[pos] === "(") {
|
|
209
|
+
pos++; // skip '('
|
|
210
|
+
const result = parseExpression();
|
|
211
|
+
pos++; // skip ')'
|
|
212
|
+
return result;
|
|
213
|
+
}
|
|
214
|
+
if (cleaned[pos] === "-") {
|
|
215
|
+
pos++;
|
|
216
|
+
return -parseFactor();
|
|
217
|
+
}
|
|
218
|
+
return parseNumber();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function parsePower(): number {
|
|
222
|
+
let left = parseFactor();
|
|
223
|
+
while (pos < cleaned.length && cleaned.slice(pos, pos + 2) === "**") {
|
|
224
|
+
pos += 2;
|
|
225
|
+
left = left ** parseFactor();
|
|
226
|
+
}
|
|
227
|
+
return left;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function parseTerm(): number {
|
|
231
|
+
let left = parsePower();
|
|
232
|
+
while (
|
|
233
|
+
pos < cleaned.length &&
|
|
234
|
+
(cleaned[pos] === "*" || cleaned[pos] === "/")
|
|
235
|
+
) {
|
|
236
|
+
const op = cleaned[pos++];
|
|
237
|
+
const right = parsePower();
|
|
238
|
+
left = op === "*" ? left * right : left / right;
|
|
239
|
+
}
|
|
240
|
+
return left;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function parseExpression(): number {
|
|
244
|
+
let left = parseTerm();
|
|
245
|
+
while (
|
|
246
|
+
pos < cleaned.length &&
|
|
247
|
+
(cleaned[pos] === "+" || cleaned[pos] === "-")
|
|
248
|
+
) {
|
|
249
|
+
const op = cleaned[pos++];
|
|
250
|
+
const right = parseTerm();
|
|
251
|
+
left = op === "+" ? left + right : left - right;
|
|
252
|
+
}
|
|
253
|
+
return left;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return parseExpression();
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
interface DateTimeInput {
|
|
260
|
+
format: "iso" | "unix" | "readable" | "components";
|
|
261
|
+
timezone?: string;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
type DateTimeOutput =
|
|
265
|
+
| { datetime: string; timezone: string }
|
|
266
|
+
| { timestamp: number; milliseconds: number }
|
|
267
|
+
| {
|
|
268
|
+
year: number;
|
|
269
|
+
month: number;
|
|
270
|
+
day: number;
|
|
271
|
+
hour: number;
|
|
272
|
+
minute: number;
|
|
273
|
+
second: number;
|
|
274
|
+
dayOfWeek: string;
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* A tool to get current date/time
|
|
279
|
+
*/
|
|
280
|
+
const dateTimeTool = createTool<DateTimeInput, DateTimeOutput>({
|
|
281
|
+
name: "get_datetime",
|
|
282
|
+
description: "Get the current date and time in various formats",
|
|
283
|
+
inputSchema: {
|
|
284
|
+
type: "object",
|
|
285
|
+
properties: {
|
|
286
|
+
format: {
|
|
287
|
+
type: "string",
|
|
288
|
+
description:
|
|
289
|
+
"Output format: 'iso', 'unix', 'readable', or 'components'",
|
|
290
|
+
enum: ["iso", "unix", "readable", "components"],
|
|
291
|
+
},
|
|
292
|
+
timezone: {
|
|
293
|
+
type: "string",
|
|
294
|
+
description:
|
|
295
|
+
"Timezone (e.g., 'UTC', 'America/New_York'). Defaults to local timezone.",
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
required: ["format"],
|
|
299
|
+
},
|
|
300
|
+
execute: async ({ format, timezone }) => {
|
|
301
|
+
const now = new Date();
|
|
302
|
+
|
|
303
|
+
switch (format) {
|
|
304
|
+
case "iso":
|
|
305
|
+
return { datetime: now.toISOString(), timezone: timezone ?? "UTC" };
|
|
306
|
+
case "unix":
|
|
307
|
+
return {
|
|
308
|
+
timestamp: Math.floor(now.getTime() / 1000),
|
|
309
|
+
milliseconds: now.getTime(),
|
|
310
|
+
};
|
|
311
|
+
case "readable":
|
|
312
|
+
return {
|
|
313
|
+
datetime: now.toLocaleString("en-US", {
|
|
314
|
+
timeZone: timezone ?? undefined,
|
|
315
|
+
dateStyle: "full",
|
|
316
|
+
timeStyle: "long",
|
|
317
|
+
}),
|
|
318
|
+
timezone: timezone ?? "local",
|
|
319
|
+
};
|
|
320
|
+
case "components":
|
|
321
|
+
return {
|
|
322
|
+
year: now.getFullYear(),
|
|
323
|
+
month: now.getMonth() + 1,
|
|
324
|
+
day: now.getDate(),
|
|
325
|
+
hour: now.getHours(),
|
|
326
|
+
minute: now.getMinutes(),
|
|
327
|
+
second: now.getSeconds(),
|
|
328
|
+
dayOfWeek: now.toLocaleDateString("en-US", { weekday: "long" }),
|
|
329
|
+
};
|
|
330
|
+
default:
|
|
331
|
+
return { datetime: now.toISOString(), timezone: "UTC" };
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
// =============================================================================
|
|
337
|
+
// Event Handler
|
|
338
|
+
// =============================================================================
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Handle agent events for logging/debugging
|
|
342
|
+
*/
|
|
343
|
+
function handleAgentEvent(event: AgentEvent): void {
|
|
344
|
+
switch (event.type) {
|
|
345
|
+
case "iteration_start":
|
|
346
|
+
console.log(`\n--- Iteration ${event.iteration} ---`);
|
|
347
|
+
break;
|
|
348
|
+
case "content_start":
|
|
349
|
+
if (event.contentType === "text") {
|
|
350
|
+
process.stdout.write(event.text ?? "");
|
|
351
|
+
} else if (event.contentType === "reasoning") {
|
|
352
|
+
if (!event.redacted) {
|
|
353
|
+
console.log(`[Thinking] ${event.reasoning ?? ""}`);
|
|
354
|
+
}
|
|
355
|
+
} else if (event.contentType === "tool") {
|
|
356
|
+
console.log(`\n[Tool] Calling ${event.toolName}...`);
|
|
357
|
+
}
|
|
358
|
+
break;
|
|
359
|
+
case "content_end":
|
|
360
|
+
if (event.contentType === "tool") {
|
|
361
|
+
if (event.error) {
|
|
362
|
+
console.log(`[Tool] ${event.toolName} failed: ${event.error}`);
|
|
363
|
+
} else {
|
|
364
|
+
console.log(
|
|
365
|
+
`[Tool] ${event.toolName} completed in ${event.durationMs}ms`,
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
break;
|
|
370
|
+
case "usage":
|
|
371
|
+
console.log(
|
|
372
|
+
`[Usage] In: ${event.totalInputTokens}, Out: ${event.totalOutputTokens}`,
|
|
373
|
+
);
|
|
374
|
+
break;
|
|
375
|
+
case "done":
|
|
376
|
+
console.log(
|
|
377
|
+
`\n--- Done (${event.reason}) after ${event.iterations} iterations ---`,
|
|
378
|
+
);
|
|
379
|
+
break;
|
|
380
|
+
case "error":
|
|
381
|
+
console.error(`[Error] ${event.error.message}`);
|
|
382
|
+
break;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// =============================================================================
|
|
387
|
+
// Main Agent Factory
|
|
388
|
+
// =============================================================================
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Creates a main orchestrator agent that can spawn sub-agents.
|
|
392
|
+
*
|
|
393
|
+
* @param systemPrompt - The system prompt defining the main agent's behavior
|
|
394
|
+
* @param config - Configuration for the agent and sub-agent spawning
|
|
395
|
+
* @param additionalTools - Additional tools to provide to the main agent
|
|
396
|
+
*/
|
|
397
|
+
export function createOrchestratorAgent(
|
|
398
|
+
systemPrompt: string,
|
|
399
|
+
config: AgentSpawnerConfig,
|
|
400
|
+
additionalTools: Tool[] = [],
|
|
401
|
+
): Agent {
|
|
402
|
+
// Create the spawn agent tool
|
|
403
|
+
const spawnTool = createSpawnAgentTool(config);
|
|
404
|
+
|
|
405
|
+
// Combine all tools (cast to Tool[] since generics are contravariant in input)
|
|
406
|
+
const tools = [
|
|
407
|
+
spawnTool,
|
|
408
|
+
calculatorTool,
|
|
409
|
+
dateTimeTool,
|
|
410
|
+
...additionalTools,
|
|
411
|
+
] as Tool[];
|
|
412
|
+
|
|
413
|
+
// Create and return the agent
|
|
414
|
+
return new Agent({
|
|
415
|
+
providerId: config.providerId,
|
|
416
|
+
modelId: config.modelId,
|
|
417
|
+
apiKey: config.apiKey,
|
|
418
|
+
baseUrl: config.baseUrl,
|
|
419
|
+
systemPrompt,
|
|
420
|
+
tools,
|
|
421
|
+
maxIterations: 50,
|
|
422
|
+
onEvent: handleAgentEvent,
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// =============================================================================
|
|
427
|
+
// Example Usage
|
|
428
|
+
// =============================================================================
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Example: Run the orchestrator agent with a task
|
|
432
|
+
*/
|
|
433
|
+
async function runExample(): Promise<void> {
|
|
434
|
+
// Check for API key
|
|
435
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
436
|
+
if (!apiKey) {
|
|
437
|
+
console.error("Please set ANTHROPIC_API_KEY environment variable");
|
|
438
|
+
process.exit(1);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Model to use
|
|
442
|
+
const modelId = "claude-sonnet-4-20250514";
|
|
443
|
+
console.log(`Using model: ${modelId}`);
|
|
444
|
+
console.log();
|
|
445
|
+
|
|
446
|
+
// Create the orchestrator agent
|
|
447
|
+
const orchestrator = createOrchestratorAgent(
|
|
448
|
+
`You are an intelligent orchestrator that can delegate tasks to specialized sub-agents.
|
|
449
|
+
|
|
450
|
+
When faced with complex tasks, consider:
|
|
451
|
+
1. Breaking them into smaller, focused sub-tasks
|
|
452
|
+
2. Spawning specialized agents with appropriate system prompts
|
|
453
|
+
3. Synthesizing results from multiple agents
|
|
454
|
+
|
|
455
|
+
You have access to:
|
|
456
|
+
- spawn_agent: Create a new agent with a custom system prompt
|
|
457
|
+
- calculate: Perform mathematical calculations
|
|
458
|
+
- get_datetime: Get current date/time
|
|
459
|
+
|
|
460
|
+
Be strategic about when to spawn agents vs. handling tasks directly.`,
|
|
461
|
+
{
|
|
462
|
+
providerId: "anthropic",
|
|
463
|
+
modelId: "claude-sonnet-4-20250514",
|
|
464
|
+
apiKey,
|
|
465
|
+
subAgentMaxIterations: 5,
|
|
466
|
+
},
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
// Example task that might benefit from sub-agent delegation
|
|
470
|
+
const task = `I need help with two things:
|
|
471
|
+
1. Calculate the compound interest on $10,000 at 5% annual rate for 10 years
|
|
472
|
+
2. Write a haiku about programming
|
|
473
|
+
|
|
474
|
+
For the haiku, please spawn a specialized creative writing agent to handle it.`;
|
|
475
|
+
|
|
476
|
+
console.log("=".repeat(60));
|
|
477
|
+
console.log("Task:", task);
|
|
478
|
+
console.log("=".repeat(60));
|
|
479
|
+
|
|
480
|
+
// Run the agent
|
|
481
|
+
const result = await orchestrator.run(task);
|
|
482
|
+
|
|
483
|
+
// Print summary
|
|
484
|
+
console.log(`\n${"=".repeat(60)}`);
|
|
485
|
+
console.log("Final Result:");
|
|
486
|
+
console.log("=".repeat(60));
|
|
487
|
+
console.log(result.text);
|
|
488
|
+
console.log("\nStats:");
|
|
489
|
+
console.log(` - Iterations: ${result.iterations}`);
|
|
490
|
+
console.log(
|
|
491
|
+
` - Total tokens: ${result.usage.inputTokens + result.usage.outputTokens}`,
|
|
492
|
+
);
|
|
493
|
+
console.log(` - Tool calls: ${result.toolCalls.length}`);
|
|
494
|
+
console.log(` - Duration: ${result.durationMs}ms`);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// =============================================================================
|
|
498
|
+
// Alternative: Lower-level Provider Usage
|
|
499
|
+
// =============================================================================
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Example of using @clinebot/llms directly for more control
|
|
503
|
+
*/
|
|
504
|
+
async function runLowLevelExample(): Promise<void> {
|
|
505
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
506
|
+
if (!apiKey) {
|
|
507
|
+
console.error("Please set ANTHROPIC_API_KEY environment variable");
|
|
508
|
+
process.exit(1);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Create a handler directly using @clinebot/llms
|
|
512
|
+
const config: providers.ProviderConfig = {
|
|
513
|
+
providerId: "anthropic",
|
|
514
|
+
apiKey,
|
|
515
|
+
modelId: "claude-sonnet-4-20250514",
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
const handler = providers.createHandler(config);
|
|
519
|
+
|
|
520
|
+
// Use the handler to create a message stream
|
|
521
|
+
const stream = handler.createMessage(
|
|
522
|
+
"You are a helpful assistant.",
|
|
523
|
+
[{ role: "user", content: "Say hello in 3 languages." }],
|
|
524
|
+
[], // No tools for this simple example
|
|
525
|
+
);
|
|
526
|
+
|
|
527
|
+
// Process the stream
|
|
528
|
+
console.log("Response: ");
|
|
529
|
+
for await (const chunk of stream) {
|
|
530
|
+
if (chunk.type === "text") {
|
|
531
|
+
process.stdout.write(chunk.text);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
console.log();
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// =============================================================================
|
|
538
|
+
// Exports for Library Usage
|
|
539
|
+
// =============================================================================
|
|
540
|
+
|
|
541
|
+
export {
|
|
542
|
+
createSpawnAgentTool,
|
|
543
|
+
calculatorTool,
|
|
544
|
+
dateTimeTool,
|
|
545
|
+
handleAgentEvent,
|
|
546
|
+
type AgentSpawnerConfig,
|
|
547
|
+
type SpawnAgentInput,
|
|
548
|
+
type SpawnAgentOutput,
|
|
549
|
+
};
|
|
550
|
+
|
|
551
|
+
// =============================================================================
|
|
552
|
+
// CLI Entry Point
|
|
553
|
+
// =============================================================================
|
|
554
|
+
|
|
555
|
+
// Run if executed directly
|
|
556
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
557
|
+
const mode = process.argv[2] ?? "orchestrator";
|
|
558
|
+
|
|
559
|
+
if (mode === "low-level") {
|
|
560
|
+
runLowLevelExample().catch(console.error);
|
|
561
|
+
} else {
|
|
562
|
+
runExample().catch(console.error);
|
|
563
|
+
}
|
|
564
|
+
}
|