@joshuaswarren/openclaw-engram 9.0.8 → 9.0.10

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.
package/dist/index.js CHANGED
@@ -74,7 +74,8 @@ var VALID_MEMORY_CATEGORIES = /* @__PURE__ */ new Set([
74
74
  "principle",
75
75
  "commitment",
76
76
  "moment",
77
- "skill"
77
+ "skill",
78
+ "rule"
78
79
  ]);
79
80
  var DEFAULT_BEHAVIOR_LOOP_PROTECTED_PARAMS = [
80
81
  "maxMemoryTokens",
@@ -472,6 +473,7 @@ function parseConfig(raw) {
472
473
  delinearizeEnabled: cfg.delinearizeEnabled !== false,
473
474
  recallConfidenceGateEnabled: cfg.recallConfidenceGateEnabled === true,
474
475
  recallConfidenceGateThreshold: typeof cfg.recallConfidenceGateThreshold === "number" ? Math.max(0, Math.min(1, cfg.recallConfidenceGateThreshold)) : 0.12,
476
+ causalRuleExtractionEnabled: cfg.causalRuleExtractionEnabled === true,
475
477
  graphLateralInhibitionEnabled: cfg.graphLateralInhibitionEnabled !== false,
476
478
  graphLateralInhibitionBeta: typeof cfg.graphLateralInhibitionBeta === "number" ? Math.max(0, Math.min(1, cfg.graphLateralInhibitionBeta)) : 0.15,
477
479
  graphLateralInhibitionTopM: typeof cfg.graphLateralInhibitionTopM === "number" ? Math.max(0, Math.round(cfg.graphLateralInhibitionTopM)) : 7,
@@ -1904,7 +1906,7 @@ function parseMemoryActionEligibilityContext(value) {
1904
1906
  };
1905
1907
  }
1906
1908
  var ExtractedFactSchema = z.object({
1907
- category: z.enum(["fact", "preference", "correction", "entity", "decision", "relationship", "principle", "commitment", "moment", "skill"]),
1909
+ category: z.enum(["fact", "preference", "correction", "entity", "decision", "relationship", "principle", "commitment", "moment", "skill", "rule"]),
1908
1910
  content: z.string().describe("The memory content \u2014 a clear, standalone statement"),
1909
1911
  confidence: z.number().min(0).max(1).describe("How confident are you this is correct (0-1)"),
1910
1912
  tags: z.array(z.string()).describe("Relevant tags for categorization"),
@@ -2936,12 +2938,13 @@ Memory categories:
2936
2938
  - principle: Durable rules, values, or operating beliefs (e.g., "never use Chat Completions API")
2937
2939
  - commitment: Promises, obligations, or deadlines (e.g., "deploy by Friday", "call accountant Monday")
2938
2940
  - moment: Emotionally significant events or milestones (e.g., "first successful deployment of engram")
2939
- - skill: Capabilities the user or agent has demonstrated (e.g., "user is proficient with Kubernetes")
2941
+ - skill: Capabilities the user or agent has demonstrated (e.g., "user is proficient with Kubernetes")${this.config.causalRuleExtractionEnabled ? `
2942
+ - rule: Causal rules discovered through experience (format: "IF <condition> THEN <action/outcome>", e.g., "IF Shopify API returns 401 THEN the admin token is missing read_products scope")` : ""}
2940
2943
 
2941
2944
  Rules:
2942
2945
  - Only extract genuinely NEW information worth remembering across sessions
2943
2946
  - Skip transient task details (file paths being edited, current errors, etc.)
2944
- - Priority: corrections > principles > preferences > commitments > decisions > relationships > entities > moments > skills > facts
2947
+ - Priority: corrections > principles${this.config.causalRuleExtractionEnabled ? " > rules" : ""} > preferences > commitments > decisions > relationships > entities > moments > skills > facts
2945
2948
  - Corrections (user saying "actually, don't do X" or "I prefer Y") get highest confidence
2946
2949
  - Each fact should be a standalone, self-contained statement
2947
2950
  - Entity references should use normalized names (lowercase, hyphenated: "jane-doe", "acme-corp")
@@ -3034,7 +3037,8 @@ Actions:
3034
3037
 
3035
3038
  Also:
3036
3039
  - Suggest profile updates based on patterns across memories
3037
- - Identify entity updates for entity tracking`
3040
+ - Identify entity updates for entity tracking${this.config.causalRuleExtractionEnabled ? `
3041
+ - When merging or updating memories, look for IF\u2192THEN causal patterns. If a memory describes "X failed/succeeded because Y" or "doing X led to Y", rewrite its content to make the causal rule explicit in the form "IF <condition> THEN <action/outcome>".` : ""}`
3038
3042
  },
3039
3043
  {
3040
3044
  role: "user",
@@ -3080,7 +3084,8 @@ Actions:
3080
3084
 
3081
3085
  Also:
3082
3086
  - Suggest profile updates based on patterns across memories
3083
- - Identify entity updates for entity tracking
3087
+ - Identify entity updates for entity tracking${this.config.causalRuleExtractionEnabled ? `
3088
+ - When merging or updating memories, look for IF\u2192THEN causal patterns. If a memory describes "X failed/succeeded because Y" or "doing X led to Y", rewrite its content to make the causal rule explicit in the form "IF <condition> THEN <action/outcome>".` : ""}
3084
3089
 
3085
3090
  Current behavioral profile:
3086
3091
  ${currentProfile || "(empty)"}
@@ -3198,7 +3203,8 @@ Actions:
3198
3203
 
3199
3204
  Also:
3200
3205
  - Suggest profile updates based on patterns across memories
3201
- - Identify entity updates for entity tracking
3206
+ - Identify entity updates for entity tracking${this.config.causalRuleExtractionEnabled ? `
3207
+ - When merging or updating memories, look for IF\u2192THEN causal patterns. If a memory describes "X failed/succeeded because Y" or "doing X led to Y", rewrite its content to make the causal rule explicit in the form "IF <condition> THEN <action/outcome>".` : ""}
3202
3208
 
3203
3209
  Current behavioral profile:
3204
3210
  ${currentProfile || "(empty)"}
@@ -3927,6 +3933,8 @@ var CATEGORY_BOOSTS = {
3927
3933
  // Corrections are always important
3928
3934
  principle: 0.12,
3929
3935
  // Durable rules/values
3936
+ rule: 0.11,
3937
+ // Causal IF→THEN rules
3930
3938
  preference: 0.1,
3931
3939
  // User preferences matter
3932
3940
  commitment: 0.1,
@@ -12528,6 +12536,9 @@ function serializeBoxFrontmatter(fm) {
12528
12536
  ];
12529
12537
  if (fm.sessionKey) lines.push(`sessionKey: ${fm.sessionKey}`);
12530
12538
  if (fm.traceId) lines.push(`traceId: ${fm.traceId}`);
12539
+ if (fm.goal) lines.push(`goal: ${fm.goal.replace(/[\r\n]+/g, " ")}`);
12540
+ if (fm.toolsUsed?.length) lines.push(`toolsUsed: [${fm.toolsUsed.map((t) => `"${t}"`).join(", ")}]`);
12541
+ if (fm.outcome) lines.push(`outcome: ${fm.outcome}`);
12531
12542
  lines.push("---");
12532
12543
  return lines.join("\n");
12533
12544
  }
@@ -12547,6 +12558,7 @@ function parseBoxFrontmatter(raw) {
12547
12558
  if (!m) return [];
12548
12559
  return m[1].split(",").map((s) => s.trim().replace(/^"|"$/g, "")).filter(Boolean);
12549
12560
  };
12561
+ const outcome = fm.outcome;
12550
12562
  return {
12551
12563
  id: fm.id ?? "",
12552
12564
  memoryKind: "box",
@@ -12556,7 +12568,10 @@ function parseBoxFrontmatter(raw) {
12556
12568
  sessionKey: fm.sessionKey,
12557
12569
  topics: parseArray(fm.topics),
12558
12570
  memoryIds: parseArray(fm.memoryIds),
12559
- traceId: fm.traceId
12571
+ traceId: fm.traceId,
12572
+ goal: fm.goal || void 0,
12573
+ toolsUsed: fm.toolsUsed ? parseArray(fm.toolsUsed) : void 0,
12574
+ outcome: outcome && ["success", "failure", "partial", "unknown"].includes(outcome) ? outcome : void 0
12560
12575
  };
12561
12576
  }
12562
12577
  var BoxBuilder = class {
@@ -12642,6 +12657,10 @@ var BoxBuilder = class {
12642
12657
  const topicSet = /* @__PURE__ */ new Set([...this.openBox.topics, ...newTopics]);
12643
12658
  this.openBox.topics = [...topicSet];
12644
12659
  this.openBox.memoryIds.push(...event.memoryIds);
12660
+ if (event.toolsUsed?.length) {
12661
+ const toolSet = /* @__PURE__ */ new Set([...this.openBox.toolsUsed ?? [], ...event.toolsUsed]);
12662
+ this.openBox.toolsUsed = [...toolSet];
12663
+ }
12645
12664
  await this.sealCurrent("max_memories");
12646
12665
  } else if (topicShifted) {
12647
12666
  await this.sealCurrent("topic_shift");
@@ -12656,6 +12675,10 @@ var BoxBuilder = class {
12656
12675
  const topicSet = /* @__PURE__ */ new Set([...this.openBox.topics, ...newTopics]);
12657
12676
  this.openBox.topics = [...topicSet];
12658
12677
  this.openBox.lastActivityAt = now.toISOString();
12678
+ if (event.toolsUsed?.length) {
12679
+ const toolSet = /* @__PURE__ */ new Set([...this.openBox.toolsUsed ?? [], ...event.toolsUsed]);
12680
+ this.openBox.toolsUsed = [...toolSet];
12681
+ }
12659
12682
  await this.saveOpenBox();
12660
12683
  }
12661
12684
  } else {
@@ -12673,7 +12696,9 @@ var BoxBuilder = class {
12673
12696
  createdAt: ts,
12674
12697
  lastActivityAt: ts,
12675
12698
  topics: event.topics.filter(Boolean),
12676
- memoryIds: [...event.memoryIds]
12699
+ memoryIds: [...event.memoryIds],
12700
+ goal: event.goal,
12701
+ toolsUsed: event.toolsUsed?.length ? [...event.toolsUsed] : void 0
12677
12702
  };
12678
12703
  }
12679
12704
  /**
@@ -12705,7 +12730,10 @@ var BoxBuilder = class {
12705
12730
  sealReason: reason,
12706
12731
  topics: box.topics,
12707
12732
  memoryIds: box.memoryIds,
12708
- traceId
12733
+ traceId,
12734
+ goal: box.goal,
12735
+ toolsUsed: box.toolsUsed?.length ? box.toolsUsed : void 0,
12736
+ outcome: "unknown"
12709
12737
  };
12710
12738
  const content = `${serializeBoxFrontmatter(fm)}
12711
12739
 
@@ -15462,7 +15490,8 @@ var DEFAULT_CATEGORIES = [
15462
15490
  "principle",
15463
15491
  "commitment",
15464
15492
  "moment",
15465
- "skill"
15493
+ "skill",
15494
+ "rule"
15466
15495
  ];
15467
15496
  function normalizeNamespace(namespace) {
15468
15497
  return namespace.trim();
@@ -18378,10 +18407,13 @@ _Context: ${topQuestion.context}_`
18378
18407
  await clearBuffer();
18379
18408
  if (this.config.memoryBoxesEnabled && persistedIds.length > 0) {
18380
18409
  const extractionTopics = deriveTopicsFromExtraction(result);
18410
+ const firstUserTurn = turns.find((t) => t.role === "user");
18411
+ const boxGoal = firstUserTurn?.content?.slice(0, 100)?.trim() || void 0;
18381
18412
  await this.boxBuilderFor(storage).onExtraction({
18382
18413
  topics: extractionTopics,
18383
18414
  memoryIds: persistedIds,
18384
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
18415
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
18416
+ goal: boxGoal
18385
18417
  }).catch((err) => log.warn("[boxes] onExtraction failed (non-fatal)", err));
18386
18418
  }
18387
18419
  if (this.config.threadingEnabled && threadIdForExtraction && persistedIds.length > 0) {
@@ -21991,8 +22023,8 @@ Best for:
21991
22023
  ),
21992
22024
  category: Type.Optional(
21993
22025
  Type.String({
21994
- description: 'Category: "fact", "preference", "correction", "entity", "decision", "relationship", "principle", "commitment", "moment", "skill" (default: "fact")',
21995
- enum: ["fact", "preference", "correction", "entity", "decision", "relationship", "principle", "commitment", "moment", "skill"]
22026
+ description: 'Category: "fact", "preference", "correction", "entity", "decision", "relationship", "principle", "commitment", "moment", "skill", "rule" (default: "fact")',
22027
+ enum: ["fact", "preference", "correction", "entity", "decision", "relationship", "principle", "commitment", "moment", "skill", "rule"]
21996
22028
  })
21997
22029
  ),
21998
22030
  tags: Type.Optional(