@xopcai/xopc 0.0.207 → 0.0.210

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 (204) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{activity-store-BmpM0zwM.js → activity-store-JLmEb1p0.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DhK5wi6_.js → agent-avatar-dicebear-CI1zQfzY.js} +1 -1
  5. package/dist/gateway/static/root/assets/agents-DqGMj3QJ.js +68 -0
  6. package/dist/gateway/static/root/assets/{api-CzaAcDOn.js → api-C6MmWfcb.js} +1 -1
  7. package/dist/gateway/static/root/assets/app-management-settings-panel-Cd02GGpV.js +1 -0
  8. package/dist/gateway/static/root/assets/appearance-settings-Db-h2I3G.js +1 -0
  9. package/dist/gateway/static/root/assets/apps-page-BT7F4WBI.js +1 -0
  10. package/dist/gateway/static/root/assets/{archive-plugin-CgnzBplN.js → archive-plugin-CMHzJT2a.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-Cuybcmhn.js → attachment-load-BzhI2LoH.js} +1 -1
  12. package/dist/gateway/static/root/assets/automations-page-CwOXGV9z.js +6 -0
  13. package/dist/gateway/static/root/assets/{binary-plugins-D6BBx6Ps.js → binary-plugins-DsUeHvZO.js} +1 -1
  14. package/dist/gateway/static/root/assets/{block-editor-Dk1c3Spa.js → block-editor-CFfsIeZ4.js} +46 -46
  15. package/dist/gateway/static/root/assets/browser-settings-page-CyRLhCod.js +8 -0
  16. package/dist/gateway/static/root/assets/{browser-workflow-inputs-DvfIzCgV.js → browser-workflow-inputs-BiWghvJ0.js} +1 -1
  17. package/dist/gateway/static/root/assets/{browser-workflows-page-DZScuPlF.js → browser-workflows-page-DPLdT6Zn.js} +2 -2
  18. package/dist/gateway/static/root/assets/capabilities-settings-panel-jRKcS7lZ.js +7 -0
  19. package/dist/gateway/static/root/assets/{capability-presets-api-hoA8R_J1.js → capability-presets-api-CTxGFvsS.js} +1 -1
  20. package/dist/gateway/static/root/assets/capability-presets-settings-panel-B3bKdtwU.js +3 -0
  21. package/dist/gateway/static/root/assets/{channel-recipient-api-BS8I65NT.js → channel-recipient-api-BklVUOxC.js} +1 -1
  22. package/dist/gateway/static/root/assets/channels-settings-yZBWH02s.js +1 -0
  23. package/dist/gateway/static/root/assets/channels-status-swr-C3zlimZd.js +1 -0
  24. package/dist/gateway/static/root/assets/chat-terminal-dock-0F4Jmma2.js +36 -0
  25. package/dist/gateway/static/root/assets/{connectors-api-B_78jmvM.js → connectors-api-BvIZ51ty.js} +1 -1
  26. package/dist/gateway/static/root/assets/connectors-page-OX4KvUkA.js +2 -0
  27. package/dist/gateway/static/root/assets/{cron-expression-BBheaBIr.js → cron-expression-BHmwaMbO.js} +1 -1
  28. package/dist/gateway/static/root/assets/{date-picker-CDwj7UrT.js → date-picker-fj_pPCv5.js} +1 -1
  29. package/dist/gateway/static/root/assets/{dependency-picker-Dnrc2qZe.js → dependency-picker-DsWvwOv-.js} +1 -1
  30. package/dist/gateway/static/root/assets/{desktop-pet-Bj_vUjXp.js → desktop-pet-mjkF0Xxh.js} +1 -1
  31. package/dist/gateway/static/root/assets/desktop-pet-settings-ClwUpRYu.js +1 -0
  32. package/dist/gateway/static/root/assets/directory-picker-path-field-OkqRFyRL.js +1 -0
  33. package/dist/gateway/static/root/assets/{extension-debug-page-_GZ4y2da.js → extension-debug-page-DC69wplH.js} +1 -1
  34. package/dist/gateway/static/root/assets/{extension-page-scR96Edg.js → extension-page-DCtk6zdJ.js} +1 -1
  35. package/dist/gateway/static/root/assets/extension-settings-page-Bkm4zzv-.js +1 -0
  36. package/dist/gateway/static/root/assets/{gateway-config-api-984O_4wM.js → gateway-config-api-Dr_NQt7v.js} +1 -1
  37. package/dist/gateway/static/root/assets/{gateway-config-swr-D4hvsdJA.js → gateway-config-swr-CEfv8N1J.js} +1 -1
  38. package/dist/gateway/static/root/assets/gateway-settings-V1XVxjHa.js +1 -0
  39. package/dist/gateway/static/root/assets/{gateway-startup-retry-Deo5-O87.js → gateway-startup-retry-B8hebJ7s.js} +1 -1
  40. package/dist/gateway/static/root/assets/heartbeat-settings-CWUBAQrE.js +1 -0
  41. package/dist/gateway/static/root/assets/home-page-D57cYRd3.js +1 -0
  42. package/dist/gateway/static/root/assets/index-DJ7HSgKs.js +85 -0
  43. package/dist/gateway/static/root/assets/index-PNBFdxHb.css +2 -0
  44. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-DGmOlNcB.js → keyboard-shortcuts-settings-DCQvf05d.js} +1 -1
  45. package/dist/gateway/static/root/assets/local-app-workbench-page-BbAiMZE1.js +2 -0
  46. package/dist/gateway/static/root/assets/{local-apps-page-CzS2sCxg.js → local-apps-page-B3Ugd0my.js} +1 -1
  47. package/dist/gateway/static/root/assets/{locale-store-C7xtkP3D.js → locale-store-hDBVeG3G.js} +1 -1
  48. package/dist/gateway/static/root/assets/logs-page-nXdF3wOT.js +2 -0
  49. package/dist/gateway/static/root/assets/{management-settings-Cpxs43JB.js → management-settings-C-S5Llq3.js} +1 -1
  50. package/dist/gateway/static/root/assets/{markdown-split-CQvFHxUa.js → markdown-split-DuVq37Uh.js} +1 -1
  51. package/dist/gateway/static/root/assets/{markdown-view-BRwrSbwM.js → markdown-view-D8eO_6h3.js} +1 -1
  52. package/dist/gateway/static/root/assets/{media-plugins-Bs9MsiaM.js → media-plugins-C1V6pkX3.js} +1 -1
  53. package/dist/gateway/static/root/assets/messages-1qg_hOOd.js +3 -0
  54. package/dist/gateway/static/root/assets/{notes-page-Dux_g6aZ.js → notes-page-Dn71ZV8c.js} +1 -1
  55. package/dist/gateway/static/root/assets/notes-workbench-BYPoZeRw.js +4 -0
  56. package/dist/gateway/static/root/assets/page-tabs-B5a5aSoS.js +1 -0
  57. package/dist/gateway/static/root/assets/preview-open-alternatives-5041AIBX.js +1 -0
  58. package/dist/gateway/static/root/assets/{product-open-page-f_jbg-9N.js → product-open-page-7UkouFQU.js} +1 -1
  59. package/dist/gateway/static/root/assets/project-detail-page-D27nOKbo.js +1 -0
  60. package/dist/gateway/static/root/assets/projects-page-CdB5cJJ-.js +1 -0
  61. package/dist/gateway/static/root/assets/remote-access-hub-DFoZ3UNS.js +1 -0
  62. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-zapSiJrv.js → runtime-tools-settings-panel-DvaXzHYS.js} +2 -2
  63. package/dist/gateway/static/root/assets/{schema-form-CFyz8y5v.js → schema-form-Dlxl_5X0.js} +1 -1
  64. package/dist/gateway/static/root/assets/sessions-page-C1cbIcJ7.js +1 -0
  65. package/dist/gateway/static/root/assets/settings-advanced-gate-DnXRlQXS.js +1 -0
  66. package/dist/gateway/static/root/assets/settings-form-section-CSaiuuer.js +1 -0
  67. package/dist/gateway/static/root/assets/{settings-loading-skeleton-DFUJEv4G.js → settings-loading-skeleton-H3mJwt3r.js} +1 -1
  68. package/dist/gateway/static/root/assets/{settings-page-Cnp9Bdd0.js → settings-page-Cs7zA4BS.js} +1 -1
  69. package/dist/gateway/static/root/assets/setup-status-panel-CwgMODfJ.js +1 -0
  70. package/dist/gateway/static/root/assets/{share-preview-page-DA8nA4cz.js → share-preview-page-Bdpw5m7M.js} +1 -1
  71. package/dist/gateway/static/root/assets/shares-settings-hlUgIkrp.js +1 -0
  72. package/dist/gateway/static/root/assets/skill-reload-api-DR31B_Gz.js +1 -0
  73. package/dist/gateway/static/root/assets/skills-page-Bup3Lg1Z.js +2 -0
  74. package/dist/gateway/static/root/assets/{skills-page.utils--1-vOg3V.js → skills-page.utils-D22ORR21.js} +1 -1
  75. package/dist/gateway/static/root/assets/system-settings-panel-GmtWsfjB.js +1 -0
  76. package/dist/gateway/static/root/assets/task-detail-page-CTKDpxhf.js +1 -0
  77. package/dist/gateway/static/root/assets/{theme-store-DoyRfkoi.js → theme-store-CtY8RwMX.js} +1 -1
  78. package/dist/gateway/static/root/assets/typed-models-lib-C2aOdlEA.js +1 -0
  79. package/dist/gateway/static/root/assets/{use-autosave-DzIR5Lxf.js → use-autosave-DOj5i8d_.js} +1 -1
  80. package/dist/gateway/static/root/assets/user-context-page-keJJYpix.js +1 -0
  81. package/dist/gateway/static/root/assets/{voice-api-key-field-B7MZS8tS.js → voice-api-key-field-5WfurWYa.js} +1 -1
  82. package/dist/gateway/static/root/assets/{work-discovery-overlay-zyX6yxxF.js → work-discovery-overlay-D5_MH3n3.js} +1 -1
  83. package/dist/gateway/static/root/assets/work-discovery-page-BcvBiebt.js +1 -0
  84. package/dist/gateway/static/root/assets/workflow-run-setup-panel-bBA8LinI.js +3 -0
  85. package/dist/gateway/static/root/assets/workflows-page-Cz2VpWdj.js +5 -0
  86. package/dist/gateway/static/root/index.html +11 -15
  87. package/dist/package.js +1 -1
  88. package/dist/src/agent/agent-manager.js +2 -2
  89. package/dist/src/agent/background-review/coordinator.d.ts +1 -1
  90. package/dist/src/agent/background-review/coordinator.js +4 -5
  91. package/dist/src/agent/background-review/run-background-review.js +0 -1
  92. package/dist/src/agent/background-review/settings.d.ts +1 -2
  93. package/dist/src/agent/background-review/settings.js +3 -4
  94. package/dist/src/agent/external-tools/composio-provider.js +8 -4
  95. package/dist/src/agent/memory/builtin-provider.js +1 -1
  96. package/dist/src/agent/memory/create-memory-manager.js +1 -1
  97. package/dist/src/agent/memory/manager.js +2 -0
  98. package/dist/src/agent/memory/sensitivity.js +1 -1
  99. package/dist/src/agent/memory/understanding/service.js +43 -19
  100. package/dist/src/agent/memory/user-context-coordinator.js +1 -1
  101. package/dist/src/agent-runtime/index.js +1 -1
  102. package/dist/src/agent-runtime/runtime-profile.js +1 -1
  103. package/dist/src/automations/domain/validation.d.ts +7 -7
  104. package/dist/src/automations/draft/automation-draft-validator.d.ts +2 -2
  105. package/dist/src/connectors/auth-provider-registry.d.ts +2 -1
  106. package/dist/src/connectors/auth-provider-registry.js +5 -2
  107. package/dist/src/connectors/composio-sessions.d.ts +38 -0
  108. package/dist/src/connectors/composio-sessions.js +64 -6
  109. package/dist/src/connectors/composio.d.ts +4 -1
  110. package/dist/src/connectors/composio.js +26 -4
  111. package/dist/src/connectors/runtime-adapter-registry.js +14 -1
  112. package/dist/src/gateway/hono/routes/agent-stream.js +4 -1
  113. package/dist/src/gateway/hono/routes/connectors.js +15 -2
  114. package/dist/src/gateway/hono/routes/session-input-handler.d.ts +60 -0
  115. package/dist/src/gateway/hono/routes/session-input-handler.js +75 -1
  116. package/dist/src/gateway/service/agent-runner.d.ts +9 -1
  117. package/dist/src/gateway/service/agent-runner.js +9 -0
  118. package/dist/src/gateway/service/session-input-coordinator.d.ts +12 -0
  119. package/dist/src/gateway/service/session-input-coordinator.js +64 -6
  120. package/dist/src/gateway/service.d.ts +8 -0
  121. package/dist/src/gateway/service.js +8 -5
  122. package/dist/src/retrieval/audit.d.ts +1 -0
  123. package/dist/src/retrieval/audit.js +8 -0
  124. package/dist/src/retrieval/candidateFusion.d.ts +5 -0
  125. package/dist/src/retrieval/candidateFusion.js +20 -0
  126. package/dist/src/retrieval/queryProfile.d.ts +16 -0
  127. package/dist/src/retrieval/queryProfile.js +66 -0
  128. package/dist/src/retrieval/textFeatures.d.ts +5 -0
  129. package/dist/src/retrieval/textFeatures.js +71 -0
  130. package/dist/src/session/client-history.d.ts +1 -0
  131. package/dist/src/session/client-history.js +4 -0
  132. package/dist/src/session/index.js +1 -1
  133. package/dist/src/session/store.js +1 -1
  134. package/dist/src/storage/sqlite/fts.d.ts +0 -4
  135. package/dist/src/storage/sqlite/fts.js +2 -49
  136. package/dist/src/storage/sqlite/index.d.ts +3 -2
  137. package/dist/src/storage/sqlite/index.js +6 -5
  138. package/dist/src/storage/sqlite/memory-records-repository.js +60 -38
  139. package/dist/src/storage/sqlite/row-mappers.js +2 -2
  140. package/dist/src/storage/sqlite/session-repository.js +2 -2
  141. package/dist/src/storage/sqlite/session-turn-replace-repository.d.ts +34 -0
  142. package/dist/src/storage/sqlite/session-turn-replace-repository.js +110 -0
  143. package/dist/src/storage/sqlite/transcript-repository.js +1 -1
  144. package/dist/src/storage/sqlite/user-context-quality-repository.d.ts +7 -0
  145. package/dist/src/storage/sqlite/user-context-quality-repository.js +25 -1
  146. package/dist/src/storage/sqlite/user-context-repository.d.ts +4 -0
  147. package/dist/src/storage/sqlite/user-context-repository.js +29 -3
  148. package/dist/src/tasks/home-query-service.d.ts +3 -1
  149. package/dist/src/tasks/home-query-service.js +73 -70
  150. package/dist/src/tui/backends/embedded-backend.js +1 -1
  151. package/dist/src/user-context/planner.d.ts +1 -0
  152. package/dist/src/user-context/planner.js +16 -29
  153. package/dist/src/user-context/retriever.d.ts +15 -0
  154. package/dist/src/user-context/retriever.js +65 -0
  155. package/dist/src/user-context/scope.d.ts +7 -0
  156. package/dist/src/user-context/scope.js +9 -0
  157. package/package.json +3 -3
  158. package/dist/gateway/static/root/assets/agents-Bc3Lc-n2.js +0 -68
  159. package/dist/gateway/static/root/assets/app-management-settings-panel-Dqj5G_cd.js +0 -1
  160. package/dist/gateway/static/root/assets/appearance-settings-Bm1uLGMi.js +0 -1
  161. package/dist/gateway/static/root/assets/apps-page-BKtwU47-.js +0 -1
  162. package/dist/gateway/static/root/assets/automations-page-ilGeRLDN.js +0 -6
  163. package/dist/gateway/static/root/assets/browser-settings-page-BCu8AZbs.js +0 -8
  164. package/dist/gateway/static/root/assets/capabilities-settings-panel-BbWQBtTe.js +0 -7
  165. package/dist/gateway/static/root/assets/capability-presets-settings-panel-BTVU46Yn.js +0 -3
  166. package/dist/gateway/static/root/assets/channels-settings-BEQsC9a9.js +0 -1
  167. package/dist/gateway/static/root/assets/channels-status-swr-DRwbgtOT.js +0 -1
  168. package/dist/gateway/static/root/assets/chat-terminal-dock-BIPhWBDI.js +0 -36
  169. package/dist/gateway/static/root/assets/connectors-page-w_3kpqbc.js +0 -2
  170. package/dist/gateway/static/root/assets/desktop-pet-settings-uiCwJJk4.js +0 -1
  171. package/dist/gateway/static/root/assets/directory-picker-path-field-D0zUQ-TO.js +0 -1
  172. package/dist/gateway/static/root/assets/extension-settings-page-CILsAwxx.js +0 -1
  173. package/dist/gateway/static/root/assets/form-field-width-DJw_jULe.js +0 -1
  174. package/dist/gateway/static/root/assets/gateway-settings-aF4eQHo3.js +0 -1
  175. package/dist/gateway/static/root/assets/heartbeat-settings-D5DrFWH6.js +0 -1
  176. package/dist/gateway/static/root/assets/home-page-DiMWxngC.js +0 -3
  177. package/dist/gateway/static/root/assets/index-DzKLVgY-.js +0 -85
  178. package/dist/gateway/static/root/assets/index-wR5jX-lw.css +0 -2
  179. package/dist/gateway/static/root/assets/interaction-BmQogeqz.js +0 -1
  180. package/dist/gateway/static/root/assets/local-app-workbench-page-De8vuwu1.js +0 -2
  181. package/dist/gateway/static/root/assets/logs-page-BI9stsVO.js +0 -2
  182. package/dist/gateway/static/root/assets/messages-Dxk5Rzj_.js +0 -3
  183. package/dist/gateway/static/root/assets/notes-workbench-CGafcgJ8.js +0 -4
  184. package/dist/gateway/static/root/assets/page-tabs-BaEQMYm_.js +0 -1
  185. package/dist/gateway/static/root/assets/preview-open-alternatives-fvhtN4Y2.js +0 -1
  186. package/dist/gateway/static/root/assets/project-detail-page-C6mNsjYr.js +0 -1
  187. package/dist/gateway/static/root/assets/projects-page-D1G6VIxR.js +0 -1
  188. package/dist/gateway/static/root/assets/remote-access-hub-CIez6X0x.js +0 -1
  189. package/dist/gateway/static/root/assets/sessions-page-6irxQjHb.js +0 -1
  190. package/dist/gateway/static/root/assets/settings-advanced-gate-CRb0QTG2.js +0 -1
  191. package/dist/gateway/static/root/assets/settings-form-draft-Dy10ldo8.js +0 -1
  192. package/dist/gateway/static/root/assets/settings-form-section-DCiK4TIq.js +0 -1
  193. package/dist/gateway/static/root/assets/setup-status-panel-BFMGTGBO.js +0 -1
  194. package/dist/gateway/static/root/assets/shares-settings-CaKfvJzQ.js +0 -1
  195. package/dist/gateway/static/root/assets/skill-reload-api-BOBUcYr5.js +0 -1
  196. package/dist/gateway/static/root/assets/skills-page-BJJACxzz.js +0 -2
  197. package/dist/gateway/static/root/assets/system-settings-panel-DY0lIaXY.js +0 -1
  198. package/dist/gateway/static/root/assets/task-detail-page-Ciuwe7AG.js +0 -1
  199. package/dist/gateway/static/root/assets/typed-models-lib-q5-Vfqd8.js +0 -1
  200. package/dist/gateway/static/root/assets/user-context-page-yf18T_BZ.js +0 -1
  201. package/dist/gateway/static/root/assets/work-discovery-page-2e5J0sIp.js +0 -1
  202. package/dist/gateway/static/root/assets/workflow-run-setup-panel-Cj1vPWRM.js +0 -3
  203. package/dist/gateway/static/root/assets/workflows-page-D37zWlWY.js +0 -5
  204. package/dist/gateway/static/root/assets/working-directory-picker-modal-Bm7cox3y.js +0 -1
