@holoscript/framework 6.0.3 → 6.0.4

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 (160) hide show
  1. package/CHANGELOG.md +1 -2
  2. package/ROADMAP.md +68 -66
  3. package/dist/{InvisibleWallet-BB6tFvRA.d.cts → InvisibleWallet-EFiuaLn3.d.cts} +1 -1
  4. package/dist/{OrchestratorAgent-BvWgf9uw.d.cts → OrchestratorAgent-CrLDGNL6.d.cts} +1 -1
  5. package/dist/agents/index.cjs +11 -10
  6. package/dist/agents/index.d.cts +4 -16
  7. package/dist/ai/index.cjs +2 -2
  8. package/dist/behavior.cjs +10 -0
  9. package/dist/economy/index.cjs +4 -4
  10. package/dist/economy/index.d.cts +2 -2
  11. package/dist/index.cjs +33 -11
  12. package/dist/index.d.cts +3 -3
  13. package/dist/swarm/index.cjs +3 -0
  14. package/package.json +14 -9
  15. package/src/__tests__/bounty-marketplace.test.ts +53 -21
  16. package/src/__tests__/delegation.test.ts +1 -4
  17. package/src/__tests__/done-log-audit.test.ts +38 -46
  18. package/src/__tests__/framework.test.ts +172 -53
  19. package/src/__tests__/goal-synthesizer.test.ts +9 -6
  20. package/src/__tests__/presence.test.ts +1 -1
  21. package/src/__tests__/protocol-agent.test.ts +12 -11
  22. package/src/__tests__/revenue-splitter.test.ts +22 -15
  23. package/src/__tests__/scenario-driven-todo.test.ts +55 -35
  24. package/src/__tests__/self-improve.test.ts +28 -9
  25. package/src/__tests__/service-lifecycle.test.ts +9 -3
  26. package/src/__tests__/skill-router.test.ts +3 -3
  27. package/src/agents/CulturalMemory.ts +6 -6
  28. package/src/agents/DelegationTraceHooks.ts +560 -0
  29. package/src/agents/FederatedRegistryAdapter.ts +1 -1
  30. package/src/agents/NormEngine.ts +3 -8
  31. package/src/agents/OrchestratorAgent.ts +1 -1
  32. package/src/agents/TaskDelegationService.ts +5 -9
  33. package/src/agents/__tests__/AgentWalletRegistry.test.ts +5 -4
  34. package/src/agents/__tests__/CrossRealityHandoff.test.ts +9 -3
  35. package/src/agents/__tests__/DelegationTraceHooks.test.ts +390 -0
  36. package/src/agents/__tests__/TaskDelegationService.test.ts +4 -2
  37. package/src/agents/spatial-comms/Layer1RealTime.ts +36 -19
  38. package/src/agents/spatial-comms/Layer2A2A.ts +1 -3
  39. package/src/agents/spatial-comms/Layer3MCP.ts +13 -4
  40. package/src/agents/spatial-comms/ProtocolTypes.ts +5 -2
  41. package/src/agents/spatial-comms/examples/multi-agent-world-creation.ts +2 -2
  42. package/src/ai/HoloScriptGenerator.ts +2 -2
  43. package/src/ai/__tests__/PerceptionSystem.prod.test.ts +1 -1
  44. package/src/ai/__tests__/PerceptionSystem.test.ts +14 -14
  45. package/src/ai/__tests__/SteeringBehaviors.prod.test.ts +1 -1
  46. package/src/ai/index.ts +5 -1
  47. package/src/board/audit.ts +17 -6
  48. package/src/board/board-ops.ts +45 -15
  49. package/src/board/board-types.ts +94 -20
  50. package/src/delegation.ts +5 -3
  51. package/src/distributed-claimer.ts +13 -2
  52. package/src/economy/BountyManager.ts +40 -18
  53. package/src/economy/KnowledgeMarketplace.ts +27 -8
  54. package/src/economy/PaymentWebhookService.ts +0 -1
  55. package/src/economy/RevenueSplitter.ts +2 -4
  56. package/src/economy/UnifiedBudgetOptimizer.ts +8 -9
  57. package/src/economy/_core-stubs.ts +1 -1
  58. package/src/economy/x402-facilitator.ts +17 -8
  59. package/src/index.ts +16 -12
  60. package/src/knowledge/__tests__/knowledge-consolidator.test.ts +138 -89
  61. package/src/knowledge/__tests__/knowledge-store-vector.test.ts +59 -16
  62. package/src/knowledge/brain.ts +7 -7
  63. package/src/knowledge/consolidation.ts +16 -16
  64. package/src/knowledge/knowledge-consolidator.ts +60 -30
  65. package/src/knowledge/knowledge-store.ts +83 -45
  66. package/src/learning/ProceduralCompiler.ts +6 -1
  67. package/src/learning/learning/MemoryConsolidator.ts +102 -0
  68. package/src/learning/learning/MemoryScorer.ts +69 -0
  69. package/src/learning/learning/ProceduralCompiler.ts +45 -0
  70. package/src/learning/learning/SemanticClusterer.ts +66 -0
  71. package/src/llm/llm-adapter.ts +24 -10
  72. package/src/mesh/index.ts +37 -17
  73. package/src/protocol/goal-synthesizer.ts +24 -34
  74. package/src/protocol/implementations.ts +91 -22
  75. package/src/protocol/micro-phase-decomposer.ts +25 -17
  76. package/src/protocol/micro-step-decomposer.test.ts +104 -39
  77. package/src/protocol-agent.test.ts +17 -7
  78. package/src/protocol-agent.ts +45 -42
  79. package/src/self-improve/absorb-scanner.ts +9 -6
  80. package/src/self-improve/evolution-engine.ts +36 -18
  81. package/src/self-improve/framework-absorber.ts +21 -16
  82. package/src/self-improve/index.ts +2 -10
  83. package/src/self-improve/prompt-optimizer.ts +31 -19
  84. package/src/self-improve/test-generator.ts +16 -12
  85. package/src/skill-router.ts +7 -6
  86. package/src/swarm/messaging/GossipProtocol.ts +1 -1
  87. package/src/swarm/messaging/__tests__/BroadcastChannel.prod.test.ts +31 -9
  88. package/src/swarm/messaging/__tests__/GossipProtocol.prod.test.ts +21 -7
  89. package/src/swarm/messaging/__tests__/SwarmEventBus.prod.test.ts +24 -8
  90. package/src/swarm/messaging/__tests__/SwarmEventBus.test.ts +6 -2
  91. package/src/team.ts +277 -122
  92. package/src/training/scripts/generate-spatial-dataset.ts +1 -1
  93. package/src/training/training/LRScheduler.ts +377 -0
  94. package/src/training/training/QualityScoringPipeline.ts +139 -0
  95. package/src/training/training/SoftDedup.ts +461 -0
  96. package/src/training/training/SparsityMonitor.ts +685 -0
  97. package/src/training/training/SparsityMonitorTypes.ts +209 -0
  98. package/src/training/training/SpatialTrainingDataGenerator.ts +1526 -0
  99. package/src/training/training/SpatialTrainingDataTypes.ts +216 -0
  100. package/src/training/training/TrainingPipelineConfig.ts +215 -0
  101. package/src/training/training/__tests__/CorpusValidation.test.ts +87 -0
  102. package/src/training/training/__tests__/LRScheduler.test.ts +592 -0
  103. package/src/training/training/__tests__/SoftDedup.test.ts +415 -0
  104. package/src/training/training/__tests__/SparsityMonitor.test.ts +1623 -0
  105. package/src/training/training/__tests__/SpatialCorpusValidation.test.ts +72 -0
  106. package/src/training/training/__tests__/SpatialTrainingDataGenerator.test.ts +1244 -0
  107. package/src/training/training/__tests__/TrainingMonkeyIntegration.test.ts +897 -0
  108. package/src/training/training/__tests__/TrainingPipelineConfig.test.ts +202 -0
  109. package/src/training/training/__tests__/schema.test.ts +72 -0
  110. package/src/training/training/__tests__/training-constants.test.ts +106 -0
  111. package/src/training/training/__tests__/trait-mappings.test.ts +81 -0
  112. package/src/training/training/constants.ts +94 -0
  113. package/src/training/training/index.ts +17 -0
  114. package/src/training/training/schema.ts +147 -0
  115. package/src/training/training/scripts/generate-novel-use-cases-dataset.ts +272 -0
  116. package/src/training/training/scripts/generate-spatial-dataset.ts +521 -0
  117. package/src/training/training/trainingmonkey/TrainingMonkeyIntegration.ts +477 -0
  118. package/src/training/training/trainingmonkey/TrainingMonkeyTypes.ts +230 -0
  119. package/src/training/training/trainingmonkey/index.ts +26 -0
  120. package/src/training/training/trait-mappings.ts +157 -0
  121. package/src/types.ts +2 -7
  122. package/ALL-test-results.json +0 -1
  123. package/LICENSE +0 -21
  124. package/dist/AgentManifest-CB4xM-Ma.d.ts +0 -704
  125. package/dist/BehaviorTree-BrBFECv5.d.ts +0 -103
  126. package/dist/InvisibleWallet-rtRrBOA8.d.ts +0 -1732
  127. package/dist/OrchestratorAgent-Q_CbVTmO.d.ts +0 -798
  128. package/dist/agents/index.d.ts +0 -1788
  129. package/dist/agents/index.js +0 -4695
  130. package/dist/ai/index.d.ts +0 -1753
  131. package/dist/ai/index.js +0 -5244
  132. package/dist/behavior.d.ts +0 -130
  133. package/dist/behavior.js +0 -407
  134. package/dist/economy/index.d.ts +0 -747
  135. package/dist/economy/index.js +0 -3617
  136. package/dist/implementations-D9T3un9D.d.ts +0 -236
  137. package/dist/index.d.ts +0 -1729
  138. package/dist/index.js +0 -24277
  139. package/dist/learning/index.d.ts +0 -104
  140. package/dist/learning/index.js +0 -189
  141. package/dist/negotiation/index.d.ts +0 -610
  142. package/dist/negotiation/index.js +0 -931
  143. package/dist/skills/index.d.ts +0 -289
  144. package/dist/skills/index.js +0 -1079
  145. package/dist/swarm/index.d.ts +0 -2433
  146. package/dist/swarm/index.js +0 -5221
  147. package/dist/training/index.d.ts +0 -1734
  148. package/dist/training/index.js +0 -2687
  149. package/extract-failures.js +0 -10
  150. package/src/training/training/data/novel-use-cases.jsonl +0 -153
  151. package/src/training/training/data/spatial-reasoning-10k.jsonl +0 -9354
  152. package/src/types/core-stubs.d.ts +0 -113
  153. package/test-output.txt +0 -0
  154. package/test-result.json +0 -1
  155. package/tsc-errors.txt +0 -4
  156. package/tsc_output.txt +0 -0
  157. package/typescript-errors-2.txt +0 -0
  158. package/typescript-errors.txt +0 -22
  159. package/vitest-log-utf8.txt +0 -268
  160. package/vitest-log.txt +0 -0
