@remnic/core 1.1.3 → 1.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/dist/access-cli.js +19 -19
  2. package/dist/access-http.d.ts +7 -7
  3. package/dist/access-http.js +12 -11
  4. package/dist/access-mcp.d.ts +7 -7
  5. package/dist/access-mcp.js +11 -10
  6. package/dist/access-schema.d.ts +89 -4
  7. package/dist/access-schema.js +1 -1
  8. package/dist/{access-service-_AEUMVyX.d.ts → access-service-CWYIkMwY.d.ts} +74 -18
  9. package/dist/access-service.d.ts +7 -7
  10. package/dist/access-service.js +9 -8
  11. package/dist/active-memory-bridge.d.ts +1 -1
  12. package/dist/active-recall.d.ts +1 -1
  13. package/dist/behavior-learner.d.ts +1 -1
  14. package/dist/behavior-signals.d.ts +1 -1
  15. package/dist/bootstrap.d.ts +6 -6
  16. package/dist/briefing.d.ts +2 -2
  17. package/dist/briefing.js +4 -4
  18. package/dist/buffer-surprise-report.d.ts +1 -1
  19. package/dist/buffer.d.ts +2 -2
  20. package/dist/calibration.d.ts +1 -1
  21. package/dist/causal-behavior.d.ts +1 -1
  22. package/dist/causal-consolidation.d.ts +2 -2
  23. package/dist/causal-consolidation.js +4 -4
  24. package/dist/{chunk-LZRYQK6L.js → chunk-3YBRSJ52.js} +2 -2
  25. package/dist/{chunk-DCE6SQLA.js → chunk-46AIFPQM.js} +3 -3
  26. package/dist/{chunk-AKUCB2OG.js → chunk-4CVIF7UZ.js} +14 -7
  27. package/dist/chunk-4CVIF7UZ.js.map +1 -0
  28. package/dist/{chunk-34F3PLWZ.js → chunk-57SNKQNS.js} +2 -2
  29. package/dist/{chunk-DHRQHX36.js → chunk-5XVDDCMH.js} +2 -2
  30. package/dist/{chunk-BOUYNNYD.js → chunk-67YLUWLG.js} +32 -13
  31. package/dist/{chunk-BOUYNNYD.js.map → chunk-67YLUWLG.js.map} +1 -1
  32. package/dist/{chunk-IM3JSE73.js → chunk-7NFZWXAY.js} +722 -27
  33. package/dist/chunk-7NFZWXAY.js.map +1 -0
  34. package/dist/{chunk-4PLGJRBV.js → chunk-DKVEJTLC.js} +188 -18
  35. package/dist/chunk-DKVEJTLC.js.map +1 -0
  36. package/dist/{chunk-DR7MCMPS.js → chunk-DTDB6YS2.js} +219 -9
  37. package/dist/chunk-DTDB6YS2.js.map +1 -0
  38. package/dist/{chunk-55FXRRSJ.js → chunk-ERWKQVCX.js} +2 -2
  39. package/dist/{chunk-7GCMLT7J.js → chunk-FG5R5AQF.js} +5 -5
  40. package/dist/{chunk-Y3WQ4ZWK.js → chunk-FLHPNR5W.js} +2 -2
  41. package/dist/{chunk-JWSENLQI.js → chunk-H62HCANJ.js} +3 -1
  42. package/dist/{chunk-JWSENLQI.js.map → chunk-H62HCANJ.js.map} +1 -1
  43. package/dist/{chunk-L5IIGA5V.js → chunk-HPJPGIGN.js} +2 -2
  44. package/dist/{chunk-SS253RXF.js → chunk-KCZZLFW5.js} +2 -2
  45. package/dist/{chunk-47WOM4YW.js → chunk-MJPNOMY4.js} +2 -2
  46. package/dist/{chunk-ZGXSCMQN.js → chunk-OAIXBFAH.js} +18 -18
  47. package/dist/{chunk-ZGXSCMQN.js.map → chunk-OAIXBFAH.js.map} +1 -1
  48. package/dist/{chunk-RILIVK4O.js → chunk-RICG4UNC.js} +28 -2
  49. package/dist/chunk-RICG4UNC.js.map +1 -0
  50. package/dist/{chunk-SMA4IMHV.js → chunk-SGTA3HJC.js} +3 -3
  51. package/dist/{chunk-VTJVUHRK.js → chunk-SRBJUAMP.js} +1 -1
  52. package/dist/chunk-SRBJUAMP.js.map +1 -0
  53. package/dist/{chunk-R2L7SUX2.js → chunk-TMPLRVHD.js} +2 -2
  54. package/dist/{chunk-43EKP2UK.js → chunk-TOC3VOOF.js} +1 -1
  55. package/dist/{chunk-43EKP2UK.js.map → chunk-TOC3VOOF.js.map} +1 -1
  56. package/dist/{chunk-USFPPRAF.js → chunk-WMK6YP7C.js} +5 -3
  57. package/dist/chunk-WMK6YP7C.js.map +1 -0
  58. package/dist/{chunk-N7X62G74.js → chunk-X6VBWOVZ.js} +4 -4
  59. package/dist/{chunk-LW2NMHDW.js → chunk-Y6EPN6XF.js} +2 -2
  60. package/dist/{chunk-LVYGDT5V.js → chunk-Z665HFAD.js} +10 -12
  61. package/dist/chunk-Z665HFAD.js.map +1 -0
  62. package/dist/{cli-x2APT9a6.d.ts → cli-CWLyGroU.d.ts} +4 -4
  63. package/dist/cli.d.ts +8 -8
  64. package/dist/cli.js +22 -21
  65. package/dist/{codex-materialize-CQlLTzke.d.ts → codex-materialize-XRen3WAz.d.ts} +1 -1
  66. package/dist/compression-optimizer.d.ts +1 -1
  67. package/dist/config.d.ts +1 -1
  68. package/dist/config.js +1 -1
  69. package/dist/consolidation-provenance-check.d.ts +2 -2
  70. package/dist/consolidation-undo.d.ts +2 -2
  71. package/dist/day-summary.d.ts +1 -1
  72. package/dist/delinearize.d.ts +1 -1
  73. package/dist/direct-answer-wiring.d.ts +1 -1
  74. package/dist/direct-answer.d.ts +1 -1
  75. package/dist/embedding-fallback.d.ts +1 -1
  76. package/dist/{engine-ICC2DSQF.js → engine-WJ7K6AZ2.js} +7 -5
  77. package/dist/entity-retrieval.d.ts +2 -2
  78. package/dist/entity-retrieval.js +4 -4
  79. package/dist/entity-schema.d.ts +1 -1
  80. package/dist/explicit-capture.d.ts +6 -6
  81. package/dist/extraction-judge-telemetry.d.ts +1 -1
  82. package/dist/extraction-judge-training.d.ts +1 -1
  83. package/dist/extraction-judge.d.ts +1 -1
  84. package/dist/extraction.d.ts +1 -1
  85. package/dist/extraction.js +2 -2
  86. package/dist/fallback-llm.d.ts +1 -1
  87. package/dist/identity-continuity.d.ts +1 -1
  88. package/dist/importance.d.ts +1 -1
  89. package/dist/index.d.ts +26 -14
  90. package/dist/index.js +47 -27
  91. package/dist/index.js.map +1 -1
  92. package/dist/intent.d.ts +1 -1
  93. package/dist/lifecycle.d.ts +1 -1
  94. package/dist/live-connectors-runner.d.ts +1 -1
  95. package/dist/local-llm.d.ts +1 -1
  96. package/dist/memory-action-policy.d.ts +1 -1
  97. package/dist/memory-cache.d.ts +1 -1
  98. package/dist/{memory-governance-KG52RITE.js → memory-governance-KXMAURFF.js} +5 -5
  99. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  100. package/dist/{memory-projection-store-D3vBHS4J.d.ts → memory-projection-store-ConH7gNj.d.ts} +2 -2
  101. package/dist/memory-projection-store.d.ts +2 -2
  102. package/dist/memory-projection-store.js +1 -1
  103. package/dist/memory-worth-outcomes.d.ts +2 -2
  104. package/dist/models-json.d.ts +1 -1
  105. package/dist/native-knowledge.d.ts +1 -1
  106. package/dist/operator-toolkit.d.ts +2 -2
  107. package/dist/operator-toolkit.js +7 -7
  108. package/dist/{orchestrator-ChkesB8U.d.ts → orchestrator-BHkiEBbd.d.ts} +36 -11
  109. package/dist/orchestrator.d.ts +6 -6
  110. package/dist/orchestrator.js +14 -14
  111. package/dist/patterns-cli.d.ts +1 -1
  112. package/dist/policy-runtime.d.ts +1 -1
  113. package/dist/{port-hqGnoStS.d.ts → port-DZHdlUId.d.ts} +1 -1
  114. package/dist/qmd-recall-cache.d.ts +2 -2
  115. package/dist/qmd.d.ts +2 -2
  116. package/dist/recall-disclosure-escalation.d.ts +1 -1
  117. package/dist/recall-explain-renderer.d.ts +1 -1
  118. package/dist/recall-explain-renderer.js +3 -3
  119. package/dist/recall-state.d.ts +1 -1
  120. package/dist/recall-tag-filter.d.ts +1 -1
  121. package/dist/recall-xray-cli.d.ts +1 -1
  122. package/dist/recall-xray-cli.js +4 -4
  123. package/dist/recall-xray-renderer.d.ts +1 -1
  124. package/dist/recall-xray-renderer.js +3 -3
  125. package/dist/recall-xray.d.ts +2 -2
  126. package/dist/recall-xray.js +2 -2
  127. package/dist/resolve-auth-token.d.ts +1 -1
  128. package/dist/resume-bundles.js +2 -2
  129. package/dist/retrieval-agents.d.ts +2 -2
  130. package/dist/retrieval-tiers.d.ts +1 -1
  131. package/dist/schemas.d.ts +54 -54
  132. package/dist/{semantic-consolidation-ByBXb-sf.d.ts → semantic-consolidation-Cxj-inGC.d.ts} +2 -2
  133. package/dist/semantic-consolidation.d.ts +3 -3
  134. package/dist/semantic-consolidation.js +4 -4
  135. package/dist/semantic-rule-promotion.js +4 -4
  136. package/dist/semantic-rule-verifier.d.ts +1 -1
  137. package/dist/semantic-rule-verifier.js +4 -4
  138. package/dist/session-observer-bands.d.ts +1 -1
  139. package/dist/session-observer-state.d.ts +1 -1
  140. package/dist/signal.d.ts +1 -1
  141. package/dist/storage.d.ts +2 -2
  142. package/dist/storage.js +3 -3
  143. package/dist/summarizer.d.ts +1 -1
  144. package/dist/summary-snapshot.d.ts +1 -1
  145. package/dist/temporal-supersession.d.ts +2 -2
  146. package/dist/temporal-validity.d.ts +1 -1
  147. package/dist/threading.d.ts +1 -1
  148. package/dist/tier-migration.d.ts +3 -3
  149. package/dist/tier-routing.d.ts +1 -1
  150. package/dist/topics.d.ts +1 -1
  151. package/dist/transcript.d.ts +1 -1
  152. package/dist/types-B49NzJ5q.d.ts +2707 -0
  153. package/dist/types.d.ts +1 -2668
  154. package/dist/types.js +1 -1
  155. package/dist/utility-runtime.d.ts +1 -1
  156. package/dist/verified-recall.js +4 -4
  157. package/package.json +6 -3
  158. package/scripts/ensure-better-sqlite3.mjs +124 -0
  159. package/dist/chunk-4PLGJRBV.js.map +0 -1
  160. package/dist/chunk-AKUCB2OG.js.map +0 -1
  161. package/dist/chunk-DR7MCMPS.js.map +0 -1
  162. package/dist/chunk-IM3JSE73.js.map +0 -1
  163. package/dist/chunk-LVYGDT5V.js.map +0 -1
  164. package/dist/chunk-RILIVK4O.js.map +0 -1
  165. package/dist/chunk-USFPPRAF.js.map +0 -1
  166. package/dist/chunk-VTJVUHRK.js.map +0 -1
  167. /package/dist/{chunk-LZRYQK6L.js.map → chunk-3YBRSJ52.js.map} +0 -0
  168. /package/dist/{chunk-DCE6SQLA.js.map → chunk-46AIFPQM.js.map} +0 -0
  169. /package/dist/{chunk-34F3PLWZ.js.map → chunk-57SNKQNS.js.map} +0 -0
  170. /package/dist/{chunk-DHRQHX36.js.map → chunk-5XVDDCMH.js.map} +0 -0
  171. /package/dist/{chunk-55FXRRSJ.js.map → chunk-ERWKQVCX.js.map} +0 -0
  172. /package/dist/{chunk-7GCMLT7J.js.map → chunk-FG5R5AQF.js.map} +0 -0
  173. /package/dist/{chunk-Y3WQ4ZWK.js.map → chunk-FLHPNR5W.js.map} +0 -0
  174. /package/dist/{chunk-L5IIGA5V.js.map → chunk-HPJPGIGN.js.map} +0 -0
  175. /package/dist/{chunk-SS253RXF.js.map → chunk-KCZZLFW5.js.map} +0 -0
  176. /package/dist/{chunk-47WOM4YW.js.map → chunk-MJPNOMY4.js.map} +0 -0
  177. /package/dist/{chunk-SMA4IMHV.js.map → chunk-SGTA3HJC.js.map} +0 -0
  178. /package/dist/{chunk-R2L7SUX2.js.map → chunk-TMPLRVHD.js.map} +0 -0
  179. /package/dist/{chunk-N7X62G74.js.map → chunk-X6VBWOVZ.js.map} +0 -0
  180. /package/dist/{chunk-LW2NMHDW.js.map → chunk-Y6EPN6XF.js.map} +0 -0
  181. /package/dist/{engine-ICC2DSQF.js.map → engine-WJ7K6AZ2.js.map} +0 -0
  182. /package/dist/{memory-governance-KG52RITE.js.map → memory-governance-KXMAURFF.js.map} +0 -0
