@remnic/core 1.1.4 → 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 (174) hide show
  1. package/dist/access-cli.js +16 -16
  2. package/dist/access-http.d.ts +7 -7
  3. package/dist/access-http.js +10 -10
  4. package/dist/access-mcp.d.ts +7 -7
  5. package/dist/access-mcp.js +9 -9
  6. package/dist/access-schema.d.ts +89 -4
  7. package/dist/access-schema.js +1 -1
  8. package/dist/{access-service-CtXFnprR.d.ts → access-service-CWYIkMwY.d.ts} +16 -12
  9. package/dist/access-service.d.ts +7 -7
  10. package/dist/access-service.js +7 -7
  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 +3 -3
  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 +3 -3
  24. package/dist/{chunk-F5VQOQ2E.js → chunk-3YBRSJ52.js} +2 -2
  25. package/dist/{chunk-Y4A6M3B6.js → chunk-46AIFPQM.js} +2 -2
  26. package/dist/{chunk-CUI2STX6.js → chunk-4CVIF7UZ.js} +12 -6
  27. package/dist/chunk-4CVIF7UZ.js.map +1 -0
  28. package/dist/{chunk-MUELDH4F.js → chunk-57SNKQNS.js} +2 -2
  29. package/dist/{chunk-EGEPUGN4.js → chunk-5XVDDCMH.js} +2 -2
  30. package/dist/{chunk-NZS2BLTP.js → chunk-7NFZWXAY.js} +711 -22
  31. package/dist/chunk-7NFZWXAY.js.map +1 -0
  32. package/dist/{chunk-XRCYKJ3V.js → chunk-DKVEJTLC.js} +61 -18
  33. package/dist/chunk-DKVEJTLC.js.map +1 -0
  34. package/dist/{chunk-AEMBDV7M.js → chunk-DTDB6YS2.js} +13 -8
  35. package/dist/chunk-DTDB6YS2.js.map +1 -0
  36. package/dist/{chunk-AGZHRWPT.js → chunk-ERWKQVCX.js} +2 -2
  37. package/dist/{chunk-TIFRGAKO.js → chunk-FG5R5AQF.js} +5 -5
  38. package/dist/{chunk-52PDY6GD.js → chunk-FLHPNR5W.js} +2 -2
  39. package/dist/{chunk-JWSENLQI.js → chunk-H62HCANJ.js} +3 -1
  40. package/dist/{chunk-JWSENLQI.js.map → chunk-H62HCANJ.js.map} +1 -1
  41. package/dist/{chunk-W7WWT4FJ.js → chunk-HPJPGIGN.js} +2 -2
  42. package/dist/{chunk-ZIBOQULP.js → chunk-KCZZLFW5.js} +2 -2
  43. package/dist/{chunk-47WOM4YW.js → chunk-MJPNOMY4.js} +2 -2
  44. package/dist/{chunk-HIRKCQGF.js → chunk-OAIXBFAH.js} +17 -17
  45. package/dist/{chunk-HIRKCQGF.js.map → chunk-OAIXBFAH.js.map} +1 -1
  46. package/dist/{chunk-RILIVK4O.js → chunk-RICG4UNC.js} +28 -2
  47. package/dist/chunk-RICG4UNC.js.map +1 -0
  48. package/dist/{chunk-SMA4IMHV.js → chunk-SGTA3HJC.js} +3 -3
  49. package/dist/{chunk-VTJVUHRK.js → chunk-SRBJUAMP.js} +1 -1
  50. package/dist/chunk-SRBJUAMP.js.map +1 -0
  51. package/dist/{chunk-V7TEH5I2.js → chunk-TMPLRVHD.js} +2 -2
  52. package/dist/{chunk-43EKP2UK.js → chunk-TOC3VOOF.js} +1 -1
  53. package/dist/{chunk-43EKP2UK.js.map → chunk-TOC3VOOF.js.map} +1 -1
  54. package/dist/{chunk-USFPPRAF.js → chunk-WMK6YP7C.js} +5 -3
  55. package/dist/chunk-WMK6YP7C.js.map +1 -0
  56. package/dist/{chunk-LW2NMHDW.js → chunk-Y6EPN6XF.js} +2 -2
  57. package/dist/{chunk-XQ4EJLUD.js → chunk-Z665HFAD.js} +2 -2
  58. package/dist/{cli-lMql2FCr.d.ts → cli-CWLyGroU.d.ts} +4 -4
  59. package/dist/cli.d.ts +8 -8
  60. package/dist/cli.js +20 -20
  61. package/dist/{codex-materialize-CQlLTzke.d.ts → codex-materialize-XRen3WAz.d.ts} +1 -1
  62. package/dist/compression-optimizer.d.ts +1 -1
  63. package/dist/config.d.ts +1 -1
  64. package/dist/config.js +1 -1
  65. package/dist/consolidation-provenance-check.d.ts +2 -2
  66. package/dist/consolidation-undo.d.ts +2 -2
  67. package/dist/day-summary.d.ts +1 -1
  68. package/dist/delinearize.d.ts +1 -1
  69. package/dist/direct-answer-wiring.d.ts +1 -1
  70. package/dist/direct-answer.d.ts +1 -1
  71. package/dist/embedding-fallback.d.ts +1 -1
  72. package/dist/{engine-O6YWKQM3.js → engine-WJ7K6AZ2.js} +4 -4
  73. package/dist/entity-retrieval.d.ts +2 -2
  74. package/dist/entity-retrieval.js +3 -3
  75. package/dist/entity-schema.d.ts +1 -1
  76. package/dist/explicit-capture.d.ts +6 -6
  77. package/dist/extraction-judge-telemetry.d.ts +1 -1
  78. package/dist/extraction-judge-training.d.ts +1 -1
  79. package/dist/extraction-judge.d.ts +1 -1
  80. package/dist/extraction.d.ts +1 -1
  81. package/dist/fallback-llm.d.ts +1 -1
  82. package/dist/identity-continuity.d.ts +1 -1
  83. package/dist/importance.d.ts +1 -1
  84. package/dist/index.d.ts +13 -13
  85. package/dist/index.js +38 -24
  86. package/dist/index.js.map +1 -1
  87. package/dist/intent.d.ts +1 -1
  88. package/dist/lifecycle.d.ts +1 -1
  89. package/dist/live-connectors-runner.d.ts +1 -1
  90. package/dist/local-llm.d.ts +1 -1
  91. package/dist/memory-action-policy.d.ts +1 -1
  92. package/dist/memory-cache.d.ts +1 -1
  93. package/dist/{memory-governance-JZHZDOLN.js → memory-governance-KXMAURFF.js} +4 -4
  94. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  95. package/dist/{memory-projection-store-CY8TU40w.d.ts → memory-projection-store-ConH7gNj.d.ts} +1 -1
  96. package/dist/memory-projection-store.d.ts +2 -2
  97. package/dist/memory-worth-outcomes.d.ts +2 -2
  98. package/dist/models-json.d.ts +1 -1
  99. package/dist/native-knowledge.d.ts +1 -1
  100. package/dist/operator-toolkit.d.ts +2 -2
  101. package/dist/operator-toolkit.js +6 -6
  102. package/dist/{orchestrator-ChkesB8U.d.ts → orchestrator-BHkiEBbd.d.ts} +36 -11
  103. package/dist/orchestrator.d.ts +6 -6
  104. package/dist/orchestrator.js +11 -11
  105. package/dist/patterns-cli.d.ts +1 -1
  106. package/dist/policy-runtime.d.ts +1 -1
  107. package/dist/{port-hqGnoStS.d.ts → port-DZHdlUId.d.ts} +1 -1
  108. package/dist/qmd-recall-cache.d.ts +2 -2
  109. package/dist/qmd.d.ts +2 -2
  110. package/dist/recall-disclosure-escalation.d.ts +1 -1
  111. package/dist/recall-explain-renderer.d.ts +1 -1
  112. package/dist/recall-explain-renderer.js +3 -3
  113. package/dist/recall-state.d.ts +1 -1
  114. package/dist/recall-tag-filter.d.ts +1 -1
  115. package/dist/recall-xray-cli.d.ts +1 -1
  116. package/dist/recall-xray-cli.js +4 -4
  117. package/dist/recall-xray-renderer.d.ts +1 -1
  118. package/dist/recall-xray-renderer.js +3 -3
  119. package/dist/recall-xray.d.ts +2 -2
  120. package/dist/recall-xray.js +2 -2
  121. package/dist/resolve-auth-token.d.ts +1 -1
  122. package/dist/resume-bundles.js +2 -2
  123. package/dist/retrieval-agents.d.ts +2 -2
  124. package/dist/retrieval-tiers.d.ts +1 -1
  125. package/dist/schemas.d.ts +32 -32
  126. package/dist/{semantic-consolidation-ByBXb-sf.d.ts → semantic-consolidation-Cxj-inGC.d.ts} +2 -2
  127. package/dist/semantic-consolidation.d.ts +3 -3
  128. package/dist/semantic-consolidation.js +3 -3
  129. package/dist/semantic-rule-promotion.js +3 -3
  130. package/dist/semantic-rule-verifier.d.ts +1 -1
  131. package/dist/semantic-rule-verifier.js +3 -3
  132. package/dist/session-observer-bands.d.ts +1 -1
  133. package/dist/session-observer-state.d.ts +1 -1
  134. package/dist/signal.d.ts +1 -1
  135. package/dist/storage.d.ts +2 -2
  136. package/dist/storage.js +2 -2
  137. package/dist/summarizer.d.ts +1 -1
  138. package/dist/summary-snapshot.d.ts +1 -1
  139. package/dist/temporal-supersession.d.ts +2 -2
  140. package/dist/temporal-validity.d.ts +1 -1
  141. package/dist/threading.d.ts +1 -1
  142. package/dist/tier-migration.d.ts +3 -3
  143. package/dist/tier-routing.d.ts +1 -1
  144. package/dist/topics.d.ts +1 -1
  145. package/dist/transcript.d.ts +1 -1
  146. package/dist/types-B49NzJ5q.d.ts +2707 -0
  147. package/dist/types.d.ts +1 -2668
  148. package/dist/types.js +1 -1
  149. package/dist/utility-runtime.d.ts +1 -1
  150. package/dist/verified-recall.js +3 -3
  151. package/package.json +1 -1
  152. package/dist/chunk-AEMBDV7M.js.map +0 -1
  153. package/dist/chunk-CUI2STX6.js.map +0 -1
  154. package/dist/chunk-NZS2BLTP.js.map +0 -1
  155. package/dist/chunk-RILIVK4O.js.map +0 -1
  156. package/dist/chunk-USFPPRAF.js.map +0 -1
  157. package/dist/chunk-VTJVUHRK.js.map +0 -1
  158. package/dist/chunk-XRCYKJ3V.js.map +0 -1
  159. /package/dist/{chunk-F5VQOQ2E.js.map → chunk-3YBRSJ52.js.map} +0 -0
  160. /package/dist/{chunk-Y4A6M3B6.js.map → chunk-46AIFPQM.js.map} +0 -0
  161. /package/dist/{chunk-MUELDH4F.js.map → chunk-57SNKQNS.js.map} +0 -0
  162. /package/dist/{chunk-EGEPUGN4.js.map → chunk-5XVDDCMH.js.map} +0 -0
  163. /package/dist/{chunk-AGZHRWPT.js.map → chunk-ERWKQVCX.js.map} +0 -0
  164. /package/dist/{chunk-TIFRGAKO.js.map → chunk-FG5R5AQF.js.map} +0 -0
  165. /package/dist/{chunk-52PDY6GD.js.map → chunk-FLHPNR5W.js.map} +0 -0
  166. /package/dist/{chunk-W7WWT4FJ.js.map → chunk-HPJPGIGN.js.map} +0 -0
  167. /package/dist/{chunk-ZIBOQULP.js.map → chunk-KCZZLFW5.js.map} +0 -0
  168. /package/dist/{chunk-47WOM4YW.js.map → chunk-MJPNOMY4.js.map} +0 -0
  169. /package/dist/{chunk-SMA4IMHV.js.map → chunk-SGTA3HJC.js.map} +0 -0
  170. /package/dist/{chunk-V7TEH5I2.js.map → chunk-TMPLRVHD.js.map} +0 -0
  171. /package/dist/{chunk-LW2NMHDW.js.map → chunk-Y6EPN6XF.js.map} +0 -0
  172. /package/dist/{chunk-XQ4EJLUD.js.map → chunk-Z665HFAD.js.map} +0 -0
  173. /package/dist/{engine-O6YWKQM3.js.map → engine-WJ7K6AZ2.js.map} +0 -0
  174. /package/dist/{memory-governance-JZHZDOLN.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-XQ4EJLUD.js";
5
+ } from "./chunk-Z665HFAD.js";
6
6
  import {
7
7
  applyUtilityPromotionRuntimePolicy,
8
8
  applyUtilityRankingRuntimeDelta,
@@ -142,7 +142,7 @@ import {
142
142
  buildEntityRecallSection,
143
143
  entityRecentTranscriptLookbackHours,
144
144
  readRecentEntityTranscriptEntries
145
- } from "./chunk-52PDY6GD.js";
145
+ } from "./chunk-FLHPNR5W.js";
146
146
  import {
147
147
  buildCompressionGuidelinesMarkdown,
148
148
  computeCompressionGuidelineCandidate,
@@ -152,16 +152,16 @@ import {
152
152
  import {
153
153
  RoutingRulesStore,
154
154
  normalizeReplaySessionKey
155
- } from "./chunk-VTJVUHRK.js";
155
+ } from "./chunk-SRBJUAMP.js";
156
156
  import {
157
157
  searchVerifiedEpisodes
158
- } from "./chunk-EGEPUGN4.js";
158
+ } from "./chunk-5XVDDCMH.js";
159
159
  import {
160
160
  ThreadingManager
161
161
  } from "./chunk-JRNQ3RNA.js";
