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.
Files changed (44) hide show
  1. package/chunking-demo.ts +339 -0
  2. package/cleanup-duplicates.ts +142 -0
  3. package/data/flower.jpg +0 -0
  4. package/generative.ts +128 -0
  5. package/graph/context-example.ts +209 -0
  6. package/graph/data-pipeline/agents.ts +60 -0
  7. package/graph/data-pipeline/fetchers.ts +166 -0
  8. package/graph/data-pipeline/index.ts +282 -0
  9. package/graph/index.ts +154 -0
  10. package/graph/map-example.ts +227 -0
  11. package/graph/metrics-example.ts +238 -0
  12. package/graph/parallel-example.ts +167 -0
  13. package/graph/pipeline-example.ts +225 -0
  14. package/graph/planning-example.ts +406 -0
  15. package/graph/router-example.ts +226 -0
  16. package/graph/sequential-example.ts +141 -0
  17. package/graph/voting-example.ts +159 -0
  18. package/graph-rag/docker-compose.yaml +14 -0
  19. package/graph-rag/index.js +99 -0
  20. package/graph-rag/init-db.sh +7 -0
  21. package/graph-rag/package.json +15 -0
  22. package/history-compression-example.ts +163 -0
  23. package/history-persistence.ts +347 -0
  24. package/index.ts +175 -0
  25. package/ingestion-pipeline.ts +353 -0
  26. package/mcp-airbnb-example.ts +69 -0
  27. package/mcp-http-example.ts +70 -0
  28. package/mcp-stdio-example.ts +63 -0
  29. package/multimodal.ts +144 -0
  30. package/ollama.ts +148 -0
  31. package/openai-compatible.ts +141 -0
  32. package/opensearch-vector-store.ts +342 -0
  33. package/package.json +24 -0
  34. package/pubmed.ts +289 -0
  35. package/reasoning-with-sub-agent.ts +311 -0
  36. package/synchronous/index.ts +48 -0
  37. package/tsconfig.json +8 -0
  38. package/vector-store-filtering.ts +303 -0
  39. package/vector-store.ts +210 -0
  40. package/vectorstore/index.ts +0 -0
  41. package/vectorstore/store/dbService.ts +80 -0
  42. package/voyage-embeddings.ts +99 -0
  43. package/weather-with-sub-agent.ts +276 -0
  44. 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);