@xopcai/xopc 0.0.228 → 0.0.229

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 (129) 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-CjGZBs4C.js → agent-avatar-dicebear-CsFAJTIN.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agents-B0NI4_NI.js → agents-DA4b6_0C.js} +1 -1
  5. package/dist/gateway/static/root/assets/{app-management-settings-panel--SjycrXk.js → app-management-settings-panel-7KcMWuah.js} +1 -1
  6. package/dist/gateway/static/root/assets/{appearance-settings-8G-TVUtg.js → appearance-settings-Cqlw7Fif.js} +1 -1
  7. package/dist/gateway/static/root/assets/{apps-page-2NiqD-YP.js → apps-page-CsnhdGZ2.js} +1 -1
  8. package/dist/gateway/static/root/assets/{attachment-load-Bx44zSpz.js → attachment-load-q4pDpqkF.js} +1 -1
  9. package/dist/gateway/static/root/assets/{automations-page-CrKAHqc0.js → automations-page-BuTqjKGX.js} +1 -1
  10. package/dist/gateway/static/root/assets/{automations-workspace-Q3g9cf0h.js → automations-workspace-CD0E2ThS.js} +1 -1
  11. package/dist/gateway/static/root/assets/{binary-plugins-DjDwnHAQ.js → binary-plugins-DUce1Bsc.js} +1 -1
  12. package/dist/gateway/static/root/assets/{block-editor-7aMOKoZM.js → block-editor-D8Ejp-QR.js} +1 -1
  13. package/dist/gateway/static/root/assets/{browser-settings-page-DTwPkmAC.js → browser-settings-page-CY1k3MMd.js} +1 -1
  14. package/dist/gateway/static/root/assets/{browser-workflows-page-DVLrWKz_.js → browser-workflows-page-BDvZbR9v.js} +1 -1
  15. package/dist/gateway/static/root/assets/{capabilities-settings-panel-YcP4FbN7.js → capabilities-settings-panel-D1VfotHQ.js} +1 -1
  16. package/dist/gateway/static/root/assets/{capability-presets-settings-panel-AcPjHHia.js → capability-presets-settings-panel-DXHqRLpU.js} +1 -1
  17. package/dist/gateway/static/root/assets/{channels-settings-Ca94Q1D-.js → channels-settings-DrFL57M_.js} +1 -1
  18. package/dist/gateway/static/root/assets/{chat-terminal-dock-BR-_7KC0.js → chat-terminal-dock-h1CKexNz.js} +1 -1
  19. package/dist/gateway/static/root/assets/{connectors-page-SGxfLTd6.js → connectors-page-DUAyfFCF.js} +1 -1
  20. package/dist/gateway/static/root/assets/{cron-expression-D8-c-Tkw.js → cron-expression-DlaQQOId.js} +1 -1
  21. package/dist/gateway/static/root/assets/{date-picker-kV-Jyl9J.js → date-picker-8R1sXJKb.js} +1 -1
  22. package/dist/gateway/static/root/assets/{dependency-picker-CwKcrfGj.js → dependency-picker-CWur0821.js} +1 -1
  23. package/dist/gateway/static/root/assets/{desktop-pet-D9rnchu3.js → desktop-pet-Knl-zNDU.js} +1 -1
  24. package/dist/gateway/static/root/assets/{desktop-pet-settings-CTs5WGzk.js → desktop-pet-settings-CAQMLVtd.js} +1 -1
  25. package/dist/gateway/static/root/assets/{directory-picker-path-field-CCl0aaDm.js → directory-picker-path-field-Caaz4Rw5.js} +1 -1
  26. package/dist/gateway/static/root/assets/{extension-debug-page-Cau40SvC.js → extension-debug-page-B965Mc15.js} +1 -1
  27. package/dist/gateway/static/root/assets/{extension-page-BsJXdvIL.js → extension-page-C0UnkBi5.js} +1 -1
  28. package/dist/gateway/static/root/assets/{extension-settings-page-qWqJyF7-.js → extension-settings-page-BUSIAZCR.js} +1 -1
  29. package/dist/gateway/static/root/assets/{gateway-config-api-BI0SELXm.js → gateway-config-api-DkH0eEgy.js} +1 -1
  30. package/dist/gateway/static/root/assets/{gateway-settings-6ZdOIC7F.js → gateway-settings-BBgLDm6I.js} +1 -1
  31. package/dist/gateway/static/root/assets/{heartbeat-settings-KBwhXeFD.js → heartbeat-settings-BtEHVXWD.js} +1 -1
  32. package/dist/gateway/static/root/assets/{home-page-BA2M4CLi.js → home-page-5SU2TNJj.js} +1 -1
  33. package/dist/gateway/static/root/assets/{index-BX0dz1JK.js → index-BNWhgmjs.js} +8 -8
  34. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-kHtpnyEm.js → keyboard-shortcuts-settings-CsRz8NrS.js} +1 -1
  35. package/dist/gateway/static/root/assets/{local-app-workbench-page-D2nkn09R.js → local-app-workbench-page-DYPEUgpP.js} +1 -1
  36. package/dist/gateway/static/root/assets/{local-apps-page-BCXa0oUa.js → local-apps-page-CTBNUG4a.js} +1 -1
  37. package/dist/gateway/static/root/assets/{logs-page-D3sNst0K.js → logs-page-B0P7rG2B.js} +1 -1
  38. package/dist/gateway/static/root/assets/{management-settings-tHnlfOAQ.js → management-settings-YqUAEwQo.js} +1 -1
  39. package/dist/gateway/static/root/assets/{markdown-split-BMLqHHr5.js → markdown-split-dxpSCXb8.js} +1 -1
  40. package/dist/gateway/static/root/assets/{media-plugins-DybwqTgv.js → media-plugins-CJ00i1Lg.js} +1 -1
  41. package/dist/gateway/static/root/assets/{notes-page-C24SfF6r.js → notes-page-DEnbnkIt.js} +1 -1
  42. package/dist/gateway/static/root/assets/{notes-workbench-CTdZc3ov.js → notes-workbench-DmVYu_Oc.js} +2 -2
  43. package/dist/gateway/static/root/assets/{product-open-page-DBfCVlJq.js → product-open-page-BHxo9U95.js} +1 -1
  44. package/dist/gateway/static/root/assets/{project-detail-page-COHaEpbA.js → project-detail-page-DV2nGmsq.js} +1 -1
  45. package/dist/gateway/static/root/assets/{projects-page-lMnST7D_.js → projects-page-BNIFwFfc.js} +1 -1
  46. package/dist/gateway/static/root/assets/{remote-access-hub-BIRKBvO_.js → remote-access-hub-DLXqKiA_.js} +1 -1
  47. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-BPEGTip5.js → runtime-tools-settings-panel-BpQ2GI-0.js} +1 -1
  48. package/dist/gateway/static/root/assets/{schema-form-Dxlu60Td.js → schema-form-HE1G26Lx.js} +1 -1
  49. package/dist/gateway/static/root/assets/{sessions-page-CATO9G3y.js → sessions-page-DWaXf_25.js} +1 -1
  50. package/dist/gateway/static/root/assets/settings-advanced-gate-JFCbnCL2.js +1 -0
  51. package/dist/gateway/static/root/assets/{settings-form-section-ChXh3Bwk.js → settings-form-section-CXAn0Xhy.js} +1 -1
  52. package/dist/gateway/static/root/assets/{settings-loading-skeleton-BCAUqIe2.js → settings-loading-skeleton-DsFu7Bcv.js} +1 -1
  53. package/dist/gateway/static/root/assets/{settings-page-D25W9Okr.js → settings-page-C4iib9nO.js} +1 -1
  54. package/dist/gateway/static/root/assets/{setup-status-panel-DsN7Z4Fl.js → setup-status-panel-BA83Wr1d.js} +1 -1
  55. package/dist/gateway/static/root/assets/{share-preview-page-CRFnUaNb.js → share-preview-page-BOGl3s6M.js} +1 -1
  56. package/dist/gateway/static/root/assets/{shares-settings-CAX0eNaP.js → shares-settings-Q2MdGaBi.js} +1 -1
  57. package/dist/gateway/static/root/assets/{skill-reload-api-Doy1gghe.js → skill-reload-api-cFtfVeFU.js} +1 -1
  58. package/dist/gateway/static/root/assets/{skills-page-Cl7jjTK7.js → skills-page-CdaFtNw9.js} +1 -1
  59. package/dist/gateway/static/root/assets/{skills-page.utils-BiCl4nb5.js → skills-page.utils-DYaAddUL.js} +1 -1
  60. package/dist/gateway/static/root/assets/{system-settings-panel-BuESR7ZT.js → system-settings-panel-Co7gilRd.js} +1 -1
  61. package/dist/gateway/static/root/assets/{task-detail-page-BRiy8NL3.js → task-detail-page-5B1pswu8.js} +1 -1
  62. package/dist/gateway/static/root/assets/{use-autosave-Dg1mgJ_l.js → use-autosave-DnnZtMpA.js} +1 -1
  63. package/dist/gateway/static/root/assets/{user-context-page-CqoADNKu.js → user-context-page-Dr1FKjXv.js} +1 -1
  64. package/dist/gateway/static/root/assets/{voice-api-key-field-BDNexlVR.js → voice-api-key-field-wetUpi3i.js} +1 -1
  65. package/dist/gateway/static/root/assets/{work-discovery-overlay-BHTfeaWL.js → work-discovery-overlay-tbTWASJJ.js} +1 -1
  66. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-Cf_w-NZy.js → workflow-run-setup-panel-Dy0fDs8w.js} +1 -1
  67. package/dist/gateway/static/root/assets/{workflows-page-j0P-uECz.js → workflows-page-IVP3GSkI.js} +1 -1
  68. package/dist/gateway/static/root/index.html +1 -1
  69. package/dist/package.js +1 -1
  70. package/dist/src/agent/agent-instance-gateway.d.ts +1 -1
  71. package/dist/src/agent/agent-manager.d.ts +1 -1
  72. package/dist/src/agent/agent-manager.js +18 -3
  73. package/dist/src/agent/background-review/prompts.d.ts +8 -2
  74. package/dist/src/agent/background-review/prompts.js +25 -12
  75. package/dist/src/agent/background-review/run-background-review.d.ts +7 -2
  76. package/dist/src/agent/background-review/run-background-review.js +175 -160
  77. package/dist/src/agent/memory/index.d.ts +1 -1
  78. package/dist/src/agent/memory/index.js +2 -2
  79. package/dist/src/agent/memory/manager.d.ts +1 -11
  80. package/dist/src/agent/memory/manager.js +0 -16
  81. package/dist/src/agent/memory/understanding/service.d.ts +0 -11
  82. package/dist/src/agent/memory/understanding/service.js +7 -173
  83. package/dist/src/agent/memory/user-context-coordinator.d.ts +1 -3
  84. package/dist/src/agent/memory/user-context-coordinator.js +3 -66
  85. package/dist/src/agent/orchestration/agent-orchestrator.js +1 -1
  86. package/dist/src/agent/service/direct-turn-helpers.js +1 -1
  87. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  88. package/dist/src/config/schema.d.ts +4 -0
  89. package/dist/src/config/schema.js +1 -0
  90. package/dist/src/connectors/connected-source-understanding.js +35 -21
  91. package/dist/src/connectors/learning-coordinator.js +1 -42
  92. package/dist/src/gateway/chat-stream/mapper.d.ts +2 -0
  93. package/dist/src/gateway/chat-stream/mapper.js +5 -0
  94. package/dist/src/gateway/hono/routes/understanding-sources.js +4 -1
  95. package/dist/src/gateway/hono/routes/you.js +29 -11
  96. package/dist/src/gateway/service/run-gateway-agent.js +5 -1
  97. package/dist/src/knowledge/index.d.ts +0 -1
  98. package/dist/src/knowledge/index.js +1 -2
  99. package/dist/src/notifications/planner.js +5 -1
  100. package/dist/src/storage/sqlite/index.d.ts +1 -1
  101. package/dist/src/storage/sqlite/index.js +2 -2
  102. package/dist/src/storage/sqlite/migrations/137_understanding_status_audit.sql +71 -0
  103. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  104. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  105. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  106. package/dist/src/storage/sqlite/schema.js +1 -1
  107. package/dist/src/storage/sqlite/user-context-repository.d.ts +16 -4
  108. package/dist/src/storage/sqlite/user-context-repository.js +56 -12
  109. package/dist/src/user-context/config.d.ts +8 -0
  110. package/dist/src/user-context/config.js +3 -0
  111. package/dist/src/user-context/consolidation.js +16 -4
  112. package/dist/src/user-context/extraction/executor.d.ts +22 -0
  113. package/dist/src/user-context/extraction/executor.js +142 -0
  114. package/dist/src/user-context/extraction/registry.d.ts +1 -1
  115. package/dist/src/user-context/extraction/registry.js +5 -34
  116. package/dist/src/user-context/extraction/repair.js +4 -1
  117. package/dist/src/user-context/extraction/semantic.d.ts +18 -0
  118. package/dist/src/user-context/extraction/semantic.js +148 -0
  119. package/dist/src/user-context/understandingQuality.js +4 -0
  120. package/dist/src/work-discovery/analyzer.js +9 -4
  121. package/dist/src/work-discovery/service.d.ts +1 -0
  122. package/dist/src/work-discovery/service.js +5 -4
  123. package/dist/src/work-discovery/types.d.ts +1 -0
  124. package/package.json +14 -8
  125. package/dist/gateway/static/root/assets/settings-advanced-gate-Cco_W41x.js +0 -1
  126. package/dist/src/agent/memory/understanding/correction.d.ts +0 -3
  127. package/dist/src/agent/memory/understanding/correction.js +0 -39
  128. package/dist/src/knowledge/connected-understanding-pipeline.d.ts +0 -17
  129. package/dist/src/knowledge/connected-understanding-pipeline.js +0 -278
