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.
Files changed (120) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/.claude/system_prompts/task-breakdown.md +100 -0
  3. package/PRPs/001-hierarchical-workflow-engine.md +2438 -0
  4. package/PRPs/PRDs/001-hierarchical-workflow-engine.md +543 -0
  5. package/PRPs/PRDs/002-agent-prompt.md +390 -0
  6. package/PRPs/PRDs/003-agent-prompt.md +943 -0
  7. package/PRPs/PRDs/004-agent-prompt.md +1136 -0
  8. package/PRPs/PRDs/tasks-001.json +492 -0
  9. package/PRPs/README.md +83 -0
  10. package/PRPs/templates/prp_base.md +222 -0
  11. package/README.md +218 -0
  12. package/docs/agent.md +422 -0
  13. package/docs/prompt.md +419 -0
  14. package/docs/workflow.md +600 -0
  15. package/examples/README.md +244 -0
  16. package/examples/examples/01-basic-workflow.ts +100 -0
  17. package/examples/examples/02-decorator-options.ts +217 -0
  18. package/examples/examples/03-parent-child.ts +241 -0
  19. package/examples/examples/04-observers-debugger.ts +340 -0
  20. package/examples/examples/05-error-handling.ts +387 -0
  21. package/examples/examples/06-concurrent-tasks.ts +352 -0
  22. package/examples/examples/07-agent-loops.ts +432 -0
  23. package/examples/examples/08-sdk-features.ts +667 -0
  24. package/examples/examples/09-reflection.ts +573 -0
  25. package/examples/examples/10-introspection.ts +550 -0
  26. package/examples/index.ts +143 -0
  27. package/examples/utils/helpers.ts +57 -0
  28. package/llms_full.txt +5890 -0
  29. package/package.json +63 -0
  30. package/plan/P1P2/PRP.md +527 -0
  31. package/plan/P1P2/research/LRU_CACHE_BEST_PRACTICES.md +1929 -0
  32. package/plan/P1P2/research/LRU_CACHE_CODE_PATTERNS.md +857 -0
  33. package/plan/P1P2/research/LRU_CACHE_INTEGRATION_GUIDE.md +738 -0
  34. package/plan/P1P2/research/LRU_CACHE_RESEARCH_INDEX.md +424 -0
  35. package/plan/P1P2/research/REFLECTION_INDEX.md +291 -0
  36. package/plan/P1P2/research/REFLECTION_RESEARCH_REPORT.md +1342 -0
  37. package/plan/P1P2/research/RESEARCH_SUMMARY.md +342 -0
  38. package/plan/P1P2/research/anthropic-sdk.md +174 -0
  39. package/plan/P1P2/research/async-local-storage.md +200 -0
  40. package/plan/P1P2/research/reflection-code-patterns.md +1205 -0
  41. package/plan/P1P2/research/reflection-decision-matrix.md +421 -0
  42. package/plan/P1P2/research/reflection-implementation-guide.md +1341 -0
  43. package/plan/P1P2/research/reflection-integration-guide.md +834 -0
  44. package/plan/P1P2/research/reflection-patterns.md +1468 -0
  45. package/plan/P1P2/research/reflection-quick-reference.md +558 -0
  46. package/plan/P1P2/research/zod-schema.md +152 -0
  47. package/plan/P3P4/PRP.md +1388 -0
  48. package/plan/P3P4/research/caching-lru.md +116 -0
  49. package/plan/P3P4/research/introspection-tools.md +177 -0
  50. package/plan/P3P4/research/reflection-patterns.md +117 -0
  51. package/plan/P4P5/PRP.md +1136 -0
  52. package/plan/P4P5/research/RESEARCH_SUMMARY.md +151 -0
  53. package/plan/architecture/external_deps.md +358 -0
  54. package/plan/architecture/system_context.md +242 -0
  55. package/plan/backlog.json +867 -0
  56. package/plan/research/INTROSPECTION_RESEARCH_SUMMARY.md +378 -0
  57. package/plan/research/README-INTROSPECTION.md +352 -0
  58. package/plan/research/agent-introspection-patterns.md +1085 -0
  59. package/plan/research/introspection-security-guide.md +928 -0
  60. package/plan/research/introspection-tool-examples.md +875 -0
  61. package/scripts/generate-llms-full.ts +206 -0
  62. package/src/__tests__/integration/agent-workflow.test.ts +256 -0
  63. package/src/__tests__/integration/tree-mirroring.test.ts +114 -0
  64. package/src/__tests__/unit/agent.test.ts +169 -0
  65. package/src/__tests__/unit/cache-key.test.ts +182 -0
  66. package/src/__tests__/unit/cache.test.ts +172 -0
  67. package/src/__tests__/unit/context.test.ts +138 -0
  68. package/src/__tests__/unit/decorators.test.ts +100 -0
  69. package/src/__tests__/unit/introspection-tools.test.ts +277 -0
  70. package/src/__tests__/unit/prompt.test.ts +135 -0
  71. package/src/__tests__/unit/reflection.test.ts +210 -0
  72. package/src/__tests__/unit/tree-debugger.test.ts +85 -0
  73. package/src/__tests__/unit/workflow.test.ts +81 -0
  74. package/src/cache/cache-key.ts +244 -0
  75. package/src/cache/cache.ts +236 -0
  76. package/src/cache/index.ts +8 -0
  77. package/src/core/agent.ts +573 -0
  78. package/src/core/context.ts +119 -0
  79. package/src/core/event-tree.ts +260 -0
  80. package/src/core/factory.ts +123 -0
  81. package/src/core/index.ts +17 -0
  82. package/src/core/logger.ts +87 -0
  83. package/src/core/mcp-handler.ts +184 -0
  84. package/src/core/prompt.ts +150 -0
  85. package/src/core/workflow-context.ts +349 -0
  86. package/src/core/workflow.ts +302 -0
  87. package/src/debugger/index.ts +1 -0
  88. package/src/debugger/tree-debugger.ts +210 -0
  89. package/src/decorators/index.ts +3 -0
  90. package/src/decorators/observed-state.ts +95 -0
  91. package/src/decorators/step.ts +139 -0
  92. package/src/decorators/task.ts +96 -0
  93. package/src/examples/index.ts +2 -0
  94. package/src/examples/tdd-orchestrator.ts +65 -0
  95. package/src/examples/test-cycle-workflow.ts +64 -0
  96. package/src/index.ts +140 -0
  97. package/src/reflection/index.ts +5 -0
  98. package/src/reflection/reflection.ts +407 -0
  99. package/src/tools/index.ts +36 -0
  100. package/src/tools/introspection.ts +464 -0
  101. package/src/types/agent.ts +90 -0
  102. package/src/types/decorators.ts +25 -0
  103. package/src/types/error-strategy.ts +13 -0
  104. package/src/types/error.ts +20 -0
  105. package/src/types/events.ts +74 -0
  106. package/src/types/index.ts +55 -0
  107. package/src/types/logging.ts +24 -0
  108. package/src/types/observer.ts +18 -0
  109. package/src/types/prompt.ts +40 -0
  110. package/src/types/reflection.ts +117 -0
  111. package/src/types/sdk-primitives.ts +128 -0
  112. package/src/types/snapshot.ts +14 -0
  113. package/src/types/workflow-context.ts +163 -0
  114. package/src/types/workflow.ts +37 -0
  115. package/src/utils/id.ts +11 -0
  116. package/src/utils/index.ts +3 -0
  117. package/src/utils/observable.ts +77 -0
  118. package/tasks.json +0 -0
  119. package/tsconfig.json +22 -0
  120. 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
+ }