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,1388 @@
1
+ # PRP: Caching, Reflection & Introspection Systems
2
+
3
+ ## Phases 3 & 4 Implementation Plan
4
+
5
+ > **PRP**: Product Requirements Package - A comprehensive implementation guide enabling one-pass success
6
+
7
+ ---
8
+
9
+ ## Pre-Implementation Checklist
10
+
11
+ Before implementing, verify you have:
12
+ - [ ] Read and understood this entire PRP
13
+ - [ ] Read PRPs/PRDs/002-agent-prompt.md (main PRD - Sections 9, 10, 11, 12)
14
+ - [ ] Verified Phase 1 & 2 are complete (Agent, Prompt, Hierarchy integration)
15
+ - [ ] Access to `./` codebase
16
+ - [ ] npm dependencies installed: `@anthropic-ai/sdk`, `zod`
17
+ - [ ] Understanding of existing patterns in `/src/core/agent.ts`, `/src/core/workflow.ts`
18
+
19
+ ---
20
+
21
+ ## 1. Goal
22
+
23
+ ### Feature Goal
24
+ Implement deterministic response caching, multi-level reflection capabilities, and agent introspection tools to complete the Groundswell orchestration framework per PRD Sections 9, 10, 11, and 12.
25
+
26
+ ### Deliverable
27
+ A complete system where:
28
+ 1. LLM responses are cached with SHA-256 deterministic keys (PRD Section 9)
29
+ 2. Reflection API provides automatic retry with self-correction at workflow, agent, and prompt levels (PRD Section 4.4)
30
+ 3. Introspection tools allow agents to inspect/manipulate their hierarchy position (PRD Section 11)
31
+ 4. Dynamic workflow/agent/prompt creation and context revision work seamlessly (PRD Section 10)
32
+ 5. Examples 7-10 are implemented (PRD Section 12)
33
+
34
+ ### Success Definition
35
+ - [ ] `npm run build` passes with no TypeScript errors
36
+ - [ ] `npm test` passes all new and existing tests
37
+ - [ ] Cache integration reduces redundant API calls in tests
38
+ - [ ] Reflection triggers automatically on step/prompt failures
39
+ - [ ] Agents can use introspection tools to navigate hierarchy
40
+ - [ ] Examples 7-10 execute successfully
41
+
42
+ ---
43
+
44
+ ## 2. Context
45
+
46
+ ### External Documentation
47
+ ```yaml
48
+ anthropic_sdk:
49
+ url: "https://github.com/anthropics/anthropic-sdk-typescript"
50
+ purpose: "Tool definitions, message API, error types"
51
+ version: "^0.71.1"
52
+
53
+ lru_cache:
54
+ url: "https://www.npmjs.com/package/lru-cache"
55
+ purpose: "LRU cache implementation with TTL and size limits"
56
+ version: "^10.0.0"
57
+ key_sections:
58
+ - "Options" - maxSize, ttl, sizeCalculation
59
+ - "Methods" - get, set, delete, has
60
+ note: "Zero external dependencies in v10+"
61
+
62
+ node_crypto:
63
+ url: "https://nodejs.org/api/crypto.html#cryptocreatehashalgorithm-options"
64
+ purpose: "SHA-256 hashing for cache keys"
65
+ section: "crypto.createHash()"
66
+
67
+ zod:
68
+ url: "https://zod.dev/"
69
+ purpose: "Schema validation, _def access for hashing"
70
+ version: "^3.23.0"
71
+ key_section: "https://zod.dev/?id=zodtype-with-zodeffects"
72
+ ```
73
+
74
+ ### Codebase Context
75
+ ```yaml
76
+ existing_patterns:
77
+ - file: "/src/core/agent.ts"
78
+ pattern: "Agent class with executePrompt() method"
79
+ follow_for: "Cache integration point"
80
+ key_lines:
81
+ - line: 171
82
+ purpose: "Start of executePrompt() - insert cache check here"
83
+ - line: 239
84
+ purpose: "After API call success - insert cache set here"
85
+ - line: 126-149
86
+ purpose: "reflect() method - upgrade to full reflection loop"
87
+
88
+ - file: "/src/core/workflow-context.ts"
89
+ pattern: "ReflectionAPIImpl placeholder class"
90
+ follow_for: "Full ReflectionAPI implementation"
91
+ key_lines:
92
+ - line: 24-42
93
+ purpose: "Placeholder implementation to replace"
94
+ - line: 83-162
95
+ purpose: "step() method - wrap with reflection retry"
96
+
97
+ - file: "/src/core/context.ts"
98
+ pattern: "AgentExecutionContext with AsyncLocalStorage"
99
+ follow_for: "Introspection tool handlers accessing context"
100
+ key_lines:
101
+ - line: 1-120
102
+ purpose: "Context propagation pattern to follow"
103
+
104
+ - file: "/src/types/events.ts"
105
+ pattern: "WorkflowEvent discriminated union"
106
+ follow_for: "Already includes reflectionStart/reflectionEnd types"
107
+ key_lines:
108
+ - line: 52-63
109
+ purpose: "Reflection events already defined"
110
+
111
+ - file: "/src/types/agent.ts"
112
+ pattern: "AgentConfig with enableCache/enableReflection flags"
113
+ follow_for: "Flags defined but not yet used in implementation"
114
+ key_lines:
115
+ - line: 35
116
+ purpose: "enableReflection?: boolean"
117
+ - line: 38
118
+ purpose: "enableCache?: boolean"
119
+
120
+ related_files:
121
+ - path: "/src/types/workflow-context.ts"
122
+ relationship: "ReflectionAPI interface definition (line 70-80)"
123
+ note: "Interface is minimal - needs extension"
124
+
125
+ - path: "/src/core/event-tree.ts"
126
+ relationship: "EventTreeHandle for introspection queries"
127
+
128
+ - path: "/src/utils/id.ts"
129
+ relationship: "generateId() for unique identifiers"
130
+
131
+ - path: "/src/__tests__/unit/agent.test.ts"
132
+ relationship: "Test patterns to follow"
133
+
134
+ - path: "/src/__tests__/integration/agent-workflow.test.ts"
135
+ relationship: "Integration test patterns"
136
+
137
+ naming_conventions:
138
+ files: "kebab-case.ts in appropriate directory"
139
+ classes: "PascalCase (e.g., LLMCache, ReflectionManager)"
140
+ functions: "camelCase (e.g., generateCacheKey, triggerReflection)"
141
+ types: "PascalCase with descriptive suffixes (e.g., CacheConfig, ReflectionEntry)"
142
+ tools: "snake_case for Anthropic tool names (e.g., inspect_current_node)"
143
+ test_files: "*.test.ts in /src/__tests__/unit/ or /src/__tests__/integration/"
144
+ ```
145
+
146
+ ### Technical Constraints
147
+ ```yaml
148
+ typescript:
149
+ version: "5.2+"
150
+ config_requirements:
151
+ - "strict: true"
152
+ - "module: NodeNext"
153
+ - "moduleResolution: NodeNext"
154
+
155
+ dependencies:
156
+ required_new:
157
+ - name: "lru-cache"
158
+ version: "^10.0.0"
159
+ purpose: "LRU cache with size/TTL limits"
160
+ existing:
161
+ - name: "@anthropic-ai/sdk"
162
+ version: "^0.71.1"
163
+ - name: "zod"
164
+ version: "^3.23.0"
165
+
166
+ runtime:
167
+ node_version: "18+"
168
+ target: "ES2022"
169
+
170
+ testing:
171
+ framework: "vitest"
172
+ config: "/vitest.config.ts"
173
+ patterns:
174
+ - "Use describe/it/expect from vitest"
175
+ - "Mock external services (Anthropic API)"
176
+ - "Use runInContext() for context tests"
177
+ ```
178
+
179
+ ### Known Gotchas
180
+ ```yaml
181
+ pitfalls:
182
+ - issue: "JSON.stringify does not guarantee key order"
183
+ solution: "Use deterministicStringify with sorted keys for cache key generation"
184
+ reference: "/plan/P3P4/research/caching-lru.md"
185
+ code_pattern: |
186
+ const keys = Object.keys(obj).sort();
187
+ const pairs = keys.map(k => JSON.stringify(k) + ':' + stringify(obj[k]));
188
+ return '{' + pairs.join(',') + '}';
189
+
190
+ - issue: "Zod schemas are functions, cannot serialize directly"
191
+ solution: "Hash schema._def for schema fingerprint in cache key"
192
+ code_pattern: |
193
+ function getSchemaHash(schema: z.ZodType): string {
194
+ const defString = JSON.stringify(schema._def);
195
+ return createHash('sha256').update(defString).digest('hex').slice(0, 16);
196
+ }
197
+
198
+ - issue: "Reflection can infinite loop"
199
+ solution: "Hard limit maxReflectionAttempts to 3, track attempt count"
200
+ reference: "/plan/P1P2/research/reflection-patterns.md"
201
+
202
+ - issue: "AsyncLocalStorage context loss in some async patterns"
203
+ solution: "Always use runInContext() wrapper from /src/core/context.ts"
204
+ test: "Test with nested async/await to verify propagation"
205
+
206
+ - issue: "Tool handlers need access to current context"
207
+ solution: "Use getExecutionContext() from context.ts inside tool handlers"
208
+ code_pattern: |
209
+ const ctx = getExecutionContext();
210
+ if (!ctx) throw new Error('Not in workflow context');
211
+
212
+ - issue: "When NOT to reflect (will waste tokens)"
213
+ solution: "Skip reflection for: rate limit errors, auth errors, quota exceeded"
214
+ reference: "/plan/P1P2/research/reflection-patterns.md lines 644-690"
215
+
216
+ - issue: "Circular references in cache key serialization"
217
+ solution: "Use WeakSet to track seen objects, throw TypeError if circular"
218
+ code_pattern: |
219
+ const seen = new WeakSet<object>();
220
+ if (seen.has(val)) throw new TypeError('Circular reference detected');
221
+ seen.add(val);
222
+ ```
223
+
224
+ ---
225
+
226
+ ## 3. Implementation Tasks
227
+
228
+ > Tasks are ordered by dependency. Complete each task fully before moving to the next.
229
+
230
+ ### Phase 3: Caching & Reflection Systems
231
+
232
+ ---
233
+
234
+ ### Task P3.1: Cache Key Generation
235
+ **Depends on**: Phase 1 & 2 complete (verified by existing agent.ts, prompt.ts)
236
+
237
+ **Input**:
238
+ - Prompt instance with user, data, responseFormat
239
+ - Merged AgentConfig (system, tools, mcps, skills, temperature, model)
240
+
241
+ **Steps**:
242
+ 1. Create `/src/cache/cache-key.ts`
243
+ 2. Implement `deterministicStringify(value: unknown): string`
244
+ - Sort object keys alphabetically using `Object.keys(obj).sort()`
245
+ - Handle arrays (preserve order), primitives, null, undefined
246
+ - Detect circular references with WeakSet, throw TypeError
247
+ - Return deterministic JSON string
248
+ 3. Implement `getSchemaHash(schema: z.ZodType): string`
249
+ - Access `schema._def` for internal representation
250
+ - Stringify and hash with SHA-256
251
+ - Return first 16 chars of hex digest (sufficient for uniqueness)
252
+ 4. Implement `generateCacheKey(inputs: CacheKeyInputs): string`
253
+ - Include: user, data, system, model, temperature, maxTokens
254
+ - Include: sorted tool names, sorted mcp names, sorted skill names
255
+ - Include: schemaHash from responseFormat
256
+ - Return 64-character hex SHA-256 digest
257
+ 5. Export `CacheKeyInputs` interface and all functions
258
+ 6. Create `/src/cache/index.ts` exporting all cache exports
259
+
260
+ **Output**: `/src/cache/cache-key.ts` with deterministic key generation
261
+
262
+ **Validation**:
263
+ ```bash
264
+ npm run build
265
+ npm test -- --grep "cache-key"
266
+ ```
267
+
268
+ **Code Pattern**:
269
+ ```typescript
270
+ // /src/cache/cache-key.ts
271
+ import { createHash } from 'node:crypto';
272
+ import type { z } from 'zod';
273
+ import type { Tool, MCPServer, Skill } from '../types/index.js';
274
+
275
+ export interface CacheKeyInputs {
276
+ user: string;
277
+ data?: Record<string, unknown>;
278
+ system?: string;
279
+ model: string;
280
+ temperature?: number;
281
+ maxTokens?: number;
282
+ tools?: Tool[];
283
+ mcps?: MCPServer[];
284
+ skills?: Skill[];
285
+ responseFormat: z.ZodType;
286
+ }
287
+
288
+ export function deterministicStringify(value: unknown): string {
289
+ const seen = new WeakSet<object>();
290
+
291
+ function stringify(val: unknown): string {
292
+ if (val === null) return 'null';
293
+ if (typeof val === 'string') return JSON.stringify(val);
294
+ if (typeof val === 'number' || typeof val === 'boolean') return String(val);
295
+ if (typeof val === 'undefined') return 'undefined';
296
+
297
+ if (typeof val === 'object') {
298
+ if (seen.has(val as object)) {
299
+ throw new TypeError('Converting circular structure');
300
+ }
301
+ seen.add(val as object);
302
+
303
+ let result: string;
304
+ if (Array.isArray(val)) {
305
+ result = '[' + val.map(stringify).join(',') + ']';
306
+ } else {
307
+ const keys = Object.keys(val as Record<string, unknown>).sort();
308
+ const pairs = keys.map(k =>
309
+ JSON.stringify(k) + ':' + stringify((val as Record<string, unknown>)[k])
310
+ );
311
+ result = '{' + pairs.join(',') + '}';
312
+ }
313
+
314
+ seen.delete(val as object);
315
+ return result;
316
+ }
317
+
318
+ return String(val);
319
+ }
320
+
321
+ return stringify(value);
322
+ }
323
+
324
+ export function getSchemaHash(schema: z.ZodType): string {
325
+ const defString = deterministicStringify(schema._def);
326
+ return createHash('sha256').update(defString, 'utf8').digest('hex').slice(0, 16);
327
+ }
328
+
329
+ export function generateCacheKey(inputs: CacheKeyInputs): string {
330
+ const normalized = {
331
+ user: inputs.user,
332
+ data: inputs.data ?? null,
333
+ system: inputs.system ?? null,
334
+ model: inputs.model,
335
+ temperature: inputs.temperature ?? null,
336
+ maxTokens: inputs.maxTokens ?? null,
337
+ tools: inputs.tools?.map(t => t.name).sort() ?? [],
338
+ mcps: inputs.mcps?.map(m => m.name).sort() ?? [],
339
+ skills: inputs.skills?.map(s => s.name).sort() ?? [],
340
+ schemaHash: getSchemaHash(inputs.responseFormat),
341
+ };
342
+
343
+ const serialized = deterministicStringify(normalized);
344
+ return createHash('sha256').update(serialized, 'utf8').digest('hex');
345
+ }
346
+ ```
347
+
348
+ ---
349
+
350
+ ### Task P3.2: LRU Cache Implementation
351
+ **Depends on**: Task P3.1
352
+
353
+ **Input**: Cache interface from PRD Section 9.2
354
+
355
+ **Steps**:
356
+ 1. Add `lru-cache@^10.0.0` to package.json dependencies
357
+ 2. Run `npm install`
358
+ 3. Create `/src/cache/cache.ts`
359
+ 4. Define `CacheConfig` interface:
360
+ ```typescript
361
+ interface CacheConfig {
362
+ maxItems?: number; // default: 1000
363
+ maxSizeBytes?: number; // default: 50MB (52428800)
364
+ defaultTTLMs?: number; // default: 1 hour (3600000)
365
+ }
366
+ ```
367
+ 5. Define `CacheMetrics` interface for observability
368
+ 6. Implement `LLMCache` class:
369
+ - Constructor accepting optional CacheConfig
370
+ - `get<T>(key: string): T | undefined` - sync lookup
371
+ - `set<T>(key: string, value: T, ttl?: number): void` - sync store
372
+ - `bust(key: string): void` - remove single entry
373
+ - `bustPrefix(prefix: string): void` - remove all keys matching prefix
374
+ - `metrics(): CacheMetrics` - return hit/miss/size stats
375
+ 7. Implement prefix tracking with Map<string, Set<string>> for bustPrefix
376
+ 8. Export singleton `defaultCache` instance with default config
377
+ 9. Update `/src/cache/index.ts` with new exports
378
+
379
+ **Output**: `/src/cache/cache.ts` with full Cache implementation
380
+
381
+ **Validation**:
382
+ ```bash
383
+ npm install
384
+ npm run build
385
+ npm test -- --grep "LLMCache"
386
+ ```
387
+
388
+ **Code Pattern**:
389
+ ```typescript
390
+ // /src/cache/cache.ts
391
+ import { LRUCache } from 'lru-cache';
392
+
393
+ export interface CacheConfig {
394
+ maxItems?: number;
395
+ maxSizeBytes?: number;
396
+ defaultTTLMs?: number;
397
+ }
398
+
399
+ export interface CacheMetrics {
400
+ hits: number;
401
+ misses: number;
402
+ size: number;
403
+ maxSize: number;
404
+ itemCount: number;
405
+ }
406
+
407
+ export class LLMCache {
408
+ private cache: LRUCache<string, unknown>;
409
+ private hits = 0;
410
+ private misses = 0;
411
+ private prefixIndex = new Map<string, Set<string>>();
412
+ private config: Required<CacheConfig>;
413
+
414
+ constructor(config: CacheConfig = {}) {
415
+ this.config = {
416
+ maxItems: config.maxItems ?? 1000,
417
+ maxSizeBytes: config.maxSizeBytes ?? 52428800, // 50MB
418
+ defaultTTLMs: config.defaultTTLMs ?? 3600000, // 1 hour
419
+ };
420
+
421
+ this.cache = new LRUCache<string, unknown>({
422
+ max: this.config.maxItems,
423
+ maxSize: this.config.maxSizeBytes,
424
+ ttl: this.config.defaultTTLMs,
425
+ sizeCalculation: (value) => {
426
+ return JSON.stringify(value).length;
427
+ },
428
+ updateAgeOnGet: true,
429
+ });
430
+ }
431
+
432
+ get<T>(key: string): T | undefined {
433
+ const value = this.cache.get(key) as T | undefined;
434
+ if (value !== undefined) {
435
+ this.hits++;
436
+ } else {
437
+ this.misses++;
438
+ }
439
+ return value;
440
+ }
441
+
442
+ set<T>(key: string, value: T, ttl?: number): void {
443
+ this.cache.set(key, value, { ttl: ttl ?? this.config.defaultTTLMs });
444
+
445
+ // Track prefix (first 8 chars) for bustPrefix
446
+ const prefix = key.slice(0, 8);
447
+ if (!this.prefixIndex.has(prefix)) {
448
+ this.prefixIndex.set(prefix, new Set());
449
+ }
450
+ this.prefixIndex.get(prefix)!.add(key);
451
+ }
452
+
453
+ bust(key: string): void {
454
+ this.cache.delete(key);
455
+ // Clean up prefix index
456
+ const prefix = key.slice(0, 8);
457
+ this.prefixIndex.get(prefix)?.delete(key);
458
+ }
459
+
460
+ bustPrefix(prefix: string): void {
461
+ const keys = this.prefixIndex.get(prefix);
462
+ if (keys) {
463
+ for (const key of keys) {
464
+ this.cache.delete(key);
465
+ }
466
+ this.prefixIndex.delete(prefix);
467
+ }
468
+ }
469
+
470
+ metrics(): CacheMetrics {
471
+ return {
472
+ hits: this.hits,
473
+ misses: this.misses,
474
+ size: this.cache.calculatedSize ?? 0,
475
+ maxSize: this.config.maxSizeBytes,
476
+ itemCount: this.cache.size,
477
+ };
478
+ }
479
+
480
+ clear(): void {
481
+ this.cache.clear();
482
+ this.prefixIndex.clear();
483
+ this.hits = 0;
484
+ this.misses = 0;
485
+ }
486
+ }
487
+
488
+ export const defaultCache = new LLMCache();
489
+ ```
490
+
491
+ ---
492
+
493
+ ### Task P3.3: Cache Integration into Agent
494
+ **Depends on**: Task P3.2
495
+
496
+ **Input**: Agent.executePrompt() method at `/src/core/agent.ts:171`
497
+
498
+ **Steps**:
499
+ 1. Import `generateCacheKey` and `defaultCache` in agent.ts
500
+ 2. Add cache check at start of `executePrompt()` (after line 175):
501
+ ```typescript
502
+ if (this.config.enableCache && !overrides?.disableCache) {
503
+ const cacheKey = generateCacheKey({
504
+ user: prompt.user,
505
+ data: prompt.data,
506
+ system: effectiveSystem,
507
+ model: effectiveModel,
508
+ temperature: effectiveTemperature,
509
+ maxTokens: effectiveMaxTokens,
510
+ tools: effectiveTools,
511
+ responseFormat: prompt.responseFormat,
512
+ });
513
+ const cached = defaultCache.get<PromptResult<T>>(cacheKey);
514
+ if (cached) {
515
+ // Emit cache hit event if in workflow context
516
+ if (ctx) {
517
+ this.emitWorkflowEvent({ type: 'cacheHit', key: cacheKey, node: ctx.workflowNode });
518
+ }
519
+ return cached;
520
+ }
521
+ }
522
+ ```
523
+ 3. Add cache set after successful response (around line 355):
524
+ ```typescript
525
+ if (this.config.enableCache && !overrides?.disableCache) {
526
+ defaultCache.set(cacheKey, result);
527
+ }
528
+ ```
529
+ 4. Update `/src/types/events.ts` to add cacheHit/cacheMiss event types:
530
+ ```typescript
531
+ | { type: 'cacheHit'; key: string; node: WorkflowNode }
532
+ | { type: 'cacheMiss'; key: string; node: WorkflowNode }
533
+ ```
534
+ 5. Emit cache miss event when cache check fails
535
+
536
+ **Output**: Agent.prompt() checks and populates cache
537
+
538
+ **Validation**:
539
+ ```bash
540
+ npm run build
541
+ npm test -- --grep "agent-cache"
542
+ ```
543
+
544
+ ---
545
+
546
+ ### Task P3.4: ReflectionAPI Type Definitions
547
+ **Depends on**: Phase 2 complete
548
+
549
+ **Input**: Placeholder at `/src/types/workflow-context.ts:70`
550
+
551
+ **Steps**:
552
+ 1. Create `/src/types/reflection.ts`
553
+ 2. Define complete interfaces:
554
+ ```typescript
555
+ export interface ReflectionConfig {
556
+ enabled: boolean;
557
+ maxAttempts: number; // default: 3
558
+ retryDelayMs?: number; // default: 0
559
+ }
560
+
561
+ export interface ReflectionContext {
562
+ level: 'workflow' | 'agent' | 'prompt';
563
+ failedNode: WorkflowNode;
564
+ error: Error;
565
+ attemptNumber: number;
566
+ previousAttempts: ReflectionEntry[];
567
+ }
568
+
569
+ export interface ReflectionResult {
570
+ shouldRetry: boolean;
571
+ revisedPromptData?: Record<string, unknown>;
572
+ revisedSystemPrompt?: string;
573
+ reason: string;
574
+ }
575
+
576
+ export interface ReflectionEntry {
577
+ timestamp: number;
578
+ level: 'workflow' | 'agent' | 'prompt';
579
+ reason: string;
580
+ error: Error;
581
+ resolution: 'retry' | 'skip' | 'abort';
582
+ success: boolean;
583
+ }
584
+
585
+ export interface ReflectionAPI {
586
+ isEnabled(): boolean;
587
+ getMaxAttempts(): number;
588
+ triggerReflection(reason?: string): Promise<void>;
589
+ getReflectionHistory(): ReflectionEntry[];
590
+ reflect(context: ReflectionContext): Promise<ReflectionResult>;
591
+ recordAttempt(entry: ReflectionEntry): void;
592
+ }
593
+ ```
594
+ 3. Update `/src/types/workflow-context.ts` to import and use extended ReflectionAPI
595
+ 4. Export from `/src/types/index.ts`
596
+
597
+ **Output**: Complete reflection type definitions
598
+
599
+ **Validation**: `npm run build` passes
600
+
601
+ ---
602
+
603
+ ### Task P3.5: Reflection Implementation
604
+ **Depends on**: Task P3.4
605
+
606
+ **Input**: ReflectionAPI interface, Agent.reflect() method
607
+
608
+ **Steps**:
609
+ 1. Create `/src/reflection/reflection.ts`
610
+ 2. Implement `ReflectionManager` class:
611
+ - Constructor: `(config: ReflectionConfig, agent?: Agent)`
612
+ - `isEnabled()`: Return config.enabled
613
+ - `getMaxAttempts()`: Return config.maxAttempts
614
+ - `reflect(context: ReflectionContext): Promise<ReflectionResult>`
615
+ - Build reflection prompt with error context
616
+ - If agent provided, call agent for reflection analysis
617
+ - Parse response for shouldRetry decision
618
+ - Record entry in history
619
+ - `triggerReflection(reason?: string)`: Emit events, log
620
+ - `getReflectionHistory()`: Return recorded entries
621
+ - `recordAttempt(entry)`: Add to history
622
+ 3. Define reflection prompt template:
623
+ ```typescript
624
+ const REFLECTION_PROMPT = `
625
+ A previous operation failed with the following error:
626
+
627
+ Error: {{error.message}}
628
+ Level: {{level}}
629
+ Attempt: {{attemptNumber}} of {{maxAttempts}}
630
+
631
+ Previous attempts:
632
+ {{previousAttempts}}
633
+
634
+ Analyze the error and determine:
635
+ 1. Can this be retried with modifications?
636
+ 2. What changes would help succeed?
637
+ 3. What should NOT be repeated?
638
+
639
+ Respond with JSON: { "shouldRetry": boolean, "reason": string, "revisedPromptData": {...} }
640
+ `;
641
+ ```
642
+ 4. Emit reflectionStart/reflectionEnd events (types already exist in events.ts)
643
+ 5. Create `/src/reflection/index.ts` exporting all reflection exports
644
+
645
+ **Output**: `/src/reflection/reflection.ts` with full implementation
646
+
647
+ **Validation**:
648
+ ```bash
649
+ npm run build
650
+ npm test -- --grep "ReflectionManager"
651
+ ```
652
+
653
+ ---
654
+
655
+ ### Task P3.6: Wire Reflection into WorkflowContext
656
+ **Depends on**: Task P3.5
657
+
658
+ **Input**: `/src/core/workflow-context.ts`
659
+
660
+ **Steps**:
661
+ 1. Replace `ReflectionAPIImpl` placeholder with real import from `/src/reflection/reflection.ts`
662
+ 2. Update `WorkflowContextImpl` constructor:
663
+ - Create `ReflectionManager` with workflow's enableReflection config
664
+ 3. Update `step()` method to wrap with reflection:
665
+ ```typescript
666
+ async step<T>(name: string, fn: () => Promise<T>): Promise<T> {
667
+ let lastError: Error | null = null;
668
+
669
+ for (let attempt = 1; attempt <= this.reflection.getMaxAttempts(); attempt++) {
670
+ try {
671
+ return await this.executeStep(name, fn, attempt);
672
+ } catch (error) {
673
+ lastError = error as Error;
674
+
675
+ if (!this.reflection.isEnabled()) throw error;
676
+ if (this.shouldSkipReflection(error)) throw error;
677
+ if (attempt >= this.reflection.getMaxAttempts()) throw error;
678
+
679
+ const result = await this.reflection.reflect({
680
+ level: 'workflow',
681
+ failedNode: stepNode,
682
+ error: lastError,
683
+ attemptNumber: attempt,
684
+ previousAttempts: this.reflection.getReflectionHistory()
685
+ });
686
+
687
+ if (!result.shouldRetry) throw error;
688
+
689
+ // Continue to next iteration with reflection context
690
+ }
691
+ }
692
+
693
+ throw lastError;
694
+ }
695
+
696
+ private shouldSkipReflection(error: Error): boolean {
697
+ const message = error.message.toLowerCase();
698
+ // Skip reflection for errors that can't be self-corrected
699
+ return message.includes('rate limit') ||
700
+ message.includes('authentication') ||
701
+ message.includes('quota exceeded') ||
702
+ message.includes('unauthorized');
703
+ }
704
+ ```
705
+
706
+ **Output**: Automatic reflection on step failures
707
+
708
+ **Validation**:
709
+ ```bash
710
+ npm run build
711
+ npm test -- --grep "workflow-reflection"
712
+ ```
713
+
714
+ ---
715
+
716
+ ### Phase 4: Dynamic Behavior & Introspection
717
+
718
+ ---
719
+
720
+ ### Task P4.1: Dynamic Factory Functions
721
+ **Depends on**: Phase 3 complete
722
+
723
+ **Input**: Workflow, Agent, Prompt classes
724
+
725
+ **Steps**:
726
+ 1. Create `/src/core/factory.ts`
727
+ 2. Implement factory functions:
728
+ ```typescript
729
+ import { Workflow, type WorkflowExecutor } from './workflow.js';
730
+ import { Agent } from './agent.js';
731
+ import { Prompt } from './prompt.js';
732
+ import type { WorkflowConfig, AgentConfig, PromptConfig } from '../types/index.js';
733
+
734
+ export function createWorkflow<T>(
735
+ config: WorkflowConfig,
736
+ executor: WorkflowExecutor<T>
737
+ ): Workflow<T> {
738
+ return new Workflow(config, executor);
739
+ }
740
+
741
+ export function createAgent(config: AgentConfig): Agent {
742
+ return new Agent(config);
743
+ }
744
+
745
+ export function createPrompt<T>(config: PromptConfig<T>): Prompt<T> {
746
+ return new Prompt(config);
747
+ }
748
+ ```
749
+ 3. Export from `/src/core/index.ts` and `/src/index.ts`
750
+
751
+ **Output**: Convenience factory functions for dynamic creation
752
+
753
+ **Validation**: `npm run build`
754
+
755
+ ---
756
+
757
+ ### Task P4.2: Dynamic Context Revision
758
+ **Depends on**: Task P4.1
759
+
760
+ **Input**: WorkflowContext, step() implementation
761
+
762
+ **Steps**:
763
+ 1. Add to WorkflowContext interface in `/src/types/workflow-context.ts`:
764
+ ```typescript
765
+ replaceLastPromptResult<T>(
766
+ newPrompt: Prompt<T>,
767
+ agent: Agent
768
+ ): Promise<T>;
769
+ ```
770
+ 2. Implement in `WorkflowContextImpl`:
771
+ - Mark previous prompt node as 'revised'
772
+ - Execute new prompt
773
+ - Attach result as sibling (not child)
774
+ - Update event tree
775
+ - Return new result
776
+ 3. Emit 'promptRevision' event (add to events.ts if needed)
777
+
778
+ **Output**: Context revision without tree forking
779
+
780
+ **Validation**:
781
+ ```bash
782
+ npm run build
783
+ npm test -- --grep "context-revision"
784
+ ```
785
+
786
+ ---
787
+
788
+ ### Task P4.3: Introspection Tool Definitions
789
+ **Depends on**: P4.1
790
+
791
+ **Input**: PRD Section 11, `/plan/P3P4/research/introspection-tools.md`
792
+
793
+ **Steps**:
794
+ 1. Create `/src/tools/introspection.ts`
795
+ 2. Define 6 tool interfaces using Anthropic Tool format:
796
+ - `inspect_current_node`: Return current node info (id, name, status, parent, childCount, depth)
797
+ - `read_ancestor_chain`: Return ancestors up to root with optional maxDepth
798
+ - `list_siblings_children`: Return siblings or children based on 'type' parameter
799
+ - `inspect_prior_outputs`: Return previous step outputs with optional nodeId/count
800
+ - `inspect_cache_status`: Check cache for prompt hash
801
+ - `request_spawn_workflow`: Request dynamic workflow creation
802
+ 3. For each tool, define:
803
+ - Tool definition (name, description, input_schema following Anthropic format)
804
+ - Handler function signature
805
+ 4. Create `/src/tools/index.ts` exporting all tools
806
+
807
+ **Output**: Tool definitions in `/src/tools/introspection.ts`
808
+
809
+ **Validation**: TypeScript compiles
810
+
811
+ **Code Pattern**:
812
+ ```typescript
813
+ // /src/tools/introspection.ts
814
+ import type { Tool } from '../types/index.js';
815
+ import type { WorkflowNode } from '../types/workflow.js';
816
+ import { getExecutionContext } from '../core/context.js';
817
+
818
+ // Tool Definitions
819
+ export const inspectCurrentNodeTool: Tool = {
820
+ name: 'inspect_current_node',
821
+ description: 'Get information about the current workflow node including ID, name, status, and parent reference',
822
+ input_schema: {
823
+ type: 'object',
824
+ properties: {},
825
+ required: []
826
+ }
827
+ };
828
+
829
+ export const readAncestorChainTool: Tool = {
830
+ name: 'read_ancestor_chain',
831
+ description: 'Get all ancestor nodes from current position up to the root workflow',
832
+ input_schema: {
833
+ type: 'object',
834
+ properties: {
835
+ maxDepth: {
836
+ type: 'number',
837
+ description: 'Maximum ancestors to return (default: all)'
838
+ }
839
+ },
840
+ required: []
841
+ }
842
+ };
843
+
844
+ export const listSiblingsChildrenTool: Tool = {
845
+ name: 'list_siblings_children',
846
+ description: 'List sibling or child nodes relative to current position',
847
+ input_schema: {
848
+ type: 'object',
849
+ properties: {
850
+ type: {
851
+ type: 'string',
852
+ enum: ['siblings', 'children'],
853
+ description: 'Type of nodes to list'
854
+ }
855
+ },
856
+ required: ['type']
857
+ }
858
+ };
859
+
860
+ export const inspectPriorOutputsTool: Tool = {
861
+ name: 'inspect_prior_outputs',
862
+ description: 'Get outputs from prior steps or prompt executions',
863
+ input_schema: {
864
+ type: 'object',
865
+ properties: {
866
+ nodeId: { type: 'string', description: 'Specific node ID to inspect' },
867
+ count: { type: 'number', description: 'Number of prior outputs (default: 1)' }
868
+ },
869
+ required: []
870
+ }
871
+ };
872
+
873
+ export const inspectCacheStatusTool: Tool = {
874
+ name: 'inspect_cache_status',
875
+ description: 'Check if a prompt response is cached',
876
+ input_schema: {
877
+ type: 'object',
878
+ properties: {
879
+ promptHash: { type: 'string', description: 'Hash of the prompt to check' }
880
+ },
881
+ required: ['promptHash']
882
+ }
883
+ };
884
+
885
+ export const requestSpawnWorkflowTool: Tool = {
886
+ name: 'request_spawn_workflow',
887
+ description: 'Request to spawn a new child workflow dynamically',
888
+ input_schema: {
889
+ type: 'object',
890
+ properties: {
891
+ name: { type: 'string', description: 'Name for the new workflow' },
892
+ description: { type: 'string', description: 'What the workflow should do' }
893
+ },
894
+ required: ['name', 'description']
895
+ }
896
+ };
897
+
898
+ // Bundle export
899
+ export const INTROSPECTION_TOOLS: Tool[] = [
900
+ inspectCurrentNodeTool,
901
+ readAncestorChainTool,
902
+ listSiblingsChildrenTool,
903
+ inspectPriorOutputsTool,
904
+ inspectCacheStatusTool,
905
+ requestSpawnWorkflowTool
906
+ ];
907
+ ```
908
+
909
+ ---
910
+
911
+ ### Task P4.4: Introspection Tool Handlers
912
+ **Depends on**: Task P4.3
913
+
914
+ **Input**: Tool definitions, AgentExecutionContext
915
+
916
+ **Steps**:
917
+ 1. Implement handler for `inspect_current_node`:
918
+ ```typescript
919
+ export interface CurrentNodeInfo {
920
+ id: string;
921
+ name: string;
922
+ status: string;
923
+ parentId?: string;
924
+ parentName?: string;
925
+ childCount: number;
926
+ depth: number;
927
+ }
928
+
929
+ export async function handleInspectCurrentNode(): Promise<CurrentNodeInfo> {
930
+ const ctx = getExecutionContext();
931
+ if (!ctx) throw new Error('Not in workflow context');
932
+
933
+ const node = ctx.workflowNode;
934
+ return {
935
+ id: node.id,
936
+ name: node.name,
937
+ status: node.status,
938
+ parentId: node.parent?.id,
939
+ parentName: node.parent?.name,
940
+ childCount: node.children.length,
941
+ depth: calculateDepth(node)
942
+ };
943
+ }
944
+
945
+ function calculateDepth(node: WorkflowNode): number {
946
+ let depth = 0;
947
+ let current = node.parent;
948
+ while (current) {
949
+ depth++;
950
+ current = current.parent;
951
+ }
952
+ return depth;
953
+ }
954
+ ```
955
+ 2. Implement remaining handlers similarly (read_ancestor_chain, list_siblings_children, etc.)
956
+ 3. Create tool executor registry mapping tool names to handlers
957
+ 4. Export `registerIntrospectionHandlers(mcpHandler: MCPHandler)` function
958
+
959
+ **Output**: Working introspection tool handlers
960
+
961
+ **Validation**:
962
+ ```bash
963
+ npm run build
964
+ npm test -- --grep "introspection-tools"
965
+ ```
966
+
967
+ ---
968
+
969
+ ### Task P4.5: Update Main Exports
970
+ **Depends on**: All prior tasks
971
+
972
+ **Input**: All new classes, types, tools
973
+
974
+ **Steps**:
975
+ 1. Update `/src/index.ts` with all new exports:
976
+ ```typescript
977
+ // Cache
978
+ export { LLMCache, defaultCache } from './cache/cache.js';
979
+ export { generateCacheKey, deterministicStringify, getSchemaHash } from './cache/cache-key.js';
980
+ export type { CacheConfig, CacheMetrics, CacheKeyInputs } from './cache/index.js';
981
+
982
+ // Reflection
983
+ export { ReflectionManager } from './reflection/reflection.js';
984
+ export type {
985
+ ReflectionAPI,
986
+ ReflectionConfig,
987
+ ReflectionContext,
988
+ ReflectionResult,
989
+ ReflectionEntry
990
+ } from './types/reflection.js';
991
+
992
+ // Introspection
993
+ export { INTROSPECTION_TOOLS, registerIntrospectionHandlers } from './tools/introspection.js';
994
+ export type { CurrentNodeInfo, AncestorInfo } from './tools/introspection.js';
995
+
996
+ // Factories
997
+ export { createWorkflow, createAgent, createPrompt } from './core/factory.js';
998
+ ```
999
+ 2. Update `/src/types/index.ts` with new type exports
1000
+
1001
+ **Output**: Complete public API
1002
+
1003
+ **Validation**:
1004
+ ```bash
1005
+ npm run build
1006
+ node -e "const g = require('./dist'); console.log(Object.keys(g).filter(k => k.includes('Cache') || k.includes('Reflection') || k.includes('INTROSPECTION')));"
1007
+ ```
1008
+
1009
+ ---
1010
+
1011
+ ### Phase 5: Examples
1012
+
1013
+ ---
1014
+
1015
+ ### Task P5.1: Example 7 - Agent Loops with Observability
1016
+ **Depends on**: All Phase 3-4 tasks
1017
+
1018
+ **Input**: PRD Section 12 item 7
1019
+
1020
+ **Steps**:
1021
+ 1. Create `/examples/examples/07-agent-loops.ts`
1022
+ 2. Implement:
1023
+ - Array of items to process
1024
+ - for loop with ctx.step() for each item
1025
+ - Multiple agents for different item types
1026
+ - Full event tree visualization
1027
+ - Timing metrics per step
1028
+
1029
+ **Output**: Working example with observability
1030
+
1031
+ ---
1032
+
1033
+ ### Task P5.2: Example 8 - SDK Features (Tools, MCPs, Hooks)
1034
+ **Depends on**: Task P5.1
1035
+
1036
+ **Input**: PRD Section 12 item 8
1037
+
1038
+ **Steps**:
1039
+ 1. Create `/examples/examples/08-sdk-features.ts`
1040
+ 2. Implement:
1041
+ - Custom tool definitions with handlers
1042
+ - MCP server configuration (inprocess)
1043
+ - Pre/Post tool hooks
1044
+ - Event capture demonstration
1045
+
1046
+ **Output**: Comprehensive SDK integration example
1047
+
1048
+ ---
1049
+
1050
+ ### Task P5.3: Example 9 - Multi-level Reflection
1051
+ **Depends on**: Task P5.2
1052
+
1053
+ **Input**: PRD Section 12 item 9
1054
+
1055
+ **Steps**:
1056
+ 1. Create `/examples/examples/09-reflection.ts`
1057
+ 2. Implement three scenarios:
1058
+ - Workflow-level: step fails, reflection retries
1059
+ - Agent-level: prompt fails validation, agent reflects
1060
+ - Prompt-level: enableReflection on specific prompt
1061
+ 3. Show reflection events in tree output
1062
+
1063
+ **Output**: Multi-level reflection demonstration
1064
+
1065
+ ---
1066
+
1067
+ ### Task P5.4: Example 10 - Introspection Tools Demo
1068
+ **Depends on**: Task P5.3
1069
+
1070
+ **Input**: PRD Section 12 item 10
1071
+
1072
+ **Steps**:
1073
+ 1. Create `/examples/examples/10-introspection.ts`
1074
+ 2. Implement:
1075
+ - Agent with all INTROSPECTION_TOOLS
1076
+ - Nested workflow structure
1077
+ - Prompt asking agent to describe its position
1078
+ - Agent using tools to explore hierarchy
1079
+
1080
+ **Output**: Agent self-awareness demonstration
1081
+
1082
+ ---
1083
+
1084
+ ## 4. Implementation Details
1085
+
1086
+ ### Code Patterns to Follow
1087
+
1088
+ ```typescript
1089
+ // Cache key generation pattern (deterministic)
1090
+ import { createHash } from 'node:crypto';
1091
+
1092
+ function generateCacheKey(inputs: CacheKeyInputs): string {
1093
+ const normalized = {
1094
+ user: inputs.user,
1095
+ data: inputs.data,
1096
+ system: inputs.system,
1097
+ model: inputs.model,
1098
+ temperature: inputs.temperature,
1099
+ maxTokens: inputs.maxTokens,
1100
+ tools: inputs.tools?.map(t => t.name).sort(),
1101
+ mcps: inputs.mcps?.map(m => m.name).sort(),
1102
+ skills: inputs.skills?.map(s => s.name).sort(),
1103
+ schemaHash: getSchemaHash(inputs.responseFormat)
1104
+ };
1105
+
1106
+ return createHash('sha256')
1107
+ .update(deterministicStringify(normalized))
1108
+ .digest('hex');
1109
+ }
1110
+ ```
1111
+
1112
+ ```typescript
1113
+ // Reflection retry pattern
1114
+ async function executeWithReflection<T>(
1115
+ fn: () => Promise<T>,
1116
+ reflection: ReflectionAPI,
1117
+ context: Partial<ReflectionContext>
1118
+ ): Promise<T> {
1119
+ const maxAttempts = reflection.getMaxAttempts();
1120
+
1121
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1122
+ try {
1123
+ return await fn();
1124
+ } catch (error) {
1125
+ if (!reflection.isEnabled() || attempt === maxAttempts) {
1126
+ throw error;
1127
+ }
1128
+
1129
+ const result = await reflection.reflect({
1130
+ ...context,
1131
+ error: error as Error,
1132
+ attemptNumber: attempt
1133
+ } as ReflectionContext);
1134
+
1135
+ if (!result.shouldRetry) {
1136
+ throw error;
1137
+ }
1138
+ // Continue to next attempt
1139
+ }
1140
+ }
1141
+
1142
+ throw new Error('Max reflection attempts exceeded');
1143
+ }
1144
+ ```
1145
+
1146
+ ### File Structure
1147
+ ```
1148
+ /src
1149
+ ├── cache/
1150
+ │ ├── cache.ts # LLMCache class
1151
+ │ ├── cache-key.ts # Key generation
1152
+ │ └── index.ts # Cache exports
1153
+ ├── reflection/
1154
+ │ ├── reflection.ts # ReflectionManager
1155
+ │ └── index.ts # Reflection exports
1156
+ ├── tools/
1157
+ │ ├── introspection.ts # Introspection tools + handlers
1158
+ │ └── index.ts # Tools exports
1159
+ ├── types/
1160
+ │ ├── reflection.ts # NEW: Reflection types
1161
+ │ └── ... (existing)
1162
+ └── ... (existing)
1163
+
1164
+ /examples/examples/
1165
+ ├── 07-agent-loops.ts # NEW
1166
+ ├── 08-sdk-features.ts # NEW
1167
+ ├── 09-reflection.ts # NEW
1168
+ └── 10-introspection.ts # NEW
1169
+ ```
1170
+
1171
+ ### Interface Definitions Summary
1172
+ ```typescript
1173
+ // Key new interfaces
1174
+
1175
+ interface CacheKeyInputs {
1176
+ user: string;
1177
+ data?: Record<string, unknown>;
1178
+ system?: string;
1179
+ model: string;
1180
+ temperature?: number;
1181
+ maxTokens?: number;
1182
+ tools?: Tool[];
1183
+ mcps?: MCPServer[];
1184
+ skills?: Skill[];
1185
+ responseFormat: z.ZodType;
1186
+ }
1187
+
1188
+ interface CacheConfig {
1189
+ maxItems?: number;
1190
+ maxSizeBytes?: number;
1191
+ defaultTTLMs?: number;
1192
+ }
1193
+
1194
+ interface ReflectionConfig {
1195
+ enabled: boolean;
1196
+ maxAttempts: number;
1197
+ retryDelayMs?: number;
1198
+ }
1199
+
1200
+ interface ReflectionAPI {
1201
+ isEnabled(): boolean;
1202
+ getMaxAttempts(): number;
1203
+ triggerReflection(reason?: string): Promise<void>;
1204
+ getReflectionHistory(): ReflectionEntry[];
1205
+ reflect(context: ReflectionContext): Promise<ReflectionResult>;
1206
+ recordAttempt(entry: ReflectionEntry): void;
1207
+ }
1208
+ ```
1209
+
1210
+ ---
1211
+
1212
+ ## 5. Testing Strategy
1213
+
1214
+ ### Unit Tests
1215
+ ```yaml
1216
+ test_files:
1217
+ - path: "/src/__tests__/unit/cache-key.test.ts"
1218
+ covers:
1219
+ - "deterministicStringify produces same output for same input"
1220
+ - "deterministicStringify sorts object keys"
1221
+ - "deterministicStringify detects circular references"
1222
+ - "getSchemaHash produces consistent hashes"
1223
+ - "generateCacheKey is deterministic"
1224
+ - "Different inputs produce different keys"
1225
+
1226
+ - path: "/src/__tests__/unit/cache.test.ts"
1227
+ covers:
1228
+ - "LLMCache get/set works correctly"
1229
+ - "LRU eviction works when maxItems exceeded"
1230
+ - "TTL expiration works"
1231
+ - "bustPrefix removes correct entries"
1232
+ - "Size limits enforced (maxSizeBytes)"
1233
+ - "metrics() returns accurate counts"
1234
+
1235
+ - path: "/src/__tests__/unit/reflection.test.ts"
1236
+ covers:
1237
+ - "ReflectionManager.isEnabled() returns config value"
1238
+ - "ReflectionManager.reflect() builds correct prompt"
1239
+ - "History is recorded correctly"
1240
+ - "maxAttempts is respected"
1241
+ - "shouldSkipReflection() filters appropriate errors"
1242
+
1243
+ - path: "/src/__tests__/unit/introspection-tools.test.ts"
1244
+ covers:
1245
+ - "Each tool definition has correct schema"
1246
+ - "Each tool handler returns expected format"
1247
+ - "Tools work within context"
1248
+ - "Tools fail gracefully outside context"
1249
+
1250
+ test_patterns:
1251
+ - "Use vitest describe/it/expect"
1252
+ - "Mock Agent for reflection tests"
1253
+ - "Use runInContext for introspection tests"
1254
+ - "Create mock WorkflowNode with createMockNode helper"
1255
+ ```
1256
+
1257
+ ### Integration Tests
1258
+ ```yaml
1259
+ scenarios:
1260
+ - name: "Cache integration with Agent"
1261
+ validates: "Second identical prompt returns cached response"
1262
+ file: "/src/__tests__/integration/agent-cache.test.ts"
1263
+ steps:
1264
+ - Create Agent with enableCache: true
1265
+ - Execute prompt
1266
+ - Execute same prompt again
1267
+ - Verify second call uses cache (check metrics)
1268
+
1269
+ - name: "Reflection in workflow step"
1270
+ validates: "Failed step triggers reflection, retry succeeds"
1271
+ file: "/src/__tests__/integration/workflow-reflection.test.ts"
1272
+ steps:
1273
+ - Create workflow with enableReflection: true
1274
+ - Execute step that fails on first attempt
1275
+ - Verify reflection events emitted
1276
+ - Verify retry succeeds on second attempt
1277
+
1278
+ - name: "Introspection tools in agent"
1279
+ validates: "Agent can use tools to explore hierarchy"
1280
+ file: "/src/__tests__/integration/introspection.test.ts"
1281
+ steps:
1282
+ - Create nested workflow structure
1283
+ - Add agent with INTROSPECTION_TOOLS
1284
+ - Have agent call inspect_current_node
1285
+ - Verify correct node info returned
1286
+ ```
1287
+
1288
+ ### Manual Validation
1289
+ ```yaml
1290
+ steps:
1291
+ - action: "Run example 09-reflection.ts"
1292
+ expected: "See reflection events in console, retry succeeds"
1293
+ command: "npx tsx examples/examples/09-reflection.ts"
1294
+
1295
+ - action: "Run example 10-introspection.ts"
1296
+ expected: "Agent describes its position in hierarchy"
1297
+ command: "npx tsx examples/examples/10-introspection.ts"
1298
+
1299
+ - action: "Verify cache reduces API calls"
1300
+ expected: "Second run much faster with cache enabled"
1301
+ command: "npm test -- --grep 'agent-cache'"
1302
+ ```
1303
+
1304
+ ---
1305
+
1306
+ ## 6. Final Validation Checklist
1307
+
1308
+ ### Code Quality
1309
+ - [ ] All TypeScript compiles without errors: `npm run build`
1310
+ - [ ] No linting warnings: `npm run lint`
1311
+ - [ ] Follows existing code patterns (check agent.ts, workflow.ts)
1312
+ - [ ] Proper error handling with typed errors
1313
+ - [ ] No circular dependencies
1314
+
1315
+ ### Functionality
1316
+ - [ ] Cache generates deterministic keys (same input = same key)
1317
+ - [ ] Cache respects maxItems and maxSizeBytes limits
1318
+ - [ ] Cache TTL works correctly (expired entries not returned)
1319
+ - [ ] bustPrefix removes all matching entries
1320
+ - [ ] Reflection triggers on step failures when enabled
1321
+ - [ ] Reflection respects maxAttempts limit (default: 3)
1322
+ - [ ] Reflection skips non-recoverable errors (rate limit, auth)
1323
+ - [ ] All 6 introspection tools work correctly
1324
+ - [ ] Dynamic factories create valid instances
1325
+ - [ ] Context revision works without forking tree
1326
+
1327
+ ### Testing
1328
+ - [ ] Unit tests pass: `npm test -- --grep "cache|reflection|introspection"`
1329
+ - [ ] Integration tests pass: `npm test`
1330
+ - [ ] Manual validation with examples complete
1331
+
1332
+ ### Documentation
1333
+ - [ ] Code is self-documenting with clear names
1334
+ - [ ] Complex logic has comments explaining "why"
1335
+ - [ ] Public APIs have JSDoc comments
1336
+ - [ ] Examples have header comments explaining purpose
1337
+
1338
+ ---
1339
+
1340
+ ## 7. "No Prior Knowledge" Test
1341
+
1342
+ **Validation**: If someone knew nothing about this codebase, would they have everything needed to implement this successfully using only this PRP?
1343
+
1344
+ - [x] All file paths are absolute and specific
1345
+ - [x] All patterns have concrete examples with code
1346
+ - [x] All dependencies are explicitly listed with versions
1347
+ - [x] All validation steps are executable commands
1348
+ - [x] No assumed knowledge of codebase internals
1349
+ - [x] Key line numbers provided for integration points
1350
+ - [x] Research documents referenced for background context
1351
+ - [x] Known gotchas documented with solutions
1352
+
1353
+ ---
1354
+
1355
+ ## Research References
1356
+
1357
+ See `/plan/P3P4/research/` for detailed research:
1358
+ - `caching-lru.md` - LRU cache implementation patterns, deterministic stringify
1359
+ - `reflection-patterns.md` - AI reflection/self-correction patterns
1360
+ - `introspection-tools.md` - Tool definitions and security considerations
1361
+
1362
+ See `/plan/P1P2/research/` for additional context:
1363
+ - `reflection-patterns.md` - Comprehensive reflection research (1400+ lines)
1364
+ - `anthropic-sdk.md` - SDK patterns and error handling
1365
+
1366
+ ---
1367
+
1368
+ ## Confidence Score: 9/10
1369
+
1370
+ **Strengths:**
1371
+ - Clear existing patterns to follow from Phase 1 & 2
1372
+ - Comprehensive research on caching and reflection already exists
1373
+ - Specific file locations and code examples provided
1374
+ - Detailed validation steps with commands
1375
+ - Event types for reflection already defined in codebase
1376
+ - Configuration flags (enableCache, enableReflection) already in types
1377
+
1378
+ **Risks:**
1379
+ - Reflection prompt effectiveness depends on LLM behavior
1380
+ - Introspection tool handlers need careful context access testing
1381
+ - Cache key generation for complex Zod schemas may need iteration
1382
+ - AsyncLocalStorage edge cases in deeply nested async flows
1383
+
1384
+ **Mitigations:**
1385
+ - Provide sensible defaults for reflection prompts
1386
+ - Extensive test coverage for edge cases
1387
+ - Schema hashing tested with various Zod types
1388
+ - Context propagation already proven in Phase 2 tests