@askexenow/exe-os 0.8.0 → 0.8.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/README.md +178 -79
- package/dist/bin/backfill-responses.js +160 -8
- package/dist/bin/backfill-vectors.js +130 -1
- package/dist/bin/cleanup-stale-review-tasks.js +130 -1
- package/dist/bin/cli.js +10111 -7540
- package/dist/bin/exe-agent.js +159 -1
- package/dist/bin/exe-assign.js +235 -16
- package/dist/bin/exe-boot.js +344 -472
- package/dist/bin/exe-call.js +145 -1
- package/dist/bin/exe-cloud.js +11 -0
- package/dist/bin/exe-dispatch.js +37 -24
- package/dist/bin/exe-doctor.js +130 -1
- package/dist/bin/exe-export-behaviors.js +150 -7
- package/dist/bin/exe-forget.js +822 -665
- package/dist/bin/exe-gateway.js +470 -62
- package/dist/bin/exe-heartbeat.js +133 -2
- package/dist/bin/exe-kill.js +150 -7
- package/dist/bin/exe-launch-agent.js +150 -7
- package/dist/bin/exe-new-employee.js +756 -224
- package/dist/bin/exe-pending-messages.js +132 -2
- package/dist/bin/exe-pending-notifications.js +130 -1
- package/dist/bin/exe-pending-reviews.js +132 -2
- package/dist/bin/exe-review.js +160 -8
- package/dist/bin/exe-search.js +2473 -2008
- package/dist/bin/exe-session-cleanup.js +238 -51
- package/dist/bin/exe-settings.js +11 -0
- package/dist/bin/exe-status.js +130 -1
- package/dist/bin/exe-team.js +130 -1
- package/dist/bin/git-sweep.js +272 -16
- package/dist/bin/graph-backfill.js +150 -7
- package/dist/bin/graph-export.js +150 -7
- package/dist/bin/install.js +5 -0
- package/dist/bin/scan-tasks.js +238 -19
- package/dist/bin/setup.js +1776 -10
- package/dist/bin/shard-migrate.js +150 -7
- package/dist/bin/update.js +9 -6
- package/dist/bin/wiki-sync.js +150 -7
- package/dist/gateway/index.js +470 -62
- package/dist/hooks/bug-report-worker.js +195 -35
- package/dist/hooks/commit-complete.js +272 -16
- package/dist/hooks/error-recall.js +2313 -1847
- package/dist/hooks/exe-heartbeat-hook.js +5 -0
- package/dist/hooks/ingest-worker.js +330 -58
- package/dist/hooks/ingest.js +11 -0
- package/dist/hooks/instructions-loaded.js +199 -10
- package/dist/hooks/notification.js +199 -10
- package/dist/hooks/post-compact.js +199 -10
- package/dist/hooks/pre-compact.js +199 -10
- package/dist/hooks/pre-tool-use.js +199 -10
- package/dist/hooks/prompt-ingest-worker.js +179 -14
- package/dist/hooks/prompt-submit.js +781 -285
- package/dist/hooks/response-ingest-worker.js +1900 -1405
- package/dist/hooks/session-end.js +456 -12
- package/dist/hooks/session-start.js +2188 -1724
- package/dist/hooks/stop.js +200 -10
- package/dist/hooks/subagent-stop.js +199 -10
- package/dist/hooks/summary-worker.js +604 -334
- package/dist/index.js +554 -61
- package/dist/lib/cloud-sync.js +5 -0
- package/dist/lib/config.js +13 -0
- package/dist/lib/consolidation.js +5 -0
- package/dist/lib/database.js +104 -0
- package/dist/lib/device-registry.js +109 -0
- package/dist/lib/embedder.js +13 -0
- package/dist/lib/employee-templates.js +53 -26
- package/dist/lib/employees.js +5 -0
- package/dist/lib/exe-daemon-client.js +5 -0
- package/dist/lib/exe-daemon.js +493 -79
- package/dist/lib/file-grep.js +20 -4
- package/dist/lib/hybrid-search.js +1435 -190
- package/dist/lib/identity-templates.js +126 -5
- package/dist/lib/identity.js +5 -0
- package/dist/lib/license.js +5 -0
- package/dist/lib/messaging.js +37 -24
- package/dist/lib/schedules.js +130 -1
- package/dist/lib/skill-learning.js +11 -0
- package/dist/lib/status-brief.js +5 -0
- package/dist/lib/store.js +199 -10
- package/dist/lib/task-router.js +72 -6
- package/dist/lib/tasks.js +179 -50
- package/dist/lib/tmux-routing.js +179 -46
- package/dist/mcp/server.js +2129 -1855
- package/dist/mcp/tools/create-task.js +86 -36
- package/dist/mcp/tools/deactivate-behavior.js +5 -0
- package/dist/mcp/tools/list-tasks.js +39 -11
- package/dist/mcp/tools/send-message.js +37 -24
- package/dist/mcp/tools/update-task.js +153 -38
- package/dist/runtime/index.js +451 -59
- package/dist/tui/App.js +454 -59
- package/package.json +1 -1
package/dist/hooks/stop.js
CHANGED
|
@@ -80,6 +80,11 @@ function normalizeSessionLifecycle(raw) {
|
|
|
80
80
|
const userSL = raw.sessionLifecycle ?? {};
|
|
81
81
|
raw.sessionLifecycle = { ...defaultSL, ...userSL };
|
|
82
82
|
}
|
|
83
|
+
function normalizeAutoUpdate(raw) {
|
|
84
|
+
const defaultAU = DEFAULT_CONFIG.autoUpdate;
|
|
85
|
+
const userAU = raw.autoUpdate ?? {};
|
|
86
|
+
raw.autoUpdate = { ...defaultAU, ...userAU };
|
|
87
|
+
}
|
|
83
88
|
async function loadConfig() {
|
|
84
89
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
85
90
|
await mkdir(dir, { recursive: true });
|
|
@@ -102,6 +107,7 @@ async function loadConfig() {
|
|
|
102
107
|
}
|
|
103
108
|
normalizeScalingRoadmap(migratedCfg);
|
|
104
109
|
normalizeSessionLifecycle(migratedCfg);
|
|
110
|
+
normalizeAutoUpdate(migratedCfg);
|
|
105
111
|
const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
106
112
|
if (config.dbPath.startsWith("~")) {
|
|
107
113
|
config.dbPath = config.dbPath.replace(/^~/, os.homedir());
|
|
@@ -124,6 +130,7 @@ function loadConfigSync() {
|
|
|
124
130
|
const { config: migratedCfg } = migrateConfig(parsed);
|
|
125
131
|
normalizeScalingRoadmap(migratedCfg);
|
|
126
132
|
normalizeSessionLifecycle(migratedCfg);
|
|
133
|
+
normalizeAutoUpdate(migratedCfg);
|
|
127
134
|
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
128
135
|
} catch {
|
|
129
136
|
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
@@ -195,6 +202,11 @@ var init_config = __esm({
|
|
|
195
202
|
idleKillTicksRequired: 3,
|
|
196
203
|
idleKillIntercomAckWindowMs: 1e4,
|
|
197
204
|
maxAutoInstances: 10
|
|
205
|
+
},
|
|
206
|
+
autoUpdate: {
|
|
207
|
+
checkOnBoot: true,
|
|
208
|
+
autoInstall: false,
|
|
209
|
+
checkIntervalMs: 24 * 60 * 60 * 1e3
|
|
198
210
|
}
|
|
199
211
|
};
|
|
200
212
|
CONFIG_MIGRATIONS = [
|
|
@@ -440,6 +452,27 @@ async function ensureSchema() {
|
|
|
440
452
|
});
|
|
441
453
|
} catch {
|
|
442
454
|
}
|
|
455
|
+
try {
|
|
456
|
+
await client.execute({
|
|
457
|
+
sql: `ALTER TABLE tasks ADD COLUMN checkpoint TEXT`,
|
|
458
|
+
args: []
|
|
459
|
+
});
|
|
460
|
+
} catch {
|
|
461
|
+
}
|
|
462
|
+
try {
|
|
463
|
+
await client.execute({
|
|
464
|
+
sql: `ALTER TABLE tasks ADD COLUMN checkpoint_count INTEGER NOT NULL DEFAULT 0`,
|
|
465
|
+
args: []
|
|
466
|
+
});
|
|
467
|
+
} catch {
|
|
468
|
+
}
|
|
469
|
+
try {
|
|
470
|
+
await client.execute({
|
|
471
|
+
sql: `ALTER TABLE tasks ADD COLUMN complexity TEXT NOT NULL DEFAULT 'standard'`,
|
|
472
|
+
args: []
|
|
473
|
+
});
|
|
474
|
+
} catch {
|
|
475
|
+
}
|
|
443
476
|
try {
|
|
444
477
|
await client.execute({
|
|
445
478
|
sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
|
|
@@ -850,6 +883,15 @@ async function ensureSchema() {
|
|
|
850
883
|
} catch {
|
|
851
884
|
}
|
|
852
885
|
}
|
|
886
|
+
for (const col of [
|
|
887
|
+
"ALTER TABLE memories ADD COLUMN source_path TEXT",
|
|
888
|
+
"ALTER TABLE memories ADD COLUMN source_type TEXT DEFAULT 'text'"
|
|
889
|
+
]) {
|
|
890
|
+
try {
|
|
891
|
+
await client.execute(col);
|
|
892
|
+
} catch {
|
|
893
|
+
}
|
|
894
|
+
}
|
|
853
895
|
await client.executeMultiple(`
|
|
854
896
|
CREATE INDEX IF NOT EXISTS idx_memories_workspace
|
|
855
897
|
ON memories(workspace_id);
|
|
@@ -914,6 +956,34 @@ async function ensureSchema() {
|
|
|
914
956
|
CREATE INDEX IF NOT EXISTS idx_conversations_channel
|
|
915
957
|
ON conversations(channel_id);
|
|
916
958
|
`);
|
|
959
|
+
try {
|
|
960
|
+
await client.execute({
|
|
961
|
+
sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
|
|
962
|
+
args: []
|
|
963
|
+
});
|
|
964
|
+
} catch {
|
|
965
|
+
}
|
|
966
|
+
try {
|
|
967
|
+
await client.execute({
|
|
968
|
+
sql: `ALTER TABLE tasks ADD COLUMN budget_fallback_model TEXT`,
|
|
969
|
+
args: []
|
|
970
|
+
});
|
|
971
|
+
} catch {
|
|
972
|
+
}
|
|
973
|
+
try {
|
|
974
|
+
await client.execute({
|
|
975
|
+
sql: `ALTER TABLE tasks ADD COLUMN tokens_used INTEGER DEFAULT 0`,
|
|
976
|
+
args: []
|
|
977
|
+
});
|
|
978
|
+
} catch {
|
|
979
|
+
}
|
|
980
|
+
try {
|
|
981
|
+
await client.execute({
|
|
982
|
+
sql: `ALTER TABLE tasks ADD COLUMN tokens_warned_at INTEGER`,
|
|
983
|
+
args: []
|
|
984
|
+
});
|
|
985
|
+
} catch {
|
|
986
|
+
}
|
|
917
987
|
await client.executeMultiple(`
|
|
918
988
|
CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
|
|
919
989
|
content_text,
|
|
@@ -940,6 +1010,52 @@ async function ensureSchema() {
|
|
|
940
1010
|
VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
|
|
941
1011
|
END;
|
|
942
1012
|
`);
|
|
1013
|
+
try {
|
|
1014
|
+
await client.execute({
|
|
1015
|
+
sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
|
|
1016
|
+
args: []
|
|
1017
|
+
});
|
|
1018
|
+
} catch {
|
|
1019
|
+
}
|
|
1020
|
+
try {
|
|
1021
|
+
await client.execute(
|
|
1022
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)`
|
|
1023
|
+
);
|
|
1024
|
+
} catch {
|
|
1025
|
+
}
|
|
1026
|
+
try {
|
|
1027
|
+
await client.execute({
|
|
1028
|
+
sql: `UPDATE memories SET tier = 1 WHERE tool_name = 'commit_to_long_term_memory' AND importance >= 8 AND tier = 3`,
|
|
1029
|
+
args: []
|
|
1030
|
+
});
|
|
1031
|
+
await client.execute({
|
|
1032
|
+
sql: `UPDATE memories SET tier = 2 WHERE tool_name IN ('store_memory', 'manual') AND importance >= 5 AND tier = 3`,
|
|
1033
|
+
args: []
|
|
1034
|
+
});
|
|
1035
|
+
} catch {
|
|
1036
|
+
}
|
|
1037
|
+
try {
|
|
1038
|
+
await client.execute({
|
|
1039
|
+
sql: `ALTER TABLE memories ADD COLUMN supersedes_id TEXT`,
|
|
1040
|
+
args: []
|
|
1041
|
+
});
|
|
1042
|
+
} catch {
|
|
1043
|
+
}
|
|
1044
|
+
try {
|
|
1045
|
+
await client.execute(
|
|
1046
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL`
|
|
1047
|
+
);
|
|
1048
|
+
} catch {
|
|
1049
|
+
}
|
|
1050
|
+
for (const col of [
|
|
1051
|
+
"ALTER TABLE tasks ADD COLUMN checkpoint TEXT",
|
|
1052
|
+
"ALTER TABLE tasks ADD COLUMN checkpoint_count INTEGER DEFAULT 0"
|
|
1053
|
+
]) {
|
|
1054
|
+
try {
|
|
1055
|
+
await client.execute(col);
|
|
1056
|
+
} catch {
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
943
1059
|
}
|
|
944
1060
|
async function disposeDatabase() {
|
|
945
1061
|
if (_client) {
|
|
@@ -1124,13 +1240,27 @@ async function ensureShardSchema(client) {
|
|
|
1124
1240
|
"ALTER TABLE memories ADD COLUMN document_id TEXT",
|
|
1125
1241
|
"ALTER TABLE memories ADD COLUMN user_id TEXT",
|
|
1126
1242
|
"ALTER TABLE memories ADD COLUMN char_offset INTEGER",
|
|
1127
|
-
"ALTER TABLE memories ADD COLUMN page_number INTEGER"
|
|
1243
|
+
"ALTER TABLE memories ADD COLUMN page_number INTEGER",
|
|
1244
|
+
// Source provenance columns (must match database.ts)
|
|
1245
|
+
"ALTER TABLE memories ADD COLUMN source_path TEXT",
|
|
1246
|
+
"ALTER TABLE memories ADD COLUMN source_type TEXT DEFAULT 'text'",
|
|
1247
|
+
"ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3",
|
|
1248
|
+
"ALTER TABLE memories ADD COLUMN supersedes_id TEXT"
|
|
1128
1249
|
]) {
|
|
1129
1250
|
try {
|
|
1130
1251
|
await client.execute(col);
|
|
1131
1252
|
} catch {
|
|
1132
1253
|
}
|
|
1133
1254
|
}
|
|
1255
|
+
for (const idx of [
|
|
1256
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
|
|
1257
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
|
|
1258
|
+
]) {
|
|
1259
|
+
try {
|
|
1260
|
+
await client.execute(idx);
|
|
1261
|
+
} catch {
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1134
1264
|
try {
|
|
1135
1265
|
await client.execute("CREATE INDEX IF NOT EXISTS idx_memories_status ON memories(status)");
|
|
1136
1266
|
} catch {
|
|
@@ -1239,8 +1369,11 @@ var store_exports = {};
|
|
|
1239
1369
|
__export(store_exports, {
|
|
1240
1370
|
attachDocumentMetadata: () => attachDocumentMetadata,
|
|
1241
1371
|
buildWikiScopeFilter: () => buildWikiScopeFilter,
|
|
1372
|
+
classifyTier: () => classifyTier,
|
|
1242
1373
|
disposeStore: () => disposeStore,
|
|
1243
1374
|
flushBatch: () => flushBatch,
|
|
1375
|
+
flushTier3: () => flushTier3,
|
|
1376
|
+
getMemoryCardinality: () => getMemoryCardinality,
|
|
1244
1377
|
initStore: () => initStore,
|
|
1245
1378
|
reserveVersions: () => reserveVersions,
|
|
1246
1379
|
searchMemories: () => searchMemories,
|
|
@@ -1286,6 +1419,11 @@ async function initStore(options) {
|
|
|
1286
1419
|
const vResult = await client.execute("SELECT MAX(version) as max_v FROM memories");
|
|
1287
1420
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1288
1421
|
}
|
|
1422
|
+
function classifyTier(record) {
|
|
1423
|
+
if (record.tool_name === "commit_to_long_term_memory" && (record.importance ?? 0) >= 8) return 1;
|
|
1424
|
+
if (["store_memory", "manual"].includes(record.tool_name ?? "") && (record.importance ?? 0) >= 5) return 2;
|
|
1425
|
+
return 3;
|
|
1426
|
+
}
|
|
1289
1427
|
async function writeMemory(record) {
|
|
1290
1428
|
if (record.vector !== null && record.vector.length !== EMBEDDING_DIM) {
|
|
1291
1429
|
throw new Error(
|
|
@@ -1313,7 +1451,11 @@ async function writeMemory(record) {
|
|
|
1313
1451
|
document_id: record.document_id ?? null,
|
|
1314
1452
|
user_id: record.user_id ?? null,
|
|
1315
1453
|
char_offset: record.char_offset ?? null,
|
|
1316
|
-
page_number: record.page_number ?? null
|
|
1454
|
+
page_number: record.page_number ?? null,
|
|
1455
|
+
source_path: record.source_path ?? null,
|
|
1456
|
+
source_type: record.source_type ?? null,
|
|
1457
|
+
tier: record.tier ?? classifyTier(record),
|
|
1458
|
+
supersedes_id: record.supersedes_id ?? null
|
|
1317
1459
|
};
|
|
1318
1460
|
_pendingRecords.push(dbRow);
|
|
1319
1461
|
if (_flushTimer === null) {
|
|
@@ -1345,20 +1487,26 @@ async function flushBatch() {
|
|
|
1345
1487
|
const userId = row.user_id ?? null;
|
|
1346
1488
|
const charOffset = row.char_offset ?? null;
|
|
1347
1489
|
const pageNumber = row.page_number ?? null;
|
|
1490
|
+
const sourcePath = row.source_path ?? null;
|
|
1491
|
+
const sourceType = row.source_type ?? null;
|
|
1492
|
+
const tier = row.tier ?? 3;
|
|
1493
|
+
const supersedesId = row.supersedes_id ?? null;
|
|
1348
1494
|
return {
|
|
1349
1495
|
sql: hasVector ? `INSERT OR IGNORE INTO memories
|
|
1350
1496
|
(id, agent_id, agent_role, session_id, timestamp,
|
|
1351
1497
|
tool_name, project_name,
|
|
1352
1498
|
has_error, raw_text, vector, version, task_id, importance, status,
|
|
1353
1499
|
confidence, last_accessed,
|
|
1354
|
-
workspace_id, document_id, user_id, char_offset, page_number
|
|
1355
|
-
|
|
1500
|
+
workspace_id, document_id, user_id, char_offset, page_number,
|
|
1501
|
+
source_path, source_type, tier, supersedes_id)
|
|
1502
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories
|
|
1356
1503
|
(id, agent_id, agent_role, session_id, timestamp,
|
|
1357
1504
|
tool_name, project_name,
|
|
1358
1505
|
has_error, raw_text, vector, version, task_id, importance, status,
|
|
1359
1506
|
confidence, last_accessed,
|
|
1360
|
-
workspace_id, document_id, user_id, char_offset, page_number
|
|
1361
|
-
|
|
1507
|
+
workspace_id, document_id, user_id, char_offset, page_number,
|
|
1508
|
+
source_path, source_type, tier, supersedes_id)
|
|
1509
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
1362
1510
|
args: hasVector ? [
|
|
1363
1511
|
row.id,
|
|
1364
1512
|
row.agent_id,
|
|
@@ -1380,7 +1528,11 @@ async function flushBatch() {
|
|
|
1380
1528
|
documentId,
|
|
1381
1529
|
userId,
|
|
1382
1530
|
charOffset,
|
|
1383
|
-
pageNumber
|
|
1531
|
+
pageNumber,
|
|
1532
|
+
sourcePath,
|
|
1533
|
+
sourceType,
|
|
1534
|
+
tier,
|
|
1535
|
+
supersedesId
|
|
1384
1536
|
] : [
|
|
1385
1537
|
row.id,
|
|
1386
1538
|
row.agent_id,
|
|
@@ -1401,7 +1553,11 @@ async function flushBatch() {
|
|
|
1401
1553
|
documentId,
|
|
1402
1554
|
userId,
|
|
1403
1555
|
charOffset,
|
|
1404
|
-
pageNumber
|
|
1556
|
+
pageNumber,
|
|
1557
|
+
sourcePath,
|
|
1558
|
+
sourceType,
|
|
1559
|
+
tier,
|
|
1560
|
+
supersedesId
|
|
1405
1561
|
]
|
|
1406
1562
|
};
|
|
1407
1563
|
};
|
|
@@ -1475,7 +1631,8 @@ async function searchMemories(queryVector, agentId, options) {
|
|
|
1475
1631
|
has_error, raw_text, vector, importance, status,
|
|
1476
1632
|
confidence, last_accessed,
|
|
1477
1633
|
workspace_id, document_id, user_id,
|
|
1478
|
-
char_offset, page_number
|
|
1634
|
+
char_offset, page_number,
|
|
1635
|
+
source_path, source_type
|
|
1479
1636
|
FROM memories
|
|
1480
1637
|
WHERE agent_id = ?
|
|
1481
1638
|
AND vector IS NOT NULL${statusFilter}
|
|
@@ -1524,7 +1681,9 @@ async function searchMemories(queryVector, agentId, options) {
|
|
|
1524
1681
|
document_id: row.document_id ?? null,
|
|
1525
1682
|
user_id: row.user_id ?? null,
|
|
1526
1683
|
char_offset: row.char_offset ?? null,
|
|
1527
|
-
page_number: row.page_number ?? null
|
|
1684
|
+
page_number: row.page_number ?? null,
|
|
1685
|
+
source_path: row.source_path ?? null,
|
|
1686
|
+
source_type: row.source_type ?? null
|
|
1528
1687
|
}));
|
|
1529
1688
|
}
|
|
1530
1689
|
async function attachDocumentMetadata(records) {
|
|
@@ -1562,6 +1721,25 @@ async function attachDocumentMetadata(records) {
|
|
|
1562
1721
|
}
|
|
1563
1722
|
return records;
|
|
1564
1723
|
}
|
|
1724
|
+
async function flushTier3(agentId, options) {
|
|
1725
|
+
const client = getClient();
|
|
1726
|
+
const maxAge = options?.maxAgeHours ?? 72;
|
|
1727
|
+
const cutoff = new Date(Date.now() - maxAge * 36e5).toISOString();
|
|
1728
|
+
if (options?.dryRun) {
|
|
1729
|
+
const result2 = await client.execute({
|
|
1730
|
+
sql: `SELECT COUNT(*) as cnt FROM memories
|
|
1731
|
+
WHERE agent_id = ? AND tier = 3 AND status = 'active' AND timestamp < ?`,
|
|
1732
|
+
args: [agentId, cutoff]
|
|
1733
|
+
});
|
|
1734
|
+
return { archived: Number(result2.rows[0]?.cnt ?? 0) };
|
|
1735
|
+
}
|
|
1736
|
+
const result = await client.execute({
|
|
1737
|
+
sql: `UPDATE memories SET status = 'archived'
|
|
1738
|
+
WHERE agent_id = ? AND tier = 3 AND status = 'active' AND timestamp < ?`,
|
|
1739
|
+
args: [agentId, cutoff]
|
|
1740
|
+
});
|
|
1741
|
+
return { archived: result.rowsAffected };
|
|
1742
|
+
}
|
|
1565
1743
|
async function disposeStore() {
|
|
1566
1744
|
if (_flushTimer !== null) {
|
|
1567
1745
|
clearInterval(_flushTimer);
|
|
@@ -1592,6 +1770,18 @@ function reserveVersions(count) {
|
|
|
1592
1770
|
}
|
|
1593
1771
|
return reserved;
|
|
1594
1772
|
}
|
|
1773
|
+
async function getMemoryCardinality(agentId) {
|
|
1774
|
+
try {
|
|
1775
|
+
const client = getClient();
|
|
1776
|
+
const result = await client.execute({
|
|
1777
|
+
sql: `SELECT COUNT(*) as cnt FROM memories WHERE agent_id = ? AND COALESCE(status, 'active') = 'active'`,
|
|
1778
|
+
args: [agentId]
|
|
1779
|
+
});
|
|
1780
|
+
return Number(result.rows[0]?.cnt) || 0;
|
|
1781
|
+
} catch {
|
|
1782
|
+
return 0;
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1595
1785
|
var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
1596
1786
|
var init_store = __esm({
|
|
1597
1787
|
"src/lib/store.ts"() {
|
|
@@ -80,6 +80,11 @@ function normalizeSessionLifecycle(raw) {
|
|
|
80
80
|
const userSL = raw.sessionLifecycle ?? {};
|
|
81
81
|
raw.sessionLifecycle = { ...defaultSL, ...userSL };
|
|
82
82
|
}
|
|
83
|
+
function normalizeAutoUpdate(raw) {
|
|
84
|
+
const defaultAU = DEFAULT_CONFIG.autoUpdate;
|
|
85
|
+
const userAU = raw.autoUpdate ?? {};
|
|
86
|
+
raw.autoUpdate = { ...defaultAU, ...userAU };
|
|
87
|
+
}
|
|
83
88
|
async function loadConfig() {
|
|
84
89
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
85
90
|
await mkdir(dir, { recursive: true });
|
|
@@ -102,6 +107,7 @@ async function loadConfig() {
|
|
|
102
107
|
}
|
|
103
108
|
normalizeScalingRoadmap(migratedCfg);
|
|
104
109
|
normalizeSessionLifecycle(migratedCfg);
|
|
110
|
+
normalizeAutoUpdate(migratedCfg);
|
|
105
111
|
const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
106
112
|
if (config.dbPath.startsWith("~")) {
|
|
107
113
|
config.dbPath = config.dbPath.replace(/^~/, os.homedir());
|
|
@@ -177,6 +183,11 @@ var init_config = __esm({
|
|
|
177
183
|
idleKillTicksRequired: 3,
|
|
178
184
|
idleKillIntercomAckWindowMs: 1e4,
|
|
179
185
|
maxAutoInstances: 10
|
|
186
|
+
},
|
|
187
|
+
autoUpdate: {
|
|
188
|
+
checkOnBoot: true,
|
|
189
|
+
autoInstall: false,
|
|
190
|
+
checkIntervalMs: 24 * 60 * 60 * 1e3
|
|
180
191
|
}
|
|
181
192
|
};
|
|
182
193
|
CONFIG_MIGRATIONS = [
|
|
@@ -422,6 +433,27 @@ async function ensureSchema() {
|
|
|
422
433
|
});
|
|
423
434
|
} catch {
|
|
424
435
|
}
|
|
436
|
+
try {
|
|
437
|
+
await client.execute({
|
|
438
|
+
sql: `ALTER TABLE tasks ADD COLUMN checkpoint TEXT`,
|
|
439
|
+
args: []
|
|
440
|
+
});
|
|
441
|
+
} catch {
|
|
442
|
+
}
|
|
443
|
+
try {
|
|
444
|
+
await client.execute({
|
|
445
|
+
sql: `ALTER TABLE tasks ADD COLUMN checkpoint_count INTEGER NOT NULL DEFAULT 0`,
|
|
446
|
+
args: []
|
|
447
|
+
});
|
|
448
|
+
} catch {
|
|
449
|
+
}
|
|
450
|
+
try {
|
|
451
|
+
await client.execute({
|
|
452
|
+
sql: `ALTER TABLE tasks ADD COLUMN complexity TEXT NOT NULL DEFAULT 'standard'`,
|
|
453
|
+
args: []
|
|
454
|
+
});
|
|
455
|
+
} catch {
|
|
456
|
+
}
|
|
425
457
|
try {
|
|
426
458
|
await client.execute({
|
|
427
459
|
sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
|
|
@@ -832,6 +864,15 @@ async function ensureSchema() {
|
|
|
832
864
|
} catch {
|
|
833
865
|
}
|
|
834
866
|
}
|
|
867
|
+
for (const col of [
|
|
868
|
+
"ALTER TABLE memories ADD COLUMN source_path TEXT",
|
|
869
|
+
"ALTER TABLE memories ADD COLUMN source_type TEXT DEFAULT 'text'"
|
|
870
|
+
]) {
|
|
871
|
+
try {
|
|
872
|
+
await client.execute(col);
|
|
873
|
+
} catch {
|
|
874
|
+
}
|
|
875
|
+
}
|
|
835
876
|
await client.executeMultiple(`
|
|
836
877
|
CREATE INDEX IF NOT EXISTS idx_memories_workspace
|
|
837
878
|
ON memories(workspace_id);
|
|
@@ -896,6 +937,34 @@ async function ensureSchema() {
|
|
|
896
937
|
CREATE INDEX IF NOT EXISTS idx_conversations_channel
|
|
897
938
|
ON conversations(channel_id);
|
|
898
939
|
`);
|
|
940
|
+
try {
|
|
941
|
+
await client.execute({
|
|
942
|
+
sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
|
|
943
|
+
args: []
|
|
944
|
+
});
|
|
945
|
+
} catch {
|
|
946
|
+
}
|
|
947
|
+
try {
|
|
948
|
+
await client.execute({
|
|
949
|
+
sql: `ALTER TABLE tasks ADD COLUMN budget_fallback_model TEXT`,
|
|
950
|
+
args: []
|
|
951
|
+
});
|
|
952
|
+
} catch {
|
|
953
|
+
}
|
|
954
|
+
try {
|
|
955
|
+
await client.execute({
|
|
956
|
+
sql: `ALTER TABLE tasks ADD COLUMN tokens_used INTEGER DEFAULT 0`,
|
|
957
|
+
args: []
|
|
958
|
+
});
|
|
959
|
+
} catch {
|
|
960
|
+
}
|
|
961
|
+
try {
|
|
962
|
+
await client.execute({
|
|
963
|
+
sql: `ALTER TABLE tasks ADD COLUMN tokens_warned_at INTEGER`,
|
|
964
|
+
args: []
|
|
965
|
+
});
|
|
966
|
+
} catch {
|
|
967
|
+
}
|
|
899
968
|
await client.executeMultiple(`
|
|
900
969
|
CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
|
|
901
970
|
content_text,
|
|
@@ -922,6 +991,52 @@ async function ensureSchema() {
|
|
|
922
991
|
VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
|
|
923
992
|
END;
|
|
924
993
|
`);
|
|
994
|
+
try {
|
|
995
|
+
await client.execute({
|
|
996
|
+
sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
|
|
997
|
+
args: []
|
|
998
|
+
});
|
|
999
|
+
} catch {
|
|
1000
|
+
}
|
|
1001
|
+
try {
|
|
1002
|
+
await client.execute(
|
|
1003
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)`
|
|
1004
|
+
);
|
|
1005
|
+
} catch {
|
|
1006
|
+
}
|
|
1007
|
+
try {
|
|
1008
|
+
await client.execute({
|
|
1009
|
+
sql: `UPDATE memories SET tier = 1 WHERE tool_name = 'commit_to_long_term_memory' AND importance >= 8 AND tier = 3`,
|
|
1010
|
+
args: []
|
|
1011
|
+
});
|
|
1012
|
+
await client.execute({
|
|
1013
|
+
sql: `UPDATE memories SET tier = 2 WHERE tool_name IN ('store_memory', 'manual') AND importance >= 5 AND tier = 3`,
|
|
1014
|
+
args: []
|
|
1015
|
+
});
|
|
1016
|
+
} catch {
|
|
1017
|
+
}
|
|
1018
|
+
try {
|
|
1019
|
+
await client.execute({
|
|
1020
|
+
sql: `ALTER TABLE memories ADD COLUMN supersedes_id TEXT`,
|
|
1021
|
+
args: []
|
|
1022
|
+
});
|
|
1023
|
+
} catch {
|
|
1024
|
+
}
|
|
1025
|
+
try {
|
|
1026
|
+
await client.execute(
|
|
1027
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL`
|
|
1028
|
+
);
|
|
1029
|
+
} catch {
|
|
1030
|
+
}
|
|
1031
|
+
for (const col of [
|
|
1032
|
+
"ALTER TABLE tasks ADD COLUMN checkpoint TEXT",
|
|
1033
|
+
"ALTER TABLE tasks ADD COLUMN checkpoint_count INTEGER DEFAULT 0"
|
|
1034
|
+
]) {
|
|
1035
|
+
try {
|
|
1036
|
+
await client.execute(col);
|
|
1037
|
+
} catch {
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
925
1040
|
}
|
|
926
1041
|
async function disposeDatabase() {
|
|
927
1042
|
if (_client) {
|
|
@@ -1106,13 +1221,27 @@ async function ensureShardSchema(client) {
|
|
|
1106
1221
|
"ALTER TABLE memories ADD COLUMN document_id TEXT",
|
|
1107
1222
|
"ALTER TABLE memories ADD COLUMN user_id TEXT",
|
|
1108
1223
|
"ALTER TABLE memories ADD COLUMN char_offset INTEGER",
|
|
1109
|
-
"ALTER TABLE memories ADD COLUMN page_number INTEGER"
|
|
1224
|
+
"ALTER TABLE memories ADD COLUMN page_number INTEGER",
|
|
1225
|
+
// Source provenance columns (must match database.ts)
|
|
1226
|
+
"ALTER TABLE memories ADD COLUMN source_path TEXT",
|
|
1227
|
+
"ALTER TABLE memories ADD COLUMN source_type TEXT DEFAULT 'text'",
|
|
1228
|
+
"ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3",
|
|
1229
|
+
"ALTER TABLE memories ADD COLUMN supersedes_id TEXT"
|
|
1110
1230
|
]) {
|
|
1111
1231
|
try {
|
|
1112
1232
|
await client.execute(col);
|
|
1113
1233
|
} catch {
|
|
1114
1234
|
}
|
|
1115
1235
|
}
|
|
1236
|
+
for (const idx of [
|
|
1237
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
|
|
1238
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
|
|
1239
|
+
]) {
|
|
1240
|
+
try {
|
|
1241
|
+
await client.execute(idx);
|
|
1242
|
+
} catch {
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1116
1245
|
try {
|
|
1117
1246
|
await client.execute("CREATE INDEX IF NOT EXISTS idx_memories_status ON memories(status)");
|
|
1118
1247
|
} catch {
|
|
@@ -1221,8 +1350,11 @@ var store_exports = {};
|
|
|
1221
1350
|
__export(store_exports, {
|
|
1222
1351
|
attachDocumentMetadata: () => attachDocumentMetadata,
|
|
1223
1352
|
buildWikiScopeFilter: () => buildWikiScopeFilter,
|
|
1353
|
+
classifyTier: () => classifyTier,
|
|
1224
1354
|
disposeStore: () => disposeStore,
|
|
1225
1355
|
flushBatch: () => flushBatch,
|
|
1356
|
+
flushTier3: () => flushTier3,
|
|
1357
|
+
getMemoryCardinality: () => getMemoryCardinality,
|
|
1226
1358
|
initStore: () => initStore,
|
|
1227
1359
|
reserveVersions: () => reserveVersions,
|
|
1228
1360
|
searchMemories: () => searchMemories,
|
|
@@ -1268,6 +1400,11 @@ async function initStore(options) {
|
|
|
1268
1400
|
const vResult = await client.execute("SELECT MAX(version) as max_v FROM memories");
|
|
1269
1401
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1270
1402
|
}
|
|
1403
|
+
function classifyTier(record) {
|
|
1404
|
+
if (record.tool_name === "commit_to_long_term_memory" && (record.importance ?? 0) >= 8) return 1;
|
|
1405
|
+
if (["store_memory", "manual"].includes(record.tool_name ?? "") && (record.importance ?? 0) >= 5) return 2;
|
|
1406
|
+
return 3;
|
|
1407
|
+
}
|
|
1271
1408
|
async function writeMemory(record) {
|
|
1272
1409
|
if (record.vector !== null && record.vector.length !== EMBEDDING_DIM) {
|
|
1273
1410
|
throw new Error(
|
|
@@ -1295,7 +1432,11 @@ async function writeMemory(record) {
|
|
|
1295
1432
|
document_id: record.document_id ?? null,
|
|
1296
1433
|
user_id: record.user_id ?? null,
|
|
1297
1434
|
char_offset: record.char_offset ?? null,
|
|
1298
|
-
page_number: record.page_number ?? null
|
|
1435
|
+
page_number: record.page_number ?? null,
|
|
1436
|
+
source_path: record.source_path ?? null,
|
|
1437
|
+
source_type: record.source_type ?? null,
|
|
1438
|
+
tier: record.tier ?? classifyTier(record),
|
|
1439
|
+
supersedes_id: record.supersedes_id ?? null
|
|
1299
1440
|
};
|
|
1300
1441
|
_pendingRecords.push(dbRow);
|
|
1301
1442
|
if (_flushTimer === null) {
|
|
@@ -1327,20 +1468,26 @@ async function flushBatch() {
|
|
|
1327
1468
|
const userId = row.user_id ?? null;
|
|
1328
1469
|
const charOffset = row.char_offset ?? null;
|
|
1329
1470
|
const pageNumber = row.page_number ?? null;
|
|
1471
|
+
const sourcePath = row.source_path ?? null;
|
|
1472
|
+
const sourceType = row.source_type ?? null;
|
|
1473
|
+
const tier = row.tier ?? 3;
|
|
1474
|
+
const supersedesId = row.supersedes_id ?? null;
|
|
1330
1475
|
return {
|
|
1331
1476
|
sql: hasVector ? `INSERT OR IGNORE INTO memories
|
|
1332
1477
|
(id, agent_id, agent_role, session_id, timestamp,
|
|
1333
1478
|
tool_name, project_name,
|
|
1334
1479
|
has_error, raw_text, vector, version, task_id, importance, status,
|
|
1335
1480
|
confidence, last_accessed,
|
|
1336
|
-
workspace_id, document_id, user_id, char_offset, page_number
|
|
1337
|
-
|
|
1481
|
+
workspace_id, document_id, user_id, char_offset, page_number,
|
|
1482
|
+
source_path, source_type, tier, supersedes_id)
|
|
1483
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories
|
|
1338
1484
|
(id, agent_id, agent_role, session_id, timestamp,
|
|
1339
1485
|
tool_name, project_name,
|
|
1340
1486
|
has_error, raw_text, vector, version, task_id, importance, status,
|
|
1341
1487
|
confidence, last_accessed,
|
|
1342
|
-
workspace_id, document_id, user_id, char_offset, page_number
|
|
1343
|
-
|
|
1488
|
+
workspace_id, document_id, user_id, char_offset, page_number,
|
|
1489
|
+
source_path, source_type, tier, supersedes_id)
|
|
1490
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
1344
1491
|
args: hasVector ? [
|
|
1345
1492
|
row.id,
|
|
1346
1493
|
row.agent_id,
|
|
@@ -1362,7 +1509,11 @@ async function flushBatch() {
|
|
|
1362
1509
|
documentId,
|
|
1363
1510
|
userId,
|
|
1364
1511
|
charOffset,
|
|
1365
|
-
pageNumber
|
|
1512
|
+
pageNumber,
|
|
1513
|
+
sourcePath,
|
|
1514
|
+
sourceType,
|
|
1515
|
+
tier,
|
|
1516
|
+
supersedesId
|
|
1366
1517
|
] : [
|
|
1367
1518
|
row.id,
|
|
1368
1519
|
row.agent_id,
|
|
@@ -1383,7 +1534,11 @@ async function flushBatch() {
|
|
|
1383
1534
|
documentId,
|
|
1384
1535
|
userId,
|
|
1385
1536
|
charOffset,
|
|
1386
|
-
pageNumber
|
|
1537
|
+
pageNumber,
|
|
1538
|
+
sourcePath,
|
|
1539
|
+
sourceType,
|
|
1540
|
+
tier,
|
|
1541
|
+
supersedesId
|
|
1387
1542
|
]
|
|
1388
1543
|
};
|
|
1389
1544
|
};
|
|
@@ -1457,7 +1612,8 @@ async function searchMemories(queryVector, agentId, options) {
|
|
|
1457
1612
|
has_error, raw_text, vector, importance, status,
|
|
1458
1613
|
confidence, last_accessed,
|
|
1459
1614
|
workspace_id, document_id, user_id,
|
|
1460
|
-
char_offset, page_number
|
|
1615
|
+
char_offset, page_number,
|
|
1616
|
+
source_path, source_type
|
|
1461
1617
|
FROM memories
|
|
1462
1618
|
WHERE agent_id = ?
|
|
1463
1619
|
AND vector IS NOT NULL${statusFilter}
|
|
@@ -1506,7 +1662,9 @@ async function searchMemories(queryVector, agentId, options) {
|
|
|
1506
1662
|
document_id: row.document_id ?? null,
|
|
1507
1663
|
user_id: row.user_id ?? null,
|
|
1508
1664
|
char_offset: row.char_offset ?? null,
|
|
1509
|
-
page_number: row.page_number ?? null
|
|
1665
|
+
page_number: row.page_number ?? null,
|
|
1666
|
+
source_path: row.source_path ?? null,
|
|
1667
|
+
source_type: row.source_type ?? null
|
|
1510
1668
|
}));
|
|
1511
1669
|
}
|
|
1512
1670
|
async function attachDocumentMetadata(records) {
|
|
@@ -1544,6 +1702,25 @@ async function attachDocumentMetadata(records) {
|
|
|
1544
1702
|
}
|
|
1545
1703
|
return records;
|
|
1546
1704
|
}
|
|
1705
|
+
async function flushTier3(agentId, options) {
|
|
1706
|
+
const client = getClient();
|
|
1707
|
+
const maxAge = options?.maxAgeHours ?? 72;
|
|
1708
|
+
const cutoff = new Date(Date.now() - maxAge * 36e5).toISOString();
|
|
1709
|
+
if (options?.dryRun) {
|
|
1710
|
+
const result2 = await client.execute({
|
|
1711
|
+
sql: `SELECT COUNT(*) as cnt FROM memories
|
|
1712
|
+
WHERE agent_id = ? AND tier = 3 AND status = 'active' AND timestamp < ?`,
|
|
1713
|
+
args: [agentId, cutoff]
|
|
1714
|
+
});
|
|
1715
|
+
return { archived: Number(result2.rows[0]?.cnt ?? 0) };
|
|
1716
|
+
}
|
|
1717
|
+
const result = await client.execute({
|
|
1718
|
+
sql: `UPDATE memories SET status = 'archived'
|
|
1719
|
+
WHERE agent_id = ? AND tier = 3 AND status = 'active' AND timestamp < ?`,
|
|
1720
|
+
args: [agentId, cutoff]
|
|
1721
|
+
});
|
|
1722
|
+
return { archived: result.rowsAffected };
|
|
1723
|
+
}
|
|
1547
1724
|
async function disposeStore() {
|
|
1548
1725
|
if (_flushTimer !== null) {
|
|
1549
1726
|
clearInterval(_flushTimer);
|
|
@@ -1574,6 +1751,18 @@ function reserveVersions(count) {
|
|
|
1574
1751
|
}
|
|
1575
1752
|
return reserved;
|
|
1576
1753
|
}
|
|
1754
|
+
async function getMemoryCardinality(agentId) {
|
|
1755
|
+
try {
|
|
1756
|
+
const client = getClient();
|
|
1757
|
+
const result = await client.execute({
|
|
1758
|
+
sql: `SELECT COUNT(*) as cnt FROM memories WHERE agent_id = ? AND COALESCE(status, 'active') = 'active'`,
|
|
1759
|
+
args: [agentId]
|
|
1760
|
+
});
|
|
1761
|
+
return Number(result.rows[0]?.cnt) || 0;
|
|
1762
|
+
} catch {
|
|
1763
|
+
return 0;
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1577
1766
|
var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
1578
1767
|
var init_store = __esm({
|
|
1579
1768
|
"src/lib/store.ts"() {
|