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,150 @@
1
+ /**
2
+ * Prompt<T> - Immutable type-safe prompt definition
3
+ *
4
+ * Prompts define what to send to an agent and how to validate the response.
5
+ * They are value objects - immutable and reusable across agents and workflows.
6
+ */
7
+
8
+ import type { z } from 'zod';
9
+ import type {
10
+ PromptConfig,
11
+ Tool,
12
+ MCPServer,
13
+ Skill,
14
+ AgentHooks,
15
+ } from '../types/index.js';
16
+ import { generateId } from '../utils/id.js';
17
+
18
+ /**
19
+ * Prompt class - immutable definition of a single agent call
20
+ * @template T The expected response type (validated via Zod schema)
21
+ */
22
+ export class Prompt<T> {
23
+ /** Unique identifier for this prompt instance */
24
+ public readonly id: string;
25
+
26
+ /** User message content */
27
+ public readonly user: string;
28
+
29
+ /** Structured data to inject into the prompt */
30
+ public readonly data: Record<string, unknown>;
31
+
32
+ /** Zod schema defining the expected response format */
33
+ public readonly responseFormat: z.ZodType<T>;
34
+
35
+ /** System prompt override (takes precedence over agent config) */
36
+ public readonly systemOverride?: string;
37
+
38
+ /** Tools override */
39
+ public readonly toolsOverride?: Tool[];
40
+
41
+ /** MCPs override */
42
+ public readonly mcpsOverride?: MCPServer[];
43
+
44
+ /** Skills override */
45
+ public readonly skillsOverride?: Skill[];
46
+
47
+ /** Hooks override */
48
+ public readonly hooksOverride?: AgentHooks;
49
+
50
+ /** Enable reflection for this specific prompt */
51
+ public readonly enableReflection?: boolean;
52
+
53
+ /**
54
+ * Create a new Prompt instance
55
+ * @param config Prompt configuration
56
+ */
57
+ constructor(config: PromptConfig<T>) {
58
+ this.id = generateId();
59
+ this.user = config.user;
60
+ this.data = config.data ?? {};
61
+ this.responseFormat = config.responseFormat;
62
+ this.systemOverride = config.system;
63
+ this.toolsOverride = config.tools;
64
+ this.mcpsOverride = config.mcps;
65
+ this.skillsOverride = config.skills;
66
+ this.hooksOverride = config.hooks;
67
+ this.enableReflection = config.enableReflection;
68
+
69
+ // Freeze to ensure immutability
70
+ Object.freeze(this);
71
+ Object.freeze(this.data);
72
+ }
73
+
74
+ /**
75
+ * Validate a response against the response format schema
76
+ * @param data Unknown data to validate
77
+ * @returns Typed validated data
78
+ * @throws ZodError if validation fails
79
+ */
80
+ public validateResponse(data: unknown): T {
81
+ return this.responseFormat.parse(data);
82
+ }
83
+
84
+ /**
85
+ * Safely validate response without throwing
86
+ * @param data Unknown data to validate
87
+ * @returns Result object with success flag and data or error
88
+ */
89
+ public safeValidateResponse(
90
+ data: unknown
91
+ ): { success: true; data: T } | { success: false; error: z.ZodError } {
92
+ const result = this.responseFormat.safeParse(data);
93
+ if (result.success) {
94
+ return { success: true, data: result.data };
95
+ }
96
+ return { success: false, error: result.error };
97
+ }
98
+
99
+ /**
100
+ * Build the full user message including any injected data
101
+ * @returns Formatted user message
102
+ */
103
+ public buildUserMessage(): string {
104
+ if (Object.keys(this.data).length === 0) {
105
+ return this.user;
106
+ }
107
+
108
+ // Format data as a structured section
109
+ const dataSection = Object.entries(this.data)
110
+ .map(([key, value]) => `<${key}>\n${JSON.stringify(value, null, 2)}\n</${key}>`)
111
+ .join('\n\n');
112
+
113
+ return `${this.user}\n\n${dataSection}`;
114
+ }
115
+
116
+ /**
117
+ * Create a new Prompt with updated data (immutable pattern)
118
+ * @param newData Data to merge or replace
119
+ * @returns New Prompt instance
120
+ */
121
+ public withData(newData: Record<string, unknown>): Prompt<T> {
122
+ return new Prompt({
123
+ user: this.user,
124
+ data: { ...this.data, ...newData },
125
+ responseFormat: this.responseFormat,
126
+ system: this.systemOverride,
127
+ tools: this.toolsOverride,
128
+ mcps: this.mcpsOverride,
129
+ skills: this.skillsOverride,
130
+ hooks: this.hooksOverride,
131
+ enableReflection: this.enableReflection,
132
+ });
133
+ }
134
+
135
+ /**
136
+ * Get the prompt data (used for cache key generation)
137
+ * @returns The prompt data object
138
+ */
139
+ public getData(): Record<string, unknown> {
140
+ return this.data;
141
+ }
142
+
143
+ /**
144
+ * Get the response format schema (used for cache key generation)
145
+ * @returns The Zod response format schema
146
+ */
147
+ public getResponseFormat(): z.ZodType<T> {
148
+ return this.responseFormat;
149
+ }
150
+ }
@@ -0,0 +1,349 @@
1
+ /**
2
+ * WorkflowContextImpl - Implementation of functional workflow context
3
+ *
4
+ * Provides step(), spawnWorkflow(), and automatic context propagation
5
+ * for agents and prompts executed within workflows.
6
+ */
7
+
8
+ import type {
9
+ WorkflowContext,
10
+ EventTreeHandle,
11
+ ReflectionAPI,
12
+ AgentLike,
13
+ PromptLike,
14
+ } from '../types/workflow-context.js';
15
+ import type {
16
+ WorkflowNode,
17
+ WorkflowEvent,
18
+ ReflectionConfig,
19
+ ReflectionContext,
20
+ } from '../types/index.js';
21
+ import { EventTreeHandleImpl, createEventTreeHandle } from './event-tree.js';
22
+ import {
23
+ runInContext,
24
+ type AgentExecutionContext,
25
+ } from './context.js';
26
+ import { generateId } from '../utils/id.js';
27
+ import { ReflectionManager } from '../reflection/reflection.js';
28
+ import { createReflectionConfig } from '../types/index.js';
29
+
30
+ /**
31
+ * Interface for workflow-like objects that can emit events
32
+ */
33
+ interface WorkflowLike {
34
+ id: string;
35
+ node: WorkflowNode;
36
+ emitEvent(event: WorkflowEvent): void;
37
+ setStatus(status: 'idle' | 'running' | 'completed' | 'failed' | 'cancelled'): void;
38
+ attachChild(child: WorkflowLike): void;
39
+ }
40
+
41
+ /**
42
+ * WorkflowContext implementation
43
+ */
44
+ export class WorkflowContextImpl implements WorkflowContext {
45
+ public readonly workflowId: string;
46
+ public readonly parentWorkflowId?: string;
47
+ public readonly eventTree: EventTreeHandle;
48
+ public readonly reflection: ReflectionAPI;
49
+
50
+ private workflow: WorkflowLike;
51
+ private eventTreeImpl: EventTreeHandleImpl;
52
+ private reflectionManager: ReflectionManager;
53
+
54
+ constructor(
55
+ workflow: WorkflowLike,
56
+ parentWorkflowId?: string,
57
+ reflectionConfig?: Partial<ReflectionConfig>
58
+ ) {
59
+ this.workflowId = workflow.id;
60
+ this.parentWorkflowId = parentWorkflowId;
61
+ this.workflow = workflow;
62
+
63
+ // Create event tree handle
64
+ this.eventTreeImpl = new EventTreeHandleImpl(workflow.node);
65
+ this.eventTree = this.eventTreeImpl;
66
+
67
+ // Create reflection manager with config
68
+ const config = createReflectionConfig(reflectionConfig);
69
+ this.reflectionManager = new ReflectionManager(config);
70
+ this.reflectionManager.setEventEmitter((event) => this.workflow.emitEvent(event));
71
+ this.reflection = this.reflectionManager;
72
+ }
73
+
74
+ /**
75
+ * Execute a named step with automatic context propagation and reflection support
76
+ */
77
+ async step<T>(name: string, fn: () => Promise<T>): Promise<T> {
78
+ const maxAttempts = this.reflectionManager.isEnabled()
79
+ ? this.reflectionManager.getMaxAttempts()
80
+ : 1;
81
+
82
+ let lastError: Error | null = null;
83
+
84
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
85
+ const startTime = Date.now();
86
+
87
+ // Create step node
88
+ const stepNode: WorkflowNode = {
89
+ id: generateId(),
90
+ name: attempt > 1 ? `${name} (retry ${attempt - 1})` : name,
91
+ parent: this.workflow.node,
92
+ children: [],
93
+ status: 'running',
94
+ logs: [],
95
+ events: [],
96
+ stateSnapshot: null,
97
+ };
98
+
99
+ // Attach to parent
100
+ this.workflow.node.children.push(stepNode);
101
+
102
+ // Emit step start
103
+ this.workflow.emitEvent({
104
+ type: 'stepStart',
105
+ node: stepNode,
106
+ step: name,
107
+ });
108
+
109
+ // Create execution context for this step
110
+ const executionContext: AgentExecutionContext = {
111
+ workflowNode: stepNode,
112
+ emitEvent: (event: WorkflowEvent) => {
113
+ stepNode.events.push(event);
114
+ this.workflow.emitEvent(event);
115
+ },
116
+ workflowId: this.workflowId,
117
+ parentWorkflowId: this.parentWorkflowId,
118
+ };
119
+
120
+ try {
121
+ // Execute function in context
122
+ const result = await runInContext(executionContext, fn);
123
+
124
+ // Update step node status
125
+ stepNode.status = 'completed';
126
+
127
+ // Emit step end
128
+ const duration = Date.now() - startTime;
129
+ this.workflow.emitEvent({
130
+ type: 'stepEnd',
131
+ node: stepNode,
132
+ step: name,
133
+ duration,
134
+ });
135
+
136
+ // Rebuild event tree
137
+ this.eventTreeImpl.rebuild(this.workflow.node);
138
+
139
+ // If we succeeded after a reflection, mark it as successful
140
+ if (attempt > 1) {
141
+ this.reflectionManager.markLastReflectionSuccessful();
142
+ }
143
+
144
+ return result;
145
+ } catch (error) {
146
+ lastError = error as Error;
147
+
148
+ // Update step node status
149
+ stepNode.status = 'failed';
150
+
151
+ // Emit error event
152
+ this.workflow.emitEvent({
153
+ type: 'error',
154
+ node: stepNode,
155
+ error: {
156
+ message: error instanceof Error ? error.message : 'Unknown error',
157
+ original: error,
158
+ workflowId: this.workflowId,
159
+ stack: error instanceof Error ? error.stack : undefined,
160
+ state: {},
161
+ logs: [],
162
+ },
163
+ });
164
+
165
+ // Rebuild event tree
166
+ this.eventTreeImpl.rebuild(this.workflow.node);
167
+
168
+ // Check if we should try reflection
169
+ if (!this.reflectionManager.isEnabled() || attempt === maxAttempts) {
170
+ throw error;
171
+ }
172
+
173
+ // Try reflection
174
+ const reflectionContext: ReflectionContext = {
175
+ level: 'workflow',
176
+ failedNode: stepNode,
177
+ error: lastError,
178
+ attemptNumber: attempt,
179
+ previousAttempts: this.reflectionManager.getReflectionHistory(),
180
+ };
181
+
182
+ const reflectionResult = await this.reflectionManager.reflect(reflectionContext);
183
+
184
+ if (!reflectionResult.shouldRetry) {
185
+ throw lastError;
186
+ }
187
+
188
+ // Continue to next iteration for retry
189
+ }
190
+ }
191
+
192
+ throw lastError ?? new Error('Max reflection attempts exceeded');
193
+ }
194
+
195
+ /**
196
+ * Spawn a child workflow
197
+ */
198
+ async spawnWorkflow<T>(workflow: { run(): Promise<T>; id?: string; node?: WorkflowNode }): Promise<T> {
199
+ // If workflow has attachChild-like capability, use it
200
+ if ('node' in workflow && workflow.node) {
201
+ // Set parent reference
202
+ workflow.node.parent = this.workflow.node;
203
+
204
+ // Attach child node
205
+ this.workflow.node.children.push(workflow.node);
206
+
207
+ // Emit child attached event
208
+ this.workflow.emitEvent({
209
+ type: 'childAttached',
210
+ parentId: this.workflowId,
211
+ child: workflow.node,
212
+ });
213
+ }
214
+
215
+ // Run the child workflow
216
+ const result = await workflow.run();
217
+
218
+ // Rebuild event tree
219
+ this.eventTreeImpl.rebuild(this.workflow.node);
220
+
221
+ return result;
222
+ }
223
+
224
+ /**
225
+ * Replace the last prompt result with a new one (context revision)
226
+ * The previous prompt node is marked as 'revised' and the new result is attached as sibling
227
+ */
228
+ async replaceLastPromptResult<T>(
229
+ newPrompt: PromptLike<T>,
230
+ agent: AgentLike
231
+ ): Promise<T> {
232
+ // Find the last completed prompt node in the tree
233
+ const children = this.workflow.node.children;
234
+ let lastPromptNodeIndex = -1;
235
+
236
+ for (let i = children.length - 1; i >= 0; i--) {
237
+ const child = children[i];
238
+ if (child.status === 'completed') {
239
+ lastPromptNodeIndex = i;
240
+ break;
241
+ }
242
+ }
243
+
244
+ // Create a revision node to mark the replacement
245
+ const revisionNode: WorkflowNode = {
246
+ id: generateId(),
247
+ name: `revision:${newPrompt.id}`,
248
+ parent: this.workflow.node,
249
+ children: [],
250
+ status: 'running',
251
+ logs: [],
252
+ events: [],
253
+ stateSnapshot: null,
254
+ };
255
+
256
+ // If we found a previous node, mark it as revised
257
+ if (lastPromptNodeIndex >= 0) {
258
+ const previousNode = children[lastPromptNodeIndex];
259
+ // Mark as revised by adding a special status flag in logs
260
+ previousNode.logs.push({
261
+ id: generateId(),
262
+ workflowId: this.workflowId,
263
+ level: 'info',
264
+ message: `Revised by ${revisionNode.id}`,
265
+ timestamp: Date.now(),
266
+ });
267
+ }
268
+
269
+ // Attach revision node as sibling (at same level)
270
+ this.workflow.node.children.push(revisionNode);
271
+
272
+ // Emit prompt revision event
273
+ this.workflow.emitEvent({
274
+ type: 'stepStart',
275
+ node: revisionNode,
276
+ step: `revision:${newPrompt.id}`,
277
+ });
278
+
279
+ // Create execution context for this revision
280
+ const executionContext: AgentExecutionContext = {
281
+ workflowNode: revisionNode,
282
+ emitEvent: (event: WorkflowEvent) => {
283
+ revisionNode.events.push(event);
284
+ this.workflow.emitEvent(event);
285
+ },
286
+ workflowId: this.workflowId,
287
+ parentWorkflowId: this.parentWorkflowId,
288
+ };
289
+
290
+ try {
291
+ // Execute the new prompt in context
292
+ const result = await runInContext(executionContext, () =>
293
+ agent.prompt(newPrompt)
294
+ );
295
+
296
+ // Update revision node status
297
+ revisionNode.status = 'completed';
298
+
299
+ // Emit completion event
300
+ this.workflow.emitEvent({
301
+ type: 'stepEnd',
302
+ node: revisionNode,
303
+ step: `revision:${newPrompt.id}`,
304
+ duration: 0, // Could track actual duration if needed
305
+ });
306
+
307
+ // Rebuild event tree
308
+ this.eventTreeImpl.rebuild(this.workflow.node);
309
+
310
+ return result;
311
+ } catch (error) {
312
+ // Update revision node status
313
+ revisionNode.status = 'failed';
314
+
315
+ // Emit error event
316
+ this.workflow.emitEvent({
317
+ type: 'error',
318
+ node: revisionNode,
319
+ error: {
320
+ message: error instanceof Error ? error.message : 'Unknown error',
321
+ original: error,
322
+ workflowId: this.workflowId,
323
+ stack: error instanceof Error ? error.stack : undefined,
324
+ state: {},
325
+ logs: [],
326
+ },
327
+ });
328
+
329
+ // Rebuild event tree
330
+ this.eventTreeImpl.rebuild(this.workflow.node);
331
+
332
+ throw error;
333
+ }
334
+ }
335
+ }
336
+
337
+ /**
338
+ * Create a WorkflowContext for a workflow
339
+ * @param workflow The workflow object
340
+ * @param parentWorkflowId Optional parent workflow ID
341
+ * @param reflectionConfig Optional reflection configuration
342
+ */
343
+ export function createWorkflowContext(
344
+ workflow: WorkflowLike,
345
+ parentWorkflowId?: string,
346
+ reflectionConfig?: Partial<ReflectionConfig>
347
+ ): WorkflowContext {
348
+ return new WorkflowContextImpl(workflow, parentWorkflowId, reflectionConfig);
349
+ }