@hanhnd/agent-kit 1.0.35 → 1.0.37

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 CHANGED
@@ -15019,6 +15019,11 @@ import * as os from "os";
15019
15019
  import * as path3 from "path";
15020
15020
 
15021
15021
  // src/services/memory/constants.ts
15022
+ var EMBEDDING_MODEL_DIMENSIONS = {
15023
+ ["tiny" /* TINY */]: 384,
15024
+ ["base" /* BASE */]: 384,
15025
+ ["large" /* LARGE */]: 768
15026
+ };
15022
15027
  var DEFAULT_MEMORY_CONFIG = {
15023
15028
  enabled: false,
15024
15029
  wikiDir: "",
@@ -15026,7 +15031,7 @@ var DEFAULT_MEMORY_CONFIG = {
15026
15031
  chunkSize: 1500,
15027
15032
  overlapLines: 2,
15028
15033
  embeddingModel: "base" /* BASE */,
15029
- vectorDimension: 384
15034
+ vectorDimension: EMBEDDING_MODEL_DIMENSIONS["base" /* BASE */]
15030
15035
  };
15031
15036
  var LOCK_RETRY_MS = 50;
15032
15037
  var LOCK_TIMEOUT_MS = 500;
@@ -15035,13 +15040,20 @@ var RRF_K = 60;
15035
15040
  // src/core/config/index.ts
15036
15041
  function resolveMemoryConfig(settings, workspaceRoot) {
15037
15042
  const override = settings.memory ?? {};
15043
+ const embeddingModel = isEmbeddingModelName(override.embeddingModel) ? override.embeddingModel : DEFAULT_MEMORY_CONFIG.embeddingModel;
15044
+ const vectorDimension = typeof override.vectorDimension === "number" && Number.isFinite(override.vectorDimension) && override.vectorDimension > 0 ? override.vectorDimension : EMBEDDING_MODEL_DIMENSIONS[embeddingModel];
15038
15045
  return {
15039
15046
  ...DEFAULT_MEMORY_CONFIG,
15040
15047
  ...override,
15041
15048
  enabled: override.enabled ?? DEFAULT_MEMORY_CONFIG.enabled,
15049
+ embeddingModel,
15050
+ vectorDimension,
15042
15051
  wikiDir: typeof override.wikiDir === "string" && override.wikiDir.length > 0 ? override.wikiDir : path3.join(workspaceRoot, ".agent-kit", "wiki")
15043
15052
  };
15044
15053
  }
15054
+ function isEmbeddingModelName(value) {
15055
+ return value === "tiny" /* TINY */ || value === "base" /* BASE */ || value === "large" /* LARGE */;
15056
+ }
15045
15057
  function getGlobalSettingsFile() {
15046
15058
  return path3.join(os.homedir(), ".agent-kit", "settings.json");
15047
15059
  }
@@ -15310,12 +15322,11 @@ ${sanitized}`;
15310
15322
 
15311
15323
  // src/services/memory/store.ts
15312
15324
  var import_stopword = __toESM(require_stopword_cjs(), 1);
15313
- import Database from "better-sqlite3";
15325
+ import Database from "libsql";
15314
15326
  import * as fs5 from "fs";
15315
- import { createRequire } from "module";
15316
15327
  import * as path7 from "path";
15317
- var require2 = createRequire(import.meta.url);
15318
- var SCHEMA_VERSION = 2;
15328
+ var SCHEMA_VERSION = 4;
15329
+ var LibsqlDatabase = Database;
15319
15330
  var StoreError = class extends Error {
15320
15331
  constructor(message, cause) {
15321
15332
  super(message);
@@ -15330,13 +15341,11 @@ var MemoryStore = class {
15330
15341
  this.db = this.openDatabase(dbPath);
15331
15342
  }
15332
15343
  db;
15333
- _vecAvailable = false;
15334
15344
  openDatabase(dbPath) {
15335
15345
  try {
15336
- const db = new Database(dbPath);
15346
+ const db = new LibsqlDatabase(dbPath);
15337
15347
  db.pragma("journal_mode = WAL");
15338
15348
  db.pragma("busy_timeout = 5000");
15339
- this.loadVecExtension(db);
15340
15349
  this.createSchema(db);
15341
15350
  return db;
15342
15351
  } catch (err) {
@@ -15345,33 +15354,28 @@ var MemoryStore = class {
15345
15354
  fs5.unlinkSync(dbPath);
15346
15355
  } catch {
15347
15356
  }
15348
- const db = new Database(dbPath);
15349
- db.pragma("journal_mode = WAL");
15350
- db.pragma("busy_timeout = 5000");
15351
- this.loadVecExtension(db);
15352
- this.createSchema(db);
15353
- return db;
15354
- }
15355
- }
15356
- loadVecExtension(db) {
15357
- try {
15358
- const sqliteVec = require2("sqlite-vec");
15359
- sqliteVec.load(db);
15360
- this._vecAvailable = true;
15361
- } catch (err) {
15362
- console.warn("[memory-store] sqlite-vec unavailable, degrading to FTS5-only:", err);
15363
- this._vecAvailable = false;
15357
+ try {
15358
+ const db = new LibsqlDatabase(dbPath);
15359
+ db.pragma("journal_mode = WAL");
15360
+ db.pragma("busy_timeout = 5000");
15361
+ this.createSchema(db);
15362
+ return db;
15363
+ } catch (retryErr) {
15364
+ throw new StoreError("database open failed", retryErr);
15365
+ }
15364
15366
  }
15365
15367
  }
15366
15368
  createSchema(db) {
15367
15369
  try {
15368
- const current = Number(db.pragma("user_version", { simple: true }) ?? 0);
15369
- if (current < SCHEMA_VERSION) {
15370
+ const current = this.readUserVersion(db);
15371
+ const currentVectorDimension = current >= SCHEMA_VERSION ? this.readEmbeddingColumnDimension(db) : void 0;
15372
+ if (current < SCHEMA_VERSION || currentVectorDimension !== void 0 && currentVectorDimension !== this.config.vectorDimension) {
15370
15373
  db.exec(`
15371
15374
  DROP TRIGGER IF EXISTS memory_chunks_ai;
15372
15375
  DROP TRIGGER IF EXISTS memory_chunks_ad;
15373
15376
  DROP TABLE IF EXISTS memory_fts;
15374
15377
  DROP TABLE IF EXISTS memory_vec;
15378
+ DROP INDEX IF EXISTS idx_memory_chunks_embedding;
15375
15379
  DROP TABLE IF EXISTS memory_chunks;
15376
15380
  `);
15377
15381
  db.pragma(`user_version = ${SCHEMA_VERSION}`);
@@ -15388,7 +15392,8 @@ var MemoryStore = class {
15388
15392
  line_start INTEGER NOT NULL,
15389
15393
  line_end INTEGER NOT NULL,
15390
15394
  indexed_at INTEGER NOT NULL,
15391
- file_mtime_at INTEGER NOT NULL DEFAULT 0
15395
+ file_mtime_at INTEGER NOT NULL DEFAULT 0,
15396
+ embedding F32_BLOB(${this.config.vectorDimension}) NOT NULL
15392
15397
  );
15393
15398
 
15394
15399
  CREATE INDEX IF NOT EXISTS idx_memory_chunks_type_mtime
@@ -15413,39 +15418,56 @@ var MemoryStore = class {
15413
15418
  INSERT INTO memory_fts(memory_fts, rowid, source, heading, content)
15414
15419
  VALUES ('delete', old.rowid, old.source, old.heading, old.content);
15415
15420
  END;
15421
+
15422
+ CREATE INDEX IF NOT EXISTS idx_memory_chunks_embedding
15423
+ ON memory_chunks (libsql_vector_idx(embedding));
15416
15424
  `);