@@ -0,0 +1,66 @@
1
+ import { EpisodicEvent } from './MemoryScorer';
2
+
3
+ /**
4
+ * SemanticClusterer
5
+ *
6
+ * Compresses raw temporal Episodic buffers into distilled arrays.
7
+ * Native distillation drops repeating trivial structures mapping them into aggregated
8
+ * density nodes explicitly reducing database storage loads across vector boundaries.
9
+ */
10
+ export class SemanticClusterer {
11
+ /**
12
+ * Actively squash sequentially repeating abstract patterns mapping out semantic arrays.
13
+ */
14
+ static distill(events: EpisodicEvent[]): EpisodicEvent[] {
15
+ if (events.length === 0) return [];
16
+
17
+ const distilled: EpisodicEvent[] = [];
18
+ let currentSequence: EpisodicEvent = { ...events[0] };
19
+ let repetitonCount = 1;
20
+
21
+ for (let i = 1; i < events.length; i++) {
22
+ const ev = events[i];
23
+
24
+ // If the Action and Target align, we squash them and increment the density metrics
25
+ if (this.isSimilar(currentSequence, ev)) {
26
+ repetitonCount++;
27
+ currentSequence.outcome = `Repeated action successfully (${repetitonCount} times)`;
28
+
29
+ // Track total time span passed over the squash boundary
30
+ if (!currentSequence.context.timeSpanStarted) {
31
+ currentSequence.context.timeSpanStarted = currentSequence.timestamp;
32
+ }
33
+ currentSequence.context.timeSpanEnded = ev.timestamp;
34
+ } else {
35
+ // Similarity broken. Push distilled sequence array and begin anew.
36
+ if (repetitonCount > 1) {
37
+ currentSequence.action = `${currentSequence.action}_Aggregated`;
38
+ }
39
+ distilled.push({ ...currentSequence });
40
+
41
+ currentSequence = { ...ev };
42
+ repetitonCount = 1;
43
+ }
44
+ }
45
+
46
+ // Push final buffer
47
+ if (repetitonCount > 1) {
48
+ currentSequence.action = `${currentSequence.action}_Aggregated`;
49
+ }
50
+ distilled.push(currentSequence);
51
+
52
+ return distilled;
53
+ }
54
+
55
+ /**
56
+ * Determines heuristic thresholds to squash logic natively offline without LLM.
57
+ */
58
+ private static isSimilar(a: EpisodicEvent, b: EpisodicEvent): boolean {
59
+ if (a.action !== b.action) return false;
60
+
61
+ const aTarget = a.context?.target || a.context?.location;
62
+ const bTarget = b.context?.target || b.context?.location;
63
+
64
+ return aTarget === bTarget;
65
+ }
66
+ }
@@ -49,11 +49,16 @@ async function callAnthropic(
49
49
  const apiKey = config.apiKey || process.env.ANTHROPIC_API_KEY;
50
50
  if (!apiKey) throw new Error('ANTHROPIC_API_KEY required');
51
51
 
52
- const system = messages.filter(m => m.role === 'system').map(m => m.content).join('\n');
53
- const userMessages = messages.filter(m => m.role !== 'system').map(m => ({
54
- role: m.role as 'user' | 'assistant',
55
- content: m.content,
56
- }));
52
+ const system = messages
53
+ .filter((m) => m.role === 'system')
54
+ .map((m) => m.content)
55
+ .join('\n');
56
+ const userMessages = messages
57
+ .filter((m) => m.role !== 'system')
58
+ .map((m) => ({
59
+ role: m.role as 'user' | 'assistant',
60
+ content: m.content,
61
+ }));
57
62
 
58
63
  const res = await fetch('https://api.anthropic.com/v1/messages', {
59
64
  method: 'POST',
@@ -73,7 +78,10 @@ async function callAnthropic(
73
78
  });
74
79
 
75
80
  if (!res.ok) throw new Error(`Anthropic API error: ${res.status}`);
76
- const data = await res.json() as { content: Array<{ text: string }>; usage?: { output_tokens: number } };
81
+ const data = (await res.json()) as {
82
+ content: Array<{ text: string }>;
83
+ usage?: { output_tokens: number };
84
+ };
77
85
 
78
86
  return {
79
87
  content: data.content?.[0]?.text || '',
@@ -105,13 +113,16 @@ async function callOpenAICompatible(
105
113
  model: config.model,
106
114
  max_tokens: maxTokens,
107
115
  temperature,
108
- messages: messages.map(m => ({ role: m.role, content: m.content })),
116
+ messages: messages.map((m) => ({ role: m.role, content: m.content })),
109
117
  }),
110
118
  signal: AbortSignal.timeout(60_000),
111
119
  });
