cozo-memory 1.0.4 → 1.0.6

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/dist/cli.js ADDED
@@ -0,0 +1,410 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Pure CLI for CozoDB Memory
5
+ * Usage: cozo-memory <command> [options]
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ var __importDefault = (this && this.__importDefault) || function (mod) {
41
+ return (mod && mod.__esModule) ? mod : { "default": mod };
42
+ };
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ const commander_1 = require("commander");
45
+ const cli_commands_js_1 = require("./cli-commands.js");
46
+ const chalk_1 = __importDefault(require("chalk"));
47
+ const fs = __importStar(require("fs"));
48
+ const program = new commander_1.Command();
49
+ const cli = new cli_commands_js_1.CLICommands();
50
+ // Helper to format output
51
+ function formatOutput(data, format = 'pretty') {
52
+ if (format === 'json') {
53
+ console.log(JSON.stringify(data, null, 2));
54
+ }
55
+ else {
56
+ console.log(chalk_1.default.cyan(JSON.stringify(data, null, 2)));
57
+ }
58
+ }
59
+ // Helper to handle errors
60
+ function handleError(error) {
61
+ console.error(chalk_1.default.red('Error:'), error.message || error);
62
+ process.exit(1);
63
+ }
64
+ program
65
+ .name('cozo-memory')
66
+ .description('CLI for CozoDB Memory - Local-first persistent memory for AI agents')
67
+ .version('1.0.6');
68
+ // Entity commands
69
+ const entity = program.command('entity').description('Entity operations');
70
+ entity
71
+ .command('create')
72
+ .description('Create a new entity')
73
+ .requiredOption('-n, --name <name>', 'Entity name')
74
+ .requiredOption('-t, --type <type>', 'Entity type')
75
+ .option('-m, --metadata <json>', 'Metadata as JSON string')
76
+ .option('-f, --format <format>', 'Output format (json|pretty)', 'pretty')
77
+ .action(async (options) => {
78
+ try {
79
+ await cli.init();
80
+ const metadata = options.metadata ? JSON.parse(options.metadata) : undefined;
81
+ const result = await cli.createEntity(options.name, options.type, metadata);
82
+ formatOutput(result, options.format);
83
+ await cli.close();
84
+ }
85
+ catch (error) {
86
+ handleError(error);
87
+ }
88
+ });
89
+ entity
90
+ .command('get')
91
+ .description('Get entity details')
92
+ .requiredOption('-i, --id <id>', 'Entity ID')
93
+ .option('-f, --format <format>', 'Output format (json|pretty)', 'pretty')
94
+ .action(async (options) => {
95
+ try {
96
+ await cli.init();
97
+ const result = await cli.getEntity(options.id);
98
+ formatOutput(result, options.format);
99
+ await cli.close();
100
+ }
101
+ catch (error) {
102
+ handleError(error);
103
+ }
104
+ });
105
+ entity
106
+ .command('delete')
107
+ .description('Delete an entity')
108
+ .requiredOption('-i, --id <id>', 'Entity ID')
109
+ .option('-f, --format <format>', 'Output format (json|pretty)', 'pretty')
110
+ .action(async (options) => {
111
+ try {
112
+ await cli.init();
113
+ const result = await cli.deleteEntity(options.id);
114
+ formatOutput(result, options.format);
115
+ await cli.close();
116
+ }
117
+ catch (error) {
118
+ handleError(error);
119
+ }
120
+ });
121
+ // Observation commands
122
+ const observation = program.command('observation').alias('obs').description('Observation operations');
123
+ observation
124
+ .command('add')
125
+ .description('Add observation to entity')
126
+ .requiredOption('-i, --entity-id <id>', 'Entity ID')
127
+ .requiredOption('-t, --text <text>', 'Observation text')
128
+ .option('-m, --metadata <json>', 'Metadata as JSON string')
129
+ .option('-f, --format <format>', 'Output format (json|pretty)', 'pretty')
130
+ .action(async (options) => {
131
+ try {
132
+ await cli.init();
133
+ const metadata = options.metadata ? JSON.parse(options.metadata) : undefined;
134
+ const result = await cli.addObservation(options.entityId, options.text, metadata);
135
+ formatOutput(result, options.format);
136
+ await cli.close();
137
+ }
138
+ catch (error) {
139
+ handleError(error);
140
+ }
141
+ });
142
+ // Relation commands
143
+ const relation = program.command('relation').alias('rel').description('Relation operations');
144
+ relation
145
+ .command('create')
146
+ .description('Create relation between entities')
147
+ .requiredOption('--from <id>', 'From entity ID')
148
+ .requiredOption('--to <id>', 'To entity ID')
149
+ .requiredOption('--type <type>', 'Relation type')
150
+ .option('-s, --strength <number>', 'Relation strength (0-1)', parseFloat)
151
+ .option('-m, --metadata <json>', 'Metadata as JSON string')
152
+ .option('-f, --format <format>', 'Output format (json|pretty)', 'pretty')
153
+ .action(async (options) => {
154
+ try {
155
+ await cli.init();
156
+ const metadata = options.metadata ? JSON.parse(options.metadata) : undefined;
157
+ const result = await cli.createRelation(options.from, options.to, options.type, options.strength, metadata);
158
+ formatOutput(result, options.format);
159
+ await cli.close();
160
+ }
161
+ catch (error) {
162
+ handleError(error);
163
+ }
164
+ });
165
+ // Search commands
166
+ const search = program.command('search').description('Search operations');
167
+ search
168
+ .command('query')
169
+ .description('Search memory')
170
+ .requiredOption('-q, --query <query>', 'Search query')
171
+ .option('-l, --limit <number>', 'Result limit', parseInt, 10)
172
+ .option('-t, --types <types>', 'Entity types (comma-separated)')
173
+ .option('--no-entities', 'Exclude entities')
174
+ .option('--no-observations', 'Exclude observations')
175
+ .option('-f, --format <format>', 'Output format (json|pretty)', 'pretty')
176
+ .action(async (options) => {
177
+ try {
178
+ await cli.init();
179
+ const entityTypes = options.types ? options.types.split(',') : undefined;
180
+ const result = await cli.search(options.query, options.limit, entityTypes, options.entities, options.observations);
181
+ formatOutput(result, options.format);
182
+ await cli.close();
183
+ }
184
+ catch (error) {
185
+ handleError(error);
186
+ }
187
+ });
188
+ search
189
+ .command('context')
190
+ .description('Get contextual information')
191
+ .requiredOption('-q, --query <query>', 'Context query')
192
+ .option('-w, --window <number>', 'Context window', parseInt)
193
+ .option('-h, --hours <number>', 'Time range in hours', parseInt)
194
+ .option('-f, --format <format>', 'Output format (json|pretty)', 'pretty')
195
+ .action(async (options) => {
196
+ try {
197
+ await cli.init();
198
+ const result = await cli.context(options.query, options.window, options.hours);
199
+ formatOutput(result, options.format);
200
+ await cli.close();
201
+ }
202
+ catch (error) {
203
+ handleError(error);
204
+ }
205
+ });
206
+ // Graph commands
207
+ const graph = program.command('graph').description('Graph operations');
208
+ graph
209
+ .command('explore')
210
+ .description('Explore graph from entity')
211
+ .requiredOption('-s, --start <id>', 'Start entity ID')
212
+ .option('-e, --end <id>', 'End entity ID (for path finding)')
213
+ .option('-h, --hops <number>', 'Max hops', parseInt, 3)
214
+ .option('-t, --types <types>', 'Relation types (comma-separated)')
215
+ .option('-f, --format <format>', 'Output format (json|pretty)', 'pretty')
216
+ .action(async (options) => {
217
+ try {
218
+ await cli.init();
219
+ const relationTypes = options.types ? options.types.split(',') : undefined;
220
+ const result = await cli.explore(options.start, options.end, options.hops, relationTypes);
221
+ formatOutput(result, options.format);
222
+ await cli.close();
223
+ }
224
+ catch (error) {
225
+ handleError(error);
226
+ }
227
+ });
228
+ graph
229
+ .command('pagerank')
230
+ .description('Calculate PageRank')
231
+ .option('-f, --format <format>', 'Output format (json|pretty)', 'pretty')
232
+ .action(async (options) => {
233
+ try {
234
+ await cli.init();
235
+ const result = await cli.pagerank();
236
+ formatOutput(result, options.format);
237
+ await cli.close();
238
+ }
239
+ catch (error) {
240
+ handleError(error);
241
+ }
242
+ });
243
+ graph
244
+ .command('communities')
245
+ .description('Detect communities')
246
+ .option('-f, --format <format>', 'Output format (json|pretty)', 'pretty')
247
+ .action(async (options) => {
248
+ try {
249
+ await cli.init();
250
+ const result = await cli.communities();
251
+ formatOutput(result, options.format);
252
+ await cli.close();
253
+ }
254
+ catch (error) {
255
+ handleError(error);
256
+ }
257
+ });
258
+ // System commands
259
+ const system = program.command('system').alias('sys').description('System operations');
260
+ system
261
+ .command('health')
262
+ .description('Check system health')
263
+ .option('-f, --format <format>', 'Output format (json|pretty)', 'pretty')
264
+ .action(async (options) => {
265
+ try {
266
+ await cli.init();
267
+ const result = await cli.health();
268
+ formatOutput(result, options.format);
269
+ await cli.close();
270
+ }
271
+ catch (error) {
272
+ handleError(error);
273
+ }
274
+ });
275
+ system
276
+ .command('metrics')
277
+ .description('Get system metrics')
278
+ .option('-f, --format <format>', 'Output format (json|pretty)', 'pretty')
279
+ .action(async (options) => {
280
+ try {
281
+ await cli.init();
282
+ const result = await cli.metrics();
283
+ formatOutput(result, options.format);
284
+ await cli.close();
285
+ }
286
+ catch (error) {
287
+ handleError(error);
288
+ }
289
+ });
290
+ // Export/Import commands
291
+ const exportCmd = program.command('export').description('Export memory');
292
+ exportCmd
293
+ .command('json')
294
+ .description('Export as JSON')
295
+ .option('-o, --output <file>', 'Output file')
296
+ .option('--include-metadata', 'Include metadata')
297
+ .option('--include-relationships', 'Include relationships')
298
+ .option('--include-observations', 'Include observations')
299
+ .action(async (options) => {
300
+ try {
301
+ await cli.init();
302
+ const result = await cli.exportMemory('json', {
303
+ includeMetadata: options.includeMetadata,
304
+ includeRelationships: options.includeRelationships,
305
+ includeObservations: options.includeObservations
306
+ });
307
+ const jsonData = typeof result.data === 'string' ? result.data : JSON.stringify(result.data, null, 2);
308
+ if (options.output) {
309
+ fs.writeFileSync(options.output, jsonData);
310
+ console.log(chalk_1.default.green(`✓ Exported to ${options.output}`));
311
+ }
312
+ else {
313
+ console.log(jsonData);
314
+ }
315
+ await cli.close();
316
+ }
317
+ catch (error) {
318
+ handleError(error);
319
+ }
320
+ });
321
+ exportCmd
322
+ .command('markdown')
323
+ .description('Export as Markdown')
324
+ .option('-o, --output <file>', 'Output file')
325
+ .action(async (options) => {
326
+ try {
327
+ await cli.init();
328
+ const result = await cli.exportMemory('markdown');
329
+ if (options.output) {
330
+ fs.writeFileSync(options.output, result.data);
331
+ console.log(chalk_1.default.green(`✓ Exported to ${options.output}`));
332
+ }
333
+ else {
334
+ console.log(result.data);
335
+ }
336
+ await cli.close();
337
+ }
338
+ catch (error) {
339
+ handleError(error);
340
+ }
341
+ });
342
+ exportCmd
343
+ .command('obsidian')
344
+ .description('Export as Obsidian ZIP')
345
+ .requiredOption('-o, --output <file>', 'Output ZIP file')
346
+ .action(async (options) => {
347
+ try {
348
+ await cli.init();
349
+ const result = await cli.exportMemory('obsidian');
350
+ // Obsidian export returns zipBuffer, not data
351
+ const buffer = result.zipBuffer || result.data;
352
+ if (!buffer) {
353
+ throw new Error('No buffer returned from export');
354
+ }
355
+ fs.writeFileSync(options.output, buffer);
356
+ console.log(chalk_1.default.green(`✓ Exported to ${options.output}`));
357
+ await cli.close();
358
+ }
359
+ catch (error) {
360
+ handleError(error);
361
+ }
362
+ });
363
+ const importCmd = program.command('import').description('Import memory');
364
+ importCmd
365
+ .command('file')
366
+ .description('Import from file')
367
+ .requiredOption('-i, --input <file>', 'Input file')
368
+ .requiredOption('-f, --format <format>', 'Source format (cozo|mem0|memgpt|markdown)')
369
+ .option('-s, --strategy <strategy>', 'Merge strategy (skip|overwrite|merge)', 'skip')
370
+ .action(async (options) => {
371
+ try {
372
+ await cli.init();
373
+ const data = fs.readFileSync(options.input, 'utf-8');
374
+ const result = await cli.importMemory(data, options.format, {
375
+ mergeStrategy: options.strategy
376
+ });
377
+ formatOutput(result, 'pretty');
378
+ await cli.close();
379
+ }
380
+ catch (error) {
381
+ handleError(error);
382
+ }
383
+ });
384
+ // Ingest commands
385
+ const ingest = program.command('ingest').description('Ingest files');
386
+ ingest
387
+ .command('file')
388
+ .description('Ingest file into entity')
389
+ .requiredOption('-i, --entity-id <id>', 'Entity ID')
390
+ .requiredOption('-p, --path <path>', 'File path')
391
+ .requiredOption('-f, --format <format>', 'File format (markdown|json|pdf)')
392
+ .option('-c, --chunking <type>', 'Chunking type (none|paragraphs)', 'paragraphs')
393
+ .option('-m, --max <number>', 'Max observations', parseInt)
394
+ .option('--no-deduplicate', 'Disable deduplication')
395
+ .action(async (options) => {
396
+ try {
397
+ await cli.init();
398
+ const result = await cli.ingestFile(options.entityId, options.format, options.path, undefined, {
399
+ chunking: options.chunking,
400
+ maxObservations: options.max,
401
+ deduplicate: options.deduplicate
402
+ });
403
+ formatOutput(result, 'pretty');
404
+ await cli.close();
405
+ }
406
+ catch (error) {
407
+ handleError(error);
408
+ }
409
+ });
410
+ program.parse();
@@ -33,12 +33,14 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ require("dotenv/config"); // Load .env file first
36
37
  const transformers_1 = require("@xenova/transformers");
