agenr 3.0.0 → 3.1.0

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.
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  CLOSE_EVENT_HISTORY_LIMIT,
3
3
  EPISODE_SUMMARY_TIMEOUT_MS,
4
+ FETCH_TOOL_PARAMETERS,
4
5
  RECALL_TOOL_PARAMETERS,
5
6
  SESSION_LINEAGE_REASONS,
6
7
  STORE_TOOL_PARAMETERS,
7
8
  UPDATE_TOOL_PARAMETERS,
8
9
  WORKING_CANDIDATE_PROMOTION_STATUSES,
9
- asRecord,
10
10
  buildRecallToolServices,
11
11
  composeHostPluginServices,
12
12
  createClaimExtractionFromAgenrConfig,
@@ -15,8 +15,6 @@ import {
15
15
  embedEpisodeSummaryWithinBudget,
16
16
  extractRecentTurnsFromMessages,
17
17
  formatAgenrSessionStartRecall,
18
- formatErrorMessage,
19
- formatTargetSelector,
20
18
  formatUnifiedRecallResults,
21
19
  isCloseManagedStatus,
22
20
  isModelVisibleOperationType,
@@ -28,6 +26,7 @@ import {
28
26
  normalizeOptionalString,
29
27
  normalizePluginInjectionMemoryPolicyConfig,
30
28
  normalizePromptText,
29
+ parseFetchToolParams,
31
30
  parseRecallToolParams,
32
31
  parseStoreToolParams,
33
32
  parseUpdateToolParams,
@@ -35,31 +34,36 @@ import {
35
34
  resolveSessionIdentityKey,
36
35
  resolveSessionStartPolicy,
37
36
  resolveWorkingContextGate,
37
+ runFetchMemoryTool,
38
38
  runRecallMemoryTool,
39
39
  runSessionStart,
40
40
  runStoreMemoryTool,
41
41
  runUpdateMemoryTool,
42
- sanitizeUpdateToolParams,
43
42
  writeBoundedSingleTranscriptEpisode
44
- } from "../../chunk-MYZ2CWY6.js";
43
+ } from "../../chunk-E2DHUFZK.js";
45
44
  import {
46
- createSingleTranscriptDiscoveryPort
47
- } from "../../chunk-LAXNNWHM.js";
45
+ asRecord,
46
+ createSingleTranscriptDiscoveryPort,
47
+ formatErrorMessage,
48
+ formatTargetSelector,
49
+ sanitizeFetchToolParams,
50
+ sanitizeUpdateToolParams
51
+ } from "../../chunk-EEEL53X4.js";
48
52
  import {
49
- buildRecallToolDetails,
50
53
  formatAgenrBeforeTurnRecall,
51
54
  runBeforeTurn
52
- } from "../../chunk-575MUIW5.js";
55
+ } from "../../chunk-V5CDMHRN.js";
53
56
  import {
54
57
  AGENR_FEATURE_FLAG_KEYS,
55
58
  DEFAULT_AGENR_FEATURE_FLAGS,
59
+ buildRecallToolDetails,
56
60
  createLlmClient,
57
61
  isRecord,
58
62
  readOptionalFiniteNumber,
59
63
  readOptionalTrimmedString,
60
64
  resolveLlmApiKey,
61
65
  resolveModel
62
- } from "../../chunk-ELR2HSVC.js";
66
+ } from "../../chunk-NNO2V4GH.js";
63
67
  import "../../chunk-5LADPJ4C.js";
64
68
 
65
69
  // src/adapters/skeln/config.ts
