@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 +93 -73
- package/dist/core/config/index.d.ts +1 -1
- package/dist/core/config/index.js +15 -1
- package/dist/server.js +93 -73
- package/dist/services/digest/digest-processor.test.js +5 -19
- package/dist/services/memory/constants.d.ts +2 -1
- package/dist/services/memory/constants.js +6 -1
- package/dist/services/memory/memory.test.js +10 -0
- package/dist/services/memory/store.d.ts +5 -3
- package/dist/services/memory/store.js +90 -74
- package/dist/services/memory/store.test.js +163 -15
- package/package.json +3 -5
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:
|
|
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 "
|
|
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
|
|
15318
|
-
var
|
|
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
|
|
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
|
-
|
|
15349
|
-
|
|
15350
|
-
|
|
15351
|
-
|
|
15352
|
-
|
|
15353
|
-
|
|
15354
|
-
|
|
15355
|
-
|
|
15356
|
-
|
|
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 =
|
|
15369
|
-
|
|
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
|
-
|
|
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
|
|
15546
|
+
const queryVector = this.toVectorBinding(embedding);
|
|
15527
15547
|
const rows = this.db.prepare(
|
|
15528
|
-
`SELECT mc.id,
|
|
15529
|
-
FROM
|
|
15530
|
-
JOIN memory_chunks mc ON mc.rowid =
|
|
15531
|
-
|
|
15532
|
-
|
|
15533
|
-
).all(
|
|
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:
|
|
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
|
|
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
|
|
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:
|
|
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 "
|
|
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
|
|
37183
|
-
var
|
|
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
|
|
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
|
-
|
|
37214
|
-
|
|
37215
|
-
|
|
37216
|
-
|
|
37217
|
-
|
|
37218
|
-
|
|
37219
|
-
|
|
37220
|
-
|
|
37221
|
-
|
|
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 =
|
|
37234
|
-
|
|
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
|
-
|
|
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
|
|
37411
|
+
const queryVector = this.toVectorBinding(embedding);
|
|
37392
37412
|
const rows = this.db.prepare(
|
|
37393
|
-
`SELECT mc.id,
|
|
37394
|
-
FROM
|
|
37395
|
-
JOIN memory_chunks mc ON mc.rowid =
|
|
37396
|
-
|
|
37397
|
-
|
|
37398
|
-
).all(
|
|
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:
|
|
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
|
|
37476
|
+
return true;
|
|
37457
37477
|
}
|
|
37458
37478
|
close() {
|
|
37459
37479
|
this.db.close();
|