@@ -2,7 +2,7 @@ import {
2
2
  CompoundingEngine,
3
3
  SharedContextManager,
4
4
  defaultTierMigrationCycleBudget
5
- } from "./chunk-LVYGDT5V.js";
5
+ } from "./chunk-Z665HFAD.js";
6
6
  import {
7
7
  applyUtilityPromotionRuntimePolicy,
8
8
  applyUtilityRankingRuntimeDelta,
@@ -119,13 +119,10 @@ import {
119
119
  } from "./chunk-C4SQJZAF.js";
120
120
  import {
121
121
  ExtractionEngine
122
- } from "./chunk-N7X62G74.js";
122
+ } from "./chunk-X6VBWOVZ.js";
123
123
  import {
124
124
  parseMemoryActionEligibilityContext
125
125
  } from "./chunk-WW3QQF4H.js";
126
- import {
127
- ProfilingCollector
128
- } from "./chunk-NBNN5GOB.js";
129
126
  import {
130
127
  ModelRegistry
131
128
  } from "./chunk-FEMOX5AD.js";
@@ -145,7 +142,7 @@ import {
145
142
  buildEntityRecallSection,
146
143
  entityRecentTranscriptLookbackHours,
147
144
  readRecentEntityTranscriptEntries
148
- } from "./chunk-Y3WQ4ZWK.js";
145
+ } from "./chunk-FLHPNR5W.js";
149
146
  import {
150
147
  buildCompressionGuidelinesMarkdown,
151
148
  computeCompressionGuidelineCandidate,
@@ -155,16 +152,16 @@ import {
155
152
  import {
156
153
  RoutingRulesStore,
157
154
  normalizeReplaySessionKey
158
- } from "./chunk-VTJVUHRK.js";
155
+ } from "./chunk-SRBJUAMP.js";
159
156
  import {
160
157
  searchVerifiedEpisodes
161
- } from "./chunk-DHRQHX36.js";
158
+ } from "./chunk-5XVDDCMH.js";
162
159
  import {
163
160
  ThreadingManager
164
161
  } from "./chunk-JRNQ3RNA.js";
