@agenr/openclaw-plugin 3.3.0 → 2026.6.2

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.
@@ -0,0 +1,3012 @@
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-LDJN7CVU.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/app/dreaming/background-triggers.ts
772
+ var MINUTE_MS = 60 * 1e3;
773
+ async function maybeRunLightDream(input, deps) {
774
+ const now = input.now ?? (() => /* @__PURE__ */ new Date());
775
+ const config = resolveLightDreamTriggerConfig(deps.config);
776
+ if (!config.lightEnabled) {
777
+ return { status: "skipped", reason: "light_disabled" };
778
+ }
779
+ if (input.trigger === "post_session" && !config.postSessionLightDream) {
780
+ return { status: "skipped", reason: "post_session_disabled" };
781
+ }
782
+ if (input.trigger === "importance" && isEpisodeWriteInProgress(deps.dbPath)) {
783
+ return { status: "skipped", reason: "episode_write_in_progress" };
784
+ }
785
+ const lock = await tryAcquireDreamingRunLock(deps.port, deps.dbPath);
786
+ if (!lock) {
787
+ return { status: "skipped", reason: "run_in_progress" };
788
+ }
789
+ return withHeldDreamingRunLock(lock, async (lease) => {
790
+ const [{ runDreamScan }, { runDreamWithHeldLock }] = await Promise.all([import("./scan-6JKPOQHD.js"), import("./service-EKFACEN6.js")]);
791
+ const lastRun = await deps.port.getLastRun();
792
+ if (isWithinMinInterval(lastRun, now(), config.minIntervalMinutes)) {
793
+ return { status: "skipped", reason: "interval_guard" };
794
+ }
795
+ const scan = await runDreamScan({ now }, { port: deps.port });
796
+ if (!hasEvidence(scan)) {
797
+ return { status: "skipped", reason: "no_evidence", unsynthesizedImportanceSum: scan.unsynthesizedImportanceSum };
798
+ }
799
+ if (input.trigger === "importance" && scan.unsynthesizedImportanceSum < config.importanceThreshold) {
800
+ return {
801
+ status: "skipped",
802
+ reason: "importance_below_threshold",
803
+ unsynthesizedImportanceSum: scan.unsynthesizedImportanceSum
804
+ };
805
+ }
806
+ const result = await runDreamWithHeldLock(
807
+ {
808
+ tier: "light",
809
+ apply: true,
810
+ verbose: false,
811
+ json: true,
812
+ skipBackup: true
813
+ },
814
+ {
815
+ port: deps.port,
816
+ dbPath: deps.dbPath,
817
+ config: deps.config,
818
+ now,
819
+ ...deps.embedding ? { embedding: deps.embedding } : {},
820
+ ...deps.createExtractLlm ? { createExtractLlm: deps.createExtractLlm } : {},
821
+ ...deps.createClaimExtractionLlm ? { createClaimExtractionLlm: deps.createClaimExtractionLlm } : {}
822
+ },
823
+ lease
824
+ );
825
+ return {
826
+ status: "ran",
827
+ result,
828
+ unsynthesizedImportanceSum: scan.unsynthesizedImportanceSum
829
+ };
830
+ });
831
+ }
832
+ function resolveLightDreamTriggerConfig(config) {
833
+ return {
834
+ lightEnabled: config?.dreaming?.tiers?.light?.enabled ?? true,
835
+ postSessionLightDream: config?.dreaming?.triggers?.postSessionLightDream ?? true,
836
+ importanceThreshold: config?.dreaming?.triggers?.importanceThreshold ?? DEFAULT_DREAMING_IMPORTANCE_THRESHOLD,
837
+ minIntervalMinutes: config?.dreaming?.triggers?.minIntervalMinutes ?? DEFAULT_DREAMING_MIN_INTERVAL_MINUTES
838
+ };
839
+ }
840
+ function isWithinMinInterval(lastRun, now, minIntervalMinutes) {
841
+ if (!lastRun || minIntervalMinutes <= 0) {
842
+ return false;
843
+ }
844
+ const reference = lastRun.completedAt ?? lastRun.startedAt;
845
+ const timestamp = Date.parse(reference);
846
+ if (!Number.isFinite(timestamp)) {
847
+ return false;
848
+ }
849
+ return now.getTime() - timestamp < minIntervalMinutes * MINUTE_MS;
850
+ }
851
+ function hasEvidence(scan) {
852
+ return scan.episodesSinceLastRun > 0 || scan.ingestFilesSinceLastRun > 0 || scan.durablesCreatedSinceLastRun > 0;
853
+ }
854
+
855
+ // src/adapters/plugin-runtime/claim-extraction.ts
856
+ async function buildClaimExtractionRuntime(config, resolveLlm) {
857
+ const claimExtractionConfig = resolveClaimExtractionConfig(config);
858
+ if (!claimExtractionConfig.enabled) {
859
+ return void 0;
860
+ }
861
+ try {
862
+ return {
863
+ llm: await resolveLlm(),
864
+ config: claimExtractionConfig
865
+ };
866
+ } catch {
867
+ return void 0;
868
+ }
869
+ }
870
+ function createClaimExtractionFromAgenrConfig(config) {
871
+ const claimExtractionConfig = resolveClaimExtractionConfig(config);
872
+ if (!claimExtractionConfig.enabled) {
873
+ return void 0;
874
+ }
875
+ try {
876
+ const { provider, modelId } = resolveModel(config, "claim");
877
+ const apiKey = resolveLlmApiKey(config, provider);
878
+ return {
879
+ llm: createLlmClient(provider, modelId, { apiKey }),
880
+ config: claimExtractionConfig
881
+ };
882
+ } catch {
883
+ return void 0;
884
+ }
885
+ }
886
+
887
+ // src/adapters/db/session-memory-repository.ts
888
+ import { randomUUID } from "crypto";
889
+
890
+ // src/adapters/db/json.ts
891
+ function serializeOptionalJson(value) {
892
+ return value === void 0 ? null : JSON.stringify(value);
893
+ }
894
+ function parseOptionalJson(value, label) {
895
+ if (!value) {
896
+ return void 0;
897
+ }
898
+ try {
899
+ return JSON.parse(value);
900
+ } catch (error) {
901
+ throw new Error(`Failed to parse ${label}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
902
+ }
903
+ }
904
+
905
+ // src/app/session-memory/types.ts
906
+ var SESSION_ARTIFACT_KINDS = ["compaction_checkpoint", "branch_abandonment", "session_episode"];
907
+ var SESSION_LINEAGE_REASONS = ["fork", "clone", "resume", "subagent_spawn"];
908
+ var SESSION_START_TRANSITION_REASONS = ["new", "unknown", ...SESSION_LINEAGE_REASONS];
909
+
910
+ // src/adapters/db/session-memory-parsing.ts
911
+ function parseSessionArtifactKind(value) {
912
+ if (SESSION_ARTIFACT_KINDS.includes(value)) {
913
+ return value;
914
+ }
915
+ throw new Error(`Unsupported session artifact kind "${value}".`);
916
+ }
917
+ function parseSessionLineageReason(value) {
918
+ if (SESSION_LINEAGE_REASONS.includes(value)) {
919
+ return value;
920
+ }
921
+ throw new Error(`Unsupported session lineage reason "${value}".`);
922
+ }
923
+
924
+ // src/adapters/db/session-memory-repository.ts
925
+ var SESSION_LINEAGE_EDGE_SELECT_COLUMNS = `
926
+ id,
927
+ child_session_key,
928
+ parent_session_key,
929
+ parent_source_ref,
930
+ reason,
931
+ fork_durable_id,
932
+ fork_position,
933
+ observed_at
934
+ `;
935
+ var SESSION_ARTIFACT_SELECT_COLUMNS = `
936
+ id,
937
+ kind,
938
+ session_key,
939
+ source,
940
+ source_id,
941
+ source_ref,
942
+ content_hash,
943
+ summary,
944
+ metadata_json,
945
+ created_at,
946
+ expires_at
947
+ `;
948
+ function createSessionMemoryRepository(database) {
949
+ return {
950
+ upsertLineageEdge: (input) => upsertLineageEdge(database, input),
951
+ upsertSessionArtifact: (input) => upsertSessionArtifact(database, input),
952
+ recordTriggerIntake: (input) => recordTriggerIntake(database, input),
953
+ listSessionArtifacts: (filter) => listSessionArtifacts(database, filter),
954
+ listSessionArtifactsBySourceRef: (filter) => listSessionArtifactsBySourceRef(database, filter),
955
+ getLatestLineageEdgeForChild: (childSessionKey) => getLatestLineageEdgeForChild(database, childSessionKey)
956
+ };
957
+ }
958
+ async function upsertLineageEdge(database, input) {
959
+ return database.withTransaction(async (transaction) => upsertLineageEdgeWithExecutor(transaction, input));
960
+ }
961
+ async function recordTriggerIntake(database, input) {
962
+ return database.withTransaction(async (transaction) => {
963
+ const executor = transaction;
964
+ const result = {};
965
+ if (input.lineage) {
966
+ result.lineageEdge = await upsertLineageEdgeWithExecutor(executor, input.lineage);
967
+ }
968
+ if (input.artifact) {
969
+ result.artifact = await upsertSessionArtifact(executor, input.artifact);
970
+ }
971
+ return result;
972
+ });
973
+ }
974
+ async function upsertLineageEdgeWithExecutor(executor, input) {
975
+ const existing = await findMatchingLineageEdge(executor, input);
976
+ if (existing) {
977
+ return existing;
978
+ }
979
+ const id = randomUUID();
980
+ await executor.execute({
981
+ sql: `
982
+ INSERT INTO session_lineage_edges (
983
+ id,
984
+ child_session_key,
985
+ parent_session_key,
986
+ parent_source_ref,
987
+ reason,
988
+ fork_durable_id,
989
+ fork_position,
990
+ observed_at
991
+ )
992
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
993
+ `,
994
+ args: [
995
+ id,
996
+ input.childSessionKey,
997
+ input.parentSessionKey ?? null,
998
+ input.parentSourceRef ?? null,
999
+ input.reason,
1000
+ input.forkEntryId ?? null,
1001
+ input.forkPosition ?? null,
1002
+ input.observedAt
1003
+ ]
1004
+ });
1005
+ const edge = await getLineageEdge(executor, id);
1006
+ if (!edge) {
1007
+ throw new Error(`Session lineage edge ${id} was not found after write.`);
1008
+ }
1009
+ return edge;
1010
+ }
1011
+ async function upsertSessionArtifact(executor, input) {
1012
+ const createdAt = (/* @__PURE__ */ new Date()).toISOString();
1013
+ await executor.execute({
1014
+ sql: `
1015
+ INSERT INTO session_artifacts (
1016
+ id,
1017
+ kind,
1018
+ session_key,
1019
+ source,
1020
+ source_id,
1021
+ source_ref,
1022
+ content_hash,
1023
+ summary,
1024
+ metadata_json,
1025
+ created_at,
1026
+ expires_at
1027
+ )
1028
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1029
+ ON CONFLICT(kind, source, source_id) DO UPDATE SET
1030
+ session_key = excluded.session_key,
1031
+ source_ref = excluded.source_ref,
1032
+ content_hash = excluded.content_hash,
1033
+ summary = excluded.summary,
1034
+ metadata_json = excluded.metadata_json,
1035
+ expires_at = excluded.expires_at
1036
+ `,
1037
+ args: [
1038
+ randomUUID(),
1039
+ input.kind,
1040
+ input.sessionKey,
1041
+ input.source,
1042
+ input.sourceId,
1043
+ input.sourceRef ?? null,
1044
+ input.contentHash,
1045
+ input.summary,
1046
+ serializeOptionalJson(input.metadata),
1047
+ createdAt,
1048
+ input.expiresAt ?? null
1049
+ ]
1050
+ });
1051
+ const artifact = await getSessionArtifactBySource(executor, input.kind, input.source, input.sourceId);
1052
+ if (!artifact) {
1053
+ throw new Error(`Session artifact ${input.kind}/${input.source}/${input.sourceId} was not found after write.`);
1054
+ }
1055
+ return artifact;
1056
+ }
1057
+ async function listSessionArtifacts(executor, filter) {
1058
+ const sessionKey = filter.sessionKey.trim();
1059
+ if (!sessionKey) {
1060
+ return [];
1061
+ }
1062
+ return querySessionArtifacts(executor, {
1063
+ conditions: ["session_key = ?"],
1064
+ args: [sessionKey],
1065
+ kinds: filter.kinds,
1066
+ limit: filter.limit
1067
+ });
1068
+ }
1069
+ async function listSessionArtifactsBySourceRef(executor, filter) {
1070
+ const sourceRef = filter.sourceRef.trim();
1071
+ if (!sourceRef) {
1072
+ return [];
1073
+ }
1074
+ return querySessionArtifacts(executor, {
1075
+ conditions: ["source_ref = ?"],
1076
+ args: [sourceRef],
1077
+ kinds: filter.kinds,
1078
+ limit: filter.limit
1079
+ });
1080
+ }
1081
+ async function getLatestLineageEdgeForChild(executor, childSessionKey) {
1082
+ const normalizedChild = childSessionKey.trim();
1083
+ if (!normalizedChild) {
1084
+ return null;
1085
+ }
1086
+ const result = await executor.execute({
1087
+ sql: `
1088
+ SELECT ${SESSION_LINEAGE_EDGE_SELECT_COLUMNS}
1089
+ FROM session_lineage_edges
1090
+ WHERE child_session_key = ?
1091
+ ORDER BY observed_at DESC, id ASC
1092
+ LIMIT 1
1093
+ `,
1094
+ args: [normalizedChild]
1095
+ });
1096
+ const row = result.rows[0];
1097
+ return row ? mapSessionLineageEdgeRow(row) : null;
1098
+ }
1099
+ async function findMatchingLineageEdge(executor, input) {
1100
+ const parentSessionKeyClause = input.parentSessionKey ? "parent_session_key = ?" : "parent_session_key IS NULL";
1101
+ const parentSourceRefClause = input.parentSourceRef ? "parent_source_ref = ?" : "parent_source_ref IS NULL";
1102
+ const args = [
1103
+ input.childSessionKey,
1104
+ input.reason,
1105
+ ...input.parentSessionKey ? [input.parentSessionKey] : [],
1106
+ ...input.parentSourceRef ? [input.parentSourceRef] : []
1107
+ ];
1108
+ const result = await executor.execute({
1109
+ sql: `
1110
+ SELECT ${SESSION_LINEAGE_EDGE_SELECT_COLUMNS}
1111
+ FROM session_lineage_edges
1112
+ WHERE child_session_key = ?
1113
+ AND reason = ?
1114
+ AND ${parentSessionKeyClause}
1115
+ AND ${parentSourceRefClause}
1116
+ ORDER BY observed_at DESC, id ASC
1117
+ LIMIT 1
1118
+ `,
1119
+ args
1120
+ });
1121
+ const row = result.rows[0];
1122
+ return row ? mapSessionLineageEdgeRow(row) : null;
1123
+ }
1124
+ async function getLineageEdge(executor, id) {
1125
+ const result = await executor.execute({
1126
+ sql: `
1127
+ SELECT ${SESSION_LINEAGE_EDGE_SELECT_COLUMNS}
1128
+ FROM session_lineage_edges
1129
+ WHERE id = ?
1130
+ LIMIT 1
1131
+ `,
1132
+ args: [id]
1133
+ });
1134
+ const row = result.rows[0];
1135
+ return row ? mapSessionLineageEdgeRow(row) : null;
1136
+ }
1137
+ async function getSessionArtifactBySource(executor, kind, source, sourceId) {
1138
+ const result = await executor.execute({
1139
+ sql: `
1140
+ SELECT ${SESSION_ARTIFACT_SELECT_COLUMNS}
1141
+ FROM session_artifacts
1142
+ WHERE kind = ?
1143
+ AND source = ?
1144
+ AND source_id = ?
1145
+ LIMIT 1
1146
+ `,
1147
+ args: [kind, source, sourceId]
1148
+ });
1149
+ const row = result.rows[0];
1150
+ return row ? mapSessionArtifactRow(row) : null;
1151
+ }
1152
+ function appendKindFilter(conditions, args, kinds) {
1153
+ if (kinds && kinds.length > 0) {
1154
+ conditions.push(`kind IN (${kinds.map(() => "?").join(", ")})`);
1155
+ args.push(...kinds);
1156
+ }
1157
+ }
1158
+ async function querySessionArtifacts(executor, filter) {
1159
+ const conditions = [...filter.conditions];
1160
+ const args = [...filter.args];
1161
+ appendKindFilter(conditions, args, filter.kinds);
1162
+ const limit = normalizeBoundedLimit(filter.limit, 20, 100);
1163
+ const result = await executor.execute({
1164
+ sql: `
1165
+ SELECT ${SESSION_ARTIFACT_SELECT_COLUMNS}
1166
+ FROM session_artifacts
1167
+ WHERE ${conditions.join(" AND ")}
1168
+ ORDER BY created_at DESC, id ASC
1169
+ LIMIT ?
1170
+ `,
1171
+ args: [...args, limit]
1172
+ });
1173
+ return result.rows.map((row) => mapSessionArtifactRow(row));
1174
+ }
1175
+ function mapSessionLineageEdgeRow(row) {
1176
+ return {
1177
+ id: readRequiredString(row, "id"),
1178
+ childSessionKey: readRequiredString(row, "child_session_key"),
1179
+ parentSessionKey: readOptionalString(row, "parent_session_key"),
1180
+ parentSourceRef: readOptionalString(row, "parent_source_ref"),
1181
+ reason: parseSessionLineageReason(readRequiredString(row, "reason")),
1182
+ forkEntryId: readOptionalString(row, "fork_durable_id"),
1183
+ forkPosition: readOptionalString(row, "fork_position"),
1184
+ observedAt: readRequiredString(row, "observed_at")
1185
+ };
1186
+ }
1187
+ function mapSessionArtifactRow(row) {
1188
+ return {
1189
+ id: readRequiredString(row, "id"),
1190
+ kind: parseSessionArtifactKind(readRequiredString(row, "kind")),
1191
+ sessionKey: readRequiredString(row, "session_key"),
1192
+ source: readRequiredString(row, "source"),
1193
+ sourceId: readRequiredString(row, "source_id"),
1194
+ sourceRef: readOptionalString(row, "source_ref"),
1195
+ contentHash: readRequiredString(row, "content_hash"),
1196
+ summary: readRequiredString(row, "summary"),
1197
+ metadata: parseOptionalJson(readOptionalString(row, "metadata_json"), "metadata_json"),
1198
+ createdAt: readRequiredString(row, "created_at"),
1199
+ expiresAt: readOptionalString(row, "expires_at")
1200
+ };
1201
+ }
1202
+
1203
+ // src/adapters/db/working-memory-repository.ts
1204
+ import { randomUUID as randomUUID2 } from "crypto";
1205
+
1206
+ // src/adapters/db/working-memory-columns.ts
1207
+ var WORKING_SET_COLUMN_NAMES = [
1208
+ "id",
1209
+ "scope_key",
1210
+ "scope_kind",
1211
+ "title",
1212
+ "objective",
1213
+ "status",
1214
+ "summary",
1215
+ "snapshot_json",
1216
+ "revision",
1217
+ "project",
1218
+ "session_id",
1219
+ "conversation_key",
1220
+ "cwd",
1221
+ "git_root",
1222
+ "git_branch",
1223
+ "task_id",
1224
+ "source",
1225
+ "created_at",
1226
+ "updated_at",
1227
+ "last_active_at",
1228
+ "closed_at",
1229
+ "close_reason",
1230
+ "episode_id"
1231
+ ];
1232
+ var WORKING_SET_SELECT_COLUMNS = WORKING_SET_COLUMN_NAMES.join(",\n ");
1233
+ var WORKING_SET_INSERT_COLUMNS = WORKING_SET_COLUMN_NAMES.join(",\n ");
1234
+ var WORKING_SET_INSERT_PLACEHOLDERS = WORKING_SET_COLUMN_NAMES.map(() => "?").join(", ");
1235
+ var WORKING_SET_UPDATE_COLUMNS = [
1236
+ "title",
1237
+ "objective",
1238
+ "status",
1239
+ "summary",
1240
+ "snapshot_json",
1241
+ "revision",
1242
+ "updated_at",
1243
+ "last_active_at",
1244
+ "closed_at",
1245
+ "close_reason",
1246
+ "episode_id"
1247
+ ];
1248
+ var WORKING_SET_SEMANTIC_ONLY_UPDATE_COLUMNS = /* @__PURE__ */ new Set(["revision", "closed_at", "close_reason", "episode_id"]);
1249
+ var WORKING_SET_USAGE_PATCH_COLUMNS = WORKING_SET_UPDATE_COLUMNS.filter((column) => !WORKING_SET_SEMANTIC_ONLY_UPDATE_COLUMNS.has(column));
1250
+ var WORKING_EVENT_SELECT_COLUMNS = `
1251
+ id,
1252
+ working_set_id,
1253
+ sequence,
1254
+ event_type,
1255
+ payload_json,
1256
+ actor,
1257
+ source,
1258
+ host_event_id,
1259
+ turn_id,
1260
+ created_at
1261
+ `;
1262
+ function buildWorkingSetUpdateSetClause() {
1263
+ return WORKING_SET_UPDATE_COLUMNS.map((column) => `${column} = ?`).join(",\n ");
1264
+ }
1265
+ function buildWorkingSetUsagePatchSetClause() {
1266
+ return WORKING_SET_USAGE_PATCH_COLUMNS.map((column) => `${column} = ?`).join(",\n ");
1267
+ }
1268
+ function mapWorkingSetRow(row) {
1269
+ const snapshot = parseJson(readRequiredString(row, "snapshot_json"), "snapshot_json");
1270
+ return {
1271
+ id: readRequiredString(row, "id"),
1272
+ scopeKey: readRequiredString(row, "scope_key"),
1273
+ scopeKind: readRequiredString(row, "scope_kind"),
1274
+ title: readOptionalString(row, "title"),
1275
+ objective: readOptionalString(row, "objective"),
1276
+ status: readRequiredString(row, "status"),
1277
+ summary: readOptionalString(row, "summary"),
1278
+ snapshot,
1279
+ revision: readNumber(row, "revision", 0),
1280
+ project: readOptionalString(row, "project"),
1281
+ sessionId: readOptionalString(row, "session_id"),
1282
+ conversationKey: readOptionalString(row, "conversation_key"),
1283
+ cwd: readOptionalString(row, "cwd"),
1284
+ gitRoot: readOptionalString(row, "git_root"),
1285
+ gitBranch: readOptionalString(row, "git_branch"),
1286
+ taskId: readOptionalString(row, "task_id"),
1287
+ source: readOptionalString(row, "source"),
1288
+ createdAt: readRequiredString(row, "created_at"),
1289
+ updatedAt: readRequiredString(row, "updated_at"),
1290
+ lastActiveAt: readRequiredString(row, "last_active_at"),
1291
+ closedAt: readOptionalString(row, "closed_at"),
1292
+ closeReason: readOptionalString(row, "close_reason"),
1293
+ episodeId: readOptionalString(row, "episode_id")
1294
+ };
1295
+ }
1296
+ function mapWorkingEventRow(row) {
1297
+ return {
1298
+ id: readRequiredString(row, "id"),
1299
+ workingSetId: readRequiredString(row, "working_set_id"),
1300
+ sequence: readNumber(row, "sequence", 0),
1301
+ eventType: readRequiredString(row, "event_type"),
1302
+ payload: parseJson(readRequiredString(row, "payload_json"), "payload_json"),
1303
+ actor: readOptionalString(row, "actor"),
1304
+ source: readOptionalString(row, "source"),
1305
+ hostEventId: readOptionalString(row, "host_event_id"),
1306
+ turnId: readOptionalString(row, "turn_id"),
1307
+ createdAt: readRequiredString(row, "created_at")
1308
+ };
1309
+ }
1310
+ function parseJson(value, column) {
1311
+ try {
1312
+ return JSON.parse(value);
1313
+ } catch (error) {
1314
+ const message = error instanceof Error ? error.message : String(error);
1315
+ throw new Error(`Invalid JSON in working-memory column ${column}: ${message}`, { cause: error });
1316
+ }
1317
+ }
1318
+
1319
+ // src/adapters/db/working-memory-repository.ts
1320
+ function createWorkingMemoryRepository(database) {
1321
+ return {
1322
+ getWorkingSet: (id) => getWorkingSet(database, id),
1323
+ findCurrentWorkingSets: (scope) => findWorkingSetsByScope(database, scope, CURRENT_WORKING_SET_STATUSES),
1324
+ listWorkingSets: (filter) => listWorkingSets(database, filter),
1325
+ listWorkingEvents: (workingSetId, limit) => listWorkingEvents(database, workingSetId, limit),
1326
+ createWorkingSet: (input) => createWorkingSet(database, input),
1327
+ updateWorkingSet: (input) => updateWorkingSet(database, input),
1328
+ patchWorkingSetUsage: (input) => patchWorkingSetUsage(database, input)
1329
+ };
1330
+ }
1331
+ async function getWorkingSet(executor, id) {
1332
+ const normalizedId = id.trim();
1333
+ if (!normalizedId) {
1334
+ return null;
1335
+ }
1336
+ const result = await executor.execute({
1337
+ sql: `
1338
+ SELECT ${WORKING_SET_SELECT_COLUMNS}
1339
+ FROM working_sets
1340
+ WHERE id = ?
1341
+ LIMIT 1
1342
+ `,
1343
+ args: [normalizedId]
1344
+ });
1345
+ const row = result.rows[0];
1346
+ return row ? mapWorkingSetRow(row) : null;
1347
+ }
1348
+ async function findWorkingSetsByScope(executor, scope, statuses) {
1349
+ const result = await executor.execute({
1350
+ sql: `
1351
+ SELECT ${WORKING_SET_SELECT_COLUMNS}
1352
+ FROM working_sets
1353
+ WHERE scope_key = ?
1354
+ AND status IN (${statuses.map(() => "?").join(", ")})
1355
+ ORDER BY last_active_at DESC, id ASC
1356
+ `,
1357
+ args: [scope.scopeKey, ...statuses]
1358
+ });
1359
+ return result.rows.map((row) => mapWorkingSetRow(row));
1360
+ }
1361
+ async function listWorkingSets(executor, filter) {
1362
+ const conditions = [];
1363
+ const args = [];
1364
+ if (filter.scope) {
1365
+ conditions.push("scope_key = ?");
1366
+ args.push(filter.scope.scopeKey);
1367
+ }
1368
+ if (filter.statuses && filter.statuses.length > 0) {
1369
+ conditions.push(`status IN (${filter.statuses.map(() => "?").join(", ")})`);
1370
+ args.push(...filter.statuses);
1371
+ }
1372
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1373
+ const limit = normalizeBoundedLimit(filter.limit, 20, 100);
1374
+ const result = await executor.execute({
1375
+ sql: `
1376
+ SELECT ${WORKING_SET_SELECT_COLUMNS}
1377
+ FROM working_sets
1378
+ ${where}
1379
+ ORDER BY last_active_at DESC, id ASC
1380
+ LIMIT ?
1381
+ `,
1382
+ args: [...args, limit]
1383
+ });
1384
+ return result.rows.map((row) => mapWorkingSetRow(row));
1385
+ }
1386
+ async function listWorkingEvents(executor, workingSetId, limit) {
1387
+ const normalizedId = workingSetId.trim();
1388
+ if (!normalizedId) {
1389
+ return [];
1390
+ }
1391
+ const normalizedLimit = normalizeBoundedLimit(limit, 50, 1e3);
1392
+ const result = await executor.execute({
1393
+ sql: `
1394
+ SELECT ${WORKING_EVENT_SELECT_COLUMNS}
1395
+ FROM working_events
1396
+ WHERE working_set_id = ?
1397
+ ORDER BY sequence DESC
1398
+ LIMIT ?
1399
+ `,
1400
+ args: [normalizedId, normalizedLimit]
1401
+ });
1402
+ return result.rows.map((row) => mapWorkingEventRow(row)).reverse();
1403
+ }
1404
+ async function createWorkingSet(database, input) {
1405
+ return database.withTransaction(async (transaction) => {
1406
+ const executor = transaction;
1407
+ const existing = await findWorkingSetsByScope(executor, input.scope, CURRENT_WORKING_SET_STATUSES);
1408
+ if (existing.length > 0) {
1409
+ return { kind: "active_set_exists", scopeKey: input.scope.scopeKey };
1410
+ }
1411
+ const id = randomUUID2();
1412
+ const event = buildEvent({
1413
+ workingSetId: id,
1414
+ sequence: 1,
1415
+ eventType: "created",
1416
+ payload: {
1417
+ objective: input.objective,
1418
+ scope: input.scope
1419
+ },
1420
+ actor: input.actor,
1421
+ source: input.source,
1422
+ now: input.now
1423
+ });
1424
+ await executor.execute({
1425
+ sql: `
1426
+ INSERT INTO working_sets (
1427
+ ${WORKING_SET_INSERT_COLUMNS}
1428
+ )
1429
+ VALUES (
1430
+ ${WORKING_SET_INSERT_PLACEHOLDERS}
1431
+ )
1432
+ `,
1433
+ args: [
1434
+ id,
1435
+ input.scope.scopeKey,
1436
+ input.scope.scopeKind,
1437
+ toNullableString(input.title),
1438
+ toNullableString(input.objective),
1439
+ input.status,
1440
+ toNullableString(input.snapshot.summary),
1441
+ serializeJson(input.snapshot),
1442
+ 1,
1443
+ toNullableString(input.scope.project),
1444
+ toNullableString(input.sessionId ?? input.scope.sessionId),
1445
+ toNullableString(input.scope.conversationKey),
1446
+ toNullableString(input.scope.cwd),
1447
+ toNullableString(input.scope.gitRoot),
1448
+ toNullableString(input.scope.gitBranch),
1449
+ toNullableString(input.scope.taskId),
1450
+ toNullableString(input.sourceLabel),
1451
+ input.now,
1452
+ input.now,
1453
+ input.now,
1454
+ null,
1455
+ null,
1456
+ null
1457
+ ]
1458
+ });
1459
+ await insertWorkingEvent(executor, event);
1460
+ const workingSet = await requireWorkingSet(executor, id);
1461
+ return { workingSet, event };
1462
+ });
1463
+ }
1464
+ async function updateWorkingSet(database, input) {
1465
+ return database.withTransaction(async (transaction) => {
1466
+ const executor = transaction;
1467
+ const current = await getWorkingSet(executor, input.workingSetId);
1468
+ if (!current) {
1469
+ return { kind: "not_found" };
1470
+ }
1471
+ if (!canApplyWorkingSetUpdate(current.status, input.status)) {
1472
+ return { kind: "terminal_status", status: current.status };
1473
+ }
1474
+ if (current.revision !== input.expectedRevision) {
1475
+ return { kind: "revision_conflict", actualRevision: current.revision };
1476
+ }
1477
+ const nextRevision = current.revision + 1;
1478
+ const event = buildEvent({
1479
+ workingSetId: current.id,
1480
+ sequence: nextRevision,
1481
+ eventType: input.eventType,
1482
+ payload: input.payload,
1483
+ actor: input.actor,
1484
+ source: input.source,
1485
+ now: input.now
1486
+ });
1487
+ await executor.execute({
1488
+ sql: `
1489
+ UPDATE working_sets
1490
+ SET ${buildWorkingSetUpdateSetClause()}
1491
+ WHERE id = ?
1492
+ AND revision = ?
1493
+ `,
1494
+ args: [
1495
+ ...buildWorkingSetSnapshotUpdateArgs({
1496
+ title: input.title,
1497
+ objective: input.objective,
1498
+ status: input.status,
1499
+ snapshot: input.snapshot,
1500
+ current
1501
+ }),
1502
+ nextRevision,
1503
+ input.now,
1504
+ input.now,
1505
+ toNullableString(input.closedAt ?? current.closedAt),
1506
+ toNullableString(input.closeReason ?? current.closeReason),
1507
+ toNullableString(input.episodeId ?? current.episodeId),
1508
+ current.id,
1509
+ input.expectedRevision
1510
+ ]
1511
+ });
1512
+ const workingSet = await requireWorkingSet(executor, current.id);
1513
+ if (workingSet.revision !== nextRevision) {
1514
+ return { kind: "revision_conflict", actualRevision: workingSet.revision };
1515
+ }
1516
+ await insertWorkingEvent(executor, event);
1517
+ return { workingSet, event };
1518
+ });
1519
+ }
1520
+ async function patchWorkingSetUsage(database, input) {
1521
+ return database.withTransaction(async (transaction) => {
1522
+ const executor = transaction;
1523
+ const current = await getWorkingSet(executor, input.workingSetId);
1524
+ if (!current) {
1525
+ return { kind: "not_found" };
1526
+ }
1527
+ if (!canApplyWorkingSetUpdate(current.status, input.status)) {
1528
+ return { kind: "terminal_status", status: current.status };
1529
+ }
1530
+ if (current.revision !== input.expectedRevision) {
1531
+ return { kind: "revision_conflict", actualRevision: current.revision };
1532
+ }
1533
+ await executor.execute({
1534
+ sql: `
1535
+ UPDATE working_sets
1536
+ SET ${buildWorkingSetUsagePatchSetClause()}
1537
+ WHERE id = ?
1538
+ AND revision = ?
1539
+ `,
1540
+ args: [
1541
+ ...buildWorkingSetSnapshotUpdateArgs({
1542
+ title: input.title,
1543
+ objective: input.objective,
1544
+ status: input.status,
1545
+ snapshot: input.snapshot,
1546
+ current
1547
+ }),
1548
+ input.now,
1549
+ input.now,
1550
+ current.id,
1551
+ input.expectedRevision
1552
+ ]
1553
+ });
1554
+ const workingSet = await requireWorkingSet(executor, current.id);
1555
+ if (workingSet.revision !== input.expectedRevision) {
1556
+ return { kind: "revision_conflict", actualRevision: workingSet.revision };
1557
+ }
1558
+ return { workingSet };
1559
+ });
1560
+ }
1561
+ async function insertWorkingEvent(executor, event) {
1562
+ await executor.execute({
1563
+ sql: `
1564
+ INSERT INTO working_events (
1565
+ id,
1566
+ working_set_id,
1567
+ sequence,
1568
+ event_type,
1569
+ payload_json,
1570
+ actor,
1571
+ source,
1572
+ host_event_id,
1573
+ turn_id,
1574
+ created_at
1575
+ )
1576
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1577
+ `,
1578
+ args: [
1579
+ event.id,
1580
+ event.workingSetId,
1581
+ event.sequence,
1582
+ event.eventType,
1583
+ serializeJson(event.payload),
1584
+ toNullableString(event.actor),
1585
+ toNullableString(event.source),
1586
+ toNullableString(event.hostEventId),
1587
+ toNullableString(event.turnId),
1588
+ event.createdAt
1589
+ ]
1590
+ });
1591
+ }
1592
+ function buildWorkingSetSnapshotUpdateArgs(input) {
1593
+ return [
1594
+ toNullableString(input.title ?? input.current.title),
1595
+ toNullableString(input.objective ?? input.snapshot.objective),
1596
+ input.status,
1597
+ toNullableString(input.snapshot.summary),
1598
+ serializeJson(input.snapshot)
1599
+ ];
1600
+ }
1601
+ function buildEvent(input) {
1602
+ return {
1603
+ id: randomUUID2(),
1604
+ workingSetId: input.workingSetId,
1605
+ sequence: input.sequence,
1606
+ eventType: input.eventType,
1607
+ payload: input.payload,
1608
+ ...input.actor ? { actor: input.actor } : {},
1609
+ ...input.source ? { source: input.source } : {},
1610
+ createdAt: input.now
1611
+ };
1612
+ }
1613
+ function canApplyWorkingSetUpdate(currentStatus, nextStatus) {
1614
+ if (OPEN_WORKING_SET_STATUSES.includes(currentStatus)) {
1615
+ return true;
1616
+ }
1617
+ return currentStatus === "complete" && CLOSE_MANAGED_WORKING_SET_STATUSES.includes(nextStatus);
1618
+ }
1619
+ async function requireWorkingSet(executor, id) {
1620
+ const workingSet = await getWorkingSet(executor, id);
1621
+ if (!workingSet) {
1622
+ throw new Error(`Working set ${id} was not found after write.`);
1623
+ }
1624
+ return workingSet;
1625
+ }
1626
+ function serializeJson(value) {
1627
+ return JSON.stringify(value);
1628
+ }
1629
+ function toNullableString(value) {
1630
+ const trimmed = value?.trim();
1631
+ return trimmed && trimmed.length > 0 ? trimmed : null;
1632
+ }
1633
+
1634
+ // src/adapters/plugin-runtime/embed-query.ts
1635
+ function createEmbedQuery(embedding, available) {
1636
+ if (!available) {
1637
+ return void 0;
1638
+ }
1639
+ return async (text) => {
1640
+ const vectors = await embedding.embed([text]);
1641
+ const vector = vectors[0];
1642
+ if (!vector) {
1643
+ throw new Error("Embedding provider returned no vector for the query.");
1644
+ }
1645
+ return vector;
1646
+ };
1647
+ }
1648
+
1649
+ // src/adapters/plugin-runtime/create-memory-runtime.ts
1650
+ async function createPluginMemoryRuntime(input) {
1651
+ const embeddingStatus = resolveEmbeddingStatus(input.agenrConfig);
1652
+ const database = await createDatabase(input.dbPath);
1653
+ const embedding = embeddingStatus.available ? createEmbeddingClient(requireApiKey(embeddingStatus), embeddingStatus.model) : createUnavailableEmbeddingPort(embeddingStatus.error ?? "Embeddings are unavailable.");
1654
+ const baseRecall = createRecallAdapter(database, embedding);
1655
+ const recall = attachCrossEncoderPort(baseRecall, resolveCrossEncoder(input.agenrConfig));
1656
+ const slotPolicies = input.slotPolicies;
1657
+ const fetchActiveAbstainDirectives = () => listActiveAbstainDirectives(database);
1658
+ const fetchSessionStartProactiveDirectives = () => listActiveSessionStartProactiveDirectives(database);
1659
+ const fetchTopicProactiveDirectives = () => listActiveTopicProactiveDirectives(database);
1660
+ const sessionMemoryRepository = createSessionMemoryRepository(database);
1661
+ let closed = false;
1662
+ return {
1663
+ entries: database,
1664
+ episodes: database,
1665
+ procedures: database,
1666
+ memory: createMemoryRepository(database, {
1667
+ claimSlotPolicyConfig: slotPolicies
1668
+ }),
1669
+ dreaming: createDreamPort(database),
1670
+ workingMemoryRepository: createWorkingMemoryRepository(database),
1671
+ sessionMemoryRepository,
1672
+ sessionStart: {
1673
+ repository: createSessionStartRepository(database),
1674
+ recall,
1675
+ slotPolicyConfig: slotPolicies,
1676
+ listActiveAbstainDirectives: fetchActiveAbstainDirectives,
1677
+ listActiveProactiveDirectives: fetchSessionStartProactiveDirectives,
1678
+ sessionMemoryRepository
1679
+ },
1680
+ beforeTurn: {
1681
+ recall,
1682
+ procedures: database,
1683
+ embedQuery: createEmbedQuery(embedding, embeddingStatus.available),
1684
+ slotPolicyConfig: slotPolicies,
1685
+ listActiveAbstainDirectives: fetchActiveAbstainDirectives,
1686
+ listActiveTopicProactiveDirectives: fetchTopicProactiveDirectives
1687
+ },
1688
+ embedding,
1689
+ recall,
1690
+ claimExtraction: input.claimExtraction,
1691
+ embeddingStatus: toPublicEmbeddingStatus(embeddingStatus),
1692
+ async close() {
1693
+ if (closed) {
1694
+ return;
1695
+ }
1696
+ closed = true;
1697
+ if (input.onBeforeClose) {
1698
+ await input.onBeforeClose();
1699
+ }
1700
+ await database.close();
1701
+ }
1702
+ };
1703
+ }
1704
+ function resolveEmbeddingStatus(config) {
1705
+ const model = resolveEmbeddingModel(config);
1706
+ try {
1707
+ return {
1708
+ available: true,
1709
+ provider: "openai",
1710
+ requestedProvider: "openai",
1711
+ model,
1712
+ apiKey: resolveEmbeddingApiKey(config)
1713
+ };
1714
+ } catch (error) {
1715
+ return {
1716
+ available: false,
1717
+ provider: "unconfigured",
1718
+ requestedProvider: "openai",
1719
+ model,
1720
+ error: error instanceof Error ? error.message : String(error)
1721
+ };
1722
+ }
1723
+ }
1724
+ function toPublicEmbeddingStatus(status) {
1725
+ return {
1726
+ available: status.available,
1727
+ provider: status.provider,
1728
+ requestedProvider: status.requestedProvider,
1729
+ model: status.model,
1730
+ ...status.error ? { error: status.error } : {}
1731
+ };
1732
+ }
1733
+ function createUnavailableEmbeddingPort(errorMessage) {
1734
+ return {
1735
+ async embed() {
1736
+ throw new Error(errorMessage);
1737
+ }
1738
+ };
1739
+ }
1740
+ function requireApiKey(status) {
1741
+ if (!status.apiKey) {
1742
+ throw new Error("Embedding API key is unavailable.");
1743
+ }
1744
+ return status.apiKey;
1745
+ }
1746
+ function resolveCrossEncoder(config) {
1747
+ try {
1748
+ const apiKey = resolveCrossEncoderApiKey(config);
1749
+ const { modelId } = resolveModel(config, "cross_encoder");
1750
+ return createOpenAICrossEncoder({ apiKey, model: modelId });
1751
+ } catch {
1752
+ return void 0;
1753
+ }
1754
+ }
1755
+
1756
+ // src/app/plugin-runtime/resolve-paths.ts
1757
+ function resolvePluginRuntimeConfig(config, resolvePath) {
1758
+ const dbPathOverride = resolveOptionalPath(config.dbPath, resolvePath);
1759
+ const configPathOverride = resolveOptionalPath(config.configPath, resolvePath);
1760
+ const configPath = resolveConfigPath({
1761
+ configPath: configPathOverride,
1762
+ dbPath: dbPathOverride
1763
+ });
1764
+ const loadedConfig = readConfig({
1765
+ configPath,
1766
+ dbPath: dbPathOverride
1767
+ });
1768
+ const dbPath = dbPathOverride ?? resolveDbPath(loadedConfig);
1769
+ return {
1770
+ resolvedConfig: {
1771
+ dbPath,
1772
+ configPath
1773
+ },
1774
+ agenrConfig: {
1775
+ ...loadedConfig,
1776
+ dbPath
1777
+ }
1778
+ };
1779
+ }
1780
+ function resolveOptionalPath(value, resolvePath) {
1781
+ const normalized = value?.trim();
1782
+ if (!normalized) {
1783
+ return void 0;
1784
+ }
1785
+ return resolvePath ? resolvePath(normalized) : normalized;
1786
+ }
1787
+
1788
+ // src/adapters/plugin-runtime/compose-host-services.ts
1789
+ async function composeHostPluginServices(input) {
1790
+ const { resolvedConfig, agenrConfig } = resolvePluginRuntimeConfig(input.config, input.resolvePath);
1791
+ const claimExtraction = input.resolveClaimExtraction ? await input.resolveClaimExtraction({ agenrConfig, hostConfig: input.config }) : void 0;
1792
+ const runtimeServices = await createPluginMemoryRuntime({
1793
+ dbPath: resolvedConfig.dbPath,
1794
+ agenrConfig,
1795
+ slotPolicies: input.readSlotPolicies?.(input.config),
1796
+ claimExtraction,
1797
+ onBeforeClose: input.onBeforeClose
1798
+ });
1799
+ return await input.extend({
1800
+ config: input.config,
1801
+ resolvedConfig,
1802
+ agenrConfig,
1803
+ runtimeServices
1804
+ });
1805
+ }
1806
+
1807
+ // src/app/goal-continuation/service.ts
1808
+ var GOAL_CONTINUATION_FEATURE_DISABLED_MESSAGE = "Goal continuation is disabled by the goalContinuation feature flag.";
1809
+ var GOAL_CONTINUATION_HOST_MISSING_MESSAGE = "Goal continuation is host-owned; no host callback was registered for this Agenr runtime.";
1810
+ function createGoalContinuationService(featureFlags, hostPort) {
1811
+ const featureEnabled = featureFlags.goalContinuation;
1812
+ return {
1813
+ async runCommand(params) {
1814
+ if (!featureEnabled) {
1815
+ return {
1816
+ ok: false,
1817
+ code: "feature_disabled",
1818
+ message: GOAL_CONTINUATION_FEATURE_DISABLED_MESSAGE
1819
+ };
1820
+ }
1821
+ if (!hostPort) {
1822
+ return {
1823
+ ok: false,
1824
+ code: "host_callback_missing",
1825
+ message: GOAL_CONTINUATION_HOST_MISSING_MESSAGE
1826
+ };
1827
+ }
1828
+ return hostPort.runCommand(params);
1829
+ }
1830
+ };
1831
+ }
1832
+
1833
+ // src/app/session-memory/trigger-router.ts
1834
+ import { createHash } from "crypto";
1835
+ var SESSION_MEMORY_TRIGGER_FLAGS = {
1836
+ session_start: "sessionTreeLineage",
1837
+ session_before_fork: "sessionTreeLineage",
1838
+ session_before_compact: "sessionTreeCompaction",
1839
+ session_compact: "sessionTreeCompaction",
1840
+ session_before_tree: "sessionTreeCompaction",
1841
+ session_tree: "sessionTreeLineage",
1842
+ session_shutdown: "sessionTreeLineage"
1843
+ };
1844
+ var LINEAGE_REASONS = new Set(SESSION_LINEAGE_REASONS);
1845
+ async function routeSessionMemoryTrigger(event, featureFlags, deps = {}) {
1846
+ const flagKey = SESSION_MEMORY_TRIGGER_FLAGS[event.type];
1847
+ if (!featureFlags[flagKey]) {
1848
+ return {
1849
+ accepted: false,
1850
+ reason: "feature_disabled",
1851
+ message: `Session-memory trigger ${event.type} is disabled by feature flags.`
1852
+ };
1853
+ }
1854
+ if (!deps.repository) {
1855
+ return {
1856
+ accepted: false,
1857
+ reason: "misconfigured",
1858
+ message: `Session-memory trigger ${event.type} is enabled, but no session-memory repository was wired into the runtime.`
1859
+ };
1860
+ }
1861
+ const artifactInput = normalizeArtifactInput(event);
1862
+ if (artifactInput.kind === "invalid") {
1863
+ return invalidEvent(artifactInput.message);
1864
+ }
1865
+ const lineageInput = normalizeLineageInput(event);
1866
+ if (lineageInput.kind === "invalid") {
1867
+ return invalidEvent(lineageInput.message);
1868
+ }
1869
+ if (artifactInput.kind === "none" && lineageInput.kind === "none") {
1870
+ return maybeAttachWorkingCheckpointRefresh(
1871
+ event,
1872
+ {
1873
+ accepted: true,
1874
+ action: isCheckpointRelevantTrigger(event.type) ? "checkpoint_relevant" : "no_lineage",
1875
+ 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.`
1876
+ },
1877
+ deps
1878
+ );
1879
+ }
1880
+ const intakeInput = {
1881
+ ...artifactInput.kind === "artifact" ? { artifact: artifactInput.input } : {},
1882
+ ...lineageInput.kind === "lineage" ? { lineage: lineageInput.input } : {}
1883
+ };
1884
+ const intake = await deps.repository.recordTriggerIntake(intakeInput);
1885
+ const artifact = intake.artifact;
1886
+ const lineageEdge = intake.lineageEdge;
1887
+ const action = resolveTriggerAction(artifact, lineageEdge);
1888
+ return maybeAttachWorkingCheckpointRefresh(
1889
+ event,
1890
+ {
1891
+ accepted: true,
1892
+ action,
1893
+ message: buildAcceptedMessage(event.type, action, artifact, lineageEdge),
1894
+ ...lineageEdge ? { lineageEdge } : {},
1895
+ ...artifact ? { artifact } : {}
1896
+ },
1897
+ deps
1898
+ );
1899
+ }
1900
+ async function maybeAttachWorkingCheckpointRefresh(event, result, deps) {
1901
+ if (!deps.workingMemoryEnabled) {
1902
+ return result;
1903
+ }
1904
+ const { attachWorkingCheckpointRefresh } = await import("./lifecycle-checkpoint-IAC5FCQU.js");
1905
+ return attachWorkingCheckpointRefresh(event, result, deps.workingMemory);
1906
+ }
1907
+ function normalizeLineageInput(event) {
1908
+ if (!event.transitionReason || event.transitionReason === "new" || event.transitionReason === "unknown") {
1909
+ return { kind: "none" };
1910
+ }
1911
+ if (!LINEAGE_REASONS.has(event.transitionReason)) {
1912
+ return { kind: "invalid", message: `Unsupported session lineage reason "${event.transitionReason}".` };
1913
+ }
1914
+ const childSessionKey = normalizeOptionalString(event.childSessionKey) ?? normalizeOptionalString(event.sessionKey);
1915
+ if (!childSessionKey) {
1916
+ return { kind: "invalid", message: "Session lineage requires a child session key." };
1917
+ }
1918
+ const parentSessionKey = normalizeOptionalString(event.predecessor?.sessionKey);
1919
+ const parentSourceRef = normalizeOptionalString(event.predecessor?.sourceRef);
1920
+ if (!parentSessionKey && !parentSourceRef) {
1921
+ return { kind: "none" };
1922
+ }
1923
+ const forkEntryId = normalizeOptionalString(event.predecessor?.forkEntryId);
1924
+ const forkPosition = normalizeOptionalString(event.predecessor?.forkPosition);
1925
+ return {
1926
+ kind: "lineage",
1927
+ input: {
1928
+ childSessionKey,
1929
+ ...parentSessionKey ? { parentSessionKey } : {},
1930
+ ...parentSourceRef ? { parentSourceRef } : {},
1931
+ reason: event.transitionReason,
1932
+ ...forkEntryId ? { forkEntryId } : {},
1933
+ ...forkPosition ? { forkPosition } : {},
1934
+ observedAt: event.observedAt
1935
+ }
1936
+ };
1937
+ }
1938
+ function normalizeArtifactInput(event) {
1939
+ if (!event.artifact) {
1940
+ return { kind: "none" };
1941
+ }
1942
+ const sessionKey = normalizeOptionalString(event.artifact.sessionKey) ?? normalizeOptionalString(event.sessionKey);
1943
+ if (!sessionKey) {
1944
+ return { kind: "invalid", message: "Session artifact intake requires a session key." };
1945
+ }
1946
+ const source = normalizeOptionalString(event.artifact.source);
1947
+ const sourceId = normalizeOptionalString(event.artifact.sourceId);
1948
+ const summary = normalizeOptionalString(event.artifact.summary);
1949
+ if (!source || !sourceId || !summary) {
1950
+ return { kind: "invalid", message: "Session artifact intake requires source, sourceId, and summary." };
1951
+ }
1952
+ const contentHash = normalizeOptionalString(event.artifact.contentHash) ?? hashArtifactContent(event.artifact);
1953
+ return {
1954
+ kind: "artifact",
1955
+ input: {
1956
+ ...event.artifact,
1957
+ sessionKey,
1958
+ source,
1959
+ sourceId,
1960
+ summary,
1961
+ contentHash
1962
+ }
1963
+ };
1964
+ }
1965
+ function hashArtifactContent(artifact) {
1966
+ const payload = JSON.stringify({
1967
+ kind: artifact.kind,
1968
+ source: artifact.source,
1969
+ sourceId: artifact.sourceId,
1970
+ sourceRef: artifact.sourceRef,
1971
+ summary: artifact.summary,
1972
+ metadata: artifact.metadata
1973
+ });
1974
+ return createHash("sha256").update(payload).digest("hex");
1975
+ }
1976
+ function resolveTriggerAction(artifact, lineageEdge) {
1977
+ if (artifact && lineageEdge) {
1978
+ return "recorded";
1979
+ }
1980
+ if (artifact) {
1981
+ return "artifact_recorded";
1982
+ }
1983
+ return "lineage_recorded";
1984
+ }
1985
+ function buildAcceptedMessage(triggerType, action, artifact, lineageEdge) {
1986
+ if (action === "recorded" && artifact && lineageEdge) {
1987
+ return `Session-memory trigger ${triggerType} recorded ${lineageEdge.reason} lineage edge ${lineageEdge.id} and ${artifact.kind} artifact ${artifact.id}.`;
1988
+ }
1989
+ if (action === "artifact_recorded" && artifact) {
1990
+ return `Session-memory trigger ${triggerType} recorded ${artifact.kind} artifact ${artifact.id}.`;
1991
+ }
1992
+ if (lineageEdge) {
1993
+ return `Session-memory trigger ${triggerType} recorded ${lineageEdge.reason} lineage edge ${lineageEdge.id}.`;
1994
+ }
1995
+ return `Session-memory trigger ${triggerType} was accepted.`;
1996
+ }
1997
+ function invalidEvent(message) {
1998
+ return {
1999
+ accepted: false,
2000
+ reason: "invalid_event",
2001
+ message
2002
+ };
2003
+ }
2004
+ function isCheckpointRelevantTrigger(type) {
2005
+ return type === "session_before_fork" || type === "session_before_compact" || type === "session_before_tree" || type === "session_shutdown";
2006
+ }
2007
+
2008
+ // src/app/working-memory/disabled-service.ts
2009
+ function createDisabledWorkingMemoryService() {
2010
+ const failure = () => createFailure("feature_disabled", WORKING_MEMORY_DISABLED_MESSAGE);
2011
+ return {
2012
+ async run(_params) {
2013
+ return failure();
2014
+ },
2015
+ async prepareExternalGoalMutation(_params) {
2016
+ return failure();
2017
+ },
2018
+ async renderProjection(input) {
2019
+ const sourceRef = typeof input === "string" ? input : input.sourceRef;
2020
+ return createWorkingContextStubProjection({
2021
+ reason: "feature_disabled",
2022
+ sourceRef
2023
+ });
2024
+ }
2025
+ };
2026
+ }
2027
+
2028
+ // src/app/host-memory/create-host-memory-services.ts
2029
+ async function createHostMemoryServices(featureFlags, options = {}) {
2030
+ const workingMemory = featureFlags.workingMemory ? (await import("./service-RHNB5AEQ.js")).createWorkingMemoryService(featureFlags, {
2031
+ repository: options.workingMemoryRepository,
2032
+ sourceLabel: options.workingMemorySourceLabel
2033
+ }) : createDisabledWorkingMemoryService();
2034
+ return {
2035
+ workingMemory,
2036
+ goalContinuation: createGoalContinuationService(featureFlags, options.goalContinuationHostPort),
2037
+ routeSessionMemoryTrigger: (event) => routeSessionMemoryTrigger(event, featureFlags, {
2038
+ repository: options.sessionMemoryRepository,
2039
+ workingMemoryEnabled: featureFlags.workingMemory,
2040
+ workingMemory: featureFlags.workingMemory ? workingMemory : void 0
2041
+ })
2042
+ };
2043
+ }
2044
+
2045
+ // src/adapters/shared/bounded-episode-embedding.ts
2046
+ var EPISODE_EMBEDDING_RACE_TIMEOUT = /* @__PURE__ */ Symbol("episode-embedding-race-timeout");
2047
+ var EPISODE_EMBEDDING_MIN_HEADROOM_MS = 5e3;
2048
+ async function embedEpisodeSummaryWithinBudget(params) {
2049
+ const minHeadroomMs = params.minHeadroomMs ?? EPISODE_EMBEDDING_MIN_HEADROOM_MS;
2050
+ if (!params.embeddingAvailable) {
2051
+ params.logger.info(`${params.logContext} reason=embedding_unavailable`);
2052
+ return void 0;
2053
+ }
2054
+ const remainingBudgetMs = params.deadlineMs - Date.now();
2055
+ if (remainingBudgetMs < minHeadroomMs) {
2056
+ params.logger.info(`${params.logContext} reason=budget_tight remainingMs=${Math.max(0, remainingBudgetMs)}`);
2057
+ return void 0;
2058
+ }
2059
+ try {
2060
+ const result = await raceEmbeddingWithTimeout(params.embedding.embed([params.summary]), remainingBudgetMs);
2061
+ if (result === EPISODE_EMBEDDING_RACE_TIMEOUT) {
2062
+ params.logger.info(`${params.logContext} reason=embedding_timeout budgetMs=${remainingBudgetMs}`);
2063
+ return void 0;
2064
+ }
2065
+ const vector = result[0]?.map((value) => Number.isFinite(value) ? value : 0);
2066
+ if (!vector || vector.length === 0) {
2067
+ params.logger.info(`${params.logContext} reason=empty_embedding`);
2068
+ return void 0;
2069
+ }
2070
+ return vector;
2071
+ } catch (error) {
2072
+ params.logger.info(`${params.logContext} reason=${formatErrorMessage(error)}`);
2073
+ return void 0;
2074
+ }
2075
+ }
2076
+ async function raceEmbeddingWithTimeout(promise, timeoutMs) {
2077
+ return new Promise((resolve, reject) => {
2078
+ const timeout = setTimeout(() => {
2079
+ resolve(EPISODE_EMBEDDING_RACE_TIMEOUT);
2080
+ }, timeoutMs);
2081
+ promise.then(
2082
+ (value) => {
2083
+ clearTimeout(timeout);
2084
+ resolve(value);
2085
+ },
2086
+ (error) => {
2087
+ clearTimeout(timeout);
2088
+ reject(error);
2089
+ }
2090
+ );
2091
+ });
2092
+ }
2093
+
2094
+ // src/adapters/shared/bounded-episode-summary.ts
2095
+ var EPISODE_SUMMARY_TIMEOUT_MS = 45e3;
2096
+ var EPISODE_SUMMARY_TIMEOUT_MESSAGE = "Episode summary generation timed out.";
2097
+ var EpisodeSummaryTimeoutError = class extends Error {
2098
+ /**
2099
+ * Creates a timeout error with a stable name for caller-side handling.
2100
+ */
2101
+ constructor() {
2102
+ super(EPISODE_SUMMARY_TIMEOUT_MESSAGE);
2103
+ this.name = "EpisodeSummaryTimeoutError";
2104
+ }
2105
+ };
2106
+ async function raceEpisodeSummaryWithinTimeout(task, timeoutMs) {
2107
+ let timeout;
2108
+ try {
2109
+ return await Promise.race([
2110
+ task,
2111
+ new Promise((_, reject) => {
2112
+ timeout = setTimeout(() => reject(new EpisodeSummaryTimeoutError()), timeoutMs);
2113
+ })
2114
+ ]);
2115
+ } finally {
2116
+ if (timeout) {
2117
+ clearTimeout(timeout);
2118
+ }
2119
+ }
2120
+ }
2121
+
2122
+ // src/adapters/shared/bounded-episode-ingest-log.ts
2123
+ function logBoundedEpisodeTranscriptIngestOutcome(params) {
2124
+ const prefix = `[agenr] ${params.actionLabel}`;
2125
+ const fileField = params.fileField ?? "file";
2126
+ const fileRef = `${fileField}=${params.filePath}`;
2127
+ const countField = params.shortCountField ?? "materialTurns";
2128
+ if (params.result.kind === "skipped") {
2129
+ const skipped = params.result.skipped;
2130
+ if (skipped.reason === "skipped_exists") {
2131
+ params.logger.info(`${prefix} skipped for ${params.context} ${fileRef} reason=already_exists episode=${skipped.existingEpisode?.id}`);
2132
+ return false;
2133
+ }
2134
+ if (skipped.reason === "skipped_short") {
2135
+ params.logger.info(`${prefix} skipped for ${params.context} ${fileRef} reason=too_short ${countField}=${skipped.messageCount}`);
2136
+ return false;
2137
+ }
2138
+ params.logger.info(`${prefix} skipped for ${params.context} ${fileRef} reason=${skipped.reason} ${countField}=${skipped.messageCount}`);
2139
+ return false;
2140
+ }
2141
+ if (params.result.kind === "invalid") {
2142
+ params.logger.info(`${prefix} skipped for ${params.context} ${fileRef} reason=invalid_transcript ${countField}=${params.result.invalid.messageCount}`);
2143
+ return false;
2144
+ }
2145
+ const session = params.result.session;
2146
+ if (session.action === "failed") {
2147
+ if (session.error === EPISODE_SUMMARY_TIMEOUT_MESSAGE) {
2148
+ params.logger.info(`${prefix} timed_out for ${params.context} ${fileRef} timeoutMs=${EPISODE_SUMMARY_TIMEOUT_MS}`);
2149
+ return false;
2150
+ }
2151
+ if (session.error === "invalid_response" && params.failureModelRef) {
2152
+ params.logger.info(`${prefix} failed for ${params.context} ${fileRef} reason=invalid_response model=${params.failureModelRef}`);
2153
+ return false;
2154
+ }
2155
+ params.logger.info(`${prefix} failed for ${params.context} ${fileRef} reason=${session.error ?? "unknown"}`);
2156
+ return false;
2157
+ }
2158
+ params.logger.info(`${prefix} ${session.action} for ${params.context} ${fileRef} episode=${session.episodeId}`);
2159
+ return true;
2160
+ }
2161
+
2162
+ // src/adapters/shared/bounded-episode-write.ts
2163
+ async function writeBoundedSingleTranscriptEpisode(params) {
2164
+ const fileField = params.fileField ?? "file";
2165
+ const fileRef = `${fileField}=${params.filePath}`;
2166
+ try {
2167
+ const ingestResult = await raceEpisodeSummaryWithinTimeout(
2168
+ ingestEpisodeTranscript(params.filePath, params.ports, params.ingestOptions),
2169
+ EPISODE_SUMMARY_TIMEOUT_MS
2170
+ );
2171
+ logBoundedEpisodeTranscriptIngestOutcome({
2172
+ logger: params.logger,
2173
+ actionLabel: params.actionLabel,
2174
+ context: params.context,
2175
+ filePath: params.filePath,
2176
+ ...params.fileField ? { fileField: params.fileField } : {},
2177
+ ...params.shortCountField ? { shortCountField: params.shortCountField } : {},
2178
+ result: ingestResult,
2179
+ ...params.failureModelRef ? { failureModelRef: params.failureModelRef } : {}
2180
+ });
2181
+ } catch (error) {
2182
+ if (error instanceof EpisodeSummaryTimeoutError) {
2183
+ params.logger.info(`[agenr] ${params.actionLabel} timed_out for ${params.context} ${fileRef} timeoutMs=${EPISODE_SUMMARY_TIMEOUT_MS}`);
2184
+ return;
2185
+ }
2186
+ const message = formatErrorMessage(error);
2187
+ if (params.unexpectedFailureLevel === "info") {
2188
+ params.logger.info(`[agenr] ${params.actionLabel} failed for ${params.context} ${fileRef} reason=${message}`);
2189
+ return;
2190
+ }
2191
+ params.logger.warn(`[agenr] ${params.actionLabel} failed for ${params.context} ${fileRef} reason=${message}`);
2192
+ }
2193
+ }
2194
+
2195
+ // src/adapters/shared/deadline-aware-episode-summary-llm.ts
2196
+ function createDeadlineAwareEpisodeSummaryLlm(baseLlm, deadlineMs) {
2197
+ const usage = cloneUsageStats(baseLlm.metadata.usage);
2198
+ const completeWithTimeout = async (task) => {
2199
+ usage.calls += 1;
2200
+ const remainingMs = Math.max(0, deadlineMs - Date.now());
2201
+ return raceEpisodeSummaryWithinTimeout(task, remainingMs);
2202
+ };
2203
+ return {
2204
+ complete: async (systemPrompt, userMessage) => completeWithTimeout(baseLlm.complete(systemPrompt, userMessage)),
2205
+ completeJson: async (systemPrompt, userMessage) => completeWithTimeout(baseLlm.completeJson(systemPrompt, userMessage)),
2206
+ metadata: {
2207
+ ...baseLlm.metadata,
2208
+ usage
2209
+ }
2210
+ };
2211
+ }
2212
+ function cloneUsageStats(usage) {
2213
+ return { ...usage };
2214
+ }
2215
+
2216
+ // src/adapters/shared/claim-support.ts
2217
+ function buildSessionSourceFile(session, prefix) {
2218
+ const target = session.sessionKey ?? session.sessionId ?? session.agentId ?? "unknown";
2219
+ return `${prefix}:${target}`;
2220
+ }
2221
+ function buildToolCallClaimSupport(session, prefix, toolName, observedAt) {
2222
+ return {
2223
+ claim_support_source_kind: "tool_call",
2224
+ claim_support_locator: `${buildSessionSourceFile(session, prefix)}#${toolName}`,
2225
+ claim_support_observed_at: observedAt,
2226
+ claim_support_mode: "explicit"
2227
+ };
2228
+ }
2229
+
2230
+ // src/adapters/shared/resolve-target.ts
2231
+ function buildEntryMemoryResolverPorts(services) {
2232
+ return {
2233
+ getDurableById: async (entryId) => await services.entries.getDurable(entryId) ?? (await services.memory.getEntryTrace(entryId))?.entry ?? null,
2234
+ findEntryBySubject: async (subject) => services.memory.findEntryBySubject(subject)
2235
+ };
2236
+ }
2237
+ async function resolveTargetDurable(ports, params) {
2238
+ const id = readOptionalStringParam(params, "id");
2239
+ const subject = readOptionalStringParam(params, "subject");
2240
+ const selectorCount = (id ? 1 : 0) + (subject ? 1 : 0);
2241
+ if (selectorCount !== 1) {
2242
+ throw new Error("Provide exactly one target selector: id or subject.");
2243
+ }
2244
+ if (id) {
2245
+ const entry2 = await ports.getDurableById(id);
2246
+ if (!entry2) {
2247
+ throw new Error(`No agenr entry found for id ${id}.`);
2248
+ }
2249
+ return entry2;
2250
+ }
2251
+ const entry = await ports.findEntryBySubject(subject ?? "");
2252
+ if (!entry) {
2253
+ throw new Error(`No agenr entry found for subject "${subject}".`);
2254
+ }
2255
+ return entry;
2256
+ }
2257
+ function readOptionalStringParam(params, key) {
2258
+ const value = params[key];
2259
+ if (value === void 0 || value === null) {
2260
+ return void 0;
2261
+ }
2262
+ if (typeof value !== "string") {
2263
+ throw new Error(`${key} must be a string.`);
2264
+ }
2265
+ const normalized = value.trim();
2266
+ return normalized.length > 0 ? normalized : void 0;
2267
+ }
2268
+
2269
+ // src/adapters/shared/memory-tools.ts
2270
+ function buildRecallToolServices(services) {
2271
+ return {
2272
+ episodes: services.episodes,
2273
+ procedures: services.procedures,
2274
+ recall: services.recall,
2275
+ embeddingStatus: services.embeddingStatus,
2276
+ embedQuery: services.beforeTurn.embedQuery
2277
+ };
2278
+ }
2279
+ var STORE_TOOL_PARAMETERS = {
2280
+ type: "object",
2281
+ additionalProperties: false,
2282
+ properties: {
2283
+ type: {
2284
+ type: "string",
2285
+ enum: [...DURABLE_KINDS],
2286
+ description: ENTRY_TYPE_DESCRIPTION
2287
+ },
2288
+ subject: {
2289
+ type: "string",
2290
+ description: "Short subject line future recall can match. Name the durable takeaway, person, system, rule, relationship, or milestone directly."
2291
+ },
2292
+ content: {
2293
+ type: "string",
2294
+ description: "What a fresh session should remember. Store the durable takeaway, not the activity log, canonical record, or transient progress snapshot."
2295
+ },
2296
+ importance: {
2297
+ type: "integer",
2298
+ minimum: 1,
2299
+ maximum: 10,
2300
+ description: "Importance from 1 to 10. Use 7 for normal durable memory, 9 for critical constraints, and 10 only rarely."
2301
+ },
2302
+ expiry: {
2303
+ type: "string",
2304
+ enum: ["core", "permanent", "temporary"],
2305
+ description: EXPIRY_DESCRIPTION
2306
+ },
2307
+ tags: {
2308
+ type: "array",
2309
+ items: { type: "string" },
2310
+ description: "Optional tags for entities, systems, teams, or themes that should improve later recall."
2311
+ },
2312
+ sourceContext: {
2313
+ type: "string",
2314
+ description: "Optional provenance note explaining why this memory was stored or what situation produced it."
2315
+ },
2316
+ supersedes: {
2317
+ type: "string",
2318
+ description: "ID of an entry this replaces. The old entry will be marked as superseded."
2319
+ },
2320
+ claimKey: {
2321
+ type: "string",
2322
+ description: CLAIM_KEY_DESCRIPTION
2323
+ },
2324
+ polarity: {
2325
+ type: "string",
2326
+ enum: ["abstain", "proactive"],
2327
+ description: "Required when type is directive. Use abstain to suppress a topic or behavior; use proactive to surface the directive when its trigger fires."
2328
+ },
2329
+ trigger: {
2330
+ type: "string",
2331
+ 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."
2332
+ },
2333
+ validFrom: {
2334
+ type: "string",
2335
+ description: "ISO 8601 timestamp for when this fact became true in the world."
2336
+ },
2337
+ validTo: {
2338
+ type: "string",
2339
+ description: "ISO 8601 timestamp for when this fact stopped being true."
2340
+ },
2341
+ project: {
2342
+ type: "string",
2343
+ 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."
2344
+ }
2345
+ },
2346
+ required: ["type", "subject", "content"]
2347
+ };
2348
+ var RECALL_TOOL_PARAMETERS = {
2349
+ type: "object",
2350
+ additionalProperties: false,
2351
+ properties: {
2352
+ query: {
2353
+ type: "string",
2354
+ 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'."
2355
+ },
2356
+ mode: {
2357
+ type: "string",
2358
+ enum: [...RECALL_MODES],
2359
+ description: RECALL_MODE_SCHEMA_DESCRIPTION
2360
+ },
2361
+ limit: {
2362
+ type: "integer",
2363
+ minimum: 1,
2364
+ maximum: 10,
2365
+ description: "Maximum results to return. Lower this when you want a tighter shortlist."
2366
+ },
2367
+ threshold: {
2368
+ type: "number",
2369
+ minimum: 0,
2370
+ maximum: 1,
2371
+ description: "Minimum final score from 0 to 1. Raise this when you want fewer, higher-confidence matches."
2372
+ },
2373
+ budget: {
2374
+ type: "integer",
2375
+ minimum: 1,
2376
+ description: "Approximate token budget applied after durable scoring. Omit when you do not want a budget cap."
2377
+ },
2378
+ types: {
2379
+ type: "array",
2380
+ items: {
2381
+ type: "string",
2382
+ enum: [...DURABLE_KINDS]
2383
+ },
2384
+ description: "Optional knowledge types to filter by, such as decision, preference, lesson, fact, milestone, or relationship."
2385
+ },
2386
+ tags: {
2387
+ type: "array",
2388
+ items: { type: "string" },
2389
+ description: "Optional tags to filter by once you already know the relevant entity, system, or theme."
2390
+ },
2391
+ asOf: {
2392
+ type: "string",
2393
+ description: "Optional reference time for current-vs-prior resolution. Supports ISO timestamps and natural-language date phrases."
2394
+ }
2395
+ },
2396
+ required: ["query"]
2397
+ };
2398
+ var UPDATE_TOOL_PARAMETERS = {
2399
+ type: "object",
2400
+ additionalProperties: false,
2401
+ properties: {
2402
+ id: {
2403
+ type: "string",
2404
+ description: "Entry id to update. Provide exactly one of id or subject."
2405
+ },
2406
+ subject: {
2407
+ type: "string",
2408
+ 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."
2409
+ },
2410
+ importance: {
2411
+ type: "integer",
2412
+ description: "New importance from 1 to 10. Use 7 for normal durable memory and reserve 9 to 10 for rare critical durables."
2413
+ },
2414
+ expiry: {
2415
+ type: "string",
2416
+ description: UPDATE_EXPIRY_DESCRIPTION
2417
+ },
2418
+ claimKey: {
2419
+ type: "string",
2420
+ description: CLAIM_KEY_DESCRIPTION
2421
+ },
2422
+ validFrom: {
2423
+ type: "string",
2424
+ description: "ISO 8601 timestamp for when this fact became true."
2425
+ },
2426
+ validTo: {
2427
+ type: "string",
2428
+ description: "ISO 8601 timestamp for when this fact stopped being true."
2429
+ },
2430
+ project: {
2431
+ type: "string",
2432
+ 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."
2433
+ }
2434
+ }
2435
+ };
2436
+ var FETCH_TOOL_PARAMETERS = {
2437
+ type: "object",
2438
+ additionalProperties: false,
2439
+ properties: {
2440
+ id: {
2441
+ type: "string",
2442
+ description: "Entry id to fetch. Provide exactly one of id or subject."
2443
+ },
2444
+ subject: {
2445
+ type: "string",
2446
+ 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."
2447
+ }
2448
+ }
2449
+ };
2450
+ function parseStoreToolParams(rawParams, reader) {
2451
+ const params = asRecord(rawParams);
2452
+ const type = parseDurableKind(reader.readString(params, "type", { required: true, label: "type" }) ?? "");
2453
+ return {
2454
+ type,
2455
+ subject: reader.readString(params, "subject", { required: true, label: "subject" }) ?? "",
2456
+ content: reader.readString(params, "content", { required: true, label: "content" }) ?? "",
2457
+ importance: reader.readNumber(params, "importance", { integer: true, strict: true }),
2458
+ expiry: parseExpiry(reader.readString(params, "expiry")),
2459
+ tags: normalizeStringArray(reader.readStringArray(params, "tags")),
2460
+ sourceContext: reader.readString(params, "sourceContext"),
2461
+ supersedes: reader.readString(params, "supersedes"),
2462
+ claimKey: reader.readString(params, "claimKey", { trim: false }),
2463
+ polarity: parseDirectivePolarityParam(reader.readString(params, "polarity")),
2464
+ trigger: parseDirectiveTriggerParam(reader.readString(params, "trigger")),
2465
+ validFrom: reader.readString(params, "validFrom"),
2466
+ validTo: reader.readString(params, "validTo"),
2467
+ project: reader.readString(params, "project")
2468
+ };
2469
+ }
2470
+ function parseRecallToolParams(rawParams, reader) {
2471
+ const params = asRecord(rawParams);
2472
+ const budget = reader.readNumber(params, "budget", { integer: true, strict: true });
2473
+ if (budget !== void 0 && budget <= 0) {
2474
+ throw new Error("budget must be a positive integer.");
2475
+ }
2476
+ return {
2477
+ query: reader.readString(params, "query", { required: true, label: "query" }) ?? "",
2478
+ mode: parseRecallMode(reader.readString(params, "mode")),
2479
+ limit: reader.readNumber(params, "limit", { integer: true, strict: true }),
2480
+ threshold: reader.readNumber(params, "threshold", { strict: true }),
2481
+ budget,
2482
+ types: parseDurableKinds(reader.readStringArray(params, "types")),
2483
+ tags: normalizeStringArray(reader.readStringArray(params, "tags")),
2484
+ asOf: reader.readString(params, "asOf")
2485
+ };
2486
+ }
2487
+ function parseUpdateToolParams(rawParams, reader) {
2488
+ const params = asRecord(rawParams);
2489
+ return {
2490
+ id: reader.readString(params, "id"),
2491
+ subject: reader.readString(params, "subject"),
2492
+ importance: reader.readNumber(params, "importance", { integer: true, strict: true }),
2493
+ expiry: parseExpiry(reader.readString(params, "expiry")),
2494
+ claimKeyInput: reader.readString(params, "claimKey", { trim: false }),
2495
+ validFrom: reader.readString(params, "validFrom"),
2496
+ validTo: reader.readString(params, "validTo"),
2497
+ project: reader.readString(params, "project")
2498
+ };
2499
+ }
2500
+ function parseFetchToolParams(rawParams, reader) {
2501
+ const params = asRecord(rawParams);
2502
+ return {
2503
+ id: reader.readString(params, "id"),
2504
+ subject: reader.readString(params, "subject")
2505
+ };
2506
+ }
2507
+ async function runStoreMemoryTool(params, services, options) {
2508
+ const sourceContext = params.sourceContext ?? options.defaultSourceContext;
2509
+ const project = resolveDurableProjectScope(
2510
+ {
2511
+ project: params.project,
2512
+ subject: params.subject,
2513
+ content: params.content,
2514
+ tags: params.tags,
2515
+ source_context: sourceContext,
2516
+ claim_key: params.claimKey
2517
+ },
2518
+ { sessionWorkspace: options.session.project }
2519
+ );
2520
+ const warnings = [];
2521
+ const handleWarning = (warning) => {
2522
+ warnings.push(warning);
2523
+ options.onWarning?.(warning);
2524
+ };
2525
+ const result = await storeDurablesDetailed(
2526
+ [
2527
+ {
2528
+ type: params.type,
2529
+ subject: params.subject,
2530
+ content: params.content,
2531
+ ...params.importance !== void 0 ? { importance: params.importance } : {},
2532
+ ...params.expiry !== void 0 ? { expiry: params.expiry } : {},
2533
+ ...params.tags.length > 0 ? { tags: params.tags } : {},
2534
+ ...params.supersedes ? { supersedes: params.supersedes } : {},
2535
+ ...params.claimKey ? {
2536
+ claim_key: params.claimKey,
2537
+ claim_key_raw: params.claimKey,
2538
+ ...buildToolCallClaimSupport(options.session, options.sourcePrefix, "agenr_store", (/* @__PURE__ */ new Date()).toISOString())
2539
+ } : {},
2540
+ ...params.polarity ? { directive_polarity: params.polarity } : {},
2541
+ ...params.trigger ? { directive_trigger: params.trigger } : {},
2542
+ ...params.validFrom ? { valid_from: params.validFrom } : {},
2543
+ ...params.validTo ? { valid_to: params.validTo } : {},
2544
+ source_file: buildSessionSourceFile(options.session, options.sourcePrefix),
2545
+ source_context: sourceContext,
2546
+ ...project ? { project } : {}
2547
+ }
2548
+ ],
2549
+ services.entries,
2550
+ services.embedding,
2551
+ {
2552
+ ...services.claimExtraction ? {
2553
+ claimExtraction: {
2554
+ llm: services.claimExtraction.llm,
2555
+ db: services.entries,
2556
+ config: services.claimExtraction.config
2557
+ }
2558
+ } : {},
2559
+ onWarning: handleWarning
2560
+ }
2561
+ );
2562
+ const storedEntry = await services.memory.findEntryBySubject(params.subject);
2563
+ if (result.stored > 0) {
2564
+ return okOutcome(
2565
+ `Stored "${params.subject}".`,
2566
+ {
2567
+ status: "stored",
2568
+ subject: params.subject,
2569
+ entryId: storedEntry?.id,
2570
+ result,
2571
+ ...options.extraDetails
2572
+ },
2573
+ warnings
2574
+ );
2575
+ }
2576
+ if (result.skipped > 0) {
2577
+ return okOutcome(
2578
+ `Skipped "${params.subject}" because an active duplicate already exists.`,
2579
+ {
2580
+ status: "skipped",
2581
+ subject: params.subject,
2582
+ entryId: storedEntry?.id,
2583
+ result,
2584
+ ...options.extraDetails
2585
+ },
2586
+ warnings
2587
+ );
2588
+ }
2589
+ return failedOutcome(
2590
+ `Rejected "${params.subject}". Check the supplied type, content, and metadata.`,
2591
+ {
2592
+ status: "failed",
2593
+ subject: params.subject,
2594
+ result,
2595
+ ...options.extraDetails
2596
+ },
2597
+ warnings
2598
+ );
2599
+ }
2600
+ async function runRecallMemoryTool(params, services, options = {}) {
2601
+ return runUnifiedRecall(
2602
+ {
2603
+ text: params.query,
2604
+ ...params.mode ? { mode: params.mode } : {},
2605
+ ...params.limit !== void 0 ? { limit: params.limit } : {},
2606
+ ...params.threshold !== void 0 ? { threshold: params.threshold } : {},
2607
+ ...params.budget !== void 0 ? { budget: params.budget } : {},
2608
+ ...params.types.length > 0 ? { types: params.types } : {},
2609
+ ...params.tags.length > 0 ? { tags: params.tags } : {},
2610
+ ...params.asOf ? { asOf: params.asOf } : {},
2611
+ ...options.sessionKey ? { sessionKey: options.sessionKey } : {}
2612
+ },
2613
+ {
2614
+ database: services.episodes,
2615
+ procedures: services.procedures,
2616
+ recall: services.recall,
2617
+ embeddingAvailable: services.embeddingStatus.available,
2618
+ embeddingError: services.embeddingStatus.error,
2619
+ claimSlotPolicyConfig: options.slotPolicyConfig,
2620
+ debugLog: options.debugLog,
2621
+ embedQuery: services.embedQuery,
2622
+ recallOptions: {
2623
+ slotPolicyConfig: options.slotPolicyConfig
2624
+ }
2625
+ }
2626
+ );
2627
+ }
2628
+ async function runFetchMemoryTool(params, services, options = {}) {
2629
+ const entry = await resolveTargetDurable(buildEntryMemoryResolverPorts(services), { id: params.id, subject: params.subject });
2630
+ assertEntryFetchableContentLength(entry.content);
2631
+ return okOutcome(formatFetchedEntryText(entry), buildFetchToolDetails(entry, options.extraDetails));
2632
+ }
2633
+ async function runUpdateMemoryTool(params, services, options) {
2634
+ const claimSupport = params.claimKeyInput === void 0 ? void 0 : buildToolCallClaimSupport(options.session, options.sourcePrefix, "agenr_update", (/* @__PURE__ */ new Date()).toISOString());
2635
+ const normalizedClaimKeyUpdate = params.claimKeyInput === void 0 ? void 0 : (() => {
2636
+ try {
2637
+ return normalizeManualClaimKeyUpdate({
2638
+ claimKey: params.claimKeyInput,
2639
+ rawClaimKey: params.claimKeyInput,
2640
+ supportSourceKind: claimSupport?.claim_support_source_kind,
2641
+ supportLocator: claimSupport?.claim_support_locator,
2642
+ supportObservedAt: claimSupport?.claim_support_observed_at,
2643
+ supportMode: claimSupport?.claim_support_mode
2644
+ });
2645
+ } catch {
2646
+ throw new Error("claimKey must use canonical entity/attribute format.");
2647
+ }
2648
+ })();
2649
+ const entry = await resolveTargetDurable(buildEntryMemoryResolverPorts(services), { id: params.id, subject: params.subject });
2650
+ const mergedValidity = validateTemporalValidityRange(params.validFrom ?? entry.valid_from, params.validTo ?? entry.valid_to);
2651
+ if (!mergedValidity.ok) {
2652
+ throw new Error(mergedValidity.message);
2653
+ }
2654
+ const normalizedValidFrom = params.validFrom !== void 0 ? mergedValidity.value.validFrom : void 0;
2655
+ const normalizedValidTo = params.validTo !== void 0 ? mergedValidity.value.validTo : void 0;
2656
+ const patch = buildUpdateMemoryToolPatch(params, normalizedClaimKeyUpdate, normalizedValidFrom, normalizedValidTo);
2657
+ if (Object.keys(patch.dbFields).length === 0) {
2658
+ throw new Error("Provide at least one update field.");
2659
+ }
2660
+ const updated = await services.entries.updateDurable(entry.id, patch.dbFields);
2661
+ if (!updated) {
2662
+ return failedOutcome(`Entry ${entry.id} is not active, so it could not be updated.`, {
2663
+ status: "failed",
2664
+ entryId: entry.id,
2665
+ ...options.failureDetails
2666
+ });
2667
+ }
2668
+ return okOutcome(`Updated "${entry.subject}".`, {
2669
+ status: "updated",
2670
+ entryId: entry.id,
2671
+ subject: entry.subject,
2672
+ ...patch.details,
2673
+ ...options.successDetails
2674
+ });
2675
+ }
2676
+ function buildUpdateMemoryToolPatch(params, normalizedClaimKeyUpdate, normalizedValidFrom, normalizedValidTo) {
2677
+ const dbFields = {
2678
+ ...params.importance !== void 0 ? { importance: params.importance } : {},
2679
+ ...params.expiry !== void 0 ? { expiry: params.expiry } : {},
2680
+ ...normalizedClaimKeyUpdate?.updateFields ?? {},
2681
+ ...params.validFrom !== void 0 ? { valid_from: normalizedValidFrom } : {},
2682
+ ...params.validTo !== void 0 ? { valid_to: normalizedValidTo } : {},
2683
+ ...params.project !== void 0 ? { project: params.project } : {}
2684
+ };
2685
+ return {
2686
+ dbFields,
2687
+ details: {
2688
+ ...params.importance !== void 0 ? { importance: params.importance } : {},
2689
+ ...params.expiry !== void 0 ? { expiry: params.expiry } : {},
2690
+ ...normalizedClaimKeyUpdate !== void 0 ? { claimKey: normalizedClaimKeyUpdate.claimKey } : {},
2691
+ ...params.validFrom !== void 0 ? { validFrom: normalizedValidFrom } : {},
2692
+ ...params.validTo !== void 0 ? { validTo: normalizedValidTo } : {},
2693
+ ...params.project !== void 0 ? projectDetailValue(params.project) : {}
2694
+ }
2695
+ };
2696
+ }
2697
+ function projectDetailValue(project) {
2698
+ const trimmed = project.trim();
2699
+ return { project: trimmed.length > 0 ? trimmed : null };
2700
+ }
2701
+ function okOutcome(text, details, warnings = []) {
2702
+ return {
2703
+ text: formatMemoryToolOutcomeText(text, warnings),
2704
+ details: { ...details, ...buildMemoryToolWarningDetails(warnings) },
2705
+ failed: false
2706
+ };
2707
+ }
2708
+ function failedOutcome(text, details, warnings = []) {
2709
+ return {
2710
+ text: formatMemoryToolOutcomeText(text, warnings),
2711
+ details: { ...details, ...buildMemoryToolWarningDetails(warnings) },
2712
+ failed: true
2713
+ };
2714
+ }
2715
+ function parseDirectivePolarityParam(value) {
2716
+ if (value === void 0) {
2717
+ return void 0;
2718
+ }
2719
+ if (value === "abstain" || value === "proactive") {
2720
+ return value;
2721
+ }
2722
+ throw new Error(`Unsupported directive polarity "${value}".`);
2723
+ }
2724
+ function parseDirectiveTriggerParam(value) {
2725
+ if (value === void 0) {
2726
+ return void 0;
2727
+ }
2728
+ const trigger = parseDirectiveTrigger(value);
2729
+ if (!trigger) {
2730
+ throw new Error(`Unsupported directive trigger "${value}".`);
2731
+ }
2732
+ return trigger;
2733
+ }
2734
+
2735
+ // src/adapters/shared/recall-format.ts
2736
+ function formatUnifiedRecallResults(result) {
2737
+ const lines = [
2738
+ "Recall Route",
2739
+ `requested=${result.routing.requested} detected=${result.routing.detectedIntent} queried=${result.routing.queried.join(", ") || "none"}`,
2740
+ result.routing.reason,
2741
+ ""
2742
+ ];
2743
+ if (result.timeWindow) {
2744
+ lines.push("Resolved Time Window");
2745
+ lines.push(`${result.timeWindow.start} -> ${result.timeWindow.end} (${result.timeWindow.timezone}) from ${JSON.stringify(result.timeWindow.resolvedFrom)}`);
2746
+ lines.push("");
2747
+ }
2748
+ if (result.asOf) {
2749
+ lines.push("As Of");
2750
+ lines.push(result.asOf);
2751
+ lines.push("");
2752
+ }
2753
+ if (result.routing.queried.includes("procedures") || result.procedure || result.procedureCandidates.length > 0 || result.procedureNotices.length > 0) {
2754
+ appendProcedureMatches(lines, result);
2755
+ lines.push("");
2756
+ }
2757
+ const renderEntriesFirst = result.routing.detectedIntent === "historical_state";
2758
+ if (renderEntriesFirst) {
2759
+ appendEntryMatches(lines, result);
2760
+ lines.push("");
2761
+ appendClaimTransitions(lines, result);
2762
+ lines.push("");
2763
+ appendEpisodeMatches(lines, result);
2764
+ } else {
2765
+ appendEpisodeMatches(lines, result);
2766
+ lines.push("");
2767
+ appendEntryMatches(lines, result);
2768
+ lines.push("");
2769
+ appendClaimTransitions(lines, result);
2770
+ }
2771
+ if (recallResultHasTruncatedEntryPreviews(result)) {
2772
+ lines.push("");
2773
+ lines.push("Fetch Guidance");
2774
+ lines.push("One or more durable previews were truncated. Call agenr_fetch with id when exact stored wording is required.");
2775
+ }
2776
+ if (result.notices.length > 0) {
2777
+ lines.push("");
2778
+ lines.push("Notices");
2779
+ for (const notice of result.notices) {
2780
+ lines.push(`- ${notice}`);
2781
+ }
2782
+ }
2783
+ return lines.join("\n");
2784
+ }
2785
+ function appendProcedureMatches(lines, result) {
2786
+ lines.push("Procedure Matches");
2787
+ if (!result.procedure && result.procedureCandidates.length === 0) {
2788
+ lines.push("None.");
2789
+ } else {
2790
+ if (result.procedure) {
2791
+ appendCanonicalProcedure(lines, result.procedure, result.procedureCandidates);
2792
+ } else {
2793
+ lines.push("Canonical procedure: none.");
2794
+ }
2795
+ const additionalCandidates = result.procedureCandidates.filter((candidate) => candidate.procedure.id !== result.procedure?.id);
2796
+ if (additionalCandidates.length > 0) {
2797
+ lines.push("Other Candidates");
2798
+ for (const [index, candidate] of additionalCandidates.entries()) {
2799
+ lines.push(
2800
+ `${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)}`
2801
+ );
2802
+ }
2803
+ }
2804
+ }
2805
+ if (result.procedureNotices.length > 0) {
2806
+ lines.push("Procedure Notices");
2807
+ for (const notice of result.procedureNotices) {
2808
+ lines.push(`- ${notice}`);
2809
+ }
2810
+ }
2811
+ }
2812
+ function appendEntryMatches(lines, result) {
2813
+ lines.push("Durable Matches");
2814
+ if (result.projectedEntries.length === 0) {
2815
+ lines.push("None.");
2816
+ return;
2817
+ }
2818
+ for (const [familyIndex, family] of result.entryFamilies.entries()) {
2819
+ lines.push(
2820
+ 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}`
2821
+ );
2822
+ for (const [entryIndex, entry] of family.entries.entries()) {
2823
+ const preview = buildEntryRecallPreview(entry.recall.entry.content);
2824
+ lines.push(
2825
+ ` ${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)}`
2826
+ );
2827
+ lines.push(` ${preview.contentPreview}`);
2828
+ lines.push(` content_chars=${preview.contentChars} preview_truncated=${preview.previewTruncated ? "true" : "false"}`);
2829
+ lines.push(` freshness=${entry.freshness.label}`);
2830
+ const provenance = formatProjectedEntryProvenance(entry);
2831
+ if (provenance) {
2832
+ lines.push(` provenance=${provenance}`);
2833
+ }
2834
+ lines.push(` why_surfaced=${entry.whySurfaced.summary}`);
2835
+ }
2836
+ }
2837
+ }
2838
+ function appendEpisodeMatches(lines, result) {
2839
+ lines.push("Episode Matches");
2840
+ if (result.episodes.length === 0) {
2841
+ lines.push("None.");
2842
+ return;
2843
+ }
2844
+ for (const [index, episode] of result.episodes.entries()) {
2845
+ lines.push(
2846
+ `${index + 1}. ${episode.episode.id} | ${episode.episode.source} | ${episode.episode.startedAt} -> ${episode.episode.endedAt ?? episode.episode.startedAt} | score ${episode.score.toFixed(2)}`
2847
+ );
2848
+ lines.push(` ${index < 3 ? episode.episode.summary.trim() : truncate(episode.episode.summary.trim(), ENTRY_PREVIEW_MAX_CHARS)}`);
2849
+ lines.push(` why_matched=${describeEpisodeMatch(episode)}`);
2850
+ }
2851
+ }
2852
+ function appendCanonicalProcedure(lines, procedure, candidates) {
2853
+ const leadCandidate = candidates.find((candidate) => candidate.procedure.id === procedure.id);
2854
+ lines.push(
2855
+ leadCandidate ? `Canonical Procedure. ${procedure.procedure_key} | ${procedure.title} | score ${leadCandidate.score.toFixed(2)}` : `Canonical Procedure. ${procedure.procedure_key} | ${procedure.title}`
2856
+ );
2857
+ lines.push(` goal=${procedure.goal}`);
2858
+ appendLabeledList(lines, "when_to_use", procedure.when_to_use);
2859
+ appendLabeledList(lines, "when_not_to_use", procedure.when_not_to_use);
2860
+ appendLabeledList(lines, "prerequisites", procedure.prerequisites);
2861
+ lines.push(" steps");
2862
+ for (const [index, step] of procedure.steps.entries()) {
2863
+ lines.push(` ${index + 1}. [${step.kind}] ${step.instruction}`);
2864
+ const stepDetails = formatProcedureStepDetails(step);
2865
+ if (stepDetails.length > 0) {
2866
+ for (const detail of stepDetails) {
2867
+ lines.push(` ${detail}`);
2868
+ }
2869
+ }
2870
+ }
2871
+ appendLabeledList(lines, "verification", procedure.verification);
2872
+ appendLabeledList(lines, "failure_modes", procedure.failure_modes);
2873
+ lines.push(" sources");
2874
+ for (const source of procedure.sources) {
2875
+ lines.push(` - ${formatProcedureSource(source)}`);
2876
+ }
2877
+ }
2878
+ function appendClaimTransitions(lines, result) {
2879
+ lines.push("Claim Transitions");
2880
+ if (result.claimTransitions.length === 0) {
2881
+ lines.push("None.");
2882
+ return;
2883
+ }
2884
+ for (const [index, transition] of result.claimTransitions.entries()) {
2885
+ lines.push(
2886
+ `${index + 1}. family=${transition.claimKey ?? transition.familyKey} | slot_policy=${transition.slotPolicy}${transition.currentEntryId ? ` | current=${transition.currentEntryId}` : ""}${transition.priorEntryId ? ` | prior=${transition.priorEntryId}` : ""}`
2887
+ );
2888
+ lines.push(` ${transition.summary}`);
2889
+ if (transition.episodeContext) {
2890
+ lines.push(
2891
+ ` episode=${transition.episodeContext.episodeId} | ${transition.episodeContext.startedAt} -> ${transition.episodeContext.endedAt ?? transition.episodeContext.startedAt}`
2892
+ );
2893
+ lines.push(` ${truncate(transition.episodeContext.summary.trim(), ENTRY_PREVIEW_MAX_CHARS)}`);
2894
+ }
2895
+ }
2896
+ }
2897
+ function appendLabeledList(lines, label, values) {
2898
+ lines.push(` ${label}`);
2899
+ if (values.length === 0) {
2900
+ lines.push(" - none");
2901
+ return;
2902
+ }
2903
+ for (const value of values) {
2904
+ lines.push(` - ${value}`);
2905
+ }
2906
+ }
2907
+ function formatProcedureStepDetails(step) {
2908
+ switch (step.kind) {
2909
+ case "run_command":
2910
+ return [`command=${step.command}`];
2911
+ case "read_reference":
2912
+ return [`ref=${formatProcedureSource(step.ref)}`];
2913
+ case "inspect_state":
2914
+ return [step.target ? `target=${step.target}` : void 0, step.query ? `query=${step.query}` : void 0].filter(
2915
+ (value) => value !== void 0
2916
+ );
2917
+ case "edit_file":
2918
+ return [`path=${step.path}`, `edit=${step.edit}`];
2919
+ case "ask_user":
2920
+ return [`prompt=${step.prompt}`];
2921
+ case "invoke_tool":
2922
+ return [step.tool ? `tool=${step.tool}` : void 0, step.arguments ? `arguments=${JSON.stringify(step.arguments)}` : void 0].filter(
2923
+ (value) => value !== void 0
2924
+ );
2925
+ case "verify":
2926
+ return step.checks.map((check) => `check=${check}`);
2927
+ default:
2928
+ return [];
2929
+ }
2930
+ }
2931
+ function formatProcedureSource(source) {
2932
+ const parts = [source.kind, source.label, source.path, source.locator].filter((value) => Boolean(value && value.length > 0));
2933
+ return parts.join(" | ");
2934
+ }
2935
+ function describeEpisodeMatch(result) {
2936
+ if (result.scores.semantic > 0 && result.scores.temporal > 0) {
2937
+ return "Semantic match within the resolved time window.";
2938
+ }
2939
+ if (result.scores.semantic > 0) {
2940
+ return "Semantic match to the episode summary.";
2941
+ }
2942
+ if (result.scores.temporal > 0) {
2943
+ return "Session overlaps the resolved time window.";
2944
+ }
2945
+ return "Matched episodic recall ranking.";
2946
+ }
2947
+ function formatClaimStatus(status) {
2948
+ return status === "no_key" ? "no-key" : status;
2949
+ }
2950
+ function formatProjectedEntryProvenance(entry) {
2951
+ const parts = [
2952
+ entry.provenance.supersededById ? `superseded_by=${entry.provenance.supersededById}` : void 0,
2953
+ entry.provenance.supersessionKind ? `kind=${entry.provenance.supersessionKind}` : void 0,
2954
+ entry.provenance.supersessionReason ? `reason=${truncate(entry.provenance.supersessionReason, 120)}` : void 0,
2955
+ entry.provenance.supportSourceKind ? `support=${entry.provenance.supportSourceKind}` : void 0,
2956
+ entry.provenance.supportMode ? `support_mode=${entry.provenance.supportMode}` : void 0,
2957
+ entry.provenance.supportObservedAt ? `observed=${entry.provenance.supportObservedAt}` : void 0,
2958
+ entry.provenance.supportLocator ? `locator=${truncate(entry.provenance.supportLocator, 120)}` : void 0
2959
+ ].filter((value) => value !== void 0);
2960
+ return parts.join(" | ");
2961
+ }
2962
+
2963
+ export {
2964
+ logSessionMemoryTriggerResult,
2965
+ routeSessionMemoryTriggerSafely,
2966
+ createSessionMemoryTriggerRouter,
2967
+ resolveSessionIdentityKey,
2968
+ createSessionStartTracker,
2969
+ createSessionLifecycleIntakeTracker,
2970
+ createCompactionPromptTracker,
2971
+ normalizeOptionalBoolean,
2972
+ normalizeOptionalPositiveInteger,
2973
+ normalizePluginInjectionMemoryPolicyConfig,
2974
+ mergeInjectionContent,
2975
+ formatAgenrSessionStartRecall,
2976
+ resolveSessionStartPolicy,
2977
+ resolveBeforeTurnPolicy,
2978
+ resolveWorkingContextGate,
2979
+ extractRecentTurnsFromMessages,
2980
+ normalizePromptText,
2981
+ scheduleGuardedEpisodeWrite,
2982
+ isPluginEpisodeWriteEnabled,
2983
+ resolveAgenrFeatureFlags,
2984
+ resolveCompactionPromptContext,
2985
+ embedEpisodeSummaryWithinBudget,
2986
+ EPISODE_SUMMARY_TIMEOUT_MS,
2987
+ writeBoundedSingleTranscriptEpisode,
2988
+ createDeadlineAwareEpisodeSummaryLlm,
2989
+ buildSessionFileSourceRef,
2990
+ buildCompactionSourceRef,
2991
+ buildSessionEndSourceRef,
2992
+ maybeRunLightDream,
2993
+ buildClaimExtractionRuntime,
2994
+ createClaimExtractionFromAgenrConfig,
2995
+ createEmbedQuery,
2996
+ composeHostPluginServices,
2997
+ createHostMemoryServices,
2998
+ buildRecallToolServices,
2999
+ STORE_TOOL_PARAMETERS,
3000
+ RECALL_TOOL_PARAMETERS,
3001
+ UPDATE_TOOL_PARAMETERS,
3002
+ FETCH_TOOL_PARAMETERS,
3003
+ parseStoreToolParams,
3004
+ parseRecallToolParams,
3005
+ parseUpdateToolParams,
3006
+ parseFetchToolParams,
3007
+ runStoreMemoryTool,
3008
+ runRecallMemoryTool,
3009
+ runFetchMemoryTool,
3010
+ runUpdateMemoryTool,
3011
+ formatUnifiedRecallResults
3012
+ };