15417
- if (this._vecAvailable) {
15418
- try {
15419
- db.exec(`
15420
- CREATE VIRTUAL TABLE IF NOT EXISTS memory_vec USING vec0(
15421
- embedding FLOAT[${this.config.vectorDimension}]
15422
- );
15423
- `);
15424
- } catch (err) {
15425
- console.warn("[memory-store] Failed to create memory_vec, disabling vector search:", err);
15426
- this._vecAvailable = false;
15427
- }
15428
- }
15429
15425
  } catch (err) {
15430
15426
  throw new StoreError("schema migration failed", err);
15431
15427
  }
15432
15428
  }
15429
+ readEmbeddingColumnDimension(db) {
15430
+ try {
15431
+ const rows = db.pragma("table_info(memory_chunks)");
15432
+ if (!Array.isArray(rows)) return void 0;
15433
+ const embeddingColumn = rows.find((row) => {
15434
+ if (!row || typeof row !== "object") return false;
15435
+ const candidate = row;
15436
+ return candidate.name === "embedding" && typeof candidate.type === "string";
15437
+ });
15438
+ const match = /^F32_BLOB\((\d+)\)$/i.exec(embeddingColumn?.type.trim() ?? "");
15439
+ if (!match) return void 0;
15440
+ return Number.parseInt(match[1], 10);
15441
+ } catch {
15442
+ return void 0;
15443
+ }
15444
+ }
15445
+ readUserVersion(db) {
15446
+ const value = db.pragma("user_version", { simple: true });
15447
+ if (typeof value === "number") return value;
15448
+ if (Array.isArray(value)) {
15449
+ const [row] = value;
15450
+ return typeof row?.user_version === "number" ? row.user_version : 0;
15451
+ }
15452
+ if (value && typeof value === "object" && "user_version" in value) {
15453
+ const row = value;
15454
+ return typeof row.user_version === "number" ? row.user_version : 0;
15455
+ }
15456
+ return 0;
15457
+ }
15433
15458
  upsert(chunks, embeddings) {
15434
15459
  const insertChunk = this.db.prepare(`
15435
15460
  INSERT OR REPLACE INTO memory_chunks
15436
- (id, source, source_type, heading, heading_level, content, line_start, line_end, indexed_at, file_mtime_at)
15437
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
15461
+ (id, source, source_type, heading, heading_level, content, line_start, line_end, indexed_at, file_mtime_at, embedding)
15462
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?))
15438
15463
  `);
15439
- let insertVec = null;
15440
- if (this._vecAvailable) {
15441
- insertVec = this.db.prepare(`INSERT OR REPLACE INTO memory_vec (rowid, embedding) VALUES (?, ?)`);
15442
- }
15443
15464
  const upsertAll = this.db.transaction(() => {
15444
15465
  for (let i = 0; i < chunks.length; i++) {
15445
15466
  const chunk = chunks[i];
15446
15467
  try {
15468
+ const vectorBinding = this.toVectorBinding(embeddings[i]);
15447
15469
  this.db.prepare(`DELETE FROM memory_chunks WHERE id = ?`).run(chunk.id);
15448
- const info = insertChunk.run(
15470
+ insertChunk.run(
15449
15471
  chunk.id,
15450
15472
  chunk.source,
15451
15473
  chunk.sourceType,
@@ -15455,14 +15477,9 @@ var MemoryStore = class {
15455
15477
  chunk.lineStart,
15456
15478
  chunk.lineEnd,
15457
15479
  Date.now(),
15458
- chunk.fileMtimeAt
15480
+ chunk.fileMtimeAt,
15481
+ vectorBinding
15459
15482
  );
15460
- if (insertVec && embeddings[i] && info.lastInsertRowid) {
15461
- const rowid = typeof info.lastInsertRowid === "bigint" ? info.lastInsertRowid : BigInt(info.lastInsertRowid);
15462
- const emb = embeddings[i];
15463
- const buf = Buffer.from(emb.buffer, emb.byteOffset, emb.byteLength);
15464
- insertVec.run(rowid, buf);
15465
- }
15466
15483
  } catch (err) {
15467
15484
  console.warn(`[memory-store] Failed to upsert chunk ${chunk.id}:`, err);
15468
15485
  }
@@ -15474,6 +15491,20 @@ var MemoryStore = class {
15474
15491
  throw new StoreError("Full batch upsert failed", err);
15475
15492
  }
15476
15493
  }
15494
+ toVectorBinding(embedding) {
15495
+ if (!embedding) throw new Error("missing embedding");
15496
+ if (!(embedding instanceof Float32Array)) throw new Error("missing embedding");
15497
+ if (embedding.length !== this.config.vectorDimension) throw new Error("embedding dimension mismatch");
15498
+ const values = Array.from(embedding, (value) => {
15499
+ if (!Number.isFinite(value)) throw new Error("embedding contains non-finite value");
15500
+ return value;
15501
+ });
15502
+ return JSON.stringify(values);
15503
+ }
15504
+ normalizeVectorDistance(distance) {
15505
+ if (distance <= 0) return 1;
15506
+ return Math.max(0, Math.min(1, 1 - distance));
15507
+ }
15477
15508
  hashesBySource(source) {
15478
15509
  const rows = this.db.prepare(`SELECT id FROM memory_chunks WHERE source = ?`).all(source);
15479
15510
  return new Set(rows.map((r) => r.id));
@@ -15497,12 +15528,7 @@ var MemoryStore = class {
15497
15528
  }
15498
15529
  }
15499
15530
  deleteBySource(source) {
15500
- const rows = this.db.prepare(`SELECT rowid FROM memory_chunks WHERE source = ?`).all(source);
15501
15531
  const deleteAll = this.db.transaction(() => {
15502
- if (this._vecAvailable && rows.length > 0) {
15503
- const placeholders = rows.map(() => "?").join(", ");
15504
- this.db.prepare(`DELETE FROM memory_vec WHERE rowid IN (${placeholders})`).run(...rows.map((r) => r.rowid));
15505
- }
15506
15532
  this.db.prepare(`DELETE FROM memory_chunks WHERE source = ?`).run(source);
15507
15533
  });
15508
15534
  deleteAll();
@@ -15510,30 +15536,24 @@ var MemoryStore = class {
15510
15536
  deleteByIds(ids) {
15511
15537
  if (ids.length === 0) return;
15512
15538
  const placeholders = ids.map(() => "?").join(", ");
15513
- const rows = this.db.prepare(`SELECT rowid FROM memory_chunks WHERE id IN (${placeholders})`).all(...ids);
15514
15539
  const deleteAll = this.db.transaction(() => {
15515
- if (this._vecAvailable && rows.length > 0) {
15516
- const rPlaceholders = rows.map(() => "?").join(", ");
15517
- this.db.prepare(`DELETE FROM memory_vec WHERE rowid IN (${rPlaceholders})`).run(...rows.map((r) => r.rowid));
15518
- }
15519
15540
  this.db.prepare(`DELETE FROM memory_chunks WHERE id IN (${placeholders})`).run(...ids);
15520
15541
  });
15521
15542
  deleteAll();
15522
15543
  }
15523
15544
  searchDense(embedding, limit) {
15524
- if (!this._vecAvailable) return [];
15525
15545
  try {
15526
- const buf = Buffer.from(embedding.buffer);
15546
+ const queryVector = this.toVectorBinding(embedding);
15527
15547
  const rows = this.db.prepare(
15528
- `SELECT mc.id, mv.distance
15529
- FROM memory_vec mv
15530
- JOIN memory_chunks mc ON mc.rowid = mv.rowid
15531
- WHERE mv.embedding MATCH ? AND k = ?
15532
- ORDER BY mv.distance`
15533
- ).all(buf, limit);
15548
+ `SELECT mc.id, vector_distance_cos(mc.embedding, vector32(?)) AS distance
15549
+ FROM vector_top_k('idx_memory_chunks_embedding', vector32(?), ?) AS vector_matches
15550
+ JOIN memory_chunks mc ON mc.rowid = vector_matches.id
15551
+ ORDER BY distance
15552
+ LIMIT ?`
15553
+ ).all(queryVector, queryVector, limit, limit);
15534
15554
  return rows.map((r) => ({
15535
15555
  id: r.id,
15536
- score: Math.max(0, 1 - r.distance)
15556
+ score: this.normalizeVectorDistance(r.distance)
15537
15557
  }));
15538
15558
  } catch (err) {
15539
15559
  console.warn("[memory-store] Dense search failed:", err);
@@ -15588,7 +15608,7 @@ var MemoryStore = class {
15588
15608
  }));
15589
15609
  }
15590
15610
  get vecAvailable() {
15591
- return this._vecAvailable;
15611
+ return true;
15592
15612
  }
15593
15613
  close() {
15594
15614
  this.db.close();
@@ -2,7 +2,7 @@
2
2
  * Configuration utilities
3
3
  * Shared configuration constants and loaders
4
4
  */
5
- import type { MemoryConfig } from '../../services/memory/types.js';
5
+ import { type MemoryConfig } from '../../services/memory/types.js';
6
6
  import type { ConversationDigestSettings } from '../../services/digest/types.js';
7
7
  /**
8
8
  * Default file extensions - expanded to support more languages
@@ -5,7 +5,8 @@
5
5
  import * as fs from 'fs';
6
6
  import * as os from 'os';
7
7
  import * as path from 'path';
8
- import { DEFAULT_MEMORY_CONFIG } from '../../services/memory/constants.js';
8
+ import { DEFAULT_MEMORY_CONFIG, EMBEDDING_MODEL_DIMENSIONS } from '../../services/memory/constants.js';
9
+ import { EmbeddingModelName } from '../../services/memory/types.js';
9
10
  import { atomicWriteJsonFile } from '../../utils/files.js';
10
11
  /**
11
12
  * Default file extensions - expanded to support more languages
@@ -40,15 +41,28 @@ export const DEFAULT_EXTENSIONS = [
40
41
  */
41
42
  export function resolveMemoryConfig(settings, workspaceRoot) {
42
43
  const override = settings.memory ?? {};
44
+ const embeddingModel = isEmbeddingModelName(override.embeddingModel)
45
+ ? override.embeddingModel
46
+ : DEFAULT_MEMORY_CONFIG.embeddingModel;
47
+ const vectorDimension = typeof override.vectorDimension === 'number' &&
48
+ Number.isFinite(override.vectorDimension) &&
49
+ override.vectorDimension > 0
50
+ ? override.vectorDimension
51
+ : EMBEDDING_MODEL_DIMENSIONS[embeddingModel];
43
52
  return {
44
53
  ...DEFAULT_MEMORY_CONFIG,
45
54
  ...override,
46
55
  enabled: override.enabled ?? DEFAULT_MEMORY_CONFIG.enabled,
56
+ embeddingModel,
57
+ vectorDimension,
47
58
  wikiDir: typeof override.wikiDir === 'string' && override.wikiDir.length > 0
48
59
  ? override.wikiDir
49
60
  : path.join(workspaceRoot, '.agent-kit', 'wiki'),
50
61
  };
51
62
  }
63
+ function isEmbeddingModelName(value) {
64
+ return value === EmbeddingModelName.TINY || value === EmbeddingModelName.BASE || value === EmbeddingModelName.LARGE;
65
+ }
52
66
  export function loadProjectSettings(projectDir) {
53
67
  const settingsPath = path.join(projectDir, '.agent-kit', 'settings.json');
54
68
  if (fs.existsSync(settingsPath)) {
package/dist/server.js CHANGED
@@ -35903,6 +35903,11 @@ import * as path2 from "path";
35903
35903
  var SOURCE_TYPES = ["digest", "concept", "entity", "preference", "wiki"];
35904
35904
 
35905
35905
  // src/services/memory/constants.ts
35906
+ var EMBEDDING_MODEL_DIMENSIONS = {
35907
+ ["tiny" /* TINY */]: 384,
35908
+ ["base" /* BASE */]: 384,
35909
+ ["large" /* LARGE */]: 768
35910
+ };
35906
35911
  var DEFAULT_MEMORY_CONFIG = {
35907
35912
  enabled: false,
35908
35913
  wikiDir: "",
@@ -35910,7 +35915,7 @@ var DEFAULT_MEMORY_CONFIG = {
35910
35915
  chunkSize: 1500,
35911
35916
  overlapLines: 2,
35912
35917
  embeddingModel: "base" /* BASE */,
35913
- vectorDimension: 384
35918
+ vectorDimension: EMBEDDING_MODEL_DIMENSIONS["base" /* BASE */]
35914
35919
  };
35915
35920
  var LOCK_RETRY_MS = 50;
35916
35921
  var LOCK_TIMEOUT_MS = 500;
@@ -35985,13 +35990,20 @@ function tryAcquireProcessLock(lockPath) {
35985
35990
  // src/core/config/index.ts
35986
35991
  function resolveMemoryConfig(settings, workspaceRoot2) {
35987
35992
  const override = settings.memory ?? {};
35993
+ const embeddingModel = isEmbeddingModelName(override.embeddingModel) ? override.embeddingModel : DEFAULT_MEMORY_CONFIG.embeddingModel;
35994
+ const vectorDimension = typeof override.vectorDimension === "number" && Number.isFinite(override.vectorDimension) && override.vectorDimension > 0 ? override.vectorDimension : EMBEDDING_MODEL_DIMENSIONS[embeddingModel];
35988
35995
  return {
35989
35996
  ...DEFAULT_MEMORY_CONFIG,
35990
35997
  ...override,
35991
35998
  enabled: override.enabled ?? DEFAULT_MEMORY_CONFIG.enabled,
35999
+ embeddingModel,
36000
+ vectorDimension,
35992
36001
  wikiDir: typeof override.wikiDir === "string" && override.wikiDir.length > 0 ? override.wikiDir : path2.join(workspaceRoot2, ".agent-kit", "wiki")
35993
36002
  };
35994
36003
  }
36004
+ function isEmbeddingModelName(value) {
36005
+ return value === "tiny" /* TINY */ || value === "base" /* BASE */ || value === "large" /* LARGE */;
36006
+ }
35995
36007
  function getGlobalSettingsFile() {
35996
36008
  return path2.join(os.homedir(), ".agent-kit", "settings.json");
35997
36009
  }
@@ -37175,12 +37187,11 @@ ${content}
37175
37187
 
37176
37188
  // src/services/memory/store.ts
37177
37189
  var import_stopword = __toESM(require_stopword_cjs(), 1);
37178
- import Database from "better-sqlite3";
37190
+ import Database from "libsql";
37179
37191
  import * as fs7 from "fs";
37180
- import { createRequire } from "module";
37181
37192
  import * as path9 from "path";
37182
- var require2 = createRequire(import.meta.url);
37183
- var SCHEMA_VERSION = 2;
37193
+ var SCHEMA_VERSION = 4;
37194
+ var LibsqlDatabase = Database;
37184
37195
  var StoreError = class extends Error {
37185
37196
  constructor(message, cause) {
37186
37197
  super(message);
@@ -37195,13 +37206,11 @@ var MemoryStore = class {
37195
37206
  this.db = this.openDatabase(dbPath);
37196
37207
  }
37197
37208
  db;
37198
- _vecAvailable = false;
37199
37209
  openDatabase(dbPath) {
37200
37210
  try {
37201
- const db = new Database(dbPath);
37211
+ const db = new LibsqlDatabase(dbPath);
37202
37212
  db.pragma("journal_mode = WAL");
37203
37213
  db.pragma("busy_timeout = 5000");
37204
- this.loadVecExtension(db);
37205
37214
  this.createSchema(db);
37206
37215
  return db;
37207
37216
  } catch (err) {
@@ -37210,33 +37219,28 @@ var MemoryStore = class {
37210
37219
  fs7.unlinkSync(dbPath);
37211
37220
  } catch {
37212
37221
  }
37213
- const db = new Database(dbPath);
37214
- db.pragma("journal_mode = WAL");
37215
- db.pragma("busy_timeout = 5000");
37216
- this.loadVecExtension(db);
37217
- this.createSchema(db);
37218
- return db;
37219
- }
37220
- }
37221
- loadVecExtension(db) {
37222
- try {
37223
- const sqliteVec = require2("sqlite-vec");
37224
- sqliteVec.load(db);
37225
- this._vecAvailable = true;
37226
- } catch (err) {
37227
- console.warn("[memory-store] sqlite-vec unavailable, degrading to FTS5-only:", err);
37228
- this._vecAvailable = false;
37222
+ try {
37223
+ const db = new LibsqlDatabase(dbPath);
37224
+ db.pragma("journal_mode = WAL");
37225
+ db.pragma("busy_timeout = 5000");
37226
+ this.createSchema(db);
37227
+ return db;
37228
+ } catch (retryErr) {
37229
+ throw new StoreError("database open failed", retryErr);
37230
+ }
37229
37231
  }
37230
37232
  }
37231
37233
  createSchema(db) {
37232
37234
  try {
37233
- const current = Number(db.pragma("user_version", { simple: true }) ?? 0);
37234
- if (current < SCHEMA_VERSION) {
37235
+ const current = this.readUserVersion(db);
37236
+ const currentVectorDimension = current >= SCHEMA_VERSION ? this.readEmbeddingColumnDimension(db) : void 0;
37237
+ if (current < SCHEMA_VERSION || currentVectorDimension !== void 0 && currentVectorDimension !== this.config.vectorDimension) {
37235
37238
  db.exec(`
37236
37239
  DROP TRIGGER IF EXISTS memory_chunks_ai;
37237
37240
  DROP TRIGGER IF EXISTS memory_chunks_ad;
37238
37241
  DROP TABLE IF EXISTS memory_fts;
37239
37242
  DROP TABLE IF EXISTS memory_vec;
37243
+ DROP INDEX IF EXISTS idx_memory_chunks_embedding;
37240
37244
  DROP TABLE IF EXISTS memory_chunks;
37241
37245
  `);
37242
37246
  db.pragma(`user_version = ${SCHEMA_VERSION}`);
@@ -37253,7 +37257,8 @@ var MemoryStore = class {
37253
37257
  line_start INTEGER NOT NULL,
37254
37258
  line_end INTEGER NOT NULL,
37255
37259
  indexed_at INTEGER NOT NULL,
37256
- file_mtime_at INTEGER NOT NULL DEFAULT 0
37260
+ file_mtime_at INTEGER NOT NULL DEFAULT 0,
37261
+ embedding F32_BLOB(${this.config.vectorDimension}) NOT NULL
37257
37262
  );
37258
37263
 
37259
37264
  CREATE INDEX IF NOT EXISTS idx_memory_chunks_type_mtime
@@ -37278,39 +37283,56 @@ var MemoryStore = class {
37278
37283
  INSERT INTO memory_fts(memory_fts, rowid, source, heading, content)
37279
37284
  VALUES ('delete', old.rowid, old.source, old.heading, old.content);
37280
37285
  END;
37286
+
37287
+ CREATE INDEX IF NOT EXISTS idx_memory_chunks_embedding
37288
+ ON memory_chunks (libsql_vector_idx(embedding));
37281
37289
  `);
37282
- if (this._vecAvailable) {
37283
- try {
37284
- db.exec(`
37285
- CREATE VIRTUAL TABLE IF NOT EXISTS memory_vec USING vec0(
37286
- embedding FLOAT[${this.config.vectorDimension}]
37287
- );
37288
- `);
37289
- } catch (err) {
37290
- console.warn("[memory-store] Failed to create memory_vec, disabling vector search:", err);
37291
- this._vecAvailable = false;
37292
- }
37293
- }
37294
37290
  } catch (err) {
37295
37291
  throw new StoreError("schema migration failed", err);
37296
37292
  }
37297
37293
  }
37294
+ readEmbeddingColumnDimension(db) {
37295
+ try {
37296
+ const rows = db.pragma("table_info(memory_chunks)");
37297
+ if (!Array.isArray(rows)) return void 0;
37298
+ const embeddingColumn = rows.find((row) => {
37299
+ if (!row || typeof row !== "object") return false;
37300
+ const candidate = row;
37301
+ return candidate.name === "embedding" && typeof candidate.type === "string";
37302
+ });
37303
+ const match = /^F32_BLOB\((\d+)\)$/i.exec(embeddingColumn?.type.trim() ?? "");
37304
+ if (!match) return void 0;
37305
+ return Number.parseInt(match[1], 10);
37306
+ } catch {
37307
+ return void 0;
37308
+ }
37309
+ }
37310
+ readUserVersion(db) {
37311
+ const value = db.pragma("user_version", { simple: true });
37312
+ if (typeof value === "number") return value;
37313
+ if (Array.isArray(value)) {
37314
+ const [row] = value;
37315
+ return typeof row?.user_version === "number" ? row.user_version : 0;
37316
+ }
37317
+ if (value && typeof value === "object" && "user_version" in value) {
37318
+ const row = value;
37319
+ return typeof row.user_version === "number" ? row.user_version : 0;
37320
+ }
37321
+ return 0;
37322
+ }
37298
37323
  upsert(chunks, embeddings) {
37299
37324
  const insertChunk = this.db.prepare(`
37300
37325
  INSERT OR REPLACE INTO memory_chunks
37301
- (id, source, source_type, heading, heading_level, content, line_start, line_end, indexed_at, file_mtime_at)
37302
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
37326
+ (id, source, source_type, heading, heading_level, content, line_start, line_end, indexed_at, file_mtime_at, embedding)
37327
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?))
37303
37328
  `);
37304
- let insertVec = null;
37305
- if (this._vecAvailable) {
37306
- insertVec = this.db.prepare(`INSERT OR REPLACE INTO memory_vec (rowid, embedding) VALUES (?, ?)`);
37307
- }
37308
37329
  const upsertAll = this.db.transaction(() => {
37309
37330
  for (let i = 0; i < chunks.length; i++) {
37310
37331
  const chunk = chunks[i];
37311
37332
  try {
37333
+ const vectorBinding = this.toVectorBinding(embeddings[i]);
37312
37334
  this.db.prepare(`DELETE FROM memory_chunks WHERE id = ?`).run(chunk.id);
37313
- const info = insertChunk.run(
37335
+ insertChunk.run(
37314
37336
  chunk.id,
37315
37337
  chunk.source,
37316
37338
  chunk.sourceType,
@@ -37320,14 +37342,9 @@ var MemoryStore = class {
37320
37342
  chunk.lineStart,
37321
37343
  chunk.lineEnd,
37322
37344
  Date.now(),
37323
- chunk.fileMtimeAt
37345
+ chunk.fileMtimeAt,
37346
+ vectorBinding
37324
37347
  );
37325
- if (insertVec && embeddings[i] && info.lastInsertRowid) {
37326
- const rowid = typeof info.lastInsertRowid === "bigint" ? info.lastInsertRowid : BigInt(info.lastInsertRowid);
37327
- const emb = embeddings[i];
37328
- const buf = Buffer.from(emb.buffer, emb.byteOffset, emb.byteLength);
37329
- insertVec.run(rowid, buf);
37330
- }
37331
37348
  } catch (err) {
37332
37349
  console.warn(`[memory-store] Failed to upsert chunk ${chunk.id}:`, err);
37333
37350
  }
@@ -37339,6 +37356,20 @@ var MemoryStore = class {
37339
37356
  throw new StoreError("Full batch upsert failed", err);
37340
37357
  }
37341
37358
  }
37359
+ toVectorBinding(embedding) {
37360
+ if (!embedding) throw new Error("missing embedding");
37361
+ if (!(embedding instanceof Float32Array)) throw new Error("missing embedding");
37362
+ if (embedding.length !== this.config.vectorDimension) throw new Error("embedding dimension mismatch");
37363
+ const values = Array.from(embedding, (value) => {
37364
+ if (!Number.isFinite(value)) throw new Error("embedding contains non-finite value");
37365
+ return value;
37366
+ });
37367
+ return JSON.stringify(values);
37368
+ }
37369
+ normalizeVectorDistance(distance) {
37370
+ if (distance <= 0) return 1;
37371
+ return Math.max(0, Math.min(1, 1 - distance));
37372
+ }
37342
37373
  hashesBySource(source) {
37343
37374
  const rows = this.db.prepare(`SELECT id FROM memory_chunks WHERE source = ?`).all(source);
37344
37375
  return new Set(rows.map((r) => r.id));
@@ -37362,12 +37393,7 @@ var MemoryStore = class {
37362
37393
  }
37363
37394
  }
37364
37395
  deleteBySource(source) {
37365
- const rows = this.db.prepare(`SELECT rowid FROM memory_chunks WHERE source = ?`).all(source);
37366
37396
  const deleteAll = this.db.transaction(() => {
37367
- if (this._vecAvailable && rows.length > 0) {
37368
- const placeholders = rows.map(() => "?").join(", ");
37369
- this.db.prepare(`DELETE FROM memory_vec WHERE rowid IN (${placeholders})`).run(...rows.map((r) => r.rowid));
37370
- }
37371
37397
  this.db.prepare(`DELETE FROM memory_chunks WHERE source = ?`).run(source);
37372
37398
  });
37373
37399
  deleteAll();
@@ -37375,30 +37401,24 @@ var MemoryStore = class {
37375
37401
  deleteByIds(ids) {
37376
37402
  if (ids.length === 0) return;
37377
37403
  const placeholders = ids.map(() => "?").join(", ");
37378
- const rows = this.db.prepare(`SELECT rowid FROM memory_chunks WHERE id IN (${placeholders})`).all(...ids);
37379
37404
  const deleteAll = this.db.transaction(() => {
37380
- if (this._vecAvailable && rows.length > 0) {
37381
- const rPlaceholders = rows.map(() => "?").join(", ");
37382
- this.db.prepare(`DELETE FROM memory_vec WHERE rowid IN (${rPlaceholders})`).run(...rows.map((r) => r.rowid));
37383
- }
37384
37405
  this.db.prepare(`DELETE FROM memory_chunks WHERE id IN (${placeholders})`).run(...ids);
37385
37406
  });
37386
37407
  deleteAll();
37387
37408
  }
37388
37409
  searchDense(embedding, limit) {
37389
- if (!this._vecAvailable) return [];
37390
37410
  try {
37391
- const buf = Buffer.from(embedding.buffer);
37411
+ const queryVector = this.toVectorBinding(embedding);
37392
37412
  const rows = this.db.prepare(
37393
- `SELECT mc.id, mv.distance
37394
- FROM memory_vec mv
37395
- JOIN memory_chunks mc ON mc.rowid = mv.rowid
37396
- WHERE mv.embedding MATCH ? AND k = ?
37397
- ORDER BY mv.distance`
37398
- ).all(buf, limit);
37413
+ `SELECT mc.id, vector_distance_cos(mc.embedding, vector32(?)) AS distance
37414
+ FROM vector_top_k('idx_memory_chunks_embedding', vector32(?), ?) AS vector_matches
37415
+ JOIN memory_chunks mc ON mc.rowid = vector_matches.id
37416
+ ORDER BY distance
37417
+ LIMIT ?`
37418
+ ).all(queryVector, queryVector, limit, limit);
37399
37419
  return rows.map((r) => ({
37400
37420
  id: r.id,
37401
- score: Math.max(0, 1 - r.distance)
37421
+ score: this.normalizeVectorDistance(r.distance)
37402
37422
  }));
37403
37423
  } catch (err) {
37404
37424
  console.warn("[memory-store] Dense search failed:", err);
@@ -37453,7 +37473,7 @@ var MemoryStore = class {
37453
37473
  }));
37454
37474
  }
37455
37475
  get vecAvailable() {
37456
- return this._vecAvailable;
37476
+ return true;
37457
37477
  }
37458
37478
  close() {
37459
37479
  this.db.close();