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,387 @@
1
+ /**
2
+ * Example 5: Error Handling
3
+ *
4
+ * Demonstrates:
5
+ * - How @Step decorator wraps errors in WorkflowError
6
+ * - Error context including state snapshots and logs
7
+ * - Error events emitted to observers
8
+ * - Error propagation in parent-child workflows
9
+ * - Recovery strategies in workflow orchestration
10
+ */
11
+
12
+ import {
13
+ Workflow,
14
+ Step,
15
+ Task,
16
+ ObservedState,
17
+ getObservedState,
18
+ WorkflowTreeDebugger,
19
+ WorkflowObserver,
20
+ WorkflowEvent,
21
+ WorkflowError,
22
+ LogEntry,
23
+ WorkflowNode,
24
+ } from 'groundswell';
25
+ import { printHeader, printSection, sleep } from '../utils/helpers.js';
26
+
27
+ /**
28
+ * Workflow that demonstrates error wrapping
29
+ */
30
+ class ErrorDemoWorkflow extends Workflow {
31
+ @ObservedState()
32
+ currentStep: string = 'init';
33
+
34
+ @ObservedState()
35
+ itemsProcessed: number = 0;
36
+
37
+ @ObservedState({ redact: true })
38
+ sensitiveContext: string = 'secret-data';
39
+
40
+ @Step({ snapshotState: true })
41
+ async step1(): Promise<void> {
42
+ this.currentStep = 'step1';
43
+ this.itemsProcessed = 5;
44
+ this.logger.info('Step 1 completed successfully');
45
+ await sleep(50);
46
+ }
47
+
48
+ @Step({ snapshotState: true })
49
+ async step2(): Promise<void> {
50
+ this.currentStep = 'step2';
51
+ this.itemsProcessed = 10;
52
+ this.logger.info('Step 2 completed successfully');
53
+ await sleep(50);
54
+ }
55
+
56
+ @Step({ snapshotState: true })
57
+ async failingStep(): Promise<void> {
58
+ this.currentStep = 'failing';
59
+ this.logger.info('About to fail...');
60
+ await sleep(30);
61
+
62
+ // This error will be wrapped in WorkflowError
63
+ throw new Error('Something went wrong in failingStep!');
64
+ }
65
+
66
+ async run(): Promise<void> {
67
+ this.setStatus('running');
68
+ this.logger.info('Starting error demo workflow');
69
+
70
+ await this.step1();
71
+ await this.step2();
72
+ await this.failingStep(); // This will throw
73
+
74
+ // This line won't be reached
75
+ this.setStatus('completed');
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Workflow with retry logic
81
+ */
82
+ class RetryableWorkflow extends Workflow {
83
+ @ObservedState()
84
+ attempt: number = 0;
85
+
86
+ @ObservedState()
87
+ maxAttempts: number = 3;
88
+
89
+ @ObservedState()
90
+ success: boolean = false;
91
+
92
+ private failUntilAttempt: number;
93
+
94
+ constructor(name: string, failUntilAttempt: number = 2) {
95
+ super(name);
96
+ this.failUntilAttempt = failUntilAttempt;
97
+ }
98
+
99
+ @Step({ trackTiming: true, snapshotState: true })
100
+ async unreliableOperation(): Promise<void> {
101
+ this.attempt++;
102
+ this.logger.info(`Attempt ${this.attempt}/${this.maxAttempts}`);
103
+ await sleep(50);
104
+
105
+ if (this.attempt < this.failUntilAttempt) {
106
+ throw new Error(`Simulated failure on attempt ${this.attempt}`);
107
+ }
108
+
109
+ this.success = true;
110
+ this.logger.info('Operation succeeded!');
111
+ }
112
+
113
+ async run(): Promise<boolean> {
114
+ this.setStatus('running');
115
+ this.logger.info('Starting retryable workflow');
116
+
117
+ while (this.attempt < this.maxAttempts) {
118
+ try {
119
+ await this.unreliableOperation();
120
+ this.setStatus('completed');
121
+ return true;
122
+ } catch (error) {
123
+ const wfError = error as WorkflowError;
124
+ this.logger.warn(`Attempt failed: ${wfError.message}`);
125
+
126
+ if (this.attempt >= this.maxAttempts) {
127
+ this.setStatus('failed');
128
+ this.logger.error('All attempts exhausted');
129
+ throw error;
130
+ }
131
+
132
+ this.logger.info('Retrying...');
133
+ await sleep(100); // Backoff delay
134
+ }
135
+ }
136
+
137
+ this.setStatus('failed');
138
+ return false;
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Child workflow that may fail
144
+ */
145
+ class FailableChildWorkflow extends Workflow {
146
+ private shouldFail: boolean;
147
+
148
+ @ObservedState()
149
+ taskStatus: string = 'pending';
150
+
151
+ constructor(name: string, shouldFail: boolean, parent?: Workflow) {
152
+ super(name, parent);
153
+ this.shouldFail = shouldFail;
154
+ }
155
+
156
+ @Step({ snapshotState: true })
157
+ async execute(): Promise<void> {
158
+ this.taskStatus = 'executing';
159
+ this.logger.info('Executing child workflow');
160
+ await sleep(50);
161
+
162
+ if (this.shouldFail) {
163
+ throw new Error(`Child ${this.getNode().name} failed intentionally`);
164
+ }
165
+
166
+ this.taskStatus = 'success';
167
+ }
168
+
169
+ async run(): Promise<void> {
170
+ this.setStatus('running');
171
+ await this.execute();
172
+ this.setStatus('completed');
173
+ }
174
+ }
175
+
176
+ /**
177
+ * Parent workflow with error recovery
178
+ */
179
+ class ResilientParentWorkflow extends Workflow {
180
+ @ObservedState()
181
+ totalChildren: number = 0;
182
+
183
+ @ObservedState()
184
+ successfulChildren: number = 0;
185
+
186
+ @ObservedState()
187
+ failedChildren: number = 0;
188
+
189
+ private childConfigs: { name: string; shouldFail: boolean }[];
190
+
191
+ constructor(name: string, childConfigs: { name: string; shouldFail: boolean }[]) {
192
+ super(name);
193
+ this.childConfigs = childConfigs;
194
+ this.totalChildren = childConfigs.length;
195
+ }
196
+
197
+ @Task()
198
+ async spawnChild(config: { name: string; shouldFail: boolean }): Promise<FailableChildWorkflow> {
199
+ return new FailableChildWorkflow(config.name, config.shouldFail, this);
200
+ }
201
+
202
+ async run(): Promise<{ success: number; failed: number }> {
203
+ this.setStatus('running');
204
+ this.logger.info(`Starting resilient parent with ${this.totalChildren} children`);
205
+
206
+ for (const config of this.childConfigs) {
207
+ const child = await this.spawnChild(config);
208
+
209
+ try {
210
+ await child.run();
211
+ this.successfulChildren++;
212
+ this.logger.info(`Child ${config.name} succeeded`);
213
+ } catch (error) {
214
+ this.failedChildren++;
215
+ const wfError = error as WorkflowError;
216
+ this.logger.warn(`Child ${config.name} failed: ${wfError.message}`);
217
+ // Continue with other children instead of failing entirely
218
+ }
219
+ }
220
+
221
+ const allSucceeded = this.failedChildren === 0;
222
+ this.setStatus(allSucceeded ? 'completed' : 'completed'); // Still complete, but with partial success
223
+ this.logger.info(`Completed: ${this.successfulChildren} succeeded, ${this.failedChildren} failed`);
224
+
225
+ return {
226
+ success: this.successfulChildren,
227
+ failed: this.failedChildren,
228
+ };
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Run the error handling example
234
+ */
235
+ export async function runErrorHandlingExample(): Promise<void> {
236
+ printHeader('Example 5: Error Handling');
237
+
238
+ // Part 1: Basic error wrapping
239
+ printSection('Part 1: WorkflowError Structure');
240
+ {
241
+ const workflow = new ErrorDemoWorkflow('ErrorDemo');
242
+ const debugger_ = new WorkflowTreeDebugger(workflow);
243
+
244
+ let capturedError: WorkflowError | null = null;
245
+
246
+ try {
247
+ await workflow.run();
248
+ } catch (error) {
249
+ capturedError = error as WorkflowError;
250
+ }
251
+
252
+ console.log('Error caught and wrapped in WorkflowError:');
253
+ console.log(` message: ${capturedError?.message}`);
254
+ console.log(` workflowId: ${capturedError?.workflowId}`);
255
+ console.log(` stack: ${capturedError?.stack?.split('\n')[0]}...`);
256
+
257
+ console.log('\nState snapshot at time of error:');
258
+ console.log(JSON.stringify(capturedError?.state, null, 2));
259
+
260
+ console.log('\nLogs at time of error:');
261
+ capturedError?.logs.forEach((log) => {
262
+ console.log(` [${log.level}] ${log.message}`);
263
+ });
264
+
265
+ console.log('\nTree state after error:');
266
+ console.log(debugger_.toTreeString());
267
+ }
268
+
269
+ // Part 2: Error events
270
+ printSection('Part 2: Error Events');
271
+ {
272
+ const workflow = new ErrorDemoWorkflow('ErrorEvents');
273
+ const errors: WorkflowEvent[] = [];
274
+
275
+ const observer: WorkflowObserver = {
276
+ onLog: () => {},
277
+ onEvent: (event) => {
278
+ if (event.type === 'error') {
279
+ errors.push(event);
280
+ }
281
+ },
282
+ onStateUpdated: () => {},
283
+ onTreeChanged: () => {},
284
+ };
285
+
286
+ workflow.addObserver(observer);
287
+
288
+ try {
289
+ await workflow.run();
290
+ } catch {
291
+ // Expected
292
+ }
293
+
294
+ console.log(`Error events captured: ${errors.length}`);
295
+ errors.forEach((e) => {
296
+ if (e.type === 'error') {
297
+ console.log(` - Node: ${e.node.name}`);
298
+ console.log(` Message: ${e.error.message}`);
299
+ console.log(` State keys: ${Object.keys(e.error.state).join(', ')}`);
300
+ }
301
+ });
302
+ }
303
+
304
+ // Part 3: Retry logic
305
+ printSection('Part 3: Retry Pattern');
306
+ {
307
+ console.log('Workflow that succeeds on 3rd attempt:');
308
+ const workflow1 = new RetryableWorkflow('RetrySuccess', 3);
309
+
310
+ try {
311
+ const success = await workflow1.run();
312
+ console.log(` Result: ${success ? 'SUCCESS' : 'FAILED'}`);
313
+ console.log(` Attempts: ${workflow1.attempt}`);
314
+ } catch {
315
+ console.log(' Unexpected failure');
316
+ }
317
+
318
+ console.log('\nWorkflow that exhausts all retries:');
319
+ const workflow2 = new RetryableWorkflow('RetryFail', 10); // Will never succeed
320
+
321
+ try {
322
+ await workflow2.run();
323
+ } catch (error) {
324
+ const wfError = error as WorkflowError;
325
+ console.log(` Failed after ${workflow2.attempt} attempts`);
326
+ console.log(` Final error: ${wfError.message}`);
327
+ }
328
+ }
329
+
330
+ // Part 4: Parent-child error isolation
331
+ printSection('Part 4: Error Isolation in Hierarchies');
332
+ {
333
+ const childConfigs = [
334
+ { name: 'Child-A', shouldFail: false },
335
+ { name: 'Child-B', shouldFail: true }, // This one will fail
336
+ { name: 'Child-C', shouldFail: false },
337
+ { name: 'Child-D', shouldFail: true }, // This one will fail
338
+ { name: 'Child-E', shouldFail: false },
339
+ ];
340
+
341
+ const workflow = new ResilientParentWorkflow('ResilientParent', childConfigs);
342
+ const debugger_ = new WorkflowTreeDebugger(workflow);
343
+
344
+ const result = await workflow.run();
345
+
346
+ console.log('Result:', result);
347
+ console.log('\nTree visualization:');
348
+ console.log(debugger_.toTreeString());
349
+
350
+ console.log('Child statuses:');
351
+ workflow.children.forEach((child) => {
352
+ const node = child.getNode();
353
+ const state = getObservedState(child);
354
+ console.log(` ${node.name}: ${node.status} (internal: ${state.taskStatus || 'N/A'})`);
355
+ });
356
+ }
357
+
358
+ // Part 5: Error context preservation
359
+ printSection('Part 5: Full Error Context');
360
+ {
361
+ const workflow = new ErrorDemoWorkflow('ContextDemo');
362
+
363
+ try {
364
+ await workflow.run();
365
+ } catch (error) {
366
+ const wfError = error as WorkflowError;
367
+
368
+ console.log('Complete WorkflowError object:');
369
+ console.log({
370
+ message: wfError.message,
371
+ workflowId: wfError.workflowId,
372
+ hasStack: !!wfError.stack,
373
+ stateFields: Object.keys(wfError.state),
374
+ logCount: wfError.logs.length,
375
+ originalError: wfError.original instanceof Error ? wfError.original.message : 'unknown',
376
+ });
377
+
378
+ console.log('\nNote: sensitiveContext is redacted in state snapshot');
379
+ console.log('State:', wfError.state);
380
+ }
381
+ }
382
+ }
383
+
384
+ // Run if executed directly
385
+ if (import.meta.url === `file://${process.argv[1]}`) {
386
+ runErrorHandlingExample().catch(console.error);
387
+ }