@@ -2,8 +2,8 @@ import { init_paths_state, resolveStateDir } from "../config/paths-state.js";
2
2
  import { createLogger } from "../utils/logger/index.js";
3
3
  import { init_logger } from "../utils/logger.js";
4
4
  import { requireXopcDatabase } from "../storage/sqlite/connection.js";
5
- import "./types.js";
6
5
  import { buildSessionContextForLlm, buildSessionDisplayMessages, isRuntimeOnlyTranscriptMessage, isTranscriptCompactionEntry, mergeLlmMessagesPreservingContextRows, transcriptRowsFromJsonArray } from "./session-context-for-llm.js";
6
+ import "./types.js";
7
7
  import { estimateTokensFromMessages } from "../storage/sqlite/row-mappers.js";
8
8
  import { deleteSessionRecord, ensureSessionRecord, findSessionKeyBySessionId, getGlobalSessionStats, getSessionMetadata, listSessionMetadata, listSessionsByAgent, patchSessionMetadata, resetSessionRecord } from "../storage/sqlite/session-repository.js";
9
9
  import { appendCompactionBoundaryIfUnchanged, appendTranscriptEntry, listCompactionBoundaries, loadCompactionSourceSnapshot, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRowsForSession, paginateTranscriptMessages, replaceTranscriptRows, restoreBeforeCompactionBoundary, searchSessionTranscript } from "../storage/sqlite/transcript-repository.js";
