groundswell 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/.claude/settings.local.json +9 -0
- package/.claude/system_prompts/task-breakdown.md +100 -0
- package/PRPs/001-hierarchical-workflow-engine.md +2438 -0
- package/PRPs/PRDs/001-hierarchical-workflow-engine.md +543 -0
- package/PRPs/PRDs/002-agent-prompt.md +390 -0
- package/PRPs/PRDs/003-agent-prompt.md +943 -0
- package/PRPs/PRDs/004-agent-prompt.md +1136 -0
- package/PRPs/PRDs/tasks-001.json +492 -0
- package/PRPs/README.md +83 -0
- package/PRPs/templates/prp_base.md +222 -0
- package/README.md +218 -0
- package/docs/agent.md +422 -0
- package/docs/prompt.md +419 -0
- package/docs/workflow.md +600 -0
- package/examples/README.md +244 -0
- package/examples/examples/01-basic-workflow.ts +100 -0
- package/examples/examples/02-decorator-options.ts +217 -0
- package/examples/examples/03-parent-child.ts +241 -0
- package/examples/examples/04-observers-debugger.ts +340 -0
- package/examples/examples/05-error-handling.ts +387 -0
- package/examples/examples/06-concurrent-tasks.ts +352 -0
- package/examples/examples/07-agent-loops.ts +432 -0
- package/examples/examples/08-sdk-features.ts +667 -0
- package/examples/examples/09-reflection.ts +573 -0
- package/examples/examples/10-introspection.ts +550 -0
- package/examples/index.ts +143 -0
- package/examples/utils/helpers.ts +57 -0
- package/llms_full.txt +5890 -0
- package/package.json +63 -0
- package/plan/P1P2/PRP.md +527 -0
- package/plan/P1P2/research/LRU_CACHE_BEST_PRACTICES.md +1929 -0
- package/plan/P1P2/research/LRU_CACHE_CODE_PATTERNS.md +857 -0
- package/plan/P1P2/research/LRU_CACHE_INTEGRATION_GUIDE.md +738 -0
- package/plan/P1P2/research/LRU_CACHE_RESEARCH_INDEX.md +424 -0
- package/plan/P1P2/research/REFLECTION_INDEX.md +291 -0
- package/plan/P1P2/research/REFLECTION_RESEARCH_REPORT.md +1342 -0
- package/plan/P1P2/research/RESEARCH_SUMMARY.md +342 -0
- package/plan/P1P2/research/anthropic-sdk.md +174 -0
- package/plan/P1P2/research/async-local-storage.md +200 -0
- package/plan/P1P2/research/reflection-code-patterns.md +1205 -0
- package/plan/P1P2/research/reflection-decision-matrix.md +421 -0
- package/plan/P1P2/research/reflection-implementation-guide.md +1341 -0
- package/plan/P1P2/research/reflection-integration-guide.md +834 -0
- package/plan/P1P2/research/reflection-patterns.md +1468 -0
- package/plan/P1P2/research/reflection-quick-reference.md +558 -0
- package/plan/P1P2/research/zod-schema.md +152 -0
- package/plan/P3P4/PRP.md +1388 -0
- package/plan/P3P4/research/caching-lru.md +116 -0
- package/plan/P3P4/research/introspection-tools.md +177 -0
- package/plan/P3P4/research/reflection-patterns.md +117 -0
- package/plan/P4P5/PRP.md +1136 -0
- package/plan/P4P5/research/RESEARCH_SUMMARY.md +151 -0
- package/plan/architecture/external_deps.md +358 -0
- package/plan/architecture/system_context.md +242 -0
- package/plan/backlog.json +867 -0
- package/plan/research/INTROSPECTION_RESEARCH_SUMMARY.md +378 -0
- package/plan/research/README-INTROSPECTION.md +352 -0
- package/plan/research/agent-introspection-patterns.md +1085 -0
- package/plan/research/introspection-security-guide.md +928 -0
- package/plan/research/introspection-tool-examples.md +875 -0
- package/scripts/generate-llms-full.ts +206 -0
- package/src/__tests__/integration/agent-workflow.test.ts +256 -0
- package/src/__tests__/integration/tree-mirroring.test.ts +114 -0
- package/src/__tests__/unit/agent.test.ts +169 -0
- package/src/__tests__/unit/cache-key.test.ts +182 -0
- package/src/__tests__/unit/cache.test.ts +172 -0
- package/src/__tests__/unit/context.test.ts +138 -0
- package/src/__tests__/unit/decorators.test.ts +100 -0
- package/src/__tests__/unit/introspection-tools.test.ts +277 -0
- package/src/__tests__/unit/prompt.test.ts +135 -0
- package/src/__tests__/unit/reflection.test.ts +210 -0
- package/src/__tests__/unit/tree-debugger.test.ts +85 -0
- package/src/__tests__/unit/workflow.test.ts +81 -0
- package/src/cache/cache-key.ts +244 -0
- package/src/cache/cache.ts +236 -0
- package/src/cache/index.ts +8 -0
- package/src/core/agent.ts +573 -0
- package/src/core/context.ts +119 -0
- package/src/core/event-tree.ts +260 -0
- package/src/core/factory.ts +123 -0
- package/src/core/index.ts +17 -0
- package/src/core/logger.ts +87 -0
- package/src/core/mcp-handler.ts +184 -0
- package/src/core/prompt.ts +150 -0
- package/src/core/workflow-context.ts +349 -0
- package/src/core/workflow.ts +302 -0
- package/src/debugger/index.ts +1 -0
- package/src/debugger/tree-debugger.ts +210 -0
- package/src/decorators/index.ts +3 -0
- package/src/decorators/observed-state.ts +95 -0
- package/src/decorators/step.ts +139 -0
- package/src/decorators/task.ts +96 -0
- package/src/examples/index.ts +2 -0
- package/src/examples/tdd-orchestrator.ts +65 -0
- package/src/examples/test-cycle-workflow.ts +64 -0
- package/src/index.ts +140 -0
- package/src/reflection/index.ts +5 -0
- package/src/reflection/reflection.ts +407 -0
- package/src/tools/index.ts +36 -0
- package/src/tools/introspection.ts +464 -0
- package/src/types/agent.ts +90 -0
- package/src/types/decorators.ts +25 -0
- package/src/types/error-strategy.ts +13 -0
- package/src/types/error.ts +20 -0
- package/src/types/events.ts +74 -0
- package/src/types/index.ts +55 -0
- package/src/types/logging.ts +24 -0
- package/src/types/observer.ts +18 -0
- package/src/types/prompt.ts +40 -0
- package/src/types/reflection.ts +117 -0
- package/src/types/sdk-primitives.ts +128 -0
- package/src/types/snapshot.ts +14 -0
- package/src/types/workflow-context.ts +163 -0
- package/src/types/workflow.ts +37 -0
- package/src/utils/id.ts +11 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/observable.ts +77 -0
- package/tasks.json +0 -0
- package/tsconfig.json +22 -0
- package/vitest.config.ts +16 -0
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example 7: Agent Loops with Observability
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates:
|
|
5
|
+
* - Using Agent.prompt() within ctx.step() loops
|
|
6
|
+
* - Multiple agents for different item types
|
|
7
|
+
* - Full event tree visualization with timing
|
|
8
|
+
* - State snapshots at each iteration
|
|
9
|
+
* - Cache hit/miss tracking
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import {
|
|
14
|
+
Workflow,
|
|
15
|
+
Step,
|
|
16
|
+
ObservedState,
|
|
17
|
+
WorkflowTreeDebugger,
|
|
18
|
+
createAgent,
|
|
19
|
+
createPrompt,
|
|
20
|
+
defaultCache,
|
|
21
|
+
} from 'groundswell';
|
|
22
|
+
import { printHeader, printSection, sleep, simulateApiCall } from '../utils/helpers.js';
|
|
23
|
+
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// Response Schemas
|
|
26
|
+
// ============================================================================
|
|
27
|
+
|
|
28
|
+
const ClassificationSchema = z.object({
|
|
29
|
+
item: z.string(),
|
|
30
|
+
category: z.enum(['fruit', 'vegetable', 'grain', 'protein', 'dairy']),
|
|
31
|
+
confidence: z.number().min(0).max(1),
|
|
32
|
+
reasoning: z.string(),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const TextAnalysisSchema = z.object({
|
|
36
|
+
input: z.string(),
|
|
37
|
+
wordCount: z.number(),
|
|
38
|
+
sentiment: z.enum(['positive', 'negative', 'neutral']),
|
|
39
|
+
keyWords: z.array(z.string()),
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const NumberAnalysisSchema = z.object({
|
|
43
|
+
input: z.number(),
|
|
44
|
+
isEven: z.boolean(),
|
|
45
|
+
isPrime: z.boolean(),
|
|
46
|
+
factors: z.array(z.number()),
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
type Classification = z.infer<typeof ClassificationSchema>;
|
|
50
|
+
type TextAnalysis = z.infer<typeof TextAnalysisSchema>;
|
|
51
|
+
type NumberAnalysis = z.infer<typeof NumberAnalysisSchema>;
|
|
52
|
+
|
|
53
|
+
// ============================================================================
|
|
54
|
+
// Simulated Agent Responses (no actual API calls)
|
|
55
|
+
// ============================================================================
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Simulate classification response
|
|
59
|
+
*/
|
|
60
|
+
async function simulateClassification(item: string): Promise<Classification> {
|
|
61
|
+
const categories: Record<string, 'fruit' | 'vegetable' | 'grain' | 'protein' | 'dairy'> = {
|
|
62
|
+
apple: 'fruit',
|
|
63
|
+
banana: 'fruit',
|
|
64
|
+
cherry: 'fruit',
|
|
65
|
+
carrot: 'vegetable',
|
|
66
|
+
broccoli: 'vegetable',
|
|
67
|
+
rice: 'grain',
|
|
68
|
+
chicken: 'protein',
|
|
69
|
+
milk: 'dairy',
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
await sleep(50 + Math.random() * 100);
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
item,
|
|
76
|
+
category: categories[item.toLowerCase()] ?? 'fruit',
|
|
77
|
+
confidence: 0.85 + Math.random() * 0.15,
|
|
78
|
+
reasoning: `${item} is classified based on its nutritional properties`,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Simulate text analysis response
|
|
84
|
+
*/
|
|
85
|
+
async function simulateTextAnalysis(input: string): Promise<TextAnalysis> {
|
|
86
|
+
await sleep(30 + Math.random() * 70);
|
|
87
|
+
|
|
88
|
+
const words = input.split(/\s+/).filter((w) => w.length > 0);
|
|
89
|
+
const sentiments: Array<'positive' | 'negative' | 'neutral'> = [
|
|
90
|
+
'positive',
|
|
91
|
+
'neutral',
|
|
92
|
+
'negative',
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
input,
|
|
97
|
+
wordCount: words.length,
|
|
98
|
+
sentiment: sentiments[Math.floor(Math.random() * 3)],
|
|
99
|
+
keyWords: words.filter((w) => w.length > 4).slice(0, 3),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Simulate number analysis response
|
|
105
|
+
*/
|
|
106
|
+
async function simulateNumberAnalysis(input: number): Promise<NumberAnalysis> {
|
|
107
|
+
await sleep(20 + Math.random() * 50);
|
|
108
|
+
|
|
109
|
+
const isPrime = (n: number): boolean => {
|
|
110
|
+
if (n < 2) return false;
|
|
111
|
+
for (let i = 2; i <= Math.sqrt(n); i++) {
|
|
112
|
+
if (n % i === 0) return false;
|
|
113
|
+
}
|
|
114
|
+
return true;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const getFactors = (n: number): number[] => {
|
|
118
|
+
const factors: number[] = [];
|
|
119
|
+
for (let i = 1; i <= n; i++) {
|
|
120
|
+
if (n % i === 0) factors.push(i);
|
|
121
|
+
}
|
|
122
|
+
return factors;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
input,
|
|
127
|
+
isEven: input % 2 === 0,
|
|
128
|
+
isPrime: isPrime(input),
|
|
129
|
+
factors: getFactors(input),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ============================================================================
|
|
134
|
+
// Workflow Definitions
|
|
135
|
+
// ============================================================================
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Basic agent loop workflow - processes items sequentially
|
|
139
|
+
*/
|
|
140
|
+
class BasicAgentLoopWorkflow extends Workflow {
|
|
141
|
+
@ObservedState()
|
|
142
|
+
items: string[] = [];
|
|
143
|
+
|
|
144
|
+
@ObservedState()
|
|
145
|
+
results: Classification[] = [];
|
|
146
|
+
|
|
147
|
+
@ObservedState()
|
|
148
|
+
currentIndex: number = 0;
|
|
149
|
+
|
|
150
|
+
constructor(name: string, items: string[]) {
|
|
151
|
+
super(name);
|
|
152
|
+
this.items = items;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
@Step({ trackTiming: true, snapshotState: true })
|
|
156
|
+
async processItem(item: string): Promise<Classification> {
|
|
157
|
+
this.logger.info(`Processing: ${item}`);
|
|
158
|
+
const result = await simulateClassification(item);
|
|
159
|
+
this.results.push(result);
|
|
160
|
+
this.currentIndex++;
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async run(): Promise<Classification[]> {
|
|
165
|
+
this.setStatus('running');
|
|
166
|
+
this.logger.info(`Starting loop with ${this.items.length} items`);
|
|
167
|
+
|
|
168
|
+
const startTime = Date.now();
|
|
169
|
+
|
|
170
|
+
for (const item of this.items) {
|
|
171
|
+
await this.processItem(item);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const duration = Date.now() - startTime;
|
|
175
|
+
this.logger.info(`Loop completed in ${duration}ms`);
|
|
176
|
+
|
|
177
|
+
this.setStatus('completed');
|
|
178
|
+
return this.results;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Multi-agent loop workflow - uses different agents for different data types
|
|
184
|
+
*/
|
|
185
|
+
class MultiAgentLoopWorkflow extends Workflow {
|
|
186
|
+
@ObservedState()
|
|
187
|
+
mixedData: Array<string | number> = [];
|
|
188
|
+
|
|
189
|
+
@ObservedState()
|
|
190
|
+
textResults: TextAnalysis[] = [];
|
|
191
|
+
|
|
192
|
+
@ObservedState()
|
|
193
|
+
numberResults: NumberAnalysis[] = [];
|
|
194
|
+
|
|
195
|
+
@ObservedState()
|
|
196
|
+
processedCount: number = 0;
|
|
197
|
+
|
|
198
|
+
constructor(name: string, data: Array<string | number>) {
|
|
199
|
+
super(name);
|
|
200
|
+
this.mixedData = data;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
@Step({ trackTiming: true, snapshotState: true, name: 'analyze-text' })
|
|
204
|
+
async analyzeText(input: string): Promise<TextAnalysis> {
|
|
205
|
+
this.logger.info(`TextAgent analyzing: "${input}"`);
|
|
206
|
+
const result = await simulateTextAnalysis(input);
|
|
207
|
+
this.textResults.push(result);
|
|
208
|
+
this.processedCount++;
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
@Step({ trackTiming: true, snapshotState: true, name: 'analyze-number' })
|
|
213
|
+
async analyzeNumber(input: number): Promise<NumberAnalysis> {
|
|
214
|
+
this.logger.info(`NumberAgent analyzing: ${input}`);
|
|
215
|
+
const result = await simulateNumberAnalysis(input);
|
|
216
|
+
this.numberResults.push(result);
|
|
217
|
+
this.processedCount++;
|
|
218
|
+
return result;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async run(): Promise<void> {
|
|
222
|
+
this.setStatus('running');
|
|
223
|
+
this.logger.info(`Starting multi-agent loop with ${this.mixedData.length} items`);
|
|
224
|
+
|
|
225
|
+
const startTime = Date.now();
|
|
226
|
+
|
|
227
|
+
for (const input of this.mixedData) {
|
|
228
|
+
if (typeof input === 'string') {
|
|
229
|
+
await this.analyzeText(input);
|
|
230
|
+
} else {
|
|
231
|
+
await this.analyzeNumber(input);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const duration = Date.now() - startTime;
|
|
236
|
+
this.logger.info(`Multi-agent loop completed in ${duration}ms`);
|
|
237
|
+
this.logger.info(`Text results: ${this.textResults.length}, Number results: ${this.numberResults.length}`);
|
|
238
|
+
|
|
239
|
+
this.setStatus('completed');
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Cached agent loop workflow - demonstrates cache hits across iterations
|
|
245
|
+
*/
|
|
246
|
+
class CachedAgentLoopWorkflow extends Workflow {
|
|
247
|
+
@ObservedState()
|
|
248
|
+
items: string[] = [];
|
|
249
|
+
|
|
250
|
+
@ObservedState()
|
|
251
|
+
cacheHits: number = 0;
|
|
252
|
+
|
|
253
|
+
@ObservedState()
|
|
254
|
+
cacheMisses: number = 0;
|
|
255
|
+
|
|
256
|
+
private cache: Map<string, Classification> = new Map();
|
|
257
|
+
|
|
258
|
+
constructor(name: string, items: string[]) {
|
|
259
|
+
super(name);
|
|
260
|
+
this.items = items;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
@Step({ trackTiming: true, snapshotState: true })
|
|
264
|
+
async processWithCache(item: string): Promise<Classification> {
|
|
265
|
+
// Check local cache first
|
|
266
|
+
const cached = this.cache.get(item);
|
|
267
|
+
if (cached) {
|
|
268
|
+
this.cacheHits++;
|
|
269
|
+
this.logger.info(`Cache HIT for: ${item}`);
|
|
270
|
+
return cached;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
this.cacheMisses++;
|
|
274
|
+
this.logger.info(`Cache MISS for: ${item}`);
|
|
275
|
+
|
|
276
|
+
const result = await simulateClassification(item);
|
|
277
|
+
this.cache.set(item, result);
|
|
278
|
+
return result;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
async run(): Promise<void> {
|
|
282
|
+
this.setStatus('running');
|
|
283
|
+
this.logger.info(`Starting cached loop with ${this.items.length} items`);
|
|
284
|
+
|
|
285
|
+
const startTime = Date.now();
|
|
286
|
+
|
|
287
|
+
for (const item of this.items) {
|
|
288
|
+
await this.processWithCache(item);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const duration = Date.now() - startTime;
|
|
292
|
+
this.logger.info(`Cached loop completed in ${duration}ms`);
|
|
293
|
+
this.logger.info(`Cache hits: ${this.cacheHits}, misses: ${this.cacheMisses}`);
|
|
294
|
+
|
|
295
|
+
this.setStatus('completed');
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// ============================================================================
|
|
300
|
+
// Main Example Runner
|
|
301
|
+
// ============================================================================
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Run the Agent Loops example
|
|
305
|
+
*/
|
|
306
|
+
export async function runAgentLoopsExample(): Promise<void> {
|
|
307
|
+
printHeader('Example 7: Agent Loops with Observability');
|
|
308
|
+
|
|
309
|
+
// Part 1: Basic Agent Loop
|
|
310
|
+
printSection('Part 1: Basic Agent Loop');
|
|
311
|
+
{
|
|
312
|
+
const items = ['apple', 'banana', 'cherry', 'carrot', 'broccoli'];
|
|
313
|
+
const workflow = new BasicAgentLoopWorkflow('ClassificationLoop', items);
|
|
314
|
+
const debugger_ = new WorkflowTreeDebugger(workflow);
|
|
315
|
+
|
|
316
|
+
console.log(`Processing ${items.length} items: ${items.join(', ')}\n`);
|
|
317
|
+
|
|
318
|
+
const startTime = Date.now();
|
|
319
|
+
const results = await workflow.run();
|
|
320
|
+
const elapsed = Date.now() - startTime;
|
|
321
|
+
|
|
322
|
+
console.log(`\nResults (${elapsed}ms total):`);
|
|
323
|
+
for (const result of results) {
|
|
324
|
+
console.log(` ${result.item}: ${result.category} (${(result.confidence * 100).toFixed(1)}%)`);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
console.log('\nTree visualization:');
|
|
328
|
+
console.log(debugger_.toTreeString());
|
|
329
|
+
|
|
330
|
+
const stats = debugger_.getStats();
|
|
331
|
+
console.log('Statistics:', {
|
|
332
|
+
totalNodes: stats.totalNodes,
|
|
333
|
+
completedSteps: stats.completed,
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Part 2: Multi-Agent Loop
|
|
338
|
+
printSection('Part 2: Multi-Agent Loop (Different Agents per Type)');
|
|
339
|
+
{
|
|
340
|
+
const mixedData: Array<string | number> = [
|
|
341
|
+
'Hello world',
|
|
342
|
+
42,
|
|
343
|
+
'TypeScript is great',
|
|
344
|
+
17,
|
|
345
|
+
'Agent loops',
|
|
346
|
+
100,
|
|
347
|
+
];
|
|
348
|
+
|
|
349
|
+
const workflow = new MultiAgentLoopWorkflow('MultiAgentLoop', mixedData);
|
|
350
|
+
const debugger_ = new WorkflowTreeDebugger(workflow);
|
|
351
|
+
|
|
352
|
+
console.log(`Processing mixed data: ${mixedData.length} items\n`);
|
|
353
|
+
|
|
354
|
+
const startTime = Date.now();
|
|
355
|
+
await workflow.run();
|
|
356
|
+
const elapsed = Date.now() - startTime;
|
|
357
|
+
|
|
358
|
+
console.log(`\nText Analysis Results:`);
|
|
359
|
+
for (const result of workflow.textResults) {
|
|
360
|
+
console.log(` "${result.input}": ${result.wordCount} words, ${result.sentiment} sentiment`);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
console.log(`\nNumber Analysis Results:`);
|
|
364
|
+
for (const result of workflow.numberResults) {
|
|
365
|
+
console.log(` ${result.input}: even=${result.isEven}, prime=${result.isPrime}, factors=[${result.factors.join(',')}]`);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
console.log(`\nTotal time: ${elapsed}ms`);
|
|
369
|
+
console.log('\nTree visualization:');
|
|
370
|
+
console.log(debugger_.toTreeString());
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Part 3: Cached Agent Loop
|
|
374
|
+
printSection('Part 3: Cached Agent Loop (Duplicate Detection)');
|
|
375
|
+
{
|
|
376
|
+
// Include duplicates to demonstrate cache hits
|
|
377
|
+
const items = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple'];
|
|
378
|
+
|
|
379
|
+
const workflow = new CachedAgentLoopWorkflow('CachedLoop', items);
|
|
380
|
+
const debugger_ = new WorkflowTreeDebugger(workflow);
|
|
381
|
+
|
|
382
|
+
console.log(`Processing ${items.length} items with duplicates: ${items.join(', ')}\n`);
|
|
383
|
+
|
|
384
|
+
const startTime = Date.now();
|
|
385
|
+
await workflow.run();
|
|
386
|
+
const elapsed = Date.now() - startTime;
|
|
387
|
+
|
|
388
|
+
console.log(`\nCache Performance:`);
|
|
389
|
+
console.log(` Total items: ${items.length}`);
|
|
390
|
+
console.log(` Cache hits: ${workflow.cacheHits}`);
|
|
391
|
+
console.log(` Cache misses: ${workflow.cacheMisses}`);
|
|
392
|
+
console.log(` Hit rate: ${((workflow.cacheHits / items.length) * 100).toFixed(1)}%`);
|
|
393
|
+
console.log(`\nTotal time: ${elapsed}ms`);
|
|
394
|
+
|
|
395
|
+
console.log('\nTree visualization:');
|
|
396
|
+
console.log(debugger_.toTreeString());
|
|
397
|
+
|
|
398
|
+
const stats = debugger_.getStats();
|
|
399
|
+
console.log('Statistics:', stats);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Part 4: Performance Comparison
|
|
403
|
+
printSection('Part 4: Sequential vs Timing Analysis');
|
|
404
|
+
{
|
|
405
|
+
const items = ['item1', 'item2', 'item3', 'item4', 'item5'];
|
|
406
|
+
|
|
407
|
+
console.log('Sequential processing of 5 items:');
|
|
408
|
+
const seqWorkflow = new BasicAgentLoopWorkflow('SequentialLoop', items);
|
|
409
|
+
|
|
410
|
+
const seqStart = Date.now();
|
|
411
|
+
await seqWorkflow.run();
|
|
412
|
+
const seqTime = Date.now() - seqStart;
|
|
413
|
+
|
|
414
|
+
console.log(` Sequential time: ${seqTime}ms`);
|
|
415
|
+
console.log(` Average per item: ${(seqTime / items.length).toFixed(1)}ms`);
|
|
416
|
+
|
|
417
|
+
// Show the timing from tree stats
|
|
418
|
+
const debugger_ = new WorkflowTreeDebugger(seqWorkflow);
|
|
419
|
+
const logs = debugger_.getTree().logs;
|
|
420
|
+
console.log(`\nLog entries: ${logs.length}`);
|
|
421
|
+
for (const log of logs.slice(-5)) {
|
|
422
|
+
console.log(` [${log.level}] ${log.message}`);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
console.log('\n=== Example 7 Complete ===');
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Allow direct execution
|
|
430
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
431
|
+
runAgentLoopsExample().catch(console.error);
|
|
432
|
+
}
|