162
162
  import {
163
163
  searchVerifiedSemanticRules
164
- } from "./chunk-W7WWT4FJ.js";
164
+ } from "./chunk-HPJPGIGN.js";
165
165
  import {
166
166
  searchWorkProductLedgerEntries
167
167
  } from "./chunk-CULXMQJH.js";
@@ -181,7 +181,7 @@ import {
181
181
  createConversationIndexRuntime,
182
182
  createSearchBackend,
183
183
  writeConversationChunks
184
- } from "./chunk-V7TEH5I2.js";
184
+ } from "./chunk-TMPLRVHD.js";
185
185
  import {
186
186
  parseQmdExplain
187
187
  } from "./chunk-WSZIHQBK.js";
@@ -228,7 +228,7 @@ import {
228
228
  materializeAfterSemanticConsolidation,
229
229
  parseConsolidationResponse,
230
230
  parseOperatorAwareConsolidationResponse
231
- } from "./chunk-AGZHRWPT.js";
231
+ } from "./chunk-ERWKQVCX.js";
232
232
  import {
233
233
  FallbackLlmClient
234
234
  } from "./chunk-CRU27Q4J.js";
@@ -263,7 +263,7 @@ import {
263
263
  } from "./chunk-EQINRHYR.js";
264
264
  import {
265
265
  buildXraySnapshot
266
- } from "./chunk-USFPPRAF.js";
266
+ } from "./chunk-WMK6YP7C.js";
267
267
  import {
268
268
  shouldSkipImplicitExtraction
269
269
  } from "./chunk-3FPTCC3Z.js";