@@ -4,7 +4,3 @@ export declare function escapeFts5Query(raw: string): string;
4
4
  export declare function buildFts5SearchQuery(raw: string): string;
5
5
  /** Normalize FTS5 BM25 ranks, where a more-negative rank is a better match. */
6
6
  export declare function fts5RankToScore(rank: number, bestRank: number, worstRank: number): number;
7
- /** Bounded lexical fallback for reformulations unsupported by unicode61 tokenization. */
8
- export declare function memoryLexicalSimilarity(query: string, content: string): number;
9
- /** Local deterministic embedding used to complement FTS without network or model coupling. */
10
- export declare function memoryVectorSimilarity(query: string, content: string): number;
@@ -40,7 +40,7 @@ const FTS_SEARCH_STOP_WORDS = new Set([
40
40
  ]);
41
41
  /** Build a syntax-safe, recall-oriented query for natural-language memory search. */
42
42
  function buildFts5SearchQuery(raw) {
43
- const terms = raw.normalize("NFKC").match(/[\p{L}\p{N}_]+/gu)?.map((term) => term.toLocaleLowerCase()).filter((term) => term.length > 1 && !FTS_SEARCH_STOP_WORDS.has(term));
43
+ const terms = raw.normalize("NFKC").match(/[\p{L}\p{N}_]+/gu)?.map((term) => term.toLowerCase()).filter((term) => term.length > 1 && !FTS_SEARCH_STOP_WORDS.has(term));
44
44
  if (!terms?.length) return escapeFts5Query(raw);
45
45
  return [...new Set(terms)].slice(0, 12).map((term) => escapeFts5Query(term)).join(" OR ");
46
46
  }
@@ -55,52 +55,5 @@ function fts5RankToScore(rank, bestRank, worstRank) {
55
55
  const normalized = (worstRank - rank) / (worstRank - bestRank);
56
56
  return .5 + .5 * Math.max(0, Math.min(1, normalized));
57
57
  }
58
- function lexicalFeatures(raw) {
59
- const normalized = raw.normalize("NFKC").toLocaleLowerCase();
60
- const features = /* @__PURE__ */ new Set();
61
- for (const term of normalized.match(/[\p{L}\p{N}_]+/gu) ?? []) if (term.length > 1 && !FTS_SEARCH_STOP_WORDS.has(term)) features.add(`word:${term}`);
62
- for (const sequence of normalized.match(/\p{Script=Han}+/gu) ?? []) {
63
- const chars = [...sequence];
64
- for (let index = 0; index < chars.length - 1; index += 1) features.add(`han:${chars[index]}${chars[index + 1]}`);
65
- }
66
- return features;
67
- }
68
- /** Bounded lexical fallback for reformulations unsupported by unicode61 tokenization. */
69
- function memoryLexicalSimilarity(query, content) {
70
- const queryFeatures = lexicalFeatures(query);
71
- const contentFeatures = lexicalFeatures(content);
72
- if (queryFeatures.size === 0 || contentFeatures.size === 0) return 0;
73
- let shared = 0;
74
- for (const feature of queryFeatures) if (contentFeatures.has(feature)) shared += 1;
75
- return 2 * shared / (queryFeatures.size + contentFeatures.size);
76
- }
77
- const VECTOR_SIZE = 128;
78
- function featureVector(raw) {
79
- const vector = new Float64Array(VECTOR_SIZE);
80
- const normalized = raw.normalize("NFKC").toLocaleLowerCase();
81
- const features = [...(normalized.match(/[\p{L}\p{N}_]+/gu) ?? []).map((term) => `w:${term}`), ...[...normalized].map((char, index, chars) => chars.slice(index, index + 3).join("")).filter((value) => value.trim().length >= 2).map((value) => `c:${value}`)];
82
- for (const feature of features) {
83
- let hash = 2166136261;
84
- for (const char of feature) hash = Math.imul(hash ^ char.codePointAt(0), 16777619);
85
- const index = (hash >>> 0) % VECTOR_SIZE;
86
- vector[index] += (hash & 1) === 0 ? 1 : -1;
87
- }
88
- return vector;
89
- }
90
- /** Local deterministic embedding used to complement FTS without network or model coupling. */
91
- function memoryVectorSimilarity(query, content) {
92
- const left = featureVector(query);
93
- const right = featureVector(content);
94
- let dot = 0;
95
- let leftNorm = 0;
96
- let rightNorm = 0;
97
- for (let index = 0; index < VECTOR_SIZE; index += 1) {
98
- dot += left[index] * right[index];
99
- leftNorm += left[index] ** 2;
100
- rightNorm += right[index] ** 2;
101
- }
102
- if (leftNorm === 0 || rightNorm === 0) return 0;
103
- return Math.max(0, dot / Math.sqrt(leftNorm * rightNorm));
104
- }
105
58
  //#endregion
106
- export { buildFts5SearchQuery, escapeFts5Query, fts5RankToScore, memoryLexicalSimilarity, memoryVectorSimilarity };
59
+ export { buildFts5SearchQuery, escapeFts5Query, fts5RankToScore };
@@ -6,9 +6,10 @@ export { discoverSqlMigrations, listRegisteredMigrationTargets } from './migrati
6
6
  export { closeXopcDatabase, getXopcDatabase, isXopcDatabaseOpen, openXopcDatabase, requireXopcDatabase, resetXopcDatabaseSingletonForTest, type OpenXopcDatabaseOptions, type XopcDatabase, } from './connection.js';
7
7
  export { getSqliteDatabase, runSqliteWriteTransaction } from './transaction.js';
8
8
  export { finishContextConsolidationRun, getContextConsolidationRun, listContextConsolidationDecisions, listContextConsolidationRuns, recordContextConsolidationDecision, startContextConsolidationRun, type ContextConsolidationDecision, type ContextConsolidationRun, } from './context-consolidation-repository.js';
9
- export { summarizeUserUnderstandingQuality, type UserUnderstandingQualityMetrics, } from './user-context-quality-repository.js';
10
- export { createCollaborationRule, createContextEvidence, createUnderstanding, consumeContextConsent, deleteCollaborationRule, deleteUnderstanding, decideContextConsent, ensureContextConsent, getCollaborationRule, getTurnPersonalization, getUnderstanding, getUserProfile, hasContextConsent, isUnderstandingSuppressed, listCollaborationRules, listUnderstandingEvidence, listUnderstandings, linkUnderstandingEvidence, recordContextFeedback, recordContextRun, rejectUnderstanding, reviseCollaborationRule, reviseUnderstanding, setCollaborationRuleStatus, setUnderstandingStatus, updateUserProfile, type CreateUnderstandingInput, } from './user-context-repository.js';
9
+ export { summarizeUnderstandingFeedback, summarizeUserUnderstandingQuality, type UnderstandingFeedbackSummary, type UserUnderstandingQualityMetrics, } from './user-context-quality-repository.js';
10
+ export { createCollaborationRule, createContextEvidence, createUnderstanding, consumeContextConsent, deleteCollaborationRule, deleteUnderstanding, decideContextConsent, ensureContextConsent, getCollaborationRule, getTurnPersonalization, getUnderstanding, getUserProfile, hasContextConsent, isUnderstandingSuppressed, listCollaborationRules, listUnderstandingEvidence, listUnderstandings, linkUnderstandingEvidence, recordContextFeedback, recordContextRun, rejectUnderstanding, reviseCollaborationRule, reviseUnderstanding, searchActiveUnderstandings, setCollaborationRuleStatus, setUnderstandingStatus, updateUserProfile, type CreateUnderstandingInput, } from './user-context-repository.js';
11
11
  export { cancelQueuedSessionInput, claimNextSessionInput, findSessionInput, finishSessionInputRun, getSessionInputState, insertSessionInput, mutateQueuedSessionInput, recoverSessionInputState, setSessionInputStatus, type SessionInput, type SessionInputDelivery, type SessionInputState, type SessionInputStatus, } from './session-input-repository.js';
