@agenr/skeln-plugin 3.3.0 → 2026.6.3

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 (34) hide show
  1. package/dist/build-before-turn-artifact-NPUHVWFE.js +71 -0
  2. package/dist/build-recall-artifact-F3LS3PZX.js +62 -0
  3. package/dist/chunk-5AXMFBHR.js +14 -0
  4. package/dist/chunk-5AYIXQRF.js +4452 -0
  5. package/dist/{chunk-Z5X7T4QZ.js → chunk-5TIP2EPP.js} +1519 -2565
  6. package/dist/{chunk-5LADPJ4C.js → chunk-GAERET5Q.js} +138 -504
  7. package/dist/chunk-GF3PX3VM.js +41 -0
  8. package/dist/chunk-GKZQ5AG5.js +44 -0
  9. package/dist/chunk-IBPS64W3.js +1069 -0
  10. package/dist/{chunk-ZYADFKX3.js → chunk-MC3C2XM5.js} +34 -1
  11. package/dist/chunk-NSLTJBUC.js +270 -0
  12. package/dist/chunk-OJSIZDZD.js +9 -0
  13. package/dist/chunk-OWGQWQUP.js +45 -0
  14. package/dist/chunk-SIY3JA7T.js +3062 -0
  15. package/dist/{chunk-M5M65AYP.js → chunk-SOQW7356.js} +271 -1934
  16. package/dist/chunk-U74RE3L7.js +3233 -0
  17. package/dist/chunk-VBPYU7GO.js +597 -0
  18. package/dist/chunk-VTHBPXDQ.js +1750 -0
  19. package/dist/{chunk-KH52KJSJ.js → chunk-XFJ4S4G2.js} +844 -39
  20. package/dist/chunk-Y5NB3FTH.js +106 -0
  21. package/dist/{chunk-RYMSM3OS.js → chunk-ZX55JBV2.js} +1710 -322
  22. package/dist/claim-slot-policy-CdrW_1l4.d.ts +13 -0
  23. package/dist/index.d.ts +630 -51
  24. package/dist/index.js +852 -4683
  25. package/dist/lifecycle-checkpoint-IAC5FCQU.js +154 -0
  26. package/dist/{claim-slot-policy-CQ-h0GaV.d.ts → ports-C4QkwDBS.d.ts} +168 -78
  27. package/dist/scan-6JKPOQHD.js +6 -0
  28. package/dist/service-EKFACEN6.js +15 -0
  29. package/dist/service-RHNB5AEQ.js +861 -0
  30. package/dist/sink-AUAAWC5O.js +8 -0
  31. package/package.json +1 -1
  32. package/dist/cli.d.ts +0 -1
  33. package/dist/internal-eval-server.d.ts +0 -1
  34. package/dist/internal-recall-eval-server.d.ts +0 -1
