@xopcai/xopc 0.0.409 → 0.0.410

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 (117) 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/{agent-avatar-dicebear-lMrejpsz.js → agent-avatar-dicebear-ColV_Z1C.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-lXwR3Rff.js → agent-defaults-settings-panel-rgRXzBCX.js} +1 -1
  5. package/dist/gateway/static/root/assets/{agents-DFwBf95X.js → agents-C1rSl_yE.js} +3 -3
  6. package/dist/gateway/static/root/assets/{app-management-settings-panel-Cja3eV7H.js → app-management-settings-panel-B-Cl1lzt.js} +1 -1
  7. package/dist/gateway/static/root/assets/{appearance-settings-Dzhmj_ZO.js → appearance-settings-byEnJz9H.js} +1 -1
  8. package/dist/gateway/static/root/assets/{apps-page-C3xbCdYa.js → apps-page-BfVMfjkC.js} +1 -1
  9. package/dist/gateway/static/root/assets/{archive-plugin-D4r4P5uG.js → archive-plugin-BXssEuq3.js} +1 -1
  10. package/dist/gateway/static/root/assets/{automations-page-BlNe3DXU.js → automations-page-C-puATkS.js} +1 -1
  11. package/dist/gateway/static/root/assets/{automations-workspace-CWvHbJBK.js → automations-workspace-b7MTHd-X.js} +1 -1
  12. package/dist/gateway/static/root/assets/{binary-plugins-DuN5L6lm.js → binary-plugins-DBz_2AhG.js} +1 -1
  13. package/dist/gateway/static/root/assets/{block-editor-DUSVn51h.js → block-editor-BOO5kjIl.js} +1 -1
  14. package/dist/gateway/static/root/assets/{browser-automations-page-BtvOURHQ.js → browser-automations-page-DMqDOJgO.js} +1 -1
  15. package/dist/gateway/static/root/assets/{browser-settings-page-C_OeE79S.js → browser-settings-page-KZStwhX7.js} +1 -1
  16. package/dist/gateway/static/root/assets/{capabilities-page-BKF6q_tC.js → capabilities-page-DeJuO2rf.js} +2 -2
  17. package/dist/gateway/static/root/assets/{capabilities-settings-panel-B7qOaUZs.js → capabilities-settings-panel-DPxL_3Km.js} +1 -1
  18. package/dist/gateway/static/root/assets/{capability-header-actions-oBPqUlbj.js → capability-header-actions-yfPUz5Wt.js} +1 -1
  19. package/dist/gateway/static/root/assets/{channels-3M9-anCN.js → channels-Cp4F9zPz.js} +1 -1
  20. package/dist/gateway/static/root/assets/{chat-terminal-dock-BLs3NaOP.js → chat-terminal-dock-Dlzn80cK.js} +1 -1
  21. package/dist/gateway/static/root/assets/{computer-settings-page-LaekhDG6.js → computer-settings-page-BXhmUWbA.js} +1 -1
  22. package/dist/gateway/static/root/assets/{connector-service-page-DJP1n1_n.js → connector-service-page-B1oJCj74.js} +1 -1
  23. package/dist/gateway/static/root/assets/{connectors-page-DmQqMy6l.js → connectors-page-Da_M7h3m.js} +1 -1
  24. package/dist/gateway/static/root/assets/{date-picker-DVlbwrYg.js → date-picker-DGjpqOKx.js} +1 -1
  25. package/dist/gateway/static/root/assets/{dependency-picker-BhElpD_6.js → dependency-picker-BfWUD3LG.js} +1 -1
  26. package/dist/gateway/static/root/assets/{desktop-pet-ByvV-cDD.js → desktop-pet-CPEi55Vt.js} +1 -1
  27. package/dist/gateway/static/root/assets/{desktop-pet-settings-BBruQu-_.js → desktop-pet-settings-CmQ_H-nM.js} +1 -1
  28. package/dist/gateway/static/root/assets/{device-pairing-wizard-C3zOy8PO.js → device-pairing-wizard-BeTjXc3C.js} +1 -1
  29. package/dist/gateway/static/root/assets/{directory-picker-path-field-QZ0p-uNa.js → directory-picker-path-field-CwT1LcLR.js} +1 -1
  30. package/dist/gateway/static/root/assets/{extension-debug-page-DoVPUHu_.js → extension-debug-page-DX-hX_d0.js} +1 -1
  31. package/dist/gateway/static/root/assets/{extension-page-BNe8n3iJ.js → extension-page-Cji87mN9.js} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-settings-page-DxNpjGJD.js → extension-settings-page-BulzpwBD.js} +1 -1
  33. package/dist/gateway/static/root/assets/{gateway-settings-CzrFZ0lB.js → gateway-settings-CIdEroWr.js} +1 -1
  34. package/dist/gateway/static/root/assets/{highlighted-body-KQOG7T2V-DrZq5KTj.js → highlighted-body-KQOG7T2V-BgTqMa_d.js} +1 -1
  35. package/dist/gateway/static/root/assets/{home-page-cXmd8x0S.js → home-page-BSbYrVda.js} +1 -1
  36. package/dist/gateway/static/root/assets/{image-generation-api-C6su4n9B.js → image-generation-api-BfPYnMoc.js} +1 -1
  37. package/dist/gateway/static/root/assets/{imports-page-CsXYryWS.js → imports-page-DYSOfHfw.js} +1 -1
  38. package/dist/gateway/static/root/assets/{index-uAJlrGvo.js → index-D2hEKnTM.js} +116 -116
  39. package/dist/gateway/static/root/assets/index-SmKNPEmJ.css +1 -0
  40. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-GYKLt0oF.js → keyboard-shortcuts-settings-BwsGM6Yd.js} +1 -1
  41. package/dist/gateway/static/root/assets/{local-app-workbench-page-Dw-i6VkX.js → local-app-workbench-page-K6UR6cAx.js} +1 -1
  42. package/dist/gateway/static/root/assets/{local-apps-page-DslilwNE.js → local-apps-page-gkdwtjDE.js} +1 -1
  43. package/dist/gateway/static/root/assets/{logs-page-4N8bGPIE.js → logs-page-BAQNYk0e.js} +1 -1
  44. package/dist/gateway/static/root/assets/{management-settings-CPmxI1k0.js → management-settings-CMVRLGox.js} +1 -1
  45. package/dist/gateway/static/root/assets/{media-plugins-s6EqtAUQ.js → media-plugins-DQJXvbr_.js} +1 -1
  46. package/dist/gateway/static/root/assets/mermaid-MCJ5UELQ-Cx0bXBqu.js +1 -0
  47. package/dist/gateway/static/root/assets/{note-detail-panel-CjTm5gxS.js → note-detail-panel-1GCqp26U.js} +3 -3
  48. package/dist/gateway/static/root/assets/note-image-lightbox-B7RA-WsY.js +1 -0
  49. package/dist/gateway/static/root/assets/{notes-page-DkESStKc.js → notes-page-DnjlEdzM.js} +1 -1
  50. package/dist/gateway/static/root/assets/{page-context-capture-button-eyzTNrCe.js → page-context-capture-button-BAwI_3uh.js} +1 -1
  51. package/dist/gateway/static/root/assets/{personal-page-DZxbFQvF.js → personal-page-XoLrcR0U.js} +1 -1
  52. package/dist/gateway/static/root/assets/{plugin-details-dialog-BjVLbxZM.js → plugin-details-dialog-BjzIp3T5.js} +1 -1
  53. package/dist/gateway/static/root/assets/{preview-open-alternatives-7pUtUL4O.js → preview-open-alternatives-2YjwlRHu.js} +1 -1
  54. package/dist/gateway/static/root/assets/{product-open-page-BPWSqtRt.js → product-open-page-Bfqez8Je.js} +1 -1
  55. package/dist/gateway/static/root/assets/{product-preview-content-COo4zwp9.js → product-preview-content-D7wLwrqj.js} +1 -1
  56. package/dist/gateway/static/root/assets/{project-detail-page-CrIH6nEy.js → project-detail-page-1ueRCmXg.js} +1 -1
  57. package/dist/gateway/static/root/assets/{projects-page-D4swvBmH.js → projects-page-CDQycMPo.js} +1 -1
  58. package/dist/gateway/static/root/assets/{remote-access-hub-DltfIMtv.js → remote-access-hub-YvVmZA4K.js} +1 -1
  59. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-CNCx2RnO.js → runtime-tools-settings-panel-DSsANtha.js} +1 -1
  60. package/dist/gateway/static/root/assets/{schema-form-nRDA2XfI.js → schema-form-vbhv4JE6.js} +1 -1
  61. package/dist/gateway/static/root/assets/{sessions-page-CfYU53aw.js → sessions-page-B3rPljgr.js} +1 -1
  62. package/dist/gateway/static/root/assets/settings-advanced-gate-Ch20Ptzp.js +1 -0
  63. package/dist/gateway/static/root/assets/{settings-form-section-_ALUREPr.js → settings-form-section-4nn0sb6v.js} +1 -1
  64. package/dist/gateway/static/root/assets/{settings-page-29ptuMYZ.js → settings-page-_HB9FC08.js} +1 -1
  65. package/dist/gateway/static/root/assets/{setup-status-panel-DZgVMRXr.js → setup-status-panel-L1HHrvzi.js} +1 -1
  66. package/dist/gateway/static/root/assets/{share-preview-page-C2LHd_Nl.js → share-preview-page-C4lC0W3d.js} +1 -1
  67. package/dist/gateway/static/root/assets/{shares-settings-C5MTc6t-.js → shares-settings-DtHZ9z5K.js} +1 -1
  68. package/dist/gateway/static/root/assets/{skill-api-C-T0K7Oo.js → skill-api-CyO89DKl.js} +1 -1
  69. package/dist/gateway/static/root/assets/{skill-reload-api-BcdA9ezU.js → skill-reload-api-Drg356Pb.js} +1 -1
  70. package/dist/gateway/static/root/assets/{skills-page-BMw8XbKL.js → skills-page-XhCLHKlK.js} +1 -1
  71. package/dist/gateway/static/root/assets/{style-DR0-RKaL.js → style-DTLpCnuA.js} +1 -1
  72. package/dist/gateway/static/root/assets/{system-settings-panel-2Kr9Y-FJ.js → system-settings-panel-bSogz4S-.js} +1 -1
  73. package/dist/gateway/static/root/assets/{task-detail-page-7kPco8Ys.js → task-detail-page-CSv2x4q-.js} +1 -1
  74. package/dist/gateway/static/root/assets/{tracing-settings-page-D53wxq60.js → tracing-settings-page-CZ5XLQmX.js} +1 -1
  75. package/dist/gateway/static/root/assets/{tunnel-api-DcDUSAjv.js → tunnel-api-DOUyF9Ew.js} +1 -1
  76. package/dist/gateway/static/root/assets/{usage-page-Hut0SDqn.js → usage-page-Bv3fdfw1.js} +1 -1
  77. package/dist/gateway/static/root/assets/{use-autosave-C4TUlpsu.js → use-autosave-D0MhLMD2.js} +1 -1
  78. package/dist/gateway/static/root/assets/{user-model-page-KRy50OBd.js → user-model-page-BD7WvhI0.js} +1 -1
  79. package/dist/gateway/static/root/assets/{voice-api-key-field-CMdihbPb.js → voice-api-key-field-Ds_ADBQH.js} +1 -1
  80. package/dist/gateway/static/root/assets/{work-discovery-overlay-Bd9HLsds.js → work-discovery-overlay-CDJp2_l2.js} +1 -1
  81. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-C9mAiHBd.js → workflow-run-setup-panel-CR4fRhZZ.js} +1 -1
  82. package/dist/gateway/static/root/assets/{workflows-page-CGg4GWwt.js → workflows-page-BeJw5liC.js} +1 -1
  83. package/dist/gateway/static/root/assets/{xopc-cloud-account-card-ClQKM2RA.js → xopc-cloud-account-card-Di-oEpCt.js} +1 -1
  84. package/dist/gateway/static/root/index.html +2 -2
  85. package/dist/package.js +1 -1
  86. package/dist/src/agent/background-review/prompts.d.ts +8 -0
  87. package/dist/src/agent/background-review/prompts.js +9 -2
  88. package/dist/src/agent/background-review/run-background-review.js +73 -11
  89. package/dist/src/agent/inbound/attachment-pipeline.d.ts +2 -0
  90. package/dist/src/agent/inbound/attachment-pipeline.js +10 -5
  91. package/dist/src/agent/tools/factory.js +15 -1
  92. package/dist/src/agent/tools/session-recall-tool.d.ts +3 -0
  93. package/dist/src/agent/tools/session-recall-tool.js +3 -0
  94. package/dist/src/agent/tools/session-search-tool.d.ts +3 -0
  95. package/dist/src/agent/tools/session-search-tool.js +20 -4
  96. package/dist/src/gateway/service.js +11 -11
  97. package/dist/src/home-intelligence/host.js +2 -2
  98. package/dist/src/knowledge-memory/repository.d.ts +3 -1
  99. package/dist/src/knowledge-memory/repository.js +10 -3
  100. package/dist/src/memory-learning/forget-capture.d.ts +14 -0
  101. package/dist/src/memory-learning/forget-capture.js +100 -0
  102. package/dist/src/memory-learning/forgotten-history.d.ts +5 -0
  103. package/dist/src/memory-learning/forgotten-history.js +33 -0
  104. package/dist/src/memory-learning/work-capture.js +2 -1
  105. package/dist/src/session/store.d.ts +1 -0
  106. package/dist/src/storage/sqlite/fts.d.ts +4 -0
  107. package/dist/src/storage/sqlite/fts.js +13 -4
  108. package/dist/src/storage/sqlite/session-repository.js +6 -3
  109. package/dist/src/storage/sqlite/transcript-repository.d.ts +1 -0
  110. package/dist/src/storage/sqlite/transcript-repository.js +14 -12
  111. package/dist/src/user-model/capture/semantic.d.ts +18 -1
  112. package/dist/src/user-model/capture/semantic.js +26 -1
  113. package/package.json +3 -3
  114. package/dist/gateway/static/root/assets/index-BZlryZm8.css +0 -1
  115. package/dist/gateway/static/root/assets/mermaid-MCJ5UELQ-Ba-WQCki.js +0 -1
  116. package/dist/gateway/static/root/assets/note-image-lightbox-hbSbEEfN.js +0 -1
  117. package/dist/gateway/static/root/assets/settings-advanced-gate-BJBoWYbO.js +0 -1
