@askexenow/exe-os 0.9.34 → 0.9.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/backfill-conversations.js +210 -10
- package/dist/bin/backfill-responses.js +210 -10
- package/dist/bin/backfill-vectors.js +13 -2
- package/dist/bin/cleanup-stale-review-tasks.js +217 -10
- package/dist/bin/cli.js +222 -11
- package/dist/bin/exe-assign.js +210 -10
- package/dist/bin/exe-boot.js +24 -3
- package/dist/bin/exe-dispatch.js +222 -11
- package/dist/bin/exe-doctor.js +13 -2
- package/dist/bin/exe-export-behaviors.js +217 -10
- package/dist/bin/exe-forget.js +217 -10
- package/dist/bin/exe-gateway.js +222 -11
- package/dist/bin/exe-heartbeat.js +217 -10
- package/dist/bin/exe-kill.js +217 -10
- package/dist/bin/exe-launch-agent.js +92 -2
- package/dist/bin/exe-link.js +8 -0
- package/dist/bin/exe-pending-messages.js +217 -10
- package/dist/bin/exe-pending-notifications.js +217 -10
- package/dist/bin/exe-pending-reviews.js +217 -10
- package/dist/bin/exe-rename.js +8 -0
- package/dist/bin/exe-review.js +217 -10
- package/dist/bin/exe-search.js +217 -10
- package/dist/bin/exe-session-cleanup.js +222 -11
- package/dist/bin/exe-start-codex.js +92 -2
- package/dist/bin/exe-start-opencode.js +92 -2
- package/dist/bin/exe-status.js +217 -10
- package/dist/bin/exe-team.js +217 -10
- package/dist/bin/git-sweep.js +222 -11
- package/dist/bin/graph-backfill.js +92 -2
- package/dist/bin/graph-export.js +217 -10
- package/dist/bin/intercom-check.js +222 -11
- package/dist/bin/scan-tasks.js +222 -11
- package/dist/bin/setup.js +8 -0
- package/dist/bin/shard-migrate.js +92 -2
- package/dist/gateway/index.js +222 -11
- package/dist/hooks/bug-report-worker.js +222 -11
- package/dist/hooks/codex-stop-task-finalizer.js +217 -10
- package/dist/hooks/commit-complete.js +222 -11
- package/dist/hooks/error-recall.js +217 -10
- package/dist/hooks/ingest.js +217 -10
- package/dist/hooks/instructions-loaded.js +217 -10
- package/dist/hooks/notification.js +217 -10
- package/dist/hooks/post-compact.js +217 -10
- package/dist/hooks/post-tool-combined.js +217 -10
- package/dist/hooks/pre-compact.js +222 -11
- package/dist/hooks/pre-tool-use.js +217 -10
- package/dist/hooks/prompt-submit.js +222 -11
- package/dist/hooks/session-end.js +222 -11
- package/dist/hooks/session-start.js +217 -10
- package/dist/hooks/stop.js +217 -10
- package/dist/hooks/subagent-stop.js +217 -10
- package/dist/hooks/summary-worker.js +14 -1
- package/dist/index.js +222 -11
- package/dist/lib/cloud-sync.js +8 -0
- package/dist/lib/consolidation.js +3 -1
- package/dist/lib/database.js +8 -0
- package/dist/lib/db.js +8 -0
- package/dist/lib/device-registry.js +8 -0
- package/dist/lib/exe-daemon.js +1667 -1413
- package/dist/lib/hybrid-search.js +217 -10
- package/dist/lib/schedules.js +13 -2
- package/dist/lib/store.js +210 -10
- package/dist/lib/tasks.js +5 -1
- package/dist/lib/tmux-routing.js +5 -1
- package/dist/mcp/server.js +222 -11
- package/dist/mcp/tools/create-task.js +5 -1
- package/dist/mcp/tools/update-task.js +5 -1
- package/dist/runtime/index.js +222 -11
- package/dist/tui/App.js +222 -11
- package/package.json +1 -1
|
@@ -2299,6 +2299,14 @@ async function ensureSchema() {
|
|
|
2299
2299
|
);
|
|
2300
2300
|
} catch {
|
|
2301
2301
|
}
|
|
2302
|
+
try {
|
|
2303
|
+
await client.execute(
|
|
2304
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
|
|
2305
|
+
ON memories(content_hash, agent_id, project_name, memory_type)
|
|
2306
|
+
WHERE content_hash IS NOT NULL`
|
|
2307
|
+
);
|
|
2308
|
+
} catch {
|
|
2309
|
+
}
|
|
2302
2310
|
await client.executeMultiple(`
|
|
2303
2311
|
CREATE TABLE IF NOT EXISTS entities (
|
|
2304
2312
|
id TEXT PRIMARY KEY,
|
|
@@ -3044,6 +3052,196 @@ var init_state_bus = __esm({
|
|
|
3044
3052
|
}
|
|
3045
3053
|
});
|
|
3046
3054
|
|
|
3055
|
+
// src/lib/memory-write-governor.ts
|
|
3056
|
+
import { createHash } from "crypto";
|
|
3057
|
+
function normalizeMemoryText(text) {
|
|
3058
|
+
return text.replace(/\r\n/g, "\n").replace(/[ \t]+$/gm, "").replace(/\n{4,}/g, "\n\n\n").trim();
|
|
3059
|
+
}
|
|
3060
|
+
function classifyMemoryType(input) {
|
|
3061
|
+
if (input.memory_type && input.memory_type.trim()) return input.memory_type.trim();
|
|
3062
|
+
const tool = input.tool_name.toLowerCase();
|
|
3063
|
+
const text = input.raw_text.toLowerCase();
|
|
3064
|
+
if (tool.includes("store_decision") || tool.includes("decision")) return "decision";
|
|
3065
|
+
if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
|
|
3066
|
+
if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
|
|
3067
|
+
if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
|
|
3068
|
+
if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
|
|
3069
|
+
if (tool === "store_memory" || tool === "manual") return "observation";
|
|
3070
|
+
return "raw";
|
|
3071
|
+
}
|
|
3072
|
+
function shouldDropMemory(text) {
|
|
3073
|
+
const normalized = normalizeMemoryText(text);
|
|
3074
|
+
if (normalized.length < 10) return { drop: true, reason: "too_short" };
|
|
3075
|
+
if (NOISE_DROP_PATTERNS.some((pattern) => pattern.test(normalized))) {
|
|
3076
|
+
return { drop: true, reason: "known_boilerplate_noise" };
|
|
3077
|
+
}
|
|
3078
|
+
return { drop: false };
|
|
3079
|
+
}
|
|
3080
|
+
function shouldSkipEmbedding(input) {
|
|
3081
|
+
const type = classifyMemoryType(input);
|
|
3082
|
+
if (HIGH_VALUE_SUPERSESSION_TYPES.has(type)) return false;
|
|
3083
|
+
if (type === "raw" && input.raw_text.length > 2e4) return true;
|
|
3084
|
+
if (SKIP_EMBED_PATTERNS.some((pattern) => pattern.test(input.raw_text))) return true;
|
|
3085
|
+
return false;
|
|
3086
|
+
}
|
|
3087
|
+
function hashMemoryContent(text) {
|
|
3088
|
+
return createHash("sha256").update(normalizeMemoryText(text)).digest("hex");
|
|
3089
|
+
}
|
|
3090
|
+
function scopedDedupArgs(input) {
|
|
3091
|
+
return [input.contentHash, input.agentId, input.projectName, input.memoryType];
|
|
3092
|
+
}
|
|
3093
|
+
function governMemoryRecord(record) {
|
|
3094
|
+
const normalized = normalizeMemoryText(record.raw_text);
|
|
3095
|
+
const memoryType = classifyMemoryType({
|
|
3096
|
+
raw_text: normalized,
|
|
3097
|
+
agent_id: record.agent_id,
|
|
3098
|
+
project_name: record.project_name,
|
|
3099
|
+
tool_name: record.tool_name,
|
|
3100
|
+
memory_type: record.memory_type
|
|
3101
|
+
});
|
|
3102
|
+
const drop = shouldDropMemory(normalized);
|
|
3103
|
+
const skipEmbedding = shouldSkipEmbedding({
|
|
3104
|
+
raw_text: normalized,
|
|
3105
|
+
agent_id: record.agent_id,
|
|
3106
|
+
project_name: record.project_name,
|
|
3107
|
+
tool_name: record.tool_name,
|
|
3108
|
+
memory_type: memoryType
|
|
3109
|
+
});
|
|
3110
|
+
return {
|
|
3111
|
+
record: {
|
|
3112
|
+
...record,
|
|
3113
|
+
raw_text: normalized,
|
|
3114
|
+
memory_type: memoryType,
|
|
3115
|
+
vector: skipEmbedding ? null : record.vector
|
|
3116
|
+
},
|
|
3117
|
+
contentHash: hashMemoryContent(normalized),
|
|
3118
|
+
shouldDrop: drop.drop,
|
|
3119
|
+
dropReason: drop.reason,
|
|
3120
|
+
skipEmbedding,
|
|
3121
|
+
hygiene: {
|
|
3122
|
+
dedup: true,
|
|
3123
|
+
supersession: HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)
|
|
3124
|
+
}
|
|
3125
|
+
};
|
|
3126
|
+
}
|
|
3127
|
+
async function findScopedDuplicate(input) {
|
|
3128
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3129
|
+
const client = getClient2();
|
|
3130
|
+
const args = scopedDedupArgs(input);
|
|
3131
|
+
let sql = `SELECT id FROM memories
|
|
3132
|
+
WHERE content_hash = ?
|
|
3133
|
+
AND agent_id = ?
|
|
3134
|
+
AND project_name = ?
|
|
3135
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
3136
|
+
AND COALESCE(status, 'active') != 'deleted'`;
|
|
3137
|
+
if (input.excludeId) {
|
|
3138
|
+
sql += " AND id != ?";
|
|
3139
|
+
args.push(input.excludeId);
|
|
3140
|
+
}
|
|
3141
|
+
sql += " ORDER BY timestamp DESC LIMIT 1";
|
|
3142
|
+
const result = await client.execute({ sql, args });
|
|
3143
|
+
return result.rows[0]?.id ? String(result.rows[0].id) : null;
|
|
3144
|
+
}
|
|
3145
|
+
async function runPostWriteMemoryHygiene(memoryId) {
|
|
3146
|
+
try {
|
|
3147
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3148
|
+
const client = getClient2();
|
|
3149
|
+
const current = await client.execute({
|
|
3150
|
+
sql: `SELECT id, agent_id, project_name, memory_type, content_hash, supersedes_id,
|
|
3151
|
+
importance, timestamp
|
|
3152
|
+
FROM memories
|
|
3153
|
+
WHERE id = ?
|
|
3154
|
+
LIMIT 1`,
|
|
3155
|
+
args: [memoryId]
|
|
3156
|
+
});
|
|
3157
|
+
const row = current.rows[0];
|
|
3158
|
+
if (!row) return;
|
|
3159
|
+
const memoryType = String(row.memory_type ?? "raw");
|
|
3160
|
+
const contentHash = row.content_hash ? String(row.content_hash) : null;
|
|
3161
|
+
const agentId = String(row.agent_id);
|
|
3162
|
+
const projectName = String(row.project_name);
|
|
3163
|
+
if (contentHash) {
|
|
3164
|
+
await client.execute({
|
|
3165
|
+
sql: `UPDATE memories
|
|
3166
|
+
SET status = 'deleted',
|
|
3167
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
3168
|
+
WHERE id != ?
|
|
3169
|
+
AND content_hash = ?
|
|
3170
|
+
AND agent_id = ?
|
|
3171
|
+
AND project_name = ?
|
|
3172
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
3173
|
+
AND COALESCE(status, 'active') = 'active'`,
|
|
3174
|
+
args: [memoryId, contentHash, agentId, projectName, memoryType]
|
|
3175
|
+
});
|
|
3176
|
+
}
|
|
3177
|
+
const supersedesId = row.supersedes_id ? String(row.supersedes_id) : null;
|
|
3178
|
+
if (supersedesId && HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)) {
|
|
3179
|
+
const old = await client.execute({
|
|
3180
|
+
sql: `SELECT importance FROM memories WHERE id = ? LIMIT 1`,
|
|
3181
|
+
args: [supersedesId]
|
|
3182
|
+
});
|
|
3183
|
+
const oldImportance = Number(old.rows[0]?.importance ?? 0);
|
|
3184
|
+
const newImportance = Number(row.importance ?? 0);
|
|
3185
|
+
await client.batch([
|
|
3186
|
+
{
|
|
3187
|
+
sql: `UPDATE memories
|
|
3188
|
+
SET status = 'archived',
|
|
3189
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
3190
|
+
WHERE id = ?`,
|
|
3191
|
+
args: [supersedesId]
|
|
3192
|
+
},
|
|
3193
|
+
{
|
|
3194
|
+
sql: `UPDATE memories
|
|
3195
|
+
SET importance = MAX(COALESCE(importance, 5), ?),
|
|
3196
|
+
parent_memory_id = COALESCE(parent_memory_id, ?)
|
|
3197
|
+
WHERE id = ?`,
|
|
3198
|
+
args: [Math.max(oldImportance, newImportance), supersedesId, memoryId]
|
|
3199
|
+
}
|
|
3200
|
+
], "write");
|
|
3201
|
+
}
|
|
3202
|
+
} catch (err) {
|
|
3203
|
+
process.stderr.write(
|
|
3204
|
+
`[memory-governor] post-write hygiene failed for ${memoryId}: ${err instanceof Error ? err.message : String(err)}
|
|
3205
|
+
`
|
|
3206
|
+
);
|
|
3207
|
+
}
|
|
3208
|
+
}
|
|
3209
|
+
function schedulePostWriteMemoryHygiene(memoryIds) {
|
|
3210
|
+
if (memoryIds.length === 0) return;
|
|
3211
|
+
const run = () => {
|
|
3212
|
+
void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
|
|
3213
|
+
};
|
|
3214
|
+
if (typeof setImmediate === "function") setImmediate(run);
|
|
3215
|
+
else setTimeout(run, 0);
|
|
3216
|
+
}
|
|
3217
|
+
var HIGH_VALUE_SUPERSESSION_TYPES, NOISE_DROP_PATTERNS, SKIP_EMBED_PATTERNS;
|
|
3218
|
+
var init_memory_write_governor = __esm({
|
|
3219
|
+
"src/lib/memory-write-governor.ts"() {
|
|
3220
|
+
"use strict";
|
|
3221
|
+
HIGH_VALUE_SUPERSESSION_TYPES = /* @__PURE__ */ new Set([
|
|
3222
|
+
"decision",
|
|
3223
|
+
"adr",
|
|
3224
|
+
"behavior",
|
|
3225
|
+
"procedure"
|
|
3226
|
+
]);
|
|
3227
|
+
NOISE_DROP_PATTERNS = [
|
|
3228
|
+
/^\s*\[📋\s+\d+\s+reviews?\s+pending\b/im,
|
|
3229
|
+
/^\s*<system-reminder>[\s\S]*?<\/system-reminder>\s*$/im,
|
|
3230
|
+
/^\s*The UserPromptSubmit hook checks the DB for new tasks/im,
|
|
3231
|
+
/^\s*Intercom is a speedup, not delivery/im,
|
|
3232
|
+
/^\s*Context bar reads as USAGE not remaining/im
|
|
3233
|
+
];
|
|
3234
|
+
SKIP_EMBED_PATTERNS = [
|
|
3235
|
+
/tmux capture-pane\b/i,
|
|
3236
|
+
/docker ps\b/i,
|
|
3237
|
+
/docker images\b/i,
|
|
3238
|
+
/git status\b/i,
|
|
3239
|
+
/grep .*node_modules/i,
|
|
3240
|
+
/npm (install|ci)\b[\s\S]*(added \d+ packages|audited \d+ packages)/i
|
|
3241
|
+
];
|
|
3242
|
+
}
|
|
3243
|
+
});
|
|
3244
|
+
|
|
3047
3245
|
// src/lib/shard-manager.ts
|
|
3048
3246
|
var shard_manager_exports = {};
|
|
3049
3247
|
__export(shard_manager_exports, {
|
|
@@ -3208,7 +3406,8 @@ async function ensureShardSchema(client) {
|
|
|
3208
3406
|
}
|
|
3209
3407
|
for (const idx of [
|
|
3210
3408
|
"CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
|
|
3211
|
-
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
|
|
3409
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
|
|
3410
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash ON memories(content_hash, agent_id, project_name, memory_type) WHERE content_hash IS NOT NULL"
|
|
3212
3411
|
]) {
|
|
3213
3412
|
try {
|
|
3214
3413
|
await client.execute(idx);
|
|
@@ -3633,7 +3832,6 @@ __export(store_exports, {
|
|
|
3633
3832
|
vectorToBlob: () => vectorToBlob,
|
|
3634
3833
|
writeMemory: () => writeMemory
|
|
3635
3834
|
});
|
|
3636
|
-
import { createHash } from "crypto";
|
|
3637
3835
|
function isBusyError2(err) {
|
|
3638
3836
|
if (err instanceof Error) {
|
|
3639
3837
|
const msg = err.message.toLowerCase();
|
|
@@ -3747,17 +3945,24 @@ async function writeMemory(record) {
|
|
|
3747
3945
|
`Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
|
|
3748
3946
|
);
|
|
3749
3947
|
}
|
|
3750
|
-
const
|
|
3751
|
-
if (
|
|
3948
|
+
const governed = governMemoryRecord(record);
|
|
3949
|
+
if (governed.shouldDrop) return;
|
|
3950
|
+
record = governed.record;
|
|
3951
|
+
const contentHash = governed.contentHash;
|
|
3952
|
+
const memoryType = record.memory_type ?? "raw";
|
|
3953
|
+
if (_pendingRecords.some(
|
|
3954
|
+
(r) => r.content_hash === contentHash && r.agent_id === record.agent_id && r.project_name === record.project_name && (r.memory_type ?? "raw") === memoryType
|
|
3955
|
+
)) {
|
|
3752
3956
|
return;
|
|
3753
3957
|
}
|
|
3754
3958
|
try {
|
|
3755
|
-
const
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3959
|
+
const existing = await findScopedDuplicate({
|
|
3960
|
+
contentHash,
|
|
3961
|
+
agentId: record.agent_id,
|
|
3962
|
+
projectName: record.project_name,
|
|
3963
|
+
memoryType
|
|
3759
3964
|
});
|
|
3760
|
-
if (existing
|
|
3965
|
+
if (existing) return;
|
|
3761
3966
|
} catch {
|
|
3762
3967
|
}
|
|
3763
3968
|
const dbRow = {
|
|
@@ -3788,7 +3993,7 @@ async function writeMemory(record) {
|
|
|
3788
3993
|
tier: record.tier ?? classifyTier(record),
|
|
3789
3994
|
supersedes_id: record.supersedes_id ?? null,
|
|
3790
3995
|
draft: record.draft ? 1 : 0,
|
|
3791
|
-
memory_type:
|
|
3996
|
+
memory_type: memoryType,
|
|
3792
3997
|
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
3793
3998
|
content_hash: contentHash,
|
|
3794
3999
|
intent: record.intent ?? null,
|
|
@@ -3947,6 +4152,7 @@ async function flushBatch() {
|
|
|
3947
4152
|
const globalClient = getClient();
|
|
3948
4153
|
const globalStmts = batch.map(buildStmt);
|
|
3949
4154
|
await globalClient.batch(globalStmts, "write");
|
|
4155
|
+
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
3950
4156
|
_pendingRecords.splice(0, batch.length);
|
|
3951
4157
|
try {
|
|
3952
4158
|
const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
@@ -4205,6 +4411,7 @@ var init_store = __esm({
|
|
|
4205
4411
|
init_keychain();
|
|
4206
4412
|
init_config();
|
|
4207
4413
|
init_state_bus();
|
|
4414
|
+
init_memory_write_governor();
|
|
4208
4415
|
INIT_MAX_RETRIES = 3;
|
|
4209
4416
|
INIT_RETRY_DELAY_MS = 1e3;
|
|
4210
4417
|
_pendingRecords = [];
|
package/dist/bin/cli.js
CHANGED
|
@@ -3920,6 +3920,14 @@ async function ensureSchema() {
|
|
|
3920
3920
|
);
|
|
3921
3921
|
} catch {
|
|
3922
3922
|
}
|
|
3923
|
+
try {
|
|
3924
|
+
await client.execute(
|
|
3925
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
|
|
3926
|
+
ON memories(content_hash, agent_id, project_name, memory_type)
|
|
3927
|
+
WHERE content_hash IS NOT NULL`
|
|
3928
|
+
);
|
|
3929
|
+
} catch {
|
|
3930
|
+
}
|
|
3923
3931
|
await client.executeMultiple(`
|
|
3924
3932
|
CREATE TABLE IF NOT EXISTS entities (
|
|
3925
3933
|
id TEXT PRIMARY KEY,
|
|
@@ -6794,6 +6802,196 @@ var init_state_bus = __esm({
|
|
|
6794
6802
|
}
|
|
6795
6803
|
});
|
|
6796
6804
|
|
|
6805
|
+
// src/lib/memory-write-governor.ts
|
|
6806
|
+
import { createHash } from "crypto";
|
|
6807
|
+
function normalizeMemoryText(text) {
|
|
6808
|
+
return text.replace(/\r\n/g, "\n").replace(/[ \t]+$/gm, "").replace(/\n{4,}/g, "\n\n\n").trim();
|
|
6809
|
+
}
|
|
6810
|
+
function classifyMemoryType(input) {
|
|
6811
|
+
if (input.memory_type && input.memory_type.trim()) return input.memory_type.trim();
|
|
6812
|
+
const tool = input.tool_name.toLowerCase();
|
|
6813
|
+
const text = input.raw_text.toLowerCase();
|
|
6814
|
+
if (tool.includes("store_decision") || tool.includes("decision")) return "decision";
|
|
6815
|
+
if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
|
|
6816
|
+
if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
|
|
6817
|
+
if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
|
|
6818
|
+
if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
|
|
6819
|
+
if (tool === "store_memory" || tool === "manual") return "observation";
|
|
6820
|
+
return "raw";
|
|
6821
|
+
}
|
|
6822
|
+
function shouldDropMemory(text) {
|
|
6823
|
+
const normalized = normalizeMemoryText(text);
|
|
6824
|
+
if (normalized.length < 10) return { drop: true, reason: "too_short" };
|
|
6825
|
+
if (NOISE_DROP_PATTERNS.some((pattern) => pattern.test(normalized))) {
|
|
6826
|
+
return { drop: true, reason: "known_boilerplate_noise" };
|
|
6827
|
+
}
|
|
6828
|
+
return { drop: false };
|
|
6829
|
+
}
|
|
6830
|
+
function shouldSkipEmbedding(input) {
|
|
6831
|
+
const type = classifyMemoryType(input);
|
|
6832
|
+
if (HIGH_VALUE_SUPERSESSION_TYPES.has(type)) return false;
|
|
6833
|
+
if (type === "raw" && input.raw_text.length > 2e4) return true;
|
|
6834
|
+
if (SKIP_EMBED_PATTERNS.some((pattern) => pattern.test(input.raw_text))) return true;
|
|
6835
|
+
return false;
|
|
6836
|
+
}
|
|
6837
|
+
function hashMemoryContent(text) {
|
|
6838
|
+
return createHash("sha256").update(normalizeMemoryText(text)).digest("hex");
|
|
6839
|
+
}
|
|
6840
|
+
function scopedDedupArgs(input) {
|
|
6841
|
+
return [input.contentHash, input.agentId, input.projectName, input.memoryType];
|
|
6842
|
+
}
|
|
6843
|
+
function governMemoryRecord(record) {
|
|
6844
|
+
const normalized = normalizeMemoryText(record.raw_text);
|
|
6845
|
+
const memoryType = classifyMemoryType({
|
|
6846
|
+
raw_text: normalized,
|
|
6847
|
+
agent_id: record.agent_id,
|
|
6848
|
+
project_name: record.project_name,
|
|
6849
|
+
tool_name: record.tool_name,
|
|
6850
|
+
memory_type: record.memory_type
|
|
6851
|
+
});
|
|
6852
|
+
const drop = shouldDropMemory(normalized);
|
|
6853
|
+
const skipEmbedding = shouldSkipEmbedding({
|
|
6854
|
+
raw_text: normalized,
|
|
6855
|
+
agent_id: record.agent_id,
|
|
6856
|
+
project_name: record.project_name,
|
|
6857
|
+
tool_name: record.tool_name,
|
|
6858
|
+
memory_type: memoryType
|
|
6859
|
+
});
|
|
6860
|
+
return {
|
|
6861
|
+
record: {
|
|
6862
|
+
...record,
|
|
6863
|
+
raw_text: normalized,
|
|
6864
|
+
memory_type: memoryType,
|
|
6865
|
+
vector: skipEmbedding ? null : record.vector
|
|
6866
|
+
},
|
|
6867
|
+
contentHash: hashMemoryContent(normalized),
|
|
6868
|
+
shouldDrop: drop.drop,
|
|
6869
|
+
dropReason: drop.reason,
|
|
6870
|
+
skipEmbedding,
|
|
6871
|
+
hygiene: {
|
|
6872
|
+
dedup: true,
|
|
6873
|
+
supersession: HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)
|
|
6874
|
+
}
|
|
6875
|
+
};
|
|
6876
|
+
}
|
|
6877
|
+
async function findScopedDuplicate(input) {
|
|
6878
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
6879
|
+
const client = getClient2();
|
|
6880
|
+
const args2 = scopedDedupArgs(input);
|
|
6881
|
+
let sql = `SELECT id FROM memories
|
|
6882
|
+
WHERE content_hash = ?
|
|
6883
|
+
AND agent_id = ?
|
|
6884
|
+
AND project_name = ?
|
|
6885
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
6886
|
+
AND COALESCE(status, 'active') != 'deleted'`;
|
|
6887
|
+
if (input.excludeId) {
|
|
6888
|
+
sql += " AND id != ?";
|
|
6889
|
+
args2.push(input.excludeId);
|
|
6890
|
+
}
|
|
6891
|
+
sql += " ORDER BY timestamp DESC LIMIT 1";
|
|
6892
|
+
const result = await client.execute({ sql, args: args2 });
|
|
6893
|
+
return result.rows[0]?.id ? String(result.rows[0].id) : null;
|
|
6894
|
+
}
|
|
6895
|
+
async function runPostWriteMemoryHygiene(memoryId) {
|
|
6896
|
+
try {
|
|
6897
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
6898
|
+
const client = getClient2();
|
|
6899
|
+
const current = await client.execute({
|
|
6900
|
+
sql: `SELECT id, agent_id, project_name, memory_type, content_hash, supersedes_id,
|
|
6901
|
+
importance, timestamp
|
|
6902
|
+
FROM memories
|
|
6903
|
+
WHERE id = ?
|
|
6904
|
+
LIMIT 1`,
|
|
6905
|
+
args: [memoryId]
|
|
6906
|
+
});
|
|
6907
|
+
const row = current.rows[0];
|
|
6908
|
+
if (!row) return;
|
|
6909
|
+
const memoryType = String(row.memory_type ?? "raw");
|
|
6910
|
+
const contentHash2 = row.content_hash ? String(row.content_hash) : null;
|
|
6911
|
+
const agentId = String(row.agent_id);
|
|
6912
|
+
const projectName = String(row.project_name);
|
|
6913
|
+
if (contentHash2) {
|
|
6914
|
+
await client.execute({
|
|
6915
|
+
sql: `UPDATE memories
|
|
6916
|
+
SET status = 'deleted',
|
|
6917
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
6918
|
+
WHERE id != ?
|
|
6919
|
+
AND content_hash = ?
|
|
6920
|
+
AND agent_id = ?
|
|
6921
|
+
AND project_name = ?
|
|
6922
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
6923
|
+
AND COALESCE(status, 'active') = 'active'`,
|
|
6924
|
+
args: [memoryId, contentHash2, agentId, projectName, memoryType]
|
|
6925
|
+
});
|
|
6926
|
+
}
|
|
6927
|
+
const supersedesId = row.supersedes_id ? String(row.supersedes_id) : null;
|
|
6928
|
+
if (supersedesId && HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)) {
|
|
6929
|
+
const old = await client.execute({
|
|
6930
|
+
sql: `SELECT importance FROM memories WHERE id = ? LIMIT 1`,
|
|
6931
|
+
args: [supersedesId]
|
|
6932
|
+
});
|
|
6933
|
+
const oldImportance = Number(old.rows[0]?.importance ?? 0);
|
|
6934
|
+
const newImportance = Number(row.importance ?? 0);
|
|
6935
|
+
await client.batch([
|
|
6936
|
+
{
|
|
6937
|
+
sql: `UPDATE memories
|
|
6938
|
+
SET status = 'archived',
|
|
6939
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
6940
|
+
WHERE id = ?`,
|
|
6941
|
+
args: [supersedesId]
|
|
6942
|
+
},
|
|
6943
|
+
{
|
|
6944
|
+
sql: `UPDATE memories
|
|
6945
|
+
SET importance = MAX(COALESCE(importance, 5), ?),
|
|
6946
|
+
parent_memory_id = COALESCE(parent_memory_id, ?)
|
|
6947
|
+
WHERE id = ?`,
|
|
6948
|
+
args: [Math.max(oldImportance, newImportance), supersedesId, memoryId]
|
|
6949
|
+
}
|
|
6950
|
+
], "write");
|
|
6951
|
+
}
|
|
6952
|
+
} catch (err) {
|
|
6953
|
+
process.stderr.write(
|
|
6954
|
+
`[memory-governor] post-write hygiene failed for ${memoryId}: ${err instanceof Error ? err.message : String(err)}
|
|
6955
|
+
`
|
|
6956
|
+
);
|
|
6957
|
+
}
|
|
6958
|
+
}
|
|
6959
|
+
function schedulePostWriteMemoryHygiene(memoryIds) {
|
|
6960
|
+
if (memoryIds.length === 0) return;
|
|
6961
|
+
const run = () => {
|
|
6962
|
+
void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
|
|
6963
|
+
};
|
|
6964
|
+
if (typeof setImmediate === "function") setImmediate(run);
|
|
6965
|
+
else setTimeout(run, 0);
|
|
6966
|
+
}
|
|
6967
|
+
var HIGH_VALUE_SUPERSESSION_TYPES, NOISE_DROP_PATTERNS, SKIP_EMBED_PATTERNS;
|
|
6968
|
+
var init_memory_write_governor = __esm({
|
|
6969
|
+
"src/lib/memory-write-governor.ts"() {
|
|
6970
|
+
"use strict";
|
|
6971
|
+
HIGH_VALUE_SUPERSESSION_TYPES = /* @__PURE__ */ new Set([
|
|
6972
|
+
"decision",
|
|
6973
|
+
"adr",
|
|
6974
|
+
"behavior",
|
|
6975
|
+
"procedure"
|
|
6976
|
+
]);
|
|
6977
|
+
NOISE_DROP_PATTERNS = [
|
|
6978
|
+
/^\s*\[📋\s+\d+\s+reviews?\s+pending\b/im,
|
|
6979
|
+
/^\s*<system-reminder>[\s\S]*?<\/system-reminder>\s*$/im,
|
|
6980
|
+
/^\s*The UserPromptSubmit hook checks the DB for new tasks/im,
|
|
6981
|
+
/^\s*Intercom is a speedup, not delivery/im,
|
|
6982
|
+
/^\s*Context bar reads as USAGE not remaining/im
|
|
6983
|
+
];
|
|
6984
|
+
SKIP_EMBED_PATTERNS = [
|
|
6985
|
+
/tmux capture-pane\b/i,
|
|
6986
|
+
/docker ps\b/i,
|
|
6987
|
+
/docker images\b/i,
|
|
6988
|
+
/git status\b/i,
|
|
6989
|
+
/grep .*node_modules/i,
|
|
6990
|
+
/npm (install|ci)\b[\s\S]*(added \d+ packages|audited \d+ packages)/i
|
|
6991
|
+
];
|
|
6992
|
+
}
|
|
6993
|
+
});
|
|
6994
|
+
|
|
6797
6995
|
// src/lib/shard-manager.ts
|
|
6798
6996
|
var shard_manager_exports = {};
|
|
6799
6997
|
__export(shard_manager_exports, {
|
|
@@ -6958,7 +7156,8 @@ async function ensureShardSchema(client) {
|
|
|
6958
7156
|
}
|
|
6959
7157
|
for (const idx of [
|
|
6960
7158
|
"CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
|
|
6961
|
-
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
|
|
7159
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
|
|
7160
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash ON memories(content_hash, agent_id, project_name, memory_type) WHERE content_hash IS NOT NULL"
|
|
6962
7161
|
]) {
|
|
6963
7162
|
try {
|
|
6964
7163
|
await client.execute(idx);
|
|
@@ -7383,7 +7582,6 @@ __export(store_exports, {
|
|
|
7383
7582
|
vectorToBlob: () => vectorToBlob,
|
|
7384
7583
|
writeMemory: () => writeMemory
|
|
7385
7584
|
});
|
|
7386
|
-
import { createHash } from "crypto";
|
|
7387
7585
|
function isBusyError2(err) {
|
|
7388
7586
|
if (err instanceof Error) {
|
|
7389
7587
|
const msg = err.message.toLowerCase();
|
|
@@ -7497,17 +7695,24 @@ async function writeMemory(record) {
|
|
|
7497
7695
|
`Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
|
|
7498
7696
|
);
|
|
7499
7697
|
}
|
|
7500
|
-
const
|
|
7501
|
-
if (
|
|
7698
|
+
const governed = governMemoryRecord(record);
|
|
7699
|
+
if (governed.shouldDrop) return;
|
|
7700
|
+
record = governed.record;
|
|
7701
|
+
const contentHash2 = governed.contentHash;
|
|
7702
|
+
const memoryType = record.memory_type ?? "raw";
|
|
7703
|
+
if (_pendingRecords.some(
|
|
7704
|
+
(r) => r.content_hash === contentHash2 && r.agent_id === record.agent_id && r.project_name === record.project_name && (r.memory_type ?? "raw") === memoryType
|
|
7705
|
+
)) {
|
|
7502
7706
|
return;
|
|
7503
7707
|
}
|
|
7504
7708
|
try {
|
|
7505
|
-
const
|
|
7506
|
-
|
|
7507
|
-
|
|
7508
|
-
|
|
7709
|
+
const existing = await findScopedDuplicate({
|
|
7710
|
+
contentHash: contentHash2,
|
|
7711
|
+
agentId: record.agent_id,
|
|
7712
|
+
projectName: record.project_name,
|
|
7713
|
+
memoryType
|
|
7509
7714
|
});
|
|
7510
|
-
if (existing
|
|
7715
|
+
if (existing) return;
|
|
7511
7716
|
} catch {
|
|
7512
7717
|
}
|
|
7513
7718
|
const dbRow = {
|
|
@@ -7538,7 +7743,7 @@ async function writeMemory(record) {
|
|
|
7538
7743
|
tier: record.tier ?? classifyTier(record),
|
|
7539
7744
|
supersedes_id: record.supersedes_id ?? null,
|
|
7540
7745
|
draft: record.draft ? 1 : 0,
|
|
7541
|
-
memory_type:
|
|
7746
|
+
memory_type: memoryType,
|
|
7542
7747
|
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
7543
7748
|
content_hash: contentHash2,
|
|
7544
7749
|
intent: record.intent ?? null,
|
|
@@ -7697,6 +7902,7 @@ async function flushBatch() {
|
|
|
7697
7902
|
const globalClient = getClient();
|
|
7698
7903
|
const globalStmts = batch.map(buildStmt);
|
|
7699
7904
|
await globalClient.batch(globalStmts, "write");
|
|
7905
|
+
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
7700
7906
|
_pendingRecords.splice(0, batch.length);
|
|
7701
7907
|
try {
|
|
7702
7908
|
const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
@@ -7955,6 +8161,7 @@ var init_store = __esm({
|
|
|
7955
8161
|
init_keychain();
|
|
7956
8162
|
init_config();
|
|
7957
8163
|
init_state_bus();
|
|
8164
|
+
init_memory_write_governor();
|
|
7958
8165
|
INIT_MAX_RETRIES = 3;
|
|
7959
8166
|
INIT_RETRY_DELAY_MS = 1e3;
|
|
7960
8167
|
_pendingRecords = [];
|
|
@@ -12955,7 +13162,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
12955
13162
|
}
|
|
12956
13163
|
if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
|
|
12957
13164
|
if (agentRtConfig.runtime === "claude" && agentRtConfig.model) {
|
|
12958
|
-
|
|
13165
|
+
let ccModel = agentRtConfig.model.replace(/(\d+)\.(\d+)/g, "$1-$2");
|
|
13166
|
+
if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
|
|
13167
|
+
ccModel += "[1m]";
|
|
13168
|
+
}
|
|
13169
|
+
envPrefix = `${envPrefix} ANTHROPIC_MODEL=${ccModel}`;
|
|
12959
13170
|
}
|
|
12960
13171
|
}
|
|
12961
13172
|
let spawnCommand;
|