37
38
  const path = __importStar(require("path"));
38
39
  // Configure cache path
39
40
  const CACHE_DIR = path.resolve('./.cache');
40
41
  transformers_1.env.cacheDir = CACHE_DIR;
41
- const MODEL_ID = "Xenova/bge-m3";
42
+ // Read model from environment variable or use default
43
+ const MODEL_ID = process.env.EMBEDDING_MODEL || "Xenova/bge-m3";
42
44
  async function downloadModel() {
43
45
  console.log(`Downloading FP32 model for ${MODEL_ID}...`);
44
46
  // quantized: false forces FP32 model download
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.EmbeddingService = void 0;
37
+ require("dotenv/config"); // Load .env file first
37
38
  const transformers_1 = require("@xenova/transformers");
38
39
  const ort = require('onnxruntime-node');
39
40
  const path = __importStar(require("path"));
@@ -91,11 +92,27 @@ class EmbeddingService {
91
92
  cache;
92
93
  session = null;
93
94
  tokenizer = null;
94
- modelId = "Xenova/bge-m3";
95
- dimensions = 1024;
95
+ modelId;
96
+ dimensions;
96
97
  queue = Promise.resolve();
97
98
  constructor() {
98
99
  this.cache = new LRUCache(1000, 3600000); // 1000 entries, 1h TTL
100
+ // Support multiple embedding models via environment variable
101
+ this.modelId = process.env.EMBEDDING_MODEL || "Xenova/bge-m3";
102
+ // Set dimensions based on model
103
+ const dimensionMap = {
104
+ "Xenova/bge-m3": 1024,
105
+ "Xenova/all-MiniLM-L6-v2": 384,
106
+ "Xenova/bge-small-en-v1.5": 384,
107
+ "Xenova/nomic-embed-text-v1": 768,
108
+ "onnx-community/Qwen3-Embedding-0.6B-ONNX": 1024,
109
+ };
110
+ this.dimensions = dimensionMap[this.modelId] || 1024;
111
+ console.error(`[EmbeddingService] Using model: ${this.modelId} (${this.dimensions} dimensions)`);
112
+ }
113
+ // Public getter for dimensions
114
+ getDimensions() {
115
+ return this.dimensions;
99
116
  }
100
117
  // Serializes embedding execution to avoid event loop blocking
101
118
  async runSerialized(task) {
@@ -109,21 +126,38 @@ class EmbeddingService {
109
126
  if (this.session && this.tokenizer)
110
127
  return;
111
128
  try {
112
- // 1. Load Tokenizer
129
+ // 1. Check if model needs to be downloaded
130
+ // Extract namespace and model name from modelId (e.g., "Xenova/bge-m3" or "onnx-community/Qwen3-Embedding-0.6B-ONNX")
131
+ const parts = this.modelId.split('/');
132
+ const namespace = parts[0];
133
+ const modelName = parts[1];
134
+ // Try both possible cache locations
135
+ let baseDir = path.join(transformers_1.env.cacheDir, namespace, modelName, 'onnx');
136
+ let fp32Path = path.join(baseDir, 'model.onnx');
137
+ let quantizedPath = path.join(baseDir, 'model_quantized.onnx');
138
+ // If ONNX model files don't exist, download them
139
+ if (!fs.existsSync(fp32Path) && !fs.existsSync(quantizedPath)) {
140
+ console.log(`[EmbeddingService] Model not found, downloading ${this.modelId}...`);
141
+ console.log(`[EmbeddingService] This may take a few minutes on first run.`);
142
+ // Import AutoModel dynamically to trigger download
143
+ const { AutoModel } = await import("@xenova/transformers");
144
+ await AutoModel.from_pretrained(this.modelId, { quantized: false });
145
+ console.log(`[EmbeddingService] Model download completed.`);
146
+ }
147
+ // 2. Load Tokenizer
113
148
  if (!this.tokenizer) {
114
149
  this.tokenizer = await transformers_1.AutoTokenizer.from_pretrained(this.modelId);
115
150
  }
116
- // 2. Determine model path
117
- const baseDir = path.join(transformers_1.env.cacheDir, 'Xenova', 'bge-m3', 'onnx');
151
+ // 3. Determine model path
118
152
  // Priority: FP32 (model.onnx) > Quantized (model_quantized.onnx)
119
- let modelPath = path.join(baseDir, 'model.onnx');
153
+ let modelPath = fp32Path;
120
154
  if (!fs.existsSync(modelPath)) {
121
- modelPath = path.join(baseDir, 'model_quantized.onnx');
155
+ modelPath = quantizedPath;
122
156
  }
123
157
  if (!fs.existsSync(modelPath)) {
124
- throw new Error(`Model file not found at: ${modelPath}`);
158
+ throw new Error(`Model file not found at: ${modelPath}. Download may have failed.`);
125
159
  }
126
- // 3. Create Session
160
+ // 4. Create Session
127
161
  if (!this.session) {
128
162
  const options = {
129
163
  executionProviders: ['cpu'], // Use CPU backend to avoid native conflicts
@@ -139,7 +173,15 @@ class EmbeddingService {
139
173
  }
140
174
  async embed(text) {
141
175
  return this.runSerialized(async () => {
142
- const textStr = String(text || "");
176
+ let textStr = String(text || "");
177
+ // For Qwen3-Embedding models, add instruction prefix for better results
178
+ // (only for queries, not for documents being indexed)
179
+ if (this.modelId.includes('Qwen3-Embedding')) {
180
+ // Add instruction prefix if not already present
181
+ if (!textStr.startsWith('Instruct:')) {
182
+ textStr = `Instruct: Given a web search query, retrieve relevant passages that answer the query\nQuery: ${textStr}`;
183
+ }
184
+ }
143
185
  // 1. Cache lookup
144
186
  const cached = this.cache.get(textStr);
145
187
  if (cached) {
@@ -171,14 +213,22 @@ class EmbeddingService {
171
213
  const results = await this.session.run(feeds);
172
214
  // 5. Pooling & Normalization
173
215
  // Output name usually 'last_hidden_state' or 'logits'
174
- // For BGE-M3, the first output is usually the hidden states [batch, seq_len, hidden_size]
175
216
  const outputName = this.session.outputNames[0];
176
217
  const outputTensor = results[outputName];
177
218
  // Ensure we have data
178
219
  if (!outputTensor || !attentionMaskData) {
179
220
  throw new Error("No output data or attention mask available");
180
221
  }
181
- const embedding = this.meanPooling(outputTensor.data, attentionMaskData, outputTensor.dims);
222
+ // Choose pooling strategy based on model
223
+ let embedding;
224
+ if (this.modelId.includes('Qwen3-Embedding')) {
225
+ // Qwen3-Embedding uses last token pooling
226
+ embedding = this.lastTokenPooling(outputTensor.data, attentionMaskData, outputTensor.dims);
227
+ }
228
+ else {
229
+ // BGE and other models use mean pooling
230
+ embedding = this.meanPooling(outputTensor.data, attentionMaskData, outputTensor.dims);
231
+ }
182
232
  // Normalize
183
233
  const normalized = this.normalize(embedding);
184
234
  this.cache.set(textStr, normalized);
@@ -200,6 +250,25 @@ class EmbeddingService {
200
250
  }
201
251
  return results;
202
252
  }
253
+ lastTokenPooling(data, attentionMask, dims) {
254
+ // dims: [batch_size, seq_len, hidden_size]
255
+ // Extract the last valid token's hidden state
256
+ const [batchSize, seqLen, hiddenSize] = dims;
257
+ // Find last valid token position
258
+ let lastValidIdx = seqLen - 1;
259
+ for (let i = seqLen - 1; i >= 0; i--) {
260
+ if (attentionMask[i] === 1n) {
261
+ lastValidIdx = i;
262
+ break;
263
+ }
264
+ }
265
+ // Extract embedding at last valid position
266
+ const embedding = new Float32Array(hiddenSize);
267
+ for (let j = 0; j < hiddenSize; j++) {
268
+ embedding[j] = data[lastValidIdx * hiddenSize + j];
269
+ }
270
+ return Array.from(embedding);
271
+ }
203
272
  meanPooling(data, attentionMask, dims) {
204
273
  // dims: [batch_size, seq_len, hidden_size]
205
274
  // We assume batch_size = 1 for single embedding call
@@ -184,7 +184,7 @@ class HybridSearch {
184
184
  console.error('--- DEBUG: Cozo Datalog Query ---');
185
185
  console.error(datalogQuery);
186
186
  console.error('--- DEBUG: Params ---');
187
- console.dir(params, { depth: null });
187
+ console.error(JSON.stringify(params, null, 2));
188
188
  try {
189
189
  const results = await this.db.run(datalogQuery, params);
190
190
  let searchResults = results.rows.map((r) => ({
@@ -234,8 +234,13 @@ class HybridSearch {
234
234
  const { limit: queryLimit = 10, filters, graphConstraints, vectorParams } = options;
235
235
  // @ts-ignore
236
236
  const { topk = 5, efSearch = 50 } = vectorParams || {};
237
- // Fallback Mock
238
- return [];
237
+ // Use advancedSearch as the default implementation
238
+ return this.advancedSearch({
239
+ ...options,
240
+ vectorParams: {
241
+ efSearch: 100
242
+ }
243
+ });
239
244
  }
240
245
  async graphRag(options) {
241
246
  console.error("[HybridSearch] Starting graphRag with options:", JSON.stringify(options, null, 2));