@@ -7,10 +7,19 @@ function escapeFts5Query(raw) {
7
7
  return `"${trimmed.replace(/"/g, "\"\"")}"`;
8
8
  }
9
9
  /** Build a syntax-safe, recall-oriented query for natural-language memory search. */
10
- function buildFts5SearchQuery(raw) {
10
+ function sessionSearchTerms(raw) {
11
11
  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));
12
- if (!terms?.length) return escapeFts5Query(raw);
13
- return [...new Set(terms)].slice(0, 12).map((term) => escapeFts5Query(term)).join(" OR ");
12
+ return [...new Set(terms?.length ? terms : [raw.trim()])].slice(0, 12);
13
+ }
14
+ function buildFts5SearchQuery(raw) {
15
+ return sessionSearchTerms(raw).map(escapeFts5Query).join(" OR ");
16
+ }
17
+ /** unicode61 does not split Han words; use literal substrings for those terms. */
18
+ function sessionHanSearchTerms(raw) {
19
+ return sessionSearchTerms(raw).filter((term) => /\p{Script=Han}/u.test(term));
20
+ }
21
+ function escapeSqlLike(raw) {
22
+ return raw.replaceAll("\\", "\\\\").replaceAll("%", "\\%").replaceAll("_", "\\_");
14
23
  }
