@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
|
@@ -313,8 +313,8 @@ var init_config = __esm({
|
|
|
313
313
|
rerankerAutoTrigger: {
|
|
314
314
|
enabled: true,
|
|
315
315
|
broadQueryMinCardinality: 5e4,
|
|
316
|
-
fetchTopK:
|
|
317
|
-
returnTopK:
|
|
316
|
+
fetchTopK: 200,
|
|
317
|
+
returnTopK: 20
|
|
318
318
|
}
|
|
319
319
|
},
|
|
320
320
|
graphRagEnabled: true,
|
|
@@ -2820,6 +2820,51 @@ async function ensureSchema() {
|
|
|
2820
2820
|
VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
|
|
2821
2821
|
END;
|
|
2822
2822
|
`);
|
|
2823
|
+
await client.executeMultiple(`
|
|
2824
|
+
CREATE TABLE IF NOT EXISTS memory_cards (
|
|
2825
|
+
id TEXT PRIMARY KEY,
|
|
2826
|
+
memory_id TEXT NOT NULL,
|
|
2827
|
+
agent_id TEXT NOT NULL,
|
|
2828
|
+
session_id TEXT NOT NULL,
|
|
2829
|
+
project_name TEXT,
|
|
2830
|
+
timestamp TEXT NOT NULL,
|
|
2831
|
+
card_type TEXT NOT NULL,
|
|
2832
|
+
subject TEXT,
|
|
2833
|
+
predicate TEXT,
|
|
2834
|
+
object TEXT,
|
|
2835
|
+
content TEXT NOT NULL,
|
|
2836
|
+
source_ref TEXT,
|
|
2837
|
+
confidence REAL DEFAULT 0.6,
|
|
2838
|
+
active INTEGER DEFAULT 1,
|
|
2839
|
+
created_at TEXT NOT NULL
|
|
2840
|
+
);
|
|
2841
|
+
|
|
2842
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cards_agent
|
|
2843
|
+
ON memory_cards(agent_id, active, timestamp);
|
|
2844
|
+
|
|
2845
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cards_memory
|
|
2846
|
+
ON memory_cards(memory_id);
|
|
2847
|
+
|
|
2848
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memory_cards_fts
|
|
2849
|
+
USING fts5(content, subject, predicate, object, content='memory_cards', content_rowid='rowid');
|
|
2850
|
+
|
|
2851
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ai AFTER INSERT ON memory_cards BEGIN
|
|
2852
|
+
INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
|
|
2853
|
+
VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
|
|
2854
|
+
END;
|
|
2855
|
+
|
|
2856
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ad AFTER DELETE ON memory_cards BEGIN
|
|
2857
|
+
INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
|
|
2858
|
+
VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
|
|
2859
|
+
END;
|
|
2860
|
+
|
|
2861
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_au AFTER UPDATE ON memory_cards BEGIN
|
|
2862
|
+
INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
|
|
2863
|
+
VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
|
|
2864
|
+
INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
|
|
2865
|
+
VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
|
|
2866
|
+
END;
|
|
2867
|
+
`);
|
|
2823
2868
|
try {
|
|
2824
2869
|
await client.execute({
|
|
2825
2870
|
sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
|
|
@@ -4109,6 +4154,164 @@ ${p.content}`).join("\n\n");
|
|
|
4109
4154
|
}
|
|
4110
4155
|
});
|
|
4111
4156
|
|
|
4157
|
+
// src/lib/memory-cards.ts
|
|
4158
|
+
var memory_cards_exports = {};
|
|
4159
|
+
__export(memory_cards_exports, {
|
|
4160
|
+
extractMemoryCards: () => extractMemoryCards,
|
|
4161
|
+
insertMemoryCardsForBatch: () => insertMemoryCardsForBatch,
|
|
4162
|
+
searchMemoryCards: () => searchMemoryCards
|
|
4163
|
+
});
|
|
4164
|
+
import { createHash as createHash2 } from "crypto";
|
|
4165
|
+
function stableId(memoryId, type, content) {
|
|
4166
|
+
return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
|
|
4167
|
+
}
|
|
4168
|
+
function cleanText(text) {
|
|
4169
|
+
return text.replace(/```[\s\S]*?```/g, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
4170
|
+
}
|
|
4171
|
+
function splitSentences(text) {
|
|
4172
|
+
return cleanText(text).split(/(?<=[.!?])\s+|\n+/).map((s) => s.trim()).filter((s) => s.length >= 24 && s.length <= MAX_SENTENCE_CHARS);
|
|
4173
|
+
}
|
|
4174
|
+
function inferCardType(sentence, toolName) {
|
|
4175
|
+
const lower = sentence.toLowerCase();
|
|
4176
|
+
if (toolName === "store_decision" || /\b(decided|decision|adr|approved|rejected)\b/.test(lower)) return "decision";
|
|
4177
|
+
if (/\b(prefers|preference|likes|dislikes|wants|doesn't want|does not want)\b/.test(lower)) return "preference";
|
|
4178
|
+
if (/\b(changed|updated|replaced|now|no longer|instead|supersedes)\b/.test(lower)) return "belief_update";
|
|
4179
|
+
if (toolName && ["Read", "Write", "Edit", "Bash"].includes(toolName)) return "code";
|
|
4180
|
+
if (/\b(meeting|deadline|shipped|launched|completed|failed|blocked|assigned|created)\b/.test(lower)) return "event";
|
|
4181
|
+
return "fact";
|
|
4182
|
+
}
|
|
4183
|
+
function extractSubject(sentence, agentId) {
|
|
4184
|
+
const explicit = sentence.match(/\b([A-Z][a-zA-Z0-9_-]{2,}(?:\s+[A-Z][a-zA-Z0-9_-]{2,})?)\b/);
|
|
4185
|
+
return explicit?.[1] ?? agentId;
|
|
4186
|
+
}
|
|
4187
|
+
function predicateFor(type) {
|
|
4188
|
+
switch (type) {
|
|
4189
|
+
case "preference":
|
|
4190
|
+
return "prefers";
|
|
4191
|
+
case "belief_update":
|
|
4192
|
+
return "updated";
|
|
4193
|
+
case "decision":
|
|
4194
|
+
return "decided";
|
|
4195
|
+
case "event":
|
|
4196
|
+
return "happened";
|
|
4197
|
+
case "code":
|
|
4198
|
+
return "implemented";
|
|
4199
|
+
default:
|
|
4200
|
+
return "states";
|
|
4201
|
+
}
|
|
4202
|
+
}
|
|
4203
|
+
function extractMemoryCards(row) {
|
|
4204
|
+
const sentences = splitSentences(row.raw_text);
|
|
4205
|
+
const cards = [];
|
|
4206
|
+
for (const sentence of sentences) {
|
|
4207
|
+
const type = inferCardType(sentence, row.tool_name);
|
|
4208
|
+
const subject = extractSubject(sentence, row.agent_id);
|
|
4209
|
+
const content = sentence.length > MAX_SENTENCE_CHARS ? `${sentence.slice(0, MAX_SENTENCE_CHARS - 1)}\u2026` : sentence;
|
|
4210
|
+
cards.push({
|
|
4211
|
+
id: stableId(row.id, type, content),
|
|
4212
|
+
memory_id: row.id,
|
|
4213
|
+
agent_id: row.agent_id,
|
|
4214
|
+
session_id: row.session_id,
|
|
4215
|
+
project_name: row.project_name ?? null,
|
|
4216
|
+
timestamp: row.timestamp,
|
|
4217
|
+
card_type: type,
|
|
4218
|
+
subject,
|
|
4219
|
+
predicate: predicateFor(type),
|
|
4220
|
+
object: content,
|
|
4221
|
+
content,
|
|
4222
|
+
source_ref: row.id,
|
|
4223
|
+
confidence: type === "fact" ? 0.55 : 0.65
|
|
4224
|
+
});
|
|
4225
|
+
if (cards.length >= MAX_CARDS_PER_MEMORY) break;
|
|
4226
|
+
}
|
|
4227
|
+
return cards;
|
|
4228
|
+
}
|
|
4229
|
+
async function insertMemoryCardsForBatch(rows) {
|
|
4230
|
+
const cards = rows.flatMap(extractMemoryCards);
|
|
4231
|
+
if (cards.length === 0) return 0;
|
|
4232
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4233
|
+
const client = getClient();
|
|
4234
|
+
const stmts = cards.map((card) => ({
|
|
4235
|
+
sql: `INSERT OR IGNORE INTO memory_cards
|
|
4236
|
+
(id, memory_id, agent_id, session_id, project_name, timestamp, card_type,
|
|
4237
|
+
subject, predicate, object, content, source_ref, confidence, active, created_at)
|
|
4238
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)`,
|
|
4239
|
+
args: [
|
|
4240
|
+
card.id,
|
|
4241
|
+
card.memory_id,
|
|
4242
|
+
card.agent_id,
|
|
4243
|
+
card.session_id,
|
|
4244
|
+
card.project_name,
|
|
4245
|
+
card.timestamp,
|
|
4246
|
+
card.card_type,
|
|
4247
|
+
card.subject,
|
|
4248
|
+
card.predicate,
|
|
4249
|
+
card.object,
|
|
4250
|
+
card.content,
|
|
4251
|
+
card.source_ref,
|
|
4252
|
+
card.confidence,
|
|
4253
|
+
now
|
|
4254
|
+
]
|
|
4255
|
+
}));
|
|
4256
|
+
await client.batch(stmts, "write");
|
|
4257
|
+
return cards.length;
|
|
4258
|
+
}
|
|
4259
|
+
function buildMatchExpr(queryText) {
|
|
4260
|
+
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);
|
|
4261
|
+
if (terms.length === 0) return null;
|
|
4262
|
+
return terms.map((t) => `${t}*`).join(terms.length >= 3 ? " AND " : " OR ");
|
|
4263
|
+
}
|
|
4264
|
+
async function searchMemoryCards(queryText, agentId, options) {
|
|
4265
|
+
const limit = options?.limit ?? 10;
|
|
4266
|
+
const matchExpr = buildMatchExpr(queryText);
|
|
4267
|
+
if (!matchExpr) return [];
|
|
4268
|
+
let sql = `SELECT c.id, c.memory_id, c.agent_id, c.session_id, c.project_name,
|
|
4269
|
+
c.timestamp, c.card_type, c.content, c.source_ref, c.confidence
|
|
4270
|
+
FROM memory_cards c
|
|
4271
|
+
JOIN memory_cards_fts fts ON c.rowid = fts.rowid
|
|
4272
|
+
WHERE memory_cards_fts MATCH ?
|
|
4273
|
+
AND c.agent_id = ?
|
|
4274
|
+
AND COALESCE(c.active, 1) = 1`;
|
|
4275
|
+
const args = [matchExpr, agentId];
|
|
4276
|
+
if (options?.projectName) {
|
|
4277
|
+
sql += ` AND c.project_name = ?`;
|
|
4278
|
+
args.push(options.projectName);
|
|
4279
|
+
}
|
|
4280
|
+
if (options?.since) {
|
|
4281
|
+
sql += ` AND c.timestamp >= ?`;
|
|
4282
|
+
args.push(options.since);
|
|
4283
|
+
}
|
|
4284
|
+
sql += ` ORDER BY rank LIMIT ?`;
|
|
4285
|
+
args.push(limit);
|
|
4286
|
+
const result = await getClient().execute({ sql, args });
|
|
4287
|
+
return result.rows.map((row) => ({
|
|
4288
|
+
id: `card:${String(row.id)}`,
|
|
4289
|
+
agent_id: String(row.agent_id),
|
|
4290
|
+
agent_role: "memory_card",
|
|
4291
|
+
session_id: String(row.session_id),
|
|
4292
|
+
timestamp: String(row.timestamp),
|
|
4293
|
+
tool_name: `memory_card:${String(row.card_type)}`,
|
|
4294
|
+
project_name: row.project_name == null ? "" : String(row.project_name),
|
|
4295
|
+
has_error: false,
|
|
4296
|
+
raw_text: `[${String(row.card_type)}] ${String(row.content)}
|
|
4297
|
+
Source memory: ${String(row.source_ref ?? row.memory_id)}`,
|
|
4298
|
+
vector: [],
|
|
4299
|
+
importance: 6,
|
|
4300
|
+
status: "active",
|
|
4301
|
+
confidence: Number(row.confidence ?? 0.6),
|
|
4302
|
+
last_accessed: String(row.timestamp)
|
|
4303
|
+
}));
|
|
4304
|
+
}
|
|
4305
|
+
var MAX_CARDS_PER_MEMORY, MAX_SENTENCE_CHARS;
|
|
4306
|
+
var init_memory_cards = __esm({
|
|
4307
|
+
"src/lib/memory-cards.ts"() {
|
|
4308
|
+
"use strict";
|
|
4309
|
+
init_database();
|
|
4310
|
+
MAX_CARDS_PER_MEMORY = 6;
|
|
4311
|
+
MAX_SENTENCE_CHARS = 360;
|
|
4312
|
+
}
|
|
4313
|
+
});
|
|
4314
|
+
|
|
4112
4315
|
// src/lib/store.ts
|
|
4113
4316
|
var store_exports = {};
|
|
4114
4317
|
__export(store_exports, {
|
|
@@ -4447,6 +4650,11 @@ async function flushBatch() {
|
|
|
4447
4650
|
const globalClient = getClient();
|
|
4448
4651
|
const globalStmts = batch.map(buildStmt);
|
|
4449
4652
|
await globalClient.batch(globalStmts, "write");
|
|
4653
|
+
try {
|
|
4654
|
+
const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
|
|
4655
|
+
await insertMemoryCardsForBatch2(batch);
|
|
4656
|
+
} catch {
|
|
4657
|
+
}
|
|
4450
4658
|
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
4451
4659
|
_pendingRecords.splice(0, batch.length);
|
|
4452
4660
|
try {
|
package/dist/bin/scan-tasks.js
CHANGED
|
@@ -562,8 +562,8 @@ var init_config = __esm({
|
|
|
562
562
|
rerankerAutoTrigger: {
|
|
563
563
|
enabled: true,
|
|
564
564
|
broadQueryMinCardinality: 5e4,
|
|
565
|
-
fetchTopK:
|
|
566
|
-
returnTopK:
|
|
565
|
+
fetchTopK: 200,
|
|
566
|
+
returnTopK: 20
|
|
567
567
|
}
|
|
568
568
|
},
|
|
569
569
|
graphRagEnabled: true,
|
|
@@ -3312,6 +3312,51 @@ async function ensureSchema() {
|
|
|
3312
3312
|
VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
|
|
3313
3313
|
END;
|
|
3314
3314
|
`);
|
|
3315
|
+
await client.executeMultiple(`
|
|
3316
|
+
CREATE TABLE IF NOT EXISTS memory_cards (
|
|
3317
|
+
id TEXT PRIMARY KEY,
|
|
3318
|
+
memory_id TEXT NOT NULL,
|
|
3319
|
+
agent_id TEXT NOT NULL,
|
|
3320
|
+
session_id TEXT NOT NULL,
|
|
3321
|
+
project_name TEXT,
|
|
3322
|
+
timestamp TEXT NOT NULL,
|
|
3323
|
+
card_type TEXT NOT NULL,
|
|
3324
|
+
subject TEXT,
|
|
3325
|
+
predicate TEXT,
|
|
3326
|
+
object TEXT,
|
|
3327
|
+
content TEXT NOT NULL,
|
|
3328
|
+
source_ref TEXT,
|
|
3329
|
+
confidence REAL DEFAULT 0.6,
|
|
3330
|
+
active INTEGER DEFAULT 1,
|
|
3331
|
+
created_at TEXT NOT NULL
|
|
3332
|
+
);
|
|
3333
|
+
|
|
3334
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cards_agent
|
|
3335
|
+
ON memory_cards(agent_id, active, timestamp);
|
|
3336
|
+
|
|
3337
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cards_memory
|
|
3338
|
+
ON memory_cards(memory_id);
|
|
3339
|
+
|
|
3340
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memory_cards_fts
|
|
3341
|
+
USING fts5(content, subject, predicate, object, content='memory_cards', content_rowid='rowid');
|
|
3342
|
+
|
|
3343
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ai AFTER INSERT ON memory_cards BEGIN
|
|
3344
|
+
INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
|
|
3345
|
+
VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
|
|
3346
|
+
END;
|
|
3347
|
+
|
|
3348
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ad AFTER DELETE ON memory_cards BEGIN
|
|
3349
|
+
INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
|
|
3350
|
+
VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
|
|
3351
|
+
END;
|
|
3352
|
+
|
|
3353
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_au AFTER UPDATE ON memory_cards BEGIN
|
|
3354
|
+
INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
|
|
3355
|
+
VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
|
|
3356
|
+
INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
|
|
3357
|
+
VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
|
|
3358
|
+
END;
|
|
3359
|
+
`);
|
|
3315
3360
|
try {
|
|
3316
3361
|
await client.execute({
|
|
3317
3362
|
sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
|
|
@@ -7787,6 +7832,164 @@ ${p.content}`).join("\n\n");
|
|
|
7787
7832
|
}
|
|
7788
7833
|
});
|
|
7789
7834
|
|
|
7835
|
+
// src/lib/memory-cards.ts
|
|
7836
|
+
var memory_cards_exports = {};
|
|
7837
|
+
__export(memory_cards_exports, {
|
|
7838
|
+
extractMemoryCards: () => extractMemoryCards,
|
|
7839
|
+
insertMemoryCardsForBatch: () => insertMemoryCardsForBatch,
|
|
7840
|
+
searchMemoryCards: () => searchMemoryCards
|
|
7841
|
+
});
|
|
7842
|
+
import { createHash as createHash2 } from "crypto";
|
|
7843
|
+
function stableId(memoryId, type, content) {
|
|
7844
|
+
return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
|
|
7845
|
+
}
|
|
7846
|
+
function cleanText(text) {
|
|
7847
|
+
return text.replace(/```[\s\S]*?```/g, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
7848
|
+
}
|
|
7849
|
+
function splitSentences(text) {
|
|
7850
|
+
return cleanText(text).split(/(?<=[.!?])\s+|\n+/).map((s) => s.trim()).filter((s) => s.length >= 24 && s.length <= MAX_SENTENCE_CHARS);
|
|
7851
|
+
}
|
|
7852
|
+
function inferCardType(sentence, toolName) {
|
|
7853
|
+
const lower = sentence.toLowerCase();
|
|
7854
|
+
if (toolName === "store_decision" || /\b(decided|decision|adr|approved|rejected)\b/.test(lower)) return "decision";
|
|
7855
|
+
if (/\b(prefers|preference|likes|dislikes|wants|doesn't want|does not want)\b/.test(lower)) return "preference";
|
|
7856
|
+
if (/\b(changed|updated|replaced|now|no longer|instead|supersedes)\b/.test(lower)) return "belief_update";
|
|
7857
|
+
if (toolName && ["Read", "Write", "Edit", "Bash"].includes(toolName)) return "code";
|
|
7858
|
+
if (/\b(meeting|deadline|shipped|launched|completed|failed|blocked|assigned|created)\b/.test(lower)) return "event";
|
|
7859
|
+
return "fact";
|
|
7860
|
+
}
|
|
7861
|
+
function extractSubject(sentence, agentId) {
|
|
7862
|
+
const explicit = sentence.match(/\b([A-Z][a-zA-Z0-9_-]{2,}(?:\s+[A-Z][a-zA-Z0-9_-]{2,})?)\b/);
|
|
7863
|
+
return explicit?.[1] ?? agentId;
|
|
7864
|
+
}
|
|
7865
|
+
function predicateFor(type) {
|
|
7866
|
+
switch (type) {
|
|
7867
|
+
case "preference":
|
|
7868
|
+
return "prefers";
|
|
7869
|
+
case "belief_update":
|
|
7870
|
+
return "updated";
|
|
7871
|
+
case "decision":
|
|
7872
|
+
return "decided";
|
|
7873
|
+
case "event":
|
|
7874
|
+
return "happened";
|
|
7875
|
+
case "code":
|
|
7876
|
+
return "implemented";
|
|
7877
|
+
default:
|
|
7878
|
+
return "states";
|
|
7879
|
+
}
|
|
7880
|
+
}
|
|
7881
|
+
function extractMemoryCards(row) {
|
|
7882
|
+
const sentences = splitSentences(row.raw_text);
|
|
7883
|
+
const cards = [];
|
|
7884
|
+
for (const sentence of sentences) {
|
|
7885
|
+
const type = inferCardType(sentence, row.tool_name);
|
|
7886
|
+
const subject = extractSubject(sentence, row.agent_id);
|
|
7887
|
+
const content = sentence.length > MAX_SENTENCE_CHARS ? `${sentence.slice(0, MAX_SENTENCE_CHARS - 1)}\u2026` : sentence;
|
|
7888
|
+
cards.push({
|
|
7889
|
+
id: stableId(row.id, type, content),
|
|
7890
|
+
memory_id: row.id,
|
|
7891
|
+
agent_id: row.agent_id,
|
|
7892
|
+
session_id: row.session_id,
|
|
7893
|
+
project_name: row.project_name ?? null,
|
|
7894
|
+
timestamp: row.timestamp,
|
|
7895
|
+
card_type: type,
|
|
7896
|
+
subject,
|
|
7897
|
+
predicate: predicateFor(type),
|
|
7898
|
+
object: content,
|
|
7899
|
+
content,
|
|
7900
|
+
source_ref: row.id,
|
|
7901
|
+
confidence: type === "fact" ? 0.55 : 0.65
|
|
7902
|
+
});
|
|
7903
|
+
if (cards.length >= MAX_CARDS_PER_MEMORY) break;
|
|
7904
|
+
}
|
|
7905
|
+
return cards;
|
|
7906
|
+
}
|
|
7907
|
+
async function insertMemoryCardsForBatch(rows) {
|
|
7908
|
+
const cards = rows.flatMap(extractMemoryCards);
|
|
7909
|
+
if (cards.length === 0) return 0;
|
|
7910
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7911
|
+
const client = getClient();
|
|
7912
|
+
const stmts = cards.map((card) => ({
|
|
7913
|
+
sql: `INSERT OR IGNORE INTO memory_cards
|
|
7914
|
+
(id, memory_id, agent_id, session_id, project_name, timestamp, card_type,
|
|
7915
|
+
subject, predicate, object, content, source_ref, confidence, active, created_at)
|
|
7916
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)`,
|
|
7917
|
+
args: [
|
|
7918
|
+
card.id,
|
|
7919
|
+
card.memory_id,
|
|
7920
|
+
card.agent_id,
|
|
7921
|
+
card.session_id,
|
|
7922
|
+
card.project_name,
|
|
7923
|
+
card.timestamp,
|
|
7924
|
+
card.card_type,
|
|
7925
|
+
card.subject,
|
|
7926
|
+
card.predicate,
|
|
7927
|
+
card.object,
|
|
7928
|
+
card.content,
|
|
7929
|
+
card.source_ref,
|
|
7930
|
+
card.confidence,
|
|
7931
|
+
now
|
|
7932
|
+
]
|
|
7933
|
+
}));
|
|
7934
|
+
await client.batch(stmts, "write");
|
|
7935
|
+
return cards.length;
|
|
7936
|
+
}
|
|
7937
|
+
function buildMatchExpr(queryText) {
|
|
7938
|
+
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);
|
|
7939
|
+
if (terms.length === 0) return null;
|
|
7940
|
+
return terms.map((t) => `${t}*`).join(terms.length >= 3 ? " AND " : " OR ");
|
|
7941
|
+
}
|
|
7942
|
+
async function searchMemoryCards(queryText, agentId, options) {
|
|
7943
|
+
const limit = options?.limit ?? 10;
|
|
7944
|
+
const matchExpr = buildMatchExpr(queryText);
|
|
7945
|
+
if (!matchExpr) return [];
|
|
7946
|
+
let sql = `SELECT c.id, c.memory_id, c.agent_id, c.session_id, c.project_name,
|
|
7947
|
+
c.timestamp, c.card_type, c.content, c.source_ref, c.confidence
|
|
7948
|
+
FROM memory_cards c
|
|
7949
|
+
JOIN memory_cards_fts fts ON c.rowid = fts.rowid
|
|
7950
|
+
WHERE memory_cards_fts MATCH ?
|
|
7951
|
+
AND c.agent_id = ?
|
|
7952
|
+
AND COALESCE(c.active, 1) = 1`;
|
|
7953
|
+
const args = [matchExpr, agentId];
|
|
7954
|
+
if (options?.projectName) {
|
|
7955
|
+
sql += ` AND c.project_name = ?`;
|
|
7956
|
+
args.push(options.projectName);
|
|
7957
|
+
}
|
|
7958
|
+
if (options?.since) {
|
|
7959
|
+
sql += ` AND c.timestamp >= ?`;
|
|
7960
|
+
args.push(options.since);
|
|
7961
|
+
}
|
|
7962
|
+
sql += ` ORDER BY rank LIMIT ?`;
|
|
7963
|
+
args.push(limit);
|
|
7964
|
+
const result = await getClient().execute({ sql, args });
|
|
7965
|
+
return result.rows.map((row) => ({
|
|
7966
|
+
id: `card:${String(row.id)}`,
|
|
7967
|
+
agent_id: String(row.agent_id),
|
|
7968
|
+
agent_role: "memory_card",
|
|
7969
|
+
session_id: String(row.session_id),
|
|
7970
|
+
timestamp: String(row.timestamp),
|
|
7971
|
+
tool_name: `memory_card:${String(row.card_type)}`,
|
|
7972
|
+
project_name: row.project_name == null ? "" : String(row.project_name),
|
|
7973
|
+
has_error: false,
|
|
7974
|
+
raw_text: `[${String(row.card_type)}] ${String(row.content)}
|
|
7975
|
+
Source memory: ${String(row.source_ref ?? row.memory_id)}`,
|
|
7976
|
+
vector: [],
|
|
7977
|
+
importance: 6,
|
|
7978
|
+
status: "active",
|
|
7979
|
+
confidence: Number(row.confidence ?? 0.6),
|
|
7980
|
+
last_accessed: String(row.timestamp)
|
|
7981
|
+
}));
|
|
7982
|
+
}
|
|
7983
|
+
var MAX_CARDS_PER_MEMORY, MAX_SENTENCE_CHARS;
|
|
7984
|
+
var init_memory_cards = __esm({
|
|
7985
|
+
"src/lib/memory-cards.ts"() {
|
|
7986
|
+
"use strict";
|
|
7987
|
+
init_database();
|
|
7988
|
+
MAX_CARDS_PER_MEMORY = 6;
|
|
7989
|
+
MAX_SENTENCE_CHARS = 360;
|
|
7990
|
+
}
|
|
7991
|
+
});
|
|
7992
|
+
|
|
7790
7993
|
// src/lib/store.ts
|
|
7791
7994
|
var store_exports = {};
|
|
7792
7995
|
__export(store_exports, {
|
|
@@ -8125,6 +8328,11 @@ async function flushBatch() {
|
|
|
8125
8328
|
const globalClient = getClient();
|
|
8126
8329
|
const globalStmts = batch.map(buildStmt);
|
|
8127
8330
|
await globalClient.batch(globalStmts, "write");
|
|
8331
|
+
try {
|
|
8332
|
+
const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
|
|
8333
|
+
await insertMemoryCardsForBatch2(batch);
|
|
8334
|
+
} catch {
|
|
8335
|
+
}
|
|
8128
8336
|
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
8129
8337
|
_pendingRecords.splice(0, batch.length);
|
|
8130
8338
|
try {
|
package/dist/bin/setup.js
CHANGED
|
@@ -247,8 +247,8 @@ var init_config = __esm({
|
|
|
247
247
|
rerankerAutoTrigger: {
|
|
248
248
|
enabled: true,
|
|
249
249
|
broadQueryMinCardinality: 5e4,
|
|
250
|
-
fetchTopK:
|
|
251
|
-
returnTopK:
|
|
250
|
+
fetchTopK: 200,
|
|
251
|
+
returnTopK: 20
|
|
252
252
|
}
|
|
253
253
|
},
|
|
254
254
|
graphRagEnabled: true,
|
|
@@ -3959,6 +3959,51 @@ async function ensureSchema() {
|
|
|
3959
3959
|
VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
|
|
3960
3960
|
END;
|
|
3961
3961
|
`);
|
|
3962
|
+
await client.executeMultiple(`
|
|
3963
|
+
CREATE TABLE IF NOT EXISTS memory_cards (
|
|
3964
|
+
id TEXT PRIMARY KEY,
|
|
3965
|
+
memory_id TEXT NOT NULL,
|
|
3966
|
+
agent_id TEXT NOT NULL,
|
|
3967
|
+
session_id TEXT NOT NULL,
|
|
3968
|
+
project_name TEXT,
|
|
3969
|
+
timestamp TEXT NOT NULL,
|
|
3970
|
+
card_type TEXT NOT NULL,
|
|
3971
|
+
subject TEXT,
|
|
3972
|
+
predicate TEXT,
|
|
3973
|
+
object TEXT,
|
|
3974
|
+
content TEXT NOT NULL,
|
|
3975
|
+
source_ref TEXT,
|
|
3976
|
+
confidence REAL DEFAULT 0.6,
|
|
3977
|
+
active INTEGER DEFAULT 1,
|
|
3978
|
+
created_at TEXT NOT NULL
|
|
3979
|
+
);
|
|
3980
|
+
|
|
3981
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cards_agent
|
|
3982
|
+
ON memory_cards(agent_id, active, timestamp);
|
|
3983
|
+
|
|
3984
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cards_memory
|
|
3985
|
+
ON memory_cards(memory_id);
|
|
3986
|
+
|
|
3987
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memory_cards_fts
|
|
3988
|
+
USING fts5(content, subject, predicate, object, content='memory_cards', content_rowid='rowid');
|
|
3989
|
+
|
|
3990
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ai AFTER INSERT ON memory_cards BEGIN
|
|
3991
|
+
INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
|
|
3992
|
+
VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
|
|
3993
|
+
END;
|
|
3994
|
+
|
|
3995
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ad AFTER DELETE ON memory_cards BEGIN
|
|
3996
|
+
INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
|
|
3997
|
+
VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
|
|
3998
|
+
END;
|
|
3999
|
+
|
|
4000
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_au AFTER UPDATE ON memory_cards BEGIN
|
|
4001
|
+
INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
|
|
4002
|
+
VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
|
|
4003
|
+
INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
|
|
4004
|
+
VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
|
|
4005
|
+
END;
|
|
4006
|
+
`);
|
|
3962
4007
|
try {
|
|
3963
4008
|
await client.execute({
|
|
3964
4009
|
sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
|