@@ -0,0 +1,142 @@
1
+ import { createContextEvidence, getTurnPersonalization, getUnderstanding, recordContextFeedback, rejectUnderstanding, setUnderstandingStatus } from "../../storage/sqlite/user-context-repository.js";
2
+ import { getSessionMetadata } from "../../storage/sqlite/session-repository.js";
3
+ import "../../storage/sqlite/index.js";
4
+ import { extractionInputHash } from "./registry.js";
5
+ //#region src/user-context/extraction/executor.ts
6
+ function emptyUnderstandingReview() {
7
+ return {
8
+ proposed: 0,
9
+ created: 0,
10
+ deduplicated: 0,
11
+ rejected: 0,
12
+ createdRecords: [],
13
+ writeOutputs: []
14
+ };
15
+ }
16
+ function resolveWritePolicy(config) {
17
+ const memory = config?.userContext.memory;
18
+ if (!memory || memory.mode === "off" || memory.mode === "readOnly") return "deny";
19
+ return memory.writePolicy?.understanding ?? (memory.mode === "auto" ? "allow" : "confirm");
20
+ }
21
+ function recordTargetFeedback(turnId, targetIds, rating, reason) {
22
+ if (!turnId || targetIds.length === 0) return;
23
+ const personalization = getTurnPersonalization(turnId);
24
+ if (!personalization) return;
25
+ for (const objectId of targetIds) recordContextFeedback({
26
+ turnId,
27
+ runId: personalization.runId,
28
+ objectType: "understanding",
29
+ objectId,
30
+ rating,
31
+ reason
32
+ });
33
+ }
34
+ async function executeUnderstandingInterpretation(params) {
35
+ const { interpretation } = params;
36
+ const result = emptyUnderstandingReview();
37
+ const targets = interpretation.targetUnderstandingIds.flatMap((id) => {
38
+ const item = getUnderstanding(id);
39
+ return item ? [item] : [];
40
+ });
41
+ const targetIds = targets.map((item) => item.id);
42
+ const policy = resolveWritePolicy(params.getConfig());
43
+ if (interpretation.intent === "memory_forget") {
44
+ for (const target of targets) {
45
+ const rejected = rejectUnderstanding(target.id, "explicit user forget request", "user");
46
+ result.writeOutputs.push({
47
+ candidateKey: rejected.canonicalKey,
48
+ objectId: rejected.id,
49
+ versionId: rejected.versionId,
50
+ outcome: "rejected"
51
+ });
52
+ }
53
+ result.rejected += targets.length;
54
+ recordTargetFeedback(params.turnId, targetIds, "irrelevant", "explicit_user_forget_request");
55
+ return result;
56
+ }
57
+ if (interpretation.intent === "memory_confirm" && policy !== "deny") {
58
+ for (const target of targets) {
59
+ const confirmed = setUnderstandingStatus(target.id, "active", {
60
+ explicitness: "explicit",
61
+ confidence: 1,
62
+ actorType: "user",
63
+ source: "semantic-memory-confirmation"
64
+ });
65
+ result.createdRecords.push({
66
+ id: confirmed.id,
67
+ content: confirmed.statement,
68
+ kind: confirmed.kind,
69
+ status: confirmed.status
70
+ });
71
+ result.writeOutputs.push({
72
+ candidateKey: confirmed.canonicalKey,
73
+ objectId: confirmed.id,
74
+ versionId: confirmed.versionId,
75
+ outcome: "deduplicated"
76
+ });
77
+ result.deduplicated += 1;
78
+ }
79
+ recordTargetFeedback(params.turnId, targetIds, "helpful", "explicit_user_confirmation");
80
+ }
81
+ if (interpretation.intent === "memory_correct" && targets.length && interpretation.candidates.length === 0) {
82
+ for (const target of targets) setUnderstandingStatus(target.id, "needs_review", {
83
+ actorType: "user",
84
+ source: "semantic-memory-correction"
85
+ });
86
+ recordTargetFeedback(params.turnId, targetIds, "wrong", "explicit_user_correction_without_replacement");
87
+ return result;
88
+ }
89
+ if (interpretation.candidates.length === 0) return result;
90
+ if (policy === "deny") {
91
+ result.proposed = interpretation.candidates.length;
92
+ result.rejected = interpretation.candidates.length;
93
+ return result;
94
+ }
95
+ const evidenceByRef = new Map(params.evidence.map((entry) => [entry.ref, entry]));
96
+ const candidates = interpretation.candidates.map((candidate) => ({
97
+ ...candidate,
98
+ explicitness: policy === "confirm" && candidate.explicitness === "explicit" ? "observed" : candidate.explicitness
99
+ }));
100
+ const evidenceIdsByRef = /* @__PURE__ */ new Map();
101
+ for (const ref of new Set(candidates.flatMap((candidate) => candidate.evidenceRefs))) {
102
+ const entry = evidenceByRef.get(ref);
103
+ if (!entry || entry.role !== "user") continue;
104
+ const evidence = createContextEvidence({
105
+ sourceType: "conversation",
106
+ sourceRef: `session:${params.sessionKey}:entry:${entry.ref}`,
107
+ sourceRunId: params.extractionRunId,
108
+ sessionId: params.sessionKey,
109
+ ...params.turnId ? { turnId: params.turnId } : {},
110
+ messageId: entry.ref,
111
+ contentHash: extractionInputHash(JSON.stringify(entry.message)),
112
+ retentionPolicy: "derived_only",
113
+ processingPolicy: params.processingPolicy,
114
+ extractorId: params.extractorId,
115
+ extractorVersion: "1",
116
+ trustLevel: "owner",
117
+ observedAt: entry.createdAt
118
+ });
119
+ evidenceIdsByRef.set(ref, evidence.id);
120
+ }
121
+ const projectId = getSessionMetadata(params.sessionKey)?.projectId;
122
+ for (const candidate of candidates) {
123
+ const applied = await params.memoryManager.applyUnderstandingCandidates([candidate], {
124
+ sessionKey: params.sessionKey,
125
+ ...projectId ? { projectId } : {},
126
+ evidenceIds: candidate.evidenceRefs.flatMap((ref) => evidenceIdsByRef.get(ref) ?? []),
127
+ reviewSource: params.reviewSource,
128
+ extractionRunId: params.extractionRunId,
129
+ ...interpretation.intent === "memory_correct" ? { supersedesRecordIds: targetIds } : {}
130
+ });
131
+ result.proposed += applied.proposed;
132
+ result.created += applied.created;
133
+ result.deduplicated += applied.deduplicated;
134
+ result.rejected += applied.rejected;
135
+ result.createdRecords.push(...applied.createdRecords);
136
+ result.writeOutputs.push(...applied.writeOutputs ?? []);
137
+ }
138
+ if (interpretation.intent === "memory_correct" && result.created > 0) recordTargetFeedback(params.turnId, targetIds, "wrong", "explicit_user_correction_with_replacement");
139
+ return result;
140
+ }
141
+ //#endregion
142
+ export { emptyUnderstandingReview, executeUnderstandingInterpretation };
@@ -1,6 +1,6 @@
1
1
  import { type ContextExtractionRun } from '../../storage/sqlite/index.js';
