squish-memory 0.8.1 → 0.9.1

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 (266) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +2 -2
  3. package/.env.mcp +30 -0
  4. package/.mcp.json +2 -5
  5. package/CHANGELOG.md +111 -0
  6. package/QUICK-START.md +65 -0
  7. package/README.md +188 -530
  8. package/commands/managed-sync.ts +69 -0
  9. package/commands/mcp-server.ts +519 -0
  10. package/config/mcp-cli-fallback-policy.json +22 -0
  11. package/config/mcp-migration-map.json +22 -0
  12. package/config/mcp-mode-semantics.json +21 -0
  13. package/config/mcp-remote-auth.json +36 -0
  14. package/config/mcp-universal.schema.json +48 -0
  15. package/config/mcp.json +38 -0
  16. package/config/remote-memory-policy.json +32 -0
  17. package/dist/algorithms/merge/detection/hash-filters.js +2 -2
  18. package/dist/algorithms/merge/detection/hash-filters.js.map +1 -1
  19. package/dist/algorithms/merge/detection/two-stage-detector.d.ts +5 -2
  20. package/dist/algorithms/merge/detection/two-stage-detector.d.ts.map +1 -1
  21. package/dist/algorithms/merge/detection/two-stage-detector.js +139 -22
  22. package/dist/algorithms/merge/detection/two-stage-detector.js.map +1 -1
  23. package/dist/commands/managed-sync.d.ts +10 -0
  24. package/dist/commands/managed-sync.d.ts.map +1 -0
  25. package/dist/commands/managed-sync.js +64 -0
  26. package/dist/commands/managed-sync.js.map +1 -0
  27. package/dist/commands/mcp-server.d.ts +3 -0
  28. package/dist/commands/mcp-server.d.ts.map +1 -0
  29. package/dist/commands/mcp-server.js +389 -0
  30. package/dist/commands/mcp-server.js.map +1 -0
  31. package/dist/config.d.ts +24 -1
  32. package/dist/config.d.ts.map +1 -1
  33. package/dist/config.js +32 -1
  34. package/dist/config.js.map +1 -1
  35. package/dist/core/associations.d.ts +1 -1
  36. package/dist/core/associations.d.ts.map +1 -1
  37. package/dist/core/consolidation.d.ts +31 -0
  38. package/dist/core/consolidation.d.ts.map +1 -1
  39. package/dist/core/consolidation.js +237 -29
  40. package/dist/core/consolidation.js.map +1 -1
  41. package/dist/core/embeddings/google-multimodal.d.ts +14 -0
  42. package/dist/core/embeddings/google-multimodal.d.ts.map +1 -0
  43. package/dist/core/embeddings/google-multimodal.js +142 -0
  44. package/dist/core/embeddings/google-multimodal.js.map +1 -0
  45. package/dist/core/embeddings.d.ts +3 -2
  46. package/dist/core/embeddings.d.ts.map +1 -1
  47. package/dist/core/embeddings.js +61 -39
  48. package/dist/core/embeddings.js.map +1 -1
  49. package/dist/core/mcp/client.d.ts +17 -0
  50. package/dist/core/mcp/client.d.ts.map +1 -0
  51. package/dist/core/mcp/client.js +101 -0
  52. package/dist/core/mcp/client.js.map +1 -0
  53. package/dist/core/mcp/index.d.ts +6 -0
  54. package/dist/core/mcp/index.d.ts.map +1 -0
  55. package/dist/core/mcp/index.js +6 -0
  56. package/dist/core/mcp/index.js.map +1 -0
  57. package/dist/core/mcp/server.d.ts +18 -0
  58. package/dist/core/mcp/server.d.ts.map +1 -0
  59. package/dist/core/mcp/server.js +131 -0
  60. package/dist/core/mcp/server.js.map +1 -0
  61. package/dist/core/mcp/standalone-server.d.ts +13 -0
  62. package/dist/core/mcp/standalone-server.d.ts.map +1 -0
  63. package/dist/core/mcp/standalone-server.js +46 -0
  64. package/dist/core/mcp/standalone-server.js.map +1 -0
  65. package/dist/core/mcp/tools.d.ts +9 -0
  66. package/dist/core/mcp/tools.d.ts.map +1 -0
  67. package/dist/core/mcp/tools.js +262 -0
  68. package/dist/core/mcp/tools.js.map +1 -0
  69. package/dist/core/mcp/types.d.ts +315 -0
  70. package/dist/core/mcp/types.d.ts.map +1 -0
  71. package/dist/core/mcp/types.js +48 -0
  72. package/dist/core/mcp/types.js.map +1 -0
  73. package/dist/core/memory/categorizer.d.ts +27 -0
  74. package/dist/core/memory/categorizer.d.ts.map +1 -0
  75. package/dist/core/memory/categorizer.js +304 -0
  76. package/dist/core/memory/categorizer.js.map +1 -0
  77. package/dist/core/memory/conflict-detector.d.ts +7 -0
  78. package/dist/core/memory/conflict-detector.d.ts.map +1 -0
  79. package/dist/core/memory/conflict-detector.js +43 -0
  80. package/dist/core/memory/conflict-detector.js.map +1 -0
  81. package/dist/core/memory/context-collector.d.ts +10 -0
  82. package/dist/core/memory/context-collector.d.ts.map +1 -0
  83. package/dist/core/memory/context-collector.js +55 -0
  84. package/dist/core/memory/context-collector.js.map +1 -0
  85. package/dist/core/memory/contradiction-resolver.d.ts +40 -0
  86. package/dist/core/memory/contradiction-resolver.d.ts.map +1 -0
  87. package/dist/core/memory/contradiction-resolver.js +368 -0
  88. package/dist/core/memory/contradiction-resolver.js.map +1 -0
  89. package/dist/core/memory/edit-workflow.d.ts +19 -0
  90. package/dist/core/memory/edit-workflow.d.ts.map +1 -0
  91. package/dist/core/memory/edit-workflow.js +120 -0
  92. package/dist/core/memory/edit-workflow.js.map +1 -0
  93. package/dist/core/memory/feedback-tracker.d.ts +12 -0
  94. package/dist/core/memory/feedback-tracker.d.ts.map +1 -0
  95. package/dist/core/memory/feedback-tracker.js +151 -0
  96. package/dist/core/memory/feedback-tracker.js.map +1 -0
  97. package/dist/core/memory/hybrid-retrieval.d.ts +11 -12
  98. package/dist/core/memory/hybrid-retrieval.d.ts.map +1 -1
  99. package/dist/core/memory/hybrid-retrieval.js +56 -28
  100. package/dist/core/memory/hybrid-retrieval.js.map +1 -1
  101. package/dist/core/memory/hybrid-scorer.d.ts +5 -16
  102. package/dist/core/memory/hybrid-scorer.d.ts.map +1 -1
  103. package/dist/core/memory/hybrid-scorer.js +161 -125
  104. package/dist/core/memory/hybrid-scorer.js.map +1 -1
  105. package/dist/core/memory/hybrid-search.js +56 -20
  106. package/dist/core/memory/hybrid-search.js.map +1 -1
  107. package/dist/core/memory/memories.d.ts +4 -0
  108. package/dist/core/memory/memories.d.ts.map +1 -1
  109. package/dist/core/memory/memories.js +133 -60
  110. package/dist/core/memory/memories.js.map +1 -1
  111. package/dist/core/memory/progressive-disclosure.d.ts +43 -0
  112. package/dist/core/memory/progressive-disclosure.d.ts.map +1 -0
  113. package/dist/core/memory/progressive-disclosure.js +280 -0
  114. package/dist/core/memory/progressive-disclosure.js.map +1 -0
  115. package/dist/core/memory/query-rewriter.d.ts +13 -0
  116. package/dist/core/memory/query-rewriter.d.ts.map +1 -0
  117. package/dist/core/memory/query-rewriter.js +118 -0
  118. package/dist/core/memory/query-rewriter.js.map +1 -0
  119. package/dist/core/memory/response-analyzer.d.ts +9 -0
  120. package/dist/core/memory/response-analyzer.d.ts.map +1 -0
  121. package/dist/core/memory/response-analyzer.js +61 -0
  122. package/dist/core/memory/response-analyzer.js.map +1 -0
  123. package/dist/core/memory/stats.d.ts +17 -0
  124. package/dist/core/memory/stats.d.ts.map +1 -0
  125. package/dist/core/memory/stats.js +87 -0
  126. package/dist/core/memory/stats.js.map +1 -0
  127. package/dist/core/memory/telemetry.d.ts +69 -0
  128. package/dist/core/memory/telemetry.d.ts.map +1 -0
  129. package/dist/core/memory/telemetry.js +313 -0
  130. package/dist/core/memory/telemetry.js.map +1 -0
  131. package/dist/core/memory/temporal-facts.d.ts +41 -0
  132. package/dist/core/memory/temporal-facts.d.ts.map +1 -0
  133. package/dist/core/memory/temporal-facts.js +262 -0
  134. package/dist/core/memory/temporal-facts.js.map +1 -0
  135. package/dist/core/memory/trigger-detector.d.ts +14 -0
  136. package/dist/core/memory/trigger-detector.d.ts.map +1 -0
  137. package/dist/core/memory/trigger-detector.js +42 -0
  138. package/dist/core/memory/trigger-detector.js.map +1 -0
  139. package/dist/core/memory/write-gate.d.ts +54 -0
  140. package/dist/core/memory/write-gate.d.ts.map +1 -0
  141. package/dist/core/memory/write-gate.js +210 -0
  142. package/dist/core/memory/write-gate.js.map +1 -0
  143. package/dist/core/projects.d.ts +2 -0
  144. package/dist/core/projects.d.ts.map +1 -1
  145. package/dist/core/projects.js +33 -0
  146. package/dist/core/projects.js.map +1 -1
  147. package/dist/core/scheduler/cron-scheduler.d.ts +32 -0
  148. package/dist/core/scheduler/cron-scheduler.d.ts.map +1 -0
  149. package/dist/core/scheduler/cron-scheduler.js +238 -0
  150. package/dist/core/scheduler/cron-scheduler.js.map +1 -0
  151. package/dist/core/scheduler/heartbeat.d.ts +11 -0
  152. package/dist/core/scheduler/heartbeat.d.ts.map +1 -0
  153. package/dist/core/scheduler/heartbeat.js +73 -0
  154. package/dist/core/scheduler/heartbeat.js.map +1 -0
  155. package/dist/core/scheduler/index.d.ts +8 -0
  156. package/dist/core/scheduler/index.d.ts.map +1 -0
  157. package/dist/core/scheduler/index.js +8 -0
  158. package/dist/core/scheduler/index.js.map +1 -0
  159. package/dist/core/scheduler/job-runner.d.ts +11 -0
  160. package/dist/core/scheduler/job-runner.d.ts.map +1 -0
  161. package/dist/core/scheduler/job-runner.js +161 -0
  162. package/dist/core/scheduler/job-runner.js.map +1 -0
  163. package/dist/core/session/auto-load.d.ts +6 -0
  164. package/dist/core/session/auto-load.d.ts.map +1 -0
  165. package/dist/core/session/auto-load.js +119 -0
  166. package/dist/core/session/auto-load.js.map +1 -0
  167. package/dist/core/session/index.d.ts +7 -0
  168. package/dist/core/session/index.d.ts.map +1 -0
  169. package/dist/core/session/index.js +7 -0
  170. package/dist/core/session/index.js.map +1 -0
  171. package/dist/core/session/types.d.ts +26 -0
  172. package/dist/core/session/types.d.ts.map +1 -0
  173. package/dist/core/session/types.js +10 -0
  174. package/dist/core/session/types.js.map +1 -0
  175. package/dist/core/snapshots/comparison.d.ts.map +1 -1
  176. package/dist/core/snapshots/comparison.js +8 -2
  177. package/dist/core/snapshots/comparison.js.map +1 -1
  178. package/dist/core/utils/content-extraction.d.ts.map +1 -1
  179. package/dist/core/utils/content-extraction.js +11 -1
  180. package/dist/core/utils/content-extraction.js.map +1 -1
  181. package/dist/core/utils/summarization-helpers.d.ts.map +1 -1
  182. package/dist/core/utils/summarization-helpers.js +4 -1
  183. package/dist/core/utils/summarization-helpers.js.map +1 -1
  184. package/dist/core/utils.d.ts.map +1 -1
  185. package/dist/core/utils.js +26 -3
  186. package/dist/core/utils.js.map +1 -1
  187. package/dist/core/worker.d.ts +20 -0
  188. package/dist/core/worker.d.ts.map +1 -1
  189. package/dist/core/worker.js +86 -0
  190. package/dist/core/worker.js.map +1 -1
  191. package/dist/db/adapter.d.ts +1 -5
  192. package/dist/db/adapter.d.ts.map +1 -1
  193. package/dist/db/adapter.js +125 -12
  194. package/dist/db/adapter.js.map +1 -1
  195. package/dist/db/bootstrap.d.ts.map +1 -1
  196. package/dist/db/bootstrap.js +178 -3
  197. package/dist/db/bootstrap.js.map +1 -1
  198. package/dist/db/index.d.ts +1 -5
  199. package/dist/db/index.d.ts.map +1 -1
  200. package/dist/db/index.js +7 -4
  201. package/dist/db/index.js.map +1 -1
  202. package/dist/drizzle/schema-sqlite.d.ts +1953 -612
  203. package/dist/drizzle/schema-sqlite.d.ts.map +1 -1
  204. package/dist/drizzle/schema-sqlite.js +134 -0
  205. package/dist/drizzle/schema-sqlite.js.map +1 -1
  206. package/dist/drizzle/schema.d.ts +684 -3
  207. package/dist/drizzle/schema.d.ts.map +1 -1
  208. package/dist/drizzle/schema.js +81 -1
  209. package/dist/drizzle/schema.js.map +1 -1
  210. package/dist/index.d.ts +3 -3
  211. package/dist/index.js +152 -13
  212. package/dist/index.js.map +1 -1
  213. package/package.json +125 -103
  214. package/scripts/build-release.sh +33 -0
  215. package/scripts/db/check-db.mjs +88 -0
  216. package/scripts/db/fix-all-columns.mjs +52 -0
  217. package/scripts/db/fix-schema-all.mjs +55 -0
  218. package/scripts/db/fix-schema-full.mjs +46 -0
  219. package/scripts/db/fix-schema.mjs +38 -0
  220. package/scripts/db/init-db.mjs +13 -0
  221. package/scripts/db/recreate-db.mjs +14 -0
  222. package/scripts/generate-mcp.mjs +264 -0
  223. package/scripts/github-release.sh +61 -0
  224. package/scripts/init-dirs.mjs +13 -0
  225. package/scripts/init-dirs.ts +15 -0
  226. package/scripts/install-mcp.mjs +116 -0
  227. package/scripts/install-web.sh +120 -0
  228. package/scripts/install.mjs +340 -0
  229. package/scripts/openclaw-bootstrap.mjs +127 -0
  230. package/scripts/package-release.sh +71 -0
  231. package/scripts/remote-preflight.mjs +62 -0
  232. package/scripts/squish-fallback.mjs +132 -0
  233. package/scripts/test/test-all-systems.mjs +139 -0
  234. package/scripts/test/test-memory-system.mjs +139 -0
  235. package/scripts/test/test-v0.5.0.mjs +210 -0
  236. package/scripts/verify-mcp.mjs +214 -0
  237. package/skills/memory-guide/SKILL.md +181 -123
  238. package/skills/squish-cli/SKILL.md +200 -0
  239. package/skills/squish-mcp/SKILL.md +311 -0
  240. package/skills/squish-memory/SKILL.md +100 -62
  241. package/skills/squish-memory/claude-desktop.json +12 -0
  242. package/skills/squish-memory/install.mjs +335 -0
  243. package/skills/squish-memory/install.sh +94 -62
  244. package/skills/squish-memory/openclaw.json +13 -0
  245. package/skills/squish-memory/opencode.json +14 -0
  246. package/skills/squish-memory/skill.json +32 -0
  247. package/dist/adapters/claude-code/capture.d.ts +0 -11
  248. package/dist/adapters/claude-code/capture.d.ts.map +0 -1
  249. package/dist/adapters/claude-code/capture.js +0 -100
  250. package/dist/adapters/claude-code/capture.js.map +0 -1
  251. package/dist/adapters/claude-code/index.d.ts +0 -5
  252. package/dist/adapters/claude-code/index.d.ts.map +0 -1
  253. package/dist/adapters/claude-code/index.js +0 -6
  254. package/dist/adapters/claude-code/index.js.map +0 -1
  255. package/dist/adapters/claude-code/injection.d.ts +0 -34
  256. package/dist/adapters/claude-code/injection.d.ts.map +0 -1
  257. package/dist/adapters/claude-code/injection.js +0 -127
  258. package/dist/adapters/claude-code/injection.js.map +0 -1
  259. package/dist/adapters/claude-code/plugin-wrapper.d.ts +0 -21
  260. package/dist/adapters/claude-code/plugin-wrapper.d.ts.map +0 -1
  261. package/dist/adapters/claude-code/plugin-wrapper.js +0 -239
  262. package/dist/adapters/claude-code/plugin-wrapper.js.map +0 -1
  263. package/dist/adapters/claude-code/types.d.ts +0 -46
  264. package/dist/adapters/claude-code/types.d.ts.map +0 -1
  265. package/dist/adapters/claude-code/types.js +0 -6
  266. package/dist/adapters/claude-code/types.js.map +0 -1
