@askexenow/exe-os 0.9.61 → 0.9.63
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/deploy/stack-manifests/v0.9.json +62 -13
- package/dist/bin/backfill-conversations.js +210 -2
- package/dist/bin/backfill-responses.js +210 -2
- package/dist/bin/backfill-vectors.js +47 -2
- package/dist/bin/cleanup-stale-review-tasks.js +210 -2
- package/dist/bin/cli.js +488 -25
- package/dist/bin/exe-agent-config.js +2 -2
- package/dist/bin/exe-agent.js +2 -2
- package/dist/bin/exe-assign.js +210 -2
- package/dist/bin/exe-boot.js +47 -2
- package/dist/bin/exe-call.js +2 -2
- package/dist/bin/exe-cloud.js +2 -2
- package/dist/bin/exe-dispatch.js +210 -2
- package/dist/bin/exe-doctor.js +2691 -1212
- package/dist/bin/exe-export-behaviors.js +210 -2
- package/dist/bin/exe-forget.js +264 -2
- package/dist/bin/exe-gateway.js +210 -2
- package/dist/bin/exe-heartbeat.js +212 -4
- package/dist/bin/exe-kill.js +210 -2
- package/dist/bin/exe-launch-agent.js +210 -2
- package/dist/bin/exe-link.js +47 -2
- package/dist/bin/exe-new-employee.js +113 -3
- package/dist/bin/exe-pending-messages.js +210 -2
- package/dist/bin/exe-pending-notifications.js +210 -2
- package/dist/bin/exe-pending-reviews.js +210 -2
- package/dist/bin/exe-rename.js +210 -2
- package/dist/bin/exe-review.js +210 -2
- package/dist/bin/exe-search.js +234 -3
- package/dist/bin/exe-session-cleanup.js +210 -2
- package/dist/bin/exe-settings.js +2 -2
- package/dist/bin/exe-start-codex.js +322 -4
- package/dist/bin/exe-start-opencode.js +336 -4
- package/dist/bin/exe-status.js +210 -2
- package/dist/bin/exe-team.js +210 -2
- package/dist/bin/git-sweep.js +210 -2
- package/dist/bin/graph-backfill.js +210 -2
- package/dist/bin/graph-export.js +210 -2
- package/dist/bin/install.js +113 -3
- package/dist/bin/intercom-check.js +210 -2
- package/dist/bin/scan-tasks.js +210 -2
- package/dist/bin/setup.js +47 -2
- package/dist/bin/shard-migrate.js +210 -2
- package/dist/bin/stack-update.js +158 -13
- package/dist/bin/update.js +2 -2
- package/dist/gateway/index.js +210 -2
- package/dist/hooks/bug-report-worker.js +321 -44
- package/dist/hooks/codex-stop-task-finalizer.js +210 -2
- package/dist/hooks/commit-complete.js +210 -2
- package/dist/hooks/error-recall.js +234 -3
- package/dist/hooks/exe-heartbeat-hook.js +2 -2
- package/dist/hooks/ingest-worker.js +2 -2
- package/dist/hooks/ingest.js +210 -2
- package/dist/hooks/instructions-loaded.js +210 -2
- package/dist/hooks/notification.js +210 -2
- package/dist/hooks/post-compact.js +210 -2
- package/dist/hooks/post-tool-combined.js +234 -3
- package/dist/hooks/pre-compact.js +446 -111
- package/dist/hooks/pre-tool-use.js +210 -2
- package/dist/hooks/prompt-submit.js +234 -3
- package/dist/hooks/session-end.js +347 -124
- package/dist/hooks/session-start.js +236 -5
- package/dist/hooks/stop.js +210 -2
- package/dist/hooks/subagent-stop.js +210 -2
- package/dist/hooks/summary-worker.js +171 -74
- package/dist/index.js +210 -2
- package/dist/lib/agent-config.js +2 -2
- package/dist/lib/cloud-sync.js +47 -2
- package/dist/lib/config.js +2 -2
- package/dist/lib/consolidation.js +2 -2
- package/dist/lib/database.js +47 -2
- package/dist/lib/db-daemon-client.js +2 -2
- package/dist/lib/db.js +47 -2
- package/dist/lib/device-registry.js +47 -2
- package/dist/lib/embedder.js +2 -2
- package/dist/lib/employee-templates.js +2 -2
- package/dist/lib/employees.js +2 -2
- package/dist/lib/exe-daemon-client.js +2 -2
- package/dist/lib/exe-daemon.js +592 -10
- package/dist/lib/hybrid-search.js +234 -3
- package/dist/lib/identity.js +2 -2
- package/dist/lib/license.js +2 -2
- package/dist/lib/messaging.js +2 -2
- package/dist/lib/reminders.js +2 -2
- package/dist/lib/schedules.js +47 -2
- package/dist/lib/skill-learning.js +2 -2
- package/dist/lib/store.js +210 -2
- package/dist/lib/task-router.js +2 -2
- package/dist/lib/tasks.js +2 -2
- package/dist/lib/tmux-routing.js +2 -2
- package/dist/lib/token-spend.js +2 -2
- package/dist/mcp/server.js +608 -10
- package/dist/mcp/tools/complete-reminder.js +2 -2
- package/dist/mcp/tools/create-reminder.js +2 -2
- package/dist/mcp/tools/create-task.js +2 -2
- package/dist/mcp/tools/deactivate-behavior.js +2 -2
- package/dist/mcp/tools/list-reminders.js +2 -2
- package/dist/mcp/tools/list-tasks.js +2 -2
- package/dist/mcp/tools/send-message.js +2 -2
- package/dist/mcp/tools/update-task.js +2 -2
- package/dist/runtime/index.js +210 -2
- package/dist/tui/App.js +210 -2
- package/package.json +3 -2
- package/stack.release.json +23 -7
|
@@ -257,8 +257,8 @@ var init_config = __esm({
|
|
|
257
257
|
rerankerAutoTrigger: {
|
|
258
258
|
enabled: true,
|
|
259
259
|
broadQueryMinCardinality: 5e4,
|
|
260
|
-
fetchTopK:
|
|
261
|
-
returnTopK:
|
|
260
|
+
fetchTopK: 200,
|
|
261
|
+
returnTopK: 20
|
|
262
262
|
}
|
|
263
263
|
},
|
|
264
264
|
graphRagEnabled: true,
|
|
@@ -3121,6 +3121,51 @@ async function ensureSchema() {
|
|
|
3121
3121
|
VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
|
|
3122
3122
|
END;
|
|
3123
3123
|
`);
|
|
3124
|
+
await client.executeMultiple(`
|
|
3125
|
+
CREATE TABLE IF NOT EXISTS memory_cards (
|
|
3126
|
+
id TEXT PRIMARY KEY,
|
|
3127
|
+
memory_id TEXT NOT NULL,
|
|
3128
|
+
agent_id TEXT NOT NULL,
|
|
3129
|
+
session_id TEXT NOT NULL,
|
|
3130
|
+
project_name TEXT,
|
|
3131
|
+
timestamp TEXT NOT NULL,
|
|
3132
|
+
card_type TEXT NOT NULL,
|
|
3133
|
+
subject TEXT,
|
|
3134
|
+
predicate TEXT,
|
|
3135
|
+
object TEXT,
|
|
3136
|
+
content TEXT NOT NULL,
|
|
3137
|
+
source_ref TEXT,
|
|
3138
|
+
confidence REAL DEFAULT 0.6,
|
|
3139
|
+
active INTEGER DEFAULT 1,
|
|
3140
|
+
created_at TEXT NOT NULL
|
|
3141
|
+
);
|
|
3142
|
+
|
|
3143
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cards_agent
|
|
3144
|
+
ON memory_cards(agent_id, active, timestamp);
|
|
3145
|
+
|
|
3146
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cards_memory
|
|
3147
|
+
ON memory_cards(memory_id);
|
|
3148
|
+
|
|
3149
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memory_cards_fts
|
|
3150
|
+
USING fts5(content, subject, predicate, object, content='memory_cards', content_rowid='rowid');
|
|
3151
|
+
|
|
3152
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ai AFTER INSERT ON memory_cards BEGIN
|
|
3153
|
+
INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
|
|
3154
|
+
VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
|
|
3155
|
+
END;
|
|
3156
|
+
|
|
3157
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ad AFTER DELETE ON memory_cards BEGIN
|
|
3158
|
+
INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
|
|
3159
|
+
VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
|
|
3160
|
+
END;
|
|
3161
|
+
|
|
3162
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_au AFTER UPDATE ON memory_cards BEGIN
|
|
3163
|
+
INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
|
|
3164
|
+
VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
|
|
3165
|
+
INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
|
|
3166
|
+
VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
|
|
3167
|
+
END;
|
|
3168
|
+
`);
|
|
3124
3169
|
try {
|
|
3125
3170
|
await client.execute({
|
|
3126
3171
|
sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
|
|
@@ -4410,6 +4455,164 @@ ${p.content}`).join("\n\n");
|
|
|
4410
4455
|
}
|
|
4411
4456
|
});
|
|
4412
4457
|
|
|
4458
|
+
// src/lib/memory-cards.ts
|
|
4459
|
+
var memory_cards_exports = {};
|
|
4460
|
+
__export(memory_cards_exports, {
|
|
4461
|
+
extractMemoryCards: () => extractMemoryCards,
|
|
4462
|
+
insertMemoryCardsForBatch: () => insertMemoryCardsForBatch,
|
|
4463
|
+
searchMemoryCards: () => searchMemoryCards
|
|
4464
|
+
});
|
|
4465
|
+
import { createHash as createHash2 } from "crypto";
|
|
4466
|
+
function stableId(memoryId, type, content) {
|
|
4467
|
+
return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
|
|
4468
|
+
}
|
|
4469
|
+
function cleanText(text) {
|
|
4470
|
+
return text.replace(/```[\s\S]*?```/g, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
4471
|
+
}
|
|
4472
|
+
function splitSentences(text) {
|
|
4473
|
+
return cleanText(text).split(/(?<=[.!?])\s+|\n+/).map((s) => s.trim()).filter((s) => s.length >= 24 && s.length <= MAX_SENTENCE_CHARS);
|
|
4474
|
+
}
|
|
4475
|
+
function inferCardType(sentence, toolName) {
|
|
4476
|
+
const lower = sentence.toLowerCase();
|
|
4477
|
+
if (toolName === "store_decision" || /\b(decided|decision|adr|approved|rejected)\b/.test(lower)) return "decision";
|
|
4478
|
+
if (/\b(prefers|preference|likes|dislikes|wants|doesn't want|does not want)\b/.test(lower)) return "preference";
|
|
4479
|
+
if (/\b(changed|updated|replaced|now|no longer|instead|supersedes)\b/.test(lower)) return "belief_update";
|
|
4480
|
+
if (toolName && ["Read", "Write", "Edit", "Bash"].includes(toolName)) return "code";
|
|
4481
|
+
if (/\b(meeting|deadline|shipped|launched|completed|failed|blocked|assigned|created)\b/.test(lower)) return "event";
|
|
4482
|
+
return "fact";
|
|
4483
|
+
}
|
|
4484
|
+
function extractSubject(sentence, agentId) {
|
|
4485
|
+
const explicit = sentence.match(/\b([A-Z][a-zA-Z0-9_-]{2,}(?:\s+[A-Z][a-zA-Z0-9_-]{2,})?)\b/);
|
|
4486
|
+
return explicit?.[1] ?? agentId;
|
|
4487
|
+
}
|
|
4488
|
+
function predicateFor(type) {
|
|
4489
|
+
switch (type) {
|
|
4490
|
+
case "preference":
|
|
4491
|
+
return "prefers";
|
|
4492
|
+
case "belief_update":
|
|
4493
|
+
return "updated";
|
|
4494
|
+
case "decision":
|
|
4495
|
+
return "decided";
|
|
4496
|
+
case "event":
|
|
4497
|
+
return "happened";
|
|
4498
|
+
case "code":
|
|
4499
|
+
return "implemented";
|
|
4500
|
+
default:
|
|
4501
|
+
return "states";
|
|
4502
|
+
}
|
|
4503
|
+
}
|
|
4504
|
+
function extractMemoryCards(row) {
|
|
4505
|
+
const sentences = splitSentences(row.raw_text);
|
|
4506
|
+
const cards = [];
|
|
4507
|
+
for (const sentence of sentences) {
|
|
4508
|
+
const type = inferCardType(sentence, row.tool_name);
|
|
4509
|
+
const subject = extractSubject(sentence, row.agent_id);
|
|
4510
|
+
const content = sentence.length > MAX_SENTENCE_CHARS ? `${sentence.slice(0, MAX_SENTENCE_CHARS - 1)}\u2026` : sentence;
|
|
4511
|
+
cards.push({
|
|
4512
|
+
id: stableId(row.id, type, content),
|
|
4513
|
+
memory_id: row.id,
|
|
4514
|
+
agent_id: row.agent_id,
|
|
4515
|
+
session_id: row.session_id,
|
|
4516
|
+
project_name: row.project_name ?? null,
|
|
4517
|
+
timestamp: row.timestamp,
|
|
4518
|
+
card_type: type,
|
|
4519
|
+
subject,
|
|
4520
|
+
predicate: predicateFor(type),
|
|
4521
|
+
object: content,
|
|
4522
|
+
content,
|
|
4523
|
+
source_ref: row.id,
|
|
4524
|
+
confidence: type === "fact" ? 0.55 : 0.65
|
|
4525
|
+
});
|
|
4526
|
+
if (cards.length >= MAX_CARDS_PER_MEMORY) break;
|
|
4527
|
+
}
|
|
4528
|
+
return cards;
|
|
4529
|
+
}
|
|
4530
|
+
async function insertMemoryCardsForBatch(rows) {
|
|
4531
|
+
const cards = rows.flatMap(extractMemoryCards);
|
|
4532
|
+
if (cards.length === 0) return 0;
|
|
4533
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4534
|
+
const client = getClient();
|
|
4535
|
+
const stmts = cards.map((card) => ({
|
|
4536
|
+
sql: `INSERT OR IGNORE INTO memory_cards
|
|
4537
|
+
(id, memory_id, agent_id, session_id, project_name, timestamp, card_type,
|
|
4538
|
+
subject, predicate, object, content, source_ref, confidence, active, created_at)
|
|
4539
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)`,
|
|
4540
|
+
args: [
|
|
4541
|
+
card.id,
|
|
4542
|
+
card.memory_id,
|
|
4543
|
+
card.agent_id,
|
|
4544
|
+
card.session_id,
|
|
4545
|
+
card.project_name,
|
|
4546
|
+
card.timestamp,
|
|
4547
|
+
card.card_type,
|
|
4548
|
+
card.subject,
|
|
4549
|
+
card.predicate,
|
|
4550
|
+
card.object,
|
|
4551
|
+
card.content,
|
|
4552
|
+
card.source_ref,
|
|
4553
|
+
card.confidence,
|
|
4554
|
+
now
|
|
4555
|
+
]
|
|
4556
|
+
}));
|
|
4557
|
+
await client.batch(stmts, "write");
|
|
4558
|
+
return cards.length;
|
|
4559
|
+
}
|
|
4560
|
+
function buildMatchExpr(queryText) {
|
|
4561
|
+
const terms = queryText.toLowerCase().split(/\s+/).filter((t) => t.length >= 3).map((t) => t.replace(/[^a-z0-9_]/g, "")).filter((t) => t.length >= 3).slice(0, 12);
|
|
4562
|
+
if (terms.length === 0) return null;
|
|
4563
|
+
return terms.map((t) => `${t}*`).join(terms.length >= 3 ? " AND " : " OR ");
|
|
4564
|
+
}
|
|
4565
|
+
async function searchMemoryCards(queryText, agentId, options) {
|
|
4566
|
+
const limit = options?.limit ?? 10;
|
|
4567
|
+
const matchExpr = buildMatchExpr(queryText);
|
|
4568
|
+
if (!matchExpr) return [];
|
|
4569
|
+
let sql = `SELECT c.id, c.memory_id, c.agent_id, c.session_id, c.project_name,
|
|
4570
|
+
c.timestamp, c.card_type, c.content, c.source_ref, c.confidence
|
|
4571
|
+
FROM memory_cards c
|
|
4572
|
+
JOIN memory_cards_fts fts ON c.rowid = fts.rowid
|
|
4573
|
+
WHERE memory_cards_fts MATCH ?
|
|
4574
|
+
AND c.agent_id = ?
|
|
4575
|
+
AND COALESCE(c.active, 1) = 1`;
|
|
4576
|
+
const args = [matchExpr, agentId];
|
|
4577
|
+
if (options?.projectName) {
|
|
4578
|
+
sql += ` AND c.project_name = ?`;
|
|
4579
|
+
args.push(options.projectName);
|
|
4580
|
+
}
|
|
4581
|
+
if (options?.since) {
|
|
4582
|
+
sql += ` AND c.timestamp >= ?`;
|
|
4583
|
+
args.push(options.since);
|
|
4584
|
+
}
|
|
4585
|
+
sql += ` ORDER BY rank LIMIT ?`;
|
|
4586
|
+
args.push(limit);
|
|
4587
|
+
const result = await getClient().execute({ sql, args });
|
|
4588
|
+
return result.rows.map((row) => ({
|
|
4589
|
+
id: `card:${String(row.id)}`,
|
|
4590
|
+
agent_id: String(row.agent_id),
|
|
4591
|
+
agent_role: "memory_card",
|
|
4592
|
+
session_id: String(row.session_id),
|
|
4593
|
+
timestamp: String(row.timestamp),
|
|
4594
|
+
tool_name: `memory_card:${String(row.card_type)}`,
|
|
4595
|
+
project_name: row.project_name == null ? "" : String(row.project_name),
|
|
4596
|
+
has_error: false,
|
|
4597
|
+
raw_text: `[${String(row.card_type)}] ${String(row.content)}
|
|
4598
|
+
Source memory: ${String(row.source_ref ?? row.memory_id)}`,
|
|
4599
|
+
vector: [],
|
|
4600
|
+
importance: 6,
|
|
4601
|
+
status: "active",
|
|
4602
|
+
confidence: Number(row.confidence ?? 0.6),
|
|
4603
|
+
last_accessed: String(row.timestamp)
|
|
4604
|
+
}));
|
|
4605
|
+
}
|
|
4606
|
+
var MAX_CARDS_PER_MEMORY, MAX_SENTENCE_CHARS;
|
|
4607
|
+
var init_memory_cards = __esm({
|
|
4608
|
+
"src/lib/memory-cards.ts"() {
|
|
4609
|
+
"use strict";
|
|
4610
|
+
init_database();
|
|
4611
|
+
MAX_CARDS_PER_MEMORY = 6;
|
|
4612
|
+
MAX_SENTENCE_CHARS = 360;
|
|
4613
|
+
}
|
|
4614
|
+
});
|
|
4615
|
+
|
|
4413
4616
|
// src/lib/store.ts
|
|
4414
4617
|
var store_exports = {};
|
|
4415
4618
|
__export(store_exports, {
|
|
@@ -4748,6 +4951,11 @@ async function flushBatch() {
|
|
|
4748
4951
|
const globalClient = getClient();
|
|
4749
4952
|
const globalStmts = batch.map(buildStmt);
|
|
4750
4953
|
await globalClient.batch(globalStmts, "write");
|
|
4954
|
+
try {
|
|
4955
|
+
const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
|
|
4956
|
+
await insertMemoryCardsForBatch2(batch);
|
|
4957
|
+
} catch {
|
|
4958
|
+
}
|
|
4751
4959
|
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
4752
4960
|
_pendingRecords.splice(0, batch.length);
|
|
4753
4961
|
try {
|
|
@@ -6256,9 +6464,18 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
6256
6464
|
} catch {
|
|
6257
6465
|
}
|
|
6258
6466
|
}
|
|
6259
|
-
const
|
|
6467
|
+
const includeStructuredCards = effectiveIsBroad || effectiveOptions.includeStructuredCards === true;
|
|
6468
|
+
const [ftsResults, vectorResults, cardResults, grepResults] = await Promise.all([
|
|
6260
6469
|
lightweightSearch(effectiveQuery, agentId, fetchOptions),
|
|
6261
6470
|
queryVector ? searchMemories(queryVector, agentId, fetchOptions) : Promise.resolve([]),
|
|
6471
|
+
includeStructuredCards ? (async () => {
|
|
6472
|
+
try {
|
|
6473
|
+
const { searchMemoryCards: searchMemoryCards2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
|
|
6474
|
+
return await searchMemoryCards2(effectiveQuery, agentId, fetchOptions);
|
|
6475
|
+
} catch {
|
|
6476
|
+
return [];
|
|
6477
|
+
}
|
|
6478
|
+
})() : Promise.resolve([]),
|
|
6262
6479
|
grepPromise
|
|
6263
6480
|
]);
|
|
6264
6481
|
const lists = [];
|
|
@@ -6271,6 +6488,10 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
6271
6488
|
lists.push(vectorResults);
|
|
6272
6489
|
weights.push(1);
|
|
6273
6490
|
}
|
|
6491
|
+
if (cardResults.length > 0) {
|
|
6492
|
+
lists.push(cardResults);
|
|
6493
|
+
weights.push(1.2);
|
|
6494
|
+
}
|
|
6274
6495
|
if (grepResults.length > 0) {
|
|
6275
6496
|
lists.push(grepResults);
|
|
6276
6497
|
weights.push(0.5);
|
|
@@ -6339,6 +6560,7 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
6339
6560
|
signals: {
|
|
6340
6561
|
fts: ftsResults.length,
|
|
6341
6562
|
vector: vectorResults.length,
|
|
6563
|
+
cards: cardResults.length,
|
|
6342
6564
|
grep: grepResults.length,
|
|
6343
6565
|
entityBoost: entityBoostRan,
|
|
6344
6566
|
reranker: rerankedAndBlended !== null,
|
|
@@ -6488,6 +6710,15 @@ async function lightweightSearch(queryText, agentId, options) {
|
|
|
6488
6710
|
if (options?.includeSource && results.length > 0) {
|
|
6489
6711
|
await attachDocumentMetadata(results);
|
|
6490
6712
|
}
|
|
6713
|
+
if (options?.includeStructuredCards !== true) return results;
|
|
6714
|
+
try {
|
|
6715
|
+
const { searchMemoryCards: searchMemoryCards2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
|
|
6716
|
+
const cardResults = await searchMemoryCards2(queryText, agentId, options);
|
|
6717
|
+
if (cardResults.length > 0) {
|
|
6718
|
+
return rrfMergeMulti([results, cardResults], limit, RRF_K, [1, 1.2]);
|
|
6719
|
+
}
|
|
6720
|
+
} catch {
|
|
6721
|
+
}
|
|
6491
6722
|
return results;
|
|
6492
6723
|
}
|
|
6493
6724
|
async function ftsQuery(client, matchExpr, agentId, options, limit) {
|
|
@@ -7696,7 +7927,7 @@ __export(identity_exports, {
|
|
|
7696
7927
|
import { existsSync as existsSync16, mkdirSync as mkdirSync8, readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "fs";
|
|
7697
7928
|
import { readdirSync as readdirSync5 } from "fs";
|
|
7698
7929
|
import path20 from "path";
|
|
7699
|
-
import { createHash as
|
|
7930
|
+
import { createHash as createHash3 } from "crypto";
|
|
7700
7931
|
function ensureDir() {
|
|
7701
7932
|
if (!existsSync16(IDENTITY_DIR2)) {
|
|
7702
7933
|
mkdirSync8(IDENTITY_DIR2, { recursive: true });
|
|
@@ -7743,7 +7974,7 @@ function parseFrontmatter(raw) {
|
|
|
7743
7974
|
};
|
|
7744
7975
|
}
|
|
7745
7976
|
function contentHash(content) {
|
|
7746
|
-
return
|
|
7977
|
+
return createHash3("sha256").update(content).digest("hex").slice(0, 16);
|
|
7747
7978
|
}
|
|
7748
7979
|
function getIdentity(agentId) {
|
|
7749
7980
|
const filePath = identityPath(agentId);
|
package/dist/hooks/stop.js
CHANGED
|
@@ -221,8 +221,8 @@ var init_config = __esm({
|
|
|
221
221
|
rerankerAutoTrigger: {
|
|
222
222
|
enabled: true,
|
|
223
223
|
broadQueryMinCardinality: 5e4,
|
|
224
|
-
fetchTopK:
|
|
225
|
-
returnTopK:
|
|
224
|
+
fetchTopK: 200,
|
|
225
|
+
returnTopK: 20
|
|
226
226
|
}
|
|
227
227
|
},
|
|
228
228
|
graphRagEnabled: true,
|
|
@@ -3044,6 +3044,51 @@ async function ensureSchema() {
|
|
|
3044
3044
|
VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
|
|
3045
3045
|
END;
|
|
3046
3046
|
`);
|
|
3047
|
+
await client.executeMultiple(`
|
|
3048
|
+
CREATE TABLE IF NOT EXISTS memory_cards (
|
|
3049
|
+
id TEXT PRIMARY KEY,
|
|
3050
|
+
memory_id TEXT NOT NULL,
|
|
3051
|
+
agent_id TEXT NOT NULL,
|
|
3052
|
+
session_id TEXT NOT NULL,
|
|
3053
|
+
project_name TEXT,
|
|
3054
|
+
timestamp TEXT NOT NULL,
|
|
3055
|
+
card_type TEXT NOT NULL,
|
|
3056
|
+
subject TEXT,
|
|
3057
|
+
predicate TEXT,
|
|
3058
|
+
object TEXT,
|
|
3059
|
+
content TEXT NOT NULL,
|
|
3060
|
+
source_ref TEXT,
|
|
3061
|
+
confidence REAL DEFAULT 0.6,
|
|
3062
|
+
active INTEGER DEFAULT 1,
|
|
3063
|
+
created_at TEXT NOT NULL
|
|
3064
|
+
);
|
|
3065
|
+
|
|
3066
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cards_agent
|
|
3067
|
+
ON memory_cards(agent_id, active, timestamp);
|
|
3068
|
+
|
|
3069
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cards_memory
|
|
3070
|
+
ON memory_cards(memory_id);
|
|
3071
|
+
|
|
3072
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memory_cards_fts
|
|
3073
|
+
USING fts5(content, subject, predicate, object, content='memory_cards', content_rowid='rowid');
|
|
3074
|
+
|
|
3075
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ai AFTER INSERT ON memory_cards BEGIN
|
|
3076
|
+
INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
|
|
3077
|
+
VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
|
|
3078
|
+
END;
|
|
3079
|
+
|
|
3080
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ad AFTER DELETE ON memory_cards BEGIN
|
|
3081
|
+
INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
|
|
3082
|
+
VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
|
|
3083
|
+
END;
|
|
3084
|
+
|
|
3085
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_au AFTER UPDATE ON memory_cards BEGIN
|
|
3086
|
+
INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
|
|
3087
|
+
VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
|
|
3088
|
+
INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
|
|
3089
|
+
VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
|
|
3090
|
+
END;
|
|
3091
|
+
`);
|
|
3047
3092
|
try {
|
|
3048
3093
|
await client.execute({
|
|
3049
3094
|
sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
|
|
@@ -4476,6 +4521,164 @@ ${p.content}`).join("\n\n");
|
|
|
4476
4521
|
}
|
|
4477
4522
|
});
|
|
4478
4523
|
|
|
4524
|
+
// src/lib/memory-cards.ts
|
|
4525
|
+
var memory_cards_exports = {};
|
|
4526
|
+
__export(memory_cards_exports, {
|
|
4527
|
+
extractMemoryCards: () => extractMemoryCards,
|
|
4528
|
+
insertMemoryCardsForBatch: () => insertMemoryCardsForBatch,
|
|
4529
|
+
searchMemoryCards: () => searchMemoryCards
|
|
4530
|
+
});
|
|
4531
|
+
import { createHash as createHash2 } from "crypto";
|
|
4532
|
+
function stableId(memoryId, type, content) {
|
|
4533
|
+
return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
|
|
4534
|
+
}
|
|
4535
|
+
function cleanText(text) {
|
|
4536
|
+
return text.replace(/```[\s\S]*?```/g, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
4537
|
+
}
|
|
4538
|
+
function splitSentences(text) {
|
|
4539
|
+
return cleanText(text).split(/(?<=[.!?])\s+|\n+/).map((s) => s.trim()).filter((s) => s.length >= 24 && s.length <= MAX_SENTENCE_CHARS);
|
|
4540
|
+
}
|
|
4541
|
+
function inferCardType(sentence, toolName) {
|
|
4542
|
+
const lower = sentence.toLowerCase();
|
|
4543
|
+
if (toolName === "store_decision" || /\b(decided|decision|adr|approved|rejected)\b/.test(lower)) return "decision";
|
|
4544
|
+
if (/\b(prefers|preference|likes|dislikes|wants|doesn't want|does not want)\b/.test(lower)) return "preference";
|
|
4545
|
+
if (/\b(changed|updated|replaced|now|no longer|instead|supersedes)\b/.test(lower)) return "belief_update";
|
|
4546
|
+
if (toolName && ["Read", "Write", "Edit", "Bash"].includes(toolName)) return "code";
|
|
4547
|
+
if (/\b(meeting|deadline|shipped|launched|completed|failed|blocked|assigned|created)\b/.test(lower)) return "event";
|
|
4548
|
+
return "fact";
|
|
4549
|
+
}
|
|
4550
|
+
function extractSubject(sentence, agentId) {
|
|
4551
|
+
const explicit = sentence.match(/\b([A-Z][a-zA-Z0-9_-]{2,}(?:\s+[A-Z][a-zA-Z0-9_-]{2,})?)\b/);
|
|
4552
|
+
return explicit?.[1] ?? agentId;
|
|
4553
|
+
}
|
|
4554
|
+
function predicateFor(type) {
|
|
4555
|
+
switch (type) {
|
|
4556
|
+
case "preference":
|
|
4557
|
+
return "prefers";
|
|
4558
|
+
case "belief_update":
|
|
4559
|
+
return "updated";
|
|
4560
|
+
case "decision":
|
|
4561
|
+
return "decided";
|
|
4562
|
+
case "event":
|
|
4563
|
+
return "happened";
|
|
4564
|
+
case "code":
|
|
4565
|
+
return "implemented";
|
|
4566
|
+
default:
|
|
4567
|
+
return "states";
|
|
4568
|
+
}
|
|
4569
|
+
}
|
|
4570
|
+
function extractMemoryCards(row) {
|
|
4571
|
+
const sentences = splitSentences(row.raw_text);
|
|
4572
|
+
const cards = [];
|
|
4573
|
+
for (const sentence of sentences) {
|
|
4574
|
+
const type = inferCardType(sentence, row.tool_name);
|
|
4575
|
+
const subject = extractSubject(sentence, row.agent_id);
|
|
4576
|
+
const content = sentence.length > MAX_SENTENCE_CHARS ? `${sentence.slice(0, MAX_SENTENCE_CHARS - 1)}\u2026` : sentence;
|
|
4577
|
+
cards.push({
|
|
4578
|
+
id: stableId(row.id, type, content),
|
|
4579
|
+
memory_id: row.id,
|
|
4580
|
+
agent_id: row.agent_id,
|
|
4581
|
+
session_id: row.session_id,
|
|
4582
|
+
project_name: row.project_name ?? null,
|
|
4583
|
+
timestamp: row.timestamp,
|
|
4584
|
+
card_type: type,
|
|
4585
|
+
subject,
|
|
4586
|
+
predicate: predicateFor(type),
|
|
4587
|
+
object: content,
|
|
4588
|
+
content,
|
|
4589
|
+
source_ref: row.id,
|
|
4590
|
+
confidence: type === "fact" ? 0.55 : 0.65
|
|
4591
|
+
});
|
|
4592
|
+
if (cards.length >= MAX_CARDS_PER_MEMORY) break;
|
|
4593
|
+
}
|
|
4594
|
+
return cards;
|
|
4595
|
+
}
|
|
4596
|
+
async function insertMemoryCardsForBatch(rows) {
|
|
4597
|
+
const cards = rows.flatMap(extractMemoryCards);
|
|
4598
|
+
if (cards.length === 0) return 0;
|
|
4599
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4600
|
+
const client = getClient();
|
|
4601
|
+
const stmts = cards.map((card) => ({
|
|
4602
|
+
sql: `INSERT OR IGNORE INTO memory_cards
|
|
4603
|
+
(id, memory_id, agent_id, session_id, project_name, timestamp, card_type,
|
|
4604
|
+
subject, predicate, object, content, source_ref, confidence, active, created_at)
|
|
4605
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)`,
|
|
4606
|
+
args: [
|
|
4607
|
+
card.id,
|
|
4608
|
+
card.memory_id,
|
|
4609
|
+
card.agent_id,
|
|
4610
|
+
card.session_id,
|
|
4611
|
+
card.project_name,
|
|
4612
|
+
card.timestamp,
|
|
4613
|
+
card.card_type,
|
|
4614
|
+
card.subject,
|
|
4615
|
+
card.predicate,
|
|
4616
|
+
card.object,
|
|
4617
|
+
card.content,
|
|
4618
|
+
card.source_ref,
|
|
4619
|
+
card.confidence,
|
|
4620
|
+
now
|
|
4621
|
+
]
|
|
4622
|
+
}));
|
|
4623
|
+
await client.batch(stmts, "write");
|
|
4624
|
+
return cards.length;
|
|
4625
|
+
}
|
|
4626
|
+
function buildMatchExpr(queryText) {
|
|
4627
|
+
const terms = queryText.toLowerCase().split(/\s+/).filter((t) => t.length >= 3).map((t) => t.replace(/[^a-z0-9_]/g, "")).filter((t) => t.length >= 3).slice(0, 12);
|
|
4628
|
+
if (terms.length === 0) return null;
|
|
4629
|
+
return terms.map((t) => `${t}*`).join(terms.length >= 3 ? " AND " : " OR ");
|
|
4630
|
+
}
|
|
4631
|
+
async function searchMemoryCards(queryText, agentId, options) {
|
|
4632
|
+
const limit = options?.limit ?? 10;
|
|
4633
|
+
const matchExpr = buildMatchExpr(queryText);
|
|
4634
|
+
if (!matchExpr) return [];
|
|
4635
|
+
let sql = `SELECT c.id, c.memory_id, c.agent_id, c.session_id, c.project_name,
|
|
4636
|
+
c.timestamp, c.card_type, c.content, c.source_ref, c.confidence
|
|
4637
|
+
FROM memory_cards c
|
|
4638
|
+
JOIN memory_cards_fts fts ON c.rowid = fts.rowid
|
|
4639
|
+
WHERE memory_cards_fts MATCH ?
|
|
4640
|
+
AND c.agent_id = ?
|
|
4641
|
+
AND COALESCE(c.active, 1) = 1`;
|
|
4642
|
+
const args = [matchExpr, agentId];
|
|
4643
|
+
if (options?.projectName) {
|
|
4644
|
+
sql += ` AND c.project_name = ?`;
|
|
4645
|
+
args.push(options.projectName);
|
|
4646
|
+
}
|
|
4647
|
+
if (options?.since) {
|
|
4648
|
+
sql += ` AND c.timestamp >= ?`;
|
|
4649
|
+
args.push(options.since);
|
|
4650
|
+
}
|
|
4651
|
+
sql += ` ORDER BY rank LIMIT ?`;
|
|
4652
|
+
args.push(limit);
|
|
4653
|
+
const result = await getClient().execute({ sql, args });
|
|
4654
|
+
return result.rows.map((row) => ({
|
|
4655
|
+
id: `card:${String(row.id)}`,
|
|
4656
|
+
agent_id: String(row.agent_id),
|
|
4657
|
+
agent_role: "memory_card",
|
|
4658
|
+
session_id: String(row.session_id),
|
|
4659
|
+
timestamp: String(row.timestamp),
|
|
4660
|
+
tool_name: `memory_card:${String(row.card_type)}`,
|
|
4661
|
+
project_name: row.project_name == null ? "" : String(row.project_name),
|
|
4662
|
+
has_error: false,
|
|
4663
|
+
raw_text: `[${String(row.card_type)}] ${String(row.content)}
|
|
4664
|
+
Source memory: ${String(row.source_ref ?? row.memory_id)}`,
|
|
4665
|
+
vector: [],
|
|
4666
|
+
importance: 6,
|
|
4667
|
+
status: "active",
|
|
4668
|
+
confidence: Number(row.confidence ?? 0.6),
|
|
4669
|
+
last_accessed: String(row.timestamp)
|
|
4670
|
+
}));
|
|
4671
|
+
}
|
|
4672
|
+
var MAX_CARDS_PER_MEMORY, MAX_SENTENCE_CHARS;
|
|
4673
|
+
var init_memory_cards = __esm({
|
|
4674
|
+
"src/lib/memory-cards.ts"() {
|
|
4675
|
+
"use strict";
|
|
4676
|
+
init_database();
|
|
4677
|
+
MAX_CARDS_PER_MEMORY = 6;
|
|
4678
|
+
MAX_SENTENCE_CHARS = 360;
|
|
4679
|
+
}
|
|
4680
|
+
});
|
|
4681
|
+
|
|
4479
4682
|
// src/lib/store.ts
|
|
4480
4683
|
var store_exports = {};
|
|
4481
4684
|
__export(store_exports, {
|
|
@@ -4814,6 +5017,11 @@ async function flushBatch() {
|
|
|
4814
5017
|
const globalClient = getClient();
|
|
4815
5018
|
const globalStmts = batch.map(buildStmt);
|
|
4816
5019
|
await globalClient.batch(globalStmts, "write");
|
|
5020
|
+
try {
|
|
5021
|
+
const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
|
|
5022
|
+
await insertMemoryCardsForBatch2(batch);
|
|
5023
|
+
} catch {
|
|
5024
|
+
}
|
|
4817
5025
|
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
4818
5026
|
_pendingRecords.splice(0, batch.length);
|
|
4819
5027
|
try {
|