165
162
  import {
166
163
  searchVerifiedSemanticRules
167
- } from "./chunk-L5IIGA5V.js";
164
+ } from "./chunk-HPJPGIGN.js";
168
165
  import {
169
166
  searchWorkProductLedgerEntries
170
167
  } from "./chunk-CULXMQJH.js";
@@ -184,7 +181,7 @@ import {
184
181
  createConversationIndexRuntime,
185
182
  createSearchBackend,
186
183
  writeConversationChunks
187
- } from "./chunk-R2L7SUX2.js";
184
+ } from "./chunk-TMPLRVHD.js";
188
185
  import {
189
186
  parseQmdExplain
190
187
  } from "./chunk-WSZIHQBK.js";
@@ -231,7 +228,7 @@ import {
231
228
  materializeAfterSemanticConsolidation,
232
229
  parseConsolidationResponse,
233
230
  parseOperatorAwareConsolidationResponse
234
- } from "./chunk-55FXRRSJ.js";
231
+ } from "./chunk-ERWKQVCX.js";
235
232
  import {
236
233
  FallbackLlmClient
237
234
  } from "./chunk-CRU27Q4J.js";
@@ -266,13 +263,16 @@ import {
266
263
  } from "./chunk-EQINRHYR.js";
267
264
  import {
268
265
  buildXraySnapshot
269
- } from "./chunk-USFPPRAF.js";
266
+ } from "./chunk-WMK6YP7C.js";
270
267
  import {
271
268
  shouldSkipImplicitExtraction
272
269
  } from "./chunk-3FPTCC3Z.js";
273
270
  import {
274
271
  selectRouteRule
275
272
  } from "./chunk-2LGMW3DJ.js";
273
+ import {
274
+ ProfilingCollector
275
+ } from "./chunk-NBNN5GOB.js";
276
276
  import {
277
277
  launchProcessSync
278
278
  } from "./chunk-OR64ZGRZ.js";
@@ -303,7 +303,7 @@ import {
303
303
  normalizeAttributePairs,
304
304
  normalizeEntityName,
305
305
  parseEntityFile
306
- } from "./chunk-DCE6SQLA.js";
306
+ } from "./chunk-46AIFPQM.js";
307
307
  import {
308
308
  attachCitation,
309
309
  hasCitationForTemplate,
@@ -311,13 +311,13 @@ import {
311
311
  } from "./chunk-4KAN3GZ3.js";
312
312
  import {
313
313
  confidenceTier
314
- } from "./chunk-43EKP2UK.js";
314
+ } from "./chunk-TOC3VOOF.js";
315
315
  import {
316
316
  isActiveMemoryStatus
317
317
  } from "./chunk-RULE4VG5.js";