@@ -1,40 +1,248 @@
1
- import { config } from '../config.js';
2
- async function clusterSimilarMemories(memories) {
3
- const clusters = [];
4
- const visited = new Set();
5
- const threshold = config.consolidationSimilarityThreshold || 0.8;
6
- for (const memory of memories) {
7
- if (visited.has(memory.id))
1
+ // Memory Consolidation & Deduplication
2
+ import { eq, inArray, and } from 'drizzle-orm';
3
+ import { getDb } from '../db/index.js';
4
+ import { getSchema } from '../db/schema.js';
5
+ import { createAssociation } from './associations.js';
6
+ import { logger } from './logger.js';
7
+ import { consolidateMemories } from './memory/consolidation.js';
8
+ /**
9
+ * Run automated deduplication job
10
+ * Finds and marks duplicates for review or auto-merges high-confidence duplicates
11
+ */
12
+ export async function runDeduplicationJob(projectId) {
13
+ const result = {
14
+ duplicatesFound: 0,
15
+ mergedCount: 0,
16
+ tokensRecovered: 0,
17
+ groups: [],
18
+ };
19
+ try {
20
+ const db = await getDb();
21
+ const schema = await getSchema();
22
+ // Get active memories for deduplication check
23
+ const whereClause = projectId
24
+ ? and(eq(schema.memories.projectId, projectId), eq(schema.memories.status, 'active'))
25
+ : eq(schema.memories.status, 'active');
26
+ const memories = await db
27
+ .select()
28
+ .from(schema.memories)
29
+ .where(whereClause)
30
+ .limit(500);
31
+ if (memories.length < 2) {
32
+ return result;
33
+ }
34
+ // Find duplicate groups using SimHash
35
+ const duplicateGroups = await findDuplicatesBySimHash(memories);
36
+ result.duplicatesFound = duplicateGroups.reduce((sum, g) => sum + g.duplicateIds.length, 0);
37
+ // Auto-merge high-confidence duplicates (>0.95 similarity)
38
+ for (const group of duplicateGroups) {
39
+ if (group.similarity >= 0.95) {
40
+ const tokensSaved = await autoMergeDuplicates(group.canonicalId, group.duplicateIds);
41
+ result.mergedCount += group.duplicateIds.length;
42
+ result.tokensRecovered += tokensSaved;
43
+ }
44
+ else {
45
+ // Lower confidence - just create association for review
46
+ for (const dupId of group.duplicateIds) {
47
+ await createAssociation(group.canonicalId, dupId, 'duplicate', group.similarity);
48
+ }
49
+ }
50
+ result.groups.push(group);
51
+ }
52
+ logger.info('Deduplication job completed', {
53
+ duplicatesFound: result.duplicatesFound,
54
+ mergedCount: result.mergedCount,
55
+ tokensRecovered: result.tokensRecovered,
56
+ });
57
+ }
58
+ catch (error) {
59
+ logger.error('Deduplication job error', error);
60
+ }
61
+ return result;
62
+ }
63
+ /**
64
+ * Find duplicates using SimHash (efficient near-duplicate detection)
65
+ */
66
+ async function findDuplicatesBySimHash(memories) {
67
+ const groups = [];
68
+ const processed = new Set();
69
+ // Compute SimHash for each memory
70
+ const hashes = memories.map(m => ({
71
+ id: m.id,
72
+ hash: computeSimHash(m.content),
73
+ content: m.content,
74
+ createdAt: m.createdAt,
75
+ }));
76
+ // Compare hashes to find similar content
77
+ for (let i = 0; i < hashes.length; i++) {
78
+ if (processed.has(hashes[i].id))
8
79
  continue;
9
- const cluster = [memory];
10
- visited.add(memory.id);
11
- for (const other of memories) {
12
- if (visited.has(other.id))
80
+ const duplicates = [];
81
+ let maxSimilarity = 0;
82
+ for (let j = i + 1; j < hashes.length; j++) {
83
+ if (processed.has(hashes[j].id))
13
84
  continue;
14
- const similarity = computeJaccardSimilarity(memory.content, other.content);
15
- if (similarity > threshold) {
16
- cluster.push(other);
17
- visited.add(other.id);
85
+ const hammingDistance = computeHammingDistance(hashes[i].hash, hashes[j].hash);
86
+ const similarity = 1 - (hammingDistance / 64); // 64-bit hash
87
+ if (similarity >= 0.85) {
88
+ duplicates.push(hashes[j].id);
89
+ maxSimilarity = Math.max(maxSimilarity, similarity);
90
+ processed.add(hashes[j].id);
18
91
  }
19
92
  }
20
- if (cluster.length > 0) {
21
- clusters.push(cluster);
93
+ if (duplicates.length > 0) {
94
+ processed.add(hashes[i].id);
95
+ groups.push({
96
+ canonicalId: hashes[i].id, // Keep oldest as canonical
97
+ duplicateIds: duplicates,
98
+ similarity: maxSimilarity,
99
+ reason: 'content-similarity',
100
+ });
22
101
  }
23
102
  }
24
- return clusters;
103
+ return groups;
25
104
  }
26
- function computeJaccardSimilarity(a, b) {
27
- const tokensA = new Set(a.toLowerCase().split(/\s+/).filter(t => t.length > 2));
28
- const tokensB = new Set(b.toLowerCase().split(/\s+/).filter(t => t.length > 2));
29
- const intersection = new Set([...tokensA].filter(x => tokensB.has(x)));
30
- const union = new Set([...tokensA, ...tokensB]);
31
- return union.size > 0 ? intersection.size / union.size : 0;
105
+ /**
106
+ * Compute SimHash for text (64-bit fingerprint)
107
+ */
108
+ function computeSimHash(text) {
109
+ const tokens = text.toLowerCase().split(/\s+/).filter(t => t.length > 2);
110
+ const weights = new Array(64).fill(0);
111
+ for (const token of tokens) {
112
+ const hash = simpleHash(token);
113
+ for (let i = 0; i < 64; i++) {
114
+ if ((hash >> BigInt(i)) & 1n) {
115
+ weights[i] += 1;
116
+ }
117
+ else {
118
+ weights[i] -= 1;
119
+ }
120
+ }
121
+ }
122
+ let simHash = 0n;
123
+ for (let i = 0; i < 64; i++) {
124
+ if (weights[i] > 0) {
125
+ simHash |= (1n << BigInt(i));
126
+ }
127
+ }
128
+ return simHash;
32
129
  }
33
- function estimateTokenRecovery(cluster) {
34
- let totalTokens = 0;
35
- for (const mem of cluster) {
36
- totalTokens += Math.ceil((mem.content || '').length / 4);
130
+ /**
131
+ * Simple hash function for strings
132
+ */
133
+ function simpleHash(str) {
134
+ let hash = 0n;
135
+ for (let i = 0; i < str.length; i++) {
136
+ const char = BigInt(str.charCodeAt(i));
137
+ hash = ((hash << 5n) - hash) + char;
138
+ hash = hash & hash; // Convert to 64bit integer
139
+ }
140
+ return hash;
141
+ }
142
+ /**
143
+ * Compute Hamming distance between two hashes
144
+ */
145
+ function computeHammingDistance(a, b) {
146
+ let xor = a ^ b;
147
+ let distance = 0;
148
+ while (xor !== 0n) {
149
+ distance += Number(xor & 1n);
150
+ xor >>= 1n;
151
+ }
152
+ return distance;
153
+ }
154
+ /**
155
+ * Auto-merge duplicates into canonical memory
156
+ */
157
+ async function autoMergeDuplicates(canonicalId, duplicateIds) {
158
+ try {
159
+ const db = await getDb();
160
+ const schema = await getSchema();
161
+ const now = new Date();
162
+ // Calculate tokens recovered
163
+ const duplicates = await db
164
+ .select()
165
+ .from(schema.memories)
166
+ .where(inArray(schema.memories.id, duplicateIds));
167
+ let tokensRecovered = 0;
168
+ for (const dup of duplicates) {
169
+ tokensRecovered += Math.ceil((dup.content?.length || 0) / 4);
170
+ }
171
+ // Mark duplicates as merged
172
+ await db
173
+ .update(schema.memories)
174
+ .set({
175
+ status: 'merged',
176
+ mergedInto: canonicalId,
177
+ mergedAt: now,
178
+ updatedAt: now,
179
+ })
180
+ .where(inArray(schema.memories.id, duplicateIds));
181
+ // Create associations for traceability
182
+ for (const dupId of duplicateIds) {
183
+ await createAssociation(canonicalId, dupId, 'merged', 0.95);
184
+ }
185
+ return tokensRecovered;
186
+ }
187
+ catch (error) {
188
+ logger.error('Error auto-merging duplicates', error);
189
+ return 0;
190
+ }
191
+ }
192
+ /**
193
+ * Run full consolidation job (dedup + memory consolidation)
194
+ */
195
+ export async function runFullConsolidationJob(projectId) {
196
+ const stats = {
197
+ clustered: 0,
198
+ merged: 0,
199
+ tokensRecovered: 0,
200
+ deduped: 0,
201
+ consolidated: 0,
202
+ };
203
+ // Run deduplication first
204
+ const dedupResult = await runDeduplicationJob(projectId);
205
+ stats.deduped = dedupResult.duplicatesFound;
206
+ stats.merged = dedupResult.mergedCount;
207
+ stats.tokensRecovered += dedupResult.tokensRecovered;
208
+ // Run memory consolidation for each project
209
+ if (projectId) {
210
+ const consolidationResults = await consolidateMemories({
211
+ projectId,
212
+ minAge: 60,
213
+ maxImportance: 25,
214
+ minClusterSize: 3,
215
+ limit: 100,
216
+ });
217
+ stats.consolidated = consolidationResults.length;
218
+ stats.clustered = consolidationResults.reduce((sum, r) => sum + r.clusterSize, 0);
219
+ }
220
+ logger.info('Full consolidation job completed', stats);
221
+ return stats;
222
+ }
223
+ /**
224
+ * Get deduplication statistics
225
+ */
226
+ export async function getDeduplicationStats(projectId) {
227
+ try {
228
+ const db = await getDb();
229
+ const schema = await getSchema();
230
+ const whereClause = projectId
231
+ ? eq(schema.memories.projectId, projectId)
232
+ : undefined;
233
+ const memories = await db
234
+ .select()
235
+ .from(schema.memories)
236
+ .where(whereClause);
237
+ return {
238
+ totalMemories: memories.length,
239
+ mergedMemories: memories.filter((m) => m.status === 'merged').length,
240
+ pendingDuplicates: 0, // Would need to query associations
241
+ };
242
+ }
243
+ catch (error) {
244
+ logger.error('Error getting deduplication stats', error);
245
+ return { totalMemories: 0, mergedMemories: 0, pendingDuplicates: 0 };
37
246
  }
38
- return Math.max(0, totalTokens - Math.ceil(cluster[0].content.length / 4));
39
247
  }
40
248
  //# sourceMappingURL=consolidation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"consolidation.js","sourceRoot":"","sources":["../../core/consolidation.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAWtC,KAAK,UAAU,sBAAsB,CAAC,QAAe;IACnD,MAAM,QAAQ,GAAY,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,SAAS,GAAG,MAAM,CAAC,gCAAgC,IAAI,GAAG,CAAC;IAEjE,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC9B,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAAE,SAAS;QAErC,MAAM,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAEvB,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;YAC7B,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;gBAAE,SAAS;YAEpC,MAAM,UAAU,GAAG,wBAAwB,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;YAC3E,IAAI,UAAU,GAAG,SAAS,EAAE,CAAC;gBAC3B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACpB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,wBAAwB,CAAC,CAAS,EAAE,CAAS;IACpD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;IAChF,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;IAEhF,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACvE,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC;IAEhD,OAAO,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,qBAAqB,CAAC,OAAc;IAC3C,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,WAAW,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;AAC7E,CAAC"}
1
+ {"version":3,"file":"consolidation.js","sourceRoot":"","sources":["../../core/consolidation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export interface MultimodalInput {
2
+ text?: string;
3
+ image?: Buffer | string;
4
+ video?: string;
5
+ }
6
+ export interface GoogleMultimodalResponse {
7
+ embedding: number[];
8
+ textEmbedding?: number[];
9
+ imageEmbedding?: number[];
10
+ videoEmbedding?: number[];
11
+ }
12
+ export declare function getGoogleMultimodalEmbedding(input: MultimodalInput): Promise<GoogleMultimodalResponse | null>;
13
+ export declare function isMultimodalInput(input: any): input is MultimodalInput;
14
+ //# sourceMappingURL=google-multimodal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-multimodal.d.ts","sourceRoot":"","sources":["../../../core/embeddings/google-multimodal.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,wBAAsB,4BAA4B,CAChD,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC,CAqF1C;AAmFD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,GAAG,GAAG,KAAK,IAAI,eAAe,CAQtE"}
@@ -0,0 +1,142 @@
1
+ import { logger } from '../logger.js';
2
+ import { config } from '../../config.js';
3
+ export async function getGoogleMultimodalEmbedding(input) {
4
+ if (!config.googleCloudApiKey && !config.googleCloudProject) {
5
+ logger.debug('Google Cloud credentials not configured');
6
+ return null;
7
+ }
8
+ try {
9
+ const endpoint = config.googleCloudLocation === 'global'
10
+ ? `https://aiplatform.googleapis.com/v1/projects/${config.googleCloudProject}/locations/${config.googleCloudLocation}/publishers/google/models/multimodalembedding@001:predict`
11
+ : `https://${config.googleCloudLocation}-aiplatform.googleapis.com/v1/projects/${config.googleCloudProject}/locations/${config.googleCloudLocation}/publishers/google/models/multimodalembedding@001:predict`;
12
+ const instances = [];
13
+ if (input.text) {
14
+ instances.push({ text: input.text });
15
+ }
16
+ if (input.image) {
17
+ const imageBytes = typeof input.image === 'string'
18
+ ? input.image
19
+ : input.image.toString('base64');
20
+ instances.push({
21
+ image: {
22
+ bytesBase64Encoded: imageBytes,
23
+ },
24
+ });
25
+ }
26
+ if (input.video) {
27
+ instances.push({
28
+ video: {
29
+ gcsUri: input.video,
30
+ },
31
+ });
32
+ }
33
+ if (instances.length === 0) {
34
+ return null;
35
+ }
36
+ const response = await fetch(endpoint, {
37
+ method: 'POST',
38
+ headers: {
39
+ 'Content-Type': 'application/json',
40
+ 'Authorization': `Bearer ${await getGoogleAccessToken()}`,
41
+ },
42
+ body: JSON.stringify({
43
+ instances,
44
+ parameters: {
45
+ dimension: 1408,
46
+ },
47
+ }),
48
+ });
49
+ if (!response.ok) {
50
+ const errorText = await response.text();
51
+ logger.warn(`Google Multimodal embeddings failed: ${response.status} ${errorText}`);
52
+ return null;
53
+ }
54
+ const data = await response.json();
55
+ const predictions = data.predictions || [];
56
+ const result = {
57
+ embedding: predictions[0]?.embedding || [],
58
+ };
59
+ if (input.text && predictions[0]?.textEmbedding) {
60
+ result.textEmbedding = predictions[0].textEmbedding;
61
+ }
62
+ if (input.image && predictions[0]?.imageEmbedding) {
63
+ result.imageEmbedding = predictions[0].imageEmbedding;
64
+ }
65
+ if (input.video && predictions[0]?.videoEmbedding) {
66
+ result.videoEmbedding = predictions[0].videoEmbedding;
67
+ }
68
+ return result.embedding.length > 0 ? result : null;
69
+ }
70
+ catch (error) {
71
+ logger.error('Google Multimodal embedding error:', error);
72
+ return null;
73
+ }
74
+ }
75
+ let cachedAccessToken = null;
76
+ let tokenExpiry = 0;
77
+ async function getGoogleAccessToken() {
78
+ if (config.googleCloudApiKey) {
79
+ return config.googleCloudApiKey;
80
+ }
81
+ if (cachedAccessToken && Date.now() < tokenExpiry) {
82
+ return cachedAccessToken;
83
+ }
84
+ if (!process.env.GOOGLE_APPLICATION_CREDENTIALS) {
85
+ throw new Error('Google Application Credentials not set');
86
+ }
87
+ try {
88
+ const credentials = JSON.parse(await import('fs').then(fs => fs.promises.readFile(process.env.GOOGLE_APPLICATION_CREDENTIALS, 'utf-8')));
89
+ const now = Math.floor(Date.now() / 1000);
90
+ const jwt = await createJWT(credentials);
91
+ const tokenResponse = await fetch('https://oauth2.googleapis.com/token', {
92
+ method: 'POST',
93
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
94
+ body: new URLSearchParams({
95
+ grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
96
+ assertion: jwt,
97
+ }),
98
+ });
99
+ if (!tokenResponse.ok) {
100
+ throw new Error('Failed to get Google access token');
101
+ }
102
+ const tokenData = await tokenResponse.json();
103
+ cachedAccessToken = tokenData.access_token;
104
+ tokenExpiry = now + tokenData.expires_in - 60;
105
+ return cachedAccessToken;
106
+ }
107
+ catch (error) {
108
+ logger.error('Failed to get Google access token:', error);
109
+ throw error;
110
+ }
111
+ }
112
+ async function createJWT(credentials) {
113
+ const now = Math.floor(Date.now() / 1000);
114
+ const header = {
115
+ alg: 'RS256',
116
+ typ: 'JWT',
117
+ };
118
+ const payload = {
119
+ iss: credentials.client_email,
120
+ sub: credentials.client_email,
121
+ aud: 'https://oauth2.googleapis.com/token',
122
+ iat: now,
123
+ exp: now + 3600,
124
+ scope: 'https://www.googleapis.com/auth/cloud-platform',
125
+ };
126
+ const crypto = await import('crypto');
127
+ const encodedHeader = Buffer.from(JSON.stringify(header)).toString('base64url');
128
+ const encodedPayload = Buffer.from(JSON.stringify(payload)).toString('base64url');
129
+ const signatureInput = `${encodedHeader}.${encodedPayload}`;
130
+ const sign = crypto.createSign('RSA-SHA256');
131
+ sign.update(signatureInput);
132
+ const signature = sign.sign(credentials.private_key, 'base64url');
133
+ return `${signatureInput}.${signature}`;
134
+ }
135
+ export function isMultimodalInput(input) {
136
+ return (typeof input === 'object' &&
137
+ (typeof input.text === 'string' ||
138
+ Buffer.isBuffer(input.image) ||
139
+ typeof input.image === 'string' ||
140
+ typeof input.video === 'string'));
141
+ }
142
+ //# sourceMappingURL=google-multimodal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-multimodal.js","sourceRoot":"","sources":["../../../core/embeddings/google-multimodal.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
- export type EmbeddingProvider = 'openai' | 'ollama' | 'local' | 'none' | 'auto' | 'qmd' | 'hybrid';
2
- export declare function getEmbedding(input: string): Promise<number[] | null>;
1
+ import { MultimodalInput } from './embeddings/google-multimodal.js';
2
+ export type EmbeddingProvider = 'openai' | 'ollama' | 'local' | 'none' | 'auto' | 'qmd' | 'hybrid' | 'google-multimodal';
3
+ export declare function getEmbedding(input: string | MultimodalInput): Promise<number[] | null>;
3
4
  /**
4
5
  * Get embeddings for multiple inputs in parallel batches
5
6
  * Processes inputs in batches to respect rate limits while parallelizing
@@ -1 +1 @@
1
- {"version":3,"file":"embeddings.d.ts","sourceRoot":"","sources":["../../core/embeddings.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;AAiCnG,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAgE1E;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EAAE,EAChB,SAAS,GAAE,MAAW,GACrB,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAuCjC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAK1E"}
1
+ {"version":3,"file":"embeddings.d.ts","sourceRoot":"","sources":["../../core/embeddings.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmD,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAGrH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,mBAAmB,CAAC;AAiCzH,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAsF5F;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EAAE,EAChB,SAAS,GAAE,MAAW,GACrB,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAuCjC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAK1E"}
@@ -1,5 +1,6 @@
1
1
  import { config } from '../config.js';
2
2
  import { getQMDClient } from './embeddings/qmd-client.js';
3
+ import { getGoogleMultimodalEmbedding, isMultimodalInput } from './embeddings/google-multimodal.js';
3
4
  import { logger } from './logger.js';
4
5
  // Simple in-memory cache for embeddings (LRU with 1000 entries)
5
6
  const embeddingCache = new Map();
@@ -29,62 +30,83 @@ function setCachedEmbedding(key, embedding) {
29
30
  embeddingCache.set(key, embedding);
30
31
  }
31
32
  export async function getEmbedding(input) {
32
- if (!input || typeof input !== 'string') {
33
+ if (!input || (typeof input !== 'string' && !isMultimodalInput(input))) {
33
34
  return null;
34
35
  }
35
36
  const provider = config.embeddingsProvider;
36
- const cacheKey = getCacheKey(input, provider);
37
+ const cacheKey = typeof input === 'string'
38
+ ? getCacheKey(input, provider)
39
+ : getCacheKey(JSON.stringify(input), provider);
37
40
  // Check cache first
38
41
  const cached = getCachedEmbedding(cacheKey);
39
42
  if (cached) {
40
43
  return cached;
41
44
  }
42
45
  let result = null;
43
- if (provider === 'none') {
44
- result = null;
45
- }
46
- else if (provider === 'qmd') {
47
- result = await getQMDEmbedding(input);
48
- // Fallback if QMD fails (unless qmd-only mode)
49
- if (!result && config.qmdFallbackMode !== 'qmd-only') {
50
- result = getLocalEmbedding(input);
46
+ // Handle multimodal input
47
+ if (isMultimodalInput(input) && (provider === 'google-multimodal' || provider === 'hybrid')) {
48
+ const multimodalResult = await getGoogleMultimodalEmbedding(input);
49
+ if (multimodalResult) {
50
+ result = multimodalResult.embedding;
51
51
  }
52
52
  }
53
- else if (provider === 'hybrid') {
54
- // Hybrid mode: Try QMD first, then cloud providers, then local
55
- if (config.qmdEnabled) {
56
- result = await getQMDEmbedding(input);
53
+ // Handle text-only input
54
+ if (!result && typeof input === 'string') {
55
+ const textInput = input;
56
+ if (provider === 'none') {
57
+ result = null;
57
58
  }
58
- if (!result && config.qmdFallbackMode !== 'qmd-only') {
59
- result = await getOllamaEmbedding(input);
59
+ else if (provider === 'google-multimodal') {
60
+ const multimodalResult = await getGoogleMultimodalEmbedding({ text: textInput });
61
+ result = multimodalResult?.embedding || null;
60
62
  }
61
- if (!result && config.qmdFallbackMode !== 'qmd-only' && config.qmdFallbackMode !== 'local-only') {
62
- result = await getOpenAiEmbedding(input);
63
+ else if (provider === 'qmd') {
64
+ result = await getQMDEmbedding(textInput);
65
+ // Fallback if QMD fails (unless qmd-only mode)
66
+ if (!result && config.qmdFallbackMode !== 'qmd-only') {
67
+ result = getLocalEmbedding(textInput);
68
+ }
63
69
  }
64
- if (!result) {
65
- result = getLocalEmbedding(input);
70
+ else if (provider === 'hybrid') {
71
+ // Hybrid mode: Try Google Multimodal first, then QMD, then cloud providers, then local
72
+ if (config.multimodalEmbeddingsEnabled) {
73
+ const multimodalResult = await getGoogleMultimodalEmbedding({ text: textInput });
74
+ result = multimodalResult?.embedding || null;
75
+ }
76
+ if (!result && config.qmdEnabled) {
77
+ result = await getQMDEmbedding(textInput);
78
+ }
79
+ if (!result && config.qmdFallbackMode !== 'qmd-only') {
80
+ result = await getOllamaEmbedding(textInput);
81
+ }
82
+ if (!result && config.qmdFallbackMode !== 'qmd-only' && config.qmdFallbackMode !== 'local-only') {
83
+ result = await getOpenAiEmbedding(textInput);
84
+ }
85
+ if (!result) {
86
+ result = getLocalEmbedding(textInput);
87
+ }
66
88
  }
67
- }
68
- else if (provider === 'openai') {
69
- result = await getOpenAiEmbedding(input);
70
- }
71
- else if (provider === 'ollama') {
72
- result = await getOllamaEmbedding(input);
73
- }
74
- else if (provider === 'local') {
75
- result = getLocalEmbedding(input);
76
- }
77
- else {
78
- // Auto mode: use local TF-IDF by default (fast, no API needed)
79
- // Only try external providers if explicitly configured
80
- if (config.openAiApiKey) {
81
- result = await getOpenAiEmbedding(input);
89
+ else if (provider === 'openai') {
90
+ result = await getOpenAiEmbedding(textInput);
91
+ }
92
+ else if (provider === 'ollama') {
93
+ result = await getOllamaEmbedding(textInput);
82
94
  }
83
- if (!result && config.ollamaUrl) {
84
- result = await getOllamaEmbedding(input);
95
+ else if (provider === 'local') {
96
+ result = getLocalEmbedding(textInput);
85
97
  }
86
- if (!result) {
87
- result = getLocalEmbedding(input);
98
+ else {
99
+ // Auto mode: use local TF-IDF by default (fast, no API needed)
100
+ // Only try external providers if explicitly configured
101
+ if (config.openAiApiKey) {
102
+ result = await getOpenAiEmbedding(textInput);
103
+ }
104
+ if (!result && config.ollamaUrl) {
105
+ result = await getOllamaEmbedding(textInput);
106
+ }
107
+ if (!result) {
108
+ result = getLocalEmbedding(textInput);
109
+ }
88
110
  }
89
111
  }
90
112
  // Cache the result if valid