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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +2 -2
- package/.env.mcp +30 -0
- package/.mcp.json +2 -5
- package/CHANGELOG.md +111 -0
- package/QUICK-START.md +65 -0
- package/README.md +188 -530
- package/commands/managed-sync.ts +69 -0
- package/commands/mcp-server.ts +519 -0
- package/config/mcp-cli-fallback-policy.json +22 -0
- package/config/mcp-migration-map.json +22 -0
- package/config/mcp-mode-semantics.json +21 -0
- package/config/mcp-remote-auth.json +36 -0
- package/config/mcp-universal.schema.json +48 -0
- package/config/mcp.json +38 -0
- package/config/remote-memory-policy.json +32 -0
- package/dist/algorithms/merge/detection/hash-filters.js +2 -2
- package/dist/algorithms/merge/detection/hash-filters.js.map +1 -1
- package/dist/algorithms/merge/detection/two-stage-detector.d.ts +5 -2
- package/dist/algorithms/merge/detection/two-stage-detector.d.ts.map +1 -1
- package/dist/algorithms/merge/detection/two-stage-detector.js +139 -22
- package/dist/algorithms/merge/detection/two-stage-detector.js.map +1 -1
- package/dist/commands/managed-sync.d.ts +10 -0
- package/dist/commands/managed-sync.d.ts.map +1 -0
- package/dist/commands/managed-sync.js +64 -0
- package/dist/commands/managed-sync.js.map +1 -0
- package/dist/commands/mcp-server.d.ts +3 -0
- package/dist/commands/mcp-server.d.ts.map +1 -0
- package/dist/commands/mcp-server.js +389 -0
- package/dist/commands/mcp-server.js.map +1 -0
- package/dist/config.d.ts +24 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +32 -1
- package/dist/config.js.map +1 -1
- package/dist/core/associations.d.ts +1 -1
- package/dist/core/associations.d.ts.map +1 -1
- package/dist/core/consolidation.d.ts +31 -0
- package/dist/core/consolidation.d.ts.map +1 -1
- package/dist/core/consolidation.js +237 -29
- package/dist/core/consolidation.js.map +1 -1
- package/dist/core/embeddings/google-multimodal.d.ts +14 -0
- package/dist/core/embeddings/google-multimodal.d.ts.map +1 -0
- package/dist/core/embeddings/google-multimodal.js +142 -0
- package/dist/core/embeddings/google-multimodal.js.map +1 -0
- package/dist/core/embeddings.d.ts +3 -2
- package/dist/core/embeddings.d.ts.map +1 -1
- package/dist/core/embeddings.js +61 -39
- package/dist/core/embeddings.js.map +1 -1
- package/dist/core/mcp/client.d.ts +17 -0
- package/dist/core/mcp/client.d.ts.map +1 -0
- package/dist/core/mcp/client.js +101 -0
- package/dist/core/mcp/client.js.map +1 -0
- package/dist/core/mcp/index.d.ts +6 -0
- package/dist/core/mcp/index.d.ts.map +1 -0
- package/dist/core/mcp/index.js +6 -0
- package/dist/core/mcp/index.js.map +1 -0
- package/dist/core/mcp/server.d.ts +18 -0
- package/dist/core/mcp/server.d.ts.map +1 -0
- package/dist/core/mcp/server.js +131 -0
- package/dist/core/mcp/server.js.map +1 -0
- package/dist/core/mcp/standalone-server.d.ts +13 -0
- package/dist/core/mcp/standalone-server.d.ts.map +1 -0
- package/dist/core/mcp/standalone-server.js +46 -0
- package/dist/core/mcp/standalone-server.js.map +1 -0
- package/dist/core/mcp/tools.d.ts +9 -0
- package/dist/core/mcp/tools.d.ts.map +1 -0
- package/dist/core/mcp/tools.js +262 -0
- package/dist/core/mcp/tools.js.map +1 -0
- package/dist/core/mcp/types.d.ts +315 -0
- package/dist/core/mcp/types.d.ts.map +1 -0
- package/dist/core/mcp/types.js +48 -0
- package/dist/core/mcp/types.js.map +1 -0
- package/dist/core/memory/categorizer.d.ts +27 -0
- package/dist/core/memory/categorizer.d.ts.map +1 -0
- package/dist/core/memory/categorizer.js +304 -0
- package/dist/core/memory/categorizer.js.map +1 -0
- package/dist/core/memory/conflict-detector.d.ts +7 -0
- package/dist/core/memory/conflict-detector.d.ts.map +1 -0
- package/dist/core/memory/conflict-detector.js +43 -0
- package/dist/core/memory/conflict-detector.js.map +1 -0
- package/dist/core/memory/context-collector.d.ts +10 -0
- package/dist/core/memory/context-collector.d.ts.map +1 -0
- package/dist/core/memory/context-collector.js +55 -0
- package/dist/core/memory/context-collector.js.map +1 -0
- package/dist/core/memory/contradiction-resolver.d.ts +40 -0
- package/dist/core/memory/contradiction-resolver.d.ts.map +1 -0
- package/dist/core/memory/contradiction-resolver.js +368 -0
- package/dist/core/memory/contradiction-resolver.js.map +1 -0
- package/dist/core/memory/edit-workflow.d.ts +19 -0
- package/dist/core/memory/edit-workflow.d.ts.map +1 -0
- package/dist/core/memory/edit-workflow.js +120 -0
- package/dist/core/memory/edit-workflow.js.map +1 -0
- package/dist/core/memory/feedback-tracker.d.ts +12 -0
- package/dist/core/memory/feedback-tracker.d.ts.map +1 -0
- package/dist/core/memory/feedback-tracker.js +151 -0
- package/dist/core/memory/feedback-tracker.js.map +1 -0
- package/dist/core/memory/hybrid-retrieval.d.ts +11 -12
- package/dist/core/memory/hybrid-retrieval.d.ts.map +1 -1
- package/dist/core/memory/hybrid-retrieval.js +56 -28
- package/dist/core/memory/hybrid-retrieval.js.map +1 -1
- package/dist/core/memory/hybrid-scorer.d.ts +5 -16
- package/dist/core/memory/hybrid-scorer.d.ts.map +1 -1
- package/dist/core/memory/hybrid-scorer.js +161 -125
- package/dist/core/memory/hybrid-scorer.js.map +1 -1
- package/dist/core/memory/hybrid-search.js +56 -20
- package/dist/core/memory/hybrid-search.js.map +1 -1
- package/dist/core/memory/memories.d.ts +4 -0
- package/dist/core/memory/memories.d.ts.map +1 -1
- package/dist/core/memory/memories.js +133 -60
- package/dist/core/memory/memories.js.map +1 -1
- package/dist/core/memory/progressive-disclosure.d.ts +43 -0
- package/dist/core/memory/progressive-disclosure.d.ts.map +1 -0
- package/dist/core/memory/progressive-disclosure.js +280 -0
- package/dist/core/memory/progressive-disclosure.js.map +1 -0
- package/dist/core/memory/query-rewriter.d.ts +13 -0
- package/dist/core/memory/query-rewriter.d.ts.map +1 -0
- package/dist/core/memory/query-rewriter.js +118 -0
- package/dist/core/memory/query-rewriter.js.map +1 -0
- package/dist/core/memory/response-analyzer.d.ts +9 -0
- package/dist/core/memory/response-analyzer.d.ts.map +1 -0
- package/dist/core/memory/response-analyzer.js +61 -0
- package/dist/core/memory/response-analyzer.js.map +1 -0
- package/dist/core/memory/stats.d.ts +17 -0
- package/dist/core/memory/stats.d.ts.map +1 -0
- package/dist/core/memory/stats.js +87 -0
- package/dist/core/memory/stats.js.map +1 -0
- package/dist/core/memory/telemetry.d.ts +69 -0
- package/dist/core/memory/telemetry.d.ts.map +1 -0
- package/dist/core/memory/telemetry.js +313 -0
- package/dist/core/memory/telemetry.js.map +1 -0
- package/dist/core/memory/temporal-facts.d.ts +41 -0
- package/dist/core/memory/temporal-facts.d.ts.map +1 -0
- package/dist/core/memory/temporal-facts.js +262 -0
- package/dist/core/memory/temporal-facts.js.map +1 -0
- package/dist/core/memory/trigger-detector.d.ts +14 -0
- package/dist/core/memory/trigger-detector.d.ts.map +1 -0
- package/dist/core/memory/trigger-detector.js +42 -0
- package/dist/core/memory/trigger-detector.js.map +1 -0
- package/dist/core/memory/write-gate.d.ts +54 -0
- package/dist/core/memory/write-gate.d.ts.map +1 -0
- package/dist/core/memory/write-gate.js +210 -0
- package/dist/core/memory/write-gate.js.map +1 -0
- package/dist/core/projects.d.ts +2 -0
- package/dist/core/projects.d.ts.map +1 -1
- package/dist/core/projects.js +33 -0
- package/dist/core/projects.js.map +1 -1
- package/dist/core/scheduler/cron-scheduler.d.ts +32 -0
- package/dist/core/scheduler/cron-scheduler.d.ts.map +1 -0
- package/dist/core/scheduler/cron-scheduler.js +238 -0
- package/dist/core/scheduler/cron-scheduler.js.map +1 -0
- package/dist/core/scheduler/heartbeat.d.ts +11 -0
- package/dist/core/scheduler/heartbeat.d.ts.map +1 -0
- package/dist/core/scheduler/heartbeat.js +73 -0
- package/dist/core/scheduler/heartbeat.js.map +1 -0
- package/dist/core/scheduler/index.d.ts +8 -0
- package/dist/core/scheduler/index.d.ts.map +1 -0
- package/dist/core/scheduler/index.js +8 -0
- package/dist/core/scheduler/index.js.map +1 -0
- package/dist/core/scheduler/job-runner.d.ts +11 -0
- package/dist/core/scheduler/job-runner.d.ts.map +1 -0
- package/dist/core/scheduler/job-runner.js +161 -0
- package/dist/core/scheduler/job-runner.js.map +1 -0
- package/dist/core/session/auto-load.d.ts +6 -0
- package/dist/core/session/auto-load.d.ts.map +1 -0
- package/dist/core/session/auto-load.js +119 -0
- package/dist/core/session/auto-load.js.map +1 -0
- package/dist/core/session/index.d.ts +7 -0
- package/dist/core/session/index.d.ts.map +1 -0
- package/dist/core/session/index.js +7 -0
- package/dist/core/session/index.js.map +1 -0
- package/dist/core/session/types.d.ts +26 -0
- package/dist/core/session/types.d.ts.map +1 -0
- package/dist/core/session/types.js +10 -0
- package/dist/core/session/types.js.map +1 -0
- package/dist/core/snapshots/comparison.d.ts.map +1 -1
- package/dist/core/snapshots/comparison.js +8 -2
- package/dist/core/snapshots/comparison.js.map +1 -1
- package/dist/core/utils/content-extraction.d.ts.map +1 -1
- package/dist/core/utils/content-extraction.js +11 -1
- package/dist/core/utils/content-extraction.js.map +1 -1
- package/dist/core/utils/summarization-helpers.d.ts.map +1 -1
- package/dist/core/utils/summarization-helpers.js +4 -1
- package/dist/core/utils/summarization-helpers.js.map +1 -1
- package/dist/core/utils.d.ts.map +1 -1
- package/dist/core/utils.js +26 -3
- package/dist/core/utils.js.map +1 -1
- package/dist/core/worker.d.ts +20 -0
- package/dist/core/worker.d.ts.map +1 -1
- package/dist/core/worker.js +86 -0
- package/dist/core/worker.js.map +1 -1
- package/dist/db/adapter.d.ts +1 -5
- package/dist/db/adapter.d.ts.map +1 -1
- package/dist/db/adapter.js +125 -12
- package/dist/db/adapter.js.map +1 -1
- package/dist/db/bootstrap.d.ts.map +1 -1
- package/dist/db/bootstrap.js +178 -3
- package/dist/db/bootstrap.js.map +1 -1
- package/dist/db/index.d.ts +1 -5
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +7 -4
- package/dist/db/index.js.map +1 -1
- package/dist/drizzle/schema-sqlite.d.ts +1953 -612
- package/dist/drizzle/schema-sqlite.d.ts.map +1 -1
- package/dist/drizzle/schema-sqlite.js +134 -0
- package/dist/drizzle/schema-sqlite.js.map +1 -1
- package/dist/drizzle/schema.d.ts +684 -3
- package/dist/drizzle/schema.d.ts.map +1 -1
- package/dist/drizzle/schema.js +81 -1
- package/dist/drizzle/schema.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +152 -13
- package/dist/index.js.map +1 -1
- package/package.json +125 -103
- package/scripts/build-release.sh +33 -0
- package/scripts/db/check-db.mjs +88 -0
- package/scripts/db/fix-all-columns.mjs +52 -0
- package/scripts/db/fix-schema-all.mjs +55 -0
- package/scripts/db/fix-schema-full.mjs +46 -0
- package/scripts/db/fix-schema.mjs +38 -0
- package/scripts/db/init-db.mjs +13 -0
- package/scripts/db/recreate-db.mjs +14 -0
- package/scripts/generate-mcp.mjs +264 -0
- package/scripts/github-release.sh +61 -0
- package/scripts/init-dirs.mjs +13 -0
- package/scripts/init-dirs.ts +15 -0
- package/scripts/install-mcp.mjs +116 -0
- package/scripts/install-web.sh +120 -0
- package/scripts/install.mjs +340 -0
- package/scripts/openclaw-bootstrap.mjs +127 -0
- package/scripts/package-release.sh +71 -0
- package/scripts/remote-preflight.mjs +62 -0
- package/scripts/squish-fallback.mjs +132 -0
- package/scripts/test/test-all-systems.mjs +139 -0
- package/scripts/test/test-memory-system.mjs +139 -0
- package/scripts/test/test-v0.5.0.mjs +210 -0
- package/scripts/verify-mcp.mjs +214 -0
- package/skills/memory-guide/SKILL.md +181 -123
- package/skills/squish-cli/SKILL.md +200 -0
- package/skills/squish-mcp/SKILL.md +311 -0
- package/skills/squish-memory/SKILL.md +100 -62
- package/skills/squish-memory/claude-desktop.json +12 -0
- package/skills/squish-memory/install.mjs +335 -0
- package/skills/squish-memory/install.sh +94 -62
- package/skills/squish-memory/openclaw.json +13 -0
- package/skills/squish-memory/opencode.json +14 -0
- package/skills/squish-memory/skill.json +32 -0
- package/dist/adapters/claude-code/capture.d.ts +0 -11
- package/dist/adapters/claude-code/capture.d.ts.map +0 -1
- package/dist/adapters/claude-code/capture.js +0 -100
- package/dist/adapters/claude-code/capture.js.map +0 -1
- package/dist/adapters/claude-code/index.d.ts +0 -5
- package/dist/adapters/claude-code/index.d.ts.map +0 -1
- package/dist/adapters/claude-code/index.js +0 -6
- package/dist/adapters/claude-code/index.js.map +0 -1
- package/dist/adapters/claude-code/injection.d.ts +0 -34
- package/dist/adapters/claude-code/injection.d.ts.map +0 -1
- package/dist/adapters/claude-code/injection.js +0 -127
- package/dist/adapters/claude-code/injection.js.map +0 -1
- package/dist/adapters/claude-code/plugin-wrapper.d.ts +0 -21
- package/dist/adapters/claude-code/plugin-wrapper.d.ts.map +0 -1
- package/dist/adapters/claude-code/plugin-wrapper.js +0 -239
- package/dist/adapters/claude-code/plugin-wrapper.js.map +0 -1
- package/dist/adapters/claude-code/types.d.ts +0 -46
- package/dist/adapters/claude-code/types.d.ts.map +0 -1
- package/dist/adapters/claude-code/types.js +0 -6
- package/dist/adapters/claude-code/types.js.map +0 -1
|
@@ -1,40 +1,248 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
|
10
|
-
|
|
11
|
-
for (
|
|
12
|
-
if (
|
|
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
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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 (
|
|
21
|
-
|
|
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
|
|
103
|
+
return groups;
|
|
25
104
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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":"
|
|
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":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAezC,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,KAAsB;IAEtB,IAAI,CAAC,MAAM,CAAC,iBAAiB,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,CAAC;QAC5D,MAAM,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,CAAC,mBAAmB,KAAK,QAAQ;YACtD,CAAC,CAAC,iDAAiD,MAAM,CAAC,kBAAkB,cAAc,MAAM,CAAC,mBAAmB,2DAA2D;YAC/K,CAAC,CAAC,WAAW,MAAM,CAAC,mBAAmB,0CAA0C,MAAM,CAAC,kBAAkB,cAAc,MAAM,CAAC,mBAAmB,2DAA2D,CAAC;QAEhN,MAAM,SAAS,GAAU,EAAE,CAAC;QAE5B,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;YACf,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACvC,CAAC;QAED,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,UAAU,GAAG,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ;gBAChD,CAAC,CAAC,KAAK,CAAC,KAAK;gBACb,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAEnC,SAAS,CAAC,IAAI,CAAC;gBACb,KAAK,EAAE;oBACL,kBAAkB,EAAE,UAAU;iBAC/B;aACF,CAAC,CAAC;QACL,CAAC;QAED,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAChB,SAAS,CAAC,IAAI,CAAC;gBACb,KAAK,EAAE;oBACL,MAAM,EAAE,KAAK,CAAC,KAAK;iBACpB;aACF,CAAC,CAAC;QACL,CAAC;QAED,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;YACrC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,eAAe,EAAE,UAAU,MAAM,oBAAoB,EAAE,EAAE;aAC1D;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,SAAS;gBACT,UAAU,EAAE;oBACV,SAAS,EAAE,IAAI;iBAChB;aACF,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,wCAAwC,QAAQ,CAAC,MAAM,IAAI,SAAS,EAAE,CAAC,CAAC;YACpF,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAA6B,CAAC;QAC9D,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC;QAE3C,MAAM,MAAM,GAA6B;YACvC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,SAAS,IAAI,EAAE;SAC3C,CAAC;QAEF,IAAI,KAAK,CAAC,IAAI,IAAI,WAAW,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC;YAChD,MAAM,CAAC,aAAa,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;QACtD,CAAC;QAED,IAAI,KAAK,CAAC,KAAK,IAAI,WAAW,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC;YAClD,MAAM,CAAC,cAAc,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC;QACxD,CAAC;QAED,IAAI,KAAK,CAAC,KAAK,IAAI,WAAW,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC;YAClD,MAAM,CAAC,cAAc,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC;QACxD,CAAC;QAED,OAAO,MAAM,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;IACrD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,CAAC,CAAC;QAC1D,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,IAAI,iBAAiB,GAAkB,IAAI,CAAC;AAC5C,IAAI,WAAW,GAAW,CAAC,CAAC;AAE5B,KAAK,UAAU,oBAAoB;IACjC,IAAI,MAAM,CAAC,iBAAiB,EAAE,CAAC;QAC7B,OAAO,MAAM,CAAC,iBAAiB,CAAC;IAClC,CAAC;IAED,IAAI,iBAAiB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,WAAW,EAAE,CAAC;QAClD,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,8BAA8B,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC5D,CAAC;IAED,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAC5B,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAC3B,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,8BAA+B,EAAE,OAAO,CAAC,CAC3E,CACF,CAAC;QAEF,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAC1C,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,WAAW,CAAC,CAAC;QAEzC,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,qCAAqC,EAAE;YACvE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;YAChE,IAAI,EAAE,IAAI,eAAe,CAAC;gBACxB,UAAU,EAAE,6CAA6C;gBACzD,SAAS,EAAE,GAAG;aACf,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,aAAa,CAAC,EAAE,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACvD,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,IAAI,EAAkD,CAAC;QAC7F,iBAAiB,GAAG,SAAS,CAAC,YAAY,CAAC;QAC3C,WAAW,GAAG,GAAG,GAAG,SAAS,CAAC,UAAU,GAAG,EAAE,CAAC;QAE9C,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,CAAC,CAAC;QAC1D,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,WAAgB;IACvC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAE1C,MAAM,MAAM,GAAG;QACb,GAAG,EAAE,OAAO;QACZ,GAAG,EAAE,KAAK;KACX,CAAC;IAEF,MAAM,OAAO,GAAG;QACd,GAAG,EAAE,WAAW,CAAC,YAAY;QAC7B,GAAG,EAAE,WAAW,CAAC,YAAY;QAC7B,GAAG,EAAE,qCAAqC;QAC1C,GAAG,EAAE,GAAG;QACR,GAAG,EAAE,GAAG,GAAG,IAAI;QACf,KAAK,EAAE,gDAAgD;KACxD,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;IAEtC,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IAChF,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IAElF,MAAM,cAAc,GAAG,GAAG,aAAa,IAAI,cAAc,EAAE,CAAC;IAE5D,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;IAC7C,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IAC5B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IAElE,OAAO,GAAG,cAAc,IAAI,SAAS,EAAE,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAU;IAC1C,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,CAAC,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;YAC9B,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC;YAC5B,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ;YAC/B,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,CAAC,CAClC,CAAC;AACJ,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
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":"
|
|
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"}
|
package/dist/core/embeddings.js
CHANGED
|
@@ -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 =
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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 (
|
|
59
|
-
|
|
59
|
+
else if (provider === 'google-multimodal') {
|
|
60
|
+
const multimodalResult = await getGoogleMultimodalEmbedding({ text: textInput });
|
|
61
|
+
result = multimodalResult?.embedding || null;
|
|
60
62
|
}
|
|
61
|
-
if (
|
|
62
|
-
result = await
|
|
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 (
|
|
65
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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 (
|
|
84
|
-
result =
|
|
95
|
+
else if (provider === 'local') {
|
|
96
|
+
result = getLocalEmbedding(textInput);
|
|
85
97
|
}
|
|
86
|
-
|
|
87
|
-
|
|
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
|