318
318
  import {
319
319
  openBetterSqlite3
320
- } from "./chunk-BOUYNNYD.js";
320
+ } from "./chunk-67YLUWLG.js";
321
321
  import {
322
322
  lintWorkspaceFiles,
323
323
  rotateMarkdownFileToArchive
@@ -1613,7 +1613,7 @@ function getTaxonomyFilePath(memoryDir) {
1613
1613
  // src/lcm/schema.ts
1614
1614
  import path4 from "path";
1615
1615
  import { mkdir as mkdir4 } from "fs/promises";
1616
- var LCM_SCHEMA_VERSION = 1;
1616
+ var LCM_SCHEMA_VERSION = 2;
1617
1617
  function openLcmDatabase(memoryDir) {
1618
1618
  const dbPath = path4.join(memoryDir, "state", "lcm.sqlite");
1619
1619
  const db = openBetterSqlite3(dbPath);
@@ -1626,6 +1626,9 @@ function openLcmDatabase(memoryDir) {
1626
1626
  async function ensureLcmStateDir(memoryDir) {
1627
1627
  await mkdir4(path4.join(memoryDir, "state"), { recursive: true });
1628
1628
  }
1629
+ function applyLcmSchema(db) {
1630
+ applySchema(db);
1631
+ }
1629
1632
  function applySchema(db) {
1630
1633
  const versionRow = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='lcm_meta'").get();
1631
1634
  if (!versionRow) {
@@ -1659,6 +1662,23 @@ function createTables(db) {
1659
1662
  CREATE INDEX IF NOT EXISTS idx_lcm_messages_session
1660
1663
  ON lcm_messages(session_id, turn_index);
1661
1664
 
1665
+ CREATE TABLE IF NOT EXISTS lcm_message_parts (
1666
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
1667
+ message_id INTEGER NOT NULL REFERENCES lcm_messages(id) ON DELETE CASCADE,
1668
+ ordinal INTEGER NOT NULL,
1669
+ kind TEXT NOT NULL,
1670
+ payload TEXT NOT NULL,
1671
+ tool_name TEXT,
1672
+ file_path TEXT,
1673
+ created_at TEXT NOT NULL
1674
+ );
1675
+ CREATE INDEX IF NOT EXISTS idx_lcm_message_parts_msg
1676
+ ON lcm_message_parts(message_id, ordinal);
1677
+ CREATE INDEX IF NOT EXISTS idx_lcm_message_parts_tool
1678
+ ON lcm_message_parts(tool_name);
1679
+ CREATE INDEX IF NOT EXISTS idx_lcm_message_parts_file
1680
+ ON lcm_message_parts(file_path);
1681
+
1662
1682
  CREATE TABLE IF NOT EXISTS lcm_summary_nodes (
1663
1683
  id TEXT PRIMARY KEY,
1664
1684
  session_id TEXT NOT NULL,
@@ -1711,6 +1731,423 @@ function createTables(db) {
1711
1731
  );
1712
1732
  }
1713
1733
 
1734
+ // src/message-parts/index.ts
1735
+ var LCM_MESSAGE_PART_KINDS = [
1736
+ "text",
1737
+ "tool_call",
1738
+ "tool_result",
1739
+ "patch",
1740
+ "file_read",
1741
+ "file_write",
1742
+ "step_start",
1743
+ "step_finish",
1744
+ "snapshot",
1745
+ "retry"
1746
+ ];
1747
+ var SECRET_KEY_RE = /(api[_-]?key|authorization|bearer|credential|password|secret|token)/i;
1748
+ var MAX_PAYLOAD_STRING = 8e3;
1749
+ var MAX_FILE_SCAN_CHARS = 2e4;
1750
+ function isLcmMessagePartKind(value) {
1751
+ return typeof value === "string" && LCM_MESSAGE_PART_KINDS.includes(value);
1752
+ }
1753
+ function parseMessageParts(input, options = {}) {
1754
+ const explicit = normalizeExplicitParts(input);
1755
+ if (explicit.length > 0) return explicit;
1756
+ const format = options.sourceFormat ?? inferSourceFormat(input);
1757
+ switch (format) {
1758
+ case "openai":
1759
+ return withRenderedFallback(parseOpenAiMessageParts(input, options), options);
1760
+ case "anthropic":
1761
+ return withRenderedFallback(parseAnthropicMessageParts(input, options), options);
1762
+ case "openclaw":
1763
+ return withRenderedFallback(parseOpenClawMessageParts(input, options), options);
1764
+ case "lossless-claw":
1765
+ case "remnic":
1766
+ return withRenderedFallback(normalizeExplicitParts(input), options);
1767
+ default:
1768
+ return renderedFallbackParts(options);
1769
+ }
1770
+ }
1771
+ function normalizeExplicitParts(input) {
1772
+ const rawParts = pickArray(input, "parts") ?? pickArray(input, "message_parts");
1773
+ if (!rawParts) return [];
1774
+ const parts = [];
1775
+ rawParts.forEach((raw, index) => {
1776
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
1777
+ const obj = raw;
1778
+ const kind = normalizeKind(obj.kind ?? obj.type);
1779
+ if (!kind) return;
1780
+ const payload = obj.payload && typeof obj.payload === "object" && !Array.isArray(obj.payload) ? obj.payload : { value: sanitizePayload(obj) };
1781
+ const toolName = asNonEmptyString(obj.toolName ?? obj.tool_name ?? obj.name);
1782
+ const filePath = asNonEmptyString(obj.filePath ?? obj.file_path ?? obj.path);
1783
+ const ordinal = typeof obj.ordinal === "number" && Number.isInteger(obj.ordinal) ? Math.max(0, obj.ordinal) : index;
1784
+ parts.push({
1785
+ ordinal,
1786
+ kind,
1787
+ payload: sanitizePayload(payload),
1788
+ toolName,
1789
+ filePath,
1790
+ createdAt: asNonEmptyString(obj.createdAt ?? obj.created_at)
1791
+ });
1792
+ });
1793
+ return parts;
1794
+ }
1795
+ function parseOpenAiMessageParts(input, _options = {}) {
1796
+ const items = gatherOpenAiItems(input);
1797
+ const parts = [];
1798
+ for (const item of items) {
1799
+ const type = asNonEmptyString(item.type) ?? asNonEmptyString(item.kind);
1800
+ if (!type) continue;
1801
+ if (isOpenAiContentBlock(item)) {
1802
+ const text = asNonEmptyString(item.text ?? item.content);
1803
+ if (text) parts.push(makePart("text", { type, text }, { filePath: firstFilePath(text) }));
1804
+ continue;
1805
+ }
1806
+ if (type === "message") {
1807
+ for (const block of gatherContentBlocks(item.content)) {
1808
+ const text = asNonEmptyString(block.text ?? block.content);
1809
+ if (text) parts.push(makePart("text", { type, text }, { filePath: firstFilePath(text) }));
1810
+ }
1811
+ continue;
1812
+ }
1813
+ if (type === "function_call") {
1814
+ const toolName = asNonEmptyString(item.name ?? item.tool_name);
1815
+ const payload = {
1816
+ id: item.id ?? item.call_id,
1817
+ name: toolName,
1818
+ arguments: parseMaybeJson(item.arguments)
1819
+ };
1820
+ parts.push(classifyToolPart(toolName, payload));
1821
+ continue;
1822
+ }
1823
+ if (type === "function_call_output") {
1824
+ const output = asNonEmptyString(item.output) ?? JSON.stringify(sanitizePayload(item.output ?? item));
1825
+ parts.push(makePart("tool_result", { id: item.id ?? item.call_id, output }, {
1826
+ filePath: firstFilePath(output)
1827
+ }));
1828
+ continue;
1829
+ }
1830
+ if (type === "reasoning") {
1831
+ parts.push(makePart("step_start", { type, summary: sanitizePayload(item.summary ?? item) }));
1832
+ continue;
1833
+ }
1834
+ if (type === "retry") {
1835
+ parts.push(makePart("retry", { type, item: sanitizePayload(item) }));
1836
+ }
1837
+ }
1838
+ return withOrdinals(parts);
1839
+ }
1840
+ function parseAnthropicMessageParts(input, _options = {}) {
1841
+ const blocks = gatherContentBlocks(
1842
+ Array.isArray(input) ? input : input && typeof input === "object" ? input.content : input
1843
+ );
1844
+ const parts = [];
1845
+ for (const block of blocks) {
1846
+ const type = asNonEmptyString(block.type);
1847
+ if (type === "text") {
1848
+ const text = asNonEmptyString(block.text);
1849
+ if (text) parts.push(makePart("text", { type, text }, { filePath: firstFilePath(text) }));
1850
+ continue;
1851
+ }
1852
+ if (type === "tool_use") {
1853
+ const toolName = asNonEmptyString(block.name);
1854
+ parts.push(classifyToolPart(toolName, {
1855
+ id: block.id,
1856
+ name: toolName,
1857
+ input: sanitizePayload(block.input)
1858
+ }));
1859
+ continue;
1860
+ }
1861
+ if (type === "tool_result") {
1862
+ const content = block.content;
1863
+ const rendered = renderUnknownContent(content);
1864
+ parts.push(makePart("tool_result", { id: block.tool_use_id, content: sanitizePayload(content) }, {
1865
+ filePath: firstFilePath(rendered)
1866
+ }));
1867
+ continue;
1868
+ }
1869
+ if (type === "thinking") {
1870
+ parts.push(makePart("step_start", {
1871
+ type,
1872
+ thinking: truncateString(asNonEmptyString(block.thinking) ?? ""),
1873
+ signature: asNonEmptyString(block.signature)
1874
+ }));
1875
+ continue;
1876
+ }
1877
+ if (type === "redacted_thinking") {
1878
+ parts.push(makePart("step_finish", { type }));
1879
+ }
1880
+ }
1881
+ return withOrdinals(parts);
1882
+ }
1883
+ function parseOpenClawMessageParts(input, options = {}) {
1884
+ const explicit = normalizeExplicitParts(input);
1885
+ if (explicit.length > 0) return explicit;
1886
+ if (!input || typeof input !== "object") return [];
1887
+ const obj = input;
1888
+ const content = obj.content;
1889
+ if (Array.isArray(content)) {
1890
+ const hasOpenAiBlocks = content.some(isOpenAiContentBlock);
1891
+ if (hasOpenAiBlocks) return parseOpenAiMessageParts(content, options);
1892
+ const hasAnthropicBlocks = content.some(
1893
+ (block) => block && typeof block === "object" && typeof block.type === "string"
1894
+ );
1895
+ if (hasAnthropicBlocks) return parseAnthropicMessageParts({ content }, options);
1896
+ }
1897
+ const toolName = asNonEmptyString(obj.toolName ?? obj.tool_name ?? obj.name);
1898
+ if (toolName) {
1899
+ return withOrdinals([
1900
+ classifyToolPart(toolName, {
1901
+ name: toolName,
1902
+ input: sanitizePayload(obj.input ?? obj.arguments ?? obj.params),
1903
+ output: sanitizePayload(obj.output ?? obj.result)
1904
+ })
1905
+ ]);
1906
+ }
1907
+ const rendered = options.renderedContent ?? asNonEmptyString(obj.content);
1908
+ return rendered ? withOrdinals(partsFromRenderedText(rendered)) : [];
1909
+ }
1910
+ function partsFromRenderedText(text) {
1911
+ if (text.includes("*** Begin Patch")) {
1912
+ const paths2 = extractFilePaths(text);
1913
+ const patchPaths = extractPatchPaths(text);
1914
+ return withOrdinals((patchPaths.length > 0 ? patchPaths : paths2).map(
1915
+ (filePath) => makePart("patch", { text: truncateString(text) }, { filePath })
1916
+ ));
1917
+ }
1918
+ const paths = extractFilePaths(text);
1919
+ if (paths.length === 0) return [];
1920
+ return withOrdinals(paths.map(
1921
+ (filePath) => makePart("file_read", { text: truncateString(text) }, { filePath })
1922
+ ));
1923
+ }
1924
+ function inferSourceFormat(input) {
1925
+ if (input && typeof input === "object") {
1926
+ const obj = input;
1927
+ const explicit = asNonEmptyString(obj.sourceFormat ?? obj.source_format);
1928
+ if (explicit === "openai" || explicit === "anthropic" || explicit === "openclaw" || explicit === "lossless-claw" || explicit === "remnic") {
1929
+ return explicit;
1930
+ }
1931
+ if (Array.isArray(obj.output)) return "openai";
1932
+ if (isOpenAiResponseItem(obj)) return "openai";
1933
+ if (Array.isArray(obj.content) && obj.content.some(isOpenAiContentBlock)) return "openai";
1934
+ if (Array.isArray(obj.content)) return "anthropic";
1935
+ }
1936
+ if (Array.isArray(input)) {
1937
+ return input.some(
1938
+ (item) => isRecord(item) && (isOpenAiResponseItem(item) || isOpenAiContentBlock(item))
1939
+ ) ? "openai" : "anthropic";
1940
+ }
1941
+ return void 0;
1942
+ }
1943
+ function isOpenAiResponseItem(obj) {
1944
+ const type = asNonEmptyString(obj.type ?? obj.kind);
1945
+ return type === "message" || type === "function_call" || type === "function_call_output" || type === "reasoning" || type === "retry";
1946
+ }
1947
+ function isOpenAiContentBlock(value) {
1948
+ if (!isRecord(value)) return false;
1949
+ const type = asNonEmptyString(value.type);
1950
+ return type === "input_text" || type === "output_text" || type === "input_image" || type === "input_file" || type === "refusal";
1951
+ }
1952
+ function gatherOpenAiItems(input) {
1953
+ if (Array.isArray(input)) return input.filter(isRecord);
1954
+ if (!isRecord(input)) return [];
1955
+ if (Array.isArray(input.output)) return input.output.filter(isRecord);
1956
+ if (Array.isArray(input.items)) return input.items.filter(isRecord);
1957
+ return [input];
1958
+ }
1959
+ function gatherContentBlocks(input) {
1960
+ if (Array.isArray(input)) return input.filter(isRecord);
1961
+ if (typeof input === "string") return [{ type: "text", text: input }];
1962
+ if (isRecord(input)) return [input];
1963
+ return [];
1964
+ }
1965
+ function classifyToolPart(toolName, payload) {
1966
+ const normalized = (toolName ?? "").toLowerCase();
1967
+ const rendered = renderUnknownContent(payload);
1968
+ const filePath = firstFilePathFromObject(payload) ?? firstFilePath(rendered) ?? null;
1969
+ if (normalized.includes("apply_patch") || rendered.includes("*** Begin Patch")) {
1970
+ return makePart("patch", payload, { toolName, filePath: filePath ?? extractPatchPaths(rendered)[0] ?? null });
1971
+ }
1972
+ if (/(write|edit|multiedit|create|save)/i.test(normalized)) {
1973
+ return makePart("file_write", payload, { toolName, filePath });
1974
+ }
1975
+ if (/(read|grep|glob|search|list|ls)/i.test(normalized)) {
1976
+ return makePart("file_read", payload, { toolName, filePath });
1977
+ }
1978
+ return makePart("tool_call", payload, { toolName, filePath });
1979
+ }
1980
+ function makePart(kind, payload, options = {}) {
1981
+ return {
1982
+ kind,
1983
+ payload: sanitizePayload(payload),
1984
+ toolName: options.toolName ?? null,
1985
+ filePath: options.filePath ?? null
1986
+ };
1987
+ }
1988
+ function withOrdinals(parts) {
1989
+ return parts.map((part, ordinal) => ({ ...part, ordinal: part.ordinal ?? ordinal }));
1990
+ }
1991
+ function withRenderedFallback(parts, options) {
1992
+ return parts.length > 0 ? parts : renderedFallbackParts(options);
1993
+ }
1994
+ function renderedFallbackParts(options) {
1995
+ const rendered = asNonEmptyString(options.renderedContent);
1996
+ return rendered ? partsFromRenderedText(rendered) : [];
1997
+ }
1998
+ function normalizeKind(value) {
1999
+ if (isLcmMessagePartKind(value)) return value;
2000
+ if (value === "tool_use" || value === "function_call") return "tool_call";
2001
+ if (value === "function_call_output") return "tool_result";
2002
+ if (value === "thinking" || value === "reasoning") return "step_start";
2003
+ return null;
2004
+ }
2005
+ function pickArray(input, key) {
2006
+ if (!input || typeof input !== "object" || Array.isArray(input)) return null;
2007
+ const value = input[key];
2008
+ return Array.isArray(value) ? value : null;
2009
+ }
2010
+ function asNonEmptyString(value) {
2011
+ if (typeof value !== "string") return null;
2012
+ const trimmed = value.trim();
2013
+ return trimmed.length > 0 ? trimmed : null;
2014
+ }
2015
+ function isRecord(value) {
2016
+ return !!value && typeof value === "object" && !Array.isArray(value);
2017
+ }
2018
+ function parseMaybeJson(value) {
2019
+ if (typeof value !== "string") return sanitizePayload(value);
2020
+ try {
2021
+ return sanitizePayload(JSON.parse(value));
2022
+ } catch {
2023
+ return truncateString(value);
2024
+ }
2025
+ }
2026
+ function sanitizePayload(value, depth = 0) {
2027
+ if (value === null || value === void 0) return value;
2028
+ if (typeof value === "string") return truncateString(value);
2029
+ if (typeof value === "number" || typeof value === "boolean") return value;
2030
+ if (Array.isArray(value)) {
2031
+ if (depth >= 4) return "[truncated]";
2032
+ return value.slice(0, 100).map((item) => sanitizePayload(item, depth + 1));
2033
+ }
2034
+ if (typeof value === "object") {
2035
+ if (depth >= 4) return "[truncated]";
2036
+ const out = {};
2037
+ for (const [key, child] of Object.entries(value)) {
2038
+ out[key] = SECRET_KEY_RE.test(key) ? "[redacted]" : sanitizePayload(child, depth + 1);
2039
+ }
2040
+ return out;
2041
+ }
2042
+ return String(value);
2043
+ }
2044
+ function truncateString(value) {
2045
+ return value.length > MAX_PAYLOAD_STRING ? `${value.slice(0, MAX_PAYLOAD_STRING)}...[truncated]` : value;
2046
+ }
2047
+ function renderUnknownContent(value) {
2048
+ if (typeof value === "string") return value;
2049
+ try {
2050
+ return JSON.stringify(value ?? "");
2051
+ } catch {
2052
+ return String(value ?? "");
2053
+ }
2054
+ }
2055
+ function firstFilePathFromObject(value) {
2056
+ if (!isRecord(value)) return null;
2057
+ const keys = ["file_path", "filePath", "path", "filename", "cwd"];
2058
+ for (const key of keys) {
2059
+ const candidate = asNonEmptyString(value[key]);
2060
+ if (candidate) return candidate;
2061
+ }
2062
+ for (const child of Object.values(value)) {
2063
+ if (typeof child === "string") {
2064
+ const fromText = extractPatchPaths(child)[0] ?? firstFilePath(child);
2065
+ if (fromText) return fromText;
2066
+ }
2067
+ if (isRecord(child)) {
2068
+ const nested = firstFilePathFromObject(child);
2069
+ if (nested) return nested;
2070
+ }
2071
+ }
2072
+ return null;
2073
+ }
2074
+ function firstFilePath(text) {
2075
+ return extractFilePaths(text)[0] ?? null;
2076
+ }
2077
+ function extractFilePaths(text) {
2078
+ const out = /* @__PURE__ */ new Set();
2079
+ let token = "";
2080
+ const scanLength = Math.min(text.length, MAX_FILE_SCAN_CHARS);
2081
+ for (let index = 0; index <= scanLength; index += 1) {
2082
+ const char = index < scanLength ? text[index] : " ";
2083
+ if (isFilePathTokenSeparator(char)) {
2084
+ addFilePathCandidate(out, token);
2085
+ token = "";
2086
+ continue;
2087
+ }
2088
+ token += char;
2089
+ if (token.length > 512) {
2090
+ addFilePathCandidate(out, token);
2091
+ token = "";
2092
+ }
2093
+ }
2094
+ return [...out].slice(0, 20);
2095
+ }
2096
+ function isFilePathTokenSeparator(char) {
2097
+ return char === " " || char === "\n" || char === "\r" || char === " " || char === '"' || char === "'" || char === "`" || char === "(" || char === ")" || char === "[" || char === "]" || char === "{" || char === "}" || char === "<" || char === ">" || char === ",";
2098
+ }
2099
+ function addFilePathCandidate(out, raw) {
2100
+ const candidate = trimFilePathPunctuation(raw);
2101
+ if (candidate.length === 0 || candidate.includes("://")) return;
2102
+ if (isLikelyFilePath(candidate)) out.add(candidate);
2103
+ }
2104
+ function trimFilePathPunctuation(raw) {
2105
+ let start = 0;
2106
+ let end = raw.length;
2107
+ while (start < end && isLeadingFilePathPunctuation(raw[start])) start += 1;
2108
+ while (end > start && isTrailingFilePathPunctuation(raw[end - 1])) end -= 1;
2109
+ return raw.slice(start, end);
2110
+ }
2111
+ function isLeadingFilePathPunctuation(char) {
2112
+ return char === ":" || char === ";" || char === "!" || char === "?" || char === "|" || char === "*" || char === "=";
2113
+ }
2114
+ function isTrailingFilePathPunctuation(char) {
2115
+ return char === "." || char === ":" || char === ";" || char === "!" || char === "?" || char === "|" || char === "*" || char === "=";
2116
+ }
2117
+ function isLikelyFilePath(value) {
2118
+ if (value.startsWith("/") || value.startsWith("./") || value.startsWith("../") || value.startsWith("~/")) {
2119
+ return hasValidFileExtension(value);
2120
+ }
2121
+ if (value.includes("/")) return hasValidFileExtension(value);
2122
+ return hasValidFileExtension(value);
2123
+ }
2124
+ function hasValidFileExtension(value) {
2125
+ const lastSlash = value.lastIndexOf("/");
2126
+ const basename = value.slice(lastSlash + 1);
2127
+ const dot = basename.lastIndexOf(".");
2128
+ if (dot <= 0 || dot === basename.length - 1) return false;
2129
+ const ext = basename.slice(dot + 1);
2130
+ if (ext.length < 1 || ext.length > 12) return false;
2131
+ for (const char of ext) {
2132
+ if (!isFileExtensionChar(char)) return false;
2133
+ }
2134
+ return true;
2135
+ }
2136
+ function isFileExtensionChar(char) {
2137
+ const code = char.charCodeAt(0);
2138
+ return code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122 || char === "_" || char === "+" || char === "-";
2139
+ }
2140
+ function extractPatchPaths(text) {
2141
+ const out = /* @__PURE__ */ new Set();
2142
+ for (const line of text.split(/\r?\n/)) {
2143
+ const match = line.match(/^\*\*\* (?:Add|Update|Delete) File: (.+)$/);
2144
+ if (match?.[1]) out.add(match[1].trim());
2145
+ const move = line.match(/^\*\*\* Move to: (.+)$/);
2146
+ if (move?.[1]) out.add(move[1].trim());
2147
+ }
2148
+ return [...out].slice(0, 20);
2149
+ }
2150
+
1714
2151
  // src/lcm/archive.ts
1715
2152
  function estimateTokens(text) {
1716
2153
  return Math.ceil(text.length / 4);
@@ -1721,7 +2158,7 @@ var LcmArchive = class {
1721
2158
  }
1722
2159
  db;
1723
2160
  /** Append a message to the archive. Returns the row id. */
1724
- appendMessage(sessionId, turnIndex, role, content, metadata) {
2161
+ appendMessage(sessionId, turnIndex, role, content, metadata, parts) {
1725
2162
  const tokenCount = estimateTokens(content);
1726
2163
  const now = (/* @__PURE__ */ new Date()).toISOString();
1727
2164
  const metaJson = metadata ? JSON.stringify(metadata) : null;
@@ -1732,18 +2169,58 @@ var LcmArchive = class {
1732
2169
  const result = stmt.run(sessionId, turnIndex, role, content, tokenCount, now, metaJson);
1733
2170
  const rowId = Number(result.lastInsertRowid);
1734
2171
  this.db.prepare("INSERT INTO lcm_messages_fts (rowid, content) VALUES (?, ?)").run(rowId, content);
2172
+ if (parts && parts.length > 0) {
2173
+ this.insertMessageParts(rowId, parts, now);
2174
+ }
1735
2175
  return rowId;
1736
2176
  }
1737
2177
  /** Append multiple messages in a single transaction. */
1738
- appendMessages(sessionId, messages) {
2178
+ appendMessages(sessionId, messages, options = {}) {
1739
2179
  if (messages.length === 0) return;
2180
+ const captureMessageParts = options.messagePartsEnabled !== false;
1740
2181
  const txn = this.db.transaction(() => {
1741
2182
  for (const msg of messages) {
1742
- this.appendMessage(sessionId, msg.turnIndex, msg.role, msg.content, msg.metadata);
2183
+ const explicitParts = msg.parts && msg.parts.length > 0 ? msg.parts : void 0;
2184
+ const rawContent = msg.rawContent ?? msg.content;
2185
+ const parts = captureMessageParts ? explicitParts ?? parseMessageParts(rawContent, {
2186
+ sourceFormat: msg.sourceFormat,
2187
+ renderedContent: msg.content
2188
+ }) : void 0;
2189
+ this.appendMessage(
2190
+ sessionId,
2191
+ msg.turnIndex,
2192
+ msg.role,
2193
+ msg.content,
2194
+ msg.metadata,
2195
+ parts
2196
+ );
1743
2197
  }
1744
2198
  });
1745
2199
  txn();
1746
2200
  }
2201
+ insertMessageParts(messageId, parts, fallbackCreatedAt) {
2202
+ if (parts.length === 0) return;
2203
+ const stmt = this.db.prepare(`
2204
+ INSERT INTO lcm_message_parts (message_id, ordinal, kind, payload, tool_name, file_path, created_at)
2205
+ VALUES (?, ?, ?, ?, ?, ?, ?)
2206
+ `);
2207
+ for (let index = 0; index < parts.length; index += 1) {
2208
+ const part = parts[index];
2209
+ const rawPart = part;
2210
+ const toolName = part.toolName ?? asNullableString(rawPart.tool_name);
2211
+ const filePath = part.filePath ?? asNullableString(rawPart.file_path);
2212
+ const createdAt = part.createdAt ?? asNullableString(rawPart.created_at);
2213
+ stmt.run(
2214
+ messageId,
2215
+ part.ordinal ?? index,
2216
+ part.kind,
2217
+ JSON.stringify(part.payload ?? {}),
2218
+ toolName ?? null,
2219
+ filePath ?? null,
2220
+ createdAt ?? fallbackCreatedAt
2221
+ );
2222
+ }
2223
+ }
1747
2224
  /** Get the highest turn_index for a session, or -1 if none. */
1748
2225
  getMaxTurnIndex(sessionId) {
1749
2226
  const row = this.db.prepare("SELECT MAX(turn_index) as max_turn FROM lcm_messages WHERE session_id = ?").get(sessionId);
@@ -1865,6 +2342,55 @@ var LcmArchive = class {
1865
2342
  return [];
1866
2343
  }
1867
2344
  }
2345
+ searchStructuredParts(query, limit, sessionId) {
2346
+ const cappedLimit = Math.max(0, Math.min(20, Math.floor(limit)));
2347
+ if (cappedLimit === 0) return [];
2348
+ const fileTerms = extractStructuredFileTerms(query);
2349
+ const toolTerms = extractStructuredToolTerms(query);
2350
+ if (fileTerms.length === 0 && toolTerms.length === 0) return [];
2351
+ const matchWhere = [];
2352
+ const whereParams = [];
2353
+ for (const term of fileTerms) {
2354
+ matchWhere.push("(p.file_path = ? OR p.file_path LIKE ? ESCAPE '\\')");
2355
+ whereParams.push(term, `%${escapeLike(term)}%`);
2356
+ }
2357
+ for (const term of toolTerms) {
2358
+ matchWhere.push("p.tool_name LIKE ? ESCAPE '\\'");
2359
+ whereParams.push(`%${escapeLike(term)}%`);
2360
+ }
2361
+ const where = [`(${matchWhere.join(" OR ")})`];
2362
+ if (sessionId) {
2363
+ where.push("m.session_id = ?");
2364
+ whereParams.push(sessionId);
2365
+ }
2366
+ const exactFileScoreParams = [...fileTerms];
2367
+ const sqlParams = [...exactFileScoreParams, ...whereParams, cappedLimit];
2368
+ const rows = this.db.prepare(`
2369
+ SELECT
2370
+ p.id AS part_id,
2371
+ p.message_id AS message_id,
2372
+ m.turn_index AS turn_index,
2373
+ m.role AS role,
2374
+ m.content AS content,
2375
+ m.session_id AS session_id,
2376
+ p.kind AS kind,
2377
+ p.tool_name AS tool_name,
2378
+ p.file_path AS file_path,
2379
+ p.payload AS payload,
2380
+ CASE
2381
+ WHEN p.file_path IN (${fileTerms.map(() => "?").join(",") || "NULL"}) THEN 3
2382
+ WHEN p.file_path IS NOT NULL THEN 2
2383
+ WHEN p.tool_name IS NOT NULL THEN 1
2384
+ ELSE 0
2385
+ END AS score
2386
+ FROM lcm_message_parts p
2387
+ JOIN lcm_messages m ON m.id = p.message_id
2388
+ WHERE ${where.join(" AND ")}
2389
+ ORDER BY score DESC, m.turn_index DESC, p.ordinal ASC
2390
+ LIMIT ?
2391
+ `).all(...sqlParams);
2392
+ return rows;
2393
+ }
1868
2394
  /** Get total message count for a session. */
1869
2395
  getMessageCount(sessionId) {
1870
2396
  const row = this.db.prepare("SELECT COUNT(*) as cnt FROM lcm_messages WHERE session_id = ?").get(sessionId);
@@ -2016,6 +2542,72 @@ var STOPWORDS = /* @__PURE__ */ new Set([
2016
2542
  "we",
2017
2543
  "they"
2018
2544
  ]);
2545
+ function extractStructuredFileTerms(query) {
2546
+ const terms = /* @__PURE__ */ new Set();
2547
+ for (const raw of splitQueryTerms(query)) {
2548
+ const cleaned = trimStructuredQueryTerm(raw);
2549
+ if (cleaned.includes("/") || hasStructuredFileExtension(cleaned)) {
2550
+ terms.add(cleaned);
2551
+ const basename = cleaned.split("/").pop();
2552
+ if (basename && basename !== cleaned) terms.add(basename);
2553
+ }
2554
+ }
2555
+ return [...terms].filter((term) => term.length > 1).slice(0, 12);
2556
+ }
2557
+ function splitQueryTerms(query) {
2558
+ const terms = [];
2559
+ let term = "";
2560
+ for (const char of query.slice(0, 2e4)) {
2561
+ if (char === " " || char === "\n" || char === "\r" || char === " ") {
2562
+ if (term.length > 0) terms.push(term);
2563
+ term = "";
2564
+ continue;
2565
+ }
2566
+ term += char;
2567
+ if (term.length > 512) {
2568
+ terms.push(term);
2569
+ term = "";
2570
+ }
2571
+ }
2572
+ if (term.length > 0) terms.push(term);
2573
+ return terms;
2574
+ }
2575
+ function trimStructuredQueryTerm(raw) {
2576
+ const leading = /* @__PURE__ */ new Set(["`", "'", '"', "(", "[", "{"]);
2577
+ const trailing = /* @__PURE__ */ new Set(["`", "'", '"', ",", ".", "?", "!", ":", ";", ")", "]", "}"]);
2578
+ let start = 0;
2579
+ let end = raw.length;
2580
+ while (start < end && leading.has(raw[start])) start += 1;
2581
+ while (end > start && trailing.has(raw[end - 1])) end -= 1;
2582
+ return raw.slice(start, end);
2583
+ }
2584
+ function hasStructuredFileExtension(value) {
2585
+ const slash = value.lastIndexOf("/");
2586
+ const basename = value.slice(slash + 1);
2587
+ const dot = basename.lastIndexOf(".");
2588
+ if (dot <= 0 || dot === basename.length - 1) return false;
2589
+ const ext = basename.slice(dot + 1);
2590
+ if (ext.length < 1 || ext.length > 12) return false;
2591
+ for (const char of ext) {
2592
+ const code = char.charCodeAt(0);
2593
+ const valid = code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122 || char === "_" || char === "+" || char === "-";
2594
+ if (!valid) return false;
2595
+ }
2596
+ return true;
2597
+ }
2598
+ function extractStructuredToolTerms(query) {
2599
+ const lower = query.toLowerCase();
2600
+ if (!/\b(tool|command|invocation|called|used|ran|read|write|patch|edit|grep|search)\b/.test(lower)) {
2601
+ return [];
2602
+ }
2603
+ return query.replace(/[^\w.-]/g, " ").split(/\s+/).filter((term) => term.length > 2 && !STOPWORDS.has(term.toLowerCase())).slice(0, 8);
2604
+ }
2605
+ function escapeLike(value) {
2606
+ return value.replace(/[\\%_]/g, (char) => `\\${char}`);
2607
+ }
2608
+ function asNullableString(value) {
2609
+ return typeof value === "string" && value.trim().length > 0 ? value : null;
2610
+ }
2019
2611
  function sanitizeFtsQuery(raw) {
2020
2612
  const words = raw.replace(/[^\w\s]/g, " ").split(/\s+/).filter((w) => w.length > 1 && !STOPWORDS.has(w.toLowerCase()));
2021
2613
  if (words.length === 0) {
@@ -2485,7 +3077,9 @@ function extractLcmConfig(cfg) {
2485
3077
  maxDepth: cfg.lcmMaxDepth ?? 5,
2486
3078
  deterministicMaxTokens: cfg.lcmDeterministicMaxTokens ?? 512,
2487
3079
  archiveRetentionDays: cfg.lcmArchiveRetentionDays ?? 90,
2488
- recallBudgetShare: cfg.lcmRecallBudgetShare ?? 0.15
3080
+ recallBudgetShare: cfg.lcmRecallBudgetShare ?? 0.15,
3081
+ messagePartsEnabled: cfg.messagePartsEnabled === true,
3082
+ messagePartsRecallMaxResults: typeof cfg.messagePartsRecallMaxResults === "number" ? Math.max(0, Math.floor(cfg.messagePartsRecallMaxResults)) : 6
2489
3083
  };
2490
3084
  }
2491
3085
  var LcmEngine = class {
@@ -2617,9 +3211,14 @@ var LcmEngine = class {
2617
3211
  const newMessages = messages.map((m, i) => ({
2618
3212
  turnIndex: currentMax + 1 + i,
2619
3213
  role: m.role,
2620
- content: m.content
3214
+ content: m.content,
3215
+ parts: this.config.messagePartsEnabled ? m.parts : void 0,
3216
+ rawContent: this.config.messagePartsEnabled ? m.rawContent : void 0,
3217
+ sourceFormat: this.config.messagePartsEnabled ? m.sourceFormat : void 0
2621
3218
  }));
2622
- this.archive.appendMessages(sessionId, newMessages);
3219
+ this.archive.appendMessages(sessionId, newMessages, {
3220
+ messagePartsEnabled: this.config.messagePartsEnabled
3221
+ });
2623
3222
  try {
2624
3223
  await this.summarizer.summarizeIncremental(sessionId);
2625
3224
  } catch (err) {
@@ -2697,6 +3296,28 @@ var LcmEngine = class {
2697
3296
  budgetChars: effectiveBudget
2698
3297
  });
2699
3298
  }
3299
+ async searchStructuredParts(sessionId, query, limit = this.config.messagePartsRecallMaxResults) {
3300
+ if (!this.config.enabled || !this.config.messagePartsEnabled) return [];
3301
+ await this.ensureInitialized();
3302
+ if (!this.archive) return [];
3303
+ return this.archive.searchStructuredParts(query, limit, sessionId);
3304
+ }
3305
+ formatStructuredRecall(matches, budgetChars) {
3306
+ if (matches.length === 0 || budgetChars <= 0) return "";
3307
+ const lines = [];
3308
+ let used = "## Structured Session Matches\n\n".length;
3309
+ for (const match of matches) {
3310
+ const label = match.file_path ? `${match.kind} ${match.file_path}` : match.tool_name ? `${match.kind} ${match.tool_name}` : match.kind;
3311
+ const excerpt = match.content.replace(/\s+/g, " ").slice(0, 220);
3312
+ const line = `- turn ${match.turn_index} (${match.role}): ${label} \u2014 ${excerpt}`;
3313
+ if (used + line.length + 1 > budgetChars) break;
3314
+ lines.push(line);
3315
+ used += line.length + 1;
3316
+ }
3317
+ return lines.length > 0 ? `## Structured Session Matches
3318
+
3319
+ ${lines.join("\n")}` : "";
3320
+ }
2700
3321
  /** Flush pending summaries before compaction (called from before_compaction hook). */
2701
3322
  async preCompactionFlush(sessionId) {
2702
3323
  if (!this.config.enabled) return;
@@ -4930,7 +5551,7 @@ ${doc.content}` : doc.content,
4930
5551
  }
4931
5552
  async runDeepSleepGovernanceNow(options) {
4932
5553
  const targetStorage = options?.storage ?? this.storage;
4933
- const { runMemoryGovernance } = await import("./memory-governance-KG52RITE.js");
5554
+ const { runMemoryGovernance } = await import("./memory-governance-KXMAURFF.js");
4934
5555
  const { summarizeGovernanceResultForDreams } = await import("./dreams-ledger-LR2NBAZE.js");
4935
5556
  const govResult = await runMemoryGovernance({
4936
5557
  memoryDir: targetStorage.dir,
@@ -7024,6 +7645,7 @@ ${r.snippet.trim()}
7024
7645
  let recalledMemoryIds = [];
7025
7646
  let recalledMemoryPaths = [];
7026
7647
  let xrayRecalledResults = [];
7648
+ const lcmStructuredXrayResults = [];
7027
7649
  const xrayBranchPoolSize = {
7028
7650
  hot_qmd: 0,
7029
7651
  hot_embedding: 0,
@@ -8947,6 +9569,32 @@ ${tmtNode.summary}`
8947
9569
  }
8948
9570
  if (this.lcmEngine?.enabled && recallMode !== "minimal" && recallMode !== "no_recall") {
8949
9571
  try {
9572
+ const structuredMatches = await this.lcmEngine.searchStructuredParts(
9573
+ sessionKey ?? "default",
9574
+ retrievalQuery
9575
+ );
9576
+ const structuredSection = this.lcmEngine.formatStructuredRecall(
9577
+ structuredMatches,
9578
+ Math.ceil(this.config.recallBudgetChars * 0.08)
9579
+ );
9580
+ if (structuredSection) {
9581
+ const structuredAppended = this.appendRecallSection(
9582
+ sectionBuckets,
9583
+ "lcm-message-parts",
9584
+ structuredSection
9585
+ );
9586
+ if (structuredAppended) {
9587
+ for (const match of structuredMatches) {
9588
+ lcmStructuredXrayResults.push({
9589
+ memoryId: `lcm-message-part-${match.part_id}`,
9590
+ path: `lcm://${match.session_id}/turn/${match.turn_index}/part/${match.part_id}`,
9591
+ servedBy: match.file_path ? "lcm-file-parts" : "lcm-tool-parts",
9592
+ scoreDecomposition: { final: match.score },
9593
+ admittedBy: ["lcm-message-parts"]
9594
+ });
9595
+ }
9596
+ }
9597
+ }
8950
9598
  const lcmSection = await this.lcmEngine.assembleRecall(
8951
9599
  sessionKey ?? "default",
8952
9600
  this.config.recallBudgetChars
@@ -9847,10 +10495,17 @@ _Context: ${topQuestion.context}_`
9847
10495
  admitted: recalledMemoryIds.length
9848
10496
  }
9849
10497
  ];
10498
+ if (lcmStructuredXrayResults.length > 0) {
10499
+ filters.push({
10500
+ name: "lcm-message-parts",
10501
+ considered: lcmStructuredXrayResults.length,
10502
+ admitted: lcmStructuredXrayResults.length
10503
+ });
10504
+ }
9850
10505
  this.lastXraySnapshot = buildXraySnapshot({
9851
10506
  query: retrievalQuery,
9852
10507
  tierExplain: null,
9853
- results,
10508
+ results: [...results, ...lcmStructuredXrayResults],
9854
10509
  filters,
9855
10510
  budget: {
9856
10511
  chars: this.getRecallBudgetChars(options.budgetCharsOverride),
@@ -10017,13 +10672,28 @@ _Context: ${topQuestion.context}_`
10017
10672
  role: turn.role,
10018
10673
  content: turn.content,
10019
10674
  timestamp: turn.timestamp,
10020
- sessionKey: key
10675
+ sessionKey: key,
10676
+ parts: turn.parts,
10677
+ rawContent: turn.rawContent,
10678
+ sourceFormat: turn.sourceFormat
10021
10679
  });
10022
10680
  bySession.set(key, list);
10023
10681
  }
10024
10682
  const replayTasks = [];
10025
10683
  for (const [key, sessionTurns] of bySession.entries()) {
10026
10684
  if (sessionTurns.length === 0) continue;
10685
+ if (options.archiveLcm !== false && this.lcmEngine?.enabled) {
10686
+ await this.lcmEngine.observeMessages(
10687
+ key,
10688
+ sessionTurns.map((turn) => ({
10689
+ role: turn.role,
10690
+ content: turn.content,
10691
+ parts: turn.parts,
10692
+ rawContent: turn.rawContent,
10693
+ sourceFormat: turn.sourceFormat
10694
+ }))
10695
+ );
10696
+ }
10027
10697
  replayTasks.push(
10028
10698
  new Promise((resolve, reject) => {
10029
10699
  void this.queueBufferedExtraction(sessionTurns, "trigger_mode", {
@@ -10112,10 +10782,25 @@ _Context: ${topQuestion.context}_`
10112
10782
  role: turn.role,
10113
10783
  content: turn.content,
10114
10784
  timestamp: turn.timestamp,
10115
- sessionKey
10785
+ sessionKey,
10786
+ parts: turn.parts,
10787
+ rawContent: turn.rawContent,
10788
+ sourceFormat: turn.sourceFormat
10116
10789
  });
10117
10790
  }
10118
10791
  if (sessionTurns.length === 0) return;
10792
+ if (this.lcmEngine?.enabled) {
10793
+ await this.lcmEngine.observeMessages(
10794
+ sessionKey,
10795
+ sessionTurns.map((turn) => ({
10796
+ role: turn.role,
10797
+ content: turn.content,
10798
+ parts: turn.parts,
10799
+ rawContent: turn.rawContent,
10800
+ sourceFormat: turn.sourceFormat
10801
+ }))
10802
+ );
10803
+ }
10119
10804
  await new Promise((resolve, reject) => {
10120
10805
  void this.queueBufferedExtraction(sessionTurns, "trigger_mode", {
10121
10806
  skipDedupeCheck: true,
@@ -14034,6 +14719,16 @@ export {
14034
14719
  saveTaxonomy,
14035
14720
  getTaxonomyDir,
14036
14721
  getTaxonomyFilePath,
14722
+ openLcmDatabase,
14723
+ ensureLcmStateDir,
14724
+ applyLcmSchema,
14725
+ isLcmMessagePartKind,
14726
+ parseMessageParts,
14727
+ normalizeExplicitParts,
14728
+ parseOpenAiMessageParts,
14729
+ parseAnthropicMessageParts,
14730
+ parseOpenClawMessageParts,
14731
+ partsFromRenderedText,
14037
14732
  projectNamespaceName,
14038
14733
  branchNamespaceName,
14039
14734
  resolveCodingNamespaceOverlay,
@@ -14066,4 +14761,4 @@ export {
14066
14761
  resolvePersistedMemoryRelativePath,
14067
14762
  Orchestrator
14068
14763
  };
14069
- //# sourceMappingURL=chunk-IM3JSE73.js.map
14764
+ //# sourceMappingURL=chunk-7NFZWXAY.js.map