@@ -426,6 +430,7 @@ function buildAgenrSkelnMemoryPromptSection() {
426
430
  "## Memory Recall",
427
431
  "Before answering anything about prior work, decisions, preferences, people, dates, unfinished work, or past sessions, call agenr_recall first. Session-start recall is automatic, and conservative before-turn recall may also appear as injected background context; use agenr_recall mid-session when you need context you do not already have.",
428
432
  "agenr_recall supports exact fact recall plus historical and episodic recall behind one tool: use mode=entries for exact facts, decisions, thresholds, and versions; use mode=auto for prior-state questions like what was the previous approach, what did we use before, or what changed from X to Y; use mode=episodes when you explicitly want session narrative recall.",
433
+ "agenr_recall returns truncated entry previews with ids, scores, and preview_truncated flags. Call agenr_fetch with id when preview_truncated=true or exact stored wording is required.",
429
434
  "When Agenr injects memory automatically, treat it as non-user background context and use it silently when relevant rather than forcing it into the reply.",
430
435
  "Use agenr_store for durable memory, not for logging. Store only the durable takeaway, standing rule, preference, risk, lesson, or relationship - not progress logs or data already canonical elsewhere.",
431
436
  "Use agenr_update to correct metadata on an existing entry. Use agenr_store with supersedes for substantive content replacement.",
@@ -1087,10 +1092,16 @@ function deriveSkelnSessionIdFromFilePath(filePath) {
1087
1092
  }
1088
1093
 
1089
1094
  // src/adapters/skeln/episode/bounded-session-episode.ts
1095
+ function resolveSkelnSessionEpisodeTarget(context) {
1096
+ return {
1097
+ sessionId: String(context.sessionManager.getSessionId()),
1098
+ sessionFile: resolveSessionFile(context)
1099
+ };
1100
+ }
1090
1101
  async function writeSkelnBoundedSessionEpisode(params) {
1091
1102
  const logger = params.logger ?? console;
1092
- const sessionFile = resolveSessionFile(params.context);
1093
- const sessionId = String(params.context.sessionManager.getSessionId());
1103
+ const sessionFile = params.target.sessionFile;
1104
+ const sessionId = params.target.sessionId;
1094
1105
  const summaryDeadlineMs = Date.now() + EPISODE_SUMMARY_TIMEOUT_MS;
1095
1106
  if (!sessionFile) {
1096
1107
  logger.info(`[agenr] ${params.actionLabel} skipped for ${params.skipDetails} reason=no_session_file`);
@@ -1153,20 +1164,58 @@ var SKELN_PHASE4_SHUTDOWN_EPISODE_ACTIVITY_THRESHOLD = {
1153
1164
  minDurationMs: 20 * 60 * 1e3
1154
1165
  };
1155
1166
  async function writeSkelnShutdownEpisode(params) {
1156
- const sessionId = String(params.context.sessionManager.getSessionId());
1157
1167
  await writeSkelnBoundedSessionEpisode({
1158
- context: params.context,
1168
+ target: params.target,
1159
1169
  services: params.services,
1160
1170
  logger: params.logger,
1161
1171
  actionLabel: "skeln shutdown episode write",
1162
1172
  genVersion: SKELN_EPISODE_GENERATOR_VERSION,
1163
1173
  activityThreshold: SKELN_PHASE4_SHUTDOWN_EPISODE_ACTIVITY_THRESHOLD,
1164
1174
  buildSourceRef: (sessionFile) => sessionFile,
1165
- logContext: `session=${sessionId} key=skeln:${sessionId}`,
1166
- skipDetails: `session=${sessionId}`
1175
+ logContext: `session=${params.target.sessionId} key=skeln:${params.target.sessionId}`,
1176
+ skipDetails: `session=${params.target.sessionId}`
1167
1177
  });
1168
1178
  }
1169
1179
 
1180
+ // src/adapters/skeln/episode/shutdown-episode-write.ts
1181
+ function buildSkelnSessionShutdownEpisodeWork(params) {
1182
+ const target = resolveSkelnSessionEpisodeTarget(params.context);
1183
+ const shutdownWork = params.event.reason === "quit" ? writeScopedSkelnShutdownEpisode(params.servicesPromise, target, params.logger).finally(() => closeSkelnServicesAfterShutdown(params.servicesPromise)) : writeScopedSkelnShutdownEpisode(params.servicesPromise, target, params.logger);
1184
+ return shutdownWork.catch((error) => {
1185
+ logSkelnShutdownEpisodeFailure(error, params.logger);
1186
+ });
1187
+ }
1188
+ function scheduleSkelnSessionShutdownEpisodeWrite(params) {
1189
+ const work = buildSkelnSessionShutdownEpisodeWork(params);
1190
+ if (params.event.reason === "quit" && params.event.deferWork) {
1191
+ params.event.deferWork(work);
1192
+ return Promise.resolve();
1193
+ }
1194
+ if (params.event.reason === "quit") {
1195
+ return work;
1196
+ }
1197
+ void work;
1198
+ return Promise.resolve();
1199
+ }
1200
+ function logSkelnShutdownEpisodeFailure(error, logger) {
1201
+ const log = logger ?? console;
1202
+ log.warn(`[agenr] skeln shutdown episode failed: ${formatErrorMessage(error)}`);
1203
+ }
1204
+ async function closeSkelnServicesAfterShutdown(servicesPromise) {
1205
+ try {
1206
+ const services = await servicesPromise;
1207
+ await services.close();
1208
+ } catch {
1209
+ }
1210
+ }
1211
+ async function writeScopedSkelnShutdownEpisode(servicesPromise, target, logger) {
1212
+ const services = await servicesPromise;
1213
+ if (!services.capabilities.shutdownEpisodes) {
1214
+ return;
1215
+ }
1216
+ await writeSkelnShutdownEpisode({ target, services, logger });
1217
+ }
1218
+
1170
1219
  // src/app/features/resolve.ts
1171
1220
  function resolveAgenrFeatureFlags(features) {
1172
1221
  const resolved = { ...DEFAULT_AGENR_FEATURE_FLAGS };
@@ -2525,6 +2574,109 @@ function createSkelnSessionScopeTracker() {
2525
2574
  };
2526
2575
  }
2527
2576
 
2577
+ // src/adapters/shared/param-readers.ts
2578
+ function readStringParam(params, key, options = {}) {
2579
+ const value = params[key];
2580
+ if (value === void 0 || value === null) {
2581
+ if (options.required) {
2582
+ throw new Error(`${options.label ?? key} is required.`);
2583
+ }
2584
+ return void 0;
2585
+ }
2586
+ if (typeof value !== "string") {
2587
+ throw new Error(`${options.label ?? key} must be a string.`);
2588
+ }
2589
+ const normalized = options.trim === false ? value : value.trim();
2590
+ if (options.required && normalized.length === 0) {
2591
+ throw new Error(`${options.label ?? key} is required.`);
2592
+ }
2593
+ return normalized.length > 0 || options.trim === false ? normalized : void 0;
2594
+ }
2595
+ function readNumberParam(params, key, options = {}) {
2596
+ const value = params[key];
2597
+ if (value === void 0 || value === null) {
2598
+ return void 0;
2599
+ }
2600
+ if (typeof value !== "number" || !Number.isFinite(value)) {
2601
+ throw new Error(`${key} must be a number.`);
2602
+ }
2603
+ if (options.integer && !Number.isInteger(value)) {
2604
+ throw new Error(`${key} must be an integer.`);
2605
+ }
2606
+ if (options.strict && value < 0) {
2607
+ throw new Error(`${key} must be non-negative.`);
2608
+ }
2609
+ return value;
2610
+ }
2611
+ function readStringArrayParam(params, key) {
2612
+ const value = params[key];
2613
+ if (value === void 0 || value === null) {
2614
+ return void 0;
2615
+ }
2616
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
2617
+ throw new Error(`${key} must be an array of strings.`);
2618
+ }
2619
+ return value;
2620
+ }
2621
+
2622
+ // src/adapters/skeln/tools/shared.ts
2623
+ var SKELN_PARAM_READER = {
2624
+ readString: readStringParam,
2625
+ readNumber: readNumberParam,
2626
+ readStringArray: readStringArrayParam
2627
+ };
2628
+ function toolSchema(value) {
2629
+ return value;
2630
+ }
2631
+ function textToolResult(text, details) {
2632
+ return {
2633
+ content: [{ type: "text", text }],
2634
+ details
2635
+ };
2636
+ }
2637
+ function toSkelnToolResult(outcome) {
2638
+ return textToolResult(outcome.text, outcome.details);
2639
+ }
2640
+ function toolFailureResult(error) {
2641
+ return textToolResult(formatErrorMessage(error), {
2642
+ status: "failed"
2643
+ });
2644
+ }
2645
+
2646
+ // src/adapters/skeln/tools/fetch.ts
2647
+ function registerAgenrSkelnFetchTool(skeln, servicesPromise, resolveScope) {
2648
+ skeln.registerTool({
2649
+ name: "agenr_fetch",
2650
+ label: "Agenr Fetch",
2651
+ description: "Fetch the full body and metadata for one durable memory entry by id or subject.",
2652
+ promptSnippet: "Use agenr_fetch after agenr_recall when you need the full entry body for an id shown in recall results.",
2653
+ promptGuidelines: [
2654
+ "Provide exactly one target selector: id or subject.",
2655
+ "Prefer id from agenr_recall when preview_truncated=true or when exact wording matters."
2656
+ ],
2657
+ parameters: toolSchema(FETCH_TOOL_PARAMETERS),
2658
+ execute: async (_toolCallId, rawParams, _signal, _onUpdate, context) => {
2659
+ try {
2660
+ const params = parseFetchToolParams(rawParams, SKELN_PARAM_READER);
2661
+ const [services, scope] = await Promise.all([servicesPromise, resolveScope(context)]);
2662
+ const outcome = await runFetchMemoryTool(params, services, {
2663
+ extraDetails: { sessionKey: scope.sessionKey }
2664
+ });
2665
+ return toSkelnToolResult({
2666
+ ...outcome,
2667
+ details: {
2668
+ ...outcome.details,
2669
+ target: formatTargetSelector(params.id, params.subject),
2670
+ sanitized: sanitizeFetchToolParams(params)
2671
+ }
2672
+ });
2673
+ } catch (error) {
2674
+ return toolFailureResult(error);
2675
+ }
2676
+ }
2677
+ });
2678
+ }
2679
+
2528
2680
  // src/adapters/shared/goal-tool-presentations.ts
2529
2681
  var COMPLETION_BUDGET_REPORT = "Goal achieved. Report final usage from this tool result's structured goal fields. If `goal.tokenBudget` is present, include token usage from `goal.tokensUsed` and `goal.tokenBudget`. If `goal.timeUsedSeconds` is greater than 0, summarize elapsed time in a concise, human-friendly form appropriate to the response language.";
2530
2682
  function toGoalToolGoal(workingSet) {
@@ -2707,75 +2859,6 @@ function goalFailure(code, message, details) {
2707
2859
  };
2708
2860
  }
2709
2861
 
2710
- // src/adapters/shared/param-readers.ts
2711
- function readStringParam(params, key, options = {}) {
2712
- const value = params[key];
2713
- if (value === void 0 || value === null) {
2714
- if (options.required) {
2715
- throw new Error(`${options.label ?? key} is required.`);
2716
- }
2717
- return void 0;
2718
- }
2719
- if (typeof value !== "string") {
2720
- throw new Error(`${options.label ?? key} must be a string.`);
2721
- }
2722
- const normalized = options.trim === false ? value : value.trim();
2723
- if (options.required && normalized.length === 0) {
2724
- throw new Error(`${options.label ?? key} is required.`);
2725
- }
2726
- return normalized.length > 0 || options.trim === false ? normalized : void 0;
2727
- }
2728
- function readNumberParam(params, key, options = {}) {
2729
- const value = params[key];
2730
- if (value === void 0 || value === null) {
2731
- return void 0;
2732
- }
2733
- if (typeof value !== "number" || !Number.isFinite(value)) {
2734
- throw new Error(`${key} must be a number.`);
2735
- }
2736
- if (options.integer && !Number.isInteger(value)) {
2737
- throw new Error(`${key} must be an integer.`);
2738
- }
2739
- if (options.strict && value < 0) {
2740
- throw new Error(`${key} must be non-negative.`);
2741
- }
2742
- return value;
2743
- }
2744
- function readStringArrayParam(params, key) {
2745
- const value = params[key];
2746
- if (value === void 0 || value === null) {
2747
- return void 0;
2748
- }
2749
- if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
2750
- throw new Error(`${key} must be an array of strings.`);
2751
- }
2752
- return value;
2753
- }
2754
-
2755
- // src/adapters/skeln/tools/shared.ts
2756
- var SKELN_PARAM_READER = {
2757
- readString: readStringParam,
2758
- readNumber: readNumberParam,
2759
- readStringArray: readStringArrayParam
2760
- };
2761
- function toolSchema(value) {
2762
- return value;
2763
- }
2764
- function textToolResult(text, details) {
2765
- return {
2766
- content: [{ type: "text", text }],
2767
- details
2768
- };
2769
- }
2770
- function toSkelnToolResult(outcome) {
2771
- return textToolResult(outcome.text, outcome.details);
2772
- }
2773
- function toolFailureResult(error) {
2774
- return textToolResult(formatErrorMessage(error), {
2775
- status: "failed"
2776
- });
2777
- }
2778
-
2779
2862
  // src/adapters/skeln/tools/goal.ts
2780
2863
  function registerAgenrSkelnGoalAliasTools(skeln, servicesPromise, resolveScope) {
2781
2864
  registerGoalAliasTool(skeln, servicesPromise, resolveScope, {
@@ -3614,6 +3697,7 @@ function registerAgenrSkelnWorkTool(skeln, servicesPromise, resolveScope) {
3614
3697
  function registerAgenrSkelnTools(skeln, servicesPromise, resolveScope) {
3615
3698
  registerAgenrSkelnStoreTool(skeln, servicesPromise, resolveScope);
3616
3699
  registerAgenrSkelnRecallTool(skeln, servicesPromise, resolveScope);
3700
+ registerAgenrSkelnFetchTool(skeln, servicesPromise, resolveScope);
3617
3701
  registerAgenrSkelnUpdateTool(skeln, servicesPromise, resolveScope);
3618
3702
  registerAgenrSkelnWorkTool(skeln, servicesPromise, resolveScope);
3619
3703
  registerAgenrSkelnGoalAliasTools(skeln, servicesPromise, resolveScope);
@@ -3630,28 +3714,28 @@ function scheduleSkelnGoalCloseEpisodePromotion(params) {
3630
3714
  if (!pendingEpisodic) {
3631
3715
  return;
3632
3716
  }
3717
+ const target = resolveSkelnSessionEpisodeTarget(params.context);
3633
3718
  void writeSkelnGoalCloseEpisode({
3634
- context: params.context,
3719
+ target,
3635
3720
  services: params.services,
3636
3721
  workingSetId: params.closeResult.workingSet.id,
3637
3722
  logger: params.logger
3638
3723
  }).catch((error) => {
3639
3724
  const logger = params.logger ?? console;
3640
- logger.warn(`[agenr] skeln goal close episode promotion failed: ${error instanceof Error ? error.message : String(error)}`);
3725
+ logger.warn(`[agenr] skeln goal close episode promotion failed: ${formatErrorMessage(error)}`);
3641
3726
  });
3642
3727
  }
3643
3728
  async function writeSkelnGoalCloseEpisode(params) {
3644
- const sessionId = String(params.context.sessionManager.getSessionId());
3645
3729
  await writeSkelnBoundedSessionEpisode({
3646
- context: params.context,
3730
+ target: params.target,
3647
3731
  services: params.services,
3648
3732
  logger: params.logger,
3649
3733
  actionLabel: "skeln goal close episode promotion",
3650
3734
  genVersion: SKELN_GOAL_CLOSE_EPISODE_GENERATOR_VERSION,
3651
3735
  activityThreshold: SKELN_GOAL_CLOSE_EPISODE_ACTIVITY_THRESHOLD,
3652
3736
  buildSourceRef: (sessionFile) => `${sessionFile}#working_set:${params.workingSetId}`,
3653
- logContext: `session=${sessionId} workingSet=${params.workingSetId}`,
3654
- skipDetails: `session=${sessionId} workingSet=${params.workingSetId}`
3737
+ logContext: `session=${params.target.sessionId} workingSet=${params.workingSetId}`,
3738
+ skipDetails: `session=${params.target.sessionId} workingSet=${params.workingSetId}`
3655
3739
  });
3656
3740
  }
3657
3741
 
@@ -3805,16 +3889,8 @@ function registerAgenrSkelnSessionMemoryHooks(skeln, scopeTracker, servicesPromi
3805
3889
  }
3806
3890
  async function handleSkelnSessionShutdown(servicesPromise, scopeTracker, resolveScope, event, context) {
3807
3891
  await routeScopedSessionMemoryTrigger(servicesPromise, resolveScope, context, (scope) => buildSkelnSessionShutdownTriggerEvent(scope, event));
3808
- await writeScopedSkelnShutdownEpisode(servicesPromise, context);
3809
3892
  clearTrackedSkelnScope(scopeTracker, context);
3810
- if (event.reason !== "quit") {
3811
- return;
3812
- }
3813
- try {
3814
- const services = await servicesPromise;
3815
- await services.close();
3816
- } catch {
3817
- }
3893
+ await scheduleSkelnSessionShutdownEpisodeWrite({ event, context, servicesPromise });
3818
3894
  }
3819
3895
  function registerAgenrSkelnSubagentFindingHooks(skeln, servicesPromise, resolveScope) {
3820
3896
  skeln.on("tool_result", async (event, context) => {
@@ -3831,17 +3907,6 @@ async function routeScopedSessionMemoryTrigger(servicesPromise, resolveScope, co
3831
3907
  console.warn(`[agenr] session-memory trigger failed: ${formatErrorMessage(error)}`);
3832
3908
  }
3833
3909
  }
3834
- async function writeScopedSkelnShutdownEpisode(servicesPromise, context) {
3835
- try {
3836
- const services = await servicesPromise;
3837
- if (!services.capabilities.shutdownEpisodes) {
3838
- return;
3839
- }
3840
- await writeSkelnShutdownEpisode({ context, services });
3841
- } catch (error) {
3842
- console.warn(`[agenr] skeln shutdown episode failed: ${formatErrorMessage(error)}`);
3843
- }
3844
- }
3845
3910
  async function resolveCurrentSkelnSessionScope(context, scopeTracker, options) {
3846
3911
  const sessionId = String(context.sessionManager.getSessionId());
3847
3912
  const tracked = scopeTracker.getSessionScope(sessionId);
@@ -3886,7 +3951,7 @@ function registerAgenrSkelnFailureBoundary(skeln) {
3886
3951
  });
3887
3952
  }
3888
3953
  function isAgenrToolName(toolName) {
3889
- return toolName === "agenr_store" || toolName === "agenr_recall" || toolName === "agenr_update" || toolName === "agenr_work" || toolName === "get_goal" || toolName === "create_goal" || toolName === "update_goal";
3954
+ return toolName === "agenr_store" || toolName === "agenr_recall" || toolName === "agenr_fetch" || toolName === "agenr_update" || toolName === "agenr_work" || toolName === "get_goal" || toolName === "create_goal" || toolName === "update_goal";
3890
3955
  }
3891
3956
  function isFailedAgenrToolDetails(details) {
3892
3957
  return typeof details === "object" && details !== null && "status" in details && details.status === "failed";