15
24
  /** Normalize FTS5 BM25 ranks, where a more-negative rank is a better match. */
16
25
  function fts5RankToScore(rank, bestRank, worstRank) {
@@ -61,4 +70,4 @@ var init_fts = __esmMin((() => {
61
70
  }));
62
71
  //#endregion
63
72
  init_fts();
64
- export { buildFts5SearchQuery, escapeFts5Query, fts5RankToScore, init_fts };
73
+ export { buildFts5SearchQuery, escapeFts5Query, escapeSqlLike, fts5RankToScore, init_fts, sessionHanSearchTerms, sessionSearchTerms };
@@ -10,7 +10,7 @@ import { buildGlobalSessionStats, init_row_mappers, metadataToSessionInsert, ses
10
10
  import { cancelConnectionObjective, init_connection_wait_repository } from "./connection-wait-repository.js";
11
11
  import { init_changes, notifyUserContextChange } from "../../user-context/changes.js";
12
12
  import { SESSION_PURPOSE_SQL, SESSION_SOURCE_SQL, init_session_identity_sql } from "./session-identity-sql.js";
13
- import { buildFts5SearchQuery, init_fts } from "./fts.js";
13
+ import { buildFts5SearchQuery, escapeSqlLike, init_fts, sessionHanSearchTerms } from "./fts.js";
14
14
  import { SESSION_COLUMNS, SESSION_FROM_JOIN, getSessionMetadata, init_session_read_repository, readSessionRow } from "./session-read-repository.js";
15
15
  import { randomUUID } from "node:crypto";
16
16
  //#region src/storage/sqlite/session-repository.ts
@@ -166,14 +166,17 @@ function listSessionMetadata(query = {}) {
166
166
  if (query.search?.trim()) {
167
167
  const rawSearch = query.search.trim();
168
168
  const like = `%${rawSearch.toLowerCase()}%`;
169
+ const hanTerms = sessionHanSearchTerms(rawSearch);
169
170
  conditions.push(`(s.conversation_id IN (
170
171
  SELECT conversation_id FROM transcript_fts WHERE transcript_fts MATCH ?
171
- ) OR LOWER(s.conversation_id) LIKE ?
172
+ ) ${hanTerms.length ? `OR s.conversation_id IN (
173
+ SELECT conversation_id FROM transcript_fts WHERE ${hanTerms.map(() => "content LIKE ? ESCAPE '\\'").join(" OR ")}
174
+ )` : ""} OR LOWER(s.conversation_id) LIKE ?
172
175
  OR LOWER(COALESCE(s.name, '')) LIKE ?
173
176
  OR LOWER(s.source_channel) LIKE ?
174
177
  OR LOWER(s.source_chat_id) LIKE ?
175
178
  OR LOWER(s.tags_json) LIKE ?)`);
176
- params.push(buildFts5SearchQuery(rawSearch), like, like, like, like, like);
179
+ params.push(buildFts5SearchQuery(rawSearch), ...hanTerms.map((term) => `%${escapeSqlLike(term)}%`), like, like, like, like, like);
177
180
  }
178
181
  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
179
182
  const sortColumn = sessionSortColumn(query.sortBy);
@@ -34,6 +34,7 @@ export declare function searchSessionTranscript(conversationId: string, query: s
34
34
  limit?: number;
35
35
  beforeSeq?: number;
36
36
  orderBySeq?: boolean;
37
+ matchMode?: 'keyword' | 'phrase';
37
38
  }): SessionTranscriptRecallMatch[];
38
39
  export declare function loadTranscriptRowsForSession(conversationId: string): TranscriptStoredRow[];
39
40
  export declare function loadTranscriptHistoryRowsForSession(conversationId: string): TranscriptStoredRow[];
@@ -3,7 +3,7 @@ import { getSqliteDatabase, init_transaction, runSqliteWriteTransaction } from "
3
3
  import { readCurrentTranscriptId } from "./session-instance-repository.js";
4
4
  import { buildSessionContextForLlm, init_session_context_for_llm, isRuntimeOnlyTranscriptMessage } from "../../session/session-context-for-llm.js";
5
5
  import { classifyStoredRow, estimateTokensFromMessages, extractFtsContent, init_row_mappers, transcriptEntryRowToStoredRow } from "./row-mappers.js";
6
- import { escapeFts5Query, init_fts } from "./fts.js";
6
+ import { buildFts5SearchQuery, escapeFts5Query, escapeSqlLike, init_fts, sessionHanSearchTerms } from "./fts.js";
7
7
  import { getCurrentTranscriptId, init_session_repository } from "./session-repository.js";
8
8
  import { createHash, randomUUID } from "node:crypto";
9
9
  //#region src/storage/sqlite/transcript-repository.ts
@@ -167,25 +167,27 @@ function searchSessionTranscript(conversationId, query, options = {}) {
167
167
  const limit = Math.min(20, Math.max(1, options.limit ?? 8));
168
168
  const beforeSeq = options.beforeSeq ?? Number.MAX_SAFE_INTEGER;
169
169
  const db = getSqliteDatabase();
170
+ const phrase = options.matchMode !== "keyword";
171
+ const hanTerms = phrase ? [] : sessionHanSearchTerms(normalized);
170
172
  const ftsRows = db.prepare(`SELECT e.entry_id, e.seq, e.role, e.created_at, f.content
171
173
  FROM transcript_fts f
172
174
  JOIN transcript_entries e
173
175
  ON e.transcript_id = f.transcript_id AND e.entry_id = f.entry_id
174
- WHERE transcript_fts MATCH ?
176
+ WHERE (transcript_fts MATCH ?)
175
177
  AND f.transcript_id = ?
176
178
  AND e.entry_kind <> 'compaction'
177
179
  AND e.seq < ?
178
180
  ORDER BY ${options.orderBySeq ? "e.seq DESC" : "bm25(transcript_fts), e.seq DESC"}
179
- LIMIT ?`).all(escapeFts5Query(normalized), transcriptId, beforeSeq, limit);
180
- const escapedLike = normalized.replaceAll("\\", "\\\\").replaceAll("%", "\\%").replaceAll("_", "\\_");
181
- const literalRows = db.prepare(`SELECT entry_id, seq, role, created_at, payload_json AS content
182
- FROM transcript_entries
183
- WHERE transcript_id = ?
184
- AND entry_kind <> 'compaction'
185
- AND seq < ?
186
- AND payload_json LIKE ? ESCAPE '\\'
187
- ORDER BY seq DESC
188
- LIMIT ?`).all(transcriptId, beforeSeq, `%${escapedLike}%`, limit);
181
+ LIMIT ?`).all(phrase ? escapeFts5Query(normalized) : buildFts5SearchQuery(normalized), transcriptId, beforeSeq, limit);
182
+ const literalTerms = [normalized, ...hanTerms];
183
+ const literalRows = phrase ? db.prepare(`SELECT entry_id, seq, role, created_at, payload_json AS content
184
+ FROM transcript_entries WHERE transcript_id = ? AND entry_kind <> 'compaction' AND seq < ?
185
+ AND payload_json LIKE ? ESCAPE '\\' ORDER BY seq DESC LIMIT ?`).all(transcriptId, beforeSeq, `%${escapeSqlLike(normalized)}%`, limit) : db.prepare(`SELECT e.entry_id, e.seq, e.role, e.created_at, f.content
186
+ FROM transcript_fts f JOIN transcript_entries e
187
+ ON e.transcript_id = f.transcript_id AND e.entry_id = f.entry_id
188
+ WHERE f.transcript_id = ? AND e.entry_kind <> 'compaction' AND e.seq < ?
189
+ AND (${literalTerms.map(() => "f.content LIKE ? ESCAPE '\\'").join(" OR ")})
190
+ ORDER BY e.seq DESC LIMIT ?`).all(transcriptId, beforeSeq, ...literalTerms.map((term) => `%${escapeSqlLike(term)}%`), limit);
189
191
  const seen = /* @__PURE__ */ new Set();
190
192
  const matches = [...ftsRows, ...literalRows].flatMap((row) => {
191
193
  const result = row;
@@ -34,6 +34,23 @@ export interface ParsedCollaborationRuleCandidate {
34
34
  }
35
35
  export interface UserModelInterpretation {
36
36
  knowledge?: WorkCandidate[];
37
+ knowledgeDeletions?: Array<{
38
+ targetKnowledgeIds: string[];
39
+ boundary: string;
40
+ reread?: {
41
+ subject: string;
42
+ property: 'date_time' | 'price';
43
+ };
44
+ evidenceRefs: string[];
45
+ evidence: Array<{
46
+ ref: string;
47
+ quote: string;
48
+ }>;
49
+ retained?: Array<{
50
+ targetKnowledgeId: string;
51
+ spans: string[];
52
+ }>;
53
+ }>;
37
54
  intent: UserModelCaptureIntent;
38
55
  assertions: ParsedAssertionOperation[];
39
56
  goals?: ParsedGoalCandidate[];
@@ -48,4 +65,4 @@ export interface InterpretationParseFailure {
48
65
  code: string;
49
66
  }>;
50
67
  }
51
- export declare function parseUserModelInterpretation(raw: string, evidence: CaptureEvidence[], allowedTargetIds?: string[], onInvalid?: (failure: InterpretationParseFailure) => void): UserModelInterpretation | null;
68
+ export declare function parseUserModelInterpretation(raw: string, evidence: CaptureEvidence[], allowedTargetIds?: string[], onInvalid?: (failure: InterpretationParseFailure) => void, allowedKnowledgeIds?: string[]): UserModelInterpretation | null;
@@ -154,6 +154,18 @@ const CollaborationRuleSchema = z.object({
154
154
  }).merge(GroundingSchema).strict();
155
155
  const InterpretationSchema = z.object({
156
156
  knowledge: z.array(WorkCandidateSchema).max(8).default([]),
157
+ knowledgeDeletions: z.array(z.object({
158
+ targetKnowledgeIds: z.array(z.string().min(1)).min(1).max(16),
159
+ boundary: z.string().min(4).max(600),
160
+ reread: z.object({
161
+ subject: z.string().min(1).max(160),
162
+ property: z.enum(["date_time", "price"])
163
+ }).strict().optional(),
164
+ retained: z.array(z.object({
165
+ targetKnowledgeId: z.string().min(1),
166
+ spans: z.array(z.string().min(1).max(600)).min(1).max(8)
167
+ }).strict()).max(8).default([])
168
+ }).merge(GroundingSchema).strict()).max(4).default([]),
157
169
  intent: z.enum(USER_MODEL_CAPTURE_INTENTS),
158
170
  assertions: z.array(AssertionOperationSchema).max(8),
159
171
  goals: z.array(GoalSchema).max(4).default([]),
@@ -184,7 +196,7 @@ function groundedEvidenceRefs(item, evidenceByRef) {
184
196
  return source?.role === "user" && comparable(source.text).includes(comparable(claim.quote));
185
197
  }) ? [...new Set(item.evidence.map((claim) => claim.ref))] : void 0;
186
198
  }
187
- function parseUserModelInterpretation(raw, evidence, allowedTargetIds = [], onInvalid) {
199
+ function parseUserModelInterpretation(raw, evidence, allowedTargetIds = [], onInvalid, allowedKnowledgeIds = []) {
188
200
  if (!raw.trim()) {
189
201
  onInvalid?.({
190
202
  reason: "empty_output",
@@ -296,6 +308,19 @@ function parseUserModelInterpretation(raw, evidence, allowedTargetIds = [], onIn
296
308
  });
297
309
  return {
298
310
  knowledge: parsed.knowledge,
311
+ knowledgeDeletions: parsed.knowledgeDeletions.flatMap((item) => {
312
+ const evidenceRefs = groundedEvidenceRefs(item, evidenceByRef);
313
+ if (!evidenceRefs || (item.intent ?? parsed.intent) !== "forget") return [];
314
+ const targetKnowledgeIds = [...new Set(item.targetKnowledgeIds.filter((id) => allowedKnowledgeIds.includes(id)))];
315
+ return targetKnowledgeIds.length ? [{
316
+ targetKnowledgeIds,
317
+ boundary: item.boundary,
318
+ evidenceRefs,
319
+ evidence: item.evidence,
320
+ retained: item.retained.filter((retained) => targetKnowledgeIds.includes(retained.targetKnowledgeId)),
321
+ ...item.reread && item.evidence.some((claim) => claim.quote.includes(item.reread.subject)) ? { reread: item.reread } : {}
322
+ }] : [];
323
+ }),
299
324
  intent: parsed.intent,
300
325
  assertions,
301
326
  goals,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xopcai/xopc",
3
- "version": "0.0.409",
3
+ "version": "0.0.410",
4
4
  "description": "Local-first personal AI with Ada, task delegation, files, projects, workflows, and automations. Use cloud or local models.",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",
@@ -170,12 +170,12 @@
170
170
  "xlsx": "file:web/vendor/xlsx-0.20.3.tgz",
171
171
  "@xopcai/browser-control-contract": "0.1.0",
172
172
  "@xopcai/computer-control-contract": "0.1.0",
173
- "@xopcai/endpoint-tools-client": "0.0.0",
174
173
  "@xopcai/endpoint-tools-protocol": "0.0.0",
175
174
  "@xopcai/gateway-contract": "0.0.0",
176
175
  "@xopcai/image-providers": "0.1.0",
177
176
  "@xopcai/realtime-client": "0.0.0",
178
- "@xopcai/realtime-protocol": "0.0.0"
177
+ "@xopcai/realtime-protocol": "0.0.0",
178
+ "@xopcai/endpoint-tools-client": "0.0.0"
179
179
  },
180
180
  "scripts": {
181
181
  "generate:device-tools": "tsx scripts/devices/generate-mobile-tools.mts",