112
120
 
113
121
  if (!res.ok) throw new Error(`${config.provider} API error: ${res.status}`);
114
- const data = await res.json() as { choices: Array<{ message: { content: string } }>; usage?: { completion_tokens: number } };
122
+ const data = (await res.json()) as {
123
+ choices: Array<{ message: { content: string } }>;
124
+ usage?: { completion_tokens: number };
125
+ };
115
126
 
116
127
  return {
117
128
  content: data.choices?.[0]?.message?.content || '',
@@ -142,13 +153,16 @@ async function callOpenRouter(
142
153
  model: config.model,
143
154
  max_tokens: maxTokens,
144
155
  temperature,
145
- messages: messages.map(m => ({ role: m.role, content: m.content })),
156
+ messages: messages.map((m) => ({ role: m.role, content: m.content })),
146
157
  }),
147
158
  signal: AbortSignal.timeout(60_000),
148
159
  });
149
160
 
150
161
  if (!res.ok) throw new Error(`OpenRouter API error: ${res.status}`);
151
- const data = await res.json() as { choices: Array<{ message: { content: string } }>; usage?: { completion_tokens: number } };
162
+ const data = (await res.json()) as {
163
+ choices: Array<{ message: { content: string } }>;
164
+ usage?: { completion_tokens: number };
165
+ };
152
166
 
