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,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data Pipeline Example
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates the factory pattern for creating data-fetching pipelines.
|
|
5
|
+
*
|
|
6
|
+
* Key concepts:
|
|
7
|
+
* - Factories capture context (user, config) at creation time
|
|
8
|
+
* - Pipeline data flow stays simple (string -> string)
|
|
9
|
+
* - Security/permissions are handled at the factory level
|
|
10
|
+
* - Easy to compose different fetchers for different use cases
|
|
11
|
+
*
|
|
12
|
+
* Run with: npx ts-node examples/graph/data-pipeline/index.ts
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import "dotenv/config";
|
|
16
|
+
import {
|
|
17
|
+
AgentGraph,
|
|
18
|
+
GraphNode,
|
|
19
|
+
createMetricsCollector,
|
|
20
|
+
} from "../../../lib/graph/AgentGraph";
|
|
21
|
+
import {
|
|
22
|
+
createDatabaseFetcher,
|
|
23
|
+
createWebFetcher,
|
|
24
|
+
createVectorDbFetcher,
|
|
25
|
+
UserContext,
|
|
26
|
+
} from "./fetchers";
|
|
27
|
+
import { createPipelineAgents } from "./agents";
|
|
28
|
+
|
|
29
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
30
|
+
|
|
31
|
+
if (!apiKey) {
|
|
32
|
+
console.error("Please set ANTHROPIC_API_KEY environment variable");
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ============================================================================
|
|
37
|
+
// Helper: Combine Multiple Data Sources
|
|
38
|
+
// ============================================================================
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Creates a node that combines results from multiple fetchers.
|
|
42
|
+
* Each fetcher runs in parallel, results are concatenated.
|
|
43
|
+
*/
|
|
44
|
+
function createDataCombiner(
|
|
45
|
+
...fetchers: GraphNode<string, string>[]
|
|
46
|
+
): GraphNode<string, string> {
|
|
47
|
+
return {
|
|
48
|
+
name: "DataCombiner",
|
|
49
|
+
nodeType: "custom",
|
|
50
|
+
execute: async (topic: string) => {
|
|
51
|
+
console.log(`\n [COMBINE] Fetching from ${fetchers.length} sources in parallel...`);
|
|
52
|
+
|
|
53
|
+
// Run all fetchers in parallel
|
|
54
|
+
const results = await Promise.all(
|
|
55
|
+
fetchers.map((f) => f.execute(topic))
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
// Combine results with clear separation
|
|
59
|
+
return results.join("\n\n");
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ============================================================================
|
|
65
|
+
// Example 1: Basic Data Pipeline with Permissions
|
|
66
|
+
// ============================================================================
|
|
67
|
+
|
|
68
|
+
async function runBasicPipeline() {
|
|
69
|
+
console.log("╔══════════════════════════════════════════════════════════════╗");
|
|
70
|
+
console.log("║ Example 1: Basic Data Pipeline with Permissions ║");
|
|
71
|
+
console.log("╚══════════════════════════════════════════════════════════════╝\n");
|
|
72
|
+
|
|
73
|
+
// Simulate a user with limited permissions
|
|
74
|
+
const regularUser: UserContext = {
|
|
75
|
+
userId: "user-123",
|
|
76
|
+
tenantId: "acme-corp",
|
|
77
|
+
permissions: ["read:tech", "read:research"],
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// Create fetchers with user context baked in
|
|
81
|
+
const dbFetcher = createDatabaseFetcher(regularUser);
|
|
82
|
+
const webFetcher = createWebFetcher();
|
|
83
|
+
|
|
84
|
+
// Create agents
|
|
85
|
+
const { summarizerAgent } = createPipelineAgents(apiKey);
|
|
86
|
+
|
|
87
|
+
// Build pipeline: Combine sources -> Summarize
|
|
88
|
+
const pipeline = AgentGraph.pipeline<string, string>(
|
|
89
|
+
createDataCombiner(dbFetcher, webFetcher),
|
|
90
|
+
AgentGraph.sequential({ wrapInput: false }, summarizerAgent)
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
console.log("User:", regularUser.userId);
|
|
94
|
+
console.log("Permissions:", regularUser.permissions.join(", "));
|
|
95
|
+
console.log("\n--- Running pipeline for 'quantum computing' ---\n");
|
|
96
|
+
|
|
97
|
+
const result = await pipeline.execute("quantum computing");
|
|
98
|
+
|
|
99
|
+
console.log("\n=== Result ===\n");
|
|
100
|
+
console.log(result);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ============================================================================
|
|
104
|
+
// Example 2: Access Denied Scenario
|
|
105
|
+
// ============================================================================
|
|
106
|
+
|
|
107
|
+
async function runAccessDeniedExample() {
|
|
108
|
+
console.log("\n╔══════════════════════════════════════════════════════════════╗");
|
|
109
|
+
console.log("║ Example 2: Access Denied Scenario ║");
|
|
110
|
+
console.log("╚══════════════════════════════════════════════════════════════╝\n");
|
|
111
|
+
|
|
112
|
+
// User without finance permissions
|
|
113
|
+
const limitedUser: UserContext = {
|
|
114
|
+
userId: "intern-456",
|
|
115
|
+
tenantId: "acme-corp",
|
|
116
|
+
permissions: ["read:research"], // No finance access
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const dbFetcher = createDatabaseFetcher(limitedUser);
|
|
120
|
+
const { summarizerAgent } = createPipelineAgents(apiKey);
|
|
121
|
+
|
|
122
|
+
const pipeline = AgentGraph.pipeline<string, string>(
|
|
123
|
+
dbFetcher,
|
|
124
|
+
AgentGraph.sequential({ wrapInput: false }, summarizerAgent)
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
console.log("User:", limitedUser.userId);
|
|
128
|
+
console.log("Permissions:", limitedUser.permissions.join(", "));
|
|
129
|
+
console.log("\n--- Attempting to access 'financials' ---\n");
|
|
130
|
+
|
|
131
|
+
const result = await pipeline.execute("financials");
|
|
132
|
+
|
|
133
|
+
console.log("\n=== Result ===\n");
|
|
134
|
+
console.log(result);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ============================================================================
|
|
138
|
+
// Example 3: Multi-Source Research Pipeline
|
|
139
|
+
// ============================================================================
|
|
140
|
+
|
|
141
|
+
async function runMultiSourcePipeline() {
|
|
142
|
+
console.log("\n╔══════════════════════════════════════════════════════════════╗");
|
|
143
|
+
console.log("║ Example 3: Multi-Source Research Pipeline ║");
|
|
144
|
+
console.log("╚══════════════════════════════════════════════════════════════╝\n");
|
|
145
|
+
|
|
146
|
+
// Admin user with full access
|
|
147
|
+
const adminUser: UserContext = {
|
|
148
|
+
userId: "admin-001",
|
|
149
|
+
tenantId: "acme-corp",
|
|
150
|
+
permissions: ["read:tech", "read:research", "read:medical", "read:finance"],
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// Create multiple fetchers
|
|
154
|
+
const dbFetcher = createDatabaseFetcher(adminUser);
|
|
155
|
+
const webFetcher = createWebFetcher();
|
|
156
|
+
const vectorFetcher = createVectorDbFetcher(adminUser, {
|
|
157
|
+
collection: "research-papers",
|
|
158
|
+
topK: 3
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// Create agents
|
|
162
|
+
const { analyzerAgent, summarizerAgent } = createPipelineAgents(apiKey);
|
|
163
|
+
|
|
164
|
+
// Create metrics collector
|
|
165
|
+
const metrics = createMetricsCollector();
|
|
166
|
+
|
|
167
|
+
// Build comprehensive research pipeline
|
|
168
|
+
const researchPipeline = AgentGraph.pipeline<string, string>(
|
|
169
|
+
// Stage 1: Fetch from all sources in parallel
|
|
170
|
+
createDataCombiner(dbFetcher, webFetcher, vectorFetcher),
|
|
171
|
+
|
|
172
|
+
// Stage 2: Deep analysis
|
|
173
|
+
AgentGraph.sequential({ wrapInput: false }, analyzerAgent),
|
|
174
|
+
|
|
175
|
+
// Stage 3: Executive summary
|
|
176
|
+
AgentGraph.sequential({ wrapInput: false }, summarizerAgent)
|
|
177
|
+
).withMetrics(metrics);
|
|
178
|
+
|
|
179
|
+
console.log("User:", adminUser.userId);
|
|
180
|
+
console.log("Data sources: Database, Web, VectorDB");
|
|
181
|
+
console.log("\n--- Running comprehensive research on 'penicillin' ---\n");
|
|
182
|
+
|
|
183
|
+
const result = await researchPipeline.execute("penicillin");
|
|
184
|
+
|
|
185
|
+
console.log("\n=== Executive Summary ===\n");
|
|
186
|
+
console.log(result);
|
|
187
|
+
|
|
188
|
+
// Show metrics
|
|
189
|
+
console.log("\n=== Pipeline Metrics ===\n");
|
|
190
|
+
console.log(metrics.toTextVisualization());
|
|
191
|
+
|
|
192
|
+
const aggregate = metrics.getAggregateMetrics();
|
|
193
|
+
console.log(`\nTotal duration: ${aggregate.totalDurationMs}ms`);
|
|
194
|
+
console.log(`Total tokens: ${aggregate.totalTokens.totalTokens}`);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// ============================================================================
|
|
198
|
+
// Example 4: Dynamic Pipeline Based on User Role
|
|
199
|
+
// ============================================================================
|
|
200
|
+
|
|
201
|
+
async function runRoleBasedPipeline() {
|
|
202
|
+
console.log("\n╔══════════════════════════════════════════════════════════════╗");
|
|
203
|
+
console.log("║ Example 4: Dynamic Pipeline Based on User Role ║");
|
|
204
|
+
console.log("╚══════════════════════════════════════════════════════════════╝\n");
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Factory that creates different pipelines based on user role.
|
|
208
|
+
* Demonstrates how to compose pipelines dynamically.
|
|
209
|
+
*/
|
|
210
|
+
function createPipelineForUser(
|
|
211
|
+
user: UserContext & { role: "basic" | "researcher" | "admin" }
|
|
212
|
+
): GraphNode<string, string> {
|
|
213
|
+
const { summarizerAgent, analyzerAgent } = createPipelineAgents(apiKey);
|
|
214
|
+
|
|
215
|
+
switch (user.role) {
|
|
216
|
+
case "basic":
|
|
217
|
+
// Basic users only get web data
|
|
218
|
+
console.log(`Creating basic pipeline for ${user.userId}`);
|
|
219
|
+
return AgentGraph.pipeline(
|
|
220
|
+
createWebFetcher(),
|
|
221
|
+
AgentGraph.sequential({ wrapInput: false }, summarizerAgent)
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
case "researcher":
|
|
225
|
+
// Researchers get DB + web
|
|
226
|
+
console.log(`Creating researcher pipeline for ${user.userId}`);
|
|
227
|
+
return AgentGraph.pipeline(
|
|
228
|
+
createDataCombiner(
|
|
229
|
+
createDatabaseFetcher(user),
|
|
230
|
+
createWebFetcher()
|
|
231
|
+
),
|
|
232
|
+
AgentGraph.sequential({ wrapInput: false }, analyzerAgent),
|
|
233
|
+
AgentGraph.sequential({ wrapInput: false }, summarizerAgent)
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
case "admin":
|
|
237
|
+
// Admins get everything
|
|
238
|
+
console.log(`Creating admin pipeline for ${user.userId}`);
|
|
239
|
+
return AgentGraph.pipeline(
|
|
240
|
+
createDataCombiner(
|
|
241
|
+
createDatabaseFetcher(user),
|
|
242
|
+
createWebFetcher(),
|
|
243
|
+
createVectorDbFetcher(user)
|
|
244
|
+
),
|
|
245
|
+
AgentGraph.sequential({ wrapInput: false }, analyzerAgent),
|
|
246
|
+
AgentGraph.sequential({ wrapInput: false }, summarizerAgent)
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Test with different roles
|
|
252
|
+
const basicUser = {
|
|
253
|
+
userId: "basic-user",
|
|
254
|
+
tenantId: "acme-corp",
|
|
255
|
+
permissions: [],
|
|
256
|
+
role: "basic" as const,
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
const pipeline = createPipelineForUser(basicUser);
|
|
260
|
+
|
|
261
|
+
console.log("\n--- Running with basic user role ---\n");
|
|
262
|
+
|
|
263
|
+
const result = await pipeline.execute("climate change");
|
|
264
|
+
|
|
265
|
+
console.log("\n=== Result ===\n");
|
|
266
|
+
console.log(result);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ============================================================================
|
|
270
|
+
// Main
|
|
271
|
+
// ============================================================================
|
|
272
|
+
|
|
273
|
+
async function main() {
|
|
274
|
+
await runBasicPipeline();
|
|
275
|
+
await runAccessDeniedExample();
|
|
276
|
+
await runMultiSourcePipeline();
|
|
277
|
+
await runRoleBasedPipeline();
|
|
278
|
+
|
|
279
|
+
console.log("\n✓ All examples completed");
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
main().catch(console.error);
|
package/graph/index.ts
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph Examples Index
|
|
3
|
+
*
|
|
4
|
+
* Run individual examples:
|
|
5
|
+
* npx ts-node examples/graph/sequential-example.ts
|
|
6
|
+
* npx ts-node examples/graph/parallel-example.ts
|
|
7
|
+
* npx ts-node examples/graph/voting-example.ts
|
|
8
|
+
* npx ts-node examples/graph/pipeline-example.ts
|
|
9
|
+
* npx ts-node examples/graph/map-example.ts
|
|
10
|
+
* npx ts-node examples/graph/router-example.ts
|
|
11
|
+
*
|
|
12
|
+
* Or run this file for a quick demo:
|
|
13
|
+
* npx ts-node examples/graph/index.ts
|
|
14
|
+
*/
|
|
15
|
+
import "dotenv/config";
|
|
16
|
+
import { ClaudeAgent } from "../../lib/agents/anthropic/ClaudeAgent";
|
|
17
|
+
import { AgentGraph, VotingInput, GraphNode } from "../../lib/graph/AgentGraph";
|
|
18
|
+
|
|
19
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
20
|
+
|
|
21
|
+
if (!apiKey) {
|
|
22
|
+
console.error("Please set ANTHROPIC_API_KEY environment variable");
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Quick demo showcasing all graph executor types
|
|
28
|
+
*/
|
|
29
|
+
async function quickDemo() {
|
|
30
|
+
console.log("╔══════════════════════════════════════════╗");
|
|
31
|
+
console.log("║ Agention Graph System Quick Demo ║");
|
|
32
|
+
console.log("╚══════════════════════════════════════════╝\n");
|
|
33
|
+
|
|
34
|
+
// Create some simple agents for demonstration
|
|
35
|
+
const uppercaseAgent = new ClaudeAgent({
|
|
36
|
+
id: "uppercase",
|
|
37
|
+
name: "Uppercase Agent",
|
|
38
|
+
description:
|
|
39
|
+
"Convert the input to uppercase. Output only the uppercase text.",
|
|
40
|
+
apiKey,
|
|
41
|
+
maxTokens: 100,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const excitedAgent = new ClaudeAgent({
|
|
45
|
+
id: "excited",
|
|
46
|
+
name: "Excited Agent",
|
|
47
|
+
description:
|
|
48
|
+
"Add excitement to the text by adding exclamation marks and enthusiastic words. Keep it short.",
|
|
49
|
+
apiKey,
|
|
50
|
+
maxTokens: 100,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const calmAgent = new ClaudeAgent({
|
|
54
|
+
id: "calm",
|
|
55
|
+
name: "Calm Agent",
|
|
56
|
+
description:
|
|
57
|
+
"Make the text calmer and more relaxed. Use peaceful language. Keep it short.",
|
|
58
|
+
apiKey,
|
|
59
|
+
maxTokens: 100,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const judgeAgent = new ClaudeAgent({
|
|
63
|
+
id: "judge",
|
|
64
|
+
name: "Judge Agent",
|
|
65
|
+
description:
|
|
66
|
+
"You receive two versions of text. Pick the better one. Output only 'Version 1' or 'Version 2'.",
|
|
67
|
+
apiKey,
|
|
68
|
+
maxTokens: 20,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// 1. Sequential Example
|
|
72
|
+
console.log("1. SEQUENTIAL EXECUTOR");
|
|
73
|
+
console.log(" Chain: Input -> Uppercase -> Excited\n");
|
|
74
|
+
|
|
75
|
+
const sequential = AgentGraph.sequential(
|
|
76
|
+
{ wrapInput: false },
|
|
77
|
+
uppercaseAgent,
|
|
78
|
+
excitedAgent
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const seqResult = await sequential.execute("hello world");
|
|
82
|
+
console.log(` Input: "hello world"`);
|
|
83
|
+
console.log(` Output: "${seqResult}"\n`);
|
|
84
|
+
|
|
85
|
+
// 2. Parallel Example
|
|
86
|
+
console.log("2. PARALLEL EXECUTOR");
|
|
87
|
+
console.log(" Running Excited and Calm agents in parallel\n");
|
|
88
|
+
|
|
89
|
+
const parallel = AgentGraph.parallel(
|
|
90
|
+
{ wrapInput: false },
|
|
91
|
+
excitedAgent,
|
|
92
|
+
calmAgent
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
const parResults = await parallel.execute("The sun is shining");
|
|
96
|
+
console.log(` Input: "The sun is shining"`);
|
|
97
|
+
console.log(` Excited: "${parResults[0]}"`);
|
|
98
|
+
console.log(` Calm: "${parResults[1]}"\n`);
|
|
99
|
+
|
|
100
|
+
// 3. Voting Example
|
|
101
|
+
console.log("3. VOTING SYSTEM");
|
|
102
|
+
console.log(" Judge picks between excited and calm versions\n");
|
|
103
|
+
|
|
104
|
+
const voting = AgentGraph.votingSystem(judgeAgent);
|
|
105
|
+
const votingInput: VotingInput = {
|
|
106
|
+
originalInput: "Pick the better version",
|
|
107
|
+
solutions: parResults,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const verdict = await voting.execute(votingInput);
|
|
111
|
+
console.log(` Verdict: ${verdict}\n`);
|
|
112
|
+
|
|
113
|
+
// 4. Map Example
|
|
114
|
+
console.log("4. MAP EXECUTOR");
|
|
115
|
+
console.log(" Processing array of items in parallel\n");
|
|
116
|
+
|
|
117
|
+
const mapper = AgentGraph.map(
|
|
118
|
+
AgentGraph.sequential({ wrapInput: false }, uppercaseAgent)
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
const mapResults = await mapper.execute(["one", "two", "three"]);
|
|
122
|
+
console.log(` Input: ["one", "two", "three"]`);
|
|
123
|
+
console.log(` Output: ${JSON.stringify(mapResults)}\n`);
|
|
124
|
+
|
|
125
|
+
// 5. Pipeline Example
|
|
126
|
+
console.log("5. PIPELINE");
|
|
127
|
+
console.log(" Complex workflow combining multiple executor types\n");
|
|
128
|
+
|
|
129
|
+
const pipeline = AgentGraph.pipeline<string, string>(
|
|
130
|
+
// Stage 1: Get two versions in parallel
|
|
131
|
+
AgentGraph.parallel({ wrapInput: false }, excitedAgent, calmAgent),
|
|
132
|
+
|
|
133
|
+
// Stage 2: Transform for voting
|
|
134
|
+
{
|
|
135
|
+
execute: async (results: string[]) => ({
|
|
136
|
+
originalInput: "Which version is better?",
|
|
137
|
+
solutions: results,
|
|
138
|
+
}),
|
|
139
|
+
} as GraphNode<string[], VotingInput>,
|
|
140
|
+
|
|
141
|
+
// Stage 3: Vote
|
|
142
|
+
voting
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
const pipelineResult = await pipeline.execute("Good morning");
|
|
146
|
+
console.log(` Input: "Good morning"`);
|
|
147
|
+
console.log(` Output: "${pipelineResult}"`);
|
|
148
|
+
|
|
149
|
+
console.log("\n╔══════════════════════════════════════════╗");
|
|
150
|
+
console.log("║ Demo Complete! ║");
|
|
151
|
+
console.log("╚══════════════════════════════════════════╝");
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
quickDemo().catch(console.error);
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map Executor Example
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates processing arrays of items in parallel using a processor agent.
|
|
5
|
+
*
|
|
6
|
+
* Use case: Batch processing documents, summarizing multiple articles, etc.
|
|
7
|
+
*/
|
|
8
|
+
import "dotenv/config";
|
|
9
|
+
import { ClaudeAgent } from "../../lib/agents/anthropic/ClaudeAgent";
|
|
10
|
+
import { AgentGraph, GraphNode } from "../../lib/graph/AgentGraph";
|
|
11
|
+
|
|
12
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
13
|
+
|
|
14
|
+
if (!apiKey) {
|
|
15
|
+
console.error("Please set ANTHROPIC_API_KEY environment variable");
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Summarization agent for processing individual documents
|
|
20
|
+
const summarizerAgent = new ClaudeAgent({
|
|
21
|
+
id: "summarizer",
|
|
22
|
+
name: "Summarizer",
|
|
23
|
+
description: `You are a summarization agent. Given a text, provide a one-sentence summary.
|
|
24
|
+
Be concise and capture the main point. Output only the summary sentence.`,
|
|
25
|
+
apiKey,
|
|
26
|
+
maxTokens: 100,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Sentiment analysis agent
|
|
30
|
+
const sentimentAgent = new ClaudeAgent({
|
|
31
|
+
id: "sentiment",
|
|
32
|
+
name: "Sentiment Analyzer",
|
|
33
|
+
description: `Analyze the sentiment of the given text.
|
|
34
|
+
Output exactly one word: POSITIVE, NEGATIVE, or NEUTRAL`,
|
|
35
|
+
apiKey,
|
|
36
|
+
maxTokens: 10,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Translation agent
|
|
40
|
+
const translatorAgent = new ClaudeAgent({
|
|
41
|
+
id: "translator",
|
|
42
|
+
name: "Translator",
|
|
43
|
+
description: `Translate the given text to Spanish. Output only the translation.`,
|
|
44
|
+
apiKey,
|
|
45
|
+
maxTokens: 200,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
async function runBatchSummarization() {
|
|
49
|
+
console.log("=== Batch Summarization Example ===\n");
|
|
50
|
+
|
|
51
|
+
const documents = [
|
|
52
|
+
"Artificial intelligence is transforming healthcare by enabling faster diagnosis and personalized treatment plans. Machine learning algorithms can now detect diseases from medical images with accuracy matching or exceeding human experts.",
|
|
53
|
+
"Climate change is causing unprecedented shifts in global weather patterns. Rising temperatures are leading to more frequent extreme weather events, including hurricanes, droughts, and wildfires.",
|
|
54
|
+
"The global economy is increasingly driven by digital services and remote work. Companies are adapting to hybrid work models, reshaping urban centers and suburban communities alike.",
|
|
55
|
+
"Space exploration has entered a new era with private companies launching missions alongside government agencies. Reusable rockets have dramatically reduced the cost of reaching orbit.",
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
console.log(`Processing ${documents.length} documents in parallel...\n`);
|
|
59
|
+
|
|
60
|
+
// Create map executor with the summarizer
|
|
61
|
+
const batchSummarizer = AgentGraph.map(
|
|
62
|
+
AgentGraph.sequential({ wrapInput: false }, summarizerAgent)
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const startTime = Date.now();
|
|
66
|
+
const summaries = await batchSummarizer.execute(documents);
|
|
67
|
+
const elapsed = Date.now() - startTime;
|
|
68
|
+
|
|
69
|
+
console.log("Summaries:");
|
|
70
|
+
summaries.forEach((summary, index) => {
|
|
71
|
+
console.log(`${index + 1}. ${summary}`);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
console.log(`\nProcessed ${documents.length} documents in ${elapsed}ms`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function runBatchSentimentAnalysis() {
|
|
78
|
+
console.log("\n=== Batch Sentiment Analysis Example ===\n");
|
|
79
|
+
|
|
80
|
+
const reviews = [
|
|
81
|
+
"This product exceeded all my expectations! Best purchase ever.",
|
|
82
|
+
"Terrible quality. Broke after one day. Complete waste of money.",
|
|
83
|
+
"It's okay. Does what it's supposed to do, nothing special.",
|
|
84
|
+
"Absolutely love it! Would recommend to everyone.",
|
|
85
|
+
"Not great, not terrible. Average product for average price.",
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
console.log("Analyzing sentiment of customer reviews...\n");
|
|
89
|
+
|
|
90
|
+
const sentimentAnalyzer = AgentGraph.map(
|
|
91
|
+
AgentGraph.sequential({ wrapInput: false }, sentimentAgent)
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const sentiments = await sentimentAnalyzer.execute(reviews);
|
|
95
|
+
|
|
96
|
+
console.log("Results:");
|
|
97
|
+
reviews.forEach((review, index) => {
|
|
98
|
+
console.log(`"${review.substring(0, 50)}..." -> ${sentiments[index]}`);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Count sentiments
|
|
102
|
+
const counts = sentiments.reduce(
|
|
103
|
+
(acc, s) => {
|
|
104
|
+
const key = s.trim().toUpperCase();
|
|
105
|
+
acc[key] = (acc[key] || 0) + 1;
|
|
106
|
+
return acc;
|
|
107
|
+
},
|
|
108
|
+
{} as Record<string, number>
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
console.log("\nSummary:", counts);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async function runBatchTranslation() {
|
|
115
|
+
console.log("\n=== Batch Translation Example ===\n");
|
|
116
|
+
|
|
117
|
+
const phrases = [
|
|
118
|
+
"Hello, how are you?",
|
|
119
|
+
"The weather is beautiful today.",
|
|
120
|
+
"I love programming.",
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
console.log("Translating phrases to Spanish...\n");
|
|
124
|
+
|
|
125
|
+
const translator = AgentGraph.map(
|
|
126
|
+
AgentGraph.sequential({ wrapInput: false }, translatorAgent)
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
const translations = await translator.execute(phrases);
|
|
130
|
+
|
|
131
|
+
console.log("Translations:");
|
|
132
|
+
phrases.forEach((phrase, index) => {
|
|
133
|
+
console.log(`EN: "${phrase}"`);
|
|
134
|
+
console.log(`ES: "${translations[index]}"`);
|
|
135
|
+
console.log();
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Custom processor example (non-agent)
|
|
140
|
+
async function runCustomProcessor() {
|
|
141
|
+
console.log("=== Custom Processor Example ===\n");
|
|
142
|
+
|
|
143
|
+
// Custom processor that doesn't use an agent
|
|
144
|
+
const wordCounter: GraphNode<string, { text: string; wordCount: number }> = {
|
|
145
|
+
execute: async (text: string) => ({
|
|
146
|
+
text: text.substring(0, 30) + "...",
|
|
147
|
+
wordCount: text.split(/\s+/).length,
|
|
148
|
+
}),
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const mapper = AgentGraph.map(wordCounter);
|
|
152
|
+
|
|
153
|
+
const texts = [
|
|
154
|
+
"This is a short sentence.",
|
|
155
|
+
"This is a much longer sentence with many more words in it.",
|
|
156
|
+
"One two three four five six seven eight nine ten eleven twelve.",
|
|
157
|
+
];
|
|
158
|
+
|
|
159
|
+
const results = await mapper.execute(texts);
|
|
160
|
+
|
|
161
|
+
console.log("Word counts:");
|
|
162
|
+
results.forEach((result) => {
|
|
163
|
+
console.log(`"${result.text}" -> ${result.wordCount} words`);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Pipeline with map example
|
|
168
|
+
async function runPipelineWithMap() {
|
|
169
|
+
console.log("\n=== Pipeline with Map Example ===\n");
|
|
170
|
+
|
|
171
|
+
const qualityChecker = new ClaudeAgent({
|
|
172
|
+
id: "quality",
|
|
173
|
+
name: "Quality Checker",
|
|
174
|
+
description: `Given multiple summaries, identify which one is the best quality.
|
|
175
|
+
Output only the number (1, 2, 3, etc.) of the best summary.`,
|
|
176
|
+
apiKey,
|
|
177
|
+
maxTokens: 10,
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Pipeline: Split -> Summarize Each -> Select Best
|
|
181
|
+
const pipeline = AgentGraph.pipeline(
|
|
182
|
+
// Split input into paragraphs
|
|
183
|
+
{
|
|
184
|
+
execute: async (text: string) => text.split("\n\n").filter((p) => p.trim()),
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
// Summarize each paragraph
|
|
188
|
+
AgentGraph.map(AgentGraph.sequential({ wrapInput: false }, summarizerAgent)),
|
|
189
|
+
|
|
190
|
+
// Combine summaries and select best
|
|
191
|
+
{
|
|
192
|
+
execute: async (summaries: string[]) => {
|
|
193
|
+
const numbered = summaries
|
|
194
|
+
.map((s, i) => `${i + 1}. ${s}`)
|
|
195
|
+
.join("\n");
|
|
196
|
+
return `Select the best summary:\n${numbered}`;
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
// Pick the best one
|
|
201
|
+
AgentGraph.sequential({ wrapInput: false }, qualityChecker)
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
const document = `
|
|
205
|
+
The ocean covers over 70% of Earth's surface. It regulates climate, produces oxygen, and supports countless species. Marine ecosystems are vital for human survival.
|
|
206
|
+
|
|
207
|
+
Technology has revolutionized communication. Smartphones connect billions of people worldwide. Social media platforms have transformed how we share information and interact.
|
|
208
|
+
|
|
209
|
+
Education is the foundation of progress. Schools prepare young minds for the future. Lifelong learning enables adaptation in a rapidly changing world.
|
|
210
|
+
`.trim();
|
|
211
|
+
|
|
212
|
+
console.log("Document has 3 paragraphs. Finding best summary...\n");
|
|
213
|
+
|
|
214
|
+
const result = await pipeline.execute(document);
|
|
215
|
+
console.log("Best summary number:", result);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Run all examples
|
|
219
|
+
async function main() {
|
|
220
|
+
await runBatchSummarization();
|
|
221
|
+
await runBatchSentimentAnalysis();
|
|
222
|
+
await runBatchTranslation();
|
|
223
|
+
await runCustomProcessor();
|
|
224
|
+
await runPipelineWithMap();
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
main().catch(console.error);
|