2
2
  import type { UnderstandingKind } from '../domain.js';
3
- export type ExtractorId = 'explicit-command' | 'deterministic-signal' | 'transcript-synthesis' | 'connector-structural' | 'connector-semantic';
3
+ export type ExtractorId = 'turn-semantics' | 'transcript-synthesis' | 'connector-semantic';
4
4
  export type ExtractorDefinition = {
5
5
  id: ExtractorId;
6
6
  version: string;
@@ -14,62 +14,33 @@ const UNDERSTANDING_KINDS = [
14
14
  "derived_insight"
15
15
  ];
16
16
  const DEFINITIONS = {
17
- "explicit-command": {
18
- id: "explicit-command",
17
+ "turn-semantics": {
18
+ id: "turn-semantics",
19
19
  version: "1",
20
20
  inputKinds: ["conversation"],
21
21
  requiredProcessingPolicy: "local_only",
22
22
  authorityCeiling: "user_explicit",
23
23
  candidateKinds: UNDERSTANDING_KINDS,
24
24
  maxAutomaticStatus: "active",
25
- timeoutMs: 500
26
- },
27
- "deterministic-signal": {
28
- id: "deterministic-signal",
29
- version: "1",
30
- inputKinds: ["conversation", "task"],
31
- requiredProcessingPolicy: "local_only",
32
- authorityCeiling: "user_observed",
33
- candidateKinds: UNDERSTANDING_KINDS,
34
- maxAutomaticStatus: "candidate",
35
- timeoutMs: 500
25
+ timeoutMs: 3e4
36
26
  },
37
27
  "transcript-synthesis": {
38
28
  id: "transcript-synthesis",
39
29
  version: "1",
40
30
  inputKinds: ["conversation"],
41
- requiredProcessingPolicy: "remote_allowed",
31
+ requiredProcessingPolicy: "local_only",
42
32
  authorityCeiling: "system_inferred",
43
33
  candidateKinds: UNDERSTANDING_KINDS,
44
34
  maxAutomaticStatus: "candidate",
45
35
  timeoutMs: 3e4
46
36
  },
47
- "connector-structural": {
48
- id: "connector-structural",
49
- version: "1",
50
- inputKinds: ["connector"],
51
- requiredProcessingPolicy: "local_only",
52
- authorityCeiling: "external_untrusted",
53
- candidateKinds: [
54
- "project_context",
55
- "current_state",
56
- "routine"
57
- ],
58
- maxAutomaticStatus: "candidate",
59
- timeoutMs: 1e4
60
- },
61
37
  "connector-semantic": {
62
38
  id: "connector-semantic",
63
39
  version: "1",
64
40
  inputKinds: ["connector", "file"],
65
41
  requiredProcessingPolicy: "remote_allowed",
66
42
  authorityCeiling: "external_untrusted",
67
- candidateKinds: [
68
- "preference",
69
- "routine",
70
- "current_state",
71
- "project_context"
72
- ],
43
+ candidateKinds: ["preference", "routine"],
73
44
  maxAutomaticStatus: "candidate",
74
45
  timeoutMs: 3e4
75
46
  }
@@ -39,7 +39,10 @@ function repairExtractedContext(filter) {
39
39
  });
40
40
  continue;
41
41
  }
42
- setUnderstandingStatus(output.objectId, "archived");
42
+ setUnderstandingStatus(output.objectId, "archived", {
43
+ actorType: "runtime",
44
+ source: "context-extraction-repair"
45
+ });
43
46
  } else {
44
47
  const focus = listUserFocuses().find((item) => item.id === output.objectId);
45
48
  if (!focus) continue;
@@ -0,0 +1,18 @@
1
+ import type { UnderstandingCandidate } from '../../agent/memory/understanding/types.js';
2
+ export declare const UNDERSTANDING_INTENTS: readonly ["memory_create", "memory_query", "memory_confirm", "memory_correct", "memory_forget", "user_assertion", "task_request", "none"];
3
+ export type UnderstandingIntent = typeof UNDERSTANDING_INTENTS[number];
4
+ export type SemanticEvidence = {
5
+ ref: string;
6
+ role: 'user' | 'assistant';
7
+ text: string;
8
+ };
9
+ export type SemanticUnderstandingCandidate = UnderstandingCandidate & {
10
+ evidenceRefs: string[];
11
+ };
12
+ export type SemanticUnderstandingInterpretation = {
13
+ intent: UnderstandingIntent;
14
+ candidates: SemanticUnderstandingCandidate[];
15
+ targetUnderstandingIds: string[];
16
+ abstentionReason?: string;
17
+ };
18
+ export declare function parseSemanticUnderstanding(raw: string, evidence: SemanticEvidence[], allowedTargetIds?: string[]): SemanticUnderstandingInterpretation | null;
@@ -0,0 +1,148 @@
1
+ import { UNDERSTANDING_KINDS } from "../domain.js";
2
+ import { isDurableUnderstandingCandidate } from "../understandingQuality.js";
3
+ import { inferMemorySensitivity } from "../../agent/memory/sensitivity.js";
4
+ import { z } from "zod";
5
+ //#region src/user-context/extraction/semantic.ts
6
+ const UNDERSTANDING_INTENTS = [
7
+ "memory_create",
8
+ "memory_query",
9
+ "memory_confirm",
10
+ "memory_correct",
11
+ "memory_forget",
12
+ "user_assertion",
13
+ "task_request",
14
+ "none"
15
+ ];
16
+ const EvidenceSchema = z.object({
17
+ ref: z.string().min(1),
18
+ quote: z.string().min(1)
19
+ }).strict();
20
+ const CandidateSchema = z.object({
21
+ factKey: z.string().regex(/^[a-z0-9][a-z0-9:-]{2,119}$/),
22
+ statement: z.string().min(4).max(600),
23
+ kind: z.enum(UNDERSTANDING_KINDS),
24
+ explicitness: z.enum([
25
+ "explicit",
26
+ "observed",
27
+ "inferred"
28
+ ]),
29
+ durability: z.enum([
30
+ "ephemeral",
31
+ "durable",
32
+ "recurring"
33
+ ]),
34
+ scopeHint: z.enum([
35
+ "global",
36
+ "workspace",
37
+ "project",
38
+ "session"
39
+ ]),
40
+ confidence: z.number().min(0).max(1),
41
+ importance: z.number().min(0).max(1),
42
+ sensitivity: z.enum([
43
+ "normal",
44
+ "personal",
45
+ "secret",
46
+ "regulated"
47
+ ]).optional(),
48
+ disclosurePolicy: z.enum([
49
+ "silent",
50
+ "referenceable",
51
+ "ask_before_reference"
52
+ ]).optional(),
53
+ evidence: z.array(EvidenceSchema).min(1).max(8),
54
+ selfContained: z.boolean(),
55
+ unresolvedReferences: z.array(z.string()).max(8)
56
+ }).strict();
57
+ const InterpretationSchema = z.object({
58
+ intent: z.enum(UNDERSTANDING_INTENTS),
59
+ candidates: z.array(CandidateSchema).max(8),
60
+ targetUnderstandingIds: z.array(z.string().min(1)).max(8),
61
+ abstentionReason: z.string().max(500).optional()
62
+ }).strict();
63
+ const CANDIDATE_INTENTS = new Set([
64
+ "memory_create",
65
+ "memory_confirm",
66
+ "memory_correct",
67
+ "user_assertion"
68
+ ]);
69
+ const QUESTION_END = /[??]\s*$/u;
70
+ function extractJson(raw) {
71
+ const fenced = /```(?:json)?\s*([\s\S]*?)```/i.exec(raw)?.[1];
72
+ const start = raw.indexOf("{");
73
+ const end = raw.lastIndexOf("}");
74
+ const candidate = fenced ?? (start >= 0 && end > start ? raw.slice(start, end + 1) : raw);
75
+ return JSON.parse(candidate);
76
+ }
77
+ function comparableText(value) {
78
+ return value.normalize("NFKC").toLocaleLowerCase().replace(/\s+/g, " ").trim();
79
+ }
80
+ function quoteIsGrounded(quote, source) {
81
+ return comparableText(source).includes(comparableText(quote));
82
+ }
83
+ function bigramSimilarity(left, right) {
84
+ const pairs = (value) => {
85
+ const normalized = comparableText(value).replace(/[^\p{L}\p{N}]/gu, "");
86
+ const output = /* @__PURE__ */ new Set();
87
+ for (let index = 0; index < normalized.length - 1; index += 1) output.add(normalized.slice(index, index + 2));
88
+ return output;
89
+ };
90
+ const a = pairs(left);
91
+ const b = pairs(right);
92
+ if (!a.size || !b.size) return 0;
93
+ let overlap = 0;
94
+ for (const pair of a) if (b.has(pair)) overlap += 1;
95
+ return 2 * overlap / (a.size + b.size);
96
+ }
97
+ function effectiveExplicitness(intent, declared) {
98
+ if (intent === "memory_create" || intent === "memory_correct" || intent === "memory_confirm") return declared;
99
+ return declared === "explicit" ? "observed" : declared;
100
+ }
101
+ function parseSemanticUnderstanding(raw, evidence, allowedTargetIds = []) {
102
+ let parsed;
103
+ try {
104
+ const result = InterpretationSchema.safeParse(extractJson(raw));
105
+ if (!result.success) return null;
106
+ parsed = result.data;
107
+ } catch {
108
+ return null;
109
+ }
110
+ const evidenceByRef = new Map(evidence.map((item) => [item.ref, item]));
111
+ const allowedTargets = new Set(allowedTargetIds);
112
+ const candidates = [];
113
+ if (CANDIDATE_INTENTS.has(parsed.intent)) for (const item of parsed.candidates) {
114
+ if (!item.selfContained || item.unresolvedReferences.length > 0) continue;
115
+ if (QUESTION_END.test(item.statement)) continue;
116
+ if (!isDurableUnderstandingCandidate(item.kind, item.statement)) continue;
117
+ if (!item.evidence.every((claim) => {
118
+ const source = evidenceByRef.get(claim.ref);
119
+ return source?.role === "user" && quoteIsGrounded(claim.quote, source.text);
120
+ })) continue;
121
+ if (item.explicitness === "explicit") {
122
+ const quotedText = item.evidence.map((claim) => claim.quote).join(" ");
123
+ if (bigramSimilarity(item.statement, quotedText) < .45) continue;
124
+ }
125
+ const evidenceRefs = [...new Set(item.evidence.map((claim) => claim.ref))];
126
+ candidates.push({
127
+ kind: item.kind,
128
+ content: item.statement.trim(),
129
+ canonicalKey: `understanding:${item.kind}:${item.factKey}`,
130
+ confidence: item.confidence,
131
+ importance: item.importance,
132
+ explicitness: effectiveExplicitness(parsed.intent, item.explicitness),
133
+ durability: item.durability,
134
+ sensitivity: item.sensitivity ?? inferMemorySensitivity(item.statement),
135
+ disclosurePolicy: item.disclosurePolicy ?? "referenceable",
136
+ payload: { scopeHint: item.scopeHint },
137
+ evidenceRefs
138
+ });
139
+ }
140
+ return {
141
+ intent: parsed.intent,
142
+ candidates,
143
+ targetUnderstandingIds: [...new Set(parsed.targetUnderstandingIds.filter((id) => allowedTargets.has(id)))],
144
+ ...parsed.abstentionReason ? { abstentionReason: parsed.abstentionReason } : {}
145
+ };
146
+ }
147
+ //#endregion
148
+ export { UNDERSTANDING_INTENTS, parseSemanticUnderstanding };
@@ -2,6 +2,8 @@
2
2
  const INCOMPLETE_PREFIX = /^(?:and\b|also\b|then\b|plus\b|as\s+well\s+as\b|which\b|that\b|并且|并将|以及|然后|同时|另外|还有|而且|或者|的事项|事项[,,、::]?)/i;
3
3
  const DEFERRED_OR_NEGATED_ACTION = /(?:not\s+now|no\s+need\s+to|do\s+not\s+(?:start|proceed)|don't\s+(?:start|proceed)|later\s+maybe|暂时不用|暂时不(?:用|要|开始)?|先不用|无需|不用开始|不要推进|不需要推进)/i;
4
4
  const ONE_OFF_ACTION_PREFIX = /^(?:please\s+|update\b|investigate\b|summari[sz]e\b|fix\b|write\b|add\b|record\b|track\b)|^(?:请|帮我|更新|调查|汇总|整理|修复|写入|加入|记录|跟进)/i;
5
+ const DURABLE_MARKER = /(?:从现在起|今后|以后|长期|每次|每回|始终|一直|默认|下次|教训|原则|习惯|from now on|going forward|long[- ]term|every time|always|by default|next time|lesson|principle|habit)/i;
6
+ const TURN_EXECUTION_INSTRUCTION = /(?:不要再问|别再问|直接执行|立即执行|当前任务|这次|本次|现在就|do not ask|don't ask|just do it|execute directly|proceed now|this task|this time)/i;
5
7
  function meaningfulLength(content) {
6
8
  return content.normalize("NFKC").replace(/[\p{P}\p{S}\s]/gu, "").length;
7
9
  }
@@ -15,6 +17,8 @@ function isActionableUnderstandingContent(content) {
15
17
  function isDurableUnderstandingCandidate(kind, content) {
16
18
  if (!isStandaloneUnderstandingContent(content)) return false;
17
19
  if ((kind === "commitment" || kind === "long_term_goal") && ONE_OFF_ACTION_PREFIX.test(content.trim())) return false;
20
+ if (kind === "task_lesson" && !DURABLE_MARKER.test(content)) return false;
21
+ if (kind === "boundary" && TURN_EXECUTION_INSTRUCTION.test(content) && !DURABLE_MARKER.test(content)) return false;
18
22
  return true;
19
23
  }
20
24
  function comparableText(content) {
@@ -83,7 +83,9 @@ function validateProfileCandidate(value, allowedRefs) {
83
83
  if (!value || typeof value !== "object") return null;
84
84
  const item = value;
85
85
  const category = item.category === "role" || item.category === "responsibility" || item.category === "preference" || item.category === "routine" ? item.category : void 0;
86
- if (!category || typeof item.statement !== "string") return null;
86
+ if (!category || typeof item.statement !== "string" || typeof item.factKey !== "string") return null;
87
+ const factKey = item.factKey.trim().toLocaleLowerCase();
88
+ if (!/^[a-z0-9][a-z0-9:-]{2,119}$/.test(factKey)) return null;
87
89
  const statement = item.statement.trim().slice(0, 500);
88
90
  if (statement.length < 4) return null;
89
91
  const confidence = item.confidence === "high" || item.confidence === "low" ? item.confidence : "medium";
@@ -92,6 +94,7 @@ function validateProfileCandidate(value, allowedRefs) {
92
94
  return {
93
95
  id: randomUUID(),
94
96
  category,
97
+ factKey,
95
98
  statement,
96
99
  confidence,
97
100
  evidence: strings(item.evidence, 4).map((entry) => entry.slice(0, 300)),
@@ -183,7 +186,8 @@ async function analyzeWorkContext(input) {
183
186
  "Return only one JSON object with projectSummary, currentState, uncertainties, suggestions, profileCandidates, workThreads, conversationStarter, lowConfidence, and contextQuestion.",
184
187
  "profileCandidates contains only user-specific role, responsibility, preference, or routine facts that are directly supported and would remain useful outside this repository snapshot.",
185
188
  "Do not put the project stack, packages, architecture, deployment setup, repository conventions, or current task in profileCandidates. Put project facts in projectSummary/currentState and current work in workThreads.",
186
- "Each profile candidate has category (role, responsibility, preference, or routine), statement, confidence, and evidence.",
189
+ "Each profile candidate has category (role, responsibility, preference, or routine), factKey, statement, confidence, and evidence.",
190
+ "factKey is a stable language-neutral lowercase identifier such as workflow:code-review:github; equivalent facts in different languages must use the same factKey.",
187
191
  USER_FACING_UNDERSTANDING_WRITING_GUIDANCE,
188
192
  "Do not infer sensitive traits, identity, health, finances, political views, or anything not directly supported by the work evidence.",
189
193
  "workThreads contains every distinct evidence-backed work stream with topicKey, title, summary, horizon, status, confidence, and evidenceRefs. Do not merge unrelated streams to force a fixed count.",
@@ -288,7 +292,8 @@ async function analyzeUnderstandingBatch(input) {
288
292
  "Return only one JSON object with profileCandidates and workThreads.",
289
293
  "Return at most 8 profileCandidates and at most 8 workThreads. Prefer the strongest distinct findings.",
290
294
  "profileCandidates contains only user-specific role, responsibility, preference, or routine facts with direct support. Current tasks belong in workThreads; project technologies, packages, architecture, and repository conventions are not user facts.",
291
- "Each profile candidate has category (role, responsibility, preference, or routine), statement, confidence, evidence, and evidenceRefs.",
295
+ "Each profile candidate has category (role, responsibility, preference, or routine), factKey, statement, confidence, evidence, and evidenceRefs.",
296
+ "factKey is a stable language-neutral lowercase identifier such as workflow:code-review:github; equivalent facts in different languages must use the same factKey.",
292
297
  USER_FACING_UNDERSTANDING_WRITING_GUIDANCE,
293
298
  "Each work thread has topicKey, title, summary, status, horizon, confidence, and evidenceRefs.",
294
299
  "Every evidenceRefs value must be one of the supplied refs. Omit anything without direct support.",
@@ -359,7 +364,7 @@ function mergeProfileCandidates(candidates) {
359
364
  high: 3
360
365
  };
361
366
  for (const candidate of candidates) {
362
- const key = `${candidate.category}:${candidate.statement.toLocaleLowerCase().replace(/[^\p{L}\p{N}]+/gu, " ").trim()}`;
367
+ const key = `${candidate.category}:${candidate.factKey}`;
363
368
  const existing = merged.get(key);
364
369
  if (!existing) {
365
370
  merged.set(key, candidate);
@@ -68,6 +68,7 @@ export declare class WorkDiscoveryService {
68
68
  understandingId: string;
69
69
  id: string;
70
70
  category: "role" | "responsibility" | "preference" | "routine";
71
+ factKey: string;
71
72
  statement: string;
72
73
  confidence: "high" | "medium" | "low";
73
74
  evidence: string[];
@@ -164,8 +164,7 @@ function understandingKind(category) {
164
164
  return "project_context";
165
165
  }
166
166
  function understandingKey(candidate) {
167
- const normalized = candidate.statement.toLocaleLowerCase().replace(/[^\p{L}\p{N}]+/gu, " ").trim();
168
- return `work-discovery:${candidate.category}:${createHash("sha256").update(normalized).digest("hex").slice(0, 20)}`;
167
+ return `understanding:${understandingKind(candidate.category)}:${candidate.factKey}`;
169
168
  }
170
169
  function sameScope(left, right) {
171
170
  return left.type === right.type && left.id === right.id;
@@ -202,7 +201,7 @@ function decideUnderstanding(input, expectedSourcePrefix) {
202
201
  const current = getUnderstanding(input.understandingId);
203
202
  const owned = current && listUnderstandingEvidence(current.id).some((evidence) => evidence.sourceRef.startsWith(expectedSourcePrefix));
204
203
  if (!current || !owned || current.status === "archived") return void 0;
205
- if (input.status === "rejected") return rejectUnderstanding(current.id, "Rejected from work discovery review");
204
+ if (input.status === "rejected") return rejectUnderstanding(current.id, "Rejected from work discovery review", "user");
206
205
  const statement = input.status === "edited" ? input.statement?.trim().slice(0, 500) : void 0;
207
206
  if (input.status === "edited" && !statement) return void 0;
208
207
  return setUnderstandingStatus((statement ? reviseUnderstanding(current.id, statement, {
@@ -211,7 +210,9 @@ function decideUnderstanding(input, expectedSourcePrefix) {
211
210
  changeReason: "Edited during work discovery review"
212
211
  }) : current).id, "active", {
213
212
  explicitness: "explicit",
214
- confidence: 1
213
+ confidence: 1,
214
+ actorType: "user",
215
+ source: "work-discovery-review"
215
216
  });
216
217
  }
217
218
  function sessionMetadata(agentId, peerId) {
@@ -167,6 +167,7 @@ export interface WorkDiscoveryProfileCandidate {
167
167
  id: string;
168
168
  understandingId?: string;
169
169
  category: 'role' | 'responsibility' | 'preference' | 'routine';
170
+ factKey: string;
170
171
  statement: string;
171
172
  confidence: 'high' | 'medium' | 'low';
172
173
  evidence: string[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xopcai/xopc",
3
- "version": "0.0.228",
3
+ "version": "0.0.229",
4
4
  "description": "Local-first personal AI assistant with reviewable user understanding, durable tasks, workflows, automations, and local or cloud models.",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",
@@ -108,22 +108,27 @@
108
108
  "zod": "^4.4.3"
109
109
  },
110
110
  "peerDependencies": {
111
+ "@huggingface/transformers": "3.8.1",
111
112
  "@larksuiteoapi/node-sdk": "^1.66.0",
112
- "playwright-core": "^1.60.0"
113
+ "playwright-core": "^1.60.0",
114
+ "sherpa-onnx-node": "1.13.4"
113
115
  },
114
116
  "peerDependenciesMeta": {
117
+ "@huggingface/transformers": {
118
+ "optional": true
119
+ },
115
120
  "@larksuiteoapi/node-sdk": {
116
121
  "optional": true
117
122
  },
118
123
  "playwright-core": {
119
124
  "optional": true
125
+ },
126
+ "sherpa-onnx-node": {
127
+ "optional": true
120
128
  }
121
129
  },
122
- "optionalDependencies": {
123
- "@huggingface/transformers": "3.8.1",
124
- "sherpa-onnx-node": "1.13.4"
125
- },
126
130
  "devDependencies": {
131
+ "@huggingface/transformers": "3.8.1",
127
132
  "@larksuiteoapi/node-sdk": "^1.66.0",
128
133
  "@resvg/resvg-js": "^2.6.2",
129
134
  "@tailwindcss/vite": "^4.3.0",
@@ -147,6 +152,7 @@
147
152
  "onnxruntime-common": "1.21.0",
148
153
  "node-pty": "1.1.0",
149
154
  "playwright-core": "^1.60.0",
155
+ "sherpa-onnx-node": "1.13.4",
150
156
  "svgo": "4.0.2",
151
157
  "tailwindcss": "^4.3.0",
152
158
  "tsdown": "0.21.10",
@@ -158,9 +164,9 @@
158
164
  "vitest": "4.1.5",
159
165
  "vue": "^3.5.35",
160
166
  "@xopcai/endpoint-tools-protocol": "0.0.0",
161
- "@xopcai/realtime-protocol": "0.0.0",
162
167
  "@xopcai/gateway-contract": "0.0.0",
163
- "@xopcai/realtime-client": "0.0.0"
168
+ "@xopcai/realtime-client": "0.0.0",
169
+ "@xopcai/realtime-protocol": "0.0.0"
164
170
  },
165
171
  "scripts": {
166
172
  "assets:brand": "node scripts/generate-brand-assets.mjs",
@@ -1 +0,0 @@
1
- import{Or as e}from"./index-BX0dz1JK.js";function t(t){let{children:n,fallback:r}=t,i=r===void 0?null:r;return e()?n:i}export{t};
@@ -1,3 +0,0 @@
1
- export declare function isExplicitUnderstandingCorrection(text: string): boolean;
2
- /** Returns only a concrete replacement statement; pure denials intentionally return null. */
3
- export declare function extractExplicitUnderstandingCorrectionContent(text: string): string | null;
@@ -1,39 +0,0 @@
1
- //#region src/agent/memory/understanding/correction.ts
2
- const UNDERSTANDING_CORRECTION_PATTERNS = [
3
- /(?:你|您)(?:记错|理解错|搞错)(?:了)?(?:我|我的)/,
4
- /(?:这|那)(?:不是|并非)我的(?:偏好|习惯|情况|信息|边界)/,
5
- /我(?:没有|从没|从未)(?:说过|表示过|要求过)(?:这|那|这个|那个)/,
6
- /(?:不要|别再)(?:认为|假设|记成)(?:我|我的)/,
7
- /you (?:remembered|understood|got) (?:me|my .+?) wrong\b/i,
8
- /that(?:'s| is) not my (?:preference|habit|situation|information|boundary)\b/i,
9
- /i (?:never|did not|didn't) (?:say|said|tell you|told you|ask for|asked for) that\b/i,
10
- /do not assume that about me\b/i
11
- ];
12
- const UNDERSTANDING_CORRECTION_CONTENT_PATTERNS = [
13
- /(?:你|您)(?:记错|理解错|搞错)(?:了)?(?:我|我的)(?:偏好|习惯|情况|信息|边界|工作方式)?[,,::;;。]\s*(?:其实|实际上|正确的是)?\s*(.+)$/,
14
- /(?:这|那)(?:不是|并非)我的(?:偏好|习惯|情况|信息|边界)[,,::;;。]\s*(.+)$/,
15
- /you (?:remembered|understood|got) (?:me|my .+?) wrong\b[,:;.]?\s*(?:actually[,:]?\s*)?(.+)$/i,
16
- /that(?:'s| is) not my (?:preference|habit|situation|information|boundary)\b[,:;.]?\s*(.+)$/i
17
- ];
18
- function normalizeCorrectionContent(content) {
19
- const normalized = content.replace(/^[“”‘’"'\s]+|[“”‘’"'\s]+$/g, "").replace(/\s+/g, " ").trim();
20
- return normalized.length >= 4 ? normalized.slice(0, 600) : null;
21
- }
22
- function isExplicitUnderstandingCorrection(text) {
23
- const normalized = text.replace(/\s+/g, " ").trim();
24
- return normalized.length > 0 && UNDERSTANDING_CORRECTION_PATTERNS.some((pattern) => pattern.test(normalized));
25
- }
26
- /** Returns only a concrete replacement statement; pure denials intentionally return null. */
27
- function extractExplicitUnderstandingCorrectionContent(text) {
28
- const normalized = text.replace(/\s+/g, " ").trim();
29
- if (!isExplicitUnderstandingCorrection(normalized)) return null;
30
- for (const pattern of UNDERSTANDING_CORRECTION_CONTENT_PATTERNS) {
31
- const match = pattern.exec(normalized);
32
- if (!match?.[1]) continue;
33
- const content = normalizeCorrectionContent(match[1]);
34
- if (content) return content;
35
- }
36
- return null;
37
- }
38
- //#endregion
39
- export { extractExplicitUnderstandingCorrectionContent, isExplicitUnderstandingCorrection };
@@ -1,17 +0,0 @@
1
- import type { UnderstandingCandidate, UnderstandingReviewResult } from '../agent/memory/understanding/types.js';
2
- import type { MemoryManager } from '../agent/memory/manager.js';
3
- import type { KnowledgeSourceItem } from './types.js';
4
- export type ClaimObservation = {
5
- class: 'relationship' | 'project' | 'routine';
6
- key: string;
7
- value: Record<string, unknown>;
8
- items: KnowledgeSourceItem[];
9
- windowDays: number;
10
- };
11
- export declare function deriveConnectedClaimObservations(items: KnowledgeSourceItem[]): ClaimObservation[];
12
- export declare function renderConnectedObservation(observation: ClaimObservation): UnderstandingCandidate;
13
- export declare class ConnectedUnderstandingPipeline {
14
- private readonly memoryManager;
15
- constructor(memoryManager: MemoryManager);
16
- process(agentId: string, extractionRunId: string): Promise<UnderstandingReviewResult>;
17
- }