@telora/daemon 0.13.17 → 0.13.19

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 (45) hide show
  1. package/build-info.json +2 -2
  2. package/dist/assembly-resolvers.js +219 -0
  3. package/dist/assembly-resolvers.js.map +1 -1
  4. package/dist/delivery-lifecycle.d.ts.map +1 -1
  5. package/dist/delivery-lifecycle.js.map +1 -1
  6. package/dist/listener.d.ts.map +1 -1
  7. package/dist/listener.js +6 -61
  8. package/dist/listener.js.map +1 -1
  9. package/dist/loop-engine.d.ts +115 -0
  10. package/dist/loop-engine.d.ts.map +1 -0
  11. package/dist/loop-engine.js +498 -0
  12. package/dist/loop-engine.js.map +1 -0
  13. package/dist/loop-event-bus.d.ts +28 -0
  14. package/dist/loop-event-bus.d.ts.map +1 -0
  15. package/dist/loop-event-bus.js +35 -0
  16. package/dist/loop-event-bus.js.map +1 -0
  17. package/dist/loop-llm-client.d.ts +16 -0
  18. package/dist/loop-llm-client.d.ts.map +1 -0
  19. package/dist/loop-llm-client.js +80 -0
  20. package/dist/loop-llm-client.js.map +1 -0
  21. package/dist/loop-prompt-builder.d.ts +39 -0
  22. package/dist/loop-prompt-builder.d.ts.map +1 -0
  23. package/dist/loop-prompt-builder.js +168 -0
  24. package/dist/loop-prompt-builder.js.map +1 -0
  25. package/dist/loop-variance.d.ts +89 -0
  26. package/dist/loop-variance.d.ts.map +1 -0
  27. package/dist/loop-variance.js +283 -0
  28. package/dist/loop-variance.js.map +1 -0
  29. package/dist/review-spawner.d.ts +32 -0
  30. package/dist/review-spawner.d.ts.map +1 -0
  31. package/dist/review-spawner.js +153 -0
  32. package/dist/review-spawner.js.map +1 -0
  33. package/dist/state-cascade.d.ts.map +1 -1
  34. package/dist/state-cascade.js +16 -0
  35. package/dist/state-cascade.js.map +1 -1
  36. package/dist/strategy-completion.d.ts.map +1 -1
  37. package/dist/strategy-completion.js +22 -28
  38. package/dist/strategy-completion.js.map +1 -1
  39. package/dist/team-spawner.d.ts.map +1 -1
  40. package/dist/team-spawner.js +15 -6
  41. package/dist/team-spawner.js.map +1 -1
  42. package/dist/unified-shell.d.ts.map +1 -1
  43. package/dist/unified-shell.js +43 -0
  44. package/dist/unified-shell.js.map +1 -1
  45. package/package.json +1 -1
