modular-agent-examples 0.0.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/chunking-demo.ts +339 -0
- package/cleanup-duplicates.ts +142 -0
- package/data/flower.jpg +0 -0
- package/generative.ts +128 -0
- package/graph/context-example.ts +209 -0
- package/graph/data-pipeline/agents.ts +60 -0
- package/graph/data-pipeline/fetchers.ts +166 -0
- package/graph/data-pipeline/index.ts +282 -0
- package/graph/index.ts +154 -0
- package/graph/map-example.ts +227 -0
- package/graph/metrics-example.ts +238 -0
- package/graph/parallel-example.ts +167 -0
- package/graph/pipeline-example.ts +225 -0
- package/graph/planning-example.ts +406 -0
- package/graph/router-example.ts +226 -0
- package/graph/sequential-example.ts +141 -0
- package/graph/voting-example.ts +159 -0
- package/graph-rag/docker-compose.yaml +14 -0
- package/graph-rag/index.js +99 -0
- package/graph-rag/init-db.sh +7 -0
- package/graph-rag/package.json +15 -0
- package/history-compression-example.ts +163 -0
- package/history-persistence.ts +347 -0
- package/index.ts +175 -0
- package/ingestion-pipeline.ts +353 -0
- package/mcp-airbnb-example.ts +69 -0
- package/mcp-http-example.ts +70 -0
- package/mcp-stdio-example.ts +63 -0
- package/multimodal.ts +144 -0
- package/ollama.ts +148 -0
- package/openai-compatible.ts +141 -0
- package/opensearch-vector-store.ts +342 -0
- package/package.json +24 -0
- package/pubmed.ts +289 -0
- package/reasoning-with-sub-agent.ts +311 -0
- package/synchronous/index.ts +48 -0
- package/tsconfig.json +8 -0
- package/vector-store-filtering.ts +303 -0
- package/vector-store.ts +210 -0
- package/vectorstore/index.ts +0 -0
- package/vectorstore/store/dbService.ts +80 -0
- package/voyage-embeddings.ts +99 -0
- package/weather-with-sub-agent.ts +276 -0
- package/weather.ts +389 -0
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Planning and Execution Example
|
|
3
|
+
*
|
|
4
|
+
* This example demonstrates the refactored PlanExecutor with clear separation:
|
|
5
|
+
* 1. Planning Agent: Creates the execution plan
|
|
6
|
+
* 2. Worker Agent: Executes individual steps
|
|
7
|
+
* 3. Executor: Orchestrates the workflow and tracks progress
|
|
8
|
+
*
|
|
9
|
+
* Run with: npx ts-node examples/graph/planning-example.ts
|
|
10
|
+
*/
|
|
11
|
+
import "dotenv/config";
|
|
12
|
+
|
|
13
|
+
import { AgentGraph } from "../../lib/graph/AgentGraph";
|
|
14
|
+
import { ClaudeAgent } from "../../lib/agents/anthropic/ClaudeAgent";
|
|
15
|
+
|
|
16
|
+
async function main() {
|
|
17
|
+
console.log("=== Plan-Based Execution Example ===\n");
|
|
18
|
+
|
|
19
|
+
// Create stores for planning and context
|
|
20
|
+
const planStore = AgentGraph.createPlanStore();
|
|
21
|
+
const contextStore = AgentGraph.createContextStore({
|
|
22
|
+
project_name: "LLM Research 2024",
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Planning Agent: Responsible ONLY for creating plans
|
|
26
|
+
const planningAgent = new ClaudeAgent({
|
|
27
|
+
id: "planner",
|
|
28
|
+
name: "Planning Agent",
|
|
29
|
+
description: `You are a planning agent. Your ONLY job is to create execution plans.
|
|
30
|
+
|
|
31
|
+
When given a task:
|
|
32
|
+
1. Analyze the task requirements
|
|
33
|
+
2. Use create_plan to create a plan with clear, actionable steps
|
|
34
|
+
3. Each step should be specific and focused on a single subtask
|
|
35
|
+
4. Order steps logically (handle dependencies first)
|
|
36
|
+
5. Tasks should be small and focused. Ask for concise answers
|
|
37
|
+
|
|
38
|
+
After creating the plan, confirm with: "Plan created with X steps."
|
|
39
|
+
|
|
40
|
+
Do NOT execute the steps yourself - that's the worker's job.`,
|
|
41
|
+
apiKey: process.env.ANTHROPIC_API_KEY || "",
|
|
42
|
+
model: "claude-haiku-4-5",
|
|
43
|
+
maxTokens: 4048,
|
|
44
|
+
tools: AgentGraph.createPlanningTools(planStore),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Worker Agent: Executes individual steps
|
|
48
|
+
const workerAgent = new ClaudeAgent({
|
|
49
|
+
id: "worker",
|
|
50
|
+
name: "Worker Agent",
|
|
51
|
+
description: `You are a worker agent. You execute ONE specific step at a time.
|
|
52
|
+
|
|
53
|
+
You will receive:
|
|
54
|
+
- The current step to execute
|
|
55
|
+
- Previous steps and their results
|
|
56
|
+
- The overall plan goal
|
|
57
|
+
|
|
58
|
+
Your job:
|
|
59
|
+
1. Execute ONLY the current step
|
|
60
|
+
2. Store important results using context_set with descriptive keys
|
|
61
|
+
3. Return a summary of what you accomplished
|
|
62
|
+
|
|
63
|
+
Context keys to use:
|
|
64
|
+
- "step_X_result" - Result of step X
|
|
65
|
+
- "findings" - Key findings or data
|
|
66
|
+
- "sources" - Sources consulted
|
|
67
|
+
- "analysis" - Analysis results
|
|
68
|
+
|
|
69
|
+
Be focused on the current step. Keep answers VERY concise (1-2 sentences max).`,
|
|
70
|
+
apiKey: process.env.ANTHROPIC_API_KEY || "",
|
|
71
|
+
model: "claude-haiku-4-5",
|
|
72
|
+
maxTokens: 512,
|
|
73
|
+
tools: AgentGraph.createContextTools(contextStore),
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Create the executor with callbacks for visibility
|
|
77
|
+
const executor = AgentGraph.planExecutor(
|
|
78
|
+
planStore,
|
|
79
|
+
planningAgent,
|
|
80
|
+
workerAgent,
|
|
81
|
+
{
|
|
82
|
+
maxSteps: 3,
|
|
83
|
+
concurrency: 1,
|
|
84
|
+
onPlanCreated: (goal, steps) => {
|
|
85
|
+
console.log(`\n📋 Plan Created: ${goal}`);
|
|
86
|
+
console.log(` Steps: ${steps.length}\n`);
|
|
87
|
+
steps.forEach((step, i) => {
|
|
88
|
+
console.log(` ${i + 1}. ${step.description}`);
|
|
89
|
+
});
|
|
90
|
+
console.log("");
|
|
91
|
+
},
|
|
92
|
+
onStepStart: (step, num, total) => {
|
|
93
|
+
console.log(`\n🔄 Step ${num}/${total}: ${step.description}`);
|
|
94
|
+
},
|
|
95
|
+
onStepComplete: (_step, result, num) => {
|
|
96
|
+
const summary =
|
|
97
|
+
result.length > 100 ? result.substring(0, 100) + "..." : result;
|
|
98
|
+
console.log(`✅ Step ${num} Complete: ${summary}`);
|
|
99
|
+
},
|
|
100
|
+
onStepFailed: (_step, error, num) => {
|
|
101
|
+
console.log(`❌ Step ${num} Failed: ${error.message}`);
|
|
102
|
+
},
|
|
103
|
+
}
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
// Execute a simple task
|
|
108
|
+
const finalOutput = await executor.execute(
|
|
109
|
+
"List 3 major programming paradigms (OOP, Functional, Procedural) " +
|
|
110
|
+
"and provide one key characteristic of each. Keep it brief."
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
// Get detailed results
|
|
114
|
+
const result = executor.getLastResult()!;
|
|
115
|
+
|
|
116
|
+
// Display results
|
|
117
|
+
console.log("\n\n=== Execution Complete ===");
|
|
118
|
+
console.log(`Success: ${result.success}`);
|
|
119
|
+
console.log(`Goal: ${result.goal}`);
|
|
120
|
+
console.log(
|
|
121
|
+
`Steps: ${result.completedSteps}/${result.totalSteps} completed`
|
|
122
|
+
);
|
|
123
|
+
if (result.failedSteps > 0) {
|
|
124
|
+
console.log(`Failed: ${result.failedSteps}`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
console.log(`\n${result.summary}`);
|
|
128
|
+
|
|
129
|
+
// Display the finalOutput (clean output ready for chaining to next graph node)
|
|
130
|
+
console.log("\n\n=== Final Output (for graph chaining) ===");
|
|
131
|
+
console.log(finalOutput);
|
|
132
|
+
|
|
133
|
+
// Display context store contents
|
|
134
|
+
console.log("\n\n=== Context Store Contents ===");
|
|
135
|
+
const contextKeys = contextStore.keys();
|
|
136
|
+
if (contextKeys.length === 0) {
|
|
137
|
+
console.log("(empty)");
|
|
138
|
+
} else {
|
|
139
|
+
for (const key of contextKeys) {
|
|
140
|
+
const value = contextStore.get(key);
|
|
141
|
+
const displayValue =
|
|
142
|
+
typeof value === "string"
|
|
143
|
+
? value.substring(0, 150) + (value.length > 150 ? "..." : "")
|
|
144
|
+
: JSON.stringify(value, null, 2).substring(0, 150);
|
|
145
|
+
console.log(`\n[${key}]:`);
|
|
146
|
+
console.log(displayValue);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Display step-by-step results
|
|
151
|
+
console.log("\n\n=== Step Results ===");
|
|
152
|
+
result.stepResults.forEach((sr, i) => {
|
|
153
|
+
console.log(`\n${i + 1}. ${sr.step.description}`);
|
|
154
|
+
console.log(` Status: ${sr.step.status}`);
|
|
155
|
+
if (sr.result) {
|
|
156
|
+
const summary =
|
|
157
|
+
sr.result.length > 100
|
|
158
|
+
? sr.result.substring(0, 100) + "..."
|
|
159
|
+
: sr.result;
|
|
160
|
+
console.log(` Result: ${summary}`);
|
|
161
|
+
}
|
|
162
|
+
if (sr.error) {
|
|
163
|
+
console.log(` Error: ${sr.error}`);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
} catch (error) {
|
|
167
|
+
console.error("\n❌ Execution failed:", error);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Example using a GraphNode worker instead of an agent
|
|
173
|
+
*/
|
|
174
|
+
async function graphNodeWorkerExample() {
|
|
175
|
+
console.log("\n\n=== GraphNode Worker Example ===\n");
|
|
176
|
+
|
|
177
|
+
const planStore = AgentGraph.createPlanStore();
|
|
178
|
+
const contextStore = AgentGraph.createContextStore();
|
|
179
|
+
|
|
180
|
+
// Planning agent
|
|
181
|
+
const planningAgent = new ClaudeAgent({
|
|
182
|
+
id: "planner",
|
|
183
|
+
name: "Planner",
|
|
184
|
+
description: "Create a plan for the given task using create_plan.",
|
|
185
|
+
apiKey: process.env.ANTHROPIC_API_KEY || "",
|
|
186
|
+
model: "claude-sonnet-4-20250514",
|
|
187
|
+
maxTokens: 2048,
|
|
188
|
+
tools: AgentGraph.createPlanningTools(planStore),
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Worker agent
|
|
192
|
+
const workerAgent = new ClaudeAgent({
|
|
193
|
+
id: "worker",
|
|
194
|
+
name: "Worker",
|
|
195
|
+
description: "Execute the given step and store results in context.",
|
|
196
|
+
apiKey: process.env.ANTHROPIC_API_KEY || "",
|
|
197
|
+
model: "claude-sonnet-4-20250514",
|
|
198
|
+
maxTokens: 2048,
|
|
199
|
+
tools: AgentGraph.createContextTools(contextStore),
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Could also use a Pipeline or other GraphNode as the worker:
|
|
203
|
+
// const workerPipeline = AgentGraph.pipeline([
|
|
204
|
+
// analyzeAgent,
|
|
205
|
+
// processAgent,
|
|
206
|
+
// storeAgent,
|
|
207
|
+
// ]);
|
|
208
|
+
|
|
209
|
+
const executor = AgentGraph.planExecutor(
|
|
210
|
+
planStore,
|
|
211
|
+
planningAgent,
|
|
212
|
+
workerAgent, // Could be workerPipeline or any GraphNode
|
|
213
|
+
{
|
|
214
|
+
onPlanCreated: (goal, steps) => {
|
|
215
|
+
console.log(`Plan: ${goal} (${steps.length} steps)`);
|
|
216
|
+
},
|
|
217
|
+
onStepComplete: (step, _result, num) => {
|
|
218
|
+
console.log(` ✓ Step ${num}: ${step.description}`);
|
|
219
|
+
},
|
|
220
|
+
}
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
try {
|
|
224
|
+
const finalOutput = await executor.execute(
|
|
225
|
+
"Analyze the components of a microservices architecture. " +
|
|
226
|
+
"List: API Gateway, Service Mesh, and Container Orchestration."
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
const result = executor.getLastResult()!;
|
|
230
|
+
console.log(
|
|
231
|
+
`\n✅ Complete: ${result.completedSteps}/${result.totalSteps} steps`
|
|
232
|
+
);
|
|
233
|
+
console.log(`\nFinal Output:\n${finalOutput}`);
|
|
234
|
+
} catch (error) {
|
|
235
|
+
console.error("Error:", error);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Example using concurrent execution
|
|
241
|
+
*/
|
|
242
|
+
async function concurrentExecutionExample() {
|
|
243
|
+
console.log("\n\n=== Concurrent Execution Example ===\n");
|
|
244
|
+
|
|
245
|
+
const planStore = AgentGraph.createPlanStore();
|
|
246
|
+
const contextStore = AgentGraph.createContextStore();
|
|
247
|
+
|
|
248
|
+
// Planning agent
|
|
249
|
+
const planningAgent = new ClaudeAgent({
|
|
250
|
+
id: "concurrent-planner",
|
|
251
|
+
name: "Concurrent Planner",
|
|
252
|
+
description: `Create a plan with independent steps that can run in parallel.
|
|
253
|
+
|
|
254
|
+
When given a task, break it into independent subtasks that don't depend on each other.
|
|
255
|
+
Use create_plan to create the plan.`,
|
|
256
|
+
apiKey: process.env.ANTHROPIC_API_KEY || "",
|
|
257
|
+
model: "claude-haiku-4-5",
|
|
258
|
+
maxTokens: 4048,
|
|
259
|
+
tools: AgentGraph.createPlanningTools(planStore),
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// Worker agent
|
|
263
|
+
const workerAgent = new ClaudeAgent({
|
|
264
|
+
id: "concurrent-worker",
|
|
265
|
+
name: "Concurrent Worker",
|
|
266
|
+
description: "Execute a single step independently and store results.",
|
|
267
|
+
apiKey: process.env.ANTHROPIC_API_KEY || "",
|
|
268
|
+
model: "claude-haiku-4-5",
|
|
269
|
+
maxTokens: 4048,
|
|
270
|
+
tools: AgentGraph.createContextTools(contextStore),
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
const executor = AgentGraph.planExecutor(
|
|
274
|
+
planStore,
|
|
275
|
+
planningAgent,
|
|
276
|
+
workerAgent,
|
|
277
|
+
{
|
|
278
|
+
maxSteps: 20,
|
|
279
|
+
concurrency: 3, // Run up to 3 steps concurrently
|
|
280
|
+
onPlanCreated: (goal, steps) => {
|
|
281
|
+
console.log(`📋 Plan: ${goal}`);
|
|
282
|
+
console.log(` Steps: ${steps.length}`);
|
|
283
|
+
console.log(` Concurrency: 3 (up to 3 steps run in parallel)\n`);
|
|
284
|
+
},
|
|
285
|
+
onStepStart: (step, num, total) => {
|
|
286
|
+
console.log(`🚀 [${num}/${total}] Starting: ${step.description}`);
|
|
287
|
+
},
|
|
288
|
+
onStepComplete: (_step, _result, num) => {
|
|
289
|
+
console.log(`✅ [${num}] Completed`);
|
|
290
|
+
},
|
|
291
|
+
onStepFailed: (_step, error, num) => {
|
|
292
|
+
console.log(`❌ [${num}] Failed: ${error.message}`);
|
|
293
|
+
},
|
|
294
|
+
}
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
try {
|
|
298
|
+
const startTime = Date.now();
|
|
299
|
+
|
|
300
|
+
const finalOutput = await executor.execute(
|
|
301
|
+
"Research three different programming languages: Python, Rust, and Go. " +
|
|
302
|
+
"For each language, summarize its main use cases and key features. " +
|
|
303
|
+
"These research tasks are independent and can be done in parallel."
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
const result = executor.getLastResult()!;
|
|
307
|
+
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
308
|
+
|
|
309
|
+
console.log(`\n\n⏱️ Total time: ${duration}s`);
|
|
310
|
+
console.log(`✅ Success: ${result.success}`);
|
|
311
|
+
console.log(
|
|
312
|
+
`📊 Steps: ${result.completedSteps}/${result.totalSteps} completed`
|
|
313
|
+
);
|
|
314
|
+
if (result.failedSteps > 0) {
|
|
315
|
+
console.log(`❌ Failed: ${result.failedSteps}`);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
console.log(`\nFinal Output:\n${finalOutput}`);
|
|
319
|
+
|
|
320
|
+
console.log(
|
|
321
|
+
"\n💡 Note: With concurrency=3, independent steps ran in parallel,"
|
|
322
|
+
);
|
|
323
|
+
console.log(
|
|
324
|
+
" reducing total execution time compared to sequential execution."
|
|
325
|
+
);
|
|
326
|
+
} catch (error) {
|
|
327
|
+
console.error("\n❌ Error:", error);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Example showing PlanExecutor chained in a pipeline
|
|
333
|
+
*/
|
|
334
|
+
async function pipelineChainExample() {
|
|
335
|
+
console.log("\n\n=== Pipeline Chain Example ===\n");
|
|
336
|
+
|
|
337
|
+
const planStore = AgentGraph.createPlanStore();
|
|
338
|
+
const contextStore = AgentGraph.createContextStore();
|
|
339
|
+
|
|
340
|
+
// Step 1: Planning executor that generates research
|
|
341
|
+
const planner = new ClaudeAgent({
|
|
342
|
+
id: "research-planner",
|
|
343
|
+
name: "Research Planner",
|
|
344
|
+
description: "Create and execute a research plan. Keep output concise.",
|
|
345
|
+
apiKey: process.env.ANTHROPIC_API_KEY || "",
|
|
346
|
+
model: "claude-haiku-4-5",
|
|
347
|
+
maxTokens: 1024,
|
|
348
|
+
tools: AgentGraph.createPlanningTools(planStore),
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
const worker = new ClaudeAgent({
|
|
352
|
+
id: "research-worker",
|
|
353
|
+
name: "Research Worker",
|
|
354
|
+
description: "Execute research steps. Keep responses to 1-2 sentences.",
|
|
355
|
+
apiKey: process.env.ANTHROPIC_API_KEY || "",
|
|
356
|
+
model: "claude-haiku-4-5",
|
|
357
|
+
maxTokens: 512,
|
|
358
|
+
tools: AgentGraph.createContextTools(contextStore),
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
const planExecutor = AgentGraph.planExecutor(planStore, planner, worker, {
|
|
362
|
+
maxSteps: 3,
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
// Step 2: Summarizer agent that processes the plan output
|
|
366
|
+
const summarizer = new ClaudeAgent({
|
|
367
|
+
id: "summarizer",
|
|
368
|
+
name: "Summarizer",
|
|
369
|
+
description: "Create a summary from the provided results.",
|
|
370
|
+
apiKey: process.env.ANTHROPIC_API_KEY || "",
|
|
371
|
+
model: "claude-haiku-4-5",
|
|
372
|
+
maxTokens: 256,
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
// Create a sequential chain: PlanExecutor → Summarizer
|
|
376
|
+
// Note: We need to wrap PlanExecutor since sequential expects BaseAgent
|
|
377
|
+
// For true pipeline chaining, PlanExecutor can be used standalone and its
|
|
378
|
+
// finalOutput can be passed to the next node manually
|
|
379
|
+
const pipeline = AgentGraph.pipeline(
|
|
380
|
+
planExecutor,
|
|
381
|
+
AgentGraph.sequential(summarizer)
|
|
382
|
+
);
|
|
383
|
+
|
|
384
|
+
try {
|
|
385
|
+
console.log("Pipeline: [PlanExecutor] → [Summarizer]\n");
|
|
386
|
+
|
|
387
|
+
const result = await pipeline.execute(
|
|
388
|
+
"List 3 benefits of TypeScript. Keep each benefit to one sentence."
|
|
389
|
+
);
|
|
390
|
+
|
|
391
|
+
console.log("\n=== Pipeline Result ===");
|
|
392
|
+
console.log(result);
|
|
393
|
+
console.log(
|
|
394
|
+
"\n💡 The PlanExecutor's finalOutput was automatically passed to the Summarizer!"
|
|
395
|
+
);
|
|
396
|
+
} catch (error) {
|
|
397
|
+
console.error("\n❌ Error:", error);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Run examples
|
|
402
|
+
main()
|
|
403
|
+
.then(() => graphNodeWorkerExample())
|
|
404
|
+
.then(() => concurrentExecutionExample())
|
|
405
|
+
.then(() => pipelineChainExample())
|
|
406
|
+
.catch(console.error);
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Router Executor Example
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates intelligent routing of user input to specialized handlers.
|
|
5
|
+
* The router agent analyzes each query and selects the most appropriate
|
|
6
|
+
* expert to handle it.
|
|
7
|
+
*
|
|
8
|
+
* Use case: Customer support, multi-domain assistants, specialized agents
|
|
9
|
+
*/
|
|
10
|
+
import "dotenv/config";
|
|
11
|
+
import { createInterface } from "node:readline/promises";
|
|
12
|
+
import { OpenAiAgent } from "../../lib/agents/openai/OpenAiAgent";
|
|
13
|
+
import { ClaudeAgent } from "../../lib/agents/anthropic/ClaudeAgent";
|
|
14
|
+
import { AgentGraph } from "../../lib/graph/AgentGraph";
|
|
15
|
+
|
|
16
|
+
const apiKey = process.env.ANTHROPIC_API_KEY as string;
|
|
17
|
+
const openAiApiKey = process.env.OPENAI_API_KEY as string;
|
|
18
|
+
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// Specialized Handler Agents
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
const technicalAgent = new OpenAiAgent({
|
|
24
|
+
id: "technical",
|
|
25
|
+
name: "Technical Expert",
|
|
26
|
+
description: `You are a technical support expert specializing in programming, software, and technology.
|
|
27
|
+
You help with:
|
|
28
|
+
- Code debugging and best practices
|
|
29
|
+
- Software installation and configuration
|
|
30
|
+
- Technical concepts and explanations
|
|
31
|
+
- Architecture and design patterns
|
|
32
|
+
|
|
33
|
+
Be precise and include code examples when relevant. Keep responses focused and actionable.`,
|
|
34
|
+
apiKey: openAiApiKey,
|
|
35
|
+
maxTokens: 1024,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const creativeAgent = new OpenAiAgent({
|
|
39
|
+
id: "creative",
|
|
40
|
+
name: "Creative Writer",
|
|
41
|
+
description: `You are a creative writing assistant specializing in storytelling and content creation.
|
|
42
|
+
You help with:
|
|
43
|
+
- Story ideas and plot development
|
|
44
|
+
- Character creation and dialogue
|
|
45
|
+
- Poetry and creative prose
|
|
46
|
+
- Marketing copy and taglines
|
|
47
|
+
|
|
48
|
+
Be imaginative and inspiring. Offer multiple options when brainstorming.`,
|
|
49
|
+
apiKey: openAiApiKey,
|
|
50
|
+
maxTokens: 1024,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const analyticsAgent = new ClaudeAgent({
|
|
54
|
+
id: "analytics",
|
|
55
|
+
name: "Data Analyst",
|
|
56
|
+
description: `You are a data analytics expert specializing in analysis and insights.
|
|
57
|
+
You help with:
|
|
58
|
+
- Data interpretation and visualization advice
|
|
59
|
+
- Statistical concepts and methods
|
|
60
|
+
- Business metrics and KPIs
|
|
61
|
+
- Research methodology
|
|
62
|
+
|
|
63
|
+
Be analytical and data-driven. Explain your reasoning clearly.`,
|
|
64
|
+
apiKey,
|
|
65
|
+
maxTokens: 1024,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const generalAgent = new ClaudeAgent({
|
|
69
|
+
id: "general",
|
|
70
|
+
name: "General Assistant",
|
|
71
|
+
description: `You are a helpful general assistant for everyday questions.
|
|
72
|
+
You help with:
|
|
73
|
+
- General knowledge questions
|
|
74
|
+
- Recommendations and advice
|
|
75
|
+
- Explanations of concepts
|
|
76
|
+
- Day-to-day problem solving
|
|
77
|
+
|
|
78
|
+
Be friendly, clear, and helpful. Ask clarifying questions if needed.`,
|
|
79
|
+
apiKey,
|
|
80
|
+
maxTokens: 1024,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// ============================================================================
|
|
84
|
+
// Router Agent
|
|
85
|
+
// ============================================================================
|
|
86
|
+
|
|
87
|
+
const routerAgent = new ClaudeAgent({
|
|
88
|
+
id: "router",
|
|
89
|
+
name: "Query Router",
|
|
90
|
+
description: `You are a routing agent that classifies user queries.
|
|
91
|
+
Analyze the user's question and determine which expert should handle it.
|
|
92
|
+
Consider the main topic, required expertise, and user intent.
|
|
93
|
+
Output ONLY the route name, nothing else.`,
|
|
94
|
+
apiKey,
|
|
95
|
+
maxTokens: 50,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// ============================================================================
|
|
99
|
+
// Router Setup
|
|
100
|
+
// ============================================================================
|
|
101
|
+
|
|
102
|
+
const supportRouter = AgentGraph.router(
|
|
103
|
+
routerAgent,
|
|
104
|
+
[
|
|
105
|
+
{
|
|
106
|
+
name: "technical",
|
|
107
|
+
description:
|
|
108
|
+
"Programming, software, debugging, code, APIs, databases, DevOps, technical concepts",
|
|
109
|
+
handler: technicalAgent,
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: "creative",
|
|
113
|
+
description:
|
|
114
|
+
"Writing, storytelling, poetry, content creation, brainstorming, marketing copy",
|
|
115
|
+
handler: creativeAgent,
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: "analytics",
|
|
119
|
+
description:
|
|
120
|
+
"Data analysis, statistics, metrics, research, charts, business intelligence",
|
|
121
|
+
handler: analyticsAgent,
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
name: "general",
|
|
125
|
+
description:
|
|
126
|
+
"General questions, everyday advice, recommendations, explanations",
|
|
127
|
+
handler: generalAgent,
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
{
|
|
131
|
+
fallbackRoute: "general",
|
|
132
|
+
includeRouterContext: false, // Pass raw input to handlers
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
// ============================================================================
|
|
137
|
+
// Interactive Session
|
|
138
|
+
// ============================================================================
|
|
139
|
+
|
|
140
|
+
async function runInteractiveSession() {
|
|
141
|
+
const rl = createInterface({
|
|
142
|
+
input: process.stdin,
|
|
143
|
+
output: process.stdout,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
console.log("\n=== Intelligent Router Example ===\n");
|
|
147
|
+
console.log("This demo routes your questions to specialized experts:");
|
|
148
|
+
console.log(" - Technical: code, software, programming");
|
|
149
|
+
console.log(" - Creative: writing, stories, content");
|
|
150
|
+
console.log(" - Analytics: data, statistics, metrics");
|
|
151
|
+
console.log(" - General: everything else");
|
|
152
|
+
console.log('\nType "exit" to quit.\n');
|
|
153
|
+
console.log("─".repeat(50));
|
|
154
|
+
|
|
155
|
+
while (true) {
|
|
156
|
+
const input = await rl.question("\nYou: ");
|
|
157
|
+
|
|
158
|
+
if (input.toLowerCase() === "exit") {
|
|
159
|
+
console.log("\nGoodbye!\n");
|
|
160
|
+
console.log(supportRouter.getMetrics());
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (!input.trim()) {
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
try {
|
|
169
|
+
console.log("\nRouting query...");
|
|
170
|
+
const response = await supportRouter.execute(input);
|
|
171
|
+
console.log("\n" + "─".repeat(50));
|
|
172
|
+
console.log(response);
|
|
173
|
+
console.log("─".repeat(50));
|
|
174
|
+
} catch (error) {
|
|
175
|
+
console.error("\nError:", error instanceof Error ? error.message : error);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
rl.close();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// ============================================================================
|
|
183
|
+
// Demo with Pre-defined Queries
|
|
184
|
+
// ============================================================================
|
|
185
|
+
|
|
186
|
+
async function runDemoQueries() {
|
|
187
|
+
console.log("\n=== Router Demo with Sample Queries ===\n");
|
|
188
|
+
|
|
189
|
+
const queries = [
|
|
190
|
+
"How do I fix a memory leak in my Node.js application?",
|
|
191
|
+
"Write me a haiku about programming",
|
|
192
|
+
"What metrics should I track for my e-commerce site?",
|
|
193
|
+
"What's a good recipe for chocolate chip cookies?",
|
|
194
|
+
];
|
|
195
|
+
|
|
196
|
+
for (const query of queries) {
|
|
197
|
+
console.log("─".repeat(50));
|
|
198
|
+
console.log(`\nQuery: "${query}"\n`);
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
const response = await supportRouter.execute(query);
|
|
202
|
+
console.log("Response:\n");
|
|
203
|
+
console.log(response);
|
|
204
|
+
} catch (error) {
|
|
205
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
console.log();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// ============================================================================
|
|
213
|
+
// Main
|
|
214
|
+
// ============================================================================
|
|
215
|
+
|
|
216
|
+
async function main() {
|
|
217
|
+
const args = process.argv.slice(2);
|
|
218
|
+
|
|
219
|
+
if (args.includes("--demo")) {
|
|
220
|
+
await runDemoQueries();
|
|
221
|
+
} else {
|
|
222
|
+
await runInteractiveSession();
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
main().catch(console.error);
|