@@ -0,0 +1,3062 @@
1
+ import {
2
+ normalizeOptionalString
3
+ } from "./chunk-OJSIZDZD.js";
4
+ import {
5
+ CLOSE_MANAGED_WORKING_SET_STATUSES,
6
+ CURRENT_WORKING_SET_STATUSES,
7
+ OPEN_WORKING_SET_STATUSES,
8
+ WORKING_MEMORY_DISABLED_MESSAGE,
9
+ createFailure,
10
+ createWorkingContextStubProjection,
11
+ normalizeBoundedLimit
12
+ } from "./chunk-NSLTJBUC.js";
13
+ import {
14
+ CLAIM_KEY_DESCRIPTION,
15
+ ENTRY_TYPE_DESCRIPTION,
16
+ EXPIRY_DESCRIPTION,
17
+ RECALL_MODES,
18
+ RECALL_MODE_SCHEMA_DESCRIPTION,
19
+ UPDATE_EXPIRY_DESCRIPTION,
20
+ asRecord,
21
+ createDreamPort,
22
+ createMemoryRepository,
23
+ formatErrorMessage,
24
+ ingestEpisodeTranscript,
25
+ normalizeStringArray,
26
+ parseDurableKind,
27
+ parseDurableKinds,
28
+ parseExpiry,
29
+ parseRecallMode,
30
+ storeDurablesDetailed
31
+ } from "./chunk-U74RE3L7.js";
32
+ import {
33
+ containsAgenrMemoryContext,
34
+ createSessionStartRepository,
35
+ formatInjectionEntryBodyLines,
36
+ formatInjectionEntryHeader,
37
+ listActiveAbstainDirectives,
38
+ listActiveSessionStartProactiveDirectives,
39
+ listActiveTopicProactiveDirectives,
40
+ stripAgenrMemoryContext,
41
+ wrapAgenrMemoryContext
42
+ } from "./chunk-XFJ4S4G2.js";
43
+ import {
44
+ ENTRY_PREVIEW_MAX_CHARS,
45
+ assertEntryFetchableContentLength,
46
+ attachCrossEncoderPort,
47
+ buildEntryRecallPreview,
48
+ buildFetchToolDetails,
49
+ buildMemoryToolWarningDetails,
50
+ createDatabase,
51
+ createEmbeddingClient,
52
+ createLlmClient,
53
+ createOpenAICrossEncoder,
54
+ createRecallAdapter,
55
+ formatFetchedEntryText,
56
+ formatMemoryToolOutcomeText,
57
+ readNumber,
58
+ readOptionalString,
59
+ readRequiredString,
60
+ recallResultHasTruncatedEntryPreviews,
61
+ resolveCrossEncoderApiKey,
62
+ resolveEmbeddingApiKey,
63
+ resolveEmbeddingModel,
64
+ resolveLlmApiKey,
65
+ resolveModel,
66
+ runUnifiedRecall,
67
+ truncate
68
+ } from "./chunk-5TIP2EPP.js";
69
+ import {
70
+ isEpisodeWriteInProgress,
71
+ resolveDurableProjectScope,
72
+ tryAcquireDreamingRunLock,
73
+ withEpisodeWriteGuard,
74
+ withHeldDreamingRunLock
75
+ } from "./chunk-SOQW7356.js";
76
+ import {
77
+ AGENR_FEATURE_FLAG_KEYS,
78
+ DEFAULT_AGENR_FEATURE_FLAGS,
79
+ DEFAULT_DREAMING_IMPORTANCE_THRESHOLD,
80
+ DEFAULT_DREAMING_MIN_INTERVAL_MINUTES,
81
+ DURABLE_KINDS,
82
+ normalizeManualClaimKeyUpdate,
83
+ parseDirectiveTrigger,
84
+ readConfig,
85
+ resolveClaimExtractionConfig,
86
+ resolveConfigPath,
87
+ resolveDbPath
88
+ } from "./chunk-VTHBPXDQ.js";
89
+ import {
90
+ validateTemporalValidityRange
91
+ } from "./chunk-VBPYU7GO.js";
92
+
93
+ // src/adapters/shared/session-memory-routing.ts
94
+ function logSessionMemoryTriggerResult(result) {
95
+ if (result.accepted || result.reason === "feature_disabled") {
96
+ return;
97
+ }
98
+ console.warn(`[agenr] session-memory trigger rejected: ${result.reason} (${result.message})`);
99
+ }
100
+ async function routeSessionMemoryTriggerSafely(params) {
101
+ try {
102
+ const scope = await params.resolveScope();
103
+ logSessionMemoryTriggerResult(await params.routeTrigger(scope));
104
+ } catch (error) {
105
+ console.warn(`[agenr] session-memory trigger failed: ${formatErrorMessage(error)}`);
106
+ }
107
+ }
108
+ function createSessionMemoryTriggerRouter(servicesPromise, buildEvent2) {
109
+ return async (scope) => {
110
+ const services = await servicesPromise;
111
+ return services.routeSessionMemoryTrigger(buildEvent2(scope));
112
+ };
113
+ }
114
+
115
+ // src/app/plugin-runtime/session-tracking.ts
116
+ function resolveSessionIdentityKey(sessionId, sessionKey) {
117
+ const normalizedSessionId = sessionId?.trim();
118
+ if (normalizedSessionId) {
119
+ return `session:${normalizedSessionId}`;
120
+ }
121
+ const normalizedSessionKey = sessionKey?.trim();
122
+ if (normalizedSessionKey) {
123
+ return `key:${normalizedSessionKey}`;
124
+ }
125
+ return void 0;
126
+ }
127
+ function createSessionStartTracker() {
128
+ const seenSessionIdentities = /* @__PURE__ */ new Set();
129
+ return {
130
+ consume(sessionId, sessionKey) {
131
+ const identityKey = resolveSessionIdentityKey(sessionId, sessionKey);
132
+ if (!identityKey) {
133
+ return {
134
+ isFirst: false,
135
+ activeCount: seenSessionIdentities.size
136
+ };
137
+ }
138
+ if (seenSessionIdentities.has(identityKey)) {
139
+ return {
140
+ isFirst: false,
141
+ activeCount: seenSessionIdentities.size
142
+ };
143
+ }
144
+ seenSessionIdentities.add(identityKey);
145
+ return {
146
+ isFirst: true,
147
+ activeCount: seenSessionIdentities.size
148
+ };
149
+ }
150
+ };
151
+ }
152
+
153
+ // src/app/plugin-runtime/session-lifecycle-intake.ts
154
+ function createSessionLifecycleIntakeTracker() {
155
+ const pendingBySession = /* @__PURE__ */ new Map();
156
+ return {
157
+ track(sessionId, sessionKey, work) {
158
+ const identityKey = resolveSessionIdentityKey(sessionId, sessionKey);
159
+ if (!identityKey) {
160
+ return work;
161
+ }
162
+ const tracked = work.finally(() => {
163
+ if (pendingBySession.get(identityKey) === tracked) {
164
+ pendingBySession.delete(identityKey);
165
+ }
166
+ });
167
+ pendingBySession.set(identityKey, tracked);
168
+ return tracked;
169
+ },
170
+ async wait(sessionId, sessionKey) {
171
+ const identityKey = resolveSessionIdentityKey(sessionId, sessionKey);
172
+ if (!identityKey) {
173
+ return;
174
+ }
175
+ const pending = pendingBySession.get(identityKey);
176
+ if (pending) {
177
+ await pending;
178
+ }
179
+ },
180
+ async clear(sessionId, sessionKey) {
181
+ await this.wait(sessionId, sessionKey);
182
+ const identityKey = resolveSessionIdentityKey(sessionId, sessionKey);
183
+ if (identityKey) {
184
+ pendingBySession.delete(identityKey);
185
+ }
186
+ }
187
+ };
188
+ }
189
+
190
+ // src/adapters/shared/compaction-prompt-tracker.ts
191
+ function createCompactionPromptTracker() {
192
+ const injectedBySession = /* @__PURE__ */ new Map();
193
+ return {
194
+ shouldInject(sessionId, sessionKey, artifactSourceId) {
195
+ const key = resolveTrackingKey(sessionId, sessionKey);
196
+ if (!key) {
197
+ return false;
198
+ }
199
+ return injectedBySession.get(key) !== artifactSourceId;
200
+ },
201
+ markInjected(sessionId, sessionKey, artifactSourceId) {
202
+ const key = resolveTrackingKey(sessionId, sessionKey);
203
+ if (!key) {
204
+ return;
205
+ }
206
+ injectedBySession.set(key, artifactSourceId);
207
+ },
208
+ clear(sessionId, sessionKey) {
209
+ const key = resolveTrackingKey(sessionId, sessionKey);
210
+ if (!key) {
211
+ return;
212
+ }
213
+ injectedBySession.delete(key);
214
+ }
215
+ };
216
+ }
217
+ function resolveTrackingKey(sessionId, sessionKey) {
218
+ return resolveSessionIdentityKey(sessionId, sessionKey);
219
+ }
220
+
221
+ // src/adapters/shared/plugin-config-validators.ts
222
+ function normalizeOptionalBoolean(value, label, errors) {
223
+ if (value === void 0) {
224
+ return void 0;
225
+ }
226
+ if (typeof value !== "boolean") {
227
+ errors.push(`${label} must be a boolean when provided`);
228
+ return void 0;
229
+ }
230
+ return value;
231
+ }
232
+ function normalizeOptionalPositiveInteger(value, label, errors) {
233
+ if (value === void 0) {
234
+ return void 0;
235
+ }
236
+ if (typeof value !== "number" || !Number.isFinite(value) || !Number.isInteger(value) || value <= 0) {
237
+ errors.push(`${label} must be a positive integer when provided`);
238
+ return void 0;
239
+ }
240
+ return value;
241
+ }
242
+ function normalizeOptionalUnitInterval(value, label, errors) {
243
+ if (value === void 0) {
244
+ return void 0;
245
+ }
246
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 1) {
247
+ errors.push(`${label} must be a number between 0 and 1 when provided`);
248
+ return void 0;
249
+ }
250
+ return value;
251
+ }
252
+
253
+ // src/adapters/shared/plugin-memory-policy-config.ts
254
+ function normalizePluginInjectionMemoryPolicyConfig(value) {
255
+ if (value === void 0) {
256
+ return { ok: true, value: void 0 };
257
+ }
258
+ if (!isRecord(value)) {
259
+ return { ok: false, errors: ["memoryPolicy must be an object when provided"] };
260
+ }
261
+ const errors = [];
262
+ const slotPoliciesResult = normalizeClaimSlotPolicyConfig(value.slotPolicies);
263
+ if (!slotPoliciesResult.ok) {
264
+ errors.push(...slotPoliciesResult.errors);
265
+ }
266
+ const sessionStartResult = normalizeSessionStartMemoryPolicyConfig(value.sessionStart);
267
+ if (!sessionStartResult.ok) {
268
+ errors.push(...sessionStartResult.errors);
269
+ }
270
+ const beforeTurnResult = normalizeBeforeTurnMemoryPolicyConfig(value.beforeTurn);
271
+ if (!beforeTurnResult.ok) {
272
+ errors.push(...beforeTurnResult.errors);
273
+ }
274
+ const workingContextResult = normalizeWorkingContextMemoryPolicyConfig(value.workingContext);
275
+ if (!workingContextResult.ok) {
276
+ errors.push(...workingContextResult.errors);
277
+ }
278
+ const episodesResult = normalizeEpisodeMemoryPolicyConfig(value.episodes);
279
+ if (!episodesResult.ok) {
280
+ errors.push(...episodesResult.errors);
281
+ }
282
+ const allowedKeys = /* @__PURE__ */ new Set(["slotPolicies", "sessionStart", "beforeTurn", "workingContext", "episodes"]);
283
+ for (const key of Object.keys(value)) {
284
+ if (!allowedKeys.has(key)) {
285
+ errors.push(`unknown config field: memoryPolicy.${key}`);
286
+ }
287
+ }
288
+ if (errors.length > 0) {
289
+ return { ok: false, errors };
290
+ }
291
+ return {
292
+ ok: true,
293
+ value: slotPoliciesResult.ok && slotPoliciesResult.value || sessionStartResult.ok && sessionStartResult.value || beforeTurnResult.ok && beforeTurnResult.value || workingContextResult.ok && workingContextResult.value || episodesResult.ok && episodesResult.value ? {
294
+ ...slotPoliciesResult.ok && slotPoliciesResult.value ? { slotPolicies: slotPoliciesResult.value } : {},
295
+ ...sessionStartResult.ok && sessionStartResult.value ? { sessionStart: sessionStartResult.value } : {},
296
+ ...beforeTurnResult.ok && beforeTurnResult.value ? { beforeTurn: beforeTurnResult.value } : {},
297
+ ...workingContextResult.ok && workingContextResult.value ? { workingContext: workingContextResult.value } : {},
298
+ ...episodesResult.ok && episodesResult.value ? { episodes: episodesResult.value } : {}
299
+ } : void 0
300
+ };
301
+ }
302
+ function normalizeWorkingContextMemoryPolicyConfig(value) {
303
+ if (value === void 0) {
304
+ return { ok: true, value: void 0 };
305
+ }
306
+ if (!isRecord(value)) {
307
+ return { ok: false, errors: ["memoryPolicy.workingContext must be an object when provided"] };
308
+ }
309
+ const errors = [];
310
+ const enabled = normalizeOptionalBoolean(value.enabled, "memoryPolicy.workingContext.enabled", errors);
311
+ const allowedKeys = /* @__PURE__ */ new Set(["enabled"]);
312
+ for (const key of Object.keys(value)) {
313
+ if (!allowedKeys.has(key)) {
314
+ errors.push(`unknown config field: memoryPolicy.workingContext.${key}`);
315
+ }
316
+ }
317
+ if (errors.length > 0) {
318
+ return { ok: false, errors };
319
+ }
320
+ return {
321
+ ok: true,
322
+ value: enabled !== void 0 ? { enabled } : void 0
323
+ };
324
+ }
325
+ function normalizeEpisodeMemoryPolicyConfig(value) {
326
+ if (value === void 0) {
327
+ return { ok: true, value: void 0 };
328
+ }
329
+ if (!isRecord(value)) {
330
+ return { ok: false, errors: ["memoryPolicy.episodes must be an object when provided"] };
331
+ }
332
+ const errors = [];
333
+ const enabled = normalizeOptionalBoolean(value.enabled, "memoryPolicy.episodes.enabled", errors);
334
+ const allowedKeys = /* @__PURE__ */ new Set(["enabled"]);
335
+ for (const key of Object.keys(value)) {
336
+ if (!allowedKeys.has(key)) {
337
+ errors.push(`unknown config field: memoryPolicy.episodes.${key}`);
338
+ }
339
+ }
340
+ if (errors.length > 0) {
341
+ return { ok: false, errors };
342
+ }
343
+ return {
344
+ ok: true,
345
+ value: enabled !== void 0 ? { enabled } : void 0
346
+ };
347
+ }
348
+ function normalizeSessionStartMemoryPolicyConfig(value) {
349
+ if (value === void 0) {
350
+ return { ok: true, value: void 0 };
351
+ }
352
+ if (!isRecord(value)) {
353
+ return { ok: false, errors: ["memoryPolicy.sessionStart must be an object when provided"] };
354
+ }
355
+ const errors = [];
356
+ const enabled = normalizeOptionalBoolean(value.enabled, "memoryPolicy.sessionStart.enabled", errors);
357
+ const coreMemory = normalizeOptionalBoolean(value.coreMemory, "memoryPolicy.sessionStart.coreMemory", errors);
358
+ const relevantDurableMemory = normalizeOptionalBoolean(value.relevantDurableMemory, "memoryPolicy.sessionStart.relevantDurableMemory", errors);
359
+ const allowedKeys = /* @__PURE__ */ new Set(["enabled", "coreMemory", "relevantDurableMemory"]);
360
+ for (const key of Object.keys(value)) {
361
+ if (!allowedKeys.has(key)) {
362
+ errors.push(`unknown config field: memoryPolicy.sessionStart.${key}`);
363
+ }
364
+ }
365
+ if (errors.length > 0) {
366
+ return { ok: false, errors };
367
+ }
368
+ return {
369
+ ok: true,
370
+ value: enabled !== void 0 || coreMemory !== void 0 || relevantDurableMemory !== void 0 ? {
371
+ ...enabled !== void 0 ? { enabled } : {},
372
+ ...coreMemory !== void 0 ? { coreMemory } : {},
373
+ ...relevantDurableMemory !== void 0 ? { relevantDurableMemory } : {}
374
+ } : void 0
375
+ };
376
+ }
377
+ function normalizeBeforeTurnMemoryPolicyConfig(value) {
378
+ if (value === void 0) {
379
+ return { ok: true, value: void 0 };
380
+ }
381
+ if (!isRecord(value)) {
382
+ return { ok: false, errors: ["memoryPolicy.beforeTurn must be an object when provided"] };
383
+ }
384
+ const errors = [];
385
+ const enabled = normalizeOptionalBoolean(value.enabled, "memoryPolicy.beforeTurn.enabled", errors);
386
+ const procedureSuggestion = normalizeOptionalBoolean(value.procedureSuggestion, "memoryPolicy.beforeTurn.procedureSuggestion", errors);
387
+ const maxDurableEntries = normalizeOptionalPositiveInteger(value.maxDurableEntries, "memoryPolicy.beforeTurn.maxDurableEntries", errors);
388
+ const recallThreshold = normalizeOptionalUnitInterval(value.recallThreshold, "memoryPolicy.beforeTurn.recallThreshold", errors);
389
+ const highConfidenceRecallThreshold = normalizeOptionalUnitInterval(
390
+ value.highConfidenceRecallThreshold,
391
+ "memoryPolicy.beforeTurn.highConfidenceRecallThreshold",
392
+ errors
393
+ );
394
+ const procedureThreshold = normalizeOptionalUnitInterval(value.procedureThreshold, "memoryPolicy.beforeTurn.procedureThreshold", errors);
395
+ const allowedKeys = /* @__PURE__ */ new Set([
396
+ "enabled",
397
+ "procedureSuggestion",
398
+ "maxDurableEntries",
399
+ "recallThreshold",
400
+ "highConfidenceRecallThreshold",
401
+ "procedureThreshold"
402
+ ]);
403
+ for (const key of Object.keys(value)) {
404
+ if (!allowedKeys.has(key)) {
405
+ errors.push(`unknown config field: memoryPolicy.beforeTurn.${key}`);
406
+ }
407
+ }
408
+ if (errors.length > 0) {
409
+ return { ok: false, errors };
410
+ }
411
+ return {
412
+ ok: true,
413
+ value: enabled !== void 0 || procedureSuggestion !== void 0 || maxDurableEntries !== void 0 || recallThreshold !== void 0 || highConfidenceRecallThreshold !== void 0 || procedureThreshold !== void 0 ? {
414
+ ...enabled !== void 0 ? { enabled } : {},
415
+ ...procedureSuggestion !== void 0 ? { procedureSuggestion } : {},
416
+ ...maxDurableEntries !== void 0 ? { maxDurableEntries } : {},
417
+ ...recallThreshold !== void 0 ? { recallThreshold } : {},
418
+ ...highConfidenceRecallThreshold !== void 0 ? { highConfidenceRecallThreshold } : {},
419
+ ...procedureThreshold !== void 0 ? { procedureThreshold } : {}
420
+ } : void 0
421
+ };
422
+ }
423
+ function normalizeClaimSlotPolicyConfig(value) {
424
+ if (value === void 0) {
425
+ return { ok: true, value: void 0 };
426
+ }
427
+ if (!isRecord(value)) {
428
+ return { ok: false, errors: ["memoryPolicy.slotPolicies must be an object when provided"] };
429
+ }
430
+ const errors = [];
431
+ const attributeHeads = normalizeClaimSlotPolicyAttributeHeads(value.attributeHeads, errors);
432
+ const allowedKeys = /* @__PURE__ */ new Set(["attributeHeads"]);
433
+ for (const key of Object.keys(value)) {
434
+ if (!allowedKeys.has(key)) {
435
+ errors.push(`unknown config field: memoryPolicy.slotPolicies.${key}`);
436
+ }
437
+ }
438
+ if (errors.length > 0) {
439
+ return { ok: false, errors };
440
+ }
441
+ return {
442
+ ok: true,
443
+ value: attributeHeads ? { attributeHeads } : void 0
444
+ };
445
+ }
446
+ function normalizeClaimSlotPolicyAttributeHeads(value, errors) {
447
+ if (value === void 0) {
448
+ return void 0;
449
+ }
450
+ if (!isRecord(value)) {
451
+ errors.push("memoryPolicy.slotPolicies.attributeHeads must be an object when provided");
452
+ return void 0;
453
+ }
454
+ const normalized = {};
455
+ for (const [rawKey, rawPolicy] of Object.entries(value)) {
456
+ const attributeHead = rawKey.trim().toLowerCase();
457
+ if (!/^[a-z0-9][a-z0-9_-]*$/.test(attributeHead)) {
458
+ errors.push(`memoryPolicy.slotPolicies.attributeHeads.${rawKey} must use a canonical attribute-head label`);
459
+ continue;
460
+ }
461
+ if (rawPolicy !== "exclusive" && rawPolicy !== "multivalued") {
462
+ errors.push(`memoryPolicy.slotPolicies.attributeHeads.${attributeHead} must be "exclusive" or "multivalued"`);
463
+ continue;
464
+ }
465
+ normalized[attributeHead] = rawPolicy;
466
+ }
467
+ return Object.keys(normalized).length > 0 ? normalized : void 0;
468
+ }
469
+ function isRecord(value) {
470
+ return typeof value === "object" && value !== null && !Array.isArray(value);
471
+ }
472
+
473
+ // src/adapters/shared/injection/merge-injection-content.ts
474
+ function mergeInjectionContent(...parts) {
475
+ const merged = parts.map((part) => part?.trim()).filter((part) => Boolean(part)).join("\n\n");
476
+ return merged.length > 0 ? merged : void 0;
477
+ }
478
+
479
+ // src/adapters/shared/injection/session-start-format.ts
480
+ function formatAgenrSessionStartRecall(patch) {
481
+ if (patch.durableMemory.length === 0) {
482
+ return "";
483
+ }
484
+ const lines = [];
485
+ const durableSections = buildSections(patch);
486
+ if (durableSections.length > 0) {
487
+ const recallLines = [
488
+ "## Agenr Session Recall",
489
+ "Use this as prior context. Confirm anything important if the current conversation conflicts with it.",
490
+ ""
491
+ ];
492
+ for (const section of durableSections) {
493
+ recallLines.push(`### ${section.title}`);
494
+ for (const item of section.entries) {
495
+ recallLines.push(formatInjectionEntryHeader(item));
496
+ recallLines.push(...formatInjectionEntryBodyLines(item));
497
+ }
498
+ recallLines.push("");
499
+ }
500
+ lines.push(wrapAgenrMemoryContext(recallLines.join("\n").trim()));
501
+ }
502
+ return lines.join("\n").trim();
503
+ }
504
+ function buildSections(patch) {
505
+ const sections = [];
506
+ const profileEntries = patch.durableMemory.filter((item) => item.sourceKind === "profile");
507
+ if (profileEntries.length > 0) {
508
+ sections.push({ title: "Profile Memory", entries: profileEntries });
509
+ }
510
+ const directiveEntries = patch.durableMemory.filter((item) => item.sourceKind === "directive");
511
+ if (directiveEntries.length > 0) {
512
+ sections.push({ title: "Memory Directives", entries: directiveEntries });
513
+ }
514
+ const coreEntries = patch.durableMemory.filter((item) => item.sourceKind === "core");
515
+ if (coreEntries.length > 0) {
516
+ sections.push({ title: "Core Memory", entries: coreEntries });
517
+ }
518
+ const artifactRecallEntries = patch.durableMemory.filter((item) => item.sourceKind === "artifact_recall");
519
+ if (artifactRecallEntries.length > 0) {
520
+ sections.push({ title: "Relevant Durable Memory", entries: artifactRecallEntries });
521
+ }
522
+ return sections;
523
+ }
524
+
525
+ // src/adapters/shared/injection/policy.ts
526
+ var DEFAULT_SESSION_START_POLICY = {
527
+ maxCoreEntries: 4,
528
+ maxArtifactRecallEntries: 3,
529
+ maxDurableEntries: 5,
530
+ maxArtifactChars: 1200
531
+ };
532
+ var DEFAULT_BEFORE_TURN_POLICY = {
533
+ maxDurableEntries: 1,
534
+ maxHighConfidenceDurableEntries: 2,
535
+ maxRecentTurns: 2,
536
+ maxQueryChars: 450,
537
+ maxProcedureCandidates: 3,
538
+ recallThreshold: 0.6,
539
+ highConfidenceRecallThreshold: 0.85,
540
+ procedureThreshold: 0.72
541
+ };
542
+ function resolveSessionStartPolicy(memoryPolicy) {
543
+ return {
544
+ ...DEFAULT_SESSION_START_POLICY,
545
+ ...memoryPolicy?.sessionStart?.coreMemory === false ? { maxCoreEntries: 0 } : {},
546
+ enableArtifactRecall: memoryPolicy?.sessionStart?.relevantDurableMemory !== false
547
+ };
548
+ }
549
+ function resolveBeforeTurnPolicy(memoryPolicy) {
550
+ return {
551
+ ...DEFAULT_BEFORE_TURN_POLICY,
552
+ enableProcedureSuggestion: memoryPolicy?.beforeTurn?.procedureSuggestion !== false,
553
+ ...memoryPolicy?.beforeTurn?.maxDurableEntries !== void 0 ? { maxDurableEntries: memoryPolicy.beforeTurn.maxDurableEntries } : {},
554
+ ...memoryPolicy?.beforeTurn?.recallThreshold !== void 0 ? { recallThreshold: memoryPolicy.beforeTurn.recallThreshold } : {},
555
+ ...memoryPolicy?.beforeTurn?.highConfidenceRecallThreshold !== void 0 ? { highConfidenceRecallThreshold: memoryPolicy.beforeTurn.highConfidenceRecallThreshold } : {},
556
+ ...memoryPolicy?.beforeTurn?.procedureThreshold !== void 0 ? { procedureThreshold: memoryPolicy.beforeTurn.procedureThreshold } : {}
557
+ };
558
+ }
559
+ function isWorkingContextPolicyEnabled(memoryPolicy) {
560
+ return memoryPolicy?.workingContext?.enabled !== false;
561
+ }
562
+ function resolveWorkingContextGate(workingMemory, memoryPolicy) {
563
+ const capability = resolveWorkingMemoryCapability(workingMemory);
564
+ if (capability === "disabled") {
565
+ return { ok: false, reason: "features.workingMemory=false" };
566
+ }
567
+ if (capability === "misconfigured") {
568
+ return { ok: false, reason: "features.workingMemory enabled without repository" };
569
+ }
570
+ if (!isWorkingContextPolicyEnabled(memoryPolicy)) {
571
+ return { ok: false, reason: "memoryPolicy.workingContext.enabled=false" };
572
+ }
573
+ return { ok: true };
574
+ }
575
+ function resolveWorkingMemoryCapability(workingMemory) {
576
+ if (typeof workingMemory === "string") {
577
+ return workingMemory;
578
+ }
579
+ return workingMemory.workingMemory ? "enabled" : "disabled";
580
+ }
581
+
582
+ // src/adapters/shared/injection/message-text.ts
583
+ var MEMORY_HEADINGS = [
584
+ "## Previous session summary",
585
+ "## Recent session",
586
+ "## Agenr Session Recall",
587
+ "### Core Memory",
588
+ "### Relevant Durable Memory",
589
+ "## Agenr Before-Turn Recall",
590
+ "### Suggested Procedure"
591
+ ];
592
+ function extractAgentMessageText(content) {
593
+ if (typeof content === "string") {
594
+ return content;
595
+ }
596
+ if (!Array.isArray(content)) {
597
+ return "";
598
+ }
599
+ const blocks = [];
600
+ for (const block of content) {
601
+ if (typeof block === "string") {
602
+ blocks.push(block);
603
+ continue;
604
+ }
605
+ if (!block || typeof block !== "object") {
606
+ continue;
607
+ }
608
+ const typed = block;
609
+ if (typeof typed.text === "string") {
610
+ blocks.push(typed.text);
611
+ continue;
612
+ }
613
+ const type = typeof typed.type === "string" ? typed.type.trim().toLowerCase() : "";
614
+ if (typeof typed.content === "string" && (type === "text" || type === "input_text" || type === "output_text")) {
615
+ blocks.push(typed.content);
616
+ }
617
+ }
618
+ return blocks.join("\n");
619
+ }
620
+ function extractRecentTurnsFromMessages(messages, options = {}) {
621
+ const turns = [];
622
+ for (const message of messages) {
623
+ const role = message.role === "user" || message.role === "assistant" ? message.role : void 0;
624
+ if (!role) {
625
+ continue;
626
+ }
627
+ const text = sanitizeRecentTurnText(extractAgentMessageText(message.content), role, options);
628
+ if (!text) {
629
+ continue;
630
+ }
631
+ turns.push({ role, text });
632
+ }
633
+ return turns;
634
+ }
635
+ function normalizePromptText(prompt, options = {}) {
636
+ let cleaned = stripAgenrMemoryContext(prompt);
637
+ if (options.stripInlineMetadata) {
638
+ cleaned = stripInlineMetadata(cleaned, options.inlineMetadataSentinels ?? []);
639
+ }
640
+ if (options.stripTimestampPrefix) {
641
+ cleaned = cleaned.replace(/^\s*\[(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s[^\]]+\]\s*/u, "");
642
+ }
643
+ if (options.stripUserPrefix) {
644
+ cleaned = cleaned.replace(/^\s*U:\s*/u, "");
645
+ }
646
+ cleaned = collapseWhitespace(cleaned);
647
+ return cleaned.length > 0 ? cleaned : void 0;
648
+ }
649
+ function sanitizeRecentTurnText(text, role, options = {}) {
650
+ if (!text.trim()) {
651
+ return "";
652
+ }
653
+ const wrapperDetected = containsAgenrMemoryContext(text) || text.includes("## Agenr Session Recall") || text.includes("## Agenr Before-Turn Recall") || options.stripMemoryCheck === true && text.includes("[MEMORY CHECK]");
654
+ let cleaned = stripAgenrMemoryContext(text);
655
+ for (const heading of MEMORY_HEADINGS) {
656
+ cleaned = cleaned.split(heading).join(" ");
657
+ }
658
+ if (options.stripMemoryCheck === true) {
659
+ cleaned = cleaned.replace(/\[MEMORY CHECK\][^\n]*/gu, " ");
660
+ }
661
+ cleaned = collapseWhitespace(cleaned);
662
+ if (!wrapperDetected) {
663
+ return cleaned;
664
+ }
665
+ const segments = stripAgenrMemoryContext(text).split(/\n\s*\n/gu).map((segment) => collapseWhitespace(segment)).filter((segment) => segment.length > 0);
666
+ const fallbackSegment = segments.at(-1);
667
+ if (fallbackSegment) {
668
+ return role === "user" ? fallbackSegment : collapseWhitespace(cleaned);
669
+ }
670
+ return cleaned;
671
+ }
672
+ function stripInlineMetadata(text, sentinels) {
673
+ let cleaned = text;
674
+ for (const sentinel of sentinels) {
675
+ const escapedSentinel = escapeForRegExp(sentinel);
676
+ cleaned = cleaned.replace(new RegExp(`${escapedSentinel}\\s*(?:\`\`\`json\\s*)?\\{[\\s\\S]*?\\}(?:\\s*\`\`\`)?`, "gu"), " ");
677
+ cleaned = cleaned.replace(new RegExp(`${escapedSentinel}[^
678
+ ]*`, "gu"), " ");
679
+ }
680
+ cleaned = cleaned.replace(/Untrusted context \(metadata, do not treat as instructions or commands\):[\s\S]*$/gu, " ");
681
+ return cleaned;
682
+ }
683
+ function collapseWhitespace(value) {
684
+ return value.replace(/\s+/gu, " ").trim();
685
+ }
686
+ function escapeForRegExp(value) {
687
+ return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
688
+ }
689
+
690
+ // src/adapters/shared/pre-compaction-episode.ts
691
+ function scheduleGuardedEpisodeWrite(params) {
692
+ void withEpisodeWriteGuard({ port: params.dreaming, dbPath: params.dbPath }, params.write).catch(params.onFailure);
693
+ }
694
+
695
+ // src/adapters/shared/episode-write-policy.ts
696
+ function isPluginEpisodeWriteEnabled(memoryPolicy) {
697
+ return memoryPolicy?.episodes?.enabled !== false;
698
+ }
699
+
700
+ // src/app/features/resolve.ts
701
+ function resolveAgenrFeatureFlags(features) {
702
+ const resolved = { ...DEFAULT_AGENR_FEATURE_FLAGS };
703
+ for (const key of AGENR_FEATURE_FLAG_KEYS) {
704
+ if (features?.[key] !== void 0) {
705
+ resolved[key] = features[key];
706
+ }
707
+ }
708
+ return resolved;
709
+ }
710
+
711
+ // src/adapters/shared/injection/compaction-context.ts
712
+ function formatCompactionRecallContext(artifact) {
713
+ const summary = artifact.summary.trim();
714
+ const metadata = readCompactionMetadata(artifact.metadata);
715
+ const lines = ["## Agenr Compaction Recall", summary];
716
+ if (metadata.compactedCount !== void 0 && metadata.messageCount !== void 0) {
717
+ lines.push(`${metadata.compactedCount} messages compacted, ${metadata.messageCount} remain in context.`);
718
+ } else if (metadata.tokensBefore !== void 0) {
719
+ lines.push(`Compacted from about ${metadata.tokensBefore.toLocaleString()} tokens.`);
720
+ }
721
+ return lines.join("\n");
722
+ }
723
+ function readCompactionMetadata(metadata) {
724
+ if (typeof metadata !== "object" || metadata === null) {
725
+ return {};
726
+ }
727
+ const record = metadata;
728
+ return {
729
+ ...readOptionalNumber(record.compactedCount) !== void 0 ? { compactedCount: readOptionalNumber(record.compactedCount) } : {},
730
+ ...readOptionalNumber(record.messageCount) !== void 0 ? { messageCount: readOptionalNumber(record.messageCount) } : {},
731
+ ...readOptionalNumber(record.tokensBefore) !== void 0 ? { tokensBefore: readOptionalNumber(record.tokensBefore) } : {}
732
+ };
733
+ }
734
+ function readOptionalNumber(value) {
735
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
736
+ }
737
+
738
+ // src/adapters/shared/compaction-prompt-context.ts
739
+ async function resolveCompactionPromptContext(params) {
740
+ const featureFlags = resolveAgenrFeatureFlags(params.features);
741
+ if (!featureFlags.sessionTreeCompaction || !params.sessionMemoryRepository) {
742
+ return void 0;
743
+ }
744
+ const artifacts = await params.sessionMemoryRepository.listSessionArtifacts({
745
+ sessionKey: params.sessionKey,
746
+ kinds: ["compaction_checkpoint"],
747
+ limit: 1
748
+ });
749
+ const artifact = artifacts[0];
750
+ if (!artifact || !params.tracker.shouldInject(params.sessionId, params.sessionKey, artifact.sourceId)) {
751
+ return void 0;
752
+ }
753
+ params.tracker.markInjected(params.sessionId, params.sessionKey, artifact.sourceId);
754
+ return formatCompactionRecallContext(artifact);
755
+ }
756
+
757
+ // src/app/session-memory/source-ref.ts
758
+ var SESSION_FILE_SOURCE_REF_PREFIX = "session_file:";
759
+ var COMPACTION_SOURCE_REF_PREFIX = "compaction:";
760
+ var SESSION_END_SOURCE_REF_PREFIX = "session_end:";
761
+ function buildSessionFileSourceRef(sessionFile) {
762
+ return `${SESSION_FILE_SOURCE_REF_PREFIX}${sessionFile.trim()}`;
763
+ }
764
+ function buildCompactionSourceRef(source) {
765
+ return `${COMPACTION_SOURCE_REF_PREFIX}${source.trim()}`;
766
+ }
767
+ function buildSessionEndSourceRef(source) {
768
+ return `${SESSION_END_SOURCE_REF_PREFIX}${source.trim()}`;
769
+ }
770
+
771
+ // src/adapters/shared/light-dream-trigger-deps.ts
772
+ function buildLightDreamTriggerDeps(services) {
773
+ return {
774
+ port: services.dreaming,
775
+ dbPath: services.config.dbPath,
776
+ config: services.agenrConfig,
777
+ embedding: services.embedding,
778
+ ...services.claimExtraction ? { createClaimExtractionLlm: () => services.claimExtraction.llm } : {}
779
+ };
780
+ }
781
+
782
+ // src/app/dreaming/background-triggers.ts
783
+ var MINUTE_MS = 60 * 1e3;
784
+ async function maybeRunLightDream(input, deps) {
785
+ const now = input.now ?? (() => /* @__PURE__ */ new Date());
786
+ const config = resolveLightDreamTriggerConfig(deps.config);
787
+ if (!config.lightEnabled) {
788
+ return { status: "skipped", reason: "light_disabled" };
789
+ }
790
+ if (input.trigger === "post_session" && !config.postSessionLightDream) {
791
+ return { status: "skipped", reason: "post_session_disabled" };
792
+ }
793
+ if (input.trigger === "importance" && isEpisodeWriteInProgress(deps.dbPath)) {
794
+ return { status: "skipped", reason: "episode_write_in_progress" };
795
+ }
796
+ const lock = await tryAcquireDreamingRunLock(deps.port, deps.dbPath);
797
+ if (!lock) {
798
+ return { status: "skipped", reason: "run_in_progress" };
799
+ }
800
+ return withHeldDreamingRunLock(lock, async (lease) => {
801
+ const [{ runDreamScan }, { runDreamWithHeldLock }] = await Promise.all([import("./scan-6JKPOQHD.js"), import("./service-EKFACEN6.js")]);
802
+ const lastRun = await deps.port.getLastRun();
803
+ if (isWithinMinInterval(lastRun, now(), config.minIntervalMinutes)) {
804
+ return { status: "skipped", reason: "interval_guard" };
805
+ }
806
+ const scan = await runDreamScan({ now }, { port: deps.port });
807
+ if (!hasEvidence(scan)) {
808
+ return { status: "skipped", reason: "no_evidence", unsynthesizedImportanceSum: scan.unsynthesizedImportanceSum };
809
+ }
810
+ if (input.trigger === "importance" && scan.unsynthesizedImportanceSum < config.importanceThreshold) {
811
+ return {
812
+ status: "skipped",
813
+ reason: "importance_below_threshold",
814
+ unsynthesizedImportanceSum: scan.unsynthesizedImportanceSum
815
+ };
816
+ }
817
+ const result = await runDreamWithHeldLock(
818
+ {
819
+ tier: "light",
820
+ apply: true,
821
+ verbose: false,
822
+ json: true,
823
+ skipBackup: true
824
+ },
825
+ {
826
+ port: deps.port,
827
+ dbPath: deps.dbPath,
828
+ config: deps.config,
829
+ now,
830
+ ...deps.embedding ? { embedding: deps.embedding } : {},
831
+ ...deps.createExtractLlm ? { createExtractLlm: deps.createExtractLlm } : {},
832
+ ...deps.createClaimExtractionLlm ? { createClaimExtractionLlm: deps.createClaimExtractionLlm } : {}
833
+ },
834
+ lease
835
+ );
836
+ return {
837
+ status: "ran",
838
+ result,
839
+ unsynthesizedImportanceSum: scan.unsynthesizedImportanceSum
840
+ };
841
+ });
842
+ }
843
+ function resolveLightDreamTriggerConfig(config) {
844
+ return {
845
+ lightEnabled: config?.dreaming?.tiers?.light?.enabled ?? true,
846
+ postSessionLightDream: config?.dreaming?.triggers?.postSessionLightDream ?? true,
847
+ importanceThreshold: config?.dreaming?.triggers?.importanceThreshold ?? DEFAULT_DREAMING_IMPORTANCE_THRESHOLD,
848
+ minIntervalMinutes: config?.dreaming?.triggers?.minIntervalMinutes ?? DEFAULT_DREAMING_MIN_INTERVAL_MINUTES
849
+ };
850
+ }
851
+ function isWithinMinInterval(lastRun, now, minIntervalMinutes) {
852
+ if (!lastRun || minIntervalMinutes <= 0) {
853
+ return false;
854
+ }
855
+ const reference = lastRun.completedAt ?? lastRun.startedAt;
856
+ const timestamp = Date.parse(reference);
857
+ if (!Number.isFinite(timestamp)) {
858
+ return false;
859
+ }
860
+ return now.getTime() - timestamp < minIntervalMinutes * MINUTE_MS;
861
+ }
862
+ function hasEvidence(scan) {
863
+ return scan.episodesSinceLastRun > 0 || scan.ingestFilesSinceLastRun > 0 || scan.durablesCreatedSinceLastRun > 0;
864
+ }
865
+
866
+ // src/adapters/shared/post-session-light-dream.ts
867
+ async function runPostSessionLightDream(params) {
868
+ const contextSuffix = params.sessionContext ? ` for ${params.sessionContext}` : "";
869
+ try {
870
+ const result = await maybeRunLightDream({ trigger: "post_session" }, params.deps);
871
+ if (result.status === "ran") {
872
+ params.logger.info(`[agenr] ${params.scope} light dream completed${contextSuffix} run=${result.result.runId}`);
873
+ return;
874
+ }
875
+ if (result.reason === "run_in_progress" || result.reason === "episode_write_in_progress") {
876
+ params.logger.info(`[agenr] ${params.scope} light dream skipped${contextSuffix} reason=${result.reason}`);
877
+ return;
878
+ }
879
+ params.logger.debug?.(`[agenr] ${params.scope} light dream skipped${contextSuffix} reason=${result.reason}`);
880
+ } catch (error) {
881
+ params.logger.warn(`[agenr] ${params.scope} light dream failed${contextSuffix}: ${formatErrorMessage(error)}`);
882
+ }
883
+ }
884
+
885
+ // src/adapters/shared/guarded-post-session-episode-capture.ts
886
+ async function runGuardedPostSessionEpisodeCapture(params) {
887
+ await withEpisodeWriteGuard({ port: params.services.dreaming, dbPath: params.services.config.dbPath }, params.writeEpisode);
888
+ await runPostSessionLightDream({
889
+ deps: buildLightDreamTriggerDeps(params.services),
890
+ logger: params.logger,
891
+ scope: params.scope,
892
+ sessionContext: params.sessionContext
893
+ });
894
+ }
895
+
896
+ // src/adapters/plugin-runtime/claim-extraction.ts
897
+ async function buildClaimExtractionRuntime(config, resolveLlm) {
898
+ const claimExtractionConfig = resolveClaimExtractionConfig(config);
899
+ if (!claimExtractionConfig.enabled) {
900
+ return void 0;
901
+ }
902
+ try {
903
+ return {
904
+ llm: await resolveLlm(),
905
+ config: claimExtractionConfig
906
+ };
907
+ } catch {
908
+ return void 0;
909
+ }
910
+ }
911
+ function createClaimExtractionFromAgenrConfig(config) {
912
+ const claimExtractionConfig = resolveClaimExtractionConfig(config);
913
+ if (!claimExtractionConfig.enabled) {
914
+ return void 0;
915
+ }
916
+ try {
917
+ const { provider, modelId } = resolveModel(config, "claim");
918
+ const apiKey = resolveLlmApiKey(config, provider);
919
+ return {
920
+ llm: createLlmClient(provider, modelId, { apiKey }),
921
+ config: claimExtractionConfig
922
+ };
923
+ } catch {
924
+ return void 0;
925
+ }
926
+ }
927
+
928
+ // src/adapters/db/session-memory-repository.ts
929
+ import { randomUUID } from "crypto";
930
+
931
+ // src/adapters/db/json.ts
932
+ function serializeOptionalJson(value) {
933
+ return value === void 0 ? null : JSON.stringify(value);
934
+ }
935
+ function parseOptionalJson(value, label) {
936
+ if (!value) {
937
+ return void 0;
938
+ }
939
+ try {
940
+ return JSON.parse(value);
941
+ } catch (error) {
942
+ throw new Error(`Failed to parse ${label}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
943
+ }
944
+ }
945
+
946
+ // src/app/session-memory/types.ts
947
+ var SESSION_ARTIFACT_KINDS = ["compaction_checkpoint", "branch_abandonment", "session_episode"];
948
+ var SESSION_LINEAGE_REASONS = ["fork", "clone", "resume", "subagent_spawn"];
949
+ var SESSION_START_TRANSITION_REASONS = ["new", "unknown", ...SESSION_LINEAGE_REASONS];
950
+
951
+ // src/adapters/db/session-memory-parsing.ts
952
+ function parseSessionArtifactKind(value) {
953
+ if (SESSION_ARTIFACT_KINDS.includes(value)) {
954
+ return value;
955
+ }
956
+ throw new Error(`Unsupported session artifact kind "${value}".`);
957
+ }
958
+ function parseSessionLineageReason(value) {
959
+ if (SESSION_LINEAGE_REASONS.includes(value)) {
960
+ return value;
961
+ }
962
+ throw new Error(`Unsupported session lineage reason "${value}".`);
963
+ }
964
+
965
+ // src/adapters/db/session-memory-repository.ts
966
+ var SESSION_LINEAGE_EDGE_SELECT_COLUMNS = `
967
+ id,
968
+ child_session_key,
969
+ parent_session_key,
970
+ parent_source_ref,
971
+ reason,
972
+ fork_durable_id,
973
+ fork_position,
974
+ observed_at
975
+ `;
976
+ var SESSION_ARTIFACT_SELECT_COLUMNS = `
977
+ id,
978
+ kind,
979
+ session_key,
980
+ source,
981
+ source_id,
982
+ source_ref,
983
+ content_hash,
984
+ summary,
985
+ metadata_json,
986
+ created_at,
987
+ expires_at
988
+ `;
989
+ function createSessionMemoryRepository(database) {
990
+ return {
991
+ upsertLineageEdge: (input) => upsertLineageEdge(database, input),
992
+ upsertSessionArtifact: (input) => upsertSessionArtifact(database, input),
993
+ recordTriggerIntake: (input) => recordTriggerIntake(database, input),
994
+ listSessionArtifacts: (filter) => listSessionArtifacts(database, filter),
995
+ listSessionArtifactsBySourceRef: (filter) => listSessionArtifactsBySourceRef(database, filter),
996
+ getLatestLineageEdgeForChild: (childSessionKey) => getLatestLineageEdgeForChild(database, childSessionKey)
997
+ };
998
+ }
999
+ async function upsertLineageEdge(database, input) {
1000
+ return database.withTransaction(async (transaction) => upsertLineageEdgeWithExecutor(transaction, input));
1001
+ }
1002
+ async function recordTriggerIntake(database, input) {
1003
+ return database.withTransaction(async (transaction) => {
1004
+ const executor = transaction;
1005
+ const result = {};
1006
+ if (input.lineage) {
1007
+ result.lineageEdge = await upsertLineageEdgeWithExecutor(executor, input.lineage);
1008
+ }
1009
+ if (input.artifact) {
1010
+ result.artifact = await upsertSessionArtifact(executor, input.artifact);
1011
+ }
1012
+ return result;
1013
+ });
1014
+ }
1015
+ async function upsertLineageEdgeWithExecutor(executor, input) {
1016
+ const existing = await findMatchingLineageEdge(executor, input);
1017
+ if (existing) {
1018
+ return existing;
1019
+ }
1020
+ const id = randomUUID();
1021
+ await executor.execute({
1022
+ sql: `
1023
+ INSERT INTO session_lineage_edges (
1024
+ id,
1025
+ child_session_key,
1026
+ parent_session_key,
1027
+ parent_source_ref,
1028
+ reason,
1029
+ fork_durable_id,
1030
+ fork_position,
1031
+ observed_at
1032
+ )
1033
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
1034
+ `,
1035
+ args: [
1036
+ id,
1037
+ input.childSessionKey,
1038
+ input.parentSessionKey ?? null,
1039
+ input.parentSourceRef ?? null,
1040
+ input.reason,
1041
+ input.forkEntryId ?? null,
1042
+ input.forkPosition ?? null,
1043
+ input.observedAt
1044
+ ]
1045
+ });
1046
+ const edge = await getLineageEdge(executor, id);
1047
+ if (!edge) {
1048
+ throw new Error(`Session lineage edge ${id} was not found after write.`);
1049
+ }
1050
+ return edge;
1051
+ }
1052
+ async function upsertSessionArtifact(executor, input) {
1053
+ const createdAt = (/* @__PURE__ */ new Date()).toISOString();
1054
+ await executor.execute({
1055
+ sql: `
1056
+ INSERT INTO session_artifacts (
1057
+ id,
1058
+ kind,
1059
+ session_key,
1060
+ source,
1061
+ source_id,
1062
+ source_ref,
1063
+ content_hash,
1064
+ summary,
1065
+ metadata_json,
1066
+ created_at,
1067
+ expires_at
1068
+ )
1069
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1070
+ ON CONFLICT(kind, source, source_id) DO UPDATE SET
1071
+ session_key = excluded.session_key,
1072
+ source_ref = excluded.source_ref,
1073
+ content_hash = excluded.content_hash,
1074
+ summary = excluded.summary,
1075
+ metadata_json = excluded.metadata_json,
1076
+ expires_at = excluded.expires_at
1077
+ `,
1078
+ args: [
1079
+ randomUUID(),
1080
+ input.kind,
1081
+ input.sessionKey,
1082
+ input.source,
1083
+ input.sourceId,
1084
+ input.sourceRef ?? null,
1085
+ input.contentHash,
1086
+ input.summary,
1087
+ serializeOptionalJson(input.metadata),
1088
+ createdAt,
1089
+ input.expiresAt ?? null
1090
+ ]
1091
+ });
1092
+ const artifact = await getSessionArtifactBySource(executor, input.kind, input.source, input.sourceId);
1093
+ if (!artifact) {
1094
+ throw new Error(`Session artifact ${input.kind}/${input.source}/${input.sourceId} was not found after write.`);
1095
+ }
1096
+ return artifact;
1097
+ }
1098
+ async function listSessionArtifacts(executor, filter) {
1099
+ const sessionKey = filter.sessionKey.trim();
1100
+ if (!sessionKey) {
1101
+ return [];
1102
+ }
1103
+ return querySessionArtifacts(executor, {
1104
+ conditions: ["session_key = ?"],
1105
+ args: [sessionKey],
1106
+ kinds: filter.kinds,
1107
+ limit: filter.limit
1108
+ });
1109
+ }
1110
+ async function listSessionArtifactsBySourceRef(executor, filter) {
1111
+ const sourceRef = filter.sourceRef.trim();
1112
+ if (!sourceRef) {
1113
+ return [];
1114
+ }
1115
+ return querySessionArtifacts(executor, {
1116
+ conditions: ["source_ref = ?"],
1117
+ args: [sourceRef],
1118
+ kinds: filter.kinds,
1119
+ limit: filter.limit
1120
+ });
1121
+ }
1122
+ async function getLatestLineageEdgeForChild(executor, childSessionKey) {
1123
+ const normalizedChild = childSessionKey.trim();
1124
+ if (!normalizedChild) {
1125
+ return null;
1126
+ }
1127
+ const result = await executor.execute({
1128
+ sql: `
1129
+ SELECT ${SESSION_LINEAGE_EDGE_SELECT_COLUMNS}
1130
+ FROM session_lineage_edges
1131
+ WHERE child_session_key = ?
1132
+ ORDER BY observed_at DESC, id ASC
1133
+ LIMIT 1
1134
+ `,
1135
+ args: [normalizedChild]
1136
+ });
1137
+ const row = result.rows[0];
1138
+ return row ? mapSessionLineageEdgeRow(row) : null;
1139
+ }
1140
+ async function findMatchingLineageEdge(executor, input) {
1141
+ const parentSessionKeyClause = input.parentSessionKey ? "parent_session_key = ?" : "parent_session_key IS NULL";
1142
+ const parentSourceRefClause = input.parentSourceRef ? "parent_source_ref = ?" : "parent_source_ref IS NULL";
1143
+ const args = [
1144
+ input.childSessionKey,
1145
+ input.reason,
1146
+ ...input.parentSessionKey ? [input.parentSessionKey] : [],
1147
+ ...input.parentSourceRef ? [input.parentSourceRef] : []
1148
+ ];
1149
+ const result = await executor.execute({
1150
+ sql: `
1151
+ SELECT ${SESSION_LINEAGE_EDGE_SELECT_COLUMNS}
1152
+ FROM session_lineage_edges
1153
+ WHERE child_session_key = ?
1154
+ AND reason = ?
1155
+ AND ${parentSessionKeyClause}
1156
+ AND ${parentSourceRefClause}
1157
+ ORDER BY observed_at DESC, id ASC
1158
+ LIMIT 1
1159
+ `,
1160
+ args
1161
+ });
1162
+ const row = result.rows[0];
1163
+ return row ? mapSessionLineageEdgeRow(row) : null;
1164
+ }
1165
+ async function getLineageEdge(executor, id) {
1166
+ const result = await executor.execute({
1167
+ sql: `
1168
+ SELECT ${SESSION_LINEAGE_EDGE_SELECT_COLUMNS}
1169
+ FROM session_lineage_edges
1170
+ WHERE id = ?
1171
+ LIMIT 1
1172
+ `,
1173
+ args: [id]
1174
+ });
1175
+ const row = result.rows[0];
1176
+ return row ? mapSessionLineageEdgeRow(row) : null;
1177
+ }
1178
+ async function getSessionArtifactBySource(executor, kind, source, sourceId) {
1179
+ const result = await executor.execute({
1180
+ sql: `
1181
+ SELECT ${SESSION_ARTIFACT_SELECT_COLUMNS}
1182
+ FROM session_artifacts
1183
+ WHERE kind = ?
1184
+ AND source = ?
1185
+ AND source_id = ?
1186
+ LIMIT 1
1187
+ `,
1188
+ args: [kind, source, sourceId]
1189
+ });
1190
+ const row = result.rows[0];
1191
+ return row ? mapSessionArtifactRow(row) : null;
1192
+ }
1193
+ function appendKindFilter(conditions, args, kinds) {
1194
+ if (kinds && kinds.length > 0) {
1195
+ conditions.push(`kind IN (${kinds.map(() => "?").join(", ")})`);
1196
+ args.push(...kinds);
1197
+ }
1198
+ }
1199
+ async function querySessionArtifacts(executor, filter) {
1200
+ const conditions = [...filter.conditions];
1201
+ const args = [...filter.args];
1202
+ appendKindFilter(conditions, args, filter.kinds);
1203
+ const limit = normalizeBoundedLimit(filter.limit, 20, 100);
1204
+ const result = await executor.execute({
1205
+ sql: `
1206
+ SELECT ${SESSION_ARTIFACT_SELECT_COLUMNS}
1207
+ FROM session_artifacts
1208
+ WHERE ${conditions.join(" AND ")}
1209
+ ORDER BY created_at DESC, id ASC
1210
+ LIMIT ?
1211
+ `,
1212
+ args: [...args, limit]
1213
+ });
1214
+ return result.rows.map((row) => mapSessionArtifactRow(row));
1215
+ }
1216
+ function mapSessionLineageEdgeRow(row) {
1217
+ return {
1218
+ id: readRequiredString(row, "id"),
1219
+ childSessionKey: readRequiredString(row, "child_session_key"),
1220
+ parentSessionKey: readOptionalString(row, "parent_session_key"),
1221
+ parentSourceRef: readOptionalString(row, "parent_source_ref"),
1222
+ reason: parseSessionLineageReason(readRequiredString(row, "reason")),
1223
+ forkEntryId: readOptionalString(row, "fork_durable_id"),
1224
+ forkPosition: readOptionalString(row, "fork_position"),
1225
+ observedAt: readRequiredString(row, "observed_at")
1226
+ };
1227
+ }
1228
+ function mapSessionArtifactRow(row) {
1229
+ return {
1230
+ id: readRequiredString(row, "id"),
1231
+ kind: parseSessionArtifactKind(readRequiredString(row, "kind")),
1232
+ sessionKey: readRequiredString(row, "session_key"),
1233
+ source: readRequiredString(row, "source"),
1234
+ sourceId: readRequiredString(row, "source_id"),
1235
+ sourceRef: readOptionalString(row, "source_ref"),
1236
+ contentHash: readRequiredString(row, "content_hash"),
1237
+ summary: readRequiredString(row, "summary"),
1238
+ metadata: parseOptionalJson(readOptionalString(row, "metadata_json"), "metadata_json"),
1239
+ createdAt: readRequiredString(row, "created_at"),
1240
+ expiresAt: readOptionalString(row, "expires_at")
1241
+ };
1242
+ }
1243
+
1244
+ // src/adapters/db/working-memory-repository.ts
1245
+ import { randomUUID as randomUUID2 } from "crypto";
1246
+
1247
+ // src/adapters/db/working-memory-columns.ts
1248
+ var WORKING_SET_COLUMN_NAMES = [
1249
+ "id",
1250
+ "scope_key",
1251
+ "scope_kind",
1252
+ "title",
1253
+ "objective",
1254
+ "status",
1255
+ "summary",
1256
+ "snapshot_json",
1257
+ "revision",
1258
+ "project",
1259
+ "session_id",
1260
+ "conversation_key",
1261
+ "cwd",
1262
+ "git_root",
1263
+ "git_branch",
1264
+ "task_id",
1265
+ "source",
1266
+ "created_at",
1267
+ "updated_at",
1268
+ "last_active_at",
1269
+ "closed_at",
1270
+ "close_reason",
1271
+ "episode_id"
1272
+ ];
1273
+ var WORKING_SET_SELECT_COLUMNS = WORKING_SET_COLUMN_NAMES.join(",\n ");
1274
+ var WORKING_SET_INSERT_COLUMNS = WORKING_SET_COLUMN_NAMES.join(",\n ");
1275
+ var WORKING_SET_INSERT_PLACEHOLDERS = WORKING_SET_COLUMN_NAMES.map(() => "?").join(", ");
1276
+ var WORKING_SET_UPDATE_COLUMNS = [
1277
+ "title",
1278
+ "objective",
1279
+ "status",
1280
+ "summary",
1281
+ "snapshot_json",
1282
+ "revision",
1283
+ "updated_at",
1284
+ "last_active_at",
1285
+ "closed_at",
1286
+ "close_reason",
1287
+ "episode_id"
1288
+ ];
1289
+ var WORKING_SET_SEMANTIC_ONLY_UPDATE_COLUMNS = /* @__PURE__ */ new Set(["revision", "closed_at", "close_reason", "episode_id"]);
1290
+ var WORKING_SET_USAGE_PATCH_COLUMNS = WORKING_SET_UPDATE_COLUMNS.filter((column) => !WORKING_SET_SEMANTIC_ONLY_UPDATE_COLUMNS.has(column));
1291
+ var WORKING_EVENT_SELECT_COLUMNS = `
1292
+ id,
1293
+ working_set_id,
1294
+ sequence,
1295
+ event_type,
1296
+ payload_json,
1297
+ actor,
1298
+ source,
1299
+ host_event_id,
1300
+ turn_id,
1301
+ created_at
1302
+ `;
1303
+ function buildWorkingSetUpdateSetClause() {
1304
+ return WORKING_SET_UPDATE_COLUMNS.map((column) => `${column} = ?`).join(",\n ");
1305
+ }
1306
+ function buildWorkingSetUsagePatchSetClause() {
1307
+ return WORKING_SET_USAGE_PATCH_COLUMNS.map((column) => `${column} = ?`).join(",\n ");
1308
+ }
1309
+ function mapWorkingSetRow(row) {
1310
+ const snapshot = parseJson(readRequiredString(row, "snapshot_json"), "snapshot_json");
1311
+ return {
1312
+ id: readRequiredString(row, "id"),
1313
+ scopeKey: readRequiredString(row, "scope_key"),
1314
+ scopeKind: readRequiredString(row, "scope_kind"),
1315
+ title: readOptionalString(row, "title"),
1316
+ objective: readOptionalString(row, "objective"),
1317
+ status: readRequiredString(row, "status"),
1318
+ summary: readOptionalString(row, "summary"),
1319
+ snapshot,
1320
+ revision: readNumber(row, "revision", 0),
1321
+ project: readOptionalString(row, "project"),
1322
+ sessionId: readOptionalString(row, "session_id"),
1323
+ conversationKey: readOptionalString(row, "conversation_key"),
1324
+ cwd: readOptionalString(row, "cwd"),
1325
+ gitRoot: readOptionalString(row, "git_root"),
1326
+ gitBranch: readOptionalString(row, "git_branch"),
1327
+ taskId: readOptionalString(row, "task_id"),
1328
+ source: readOptionalString(row, "source"),
1329
+ createdAt: readRequiredString(row, "created_at"),
1330
+ updatedAt: readRequiredString(row, "updated_at"),
1331
+ lastActiveAt: readRequiredString(row, "last_active_at"),
1332
+ closedAt: readOptionalString(row, "closed_at"),
1333
+ closeReason: readOptionalString(row, "close_reason"),
1334
+ episodeId: readOptionalString(row, "episode_id")
1335
+ };
1336
+ }
1337
+ function mapWorkingEventRow(row) {
1338
+ return {
1339
+ id: readRequiredString(row, "id"),
1340
+ workingSetId: readRequiredString(row, "working_set_id"),
1341
+ sequence: readNumber(row, "sequence", 0),
1342
+ eventType: readRequiredString(row, "event_type"),
1343
+ payload: parseJson(readRequiredString(row, "payload_json"), "payload_json"),
1344
+ actor: readOptionalString(row, "actor"),
1345
+ source: readOptionalString(row, "source"),
1346
+ hostEventId: readOptionalString(row, "host_event_id"),
1347
+ turnId: readOptionalString(row, "turn_id"),
1348
+ createdAt: readRequiredString(row, "created_at")
1349
+ };
1350
+ }
1351
+ function parseJson(value, column) {
1352
+ try {
1353
+ return JSON.parse(value);
1354
+ } catch (error) {
1355
+ const message = error instanceof Error ? error.message : String(error);
1356
+ throw new Error(`Invalid JSON in working-memory column ${column}: ${message}`, { cause: error });
1357
+ }
1358
+ }
1359
+
1360
+ // src/adapters/db/working-memory-repository.ts
1361
+ function createWorkingMemoryRepository(database) {
1362
+ return {
1363
+ getWorkingSet: (id) => getWorkingSet(database, id),
1364
+ findCurrentWorkingSets: (scope) => findWorkingSetsByScope(database, scope, CURRENT_WORKING_SET_STATUSES),
1365
+ listWorkingSets: (filter) => listWorkingSets(database, filter),
1366
+ listWorkingEvents: (workingSetId, limit) => listWorkingEvents(database, workingSetId, limit),
1367
+ createWorkingSet: (input) => createWorkingSet(database, input),
1368
+ updateWorkingSet: (input) => updateWorkingSet(database, input),
1369
+ patchWorkingSetUsage: (input) => patchWorkingSetUsage(database, input)
1370
+ };
1371
+ }
1372
+ async function getWorkingSet(executor, id) {
1373
+ const normalizedId = id.trim();
1374
+ if (!normalizedId) {
1375
+ return null;
1376
+ }
1377
+ const result = await executor.execute({
1378
+ sql: `
1379
+ SELECT ${WORKING_SET_SELECT_COLUMNS}
1380
+ FROM working_sets
1381
+ WHERE id = ?
1382
+ LIMIT 1
1383
+ `,
1384
+ args: [normalizedId]
1385
+ });
1386
+ const row = result.rows[0];
1387
+ return row ? mapWorkingSetRow(row) : null;
1388
+ }
1389
+ async function findWorkingSetsByScope(executor, scope, statuses) {
1390
+ const result = await executor.execute({
1391
+ sql: `
1392
+ SELECT ${WORKING_SET_SELECT_COLUMNS}
1393
+ FROM working_sets
1394
+ WHERE scope_key = ?
1395
+ AND status IN (${statuses.map(() => "?").join(", ")})
1396
+ ORDER BY last_active_at DESC, id ASC
1397
+ `,
1398
+ args: [scope.scopeKey, ...statuses]
1399
+ });
1400
+ return result.rows.map((row) => mapWorkingSetRow(row));
1401
+ }
1402
+ async function listWorkingSets(executor, filter) {
1403
+ const conditions = [];
1404
+ const args = [];
1405
+ if (filter.scope) {
1406
+ conditions.push("scope_key = ?");
1407
+ args.push(filter.scope.scopeKey);
1408
+ }
1409
+ if (filter.statuses && filter.statuses.length > 0) {
1410
+ conditions.push(`status IN (${filter.statuses.map(() => "?").join(", ")})`);
1411
+ args.push(...filter.statuses);
1412
+ }
1413
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1414
+ const limit = normalizeBoundedLimit(filter.limit, 20, 100);
1415
+ const result = await executor.execute({
1416
+ sql: `
1417
+ SELECT ${WORKING_SET_SELECT_COLUMNS}
1418
+ FROM working_sets
1419
+ ${where}
1420
+ ORDER BY last_active_at DESC, id ASC
1421
+ LIMIT ?
1422
+ `,
1423
+ args: [...args, limit]
1424
+ });
1425
+ return result.rows.map((row) => mapWorkingSetRow(row));
1426
+ }
1427
+ async function listWorkingEvents(executor, workingSetId, limit) {
1428
+ const normalizedId = workingSetId.trim();
1429
+ if (!normalizedId) {
1430
+ return [];
1431
+ }
1432
+ const normalizedLimit = normalizeBoundedLimit(limit, 50, 1e3);
1433
+ const result = await executor.execute({
1434
+ sql: `
1435
+ SELECT ${WORKING_EVENT_SELECT_COLUMNS}
1436
+ FROM working_events
1437
+ WHERE working_set_id = ?
1438
+ ORDER BY sequence DESC
1439
+ LIMIT ?
1440
+ `,
1441
+ args: [normalizedId, normalizedLimit]
1442
+ });
1443
+ return result.rows.map((row) => mapWorkingEventRow(row)).reverse();
1444
+ }
1445
+ async function createWorkingSet(database, input) {
1446
+ return database.withTransaction(async (transaction) => {
1447
+ const executor = transaction;
1448
+ const existing = await findWorkingSetsByScope(executor, input.scope, CURRENT_WORKING_SET_STATUSES);
1449
+ if (existing.length > 0) {
1450
+ return { kind: "active_set_exists", scopeKey: input.scope.scopeKey };
1451
+ }
1452
+ const id = randomUUID2();
1453
+ const event = buildEvent({
1454
+ workingSetId: id,
1455
+ sequence: 1,
1456
+ eventType: "created",
1457
+ payload: {
1458
+ objective: input.objective,
1459
+ scope: input.scope
1460
+ },
1461
+ actor: input.actor,
1462
+ source: input.source,
1463
+ now: input.now
1464
+ });
1465
+ await executor.execute({
1466
+ sql: `
1467
+ INSERT INTO working_sets (
1468
+ ${WORKING_SET_INSERT_COLUMNS}
1469
+ )
1470
+ VALUES (
1471
+ ${WORKING_SET_INSERT_PLACEHOLDERS}
1472
+ )
1473
+ `,
1474
+ args: [
1475
+ id,
1476
+ input.scope.scopeKey,
1477
+ input.scope.scopeKind,
1478
+ toNullableString(input.title),
1479
+ toNullableString(input.objective),
1480
+ input.status,
1481
+ toNullableString(input.snapshot.summary),
1482
+ serializeJson(input.snapshot),
1483
+ 1,
1484
+ toNullableString(input.scope.project),
1485
+ toNullableString(input.sessionId ?? input.scope.sessionId),
1486
+ toNullableString(input.scope.conversationKey),
1487
+ toNullableString(input.scope.cwd),
1488
+ toNullableString(input.scope.gitRoot),
1489
+ toNullableString(input.scope.gitBranch),
1490
+ toNullableString(input.scope.taskId),
1491
+ toNullableString(input.sourceLabel),
1492
+ input.now,
1493
+ input.now,
1494
+ input.now,
1495
+ null,
1496
+ null,
1497
+ null
1498
+ ]
1499
+ });
1500
+ await insertWorkingEvent(executor, event);
1501
+ const workingSet = await requireWorkingSet(executor, id);
1502
+ return { workingSet, event };
1503
+ });
1504
+ }
1505
+ async function updateWorkingSet(database, input) {
1506
+ return database.withTransaction(async (transaction) => {
1507
+ const executor = transaction;
1508
+ const current = await getWorkingSet(executor, input.workingSetId);
1509
+ if (!current) {
1510
+ return { kind: "not_found" };
1511
+ }
1512
+ if (!canApplyWorkingSetUpdate(current.status, input.status)) {
1513
+ return { kind: "terminal_status", status: current.status };
1514
+ }
1515
+ if (current.revision !== input.expectedRevision) {
1516
+ return { kind: "revision_conflict", actualRevision: current.revision };
1517
+ }
1518
+ const nextRevision = current.revision + 1;
1519
+ const event = buildEvent({
1520
+ workingSetId: current.id,
1521
+ sequence: nextRevision,
1522
+ eventType: input.eventType,
1523
+ payload: input.payload,
1524
+ actor: input.actor,
1525
+ source: input.source,
1526
+ now: input.now
1527
+ });
1528
+ await executor.execute({
1529
+ sql: `
1530
+ UPDATE working_sets
1531
+ SET ${buildWorkingSetUpdateSetClause()}
1532
+ WHERE id = ?
1533
+ AND revision = ?
1534
+ `,
1535
+ args: [
1536
+ ...buildWorkingSetSnapshotUpdateArgs({
1537
+ title: input.title,
1538
+ objective: input.objective,
1539
+ status: input.status,
1540
+ snapshot: input.snapshot,
1541
+ current
1542
+ }),
1543
+ nextRevision,
1544
+ input.now,
1545
+ input.now,
1546
+ toNullableString(input.closedAt ?? current.closedAt),
1547
+ toNullableString(input.closeReason ?? current.closeReason),
1548
+ toNullableString(input.episodeId ?? current.episodeId),
1549
+ current.id,
1550
+ input.expectedRevision
1551
+ ]
1552
+ });
1553
+ const workingSet = await requireWorkingSet(executor, current.id);
1554
+ if (workingSet.revision !== nextRevision) {
1555
+ return { kind: "revision_conflict", actualRevision: workingSet.revision };
1556
+ }
1557
+ await insertWorkingEvent(executor, event);
1558
+ return { workingSet, event };
1559
+ });
1560
+ }
1561
+ async function patchWorkingSetUsage(database, input) {
1562
+ return database.withTransaction(async (transaction) => {
1563
+ const executor = transaction;
1564
+ const current = await getWorkingSet(executor, input.workingSetId);
1565
+ if (!current) {
1566
+ return { kind: "not_found" };
1567
+ }
1568
+ if (!canApplyWorkingSetUpdate(current.status, input.status)) {
1569
+ return { kind: "terminal_status", status: current.status };
1570
+ }
1571
+ if (current.revision !== input.expectedRevision) {
1572
+ return { kind: "revision_conflict", actualRevision: current.revision };
1573
+ }
1574
+ await executor.execute({
1575
+ sql: `
1576
+ UPDATE working_sets
1577
+ SET ${buildWorkingSetUsagePatchSetClause()}
1578
+ WHERE id = ?
1579
+ AND revision = ?
1580
+ `,
1581
+ args: [
1582
+ ...buildWorkingSetSnapshotUpdateArgs({
1583
+ title: input.title,
1584
+ objective: input.objective,
1585
+ status: input.status,
1586
+ snapshot: input.snapshot,
1587
+ current
1588
+ }),
1589
+ input.now,
1590
+ input.now,
1591
+ current.id,
1592
+ input.expectedRevision
1593
+ ]
1594
+ });
1595
+ const workingSet = await requireWorkingSet(executor, current.id);
1596
+ if (workingSet.revision !== input.expectedRevision) {
1597
+ return { kind: "revision_conflict", actualRevision: workingSet.revision };
1598
+ }
1599
+ return { workingSet };
1600
+ });
1601
+ }
1602
+ async function insertWorkingEvent(executor, event) {
1603
+ await executor.execute({
1604
+ sql: `
1605
+ INSERT INTO working_events (
1606
+ id,
1607
+ working_set_id,
1608
+ sequence,
1609
+ event_type,
1610
+ payload_json,
1611
+ actor,
1612
+ source,
1613
+ host_event_id,
1614
+ turn_id,
1615
+ created_at
1616
+ )
1617
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1618
+ `,
1619
+ args: [
1620
+ event.id,
1621
+ event.workingSetId,
1622
+ event.sequence,
1623
+ event.eventType,
1624
+ serializeJson(event.payload),
1625
+ toNullableString(event.actor),
1626
+ toNullableString(event.source),
1627
+ toNullableString(event.hostEventId),
1628
+ toNullableString(event.turnId),
1629
+ event.createdAt
1630
+ ]
1631
+ });
1632
+ }
1633
+ function buildWorkingSetSnapshotUpdateArgs(input) {
1634
+ return [
1635
+ toNullableString(input.title ?? input.current.title),
1636
+ toNullableString(input.objective ?? input.snapshot.objective),
1637
+ input.status,
1638
+ toNullableString(input.snapshot.summary),
1639
+ serializeJson(input.snapshot)
1640
+ ];
1641
+ }
1642
+ function buildEvent(input) {
1643
+ return {
1644
+ id: randomUUID2(),
1645
+ workingSetId: input.workingSetId,
1646
+ sequence: input.sequence,
1647
+ eventType: input.eventType,
1648
+ payload: input.payload,
1649
+ ...input.actor ? { actor: input.actor } : {},
1650
+ ...input.source ? { source: input.source } : {},
1651
+ createdAt: input.now
1652
+ };
1653
+ }
1654
+ function canApplyWorkingSetUpdate(currentStatus, nextStatus) {
1655
+ if (OPEN_WORKING_SET_STATUSES.includes(currentStatus)) {
1656
+ return true;
1657
+ }
1658
+ return currentStatus === "complete" && CLOSE_MANAGED_WORKING_SET_STATUSES.includes(nextStatus);
1659
+ }
1660
+ async function requireWorkingSet(executor, id) {
1661
+ const workingSet = await getWorkingSet(executor, id);
1662
+ if (!workingSet) {
1663
+ throw new Error(`Working set ${id} was not found after write.`);
1664
+ }
1665
+ return workingSet;
1666
+ }
1667
+ function serializeJson(value) {
1668
+ return JSON.stringify(value);
1669
+ }
1670
+ function toNullableString(value) {
1671
+ const trimmed = value?.trim();
1672
+ return trimmed && trimmed.length > 0 ? trimmed : null;
1673
+ }
1674
+
1675
+ // src/adapters/plugin-runtime/embed-query.ts
1676
+ function createEmbedQuery(embedding, available) {
1677
+ if (!available) {
1678
+ return void 0;
1679
+ }
1680
+ return async (text) => {
1681
+ const vectors = await embedding.embed([text]);
1682
+ const vector = vectors[0];
1683
+ if (!vector) {
1684
+ throw new Error("Embedding provider returned no vector for the query.");
1685
+ }
1686
+ return vector;
1687
+ };
1688
+ }
1689
+
1690
+ // src/adapters/plugin-runtime/create-memory-runtime.ts
1691
+ async function createPluginMemoryRuntime(input) {
1692
+ const embeddingStatus = resolveEmbeddingStatus(input.agenrConfig);
1693
+ const database = await createDatabase(input.dbPath);
1694
+ const embedding = embeddingStatus.available ? createEmbeddingClient(requireApiKey(embeddingStatus), embeddingStatus.model) : createUnavailableEmbeddingPort(embeddingStatus.error ?? "Embeddings are unavailable.");
1695
+ const baseRecall = createRecallAdapter(database, embedding);
1696
+ const recall = attachCrossEncoderPort(baseRecall, resolveCrossEncoder(input.agenrConfig));
1697
+ const slotPolicies = input.slotPolicies;
1698
+ const fetchActiveAbstainDirectives = () => listActiveAbstainDirectives(database);
1699
+ const fetchSessionStartProactiveDirectives = () => listActiveSessionStartProactiveDirectives(database);
1700
+ const fetchTopicProactiveDirectives = () => listActiveTopicProactiveDirectives(database);
1701
+ const sessionMemoryRepository = createSessionMemoryRepository(database);
1702
+ let closed = false;
1703
+ return {
1704
+ entries: database,
1705
+ episodes: database,
1706
+ procedures: database,
1707
+ memory: createMemoryRepository(database, {
1708
+ claimSlotPolicyConfig: slotPolicies
1709
+ }),
1710
+ dreaming: createDreamPort(database),
1711
+ workingMemoryRepository: createWorkingMemoryRepository(database),
1712
+ sessionMemoryRepository,
1713
+ sessionStart: {
1714
+ repository: createSessionStartRepository(database),
1715
+ recall,
1716
+ slotPolicyConfig: slotPolicies,
1717
+ listActiveAbstainDirectives: fetchActiveAbstainDirectives,
1718
+ listActiveProactiveDirectives: fetchSessionStartProactiveDirectives,
1719
+ sessionMemoryRepository
1720
+ },
1721
+ beforeTurn: {
1722
+ recall,
1723
+ procedures: database,
1724
+ embedQuery: createEmbedQuery(embedding, embeddingStatus.available),
1725
+ slotPolicyConfig: slotPolicies,
1726
+ listActiveAbstainDirectives: fetchActiveAbstainDirectives,
1727
+ listActiveTopicProactiveDirectives: fetchTopicProactiveDirectives
1728
+ },
1729
+ embedding,
1730
+ recall,
1731
+ claimExtraction: input.claimExtraction,
1732
+ embeddingStatus: toPublicEmbeddingStatus(embeddingStatus),
1733
+ async close() {
1734
+ if (closed) {
1735
+ return;
1736
+ }
1737
+ closed = true;
1738
+ if (input.onBeforeClose) {
1739
+ await input.onBeforeClose();
1740
+ }
1741
+ await database.close();
1742
+ }
1743
+ };
1744
+ }
1745
+ function resolveEmbeddingStatus(config) {
1746
+ const model = resolveEmbeddingModel(config);
1747
+ try {
1748
+ return {
1749
+ available: true,
1750
+ provider: "openai",
1751
+ requestedProvider: "openai",
1752
+ model,
1753
+ apiKey: resolveEmbeddingApiKey(config)
1754
+ };
1755
+ } catch (error) {
1756
+ return {
1757
+ available: false,
1758
+ provider: "unconfigured",
1759
+ requestedProvider: "openai",
1760
+ model,
1761
+ error: error instanceof Error ? error.message : String(error)
1762
+ };
1763
+ }
1764
+ }
1765
+ function toPublicEmbeddingStatus(status) {
1766
+ return {
1767
+ available: status.available,
1768
+ provider: status.provider,
1769
+ requestedProvider: status.requestedProvider,
1770
+ model: status.model,
1771
+ ...status.error ? { error: status.error } : {}
1772
+ };
1773
+ }
1774
+ function createUnavailableEmbeddingPort(errorMessage) {
1775
+ return {
1776
+ async embed() {
1777
+ throw new Error(errorMessage);
1778
+ }
1779
+ };
1780
+ }
1781
+ function requireApiKey(status) {
1782
+ if (!status.apiKey) {
1783
+ throw new Error("Embedding API key is unavailable.");
1784
+ }
1785
+ return status.apiKey;
1786
+ }
1787
+ function resolveCrossEncoder(config) {
1788
+ try {
1789
+ const apiKey = resolveCrossEncoderApiKey(config);
1790
+ const { modelId } = resolveModel(config, "cross_encoder");
1791
+ return createOpenAICrossEncoder({ apiKey, model: modelId });
1792
+ } catch {
1793
+ return void 0;
1794
+ }
1795
+ }
1796
+
1797
+ // src/app/plugin-runtime/resolve-paths.ts
1798
+ function resolvePluginRuntimeConfig(config, resolvePath) {
1799
+ const dbPathOverride = resolveOptionalPath(config.dbPath, resolvePath);
1800
+ const configPathOverride = resolveOptionalPath(config.configPath, resolvePath);
1801
+ const configPath = resolveConfigPath({
1802
+ configPath: configPathOverride,
1803
+ dbPath: dbPathOverride
1804
+ });
1805
+ const loadedConfig = readConfig({
1806
+ configPath,
1807
+ dbPath: dbPathOverride
1808
+ });
1809
+ const dbPath = dbPathOverride ?? resolveDbPath(loadedConfig);
1810
+ return {
1811
+ resolvedConfig: {
1812
+ dbPath,
1813
+ configPath
1814
+ },
1815
+ agenrConfig: {
1816
+ ...loadedConfig,
1817
+ dbPath
1818
+ }
1819
+ };
1820
+ }
1821
+ function resolveOptionalPath(value, resolvePath) {
1822
+ const normalized = value?.trim();
1823
+ if (!normalized) {
1824
+ return void 0;
1825
+ }
1826
+ return resolvePath ? resolvePath(normalized) : normalized;
1827
+ }
1828
+
1829
+ // src/adapters/plugin-runtime/compose-host-services.ts
1830
+ async function composeHostPluginServices(input) {
1831
+ const { resolvedConfig, agenrConfig } = resolvePluginRuntimeConfig(input.config, input.resolvePath);
1832
+ const claimExtraction = input.resolveClaimExtraction ? await input.resolveClaimExtraction({ agenrConfig, hostConfig: input.config }) : void 0;
1833
+ const runtimeServices = await createPluginMemoryRuntime({
1834
+ dbPath: resolvedConfig.dbPath,
1835
+ agenrConfig,
1836
+ slotPolicies: input.readSlotPolicies?.(input.config),
1837
+ claimExtraction,
1838
+ onBeforeClose: input.onBeforeClose
1839
+ });
1840
+ return await input.extend({
1841
+ config: input.config,
1842
+ resolvedConfig,
1843
+ agenrConfig,
1844
+ runtimeServices
1845
+ });
1846
+ }
1847
+
1848
+ // src/app/goal-continuation/service.ts
1849
+ var GOAL_CONTINUATION_FEATURE_DISABLED_MESSAGE = "Goal continuation is disabled by the goalContinuation feature flag.";
1850
+ var GOAL_CONTINUATION_HOST_MISSING_MESSAGE = "Goal continuation is host-owned; no host callback was registered for this Agenr runtime.";
1851
+ function createGoalContinuationService(featureFlags, hostPort) {
1852
+ const featureEnabled = featureFlags.goalContinuation;
1853
+ return {
1854
+ async runCommand(params) {
1855
+ if (!featureEnabled) {
1856
+ return {
1857
+ ok: false,
1858
+ code: "feature_disabled",
1859
+ message: GOAL_CONTINUATION_FEATURE_DISABLED_MESSAGE
1860
+ };
1861
+ }
1862
+ if (!hostPort) {
1863
+ return {
1864
+ ok: false,
1865
+ code: "host_callback_missing",
1866
+ message: GOAL_CONTINUATION_HOST_MISSING_MESSAGE
1867
+ };
1868
+ }
1869
+ return hostPort.runCommand(params);
1870
+ }
1871
+ };
1872
+ }
1873
+
1874
+ // src/app/session-memory/trigger-router.ts
1875
+ import { createHash } from "crypto";
1876
+ var SESSION_MEMORY_TRIGGER_FLAGS = {
1877
+ session_start: "sessionTreeLineage",
1878
+ session_before_fork: "sessionTreeLineage",
1879
+ session_before_compact: "sessionTreeCompaction",
1880
+ session_compact: "sessionTreeCompaction",
1881
+ session_before_tree: "sessionTreeCompaction",
1882
+ session_tree: "sessionTreeLineage",
1883
+ session_shutdown: "sessionTreeLineage"
1884
+ };
1885
+ var LINEAGE_REASONS = new Set(SESSION_LINEAGE_REASONS);
1886
+ async function routeSessionMemoryTrigger(event, featureFlags, deps = {}) {
1887
+ const flagKey = SESSION_MEMORY_TRIGGER_FLAGS[event.type];
1888
+ if (!featureFlags[flagKey]) {
1889
+ return {
1890
+ accepted: false,
1891
+ reason: "feature_disabled",
1892
+ message: `Session-memory trigger ${event.type} is disabled by feature flags.`
1893
+ };
1894
+ }
1895
+ if (!deps.repository) {
1896
+ return {
1897
+ accepted: false,
1898
+ reason: "misconfigured",
1899
+ message: `Session-memory trigger ${event.type} is enabled, but no session-memory repository was wired into the runtime.`
1900
+ };
1901
+ }
1902
+ const artifactInput = normalizeArtifactInput(event);
1903
+ if (artifactInput.kind === "invalid") {
1904
+ return invalidEvent(artifactInput.message);
1905
+ }
1906
+ const lineageInput = normalizeLineageInput(event);
1907
+ if (lineageInput.kind === "invalid") {
1908
+ return invalidEvent(lineageInput.message);
1909
+ }
1910
+ if (artifactInput.kind === "none" && lineageInput.kind === "none") {
1911
+ return maybeAttachWorkingCheckpointRefresh(
1912
+ event,
1913
+ {
1914
+ accepted: true,
1915
+ action: isCheckpointRelevantTrigger(event.type) ? "checkpoint_relevant" : "no_lineage",
1916
+ message: isCheckpointRelevantTrigger(event.type) ? `Session-memory trigger ${event.type} was accepted for checkpoint-relevant lifecycle handling.` : `Session-memory trigger ${event.type} did not include lineage or artifact facts.`
1917
+ },
1918
+ deps
1919
+ );
1920
+ }
1921
+ const intakeInput = {
1922
+ ...artifactInput.kind === "artifact" ? { artifact: artifactInput.input } : {},
1923
+ ...lineageInput.kind === "lineage" ? { lineage: lineageInput.input } : {}
1924
+ };
1925
+ const intake = await deps.repository.recordTriggerIntake(intakeInput);
1926
+ const artifact = intake.artifact;
1927
+ const lineageEdge = intake.lineageEdge;
1928
+ const action = resolveTriggerAction(artifact, lineageEdge);
1929
+ return maybeAttachWorkingCheckpointRefresh(
1930
+ event,
1931
+ {
1932
+ accepted: true,
1933
+ action,
1934
+ message: buildAcceptedMessage(event.type, action, artifact, lineageEdge),
1935
+ ...lineageEdge ? { lineageEdge } : {},
1936
+ ...artifact ? { artifact } : {}
1937
+ },
1938
+ deps
1939
+ );
1940
+ }
1941
+ async function maybeAttachWorkingCheckpointRefresh(event, result, deps) {
1942
+ if (!deps.workingMemoryEnabled) {
1943
+ return result;
1944
+ }
1945
+ const { attachWorkingCheckpointRefresh } = await import("./lifecycle-checkpoint-IAC5FCQU.js");
1946
+ return attachWorkingCheckpointRefresh(event, result, deps.workingMemory);
1947
+ }
1948
+ function normalizeLineageInput(event) {
1949
+ if (!event.transitionReason || event.transitionReason === "new" || event.transitionReason === "unknown") {
1950
+ return { kind: "none" };
1951
+ }
1952
+ if (!LINEAGE_REASONS.has(event.transitionReason)) {
1953
+ return { kind: "invalid", message: `Unsupported session lineage reason "${event.transitionReason}".` };
1954
+ }
1955
+ const childSessionKey = normalizeOptionalString(event.childSessionKey) ?? normalizeOptionalString(event.sessionKey);
1956
+ if (!childSessionKey) {
1957
+ return { kind: "invalid", message: "Session lineage requires a child session key." };
1958
+ }
1959
+ const parentSessionKey = normalizeOptionalString(event.predecessor?.sessionKey);
1960
+ const parentSourceRef = normalizeOptionalString(event.predecessor?.sourceRef);
1961
+ if (!parentSessionKey && !parentSourceRef) {
1962
+ return { kind: "none" };
1963
+ }
1964
+ const forkEntryId = normalizeOptionalString(event.predecessor?.forkEntryId);
1965
+ const forkPosition = normalizeOptionalString(event.predecessor?.forkPosition);
1966
+ return {
1967
+ kind: "lineage",
1968
+ input: {
1969
+ childSessionKey,
1970
+ ...parentSessionKey ? { parentSessionKey } : {},
1971
+ ...parentSourceRef ? { parentSourceRef } : {},
1972
+ reason: event.transitionReason,
1973
+ ...forkEntryId ? { forkEntryId } : {},
1974
+ ...forkPosition ? { forkPosition } : {},
1975
+ observedAt: event.observedAt
1976
+ }
1977
+ };
1978
+ }
1979
+ function normalizeArtifactInput(event) {
1980
+ if (!event.artifact) {
1981
+ return { kind: "none" };
1982
+ }
1983
+ const sessionKey = normalizeOptionalString(event.artifact.sessionKey) ?? normalizeOptionalString(event.sessionKey);
1984
+ if (!sessionKey) {
1985
+ return { kind: "invalid", message: "Session artifact intake requires a session key." };
1986
+ }
1987
+ const source = normalizeOptionalString(event.artifact.source);
1988
+ const sourceId = normalizeOptionalString(event.artifact.sourceId);
1989
+ const summary = normalizeOptionalString(event.artifact.summary);
1990
+ if (!source || !sourceId || !summary) {
1991
+ return { kind: "invalid", message: "Session artifact intake requires source, sourceId, and summary." };
1992
+ }
1993
+ const contentHash = normalizeOptionalString(event.artifact.contentHash) ?? hashArtifactContent(event.artifact);
1994
+ return {
1995
+ kind: "artifact",
1996
+ input: {
1997
+ ...event.artifact,
1998
+ sessionKey,
1999
+ source,
2000
+ sourceId,
2001
+ summary,
2002
+ contentHash
2003
+ }
2004
+ };
2005
+ }
2006
+ function hashArtifactContent(artifact) {
2007
+ const payload = JSON.stringify({
2008
+ kind: artifact.kind,
2009
+ source: artifact.source,
2010
+ sourceId: artifact.sourceId,
2011
+ sourceRef: artifact.sourceRef,
2012
+ summary: artifact.summary,
2013
+ metadata: artifact.metadata
2014
+ });
2015
+ return createHash("sha256").update(payload).digest("hex");
2016
+ }
2017
+ function resolveTriggerAction(artifact, lineageEdge) {
2018
+ if (artifact && lineageEdge) {
2019
+ return "recorded";
2020
+ }
2021
+ if (artifact) {
2022
+ return "artifact_recorded";
2023
+ }
2024
+ return "lineage_recorded";
2025
+ }
2026
+ function buildAcceptedMessage(triggerType, action, artifact, lineageEdge) {
2027
+ if (action === "recorded" && artifact && lineageEdge) {
2028
+ return `Session-memory trigger ${triggerType} recorded ${lineageEdge.reason} lineage edge ${lineageEdge.id} and ${artifact.kind} artifact ${artifact.id}.`;
2029
+ }
2030
+ if (action === "artifact_recorded" && artifact) {
2031
+ return `Session-memory trigger ${triggerType} recorded ${artifact.kind} artifact ${artifact.id}.`;
2032
+ }
2033
+ if (lineageEdge) {
2034
+ return `Session-memory trigger ${triggerType} recorded ${lineageEdge.reason} lineage edge ${lineageEdge.id}.`;
2035
+ }
2036
+ return `Session-memory trigger ${triggerType} was accepted.`;
2037
+ }
2038
+ function invalidEvent(message) {
2039
+ return {
2040
+ accepted: false,
2041
+ reason: "invalid_event",
2042
+ message
2043
+ };
2044
+ }
2045
+ function isCheckpointRelevantTrigger(type) {
2046
+ return type === "session_before_fork" || type === "session_before_compact" || type === "session_before_tree" || type === "session_shutdown";
2047
+ }
2048
+
2049
+ // src/app/working-memory/disabled-service.ts
2050
+ function createDisabledWorkingMemoryService() {
2051
+ const failure = () => createFailure("feature_disabled", WORKING_MEMORY_DISABLED_MESSAGE);
2052
+ return {
2053
+ async run(_params) {
2054
+ return failure();
2055
+ },
2056
+ async prepareExternalGoalMutation(_params) {
2057
+ return failure();
2058
+ },
2059
+ async renderProjection(input) {
2060
+ const sourceRef = typeof input === "string" ? input : input.sourceRef;
2061
+ return createWorkingContextStubProjection({
2062
+ reason: "feature_disabled",
2063
+ sourceRef
2064
+ });
2065
+ }
2066
+ };
2067
+ }
2068
+
2069
+ // src/app/host-memory/create-host-memory-services.ts
2070
+ async function createHostMemoryServices(featureFlags, options = {}) {
2071
+ const workingMemory = featureFlags.workingMemory ? (await import("./service-RHNB5AEQ.js")).createWorkingMemoryService(featureFlags, {
2072
+ repository: options.workingMemoryRepository,
2073
+ sourceLabel: options.workingMemorySourceLabel
2074
+ }) : createDisabledWorkingMemoryService();
2075
+ return {
2076
+ workingMemory,
2077
+ goalContinuation: createGoalContinuationService(featureFlags, options.goalContinuationHostPort),
2078
+ routeSessionMemoryTrigger: (event) => routeSessionMemoryTrigger(event, featureFlags, {
2079
+ repository: options.sessionMemoryRepository,
2080
+ workingMemoryEnabled: featureFlags.workingMemory,
2081
+ workingMemory: featureFlags.workingMemory ? workingMemory : void 0
2082
+ })
2083
+ };
2084
+ }
2085
+
2086
+ // src/adapters/shared/shutdown-episode-threshold.ts
2087
+ var HOST_SHUTDOWN_EPISODE_ACTIVITY_THRESHOLD = {
2088
+ minMaterialTurns: 8,
2089
+ minDurationMs: 20 * 60 * 1e3
2090
+ };
2091
+
2092
+ // src/adapters/shared/bounded-episode-embedding.ts
2093
+ var EPISODE_EMBEDDING_RACE_TIMEOUT = /* @__PURE__ */ Symbol("episode-embedding-race-timeout");
2094
+ var EPISODE_EMBEDDING_MIN_HEADROOM_MS = 5e3;
2095
+ async function embedEpisodeSummaryWithinBudget(params) {
2096
+ const minHeadroomMs = params.minHeadroomMs ?? EPISODE_EMBEDDING_MIN_HEADROOM_MS;
2097
+ if (!params.embeddingAvailable) {
2098
+ params.logger.info(`${params.logContext} reason=embedding_unavailable`);
2099
+ return void 0;
2100
+ }
2101
+ const remainingBudgetMs = params.deadlineMs - Date.now();
2102
+ if (remainingBudgetMs < minHeadroomMs) {
2103
+ params.logger.info(`${params.logContext} reason=budget_tight remainingMs=${Math.max(0, remainingBudgetMs)}`);
2104
+ return void 0;
2105
+ }
2106
+ try {
2107
+ const result = await raceEmbeddingWithTimeout(params.embedding.embed([params.summary]), remainingBudgetMs);
2108
+ if (result === EPISODE_EMBEDDING_RACE_TIMEOUT) {
2109
+ params.logger.info(`${params.logContext} reason=embedding_timeout budgetMs=${remainingBudgetMs}`);
2110
+ return void 0;
2111
+ }
2112
+ const vector = result[0]?.map((value) => Number.isFinite(value) ? value : 0);
2113
+ if (!vector || vector.length === 0) {
2114
+ params.logger.info(`${params.logContext} reason=empty_embedding`);
2115
+ return void 0;
2116
+ }
2117
+ return vector;
2118
+ } catch (error) {
2119
+ params.logger.info(`${params.logContext} reason=${formatErrorMessage(error)}`);
2120
+ return void 0;
2121
+ }
2122
+ }
2123
+ async function raceEmbeddingWithTimeout(promise, timeoutMs) {
2124
+ return new Promise((resolve, reject) => {
2125
+ const timeout = setTimeout(() => {
2126
+ resolve(EPISODE_EMBEDDING_RACE_TIMEOUT);
2127
+ }, timeoutMs);
2128
+ promise.then(
2129
+ (value) => {
2130
+ clearTimeout(timeout);
2131
+ resolve(value);
2132
+ },
2133
+ (error) => {
2134
+ clearTimeout(timeout);
2135
+ reject(error);
2136
+ }
2137
+ );
2138
+ });
2139
+ }
2140
+
2141
+ // src/adapters/shared/bounded-episode-summary.ts
2142
+ var EPISODE_SUMMARY_TIMEOUT_MS = 45e3;
2143
+ var EPISODE_SUMMARY_TIMEOUT_MESSAGE = "Episode summary generation timed out.";
2144
+ var EpisodeSummaryTimeoutError = class extends Error {
2145
+ /**
2146
+ * Creates a timeout error with a stable name for caller-side handling.
2147
+ */
2148
+ constructor() {
2149
+ super(EPISODE_SUMMARY_TIMEOUT_MESSAGE);
2150
+ this.name = "EpisodeSummaryTimeoutError";
2151
+ }
2152
+ };
2153
+ async function raceEpisodeSummaryWithinTimeout(task, timeoutMs) {
2154
+ let timeout;
2155
+ try {
2156
+ return await Promise.race([
2157
+ task,
2158
+ new Promise((_, reject) => {
2159
+ timeout = setTimeout(() => reject(new EpisodeSummaryTimeoutError()), timeoutMs);
2160
+ })
2161
+ ]);
2162
+ } finally {
2163
+ if (timeout) {
2164
+ clearTimeout(timeout);
2165
+ }
2166
+ }
2167
+ }
2168
+
2169
+ // src/adapters/shared/bounded-episode-ingest-log.ts
2170
+ function logBoundedEpisodeTranscriptIngestOutcome(params) {
2171
+ const prefix = `[agenr] ${params.actionLabel}`;
2172
+ const fileField = params.fileField ?? "file";
2173
+ const fileRef = `${fileField}=${params.filePath}`;
2174
+ const countField = params.shortCountField ?? "materialTurns";
2175
+ if (params.result.kind === "skipped") {
2176
+ const skipped = params.result.skipped;
2177
+ if (skipped.reason === "skipped_exists") {
2178
+ params.logger.info(`${prefix} skipped for ${params.context} ${fileRef} reason=already_exists episode=${skipped.existingEpisode?.id}`);
2179
+ return false;
2180
+ }
2181
+ if (skipped.reason === "skipped_short") {
2182
+ params.logger.info(`${prefix} skipped for ${params.context} ${fileRef} reason=too_short ${countField}=${skipped.messageCount}`);
2183
+ return false;
2184
+ }
2185
+ params.logger.info(`${prefix} skipped for ${params.context} ${fileRef} reason=${skipped.reason} ${countField}=${skipped.messageCount}`);
2186
+ return false;
2187
+ }
2188
+ if (params.result.kind === "invalid") {
2189
+ params.logger.info(`${prefix} skipped for ${params.context} ${fileRef} reason=invalid_transcript ${countField}=${params.result.invalid.messageCount}`);
2190
+ return false;
2191
+ }
2192
+ const session = params.result.session;
2193
+ if (session.action === "failed") {
2194
+ if (session.error === EPISODE_SUMMARY_TIMEOUT_MESSAGE) {
2195
+ params.logger.info(`${prefix} timed_out for ${params.context} ${fileRef} timeoutMs=${EPISODE_SUMMARY_TIMEOUT_MS}`);
2196
+ return false;
2197
+ }
2198
+ if (session.error === "invalid_response" && params.failureModelRef) {
2199
+ params.logger.info(`${prefix} failed for ${params.context} ${fileRef} reason=invalid_response model=${params.failureModelRef}`);
2200
+ return false;
2201
+ }
2202
+ params.logger.info(`${prefix} failed for ${params.context} ${fileRef} reason=${session.error ?? "unknown"}`);
2203
+ return false;
2204
+ }
2205
+ params.logger.info(`${prefix} ${session.action} for ${params.context} ${fileRef} episode=${session.episodeId}`);
2206
+ return true;
2207
+ }
2208
+
2209
+ // src/adapters/shared/bounded-episode-write.ts
2210
+ async function writeBoundedSingleTranscriptEpisode(params) {
2211
+ const fileField = params.fileField ?? "file";
2212
+ const fileRef = `${fileField}=${params.filePath}`;
2213
+ try {
2214
+ const ingestResult = await raceEpisodeSummaryWithinTimeout(
2215
+ ingestEpisodeTranscript(params.filePath, params.ports, params.ingestOptions),
2216
+ EPISODE_SUMMARY_TIMEOUT_MS
2217
+ );
2218
+ logBoundedEpisodeTranscriptIngestOutcome({
2219
+ logger: params.logger,
2220
+ actionLabel: params.actionLabel,
2221
+ context: params.context,
2222
+ filePath: params.filePath,
2223
+ ...params.fileField ? { fileField: params.fileField } : {},
2224
+ ...params.shortCountField ? { shortCountField: params.shortCountField } : {},
2225
+ result: ingestResult,
2226
+ ...params.failureModelRef ? { failureModelRef: params.failureModelRef } : {}
2227
+ });
2228
+ } catch (error) {
2229
+ if (error instanceof EpisodeSummaryTimeoutError) {
2230
+ params.logger.info(`[agenr] ${params.actionLabel} timed_out for ${params.context} ${fileRef} timeoutMs=${EPISODE_SUMMARY_TIMEOUT_MS}`);
2231
+ return;
2232
+ }
2233
+ const message = formatErrorMessage(error);
2234
+ if (params.unexpectedFailureLevel === "info") {
2235
+ params.logger.info(`[agenr] ${params.actionLabel} failed for ${params.context} ${fileRef} reason=${message}`);
2236
+ return;
2237
+ }
2238
+ params.logger.warn(`[agenr] ${params.actionLabel} failed for ${params.context} ${fileRef} reason=${message}`);
2239
+ }
2240
+ }
2241
+
2242
+ // src/adapters/shared/deadline-aware-episode-summary-llm.ts
2243
+ function createDeadlineAwareEpisodeSummaryLlm(baseLlm, deadlineMs) {
2244
+ const usage = cloneUsageStats(baseLlm.metadata.usage);
2245
+ const completeWithTimeout = async (task) => {
2246
+ usage.calls += 1;
2247
+ const remainingMs = Math.max(0, deadlineMs - Date.now());
2248
+ return raceEpisodeSummaryWithinTimeout(task, remainingMs);
2249
+ };
2250
+ return {
2251
+ complete: async (systemPrompt, userMessage) => completeWithTimeout(baseLlm.complete(systemPrompt, userMessage)),
2252
+ completeJson: async (systemPrompt, userMessage) => completeWithTimeout(baseLlm.completeJson(systemPrompt, userMessage)),
2253
+ metadata: {
2254
+ ...baseLlm.metadata,
2255
+ usage
2256
+ }
2257
+ };
2258
+ }
2259
+ function cloneUsageStats(usage) {
2260
+ return { ...usage };
2261
+ }
2262
+
2263
+ // src/adapters/shared/claim-support.ts
2264
+ function buildSessionSourceFile(session, prefix) {
2265
+ const target = session.sessionKey ?? session.sessionId ?? session.agentId ?? "unknown";
2266
+ return `${prefix}:${target}`;
2267
+ }
2268
+ function buildToolCallClaimSupport(session, prefix, toolName, observedAt) {
2269
+ return {
2270
+ claim_support_source_kind: "tool_call",
2271
+ claim_support_locator: `${buildSessionSourceFile(session, prefix)}#${toolName}`,
2272
+ claim_support_observed_at: observedAt,
2273
+ claim_support_mode: "explicit"
2274
+ };
2275
+ }
2276
+
2277
+ // src/adapters/shared/resolve-target.ts
2278
+ function buildEntryMemoryResolverPorts(services) {
2279
+ return {
2280
+ getDurableById: async (entryId) => await services.entries.getDurable(entryId) ?? (await services.memory.getEntryTrace(entryId))?.entry ?? null,
2281
+ findEntryBySubject: async (subject) => services.memory.findEntryBySubject(subject)
2282
+ };
2283
+ }
2284
+ async function resolveTargetDurable(ports, params) {
2285
+ const id = readOptionalStringParam(params, "id");
2286
+ const subject = readOptionalStringParam(params, "subject");
2287
+ const selectorCount = (id ? 1 : 0) + (subject ? 1 : 0);
2288
+ if (selectorCount !== 1) {
2289
+ throw new Error("Provide exactly one target selector: id or subject.");
2290
+ }
2291
+ if (id) {
2292
+ const entry2 = await ports.getDurableById(id);
2293
+ if (!entry2) {
2294
+ throw new Error(`No agenr entry found for id ${id}.`);
2295
+ }
2296
+ return entry2;
2297
+ }
2298
+ const entry = await ports.findEntryBySubject(subject ?? "");
2299
+ if (!entry) {
2300
+ throw new Error(`No agenr entry found for subject "${subject}".`);
2301
+ }
2302
+ return entry;
2303
+ }
2304
+ function readOptionalStringParam(params, key) {
2305
+ const value = params[key];
2306
+ if (value === void 0 || value === null) {
2307
+ return void 0;
2308
+ }
2309
+ if (typeof value !== "string") {
2310
+ throw new Error(`${key} must be a string.`);
2311
+ }
2312
+ const normalized = value.trim();
2313
+ return normalized.length > 0 ? normalized : void 0;
2314
+ }
2315
+
2316
+ // src/adapters/shared/memory-tools.ts
2317
+ function buildRecallToolServices(services) {
2318
+ return {
2319
+ episodes: services.episodes,
2320
+ procedures: services.procedures,
2321
+ recall: services.recall,
2322
+ embeddingStatus: services.embeddingStatus,
2323
+ embedQuery: services.beforeTurn.embedQuery
2324
+ };
2325
+ }
2326
+ var STORE_TOOL_PARAMETERS = {
2327
+ type: "object",
2328
+ additionalProperties: false,
2329
+ properties: {
2330
+ type: {
2331
+ type: "string",
2332
+ enum: [...DURABLE_KINDS],
2333
+ description: ENTRY_TYPE_DESCRIPTION
2334
+ },
2335
+ subject: {
2336
+ type: "string",
2337
+ description: "Short subject line future recall can match. Name the durable takeaway, person, system, rule, relationship, or milestone directly."
2338
+ },
2339
+ content: {
2340
+ type: "string",
2341
+ description: "What a fresh session should remember. Store the durable takeaway, not the activity log, canonical record, or transient progress snapshot."
2342
+ },
2343
+ importance: {
2344
+ type: "integer",
2345
+ minimum: 1,
2346
+ maximum: 10,
2347
+ description: "Importance from 1 to 10. Use 7 for normal durable memory, 9 for critical constraints, and 10 only rarely."
2348
+ },
2349
+ expiry: {
2350
+ type: "string",
2351
+ enum: ["core", "permanent", "temporary"],
2352
+ description: EXPIRY_DESCRIPTION
2353
+ },
2354
+ tags: {
2355
+ type: "array",
2356
+ items: { type: "string" },
2357
+ description: "Optional tags for entities, systems, teams, or themes that should improve later recall."
2358
+ },
2359
+ sourceContext: {
2360
+ type: "string",
2361
+ description: "Optional provenance note explaining why this memory was stored or what situation produced it."
2362
+ },
2363
+ supersedes: {
2364
+ type: "string",
2365
+ description: "ID of an entry this replaces. The old entry will be marked as superseded."
2366
+ },
2367
+ claimKey: {
2368
+ type: "string",
2369
+ description: CLAIM_KEY_DESCRIPTION
2370
+ },
2371
+ polarity: {
2372
+ type: "string",
2373
+ enum: ["abstain", "proactive"],
2374
+ description: "Required when type is directive. Use abstain to suppress a topic or behavior; use proactive to surface the directive when its trigger fires."
2375
+ },
2376
+ trigger: {
2377
+ type: "string",
2378
+ description: "Optional when type is directive. Use session_start or always for proactive directives that should surface at session start; use topic:<term> for proactive directives that should surface during before-turn when the user mentions the topic; use always for abstain directives. Defaults to session_start for proactive directives and always for abstain directives."
2379
+ },
2380
+ validFrom: {
2381
+ type: "string",
2382
+ description: "ISO 8601 timestamp for when this fact became true in the world."
2383
+ },
2384
+ validTo: {
2385
+ type: "string",
2386
+ description: "ISO 8601 timestamp for when this fact stopped being true."
2387
+ },
2388
+ project: {
2389
+ type: "string",
2390
+ description: "Optional workspace or product slug when this memory is specifically about one repo or deployment. Omit for personal, family, and other cross-workspace facts even when the current session has a workspace."
2391
+ }
2392
+ },
2393
+ required: ["type", "subject", "content"]
2394
+ };
2395
+ var RECALL_TOOL_PARAMETERS = {
2396
+ type: "object",
2397
+ additionalProperties: false,
2398
+ properties: {
2399
+ query: {
2400
+ type: "string",
2401
+ description: "What you need to remember. Use a focused natural-language query rather than a broad 'everything' search. Phrase prior-state asks directly, for example 'what was the previous approach' or 'what changed from X to Y'. Phrase procedural asks directly, for example 'how do I rotate credentials' or 'what steps should I follow'."
2402
+ },
2403
+ mode: {
2404
+ type: "string",
2405
+ enum: [...RECALL_MODES],
2406
+ description: RECALL_MODE_SCHEMA_DESCRIPTION
2407
+ },
2408
+ limit: {
2409
+ type: "integer",
2410
+ minimum: 1,
2411
+ maximum: 10,
2412
+ description: "Maximum results to return. Lower this when you want a tighter shortlist."
2413
+ },
2414
+ threshold: {
2415
+ type: "number",
2416
+ minimum: 0,
2417
+ maximum: 1,
2418
+ description: "Minimum final score from 0 to 1. Raise this when you want fewer, higher-confidence matches."
2419
+ },
2420
+ budget: {
2421
+ type: "integer",
2422
+ minimum: 1,
2423
+ description: "Approximate token budget applied after durable scoring. Omit when you do not want a budget cap."
2424
+ },
2425
+ types: {
2426
+ type: "array",
2427
+ items: {
2428
+ type: "string",
2429
+ enum: [...DURABLE_KINDS]
2430
+ },
2431
+ description: "Optional knowledge types to filter by, such as decision, preference, lesson, fact, milestone, or relationship."
2432
+ },
2433
+ tags: {
2434
+ type: "array",
2435
+ items: { type: "string" },
2436
+ description: "Optional tags to filter by once you already know the relevant entity, system, or theme."
2437
+ },
2438
+ asOf: {
2439
+ type: "string",
2440
+ description: "Optional reference time for current-vs-prior resolution. Supports ISO timestamps and natural-language date phrases."
2441
+ }
2442
+ },
2443
+ required: ["query"]
2444
+ };
2445
+ var UPDATE_TOOL_PARAMETERS = {
2446
+ type: "object",
2447
+ additionalProperties: false,
2448
+ properties: {
2449
+ id: {
2450
+ type: "string",
2451
+ description: "Entry id to update. Provide exactly one of id or subject."
2452
+ },
2453
+ subject: {
2454
+ type: "string",
2455
+ description: "Subject text to resolve when the id is unknown. The most recent exact or substring match wins. Provide exactly one of id or subject."
2456
+ },
2457
+ importance: {
2458
+ type: "integer",
2459
+ description: "New importance from 1 to 10. Use 7 for normal durable memory and reserve 9 to 10 for rare critical durables."
2460
+ },
2461
+ expiry: {
2462
+ type: "string",
2463
+ description: UPDATE_EXPIRY_DESCRIPTION
2464
+ },
2465
+ claimKey: {
2466
+ type: "string",
2467
+ description: CLAIM_KEY_DESCRIPTION
2468
+ },
2469
+ validFrom: {
2470
+ type: "string",
2471
+ description: "ISO 8601 timestamp for when this fact became true."
2472
+ },
2473
+ validTo: {
2474
+ type: "string",
2475
+ description: "ISO 8601 timestamp for when this fact stopped being true."
2476
+ },
2477
+ project: {
2478
+ type: "string",
2479
+ description: "Workspace or product slug for correcting memory scope/routing metadata. Use agenr_store with supersedes instead when the memory content, subject, type, or meaning changes."
2480
+ }
2481
+ }
2482
+ };
2483
+ var FETCH_TOOL_PARAMETERS = {
2484
+ type: "object",
2485
+ additionalProperties: false,
2486
+ properties: {
2487
+ id: {
2488
+ type: "string",
2489
+ description: "Entry id to fetch. Provide exactly one of id or subject."
2490
+ },
2491
+ subject: {
2492
+ type: "string",
2493
+ description: "Subject text to resolve when the id is unknown. The most recent exact or substring match wins. Provide exactly one of id or subject."
2494
+ }
2495
+ }
2496
+ };
2497
+ function parseStoreToolParams(rawParams, reader) {
2498
+ const params = asRecord(rawParams);
2499
+ const type = parseDurableKind(reader.readString(params, "type", { required: true, label: "type" }) ?? "");
2500
+ return {
2501
+ type,
2502
+ subject: reader.readString(params, "subject", { required: true, label: "subject" }) ?? "",
2503
+ content: reader.readString(params, "content", { required: true, label: "content" }) ?? "",
2504
+ importance: reader.readNumber(params, "importance", { integer: true, strict: true }),
2505
+ expiry: parseExpiry(reader.readString(params, "expiry")),
2506
+ tags: normalizeStringArray(reader.readStringArray(params, "tags")),
2507
+ sourceContext: reader.readString(params, "sourceContext"),
2508
+ supersedes: reader.readString(params, "supersedes"),
2509
+ claimKey: reader.readString(params, "claimKey", { trim: false }),
2510
+ polarity: parseDirectivePolarityParam(reader.readString(params, "polarity")),
2511
+ trigger: parseDirectiveTriggerParam(reader.readString(params, "trigger")),
2512
+ validFrom: reader.readString(params, "validFrom"),
2513
+ validTo: reader.readString(params, "validTo"),
2514
+ project: reader.readString(params, "project")
2515
+ };
2516
+ }
2517
+ function parseRecallToolParams(rawParams, reader) {
2518
+ const params = asRecord(rawParams);
2519
+ const budget = reader.readNumber(params, "budget", { integer: true, strict: true });
2520
+ if (budget !== void 0 && budget <= 0) {
2521
+ throw new Error("budget must be a positive integer.");
2522
+ }
2523
+ return {
2524
+ query: reader.readString(params, "query", { required: true, label: "query" }) ?? "",
2525
+ mode: parseRecallMode(reader.readString(params, "mode")),
2526
+ limit: reader.readNumber(params, "limit", { integer: true, strict: true }),
2527
+ threshold: reader.readNumber(params, "threshold", { strict: true }),
2528
+ budget,
2529
+ types: parseDurableKinds(reader.readStringArray(params, "types")),
2530
+ tags: normalizeStringArray(reader.readStringArray(params, "tags")),
2531
+ asOf: reader.readString(params, "asOf")
2532
+ };
2533
+ }
2534
+ function parseUpdateToolParams(rawParams, reader) {
2535
+ const params = asRecord(rawParams);
2536
+ return {
2537
+ id: reader.readString(params, "id"),
2538
+ subject: reader.readString(params, "subject"),
2539
+ importance: reader.readNumber(params, "importance", { integer: true, strict: true }),
2540
+ expiry: parseExpiry(reader.readString(params, "expiry")),
2541
+ claimKeyInput: reader.readString(params, "claimKey", { trim: false }),
2542
+ validFrom: reader.readString(params, "validFrom"),
2543
+ validTo: reader.readString(params, "validTo"),
2544
+ project: reader.readString(params, "project")
2545
+ };
2546
+ }
2547
+ function parseFetchToolParams(rawParams, reader) {
2548
+ const params = asRecord(rawParams);
2549
+ return {
2550
+ id: reader.readString(params, "id"),
2551
+ subject: reader.readString(params, "subject")
2552
+ };
2553
+ }
2554
+ async function runStoreMemoryTool(params, services, options) {
2555
+ const sourceContext = params.sourceContext ?? options.defaultSourceContext;
2556
+ const project = resolveDurableProjectScope(
2557
+ {
2558
+ project: params.project,
2559
+ subject: params.subject,
2560
+ content: params.content,
2561
+ tags: params.tags,
2562
+ source_context: sourceContext,
2563
+ claim_key: params.claimKey
2564
+ },
2565
+ { sessionWorkspace: options.session.project }
2566
+ );
2567
+ const warnings = [];
2568
+ const handleWarning = (warning) => {
2569
+ warnings.push(warning);
2570
+ options.onWarning?.(warning);
2571
+ };
2572
+ const result = await storeDurablesDetailed(
2573
+ [
2574
+ {
2575
+ type: params.type,
2576
+ subject: params.subject,
2577
+ content: params.content,
2578
+ ...params.importance !== void 0 ? { importance: params.importance } : {},
2579
+ ...params.expiry !== void 0 ? { expiry: params.expiry } : {},
2580
+ ...params.tags.length > 0 ? { tags: params.tags } : {},
2581
+ ...params.supersedes ? { supersedes: params.supersedes } : {},
2582
+ ...params.claimKey ? {
2583
+ claim_key: params.claimKey,
2584
+ claim_key_raw: params.claimKey,
2585
+ ...buildToolCallClaimSupport(options.session, options.sourcePrefix, "agenr_store", (/* @__PURE__ */ new Date()).toISOString())
2586
+ } : {},
2587
+ ...params.polarity ? { directive_polarity: params.polarity } : {},
2588
+ ...params.trigger ? { directive_trigger: params.trigger } : {},
2589
+ ...params.validFrom ? { valid_from: params.validFrom } : {},
2590
+ ...params.validTo ? { valid_to: params.validTo } : {},
2591
+ source_file: buildSessionSourceFile(options.session, options.sourcePrefix),
2592
+ source_context: sourceContext,
2593
+ ...project ? { project } : {}
2594
+ }
2595
+ ],
2596
+ services.entries,
2597
+ services.embedding,
2598
+ {
2599
+ ...services.claimExtraction ? {
2600
+ claimExtraction: {
2601
+ llm: services.claimExtraction.llm,
2602
+ db: services.entries,
2603
+ config: services.claimExtraction.config
2604
+ }
2605
+ } : {},
2606
+ onWarning: handleWarning
2607
+ }
2608
+ );
2609
+ const storedEntry = await services.memory.findEntryBySubject(params.subject);
2610
+ if (result.stored > 0) {
2611
+ return okOutcome(
2612
+ `Stored "${params.subject}".`,
2613
+ {
2614
+ status: "stored",
2615
+ subject: params.subject,
2616
+ entryId: storedEntry?.id,
2617
+ result,
2618
+ ...options.extraDetails
2619
+ },
2620
+ warnings
2621
+ );
2622
+ }
2623
+ if (result.skipped > 0) {
2624
+ return okOutcome(
2625
+ `Skipped "${params.subject}" because an active duplicate already exists.`,
2626
+ {
2627
+ status: "skipped",
2628
+ subject: params.subject,
2629
+ entryId: storedEntry?.id,
2630
+ result,
2631
+ ...options.extraDetails
2632
+ },
2633
+ warnings
2634
+ );
2635
+ }
2636
+ return failedOutcome(
2637
+ `Rejected "${params.subject}". Check the supplied type, content, and metadata.`,
2638
+ {
2639
+ status: "failed",
2640
+ subject: params.subject,
2641
+ result,
2642
+ ...options.extraDetails
2643
+ },
2644
+ warnings
2645
+ );
2646
+ }
2647
+ async function runRecallMemoryTool(params, services, options = {}) {
2648
+ return runUnifiedRecall(
2649
+ {
2650
+ text: params.query,
2651
+ ...params.mode ? { mode: params.mode } : {},
2652
+ ...params.limit !== void 0 ? { limit: params.limit } : {},
2653
+ ...params.threshold !== void 0 ? { threshold: params.threshold } : {},
2654
+ ...params.budget !== void 0 ? { budget: params.budget } : {},
2655
+ ...params.types.length > 0 ? { types: params.types } : {},
2656
+ ...params.tags.length > 0 ? { tags: params.tags } : {},
2657
+ ...params.asOf ? { asOf: params.asOf } : {},
2658
+ ...options.sessionKey ? { sessionKey: options.sessionKey } : {}
2659
+ },
2660
+ {
2661
+ database: services.episodes,
2662
+ procedures: services.procedures,
2663
+ recall: services.recall,
2664
+ embeddingAvailable: services.embeddingStatus.available,
2665
+ embeddingError: services.embeddingStatus.error,
2666
+ claimSlotPolicyConfig: options.slotPolicyConfig,
2667
+ debugLog: options.debugLog,
2668
+ embedQuery: services.embedQuery,
2669
+ recallOptions: {
2670
+ slotPolicyConfig: options.slotPolicyConfig
2671
+ }
2672
+ }
2673
+ );
2674
+ }
2675
+ async function runFetchMemoryTool(params, services, options = {}) {
2676
+ const entry = await resolveTargetDurable(buildEntryMemoryResolverPorts(services), { id: params.id, subject: params.subject });
2677
+ assertEntryFetchableContentLength(entry.content);
2678
+ return okOutcome(formatFetchedEntryText(entry), buildFetchToolDetails(entry, options.extraDetails));
2679
+ }
2680
+ async function runUpdateMemoryTool(params, services, options) {
2681
+ const claimSupport = params.claimKeyInput === void 0 ? void 0 : buildToolCallClaimSupport(options.session, options.sourcePrefix, "agenr_update", (/* @__PURE__ */ new Date()).toISOString());
2682
+ const normalizedClaimKeyUpdate = params.claimKeyInput === void 0 ? void 0 : (() => {
2683
+ try {
2684
+ return normalizeManualClaimKeyUpdate({
2685
+ claimKey: params.claimKeyInput,
2686
+ rawClaimKey: params.claimKeyInput,
2687
+ supportSourceKind: claimSupport?.claim_support_source_kind,
2688
+ supportLocator: claimSupport?.claim_support_locator,
2689
+ supportObservedAt: claimSupport?.claim_support_observed_at,
2690
+ supportMode: claimSupport?.claim_support_mode
2691
+ });
2692
+ } catch {
2693
+ throw new Error("claimKey must use canonical entity/attribute format.");
2694
+ }
2695
+ })();
2696
+ const entry = await resolveTargetDurable(buildEntryMemoryResolverPorts(services), { id: params.id, subject: params.subject });
2697
+ const mergedValidity = validateTemporalValidityRange(params.validFrom ?? entry.valid_from, params.validTo ?? entry.valid_to);
2698
+ if (!mergedValidity.ok) {
2699
+ throw new Error(mergedValidity.message);
2700
+ }
2701
+ const normalizedValidFrom = params.validFrom !== void 0 ? mergedValidity.value.validFrom : void 0;
2702
+ const normalizedValidTo = params.validTo !== void 0 ? mergedValidity.value.validTo : void 0;
2703
+ const patch = buildUpdateMemoryToolPatch(params, normalizedClaimKeyUpdate, normalizedValidFrom, normalizedValidTo);
2704
+ if (Object.keys(patch.dbFields).length === 0) {
2705
+ throw new Error("Provide at least one update field.");
2706
+ }
2707
+ const updated = await services.entries.updateDurable(entry.id, patch.dbFields);
2708
+ if (!updated) {
2709
+ return failedOutcome(`Entry ${entry.id} is not active, so it could not be updated.`, {
2710
+ status: "failed",
2711
+ entryId: entry.id,
2712
+ ...options.failureDetails
2713
+ });
2714
+ }
2715
+ return okOutcome(`Updated "${entry.subject}".`, {
2716
+ status: "updated",
2717
+ entryId: entry.id,
2718
+ subject: entry.subject,
2719
+ ...patch.details,
2720
+ ...options.successDetails
2721
+ });
2722
+ }
2723
+ function buildUpdateMemoryToolPatch(params, normalizedClaimKeyUpdate, normalizedValidFrom, normalizedValidTo) {
2724
+ const dbFields = {
2725
+ ...params.importance !== void 0 ? { importance: params.importance } : {},
2726
+ ...params.expiry !== void 0 ? { expiry: params.expiry } : {},
2727
+ ...normalizedClaimKeyUpdate?.updateFields ?? {},
2728
+ ...params.validFrom !== void 0 ? { valid_from: normalizedValidFrom } : {},
2729
+ ...params.validTo !== void 0 ? { valid_to: normalizedValidTo } : {},
2730
+ ...params.project !== void 0 ? { project: params.project } : {}
2731
+ };
2732
+ return {
2733
+ dbFields,
2734
+ details: {
2735
+ ...params.importance !== void 0 ? { importance: params.importance } : {},
2736
+ ...params.expiry !== void 0 ? { expiry: params.expiry } : {},
2737
+ ...normalizedClaimKeyUpdate !== void 0 ? { claimKey: normalizedClaimKeyUpdate.claimKey } : {},
2738
+ ...params.validFrom !== void 0 ? { validFrom: normalizedValidFrom } : {},
2739
+ ...params.validTo !== void 0 ? { validTo: normalizedValidTo } : {},
2740
+ ...params.project !== void 0 ? projectDetailValue(params.project) : {}
2741
+ }
2742
+ };
2743
+ }
2744
+ function projectDetailValue(project) {
2745
+ const trimmed = project.trim();
2746
+ return { project: trimmed.length > 0 ? trimmed : null };
2747
+ }
2748
+ function okOutcome(text, details, warnings = []) {
2749
+ return {
2750
+ text: formatMemoryToolOutcomeText(text, warnings),
2751
+ details: { ...details, ...buildMemoryToolWarningDetails(warnings) },
2752
+ failed: false
2753
+ };
2754
+ }
2755
+ function failedOutcome(text, details, warnings = []) {
2756
+ return {
2757
+ text: formatMemoryToolOutcomeText(text, warnings),
2758
+ details: { ...details, ...buildMemoryToolWarningDetails(warnings) },
2759
+ failed: true
2760
+ };
2761
+ }
2762
+ function parseDirectivePolarityParam(value) {
2763
+ if (value === void 0) {
2764
+ return void 0;
2765
+ }
2766
+ if (value === "abstain" || value === "proactive") {
2767
+ return value;
2768
+ }
2769
+ throw new Error(`Unsupported directive polarity "${value}".`);
2770
+ }
2771
+ function parseDirectiveTriggerParam(value) {
2772
+ if (value === void 0) {
2773
+ return void 0;
2774
+ }
2775
+ const trigger = parseDirectiveTrigger(value);
2776
+ if (!trigger) {
2777
+ throw new Error(`Unsupported directive trigger "${value}".`);
2778
+ }
2779
+ return trigger;
2780
+ }
2781
+
2782
+ // src/adapters/shared/recall-format.ts
2783
+ function formatUnifiedRecallResults(result) {
2784
+ const lines = [
2785
+ "Recall Route",
2786
+ `requested=${result.routing.requested} detected=${result.routing.detectedIntent} queried=${result.routing.queried.join(", ") || "none"}`,
2787
+ result.routing.reason,
2788
+ ""
2789
+ ];
2790
+ if (result.timeWindow) {
2791
+ lines.push("Resolved Time Window");
2792
+ lines.push(`${result.timeWindow.start} -> ${result.timeWindow.end} (${result.timeWindow.timezone}) from ${JSON.stringify(result.timeWindow.resolvedFrom)}`);
2793
+ lines.push("");
2794
+ }
2795
+ if (result.asOf) {
2796
+ lines.push("As Of");
2797
+ lines.push(result.asOf);
2798
+ lines.push("");
2799
+ }
2800
+ if (result.routing.queried.includes("procedures") || result.procedure || result.procedureCandidates.length > 0 || result.procedureNotices.length > 0) {
2801
+ appendProcedureMatches(lines, result);
2802
+ lines.push("");
2803
+ }
2804
+ const renderEntriesFirst = result.routing.detectedIntent === "historical_state";
2805
+ if (renderEntriesFirst) {
2806
+ appendEntryMatches(lines, result);
2807
+ lines.push("");
2808
+ appendClaimTransitions(lines, result);
2809
+ lines.push("");
2810
+ appendEpisodeMatches(lines, result);
2811
+ } else {
2812
+ appendEpisodeMatches(lines, result);
2813
+ lines.push("");
2814
+ appendEntryMatches(lines, result);
2815
+ lines.push("");
2816
+ appendClaimTransitions(lines, result);
2817
+ }
2818
+ if (recallResultHasTruncatedEntryPreviews(result)) {
2819
+ lines.push("");
2820
+ lines.push("Fetch Guidance");
2821
+ lines.push("One or more durable previews were truncated. Call agenr_fetch with id when exact stored wording is required.");
2822
+ }
2823
+ if (result.notices.length > 0) {
2824
+ lines.push("");
2825
+ lines.push("Notices");
2826
+ for (const notice of result.notices) {
2827
+ lines.push(`- ${notice}`);
2828
+ }
2829
+ }
2830
+ return lines.join("\n");
2831
+ }
2832
+ function appendProcedureMatches(lines, result) {
2833
+ lines.push("Procedure Matches");
2834
+ if (!result.procedure && result.procedureCandidates.length === 0) {
2835
+ lines.push("None.");
2836
+ } else {
2837
+ if (result.procedure) {
2838
+ appendCanonicalProcedure(lines, result.procedure, result.procedureCandidates);
2839
+ } else {
2840
+ lines.push("Canonical procedure: none.");
2841
+ }
2842
+ const additionalCandidates = result.procedureCandidates.filter((candidate) => candidate.procedure.id !== result.procedure?.id);
2843
+ if (additionalCandidates.length > 0) {
2844
+ lines.push("Other Candidates");
2845
+ for (const [index, candidate] of additionalCandidates.entries()) {
2846
+ lines.push(
2847
+ `${index + 1}. ${candidate.procedure.procedure_key} | ${candidate.procedure.title} | score ${candidate.score.toFixed(2)} | lexical=${candidate.scores.lexical.toFixed(2)} | vector=${candidate.scores.vector.toFixed(2)}`
2848
+ );
2849
+ }
2850
+ }
2851
+ }
2852
+ if (result.procedureNotices.length > 0) {
2853
+ lines.push("Procedure Notices");
2854
+ for (const notice of result.procedureNotices) {
2855
+ lines.push(`- ${notice}`);
2856
+ }
2857
+ }
2858
+ }
2859
+ function appendEntryMatches(lines, result) {
2860
+ lines.push("Durable Matches");
2861
+ if (result.projectedEntries.length === 0) {
2862
+ lines.push("None.");
2863
+ return;
2864
+ }
2865
+ for (const [familyIndex, family] of result.entryFamilies.entries()) {
2866
+ lines.push(
2867
+ family.claimKey ? `Family ${familyIndex + 1}. claim_key=${family.claimKey} | slot_policy=${family.slotPolicy} | primary=${family.primary.entryId} | subject=${family.subject}` : `Standalone ${familyIndex + 1}. ${family.primary.entryId} | subject=${family.subject}`
2868
+ );
2869
+ for (const [entryIndex, entry] of family.entries.entries()) {
2870
+ const preview = buildEntryRecallPreview(entry.recall.entry.content);
2871
+ lines.push(
2872
+ ` ${entryIndex + 1}. ${entry.entryId} | ${entry.recall.entry.type} | ${entry.recall.entry.subject} | score ${entry.recall.score.toFixed(2)} | state=${entry.memoryState} | claim_status=${formatClaimStatus(entry.claimStatus)}`
2873
+ );
2874
+ lines.push(` ${preview.contentPreview}`);
2875
+ lines.push(` content_chars=${preview.contentChars} preview_truncated=${preview.previewTruncated ? "true" : "false"}`);
2876
+ lines.push(` freshness=${entry.freshness.label}`);
2877
+ const provenance = formatProjectedEntryProvenance(entry);
2878
+ if (provenance) {
2879
+ lines.push(` provenance=${provenance}`);
2880
+ }
2881
+ lines.push(` why_surfaced=${entry.whySurfaced.summary}`);
2882
+ }
2883
+ }
2884
+ }
2885
+ function appendEpisodeMatches(lines, result) {
2886
+ lines.push("Episode Matches");
2887
+ if (result.episodes.length === 0) {
2888
+ lines.push("None.");
2889
+ return;
2890
+ }
2891
+ for (const [index, episode] of result.episodes.entries()) {
2892
+ lines.push(
2893
+ `${index + 1}. ${episode.episode.id} | ${episode.episode.source} | ${episode.episode.startedAt} -> ${episode.episode.endedAt ?? episode.episode.startedAt} | score ${episode.score.toFixed(2)}`
2894
+ );
2895
+ lines.push(` ${index < 3 ? episode.episode.summary.trim() : truncate(episode.episode.summary.trim(), ENTRY_PREVIEW_MAX_CHARS)}`);
2896
+ lines.push(` why_matched=${describeEpisodeMatch(episode)}`);
2897
+ }
2898
+ }
2899
+ function appendCanonicalProcedure(lines, procedure, candidates) {
2900
+ const leadCandidate = candidates.find((candidate) => candidate.procedure.id === procedure.id);
2901
+ lines.push(
2902
+ leadCandidate ? `Canonical Procedure. ${procedure.procedure_key} | ${procedure.title} | score ${leadCandidate.score.toFixed(2)}` : `Canonical Procedure. ${procedure.procedure_key} | ${procedure.title}`
2903
+ );
2904
+ lines.push(` goal=${procedure.goal}`);
2905
+ appendLabeledList(lines, "when_to_use", procedure.when_to_use);
2906
+ appendLabeledList(lines, "when_not_to_use", procedure.when_not_to_use);
2907
+ appendLabeledList(lines, "prerequisites", procedure.prerequisites);
2908
+ lines.push(" steps");
2909
+ for (const [index, step] of procedure.steps.entries()) {
2910
+ lines.push(` ${index + 1}. [${step.kind}] ${step.instruction}`);
2911
+ const stepDetails = formatProcedureStepDetails(step);
2912
+ if (stepDetails.length > 0) {
2913
+ for (const detail of stepDetails) {
2914
+ lines.push(` ${detail}`);
2915
+ }
2916
+ }
2917
+ }
2918
+ appendLabeledList(lines, "verification", procedure.verification);
2919
+ appendLabeledList(lines, "failure_modes", procedure.failure_modes);
2920
+ lines.push(" sources");
2921
+ for (const source of procedure.sources) {
2922
+ lines.push(` - ${formatProcedureSource(source)}`);
2923
+ }
2924
+ }
2925
+ function appendClaimTransitions(lines, result) {
2926
+ lines.push("Claim Transitions");
2927
+ if (result.claimTransitions.length === 0) {
2928
+ lines.push("None.");
2929
+ return;
2930
+ }
2931
+ for (const [index, transition] of result.claimTransitions.entries()) {
2932
+ lines.push(
2933
+ `${index + 1}. family=${transition.claimKey ?? transition.familyKey} | slot_policy=${transition.slotPolicy}${transition.currentEntryId ? ` | current=${transition.currentEntryId}` : ""}${transition.priorEntryId ? ` | prior=${transition.priorEntryId}` : ""}`
2934
+ );
2935
+ lines.push(` ${transition.summary}`);
2936
+ if (transition.episodeContext) {
2937
+ lines.push(
2938
+ ` episode=${transition.episodeContext.episodeId} | ${transition.episodeContext.startedAt} -> ${transition.episodeContext.endedAt ?? transition.episodeContext.startedAt}`
2939
+ );
2940
+ lines.push(` ${truncate(transition.episodeContext.summary.trim(), ENTRY_PREVIEW_MAX_CHARS)}`);
2941
+ }
2942
+ }
2943
+ }
2944
+ function appendLabeledList(lines, label, values) {
2945
+ lines.push(` ${label}`);
2946
+ if (values.length === 0) {
2947
+ lines.push(" - none");
2948
+ return;
2949
+ }
2950
+ for (const value of values) {
2951
+ lines.push(` - ${value}`);
2952
+ }
2953
+ }
2954
+ function formatProcedureStepDetails(step) {
2955
+ switch (step.kind) {
2956
+ case "run_command":
2957
+ return [`command=${step.command}`];
2958
+ case "read_reference":
2959
+ return [`ref=${formatProcedureSource(step.ref)}`];
2960
+ case "inspect_state":
2961
+ return [step.target ? `target=${step.target}` : void 0, step.query ? `query=${step.query}` : void 0].filter(
2962
+ (value) => value !== void 0
2963
+ );
2964
+ case "edit_file":
2965
+ return [`path=${step.path}`, `edit=${step.edit}`];
2966
+ case "ask_user":
2967
+ return [`prompt=${step.prompt}`];
2968
+ case "invoke_tool":
2969
+ return [step.tool ? `tool=${step.tool}` : void 0, step.arguments ? `arguments=${JSON.stringify(step.arguments)}` : void 0].filter(
2970
+ (value) => value !== void 0
2971
+ );
2972
+ case "verify":
2973
+ return step.checks.map((check) => `check=${check}`);
2974
+ default:
2975
+ return [];
2976
+ }
2977
+ }
2978
+ function formatProcedureSource(source) {
2979
+ const parts = [source.kind, source.label, source.path, source.locator].filter((value) => Boolean(value && value.length > 0));
2980
+ return parts.join(" | ");
2981
+ }
2982
+ function describeEpisodeMatch(result) {
2983
+ if (result.scores.semantic > 0 && result.scores.temporal > 0) {
2984
+ return "Semantic match within the resolved time window.";
2985
+ }
2986
+ if (result.scores.semantic > 0) {
2987
+ return "Semantic match to the episode summary.";
2988
+ }
2989
+ if (result.scores.temporal > 0) {
2990
+ return "Session overlaps the resolved time window.";
2991
+ }
2992
+ return "Matched episodic recall ranking.";
2993
+ }
2994
+ function formatClaimStatus(status) {
2995
+ return status === "no_key" ? "no-key" : status;
2996
+ }
2997
+ function formatProjectedEntryProvenance(entry) {
2998
+ const parts = [
2999
+ entry.provenance.supersededById ? `superseded_by=${entry.provenance.supersededById}` : void 0,
3000
+ entry.provenance.supersessionKind ? `kind=${entry.provenance.supersessionKind}` : void 0,
3001
+ entry.provenance.supersessionReason ? `reason=${truncate(entry.provenance.supersessionReason, 120)}` : void 0,
3002
+ entry.provenance.supportSourceKind ? `support=${entry.provenance.supportSourceKind}` : void 0,
3003
+ entry.provenance.supportMode ? `support_mode=${entry.provenance.supportMode}` : void 0,
3004
+ entry.provenance.supportObservedAt ? `observed=${entry.provenance.supportObservedAt}` : void 0,
3005
+ entry.provenance.supportLocator ? `locator=${truncate(entry.provenance.supportLocator, 120)}` : void 0
3006
+ ].filter((value) => value !== void 0);
3007
+ return parts.join(" | ");
3008
+ }
3009
+
3010
+ export {
3011
+ logSessionMemoryTriggerResult,
3012
+ routeSessionMemoryTriggerSafely,
3013
+ createSessionMemoryTriggerRouter,
3014
+ resolveSessionIdentityKey,
3015
+ createSessionStartTracker,
3016
+ createSessionLifecycleIntakeTracker,
3017
+ createCompactionPromptTracker,
3018
+ normalizeOptionalBoolean,
3019
+ normalizeOptionalPositiveInteger,
3020
+ normalizePluginInjectionMemoryPolicyConfig,
3021
+ mergeInjectionContent,
3022
+ formatAgenrSessionStartRecall,
3023
+ resolveSessionStartPolicy,
3024
+ resolveBeforeTurnPolicy,
3025
+ resolveWorkingContextGate,
3026
+ extractRecentTurnsFromMessages,
3027
+ normalizePromptText,
3028
+ scheduleGuardedEpisodeWrite,
3029
+ isPluginEpisodeWriteEnabled,
3030
+ resolveAgenrFeatureFlags,
3031
+ resolveCompactionPromptContext,
3032
+ HOST_SHUTDOWN_EPISODE_ACTIVITY_THRESHOLD,
3033
+ embedEpisodeSummaryWithinBudget,
3034
+ EPISODE_SUMMARY_TIMEOUT_MS,
3035
+ writeBoundedSingleTranscriptEpisode,
3036
+ createDeadlineAwareEpisodeSummaryLlm,
3037
+ buildSessionFileSourceRef,
3038
+ buildCompactionSourceRef,
3039
+ buildSessionEndSourceRef,
3040
+ buildLightDreamTriggerDeps,
3041
+ maybeRunLightDream,
3042
+ runGuardedPostSessionEpisodeCapture,
3043
+ buildClaimExtractionRuntime,
3044
+ createClaimExtractionFromAgenrConfig,
3045
+ createEmbedQuery,
3046
+ composeHostPluginServices,
3047
+ createHostMemoryServices,
3048
+ buildRecallToolServices,
3049
+ STORE_TOOL_PARAMETERS,
3050
+ RECALL_TOOL_PARAMETERS,
3051
+ UPDATE_TOOL_PARAMETERS,
3052
+ FETCH_TOOL_PARAMETERS,
3053
+ parseStoreToolParams,
3054
+ parseRecallToolParams,
3055
+ parseUpdateToolParams,
3056
+ parseFetchToolParams,
3057
+ runStoreMemoryTool,
3058
+ runRecallMemoryTool,
3059
+ runFetchMemoryTool,
3060
+ runUpdateMemoryTool,
3061
+ formatUnifiedRecallResults
3062
+ };