153
167
  return {
154
168
  content: data.choices?.[0]?.message?.content || '',
package/src/mesh/index.ts CHANGED
@@ -47,9 +47,15 @@ export class MeshDiscovery {
47
47
  return false;
48
48
  }
49
49
 
50
- getPeers(): PeerMetadata[] { return [...this.peers.values()]; }
51
- getPeer(id: string): PeerMetadata | undefined { return this.peers.get(id); }
52
- getPeerCount(): number { return this.peers.size; }
50
+ getPeers(): PeerMetadata[] {
51
+ return [...this.peers.values()];
52
+ }
53
+ getPeer(id: string): PeerMetadata | undefined {
54
+ return this.peers.get(id);
55
+ }
56
+ getPeerCount(): number {
57
+ return this.peers.size;
58
+ }
53
59
 
54
60
  pruneStalePeers(timeoutMs: number = 15000): number {
55
61
  const now = Date.now();
@@ -97,7 +103,10 @@ export class SignalService {
97
103
  this.nodeId = nodeId ?? `node-${Date.now().toString(36)}`;
98
104
  }
99
105
 
100
- broadcastSignal(signal: Omit<MeshSignal, 'nodeId' | 'expiresAt'>, ttlMs: number = 3600000): MeshSignal {
106
+ broadcastSignal(
107
+ signal: Omit<MeshSignal, 'nodeId' | 'expiresAt'>,
108
+ ttlMs: number = 3600000
109
+ ): MeshSignal {
101
110
  const full: MeshSignal = { ...signal, nodeId: this.nodeId, expiresAt: Date.now() + ttlMs };
102
111
  this.localSignals.set(`${full.type}:${full.nodeId}`, full);
103
112
  return full;
@@ -112,13 +121,14 @@ export class SignalService {
112
121
  for (const [key, sig] of this.remoteSignals) {
113
122
  if (sig.expiresAt < now) this.remoteSignals.delete(key);
114
123
  }
115
- return [
116
- ...this.remoteSignals.values(),
117
- ...this.localSignals.values(),
118
- ].filter((s) => s.type === type);
124
+ return [...this.remoteSignals.values(), ...this.localSignals.values()].filter(
125
+ (s) => s.type === type
126
+ );
119
127
  }
120
128
 
121
- getLocalSignals(): MeshSignal[] { return [...this.localSignals.values()]; }
129
+ getLocalSignals(): MeshSignal[] {
130
+ return [...this.localSignals.values()];
131
+ }
122
132
  }
123
133
 
124
134
  // =============================================================================
@@ -160,8 +170,12 @@ export class GossipProtocol {
160
170
  return absorbed;
161
171
  }
162
172
 
163
- getPool(): Map<string, GossipPacket> { return new Map(this.pool); }
164
- getPoolSize(): number { return this.pool.size; }
173
+ getPool(): Map<string, GossipPacket> {
174
+ return new Map(this.pool);
175
+ }
176
+ getPoolSize(): number {
177
+ return this.pool.size;
178
+ }
165
179
  }
166
180
 
167
181
  // =============================================================================
@@ -194,8 +208,10 @@ export const MCP_TOOL_SCHEMAS: MCPToolSchema[] = [
194
208
  inputSchema: {
195
209
  type: 'object',
196
210
  properties: {
197
- id: { type: 'string' }, domain: { type: 'string' },
198
- problem: { type: 'string' }, solution: { type: 'string' },
211
+ id: { type: 'string' },
212
+ domain: { type: 'string' },
213
+ problem: { type: 'string' },
214
+ solution: { type: 'string' },
199
215
  tags: { type: 'array', items: { type: 'string' } },
200
216
  },
201
217
  required: ['id', 'domain', 'problem', 'solution'],
@@ -207,8 +223,10 @@ export const MCP_TOOL_SCHEMAS: MCPToolSchema[] = [
207
223
  inputSchema: {
208
224
  type: 'object',
209
225
  properties: {
210
- id: { type: 'string' }, domain: { type: 'string' },
211
- insight: { type: 'string' }, context: { type: 'string' },
226
+ id: { type: 'string' },
227
+ domain: { type: 'string' },
228
+ insight: { type: 'string' },
229
+ context: { type: 'string' },
212
230
  },
213
231
  required: ['id', 'domain', 'insight'],
214
232
  },
@@ -219,8 +237,10 @@ export const MCP_TOOL_SCHEMAS: MCPToolSchema[] = [
219
237
  inputSchema: {
220
238
  type: 'object',
221
239
  properties: {
222
- id: { type: 'string' }, domain: { type: 'string' },
223
- mistake: { type: 'string' }, fix: { type: 'string' },
240
+ id: { type: 'string' },
241
+ domain: { type: 'string' },
242
+ mistake: { type: 'string' },
243
+ fix: { type: 'string' },
224
244
  severity: { type: 'string', enum: ['low', 'medium', 'high', 'critical'] },
225
245
  },
226
246
  required: ['id', 'domain', 'mistake', 'fix'],
@@ -107,7 +107,7 @@ const DOMAIN_GOALS: Record<string, string[]> = {
107
107
  'Review and refine CI/CD pipeline efficiency',
108
108
  'Automate environment provisioning for local scenario tests',
109
109
  'Evaluate telemetry logging cardinality and storage costs',
110
- ]
110
+ ],
111
111
  };
112
112
 
113
113
  // ── GoalSynthesizer ──
@@ -125,10 +125,7 @@ export class GoalSynthesizer {
125
125
  * Synthesize goals from context. Uses LLM when available, falls back to heuristics.
126
126
  * Returns goals ranked by relevance.
127
127
  */
128
- async synthesizeMultiple(
129
- context: GoalContext,
130
- count = 3
131
- ): Promise<SynthesizedGoal[]> {
128
+ async synthesizeMultiple(context: GoalContext, count = 3): Promise<SynthesizedGoal[]> {
132
129
  // Gather knowledge context
133
130
  const knowledgeEntries = context.recentKnowledge ?? this.queryKnowledge(context.domain);
134
131
 
@@ -148,15 +145,8 @@ export class GoalSynthesizer {
148
145
  /**
149
146
  * Synthesize a single goal. Backward-compatible with the original API.
150
147
  */
151
- synthesize(
152
- agentDomain: string = 'general',
153
- source: Goal['source'] = 'autonomous-boredom'
154
- ): Goal {
155
- const goals = this.synthesizeHeuristic(
156
- { domain: agentDomain },
157
- [],
158
- 1
159
- );
148
+ synthesize(agentDomain: string = 'general', source: Goal['source'] = 'autonomous-boredom'): Goal {
149
+ const goals = this.synthesizeHeuristic({ domain: agentDomain }, [], 1);
160
150
  if (goals.length > 0) {
161
151
  return { ...goals[0], source };
162
152
  }
@@ -189,9 +179,10 @@ export class GoalSynthesizer {
189
179
  knowledge: StoredEntry[],
190
180
  count: number
191
181
  ): Promise<SynthesizedGoal[]> {
192
- const knowledgeContext = knowledge.length > 0
193
- ? knowledge.map(k => `[${k.type}] ${k.content}`).join('\n')
194
- : 'No relevant knowledge entries found.';
182
+ const knowledgeContext =
183
+ knowledge.length > 0
184
+ ? knowledge.map((k) => `[${k.type}] ${k.content}`).join('\n')
185
+ : 'No relevant knowledge entries found.';
195
186
 
196
187
  const recentTasks = context.recentCompletedTasks?.length
197
188
  ? context.recentCompletedTasks.slice(0, 10).join('\n- ')
@@ -200,15 +191,15 @@ export class GoalSynthesizer {
200
191
  const systemPrompt = [
201
192
  `You are a goal synthesizer for an autonomous AI agent team.`,
202
193
  `The agent "${context.agentName ?? 'unknown'}" operates in the "${context.domain}" domain.`,
203
- context.capabilities?.length
204
- ? `Agent capabilities: ${context.capabilities.join(', ')}`
205
- : '',
194
+ context.capabilities?.length ? `Agent capabilities: ${context.capabilities.join(', ')}` : '',
206
195
  context.teamName ? `Team: ${context.teamName}` : '',
207
196
  ``,
208
197
  `Your job: propose ${count} actionable goals the agent should pursue autonomously.`,
209
198
  `Goals should be specific, achievable, and build on existing knowledge.`,
210
199
  `Avoid duplicating recently completed tasks.`,
211
- ].filter(Boolean).join('\n');
200
+ ]
201
+ .filter(Boolean)
202
+ .join('\n');
212
203
 
213
204
  const userPrompt = [
214
205
  `## Knowledge Context`,
@@ -223,7 +214,9 @@ export class GoalSynthesizer {
223
214
  `[{"description": "...", "category": "...", "priority": "low|medium|high", "rationale": "...", "estimatedComplexity": 1-5}]`,
224
215
  ``,
225
216
  `Respond with ONLY the JSON array, no markdown fences.`,
226
- ].filter(Boolean).join('\n');
217
+ ]
218
+ .filter(Boolean)
219
+ .join('\n');
227
220
 
228
221
  const messages: LLMMessage[] = [
229
222
  { role: 'system', content: systemPrompt },
@@ -238,11 +231,7 @@ export class GoalSynthesizer {
238
231
  return this.parseLLMGoals(response.content, context, count);
239
232
  }
240
233
 
241
- private parseLLMGoals(
242
- content: string,
243
- context: GoalContext,
244
- count: number
245
- ): SynthesizedGoal[] {
234
+ private parseLLMGoals(content: string, context: GoalContext, count: number): SynthesizedGoal[] {
246
235
  try {
247
236
  // Strip markdown fences if present
248
237
  const cleaned = content.replace(/```(?:json)?\s*\n?/g, '').trim();
@@ -265,7 +254,7 @@ export class GoalSynthesizer {
265
254
  generatedAt: new Date().toISOString(),
266
255
  source: 'autonomous-boredom' as const,
267
256
  rationale: g.rationale || 'LLM-generated goal based on context',
268
- relevanceScore: 1 - (i * 0.1), // rank order from LLM
257
+ relevanceScore: 1 - i * 0.1, // rank order from LLM
269
258
  }));
270
259
  } catch {
271
260
  return this.synthesizeHeuristic(context, [], count);
@@ -278,7 +267,7 @@ export class GoalSynthesizer {
278
267
  count: number
279
268
  ): SynthesizedGoal[] {
280
269
  const completedSet = new Set(
281
- (context.recentCompletedTasks ?? []).map(t => t.toLowerCase().trim())
270
+ (context.recentCompletedTasks ?? []).map((t) => t.toLowerCase().trim())
282
271
  );
283
272
 
284
273
  // Build candidate pool from domain + generic goals
@@ -287,11 +276,12 @@ export class GoalSynthesizer {
287
276
 
288
277
  // If we have knowledge, generate knowledge-derived goals
289
278
  const knowledgeGoals = knowledge
290
- .filter(k => k.type === 'gotcha')
291
- .map(k => `Investigate and resolve: ${k.content.slice(0, 120)}`);
279
+ .filter((k) => k.type === 'gotcha')
280
+ .map((k) => `Investigate and resolve: ${k.content.slice(0, 120)}`);
292
281
 
293
- const allCandidates = [...knowledgeGoals, ...candidates]
294
- .filter(desc => !completedSet.has(desc.toLowerCase().trim()));
282
+ const allCandidates = [...knowledgeGoals, ...candidates].filter(
283
+ (desc) => !completedSet.has(desc.toLowerCase().trim())
284
+ );
295
285
 
296
286
  // Shuffle and pick
297
287
  const shuffled = allCandidates.sort(() => Math.random() - 0.5);
@@ -308,7 +298,7 @@ export class GoalSynthesizer {
308
298
  rationale: knowledgeGoals.includes(description)
309
299
  ? 'Derived from knowledge store gotcha entries'
310
300
  : `Heuristic goal for ${context.domain} domain`,
311
- relevanceScore: Math.max(0.3, 1 - (i * 0.2)),
301
+ relevanceScore: Math.max(0.3, 1 - i * 0.2),
312
302
  }));
313
303
  }
314
304
  }
@@ -117,22 +117,48 @@ export interface ServiceConfig {
117
117
  export type PWGSeverity = 'low' | 'medium' | 'high' | 'critical';
118
118
 
119
119
  export interface Pattern {
120
- id: string; domain: string; problem: string; solution: string; context?: string; tags: string[]; confidence: number; createdAt: number; updatedAt: number;
120
+ id: string;
121
+ domain: string;
122
+ problem: string;
123
+ solution: string;
124
+ context?: string;
125
+ tags: string[];
126
+ confidence: number;
127
+ createdAt: number;
128
+ updatedAt: number;
121
129
  }
122
130
 
123
131
  export interface Wisdom {
124
- id: string; domain: string; insight: string; context: string; source: string; tags: string[]; createdAt: number;
132
+ id: string;
133
+ domain: string;
134
+ insight: string;
135
+ context: string;
136
+ source: string;
137
+ tags: string[];
138
+ createdAt: number;
125
139
  }
126
140
 
127
141
  export interface Gotcha {
128
- id: string; domain: string; mistake: string; fix: string; severity: PWGSeverity; tags: string[]; createdAt: number;
142
+ id: string;
143
+ domain: string;
144
+ mistake: string;
145
+ fix: string;
146
+ severity: PWGSeverity;
147
+ tags: string[];
148
+ createdAt: number;
129
149
  }
130
150
 
131
151
  export type PWGEntry = Pattern | Wisdom | Gotcha;
132
152
 
133
- export function isPattern(entry: PWGEntry): entry is Pattern { return entry.id.startsWith('P.'); }
134
- export function isWisdom(entry: PWGEntry): entry is Wisdom { return entry.id.startsWith('W.'); }
135
- export function isGotcha(entry: PWGEntry): entry is Gotcha { return entry.id.startsWith('G.'); }
153
+ export function isPattern(entry: PWGEntry): entry is Pattern {
154
+ return entry.id.startsWith('P.');
155
+ }
156
+ export function isWisdom(entry: PWGEntry): entry is Wisdom {
157
+ return entry.id.startsWith('W.');
158
+ }
159
+ export function isGotcha(entry: PWGEntry): entry is Gotcha {
160
+ return entry.id.startsWith('G.');
161
+ }
136
162
 
137
163
  // =============================================================================
138
164
  // BASE AGENT — Abstract 7-phase agent contract
@@ -159,7 +185,10 @@ export abstract class BaseAgent {
159
185
  /**
160
186
  * Execute a complete 7-phase cycle
161
187
  */
162
- async runCycle(task: string, context: Record<string, unknown> = {}): Promise<ProtocolCycleResult> {
188
+ async runCycle(
189
+ task: string,
190
+ context: Record<string, unknown> = {}
191
+ ): Promise<ProtocolCycleResult> {
163
192
  const startedAt = Date.now();
164
193
  const cycleId = `cycle_${startedAt}_${Math.random().toString(36).slice(2, 8)}`;
165
194
  const phases: PhaseResult[] = [];
@@ -191,8 +220,16 @@ export abstract class BaseAgent {
191
220
  const intakeResult = await runPhase(ProtocolPhase.INTAKE, this.intake, { task, ...context });
192
221
  const reflectResult = await runPhase(ProtocolPhase.REFLECT, this.reflect, intakeResult.data);
193
222
  const executeResult = await runPhase(ProtocolPhase.EXECUTE, this.execute, reflectResult.data);
194
- const compressResult = await runPhase(ProtocolPhase.COMPRESS, this.compress, executeResult.data);
195
- const reintakeResult = await runPhase(ProtocolPhase.REINTAKE, this.reintake, compressResult.data);
223
+ const compressResult = await runPhase(
224
+ ProtocolPhase.COMPRESS,
225
+ this.compress,
226
+ executeResult.data
227
+ );
228
+ const reintakeResult = await runPhase(
229
+ ProtocolPhase.REINTAKE,
230
+ this.reintake,
231
+ compressResult.data
232
+ );
196
233
  const growResult = await runPhase(ProtocolPhase.GROW, this.grow, reintakeResult.data);
197
234
  await runPhase(ProtocolPhase.EVOLVE, this.evolve, growResult.data);
198
235
 
@@ -273,9 +310,15 @@ export abstract class BaseService {
273
310
  this.metadata.lifecycle = ServiceLifecycle.STOPPED;
274
311
  }
275
312
 
276
- getMetadata(): ServiceMetadata { return { ...this.metadata }; }
277
- getMetrics(): ServiceMetrics { return { ...this.metrics }; }
278
- isReady(): boolean { return this.metadata.lifecycle === ServiceLifecycle.READY; }
313
+ getMetadata(): ServiceMetadata {
314
+ return { ...this.metadata };
315
+ }
316
+ getMetrics(): ServiceMetrics {
317
+ return { ...this.metrics };
318
+ }
319
+ isReady(): boolean {
320
+ return this.metadata.lifecycle === ServiceLifecycle.READY;
321
+ }
279
322
 
280
323
  protected recordRequest(latency: number): void {
281
324
  this.metrics.requestCount++;
@@ -333,16 +376,16 @@ export class ServiceManager {
333
376
  }
334
377
 
335
378
  health(): ServiceManagerHealth {
336
- const ready = this.services.filter(s => s.isReady());
379
+ const ready = this.services.filter((s) => s.isReady());
337
380
  return {
338
381
  totalServices: this.services.length,
339
382
  readyCount: ready.length,
340
383
  allReady: this.services.length > 0 && ready.length === this.services.length,
341
- services: this.services.map(s => ({
384
+ services: this.services.map((s) => ({
342
385
  name: s.getMetadata().name,
343
386
  ready: s.isReady(),
344
- lifecycle: s.getMetadata().lifecycle
345
- }))
387
+ lifecycle: s.getMetadata().lifecycle,
388
+ })),
346
389
  };
347
390
  }
348
391
  }
@@ -406,7 +449,13 @@ export class MicroPhaseDecomposer {
406
449
  groupIdx = Math.max(groupIdx, (assignedToGroup.get(depId) ?? 0) + 1);
407
450
  }
408
451
  while (groups.length <= groupIdx) {
409
- groups.push({ id: `group_${groups.length}`, name: `Group ${groups.length}`, tasks: [], parallel: true, estimatedDuration: 0 });
452
+ groups.push({
453
+ id: `group_${groups.length}`,
454
+ name: `Group ${groups.length}`,
455
+ tasks: [],
456
+ parallel: true,
457
+ estimatedDuration: 0,
458
+ });
410
459
  }
411
460
  groups[groupIdx].tasks.push(task);
412
461
  assignedToGroup.set(taskId, groupIdx);
@@ -419,7 +468,11 @@ export class MicroPhaseDecomposer {
419
468
  }
420
469
 
421
470
  const seqTime = [...this.nodes.values()].reduce((s, t) => s + t.estimatedDuration, 0);
422
- return { groups, totalEstimatedTime: totalTime, parallelizationRatio: seqTime > 0 ? ((seqTime - totalTime) / seqTime) * 100 : 0 };
471
+ return {
472
+ groups,
473
+ totalEstimatedTime: totalTime,
474
+ parallelizationRatio: seqTime > 0 ? ((seqTime - totalTime) / seqTime) * 100 : 0,
475
+ };
423
476
  }
424
477
 
425
478
  async executePlan(plan: ExecutionPlan): Promise<ExecutionResult[]> {
@@ -432,12 +485,26 @@ export class MicroPhaseDecomposer {
432
485
  const timeout = task.timeout ?? 30000;
433
486
  const result = await Promise.race([
434
487
  task.execute(),
435
- new Promise((_, reject) => setTimeout(() => reject(new Error('Task timeout')), timeout)),
488
+ new Promise((_, reject) =>
489
+ setTimeout(() => reject(new Error('Task timeout')), timeout)
490
+ ),
436
491
  ]);
437
- return { taskId: task.id, status: 'success' as const, duration: Date.now() - start, result, timestamp: Date.now() };
492
+ return {
493
+ taskId: task.id,
494
+ status: 'success' as const,
495
+ duration: Date.now() - start,
496
+ result,
497
+ timestamp: Date.now(),
498
+ };
438
499
  } catch (err) {
439
500
  const isTimeout = err instanceof Error && err.message === 'Task timeout';
440
- return { taskId: task.id, status: (isTimeout ? 'timeout' : 'failure') as 'timeout' | 'failure', duration: Date.now() - start, error: err instanceof Error ? err : new Error(String(err)), timestamp: Date.now() };
501
+ return {
502
+ taskId: task.id,
503
+ status: (isTimeout ? 'timeout' : 'failure') as 'timeout' | 'failure',
504
+ duration: Date.now() - start,
505
+ error: err instanceof Error ? err : new Error(String(err)),
506
+ timestamp: Date.now(),
507
+ };
441
508
  }
442
509
  })
443
510
  );
@@ -447,7 +514,9 @@ export class MicroPhaseDecomposer {
447
514
  return results;
448
515
  }
449
516
 
450
- getHistory(): ExecutionResult[] { return [...this.history]; }
517
+ getHistory(): ExecutionResult[] {
518
+ return [...this.history];
519
+ }
451
520
 
452
521
  reset(): void {
453
522
  this.nodes.clear();
@@ -58,7 +58,10 @@ const DEFAULT_COMPLEXITY_THRESHOLD = 2;
58
58
  // ── LLM Adapter Interface (injectable for testing) ──
59
59
 
60
60
  export interface LLMAdapter {
61
- call(messages: LLMMessage[], options?: { maxTokens?: number; temperature?: number }): Promise<string>;
61
+ call(
62
+ messages: LLMMessage[],
63
+ options?: { maxTokens?: number; temperature?: number }
64
+ ): Promise<string>;
62
65
  }
63
66
 
64
67
  /** Create an LLMAdapter from a ModelConfig */
@@ -159,7 +162,7 @@ Rules:
159
162
  this.validatePhases(phases);
160
163
 
161
164
  const sorted = this.topologicalSort(phases);
162
- const phaseMap = new Map(phases.map(p => [p.id, p]));
165
+ const phaseMap = new Map(phases.map((p) => [p.id, p]));
163
166
  const waveAssignment = new Map<string, number>();
164
167
  const waves: MicroPhase[][] = [];
165
168
 
@@ -181,15 +184,16 @@ Rules:
181
184
  // Calculate timing
182
185
  const sequentialTime = phases.reduce((sum, p) => sum + p.estimatedDuration, 0);
183
186
  const parallelTime = waves.reduce((sum, wave) => {
184
- return sum + Math.max(...wave.map(p => p.estimatedDuration));
187
+ return sum + Math.max(...wave.map((p) => p.estimatedDuration));
185
188
  }, 0);
186
189
 
187
190
  return {
188
191
  waves,
189
192
  totalEstimatedDuration: parallelTime,
190
- parallelizationRatio: sequentialTime > 0
191
- ? Math.round(((sequentialTime - parallelTime) / sequentialTime) * 100)
192
- : 0,
193
+ parallelizationRatio:
194
+ sequentialTime > 0
195
+ ? Math.round(((sequentialTime - parallelTime) / sequentialTime) * 100)
196
+ : 0,
193
197
  phaseCount: phases.length,
194
198
  };
195
199
  }
@@ -212,7 +216,9 @@ Rules:
212
216
  description: String(p.description ?? 'Unknown phase'),
213
217
  dependencies: Array.isArray(p.dependencies) ? p.dependencies.map(String) : [],
214
218
  estimatedDuration: typeof p.estimatedDuration === 'number' ? p.estimatedDuration : 5000,
215
- requiredCapabilities: Array.isArray(p.requiredCapabilities) ? p.requiredCapabilities.map(String) : ['coding'],
219
+ requiredCapabilities: Array.isArray(p.requiredCapabilities)
220
+ ? p.requiredCapabilities.map(String)
221
+ : ['coding'],
216
222
  }));
217
223
  } catch {
218
224
  return this.fallbackSinglePhase(taskId);
@@ -220,17 +226,19 @@ Rules:
220
226
  }
221
227
 
222
228
  private fallbackSinglePhase(taskId: string): MicroPhase[] {
223
- return [{
224
- id: `${taskId}_single`,
225
- description: 'Execute task as single unit',
226
- dependencies: [],
227
- estimatedDuration: 10000,
228
- requiredCapabilities: ['coding'],
229
- }];
229
+ return [
230
+ {
231
+ id: `${taskId}_single`,
232
+ description: 'Execute task as single unit',
233
+ dependencies: [],
234
+ estimatedDuration: 10000,
235
+ requiredCapabilities: ['coding'],
236
+ },
237
+ ];
230
238
  }
231
239
 
232
240
  private validatePhases(phases: MicroPhase[]): void {
233
- const ids = new Set(phases.map(p => p.id));
241
+ const ids = new Set(phases.map((p) => p.id));
234
242
 
235
243
  for (const phase of phases) {
236
244
  for (const dep of phase.dependencies) {
@@ -245,7 +253,7 @@ Rules:
245
253
  }
246
254
 
247
255
  private topologicalSort(phases: MicroPhase[]): string[] {
248
- const phaseMap = new Map(phases.map(p => [p.id, p]));
256
+ const phaseMap = new Map(phases.map((p) => [p.id, p]));
249
257
  const visited = new Set<string>();
250
258
  const inStack = new Set<string>();
251
259
  const result: string[] = [];
@@ -280,7 +288,7 @@ Rules:
280
288
  private enforceParallelismLimit(phases: MicroPhase[], maxParallelism: number): void {
281
289
  // Build initial plan to see wave sizes
282
290
  const plan = this.buildExecutionPlan(phases);
283
- const phaseMap = new Map(phases.map(p => [p.id, p]));
291
+ const phaseMap = new Map(phases.map((p) => [p.id, p]));
284
292
 
285
293
  for (const wave of plan.waves) {
286
294
  if (wave.length <= maxParallelism) continue;