12
+ export { replaceLatestSessionTurnAndQueueInput, validateLatestSessionTurnTarget, type ReplaceLatestSessionTurnInput, type ReplaceLatestSessionTurnResult, } from './session-turn-replace-repository.js';
12
13
  export { acknowledgeHomeAttention, isHomeAttentionAcknowledged, type HomeAttentionSubjectKind, } from './home-attention-repository.js';
13
14
  export { claimNextConnectorLearningJob, enqueueConnectorLearningJob, listConnectorLearningJobs, recoverStaleConnectorLearningJobs, setConnectorLearningPaused, updateConnectorLearningJob, type ConnectorLearningJob, type ConnectorLearningMode, type ConnectorLearningPhase, type ConnectorLearningStatus, } from './connector-learning-repository.js';
14
15
  export { appendComposerInputHistory, clearComposerInputHistory, listComposerInputHistory, COMPOSER_INPUT_HISTORY_LIMIT, type ComposerInputHistoryItem, } from './composer-input-history-repository.js';
@@ -7,17 +7,18 @@ import { ensureXopcDatabaseSchema } from "./schema.js";
7
7
  import { closeXopcDatabase, getXopcDatabase, isXopcDatabaseOpen, openXopcDatabase, requireXopcDatabase, resetXopcDatabaseSingletonForTest } from "./connection.js";
8
8
  import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
9
9
  import { finishContextConsolidationRun, getContextConsolidationRun, listContextConsolidationDecisions, listContextConsolidationRuns, recordContextConsolidationDecision, startContextConsolidationRun } from "./context-consolidation-repository.js";
10
- import { summarizeUserUnderstandingQuality } from "./user-context-quality-repository.js";
11
- import { consumeContextConsent, createCollaborationRule, createContextEvidence, createUnderstanding, decideContextConsent, deleteCollaborationRule, deleteUnderstanding, ensureContextConsent, getCollaborationRule, getTurnPersonalization, getUnderstanding, getUserProfile, hasContextConsent, isUnderstandingSuppressed, linkUnderstandingEvidence, listCollaborationRules, listUnderstandingEvidence, listUnderstandings, recordContextFeedback, recordContextRun, rejectUnderstanding, reviseCollaborationRule, reviseUnderstanding, setCollaborationRuleStatus, setUnderstandingStatus, updateUserProfile } from "./user-context-repository.js";
10
+ import { summarizeUnderstandingFeedback, summarizeUserUnderstandingQuality } from "./user-context-quality-repository.js";
11
+ import { consumeContextConsent, createCollaborationRule, createContextEvidence, createUnderstanding, decideContextConsent, deleteCollaborationRule, deleteUnderstanding, ensureContextConsent, getCollaborationRule, getTurnPersonalization, getUnderstanding, getUserProfile, hasContextConsent, isUnderstandingSuppressed, linkUnderstandingEvidence, listCollaborationRules, listUnderstandingEvidence, listUnderstandings, recordContextFeedback, recordContextRun, rejectUnderstanding, reviseCollaborationRule, reviseUnderstanding, searchActiveUnderstandings, setCollaborationRuleStatus, setUnderstandingStatus, updateUserProfile } from "./user-context-repository.js";
12
12
  import { cancelQueuedSessionInput, claimNextSessionInput, findSessionInput, finishSessionInputRun, getSessionInputState, insertSessionInput, mutateQueuedSessionInput, recoverSessionInputState, setSessionInputStatus } from "./session-input-repository.js";
13
+ import { buildDefaultSessionMetadata } from "./session-metadata.js";
14
+ import { buildGlobalSessionStats, classifyStoredRow, estimateTokensFromMessages, extractFtsContent, metadataToSessionInsert, sessionConfigRowToConfig, sessionRowToMetadata, transcriptEntryRowToStoredRow } from "./row-mappers.js";
15
+ import { replaceLatestSessionTurnAndQueueInput, validateLatestSessionTurnTarget } from "./session-turn-replace-repository.js";
13
16
  import { acknowledgeHomeAttention, isHomeAttentionAcknowledged } from "./home-attention-repository.js";
14
17
  import { claimNextConnectorLearningJob, enqueueConnectorLearningJob, listConnectorLearningJobs, recoverStaleConnectorLearningJobs, setConnectorLearningPaused, updateConnectorLearningJob } from "./connector-learning-repository.js";
15
18
  import { COMPOSER_INPUT_HISTORY_LIMIT, appendComposerInputHistory, clearComposerInputHistory, listComposerInputHistory } from "./composer-input-history-repository.js";
16
19
  import { bindEndpointPrincipal, createEndpointPrincipal, getEndpointPrincipal, listEndpointPrincipals, revokeEndpointPrincipal, touchEndpointPrincipal } from "./endpoint-principal-repository.js";
17
20
  import { finishEndpointToolInvocationAudit, listEndpointToolInvocationAudits, startEndpointToolInvocationAudit } from "./endpoint-tool-invocation-repository.js";
18
21
  import { getInteractionState, setInteractionState, updateInteractionStateFromMessage } from "./interaction-state-repository.js";
19
- import { buildDefaultSessionMetadata } from "./session-metadata.js";
20
- import { buildGlobalSessionStats, classifyStoredRow, estimateTokensFromMessages, extractFtsContent, metadataToSessionInsert, sessionConfigRowToConfig, sessionRowToMetadata, transcriptEntryRowToStoredRow } from "./row-mappers.js";
21
22
  import { deleteSessionRecord, ensureSessionRecord, findSessionKeyBySessionId, getCurrentSessionId, getGlobalSessionStats, getSessionMetadata, getSessionPersistedLevels, incrementSessionStatsOnAppend, listSessionMetadata, listSessionsByAgent, patchSessionMetadata, resetSessionRecord, resolveSessionAgentId, updateSessionStats } from "./session-repository.js";
22
23
  import { getSessionTaskPlan, setSessionTaskPlan } from "./session-task-plan-repository.js";
23
24
  import { buildRelationshipPrompt, getRelationshipSettings, isProactiveSupportAllowed, updateRelationshipSettings } from "./relationship-settings-repository.js";