@@ -303,7 +303,7 @@ import {
303
303
  normalizeAttributePairs,
304
304
  normalizeEntityName,
305
305
  parseEntityFile
306
- } from "./chunk-Y4A6M3B6.js";
306
+ } from "./chunk-46AIFPQM.js";
307
307
  import {
308
308
  attachCitation,
309
309
  hasCitationForTemplate,
@@ -311,7 +311,7 @@ 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";
@@ -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);
@@ -1662,6 +1662,23 @@ function createTables(db) {
1662
1662
  CREATE INDEX IF NOT EXISTS idx_lcm_messages_session
1663
1663
  ON lcm_messages(session_id, turn_index);
1664
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
+
1665
1682
  CREATE TABLE IF NOT EXISTS lcm_summary_nodes (
1666
1683
  id TEXT PRIMARY KEY,
1667
1684
  session_id TEXT NOT NULL,
@@ -1714,6 +1731,423 @@ function createTables(db) {
1714
1731
  );
1715
1732
  }
1716
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
+
1717
2151
  // src/lcm/archive.ts
1718
2152
  function estimateTokens(text) {
1719
2153
  return Math.ceil(text.length / 4);
@@ -1724,7 +2158,7 @@ var LcmArchive = class {
1724
2158
  }
1725
2159
  db;
1726
2160
  /** Append a message to the archive. Returns the row id. */
1727
- appendMessage(sessionId, turnIndex, role, content, metadata) {
2161
+ appendMessage(sessionId, turnIndex, role, content, metadata, parts) {
1728
2162
  const tokenCount = estimateTokens(content);
1729
2163
  const now = (/* @__PURE__ */ new Date()).toISOString();
1730
2164
  const metaJson = metadata ? JSON.stringify(metadata) : null;
@@ -1735,18 +2169,58 @@ var LcmArchive = class {
1735
2169
  const result = stmt.run(sessionId, turnIndex, role, content, tokenCount, now, metaJson);
1736
2170
  const rowId = Number(result.lastInsertRowid);
1737
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
+ }
1738
2175
  return rowId;
1739
2176
  }
1740
2177
  /** Append multiple messages in a single transaction. */
1741
- appendMessages(sessionId, messages) {
2178
+ appendMessages(sessionId, messages, options = {}) {
1742
2179
  if (messages.length === 0) return;
2180
+ const captureMessageParts = options.messagePartsEnabled !== false;
1743
2181
  const txn = this.db.transaction(() => {
1744
2182
  for (const msg of messages) {
1745
- 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
+ );
1746
2197
  }
1747
2198
  });
1748
2199
  txn();
1749
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
+ }
1750
2224
  /** Get the highest turn_index for a session, or -1 if none. */
1751
2225
  getMaxTurnIndex(sessionId) {
1752
2226
  const row = this.db.prepare("SELECT MAX(turn_index) as max_turn FROM lcm_messages WHERE session_id = ?").get(sessionId);
@@ -1868,6 +2342,55 @@ var LcmArchive = class {
1868
2342
  return [];
1869
2343
  }
1870
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
+ }
1871
2394
  /** Get total message count for a session. */
1872
2395
  getMessageCount(sessionId) {
1873
2396
  const row = this.db.prepare("SELECT COUNT(*) as cnt FROM lcm_messages WHERE session_id = ?").get(sessionId);
@@ -2019,6 +2542,72 @@ var STOPWORDS = /* @__PURE__ */ new Set([
2019
2542
  "we",
2020
2543
  "they"
2021
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
+ }
2022
2611
  function sanitizeFtsQuery(raw) {
2023
2612
  const words = raw.replace(/[^\w\s]/g, " ").split(/\s+/).filter((w) => w.length > 1 && !STOPWORDS.has(w.toLowerCase()));
2024
2613
  if (words.length === 0) {
@@ -2488,7 +3077,9 @@ function extractLcmConfig(cfg) {
2488
3077
  maxDepth: cfg.lcmMaxDepth ?? 5,
2489
3078
  deterministicMaxTokens: cfg.lcmDeterministicMaxTokens ?? 512,
2490
3079
  archiveRetentionDays: cfg.lcmArchiveRetentionDays ?? 90,
2491
- 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
2492
3083
  };
2493
3084
  }
2494
3085
  var LcmEngine = class {
@@ -2620,9 +3211,14 @@ var LcmEngine = class {
2620
3211
  const newMessages = messages.map((m, i) => ({
2621
3212
  turnIndex: currentMax + 1 + i,
2622
3213
  role: m.role,
2623
- 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
2624
3218
  }));
2625
- this.archive.appendMessages(sessionId, newMessages);
3219
+ this.archive.appendMessages(sessionId, newMessages, {
3220
+ messagePartsEnabled: this.config.messagePartsEnabled
3221
+ });
2626
3222
  try {
2627
3223
  await this.summarizer.summarizeIncremental(sessionId);
2628
3224
  } catch (err) {
@@ -2700,6 +3296,28 @@ var LcmEngine = class {
2700
3296
  budgetChars: effectiveBudget
2701
3297
  });
2702
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
+ }
2703
3321
  /** Flush pending summaries before compaction (called from before_compaction hook). */
2704
3322
  async preCompactionFlush(sessionId) {
2705
3323
  if (!this.config.enabled) return;
@@ -4933,7 +5551,7 @@ ${doc.content}` : doc.content,
4933
5551
  }
4934
5552
  async runDeepSleepGovernanceNow(options) {
4935
5553
  const targetStorage = options?.storage ?? this.storage;
4936
- const { runMemoryGovernance } = await import("./memory-governance-JZHZDOLN.js");
5554
+ const { runMemoryGovernance } = await import("./memory-governance-KXMAURFF.js");
4937
5555
  const { summarizeGovernanceResultForDreams } = await import("./dreams-ledger-LR2NBAZE.js");
4938
5556
  const govResult = await runMemoryGovernance({
4939
5557
  memoryDir: targetStorage.dir,
@@ -7027,6 +7645,7 @@ ${r.snippet.trim()}
7027
7645
  let recalledMemoryIds = [];
7028
7646
  let recalledMemoryPaths = [];
7029
7647
  let xrayRecalledResults = [];
7648
+ const lcmStructuredXrayResults = [];
7030
7649
  const xrayBranchPoolSize = {
7031
7650
  hot_qmd: 0,
7032
7651
  hot_embedding: 0,
@@ -8950,6 +9569,32 @@ ${tmtNode.summary}`
8950
9569
  }
8951
9570
  if (this.lcmEngine?.enabled && recallMode !== "minimal" && recallMode !== "no_recall") {
8952
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
+ }
8953
9598
  const lcmSection = await this.lcmEngine.assembleRecall(
8954
9599
  sessionKey ?? "default",
8955
9600
  this.config.recallBudgetChars
@@ -9850,10 +10495,17 @@ _Context: ${topQuestion.context}_`
9850
10495
  admitted: recalledMemoryIds.length
9851
10496
  }
9852
10497
  ];
10498
+ if (lcmStructuredXrayResults.length > 0) {
10499
+ filters.push({
10500
+ name: "lcm-message-parts",
10501
+ considered: lcmStructuredXrayResults.length,
10502
+ admitted: lcmStructuredXrayResults.length
10503
+ });
10504
+ }
9853
10505
  this.lastXraySnapshot = buildXraySnapshot({
9854
10506
  query: retrievalQuery,
9855
10507
  tierExplain: null,
9856
- results,
10508
+ results: [...results, ...lcmStructuredXrayResults],
9857
10509
  filters,
9858
10510
  budget: {
9859
10511
  chars: this.getRecallBudgetChars(options.budgetCharsOverride),
@@ -10020,13 +10672,28 @@ _Context: ${topQuestion.context}_`
10020
10672
  role: turn.role,
10021
10673
  content: turn.content,
10022
10674
  timestamp: turn.timestamp,
10023
- sessionKey: key
10675
+ sessionKey: key,
10676
+ parts: turn.parts,
10677
+ rawContent: turn.rawContent,
10678
+ sourceFormat: turn.sourceFormat
10024
10679
  });
10025
10680
  bySession.set(key, list);
10026
10681
  }
10027
10682
  const replayTasks = [];
10028
10683
  for (const [key, sessionTurns] of bySession.entries()) {
10029
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
+ }
10030
10697
  replayTasks.push(
10031
10698
  new Promise((resolve, reject) => {
10032
10699
  void this.queueBufferedExtraction(sessionTurns, "trigger_mode", {
@@ -10115,10 +10782,25 @@ _Context: ${topQuestion.context}_`
10115
10782
  role: turn.role,
10116
10783
  content: turn.content,
10117
10784
  timestamp: turn.timestamp,
10118
- sessionKey
10785
+ sessionKey,
10786
+ parts: turn.parts,
10787
+ rawContent: turn.rawContent,
10788
+ sourceFormat: turn.sourceFormat
10119
10789
  });
10120
10790
  }
10121
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
+ }
10122
10804
  await new Promise((resolve, reject) => {
10123
10805
  void this.queueBufferedExtraction(sessionTurns, "trigger_mode", {
10124
10806
  skipDedupeCheck: true,
@@ -14040,6 +14722,13 @@ export {
14040
14722
  openLcmDatabase,
14041
14723
  ensureLcmStateDir,
14042
14724
  applyLcmSchema,
14725
+ isLcmMessagePartKind,
14726
+ parseMessageParts,
14727
+ normalizeExplicitParts,
14728
+ parseOpenAiMessageParts,
14729
+ parseAnthropicMessageParts,
14730
+ parseOpenClawMessageParts,
14731
+ partsFromRenderedText,
14043
14732
  projectNamespaceName,
14044
14733
  branchNamespaceName,
14045
14734
  resolveCodingNamespaceOverlay,
@@ -14072,4 +14761,4 @@ export {
14072
14761
  resolvePersistedMemoryRelativePath,
14073
14762
  Orchestrator
14074
14763
  };
14075
- //# sourceMappingURL=chunk-NZS2BLTP.js.map
14764
+ //# sourceMappingURL=chunk-7NFZWXAY.js.map