@@ -0,0 +1,115 @@
1
+ /**
2
+ * LoopEngine -- ExecutionEngine adapter for the Loop Agent (differential receiver).
3
+ *
4
+ * The Loop Agent is a monitoring-only engine that does NOT spawn Claude Code
5
+ * processes. It polls for strategies with loop data, computes variance between
6
+ * intent (loop documents/questions) and forecasted reality (metrics/projections),
7
+ * and when variance shifts enough, calls the LLM to re-evaluate loop data.
8
+ *
9
+ * Lifecycle (called by the process shell):
10
+ * 1. init(config) -- validate config, initialize API client
11
+ * 2. recoverFromCrash() -- no-op (no worktrees or processes to recover)
12
+ * 3. start() -- begin adaptive poll loop
13
+ * 4. stop() -- clear intervals, set shutting-down flag
14
+ * 5. shutdown() -- no-op (no processes to kill)
15
+ */
16
+ import type { ExecutionEngine, EngineHealth, ResourceUsage, BaseConfig, ResourceGovernor } from '@telora/daemon-core';
17
+ export interface LoopEventTriggerConfig {
18
+ /** Trigger on delivery completion. Default: true. */
19
+ deliveryCompleted: boolean;
20
+ /** Trigger on strategy status change. Default: true. */
21
+ strategyStatusChanged: boolean;
22
+ /** Trigger on review completion. Default: true. */
23
+ reviewCompleted: boolean;
24
+ }
25
+ export interface LoopEngineConfig {
26
+ /** Whether the loop engine is enabled. Default: true. */
27
+ enabled: boolean;
28
+ /** Poll interval when active strategies with loop data exist (ms). Default: 60000. */
29
+ activeIntervalMs: number;
30
+ /** Poll interval when idle (no active strategies). Default: 300000 (5min). */
31
+ idleIntervalMs: number;
32
+ /** Minimum interval between LLM evaluations per strategy (ms). Default: 300000 (5min). */
33
+ minEvaluationIntervalMs: number;
34
+ /** Force re-evaluation even without events after this threshold (ms). Default: 86400000 (24h). */
35
+ staleThresholdMs: number;
36
+ /** Event triggers that cause immediate re-evaluation. Default: all enabled. */
37
+ eventTriggers: LoopEventTriggerConfig;
38
+ }
39
+ export declare class LoopEngine implements ExecutionEngine {
40
+ readonly name = "loop";
41
+ private config;
42
+ private loopConfig;
43
+ private governor;
44
+ private pollTimeout;
45
+ private shuttingDown;
46
+ /** Number of active strategies with loop data from last poll. */
47
+ private activeStrategyCount;
48
+ /** Last poll timestamp for health reporting. */
49
+ private lastPollAt;
50
+ /** Per-strategy last LLM evaluation timestamp. */
51
+ private lastEvaluationAt;
52
+ /** Per-strategy last computed variance (for threshold comparison). */
53
+ private lastVariance;
54
+ /** Strategies that have been triggered by lifecycle events (pending immediate evaluation). */
55
+ private triggeredStrategies;
56
+ /** Cleanup function for event bus subscription. */
57
+ private unsubscribeEvents;
58
+ setGovernor(gov: ResourceGovernor): void;
59
+ init(config: BaseConfig & Record<string, unknown>): Promise<void>;
60
+ recoverFromCrash(): Promise<void>;
61
+ start(): Promise<void>;
62
+ stop(): void;
63
+ shutdown(): Promise<void>;
64
+ healthCheck(): EngineHealth;
65
+ getResourceUsage(): ResourceUsage;
66
+ private runPollCycle;
67
+ /**
68
+ * Poll a single product for strategies with loop data.
69
+ * Returns the number of active strategies processed.
70
+ */
71
+ private pollProduct;
72
+ /**
73
+ * Process a single strategy: load intent + reality, compute variance,
74
+ * optionally call LLM for updates, persist variance snapshot.
75
+ */
76
+ private processStrategy;
77
+ /**
78
+ * Load loop data (intent) for a strategy.
79
+ */
80
+ private loadIntentData;
81
+ /**
82
+ * Load reality data (metrics + projections) for a strategy.
83
+ */
84
+ private loadRealityData;
85
+ /**
86
+ * Persist variance snapshot to the database.
87
+ */
88
+ private persistVarianceSnapshot;
89
+ /**
90
+ * Determine whether to trigger an LLM update based on:
91
+ * - Minimum interval between evaluations (debounce)
92
+ * - Event-aware: new activity since last evaluation
93
+ * - Variance change beyond threshold
94
+ * - Stale loop data
95
+ */
96
+ private shouldTriggerLLMUpdate;
97
+ /**
98
+ * Run the LLM to re-evaluate loop data given current variance.
99
+ */
100
+ private runLLMUpdate;
101
+ /**
102
+ * Apply parsed LLM updates back to loop data via edge function.
103
+ */
104
+ private applyLoopUpdates;
105
+ /**
106
+ * Handle a lifecycle event from the strategy engine.
107
+ * Marks the strategy for immediate re-evaluation on the next poll cycle.
108
+ */
109
+ private handleLifecycleEvent;
110
+ /**
111
+ * Schedule the next poll cycle using adaptive interval.
112
+ */
113
+ private scheduleNextPoll;
114
+ }
115
+ //# sourceMappingURL=loop-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop-engine.d.ts","sourceRoot":"","sources":["../src/loop-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,aAAa,EACb,UAAU,EACV,gBAAgB,EACjB,MAAM,qBAAqB,CAAC;AAY7B,MAAM,WAAW,sBAAsB;IACrC,qDAAqD;IACrD,iBAAiB,EAAE,OAAO,CAAC;IAC3B,wDAAwD;IACxD,qBAAqB,EAAE,OAAO,CAAC;IAC/B,mDAAmD;IACnD,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,yDAAyD;IACzD,OAAO,EAAE,OAAO,CAAC;IACjB,sFAAsF;IACtF,gBAAgB,EAAE,MAAM,CAAC;IACzB,8EAA8E;IAC9E,cAAc,EAAE,MAAM,CAAC;IACvB,0FAA0F;IAC1F,uBAAuB,EAAE,MAAM,CAAC;IAChC,kGAAkG;IAClG,gBAAgB,EAAE,MAAM,CAAC;IACzB,+EAA+E;IAC/E,aAAa,EAAE,sBAAsB,CAAC;CACvC;AA2DD,qBAAa,UAAW,YAAW,eAAe;IAChD,QAAQ,CAAC,IAAI,UAAU;IAEvB,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,UAAU,CAAgD;IAClE,OAAO,CAAC,QAAQ,CAAiC;IAEjD,OAAO,CAAC,WAAW,CAA8C;IACjE,OAAO,CAAC,YAAY,CAAS;IAE7B,iEAAiE;IACjE,OAAO,CAAC,mBAAmB,CAAK;IAEhC,gDAAgD;IAChD,OAAO,CAAC,UAAU,CAAqB;IAEvC,kDAAkD;IAClD,OAAO,CAAC,gBAAgB,CAAkC;IAE1D,sEAAsE;IACtE,OAAO,CAAC,YAAY,CAA0C;IAE9D,8FAA8F;IAC9F,OAAO,CAAC,mBAAmB,CAA0B;IAErD,mDAAmD;IACnD,OAAO,CAAC,iBAAiB,CAA6B;IAMtD,WAAW,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI;IASlC,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAuCjE,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAQjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB5B,IAAI,IAAI,IAAI;IAgBN,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ/B,WAAW,IAAI,YAAY;IAkB3B,gBAAgB,IAAI,aAAa;YAWnB,YAAY;IAqB1B;;;OAGG;YACW,WAAW;IAgCzB;;;OAGG;YACW,eAAe;IAgC7B;;OAEG;YACW,cAAc;IA6C5B;;OAEG;YACW,eAAe;IAe7B;;OAEG;YACW,uBAAuB;IAerC;;;;;;OAMG;IACH,OAAO,CAAC,sBAAsB;IAoE9B;;OAEG;YACW,YAAY;IAmC1B;;OAEG;YACW,gBAAgB;IAsD9B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAe5B;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAqBzB"}
@@ -0,0 +1,498 @@
1
+ /**
2
+ * LoopEngine -- ExecutionEngine adapter for the Loop Agent (differential receiver).
3
+ *
4
+ * The Loop Agent is a monitoring-only engine that does NOT spawn Claude Code
5
+ * processes. It polls for strategies with loop data, computes variance between
6
+ * intent (loop documents/questions) and forecasted reality (metrics/projections),
7
+ * and when variance shifts enough, calls the LLM to re-evaluate loop data.
8
+ *
9
+ * Lifecycle (called by the process shell):
10
+ * 1. init(config) -- validate config, initialize API client
11
+ * 2. recoverFromCrash() -- no-op (no worktrees or processes to recover)
12
+ * 3. start() -- begin adaptive poll loop
13
+ * 4. stop() -- clear intervals, set shutting-down flag
14
+ * 5. shutdown() -- no-op (no processes to kill)
15
+ */
16
+ import { initSupabase, callApi } from './queries/shared.js';
17
+ import { computeVariance } from './loop-variance.js';
18
+ import { buildLoopUpdatePrompt, parseLoopUpdateResponse } from './loop-prompt-builder.js';
19
+ import { callLoopLLM } from './loop-llm-client.js';
20
+ import { onLoopTrigger } from './loop-event-bus.js';
21
+ const DEFAULT_EVENT_TRIGGERS = {
22
+ deliveryCompleted: true,
23
+ strategyStatusChanged: true,
24
+ reviewCompleted: true,
25
+ };
26
+ const DEFAULT_LOOP_CONFIG = {
27
+ enabled: true,
28
+ activeIntervalMs: 60_000,
29
+ idleIntervalMs: 300_000,
30
+ minEvaluationIntervalMs: 300_000,
31
+ staleThresholdMs: 86_400_000,
32
+ eventTriggers: { ...DEFAULT_EVENT_TRIGGERS },
33
+ };
34
+ // ---------------------------------------------------------------------------
35
+ // LoopEngine
36
+ // ---------------------------------------------------------------------------
37
+ export class LoopEngine {
38
+ name = 'loop';
39
+ config = null;
40
+ loopConfig = { ...DEFAULT_LOOP_CONFIG };
41
+ governor = null;
42
+ pollTimeout = null;
43
+ shuttingDown = false;
44
+ /** Number of active strategies with loop data from last poll. */
45
+ activeStrategyCount = 0;
46
+ /** Last poll timestamp for health reporting. */
47
+ lastPollAt = null;
48
+ /** Per-strategy last LLM evaluation timestamp. */
49
+ lastEvaluationAt = new Map();
50
+ /** Per-strategy last computed variance (for threshold comparison). */
51
+ lastVariance = new Map();
52
+ /** Strategies that have been triggered by lifecycle events (pending immediate evaluation). */
53
+ triggeredStrategies = new Set();
54
+ /** Cleanup function for event bus subscription. */
55
+ unsubscribeEvents = null;
56
+ // -----------------------------------------------------------------------
57
+ // setGovernor
58
+ // -----------------------------------------------------------------------
59
+ setGovernor(gov) {
60
+ this.governor = gov;
61
+ // Loop engine does not acquire governor slots (no Claude processes)
62
+ }
63
+ // -----------------------------------------------------------------------
64
+ // init
65
+ // -----------------------------------------------------------------------
66
+ async init(config) {
67
+ this.config = config;
68
+ // Resolve loop config from the raw config
69
+ const loopSection = config.loop;
70
+ if (loopSection && typeof loopSection === 'object') {
71
+ const lc = loopSection;
72
+ // Parse event triggers config
73
+ const etRaw = lc.eventTriggers;
74
+ let eventTriggers = { ...DEFAULT_EVENT_TRIGGERS };
75
+ if (etRaw && typeof etRaw === 'object') {
76
+ const et = etRaw;
77
+ eventTriggers = {
78
+ deliveryCompleted: typeof et.deliveryCompleted === 'boolean' ? et.deliveryCompleted : DEFAULT_EVENT_TRIGGERS.deliveryCompleted,
79
+ strategyStatusChanged: typeof et.strategyStatusChanged === 'boolean' ? et.strategyStatusChanged : DEFAULT_EVENT_TRIGGERS.strategyStatusChanged,
80
+ reviewCompleted: typeof et.reviewCompleted === 'boolean' ? et.reviewCompleted : DEFAULT_EVENT_TRIGGERS.reviewCompleted,
81
+ };
82
+ }
83
+ this.loopConfig = {
84
+ enabled: typeof lc.enabled === 'boolean' ? lc.enabled : DEFAULT_LOOP_CONFIG.enabled,
85
+ activeIntervalMs: typeof lc.activeIntervalMs === 'number' ? lc.activeIntervalMs : DEFAULT_LOOP_CONFIG.activeIntervalMs,
86
+ idleIntervalMs: typeof lc.idleIntervalMs === 'number' ? lc.idleIntervalMs : DEFAULT_LOOP_CONFIG.idleIntervalMs,
87
+ minEvaluationIntervalMs: typeof lc.minEvaluationIntervalMs === 'number' ? lc.minEvaluationIntervalMs : DEFAULT_LOOP_CONFIG.minEvaluationIntervalMs,
88
+ staleThresholdMs: typeof lc.staleThresholdMs === 'number' ? lc.staleThresholdMs : DEFAULT_LOOP_CONFIG.staleThresholdMs,
89
+ eventTriggers,
90
+ };
91
+ }
92
+ // Initialize API client (idempotent)
93
+ initSupabase(this.config);
94
+ console.log('[Loop] Engine initialized');
95
+ }
96
+ // -----------------------------------------------------------------------
97
+ // recoverFromCrash
98
+ // -----------------------------------------------------------------------
99
+ async recoverFromCrash() {
100
+ console.log('[Loop] No crash recovery needed (monitoring-only engine)');
101
+ }
102
+ // -----------------------------------------------------------------------
103
+ // start
104
+ // -----------------------------------------------------------------------
105
+ async start() {
106
+ this.shuttingDown = false;
107
+ // Subscribe to lifecycle events from the strategy engine
108
+ this.unsubscribeEvents = onLoopTrigger((event) => this.handleLifecycleEvent(event));
109
+ // Run initial poll immediately
110
+ await this.runPollCycle();
111
+ // Schedule next poll with adaptive interval
112
+ this.scheduleNextPoll();
113
+ console.log('[Loop] Engine started (adaptive polling active, event triggers subscribed)');
114
+ }
115
+ // -----------------------------------------------------------------------
116
+ // stop
117
+ // -----------------------------------------------------------------------
118
+ stop() {
119
+ this.shuttingDown = true;
120
+ if (this.pollTimeout !== null) {
121
+ clearTimeout(this.pollTimeout);
122
+ this.pollTimeout = null;
123
+ }
124
+ if (this.unsubscribeEvents) {
125
+ this.unsubscribeEvents();
126
+ this.unsubscribeEvents = null;
127
+ }
128
+ }
129
+ // -----------------------------------------------------------------------
130
+ // shutdown
131
+ // -----------------------------------------------------------------------
132
+ async shutdown() {
133
+ console.log('[Loop] Shutdown complete');
134
+ }
135
+ // -----------------------------------------------------------------------
136
+ // healthCheck
137
+ // -----------------------------------------------------------------------
138
+ healthCheck() {
139
+ return {
140
+ status: this.config ? 'healthy' : 'unhealthy',
141
+ activeWorkItems: this.activeStrategyCount,
142
+ details: {
143
+ activeStrategyCount: this.activeStrategyCount,
144
+ lastPollAt: this.lastPollAt?.toISOString() ?? null,
145
+ currentPollIntervalMs: this.activeStrategyCount > 0
146
+ ? this.loopConfig.activeIntervalMs
147
+ : this.loopConfig.idleIntervalMs,
148
+ },
149
+ };
150
+ }
151
+ // -----------------------------------------------------------------------
152
+ // getResourceUsage
153
+ // -----------------------------------------------------------------------
154
+ getResourceUsage() {
155
+ return {
156
+ activeClaudeProcesses: 0,
157
+ activeWorktrees: 0,
158
+ };
159
+ }
160
+ // -----------------------------------------------------------------------
161
+ // Private: poll cycle
162
+ // -----------------------------------------------------------------------
163
+ async runPollCycle() {
164
+ const config = this.config;
165
+ if (!config)
166
+ return;
167
+ this.lastPollAt = new Date();
168
+ let totalActiveStrategies = 0;
169
+ for (const product of config.products) {
170
+ try {
171
+ const count = await this.pollProduct(product.id);
172
+ totalActiveStrategies += count;
173
+ }
174
+ catch (err) {
175
+ console.log(`[Loop] Poll failed for product ${product.id}: ${err instanceof Error ? err.message : String(err)}`);
176
+ }
177
+ }
178
+ this.activeStrategyCount = totalActiveStrategies;
179
+ }
180
+ /**
181
+ * Poll a single product for strategies with loop data.
182
+ * Returns the number of active strategies processed.
183
+ */
184
+ async pollProduct(productId) {
185
+ // Fetch active strategies for this product
186
+ let strategies;
187
+ try {
188
+ const result = await callApi('strategy_list', {
189
+ productId,
190
+ status: 'active',
191
+ });
192
+ strategies = result.items ?? [];
193
+ }
194
+ catch (err) {
195
+ console.log(`[Loop] Failed to fetch strategies for product ${productId}: ${err instanceof Error ? err.message : String(err)}`);
196
+ return 0;
197
+ }
198
+ if (strategies.length === 0)
199
+ return 0;
200
+ let processed = 0;
201
+ for (const strategy of strategies) {
202
+ try {
203
+ await this.processStrategy(strategy);
204
+ processed++;
205
+ }
206
+ catch (err) {
207
+ console.log(`[Loop] Failed to process strategy ${strategy.id}: ${err instanceof Error ? err.message : String(err)}`);
208
+ }
209
+ }
210
+ return processed;
211
+ }
212
+ /**
213
+ * Process a single strategy: load intent + reality, compute variance,
214
+ * optionally call LLM for updates, persist variance snapshot.
215
+ */
216
+ async processStrategy(strategy) {
217
+ // 1. Load intent data (loop documents + questions + answers)
218
+ const intent = await this.loadIntentData(strategy.id);
219
+ // Skip strategies with no loop data (not yet initialized)
220
+ if (intent.documents.length === 0 && intent.questions.length === 0) {
221
+ return;
222
+ }
223
+ // 2. Load reality data (metrics + projections)
224
+ const reality = await this.loadRealityData(strategy.id);
225
+ // 3. Compute variance (pass previous for trend direction)
226
+ const previousVariance = this.lastVariance.get(strategy.id) ?? null;
227
+ const variance = computeVariance(intent, reality, strategy.targetDate ?? null, previousVariance);
228
+ // 4. Persist variance snapshot
229
+ await this.persistVarianceSnapshot(strategy, variance);
230
+ // 5. Determine if LLM update is needed
231
+ const shouldUpdate = this.shouldTriggerLLMUpdate(strategy.id, variance, reality);
232
+ if (shouldUpdate) {
233
+ console.log(`[Loop] Triggering LLM update for strategy "${strategy.name}" (${strategy.id.slice(0, 8)}) -- lock: ${variance.lockStatus}`);
234
+ await this.runLLMUpdate(strategy, intent, reality, variance);
235
+ this.lastEvaluationAt.set(strategy.id, Date.now());
236
+ }
237
+ // 6. Store variance for threshold comparison
238
+ this.lastVariance.set(strategy.id, variance);
239
+ }
240
+ /**
241
+ * Load loop data (intent) for a strategy.
242
+ */
243
+ async loadIntentData(strategyId) {
244
+ const [docsResult, questionsResult, personaResult] = await Promise.all([
245
+ callApi('loop_document_list', {
246
+ entityType: 'strategy',
247
+ entityId: strategyId,
248
+ detail: 'full',
249
+ limit: 50,
250
+ }).catch(() => ({ items: [] })),
251
+ callApi('loop_question_list', {
252
+ entityType: 'strategy',
253
+ entityId: strategyId,
254
+ detail: 'full',
255
+ limit: 50,
256
+ }).catch(() => ({ items: [] })),
257
+ callApi('loop_persona_get', {
258
+ entityType: 'strategy',
259
+ entityId: strategyId,
260
+ }).catch(() => ({ persona: null })),
261
+ ]);
262
+ // Fetch answers for each question
263
+ const questionsWithAnswers = await Promise.all((questionsResult.items ?? []).map(async (q) => {
264
+ try {
265
+ const answerResult = await callApi('loop_answer_get', {
266
+ questionId: q.id,
267
+ });
268
+ return {
269
+ ...q,
270
+ answer: answerResult.answer?.content ?? null,
271
+ };
272
+ }
273
+ catch {
274
+ return { ...q, answer: null };
275
+ }
276
+ }));
277
+ return {
278
+ documents: docsResult.items ?? [],
279
+ questions: questionsWithAnswers,
280
+ persona: personaResult.persona?.content ?? null,
281
+ proposedPersona: personaResult.persona?.proposedContent ?? null,
282
+ };
283
+ }
284
+ /**
285
+ * Load reality data (metrics + projections) for a strategy.
286
+ */
287
+ async loadRealityData(strategyId) {
288
+ try {
289
+ const result = await callApi('reality_metrics_strategy', {
290
+ strategyId,
291
+ });
292
+ return {
293
+ metrics: result.metrics,
294
+ projections: result.projections,
295
+ };
296
+ }
297
+ catch (err) {
298
+ console.log(`[Loop] Failed to load reality data for strategy ${strategyId}: ${err instanceof Error ? err.message : String(err)}`);
299
+ return { metrics: null, projections: { completion: null, cost: null } };
300
+ }
301
+ }
302
+ /**
303
+ * Persist variance snapshot to the database.
304
+ */
305
+ async persistVarianceSnapshot(strategy, variance) {
306
+ try {
307
+ await callApi('loop_variance_upsert', {
308
+ entityType: 'strategy',
309
+ entityId: strategy.id,
310
+ varianceData: variance,
311
+ });
312
+ }
313
+ catch (err) {
314
+ console.log(`[Loop] Failed to persist variance snapshot for strategy ${strategy.id}: ${err instanceof Error ? err.message : String(err)}`);
315
+ }
316
+ }
317
+ /**
318
+ * Determine whether to trigger an LLM update based on:
319
+ * - Minimum interval between evaluations (debounce)
320
+ * - Event-aware: new activity since last evaluation
321
+ * - Variance change beyond threshold
322
+ * - Stale loop data
323
+ */
324
+ shouldTriggerLLMUpdate(strategyId, variance, reality) {
325
+ const now = Date.now();
326
+ const lastEval = this.lastEvaluationAt.get(strategyId) ?? 0;
327
+ // Enforce minimum interval (debounce bursts)
328
+ if (now - lastEval < this.loopConfig.minEvaluationIntervalMs) {
329
+ return false;
330
+ }
331
+ // Force update if stale
332
+ if (now - lastEval > this.loopConfig.staleThresholdMs) {
333
+ return true;
334
+ }
335
+ // Event-driven trigger: lifecycle event flagged this strategy for re-evaluation
336
+ if (this.triggeredStrategies.has(strategyId)) {
337
+ this.triggeredStrategies.delete(strategyId);
338
+ return true;
339
+ }
340
+ // Event-aware trigger: check if new activity occurred since last evaluation
341
+ // Uses last_session_at from reality metrics as a proxy for recent events
342
+ const metrics = reality.metrics;
343
+ if (metrics?.last_session_at && lastEval > 0) {
344
+ const lastSessionAt = new Date(metrics.last_session_at).getTime();
345
+ if (lastSessionAt > lastEval) {
346
+ return true; // New agent activity since last evaluation
347
+ }
348
+ }
349
+ // Compare with previous variance
350
+ const prevVariance = this.lastVariance.get(strategyId);
351
+ if (!prevVariance) {
352
+ // First evaluation -- always run
353
+ return true;
354
+ }
355
+ // Trigger if lock status changed
356
+ if (prevVariance.lockStatus !== variance.lockStatus) {
357
+ return true;
358
+ }
359
+ // Trigger if any noise flag changed
360
+ if (JSON.stringify(prevVariance.noiseFlags) !== JSON.stringify(variance.noiseFlags)) {
361
+ return true;
362
+ }
363
+ // Trigger if schedule variance crossed a threshold (>= 2 day change)
364
+ const prevScheduleDays = prevVariance.dimensions.schedule?.varianceDays ?? 0;
365
+ const currScheduleDays = variance.dimensions.schedule?.varianceDays ?? 0;
366
+ if (Math.abs(currScheduleDays - prevScheduleDays) >= 2) {
367
+ return true;
368
+ }
369
+ // Trigger if throughput trend changed
370
+ const prevTrend = prevVariance.dimensions.throughput?.trend;
371
+ const currTrend = variance.dimensions.throughput?.trend;
372
+ if (prevTrend && currTrend && prevTrend !== currTrend) {
373
+ return true;
374
+ }
375
+ return false;
376
+ }
377
+ /**
378
+ * Run the LLM to re-evaluate loop data given current variance.
379
+ */
380
+ async runLLMUpdate(strategy, intent, reality, variance) {
381
+ try {
382
+ // Build the prompt
383
+ const prompt = buildLoopUpdatePrompt(intent, reality, variance);
384
+ // Call the LLM
385
+ const rawResponse = await callLoopLLM(strategy.organizationId, prompt);
386
+ if (!rawResponse) {
387
+ console.log(`[Loop] LLM returned empty response for strategy ${strategy.id}`);
388
+ return;
389
+ }
390
+ // Parse the response
391
+ const updates = parseLoopUpdateResponse(rawResponse);
392
+ // Write updates back
393
+ await this.applyLoopUpdates(strategy.id, updates);
394
+ console.log(`[Loop] Applied updates for strategy "${strategy.name}": ` +
395
+ `${updates.documentReorders.length} re-ranks, ` +
396
+ `${updates.answerUpdates.length} answers, ` +
397
+ `${updates.newQuestions.length} new questions` +
398
+ `${updates.personaProposal ? ', 1 persona proposal' : ''}`);
399
+ }
400
+ catch (err) {
401
+ console.log(`[Loop] LLM update failed for strategy ${strategy.id}: ${err instanceof Error ? err.message : String(err)}`);
402
+ }
403
+ }
404
+ /**
405
+ * Apply parsed LLM updates back to loop data via edge function.
406
+ */
407
+ async applyLoopUpdates(strategyId, updates) {
408
+ // Re-rank documents
409
+ if (updates.documentReorders.length > 0) {
410
+ try {
411
+ await callApi('loop_document_reorder', {
412
+ entityType: 'strategy',
413
+ entityId: strategyId,
414
+ documentIds: updates.documentReorders,
415
+ });
416
+ }
417
+ catch (err) {
418
+ console.log(`[Loop] Failed to reorder documents: ${err instanceof Error ? err.message : String(err)}`);
419
+ }
420
+ }
421
+ // Update answers
422
+ for (const answerUpdate of updates.answerUpdates) {
423
+ try {
424
+ await callApi('loop_answer_upsert', {
425
+ questionId: answerUpdate.questionId,
426
+ content: answerUpdate.content,
427
+ });
428
+ }
429
+ catch (err) {
430
+ console.log(`[Loop] Failed to update answer for question ${answerUpdate.questionId}: ${err instanceof Error ? err.message : String(err)}`);
431
+ }
432
+ }
433
+ // Create new questions
434
+ for (const newQuestion of updates.newQuestions) {
435
+ try {
436
+ await callApi('loop_question_create', {
437
+ entityType: 'strategy',
438
+ entityId: strategyId,
439
+ text: newQuestion.text,
440
+ questionType: 'generated',
441
+ });
442
+ }
443
+ catch (err) {
444
+ console.log(`[Loop] Failed to create question: ${err instanceof Error ? err.message : String(err)}`);
445
+ }
446
+ }
447
+ // Propose persona adjustment
448
+ if (updates.personaProposal) {
449
+ try {
450
+ await callApi('loop_persona_propose', {
451
+ entityType: 'strategy',
452
+ entityId: strategyId,
453
+ proposedContent: updates.personaProposal,
454
+ });
455
+ }
456
+ catch (err) {
457
+ console.log(`[Loop] Failed to propose persona: ${err instanceof Error ? err.message : String(err)}`);
458
+ }
459
+ }
460
+ }
461
+ /**
462
+ * Handle a lifecycle event from the strategy engine.
463
+ * Marks the strategy for immediate re-evaluation on the next poll cycle.
464
+ */
465
+ handleLifecycleEvent(event) {
466
+ const triggers = this.loopConfig.eventTriggers;
467
+ // Check if this event type is enabled
468
+ const eventEnabled = (event.type === 'delivery_completed' && triggers.deliveryCompleted) ||
469
+ (event.type === 'strategy_status_changed' && triggers.strategyStatusChanged) ||
470
+ (event.type === 'review_completed' && triggers.reviewCompleted);
471
+ if (!eventEnabled)
472
+ return;
473
+ this.triggeredStrategies.add(event.strategyId);
474
+ console.log(`[Loop] Event trigger: ${event.type} for strategy ${event.strategyId.slice(0, 8)}${event.detail ? ` (${event.detail})` : ''}`);
475
+ }
476
+ /**
477
+ * Schedule the next poll cycle using adaptive interval.
478
+ */
479
+ scheduleNextPoll() {
480
+ if (this.shuttingDown)
481
+ return;
482
+ const intervalMs = this.activeStrategyCount > 0
483
+ ? this.loopConfig.activeIntervalMs
484
+ : this.loopConfig.idleIntervalMs;
485
+ this.pollTimeout = setTimeout(async () => {
486
+ if (this.shuttingDown)
487
+ return;
488
+ try {
489
+ await this.runPollCycle();
490
+ }
491
+ catch (err) {
492
+ console.log(`[Loop] Poll cycle error: ${err instanceof Error ? err.message : String(err)}`);
493
+ }
494
+ this.scheduleNextPoll();
495
+ }, intervalMs);
496
+ }
497
+ }
498
+ //# sourceMappingURL=loop-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop-engine.js","sourceRoot":"","sources":["../src/loop-engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Loop Event Bus -- lightweight pub/sub for lifecycle events that trigger
3
+ * Loop Agent re-evaluation.
4
+ *
5
+ * The strategy engine emits events when deliveries complete, strategies change,
6
+ * or reviews finish. The Loop Engine subscribes and schedules immediate
7
+ * re-evaluation for the affected strategy (subject to debounce).
8
+ *
9
+ * Singleton pattern: both emitter and subscriber import this module.
10
+ */
11
+ export type LoopTriggerEventType = 'delivery_completed' | 'strategy_status_changed' | 'review_completed';
12
+ export interface LoopTriggerEvent {
13
+ type: LoopTriggerEventType;
14
+ strategyId: string;
15
+ /** Optional context about what triggered the event. */
16
+ detail?: string;
17
+ }
18
+ /**
19
+ * Emit a lifecycle event that may trigger Loop Agent re-evaluation.
20
+ * Called from strategy engine components (delivery-lifecycle, state-cascade, etc.).
21
+ */
22
+ export declare function emitLoopTrigger(event: LoopTriggerEvent): void;
23
+ /**
24
+ * Subscribe to lifecycle events. Called by LoopEngine on start.
25
+ * Returns a cleanup function to unsubscribe.
26
+ */
27
+ export declare function onLoopTrigger(handler: (event: LoopTriggerEvent) => void): () => void;
28
+ //# sourceMappingURL=loop-event-bus.d.ts.map