@@ -32,4 +33,4 @@ import { appendConnectorExecutionAudit, claimConnectorWebhookDelivery, completeC
32
33
  import { getConnectorAccount, listConnectorAccounts, reconcileConnectorAccount, refreshConnectorAccountCurrent } from "./connector-account-repository.js";
33
34
  import { getConnectorSyncPolicy, getConnectorSyncPolicyForConnection, listConnectorSyncPolicies, upsertConnectorSyncPolicy } from "./connector-sync-policy-repository.js";
34
35
  import { getUserTrustPolicy, setUserTrustPolicy } from "./user-trust-repository.js";
35
- export { COMPOSER_INPUT_HISTORY_LIMIT, DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError, SCHEMA_META_SCHEMA_VERSION_KEY, XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_FILENAME, XOPC_DB_SCHEMA_VERSION, acknowledgeHomeAttention, appendCompactionBoundaryIfUnchanged, appendComposerInputHistory, appendConnectorExecutionAudit, appendMemorySignal, appendMemoryTraceEvent, appendTranscriptEntry, applyPendingMigrations, attachMemoryEvidence, bindEndpointPrincipal, buildDefaultSessionMetadata, buildGlobalSessionStats, buildRelationshipPrompt, cancelQueuedSessionInput, claimConnectorWebhookDelivery, claimKnowledgeSourceItems, claimNextConnectorLearningJob, claimNextSessionInput, classifyStoredRow, clearComposerInputHistory, closeXopcDatabase, completeConnectorWebhookDelivery, completeKnowledgeSourceItemSynthesis, consumeConnectorApproval, consumeContextConsent, createCollaborationRule, createConnectorApproval, createContextEvidence, createEndpointPrincipal, createObjectLinkRecord, createUnderstanding, decideConnectorApproval, decideContextConsent, deleteCollaborationRule, deleteConnectorConnection, deleteConnectorInstallation, deleteMemoryEvidenceForRecord, deleteMemoryRecord, deleteNoteAgentContextRecord, deleteNoteRecord, deleteObjectLinkRecord, deleteSessionConfig, deleteSessionRecord, deleteUnderstanding, discoverSqlMigrations, enqueueConnectorLearningJob, ensureContextConsent, ensureSessionRecord, ensureXopcDatabaseSchema, estimateTokensFromMessages, extractFtsContent, findSessionInput, findSessionKeyBySessionId, finishContextConsolidationRun, finishEndpointToolInvocationAudit, finishKnowledgeSyncRun, finishSessionInputRun, getActivityEventRecord, getCachedConnectorCatalogEntry, getCollaborationRule, getConnectorAccount, getConnectorApproval, getConnectorConnection, getConnectorInstallation, getConnectorSyncPolicy, getConnectorSyncPolicyForConnection, getContextConsolidationRun, getCurrentSessionId, getEndpointPrincipal, getGlobalSessionStats, getInteractionState, getKnowledgeConsumerWatermark, getKnowledgeSourceCursor, getKnowledgeSourceItem, getMemoryProviderState, getMemoryRecord, getMemoryTurnFeedback, getNoteAgentContextRecord, getNoteRecord, getRelationshipSettings, getSessionConfig, getSessionInputState, getSessionMetadata, getSessionPersistedLevels, getSessionTaskPlan, getSqliteDatabase, getTurnPersonalization, getUnderstanding, getUserProfile, getUserTrustPolicy, getXopcDatabase, hasContextConsent, hasSessionConfig, hasUnresolvedMemoryConflict, incrementSessionStatsOnAppend, insertSessionInput, inspectSchemaMigrationStatus, isHomeAttentionAcknowledged, isProactiveSupportAllowed, isUnderstandingSuppressed, isXopcDatabaseOpen, linkUnderstandingEvidence, listActivityRecords, listCachedConnectorCatalogEntries, listCollaborationRules, listCompactionBoundaries, listComposerInputHistory, listConnectorAccounts, listConnectorActionMetadata, listConnectorApprovals, listConnectorConnections, listConnectorExecutionAudit, listConnectorInstallations, listConnectorLearningJobs, listConnectorSyncPolicies, listContextConsolidationDecisions, listContextConsolidationRuns, listEndpointPrincipals, listEndpointToolInvocationAudits, listKnowledgeSourceChanges, listKnowledgeSourceItems, listKnowledgeSyncRuns, listMemoryEvidence, listMemoryRecords, listMemorySignals, listMemoryTraceEvents, listNoteRecords, listObjectActivityRecords, listObjectLinkRecords, listProjectActivityRecords, listRegisteredMigrationTargets, listSessionMetadata, listSessionsByAgent, listUnderstandingEvidence, listUnderstandings, loadCompactionSourceSnapshot, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, markMemoryRecordsConflicted, metadataToSessionInsert, mutateQueuedSessionInput, openXopcDatabase, paginateTranscriptMessages, patchSessionMetadata, pruneBoundedKnowledgeSourceItems, readSchemaVersion, readSchemaVersionForTest, reconcileConnectorAccount, recordActivityEvent, recordContextConsolidationDecision, recordContextFeedback, recordContextRun, recoverSessionInputState, recoverStaleConnectorLearningJobs, refreshConnectorAccountCurrent, rejectUnderstanding, releaseConnectorWebhookDelivery, replaceConnectorCatalogEntries, replaceTranscriptRows, requireXopcDatabase, resetSessionRecord, resetXopcDatabaseSingletonForTest, resolveMigrationsDir, resolveSessionAgentId, resolveXopcDatabasePath, restoreBeforeCompactionBoundary, reviseCollaborationRule, reviseUnderstanding, revokeEndpointPrincipal, runSqliteWriteTransaction, searchMemoryRecords, searchSessionTranscript, sessionConfigRowToConfig, sessionRowToMetadata, setCollaborationRuleStatus, setConnectorLearningPaused, setInteractionState, setKnowledgeConsumerWatermark, setKnowledgeSourceCursor, setKnowledgeSourceItemSynthesisStatus, setMemoryProviderState, setMemoryRecordStatus, setMemoryTurnFeedback, setSessionConfig, setSessionInputStatus, setSessionTaskPlan, setUnderstandingStatus, setUserTrustPolicy, startContextConsolidationRun, startEndpointToolInvocationAudit, startKnowledgeSyncRun, summarizeMemoryRecallFeedback, summarizeUserUnderstandingQuality, touchEndpointPrincipal, transcriptEntryRowToStoredRow, updateConnectorLearningJob, updateInteractionStateFromMessage, updateRelationshipSettings, updateSessionConfig, updateSessionStats, updateUserProfile, upsertConnectorActionMetadata, upsertConnectorCatalogEntry, upsertConnectorConnection, upsertConnectorInstallation, upsertConnectorSyncPolicy, upsertKnowledgeSourceItems, upsertMemoryRecord, upsertNoteAgentContextRecord, upsertNoteRecord };
36
+ export { COMPOSER_INPUT_HISTORY_LIMIT, DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError, SCHEMA_META_SCHEMA_VERSION_KEY, XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_FILENAME, XOPC_DB_SCHEMA_VERSION, acknowledgeHomeAttention, appendCompactionBoundaryIfUnchanged, appendComposerInputHistory, appendConnectorExecutionAudit, appendMemorySignal, appendMemoryTraceEvent, appendTranscriptEntry, applyPendingMigrations, attachMemoryEvidence, bindEndpointPrincipal, buildDefaultSessionMetadata, buildGlobalSessionStats, buildRelationshipPrompt, cancelQueuedSessionInput, claimConnectorWebhookDelivery, claimKnowledgeSourceItems, claimNextConnectorLearningJob, claimNextSessionInput, classifyStoredRow, clearComposerInputHistory, closeXopcDatabase, completeConnectorWebhookDelivery, completeKnowledgeSourceItemSynthesis, consumeConnectorApproval, consumeContextConsent, createCollaborationRule, createConnectorApproval, createContextEvidence, createEndpointPrincipal, createObjectLinkRecord, createUnderstanding, decideConnectorApproval, decideContextConsent, deleteCollaborationRule, deleteConnectorConnection, deleteConnectorInstallation, deleteMemoryEvidenceForRecord, deleteMemoryRecord, deleteNoteAgentContextRecord, deleteNoteRecord, deleteObjectLinkRecord, deleteSessionConfig, deleteSessionRecord, deleteUnderstanding, discoverSqlMigrations, enqueueConnectorLearningJob, ensureContextConsent, ensureSessionRecord, ensureXopcDatabaseSchema, estimateTokensFromMessages, extractFtsContent, findSessionInput, findSessionKeyBySessionId, finishContextConsolidationRun, finishEndpointToolInvocationAudit, finishKnowledgeSyncRun, finishSessionInputRun, getActivityEventRecord, getCachedConnectorCatalogEntry, getCollaborationRule, getConnectorAccount, getConnectorApproval, getConnectorConnection, getConnectorInstallation, getConnectorSyncPolicy, getConnectorSyncPolicyForConnection, getContextConsolidationRun, getCurrentSessionId, getEndpointPrincipal, getGlobalSessionStats, getInteractionState, getKnowledgeConsumerWatermark, getKnowledgeSourceCursor, getKnowledgeSourceItem, getMemoryProviderState, getMemoryRecord, getMemoryTurnFeedback, getNoteAgentContextRecord, getNoteRecord, getRelationshipSettings, getSessionConfig, getSessionInputState, getSessionMetadata, getSessionPersistedLevels, getSessionTaskPlan, getSqliteDatabase, getTurnPersonalization, getUnderstanding, getUserProfile, getUserTrustPolicy, getXopcDatabase, hasContextConsent, hasSessionConfig, hasUnresolvedMemoryConflict, incrementSessionStatsOnAppend, insertSessionInput, inspectSchemaMigrationStatus, isHomeAttentionAcknowledged, isProactiveSupportAllowed, isUnderstandingSuppressed, isXopcDatabaseOpen, linkUnderstandingEvidence, listActivityRecords, listCachedConnectorCatalogEntries, listCollaborationRules, listCompactionBoundaries, listComposerInputHistory, listConnectorAccounts, listConnectorActionMetadata, listConnectorApprovals, listConnectorConnections, listConnectorExecutionAudit, listConnectorInstallations, listConnectorLearningJobs, listConnectorSyncPolicies, listContextConsolidationDecisions, listContextConsolidationRuns, listEndpointPrincipals, listEndpointToolInvocationAudits, listKnowledgeSourceChanges, listKnowledgeSourceItems, listKnowledgeSyncRuns, listMemoryEvidence, listMemoryRecords, listMemorySignals, listMemoryTraceEvents, listNoteRecords, listObjectActivityRecords, listObjectLinkRecords, listProjectActivityRecords, listRegisteredMigrationTargets, listSessionMetadata, listSessionsByAgent, listUnderstandingEvidence, listUnderstandings, loadCompactionSourceSnapshot, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, markMemoryRecordsConflicted, metadataToSessionInsert, mutateQueuedSessionInput, openXopcDatabase, paginateTranscriptMessages, patchSessionMetadata, pruneBoundedKnowledgeSourceItems, readSchemaVersion, readSchemaVersionForTest, reconcileConnectorAccount, recordActivityEvent, recordContextConsolidationDecision, recordContextFeedback, recordContextRun, recoverSessionInputState, recoverStaleConnectorLearningJobs, refreshConnectorAccountCurrent, rejectUnderstanding, releaseConnectorWebhookDelivery, replaceConnectorCatalogEntries, replaceLatestSessionTurnAndQueueInput, replaceTranscriptRows, requireXopcDatabase, resetSessionRecord, resetXopcDatabaseSingletonForTest, resolveMigrationsDir, resolveSessionAgentId, resolveXopcDatabasePath, restoreBeforeCompactionBoundary, reviseCollaborationRule, reviseUnderstanding, revokeEndpointPrincipal, runSqliteWriteTransaction, searchActiveUnderstandings, searchMemoryRecords, searchSessionTranscript, sessionConfigRowToConfig, sessionRowToMetadata, setCollaborationRuleStatus, setConnectorLearningPaused, setInteractionState, setKnowledgeConsumerWatermark, setKnowledgeSourceCursor, setKnowledgeSourceItemSynthesisStatus, setMemoryProviderState, setMemoryRecordStatus, setMemoryTurnFeedback, setSessionConfig, setSessionInputStatus, setSessionTaskPlan, setUnderstandingStatus, setUserTrustPolicy, startContextConsolidationRun, startEndpointToolInvocationAudit, startKnowledgeSyncRun, summarizeMemoryRecallFeedback, summarizeUnderstandingFeedback, summarizeUserUnderstandingQuality, touchEndpointPrincipal, transcriptEntryRowToStoredRow, updateConnectorLearningJob, updateInteractionStateFromMessage, updateRelationshipSettings, updateSessionConfig, updateSessionStats, updateUserProfile, upsertConnectorActionMetadata, upsertConnectorCatalogEntry, upsertConnectorConnection, upsertConnectorInstallation, upsertConnectorSyncPolicy, upsertKnowledgeSourceItems, upsertMemoryRecord, upsertNoteAgentContextRecord, upsertNoteRecord, validateLatestSessionTurnTarget };
@@ -1,9 +1,18 @@
1
1
  import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
2
- import { buildFts5SearchQuery, fts5RankToScore, memoryLexicalSimilarity, memoryVectorSimilarity } from "./fts.js";
2
+ import { buildFts5SearchQuery } from "./fts.js";
3
3
  import { LOCAL_USER_ID } from "../../user-context/owner.js";
4
+ import { fuseRankedCandidates } from "../../retrieval/candidateFusion.js";
5
+ import { normalizeRetrievalText, retrievalLexicalSimilarity } from "../../retrieval/textFeatures.js";
6
+ import { buildRetrievalQueryProfile } from "../../retrieval/queryProfile.js";
4
7
  import { listMemoryEvidence, listMemoryEvidenceForRecords, replaceMemoryEvidenceForRecord } from "./knowledge-repository.js";
5
8
  import { randomUUID } from "node:crypto";
6
9
  //#region src/storage/sqlite/memory-records-repository.ts
10
+ function memoryFeedbackAdjustment(summary) {
11
+ if (!summary || summary.total < 3) return 0;
12
+ const helpfulRate = (summary.helpful + 1) / (summary.total + 2);
13
+ const relevancePenalty = summary.irrelevant >= 3 ? .05 : 0;
14
+ return Math.max(-.1, Math.min(.05, (helpfulRate - .5) * .1 - relevancePenalty));
15
+ }
7
16
  function parseStringArray(json) {
8
17
  try {
9
18
  const parsed = JSON.parse(json);
@@ -285,7 +294,12 @@ function listMemoryRecords(options = {}) {
285
294
  LIMIT ? OFFSET ?`).all(...params, limit, offset));
286
295
  }
287
296
  function searchMemoryRecords(options) {
288
- const query = buildFts5SearchQuery(options.query);
297
+ const profile = buildRetrievalQueryProfile(options.query, {
298
+ ...options.visibleToSessionKey ? { sessionKey: options.visibleToSessionKey } : {},
299
+ ...options.visibleToWorkspaceId ?? options.workspaceId ? { workspaceId: options.visibleToWorkspaceId ?? options.workspaceId } : {},
300
+ ...options.visibleToProjectId ?? options.projectId ? { projectId: options.visibleToProjectId ?? options.projectId } : {}
301
+ });
302
+ const query = buildFts5SearchQuery(profile.normalized);
289
303
  if (!query) return [];
290
304
  const filters = ["memory_records_fts MATCH ?"];
291
305
  const params = [query];
@@ -330,6 +344,7 @@ function searchMemoryRecords(options) {
330
344
  params.push(...statuses);
331
345
  const maxResults = Math.max(1, Math.min(50, options.maxResults ?? 5));
332
346
  const minScore = options.minScore ?? 0;
347
+ const candidateLimit = Math.max(50, Math.min(200, maxResults * 10));
333
348
  const rows = getSqliteDatabase().prepare(`SELECT
334
349
  r.*,
335
350
  bm25(memory_records_fts) AS rank
@@ -337,7 +352,7 @@ function searchMemoryRecords(options) {
337
352
  JOIN memory_records r ON r.record_id = f.record_id
338
353
  WHERE ${filters.join(" AND ")}
339
354
  ORDER BY rank
340
- LIMIT ?`).all(...params, maxResults * 3);
355
+ LIMIT ?`).all(...params, candidateLimit);
341
356
  const candidateRecords = listMemoryRecords({
342
357
  providerId: options.providerId,
343
358
  userId: options.userId,
@@ -352,40 +367,44 @@ function searchMemoryRecords(options) {
352
367
  unscopedWorkspaceOnly: options.unscopedWorkspaceOnly,
353
368
  limit: 500
354
369
  }).filter((record) => statuses.includes(record.status ?? "active") && (!options.kinds?.length || options.kinds.includes(record.kind)));
355
- const byId = /* @__PURE__ */ new Map();
356
370
  const candidateById = new Map(candidateRecords.map((record) => [record.id, record]));
357
- const missingEvidence = listMemoryEvidenceForRecords(rows.filter((row) => !candidateById.has(row.record_id)).map((row) => row.record_id));
358
- if (rows.length > 0) {
359
- const bestRank = Math.min(...rows.map((row) => row.rank));
360
- const worstRank = Math.max(...rows.map((row) => row.rank));
361
- for (const row of rows) {
362
- const record = candidateById.get(row.record_id) ?? rowToRecord(row, missingEvidence.get(row.record_id) ?? []);
363
- byId.set(record.id, {
364
- record,
365
- score: fts5RankToScore(row.rank, bestRank, worstRank) * .65,
366
- snippet: record.content,
367
- citation: {
368
- providerId: row.provider_id,
369
- recordId: row.record_id,
370
- path: record.source.path,
371
- lineStart: record.source.lineStart,
372
- lineEnd: record.source.lineEnd,
373
- createdAt: record.createdAt
374
- }
375
- });
371
+ const missingRows = rows.filter((row) => !candidateById.has(row.record_id));
372
+ const missingEvidence = listMemoryEvidenceForRecords(missingRows.map((row) => row.record_id));
373
+ const recordById = new Map(candidateRecords.map((record) => [record.id, record]));
374
+ for (const row of missingRows) recordById.set(row.record_id, rowToRecord(row, missingEvidence.get(row.record_id) ?? []));
375
+ const lexical = candidateRecords.map((record) => ({
376
+ id: record.id,
377
+ score: retrievalLexicalSimilarity(profile.normalized, record.content)
378
+ })).filter((result) => result.score > 0).sort((left, right) => right.score - left.score).slice(0, candidateLimit);
379
+ const fused = fuseRankedCandidates([
380
+ {
381
+ weight: 1.4,
382
+ ids: (profile.identifiers.length ? candidateRecords.map((record) => {
383
+ const content = normalizeRetrievalText(record.content);
384
+ return {
385
+ id: record.id,
386
+ matches: profile.identifiers.filter((identifier) => content.includes(identifier)).length
387
+ };
388
+ }).filter((result) => result.matches > 0).sort((left, right) => right.matches - left.matches).slice(0, candidateLimit) : []).map((result) => result.id)
389
+ },
390
+ {
391
+ weight: 1,
392
+ ids: rows.map((row) => row.record_id)
393
+ },
394
+ {
395
+ weight: .8,
396
+ ids: lexical.map((result) => result.id)
376
397
  }
377
- }
378
- for (const record of candidateRecords) {
379
- const vector = memoryVectorSimilarity(options.query, record.content);
380
- const lexical = memoryLexicalSimilarity(options.query, record.content);
381
- const existing = byId.get(record.id);
382
- const score = existing ? Math.min(1, existing.score + vector * .25 + lexical * .1) : Math.max(vector, lexical);
383
- byId.set(record.id, existing ? {
384
- ...existing,
385
- score
386
- } : {
398
+ ]);
399
+ const feedback = new Map(summarizeMemoryRecallFeedback({ limit: 1e3 }).map((summary) => [summary.recordId, summary]));
400
+ return [...fused.entries()].map(([id, fusionScore]) => {
401
+ const record = recordById.get(id);
402
+ if (!record) return null;
403
+ const kindBonus = profile.intentKinds.includes(record.kind) ? .08 : 0;
404
+ const authorityBonus = record.explicitness === "explicit" ? .03 : 0;
405
+ return {
387
406
  record,
388
- score,
407
+ score: Math.max(0, Math.min(1, fusionScore * .85 + kindBonus + authorityBonus + record.importance * .04 + memoryFeedbackAdjustment(feedback.get(record.id)))),
389
408
  snippet: record.content,
390
409
  citation: {
391
410
  providerId: record.providerId,
@@ -395,9 +414,8 @@ function searchMemoryRecords(options) {
395
414
  lineEnd: record.source.lineEnd,
396
415
  createdAt: record.createdAt
397
416
  }
398
- });
399
- }
400
- return [...byId.values()].filter((result) => result.score >= minScore).sort((left, right) => right.score - left.score).slice(0, maxResults);
417
+ };
418
+ }).filter((result) => Boolean(result)).filter((result) => result.score >= minScore).sort((left, right) => right.score - left.score).slice(0, maxResults);
401
419
  }
402
420
  function deleteMemoryRecord(recordId) {
403
421
  return runSqliteWriteTransaction((db) => {
@@ -566,7 +584,11 @@ function setMemoryTurnFeedback(input) {
566
584
  ON CONFLICT DO UPDATE SET rating = excluded.rating, score = excluded.score,
567
585
  reason_code = excluded.reason_code, note = excluded.note, updated_at = excluded.updated_at`);
568
586
  upsert.run(randomUUID(), trace.trace_id, turnId, null, "response", input.rating, typeof input.score === "number" ? Math.max(-1, Math.min(1, input.score)) : null, input.reasonCode?.trim().slice(0, 200) || null, input.note?.trim().slice(0, 2e3) || null, source, nowMs, nowMs);
569
- for (const item of records) upsert.run(randomUUID(), trace.trace_id, turnId, item.recordId, "record", item.rating, null, item.reasonCode?.trim().slice(0, 200) || null, item.note?.trim().slice(0, 2e3) || null, source, nowMs, nowMs);
587
+ for (const item of records) {
588
+ upsert.run(randomUUID(), trace.trace_id, turnId, item.recordId, "record", item.rating, null, item.reasonCode?.trim().slice(0, 200) || null, item.note?.trim().slice(0, 2e3) || null, source, nowMs, nowMs);
589
+ if (item.rating === "incorrect" || item.rating === "sensitive") db.prepare("UPDATE memory_records SET status = 'needs_review', updated_at = ? WHERE record_id = ?").run(nowMs, item.recordId);
590
+ else if (item.rating === "outdated") db.prepare("UPDATE memory_records SET status = 'stale', updated_at = ? WHERE record_id = ?").run(nowMs, item.recordId);
591
+ }
570
592
  });
571
593
  return memoryTraceRowToPayload(trace);
572
594
  }
@@ -1,7 +1,7 @@
1
- import "../../session/types.js";
2
- import { buildDefaultSessionMetadata } from "./session-metadata.js";
3
1
  import { isTranscriptContextEntry } from "../../session/session-context-for-llm.js";
2
+ import "../../session/types.js";
4
3
  import { init_agent_session_key, resolveAgentIdFromSessionKey } from "../../routing/agent-session-key.js";
4
+ import { buildDefaultSessionMetadata } from "./session-metadata.js";
5
5
  //#region src/storage/sqlite/row-mappers.ts
6
6
  init_agent_session_key();
7
7
  function parseJson(raw) {
@@ -1,8 +1,8 @@
1
1
  import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
2
- import { validateSessionId } from "../../session/session-id.js";
2
+ import { escapeFts5Query } from "./fts.js";
3
3
  import { buildDefaultSessionMetadata } from "./session-metadata.js";
4
4
  import { buildGlobalSessionStats, metadataToSessionInsert, sessionRowToMetadata } from "./row-mappers.js";
5
- import { escapeFts5Query } from "./fts.js";
5
+ import { validateSessionId } from "../../session/session-id.js";
6
6
  import { randomUUID } from "node:crypto";
7
7
  //#region src/storage/sqlite/session-repository.ts
8
8
  const SESSION_COLUMNS = `
@@ -0,0 +1,34 @@
1
+ import type { AgentMessage } from '@earendil-works/pi-agent-core';
2
+ import type { TurnOrigin } from '@xopcai/endpoint-tools-protocol';
3
+ export type ReplaceLatestSessionTurnInput = {
4
+ sessionKey: string;
5
+ targetTurnId: string;
6
+ clientMessageId: string;
7
+ content: string;
8
+ attachments?: unknown[];
9
+ thinking?: string;
10
+ origin: TurnOrigin;
11
+ };
12
+ export type ReplaceLatestSessionTurnResult = {
13
+ ok: true;
14
+ idempotent: boolean;
15
+ inputId: string;
16
+ removedMessages: AgentMessage[];
17
+ remainingMessages: AgentMessage[];
18
+ } | {
19
+ ok: false;
20
+ code: 'TARGET_NOT_FOUND' | 'NOT_LATEST' | 'SESSION_BUSY';
21
+ };
22
+ /** Validate before aborting a run; the transactional mutation validates again. */
23
+ export declare function validateLatestSessionTurnTarget(sessionKey: string, targetTurnId: string): {
24
+ ok: true;
25
+ } | {
26
+ ok: false;
27
+ code: 'TARGET_NOT_FOUND' | 'NOT_LATEST';
28
+ };
29
+ /**
30
+ * Replace the latest persisted user turn with a durable queued input.
31
+ * Transcript deletion and input insertion share one SQLite transaction so a
32
+ * failed enqueue cannot leave the conversation without the original turn.
33
+ */
34
+ export declare function replaceLatestSessionTurnAndQueueInput(input: ReplaceLatestSessionTurnInput): ReplaceLatestSessionTurnResult;
@@ -0,0 +1,110 @@
1
+ import { getXopcDatabase } from "./connection.js";
2
+ import { runSqliteWriteTransaction } from "./transaction.js";
3
+ import { buildSessionContextForLlm, buildSessionDisplayMessages } from "../../session/session-context-for-llm.js";
4
+ import { estimateTokensFromMessages, transcriptEntryRowToStoredRow } from "./row-mappers.js";
5
+ import { randomUUID } from "node:crypto";
6
+ //#region src/storage/sqlite/session-turn-replace-repository.ts
7
+ function isUserRow(row) {
8
+ return row.role === "user";
9
+ }
10
+ function rowTurnId(row) {
11
+ const value = row.turnId;
12
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
13
+ }
14
+ function validateTargetRows(rows, targetTurnId) {
15
+ const targetIndex = rows.findIndex((row) => row.role === "user" && rowTurnId(row) === targetTurnId);
16
+ if (targetIndex < 0) return {
17
+ ok: false,
18
+ code: "TARGET_NOT_FOUND"
19
+ };
20
+ if (rows.slice(targetIndex + 1).some(isUserRow)) return {
21
+ ok: false,
22
+ code: "NOT_LATEST"
23
+ };
24
+ return {
25
+ ok: true,
26
+ targetIndex
27
+ };
28
+ }
29
+ /** Validate before aborting a run; the transactional mutation validates again. */
30
+ function validateLatestSessionTurnTarget(sessionKey, targetTurnId) {
31
+ const { db } = getXopcDatabase();
32
+ const session = db.prepare(`SELECT session_id FROM sessions WHERE session_key = ?`).get(sessionKey);
33
+ if (!session) return {
34
+ ok: false,
35
+ code: "TARGET_NOT_FOUND"
36
+ };
37
+ const result = validateTargetRows(db.prepare(`SELECT entry_id, session_id, seq, entry_kind, role, payload_json, created_at
38
+ FROM transcript_entries WHERE session_id = ? ORDER BY seq ASC`).all(session.session_id).map(transcriptEntryRowToStoredRow), targetTurnId);
39
+ return result.ok ? { ok: true } : result;
40
+ }
41
+ /**
42
+ * Replace the latest persisted user turn with a durable queued input.
43
+ * Transcript deletion and input insertion share one SQLite transaction so a
44
+ * failed enqueue cannot leave the conversation without the original turn.
45
+ */
46
+ function replaceLatestSessionTurnAndQueueInput(input) {
47
+ return runSqliteWriteTransaction((db) => {
48
+ const existing = db.prepare(`SELECT id FROM session_inputs WHERE session_key = ? AND client_message_id = ?`).get(input.sessionKey, input.clientMessageId);
49
+ if (existing) return {
50
+ ok: true,
51
+ idempotent: true,
52
+ inputId: existing.id,
53
+ removedMessages: [],
54
+ remainingMessages: []
55
+ };
56
+ const session = db.prepare(`SELECT session_id FROM sessions WHERE session_key = ?`).get(input.sessionKey);
57
+ if (!session) return {
58
+ ok: false,
59
+ code: "TARGET_NOT_FOUND"
60
+ };
61
+ db.prepare(`INSERT INTO session_input_runtime(session_key, revision, updated_at_ms)
62
+ VALUES (?, 0, ?) ON CONFLICT(session_key) DO NOTHING`).run(input.sessionKey, Date.now());
63
+ const runtime = db.prepare(`SELECT active_run_id FROM session_input_runtime WHERE session_key = ?`).get(input.sessionKey);
64
+ const pending = db.prepare(`SELECT 1 AS found FROM session_inputs
65
+ WHERE session_key = ? AND status IN ('queued', 'running', 'injecting', 'interrupted')
66
+ LIMIT 1`).get(input.sessionKey);
67
+ if (runtime?.active_run_id || pending) return {
68
+ ok: false,
69
+ code: "SESSION_BUSY"
70
+ };
71
+ const entries = db.prepare(`SELECT entry_id, session_id, seq, entry_kind, role, payload_json, created_at
72
+ FROM transcript_entries WHERE session_id = ? ORDER BY seq ASC`).all(session.session_id);
73
+ const target = validateTargetRows(entries.map(transcriptEntryRowToStoredRow), input.targetTurnId);
74
+ if (target.ok === false) return target;
75
+ const targetSeq = entries[target.targetIndex].seq;
76
+ const removedEntries = entries.filter((entry) => entry.seq >= targetSeq && entry.entry_kind !== "compaction");
77
+ const remainingEntries = entries.filter((entry) => entry.seq < targetSeq && entry.entry_kind !== "compaction");
78
+ const deleteEntries = entries.filter((entry) => entry.seq >= targetSeq || entry.entry_kind === "compaction");
79
+ const removedRows = removedEntries.map(transcriptEntryRowToStoredRow);
80
+ const remainingRows = remainingEntries.map(transcriptEntryRowToStoredRow);
81
+ const deleteFts = db.prepare(`DELETE FROM transcript_fts WHERE entry_id = ?`);
82
+ const deleteEntry = db.prepare(`DELETE FROM transcript_entries WHERE entry_id = ?`);
83
+ for (const entry of deleteEntries) {
84
+ deleteFts.run(entry.entry_id);
85
+ deleteEntry.run(entry.entry_id);
86
+ }
87
+ const llm = buildSessionContextForLlm(remainingRows);
88
+ const now = Date.now();
89
+ db.prepare(`UPDATE sessions SET message_count = ?, estimated_tokens = ?, compacted_count = 0,
90
+ updated_at = ?, last_accessed_at = ?, last_interaction_at = ? WHERE session_key = ?`).run(llm.length, estimateTokensFromMessages(llm), now, now, now, input.sessionKey);
91
+ const maxPosition = db.prepare(`SELECT COALESCE(MAX(position), 0) AS value FROM session_inputs
92
+ WHERE session_key = ? AND status IN ('queued', 'running', 'injecting', 'interrupted')`).get(input.sessionKey);
93
+ const inputId = randomUUID();
94
+ db.prepare(`INSERT INTO session_inputs(id, session_key, client_message_id,
95
+ requested_delivery, effective_delivery, status, content, attachments_json,
96
+ thinking, origin_json, position, target_run_id, version, created_at_ms, updated_at_ms)
97
+ VALUES (?, ?, ?, 'next', 'next', 'queued', ?, ?, ?, ?, ?, NULL, 1, ?, ?)`).run(inputId, input.sessionKey, input.clientMessageId, input.content, input.attachments ? JSON.stringify(input.attachments) : null, input.thinking ?? null, JSON.stringify(input.origin), maxPosition.value + 1, now, now);
98
+ db.prepare(`UPDATE session_input_runtime SET revision = revision + 1, updated_at_ms = ?
99
+ WHERE session_key = ?`).run(now, input.sessionKey);
100
+ return {
101
+ ok: true,
102
+ idempotent: false,
103
+ inputId,
104
+ removedMessages: buildSessionDisplayMessages(removedRows),
105
+ remainingMessages: buildSessionDisplayMessages(remainingRows)
106
+ };
107
+ });
108
+ }
109
+ //#endregion
110
+ export { replaceLatestSessionTurnAndQueueInput, validateLatestSessionTurnTarget };
@@ -1,7 +1,7 @@
1
1
  import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
2
+ import { escapeFts5Query } from "./fts.js";
2
3
  import { buildSessionContextForLlm, isRuntimeOnlyTranscriptMessage } from "../../session/session-context-for-llm.js";
3
4
  import { classifyStoredRow, estimateTokensFromMessages, extractFtsContent, transcriptEntryRowToStoredRow } from "./row-mappers.js";
4
- import { escapeFts5Query } from "./fts.js";
5
5
  import { getCurrentSessionId, readCurrentSessionId } from "./session-repository.js";
6
6
  import { randomUUID } from "node:crypto";
7
7
  //#region src/storage/sqlite/transcript-repository.ts
@@ -27,6 +27,13 @@ export type UserUnderstandingQualityMetrics = {
27
27
  helpfulRate: number | null;
28
28
  };
29
29
  };
30
+ export type UnderstandingFeedbackSummary = {
31
+ understandingId: string;
32
+ helpful: number;
33
+ irrelevant: number;
34
+ total: number;
35
+ };
36
+ export declare function summarizeUnderstandingFeedback(understandingIds: string[]): UnderstandingFeedbackSummary[];
30
37
  export declare function summarizeUserUnderstandingQuality(options?: {
31
38
  windowDays?: number;
32
39
  agingCandidateDays?: number;
@@ -1,6 +1,30 @@
1
1
  import { getSqliteDatabase } from "./transaction.js";
2
2
  import { USER_CONTEXT_PRINCIPAL_ID } from "../../user-context/domain.js";
3
3
  //#region src/storage/sqlite/user-context-quality-repository.ts
4
+ function summarizeUnderstandingFeedback(understandingIds) {
5
+ const ids = [...new Set(understandingIds.filter(Boolean))].slice(0, 1e3);
6
+ if (!ids.length) return [];
7
+ const rows = getSqliteDatabase().prepare(`
8
+ SELECT object_id, rating, COUNT(*) AS count
9
+ FROM context_feedback
10
+ WHERE object_type = 'understanding' AND object_id IN (${ids.map(() => "?").join(", ")})
11
+ GROUP BY object_id, rating
12
+ `).all(...ids);
13
+ const summaries = /* @__PURE__ */ new Map();
14
+ for (const row of rows) {
15
+ const current = summaries.get(row.object_id) ?? {
16
+ understandingId: row.object_id,
17
+ helpful: 0,
18
+ irrelevant: 0,
19
+ total: 0
20
+ };
21
+ if (row.rating === "helpful") current.helpful += row.count;
22
+ if (row.rating === "irrelevant") current.irrelevant += row.count;
23
+ current.total += row.count;
24
+ summaries.set(row.object_id, current);
25
+ }
26
+ return [...summaries.values()];
27
+ }
4
28
  function rate(numerator, denominator) {
5
29
  return denominator > 0 ? Math.round(numerator / denominator * 1e4) / 1e4 : null;
6
30
  }
@@ -71,4 +95,4 @@ function summarizeUserUnderstandingQuality(options = {}) {
71
95
  };
72
96
  }
73
97
  //#endregion
74
- export { summarizeUserUnderstandingQuality };
98
+ export { summarizeUnderstandingFeedback, summarizeUserUnderstandingQuality };
@@ -10,6 +10,10 @@ export type CreateUnderstandingInput = Omit<UserUnderstanding, 'id' | 'versionId
10
10
  export declare function createUnderstanding(input: CreateUnderstandingInput, principalId?: string): UserUnderstanding;
11
11
  export declare function getUnderstanding(id: string): UserUnderstanding | undefined;
12
12
  export declare function listUnderstandings(statuses?: UnderstandingStatus[], principalId?: string): UserUnderstanding[];
13
+ export declare function searchActiveUnderstandings(query: string, limit?: number): Array<{
14
+ understanding: UserUnderstanding;
15
+ score: number;
16
+ }>;
13
17
  export declare function reviseUnderstanding(id: string, statement: string, options: {
14
18
  payload?: Record<string, unknown>;
15
19
  canonicalKey?: string;
@@ -1,5 +1,7 @@
1
1
  import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
2
2
  import { USER_CONTEXT_PRINCIPAL_ID } from "../../user-context/domain.js";
3
+ import { retrievalQueryAuditValue } from "../../retrieval/audit.js";
4
+ import { buildFts5SearchQuery, fts5RankToScore } from "./fts.js";
3
5
  import { randomUUID } from "node:crypto";
4
6
  //#region src/storage/sqlite/user-context-repository.ts
5
7
  const UNDERSTANDING_SELECT = `
@@ -132,6 +134,29 @@ function listUnderstandings(statuses, principalId = USER_CONTEXT_PRINCIPAL_ID) {
132
134
  const placeholders = statuses.map(() => "?").join(", ");
133
135
  return db.prepare(`${UNDERSTANDING_SELECT} WHERE u.principal_id = ? AND u.status IN (${placeholders}) ORDER BY u.updated_at DESC`).all(principalId, ...statuses).map(understandingFromRow);
134
136
  }
137
+ function searchActiveUnderstandings(query, limit = 50) {
138
+ const ftsQuery = buildFts5SearchQuery(query);
139
+ if (!ftsQuery) return [];
140
+ const boundedLimit = Math.max(1, Math.min(200, Math.floor(limit)));
141
+ const rows = getSqliteDatabase().prepare(`
142
+ SELECT u.*, v.statement, v.payload_json, bm25(user_understanding_fts) AS search_rank
143
+ FROM user_understanding_fts
144
+ JOIN user_understandings u
145
+ ON u.understanding_id = user_understanding_fts.understanding_id
146
+ JOIN user_understanding_versions v
147
+ ON v.version_id = u.current_version_id
148
+ WHERE user_understanding_fts MATCH ? AND u.principal_id = ? AND u.status = 'active'
149
+ ORDER BY search_rank
150
+ LIMIT ?
151
+ `).all(ftsQuery, USER_CONTEXT_PRINCIPAL_ID, boundedLimit);
152
+ if (!rows.length) return [];
153
+ const bestRank = Math.min(...rows.map((row) => row.search_rank));
154
+ const worstRank = Math.max(...rows.map((row) => row.search_rank));
155
+ return rows.map((row) => ({
156
+ understanding: understandingFromRow(row),
157
+ score: fts5RankToScore(row.search_rank, bestRank, worstRank)
158
+ }));
159
+ }
135
160
  function reviseUnderstanding(id, statement, options) {
136
161
  const current = getUnderstanding(id);
137
162
  if (!current) throw new Error(`User understanding not found: ${id}`);
@@ -282,16 +307,17 @@ function listUnderstandingEvidence(understandingId, relation) {
282
307
  }));
283
308
  }
284
309
  function recordContextRun(input) {
310
+ const auditedQuery = retrievalQueryAuditValue(input.query);
285
311
  const existing = getSqliteDatabase().prepare("SELECT context_run_id FROM context_runs WHERE turn_id = ?").get(input.turnId);
286
312
  const runId = existing?.context_run_id ?? randomUUID();
287
313
  runSqliteWriteTransaction((db) => {
288
314
  if (existing) {
289
315
  db.prepare(`UPDATE context_runs SET principal_id = ?, session_key = ?, query = ?, budget = ?, duration_ms = ?
290
- WHERE context_run_id = ?`).run(input.principalId ?? "local-owner", input.sessionKey, input.query, input.budget, input.durationMs, runId);
316
+ WHERE context_run_id = ?`).run(input.principalId ?? "local-owner", input.sessionKey, auditedQuery, input.budget, input.durationMs, runId);
291
317
  db.prepare("DELETE FROM context_run_items WHERE context_run_id = ?").run(runId);
292
318
  } else db.prepare(`INSERT INTO context_runs (
293
319
  context_run_id, principal_id, turn_id, session_key, query, budget, duration_ms, created_at
294
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(runId, input.principalId ?? "local-owner", input.turnId, input.sessionKey, input.query, input.budget, input.durationMs, Date.now());
320
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(runId, input.principalId ?? "local-owner", input.turnId, input.sessionKey, auditedQuery, input.budget, input.durationMs, Date.now());
295
321
  const insert = db.prepare(`INSERT INTO context_run_items (
296
322
  context_run_id, object_type, object_id, version_id, decision, reason, content_snapshot,
297
323
  source_label, rank, score, injected_chars
@@ -380,4 +406,4 @@ function decideContextConsent(id, decision) {
380
406
  return Number(result.changes) > 0;
381
407
  }
382
408
  //#endregion
383
- export { consumeContextConsent, createCollaborationRule, createContextEvidence, createUnderstanding, decideContextConsent, deleteCollaborationRule, deleteUnderstanding, ensureContextConsent, getCollaborationRule, getTurnPersonalization, getUnderstanding, getUserProfile, hasContextConsent, isUnderstandingSuppressed, linkUnderstandingEvidence, listCollaborationRules, listUnderstandingEvidence, listUnderstandings, recordContextFeedback, recordContextRun, rejectUnderstanding, reviseCollaborationRule, reviseUnderstanding, setCollaborationRuleStatus, setUnderstandingStatus, updateUserProfile };
409
+ export { consumeContextConsent, createCollaborationRule, createContextEvidence, createUnderstanding, decideContextConsent, deleteCollaborationRule, deleteUnderstanding, ensureContextConsent, getCollaborationRule, getTurnPersonalization, getUnderstanding, getUserProfile, hasContextConsent, isUnderstandingSuppressed, linkUnderstandingEvidence, listCollaborationRules, listUnderstandingEvidence, listUnderstandings, recordContextFeedback, recordContextRun, rejectUnderstanding, reviseCollaborationRule, reviseUnderstanding, searchActiveUnderstandings, setCollaborationRuleStatus, setUnderstandingStatus, updateUserProfile };