@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
package/dist/bin/exe-assign.js
CHANGED
|
@@ -2223,6 +2223,14 @@ async function ensureSchema() {
|
|
|
2223
2223
|
);
|
|
2224
2224
|
} catch {
|
|
2225
2225
|
}
|
|
2226
|
+
try {
|
|
2227
|
+
await client.execute(
|
|
2228
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
|
|
2229
|
+
ON memories(content_hash, agent_id, project_name, memory_type)
|
|
2230
|
+
WHERE content_hash IS NOT NULL`
|
|
2231
|
+
);
|
|
2232
|
+
} catch {
|
|
2233
|
+
}
|
|
2226
2234
|
await client.executeMultiple(`
|
|
2227
2235
|
CREATE TABLE IF NOT EXISTS entities (
|
|
2228
2236
|
id TEXT PRIMARY KEY,
|
|
@@ -2892,7 +2900,8 @@ async function ensureShardSchema(client) {
|
|
|
2892
2900
|
}
|
|
2893
2901
|
for (const idx of [
|
|
2894
2902
|
"CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
|
|
2895
|
-
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
|
|
2903
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
|
|
2904
|
+
"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"
|
|
2896
2905
|
]) {
|
|
2897
2906
|
try {
|
|
2898
2907
|
await client.execute(idx);
|
|
@@ -3448,7 +3457,6 @@ async function embed(text) {
|
|
|
3448
3457
|
// src/lib/store.ts
|
|
3449
3458
|
init_memory();
|
|
3450
3459
|
init_database();
|
|
3451
|
-
import { createHash } from "crypto";
|
|
3452
3460
|
|
|
3453
3461
|
// src/lib/keychain.ts
|
|
3454
3462
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
@@ -3681,6 +3689,190 @@ var StateBus = class {
|
|
|
3681
3689
|
};
|
|
3682
3690
|
var orgBus = new StateBus();
|
|
3683
3691
|
|
|
3692
|
+
// src/lib/memory-write-governor.ts
|
|
3693
|
+
import { createHash } from "crypto";
|
|
3694
|
+
var HIGH_VALUE_SUPERSESSION_TYPES = /* @__PURE__ */ new Set([
|
|
3695
|
+
"decision",
|
|
3696
|
+
"adr",
|
|
3697
|
+
"behavior",
|
|
3698
|
+
"procedure"
|
|
3699
|
+
]);
|
|
3700
|
+
var NOISE_DROP_PATTERNS = [
|
|
3701
|
+
/^\s*\[📋\s+\d+\s+reviews?\s+pending\b/im,
|
|
3702
|
+
/^\s*<system-reminder>[\s\S]*?<\/system-reminder>\s*$/im,
|
|
3703
|
+
/^\s*The UserPromptSubmit hook checks the DB for new tasks/im,
|
|
3704
|
+
/^\s*Intercom is a speedup, not delivery/im,
|
|
3705
|
+
/^\s*Context bar reads as USAGE not remaining/im
|
|
3706
|
+
];
|
|
3707
|
+
var SKIP_EMBED_PATTERNS = [
|
|
3708
|
+
/tmux capture-pane\b/i,
|
|
3709
|
+
/docker ps\b/i,
|
|
3710
|
+
/docker images\b/i,
|
|
3711
|
+
/git status\b/i,
|
|
3712
|
+
/grep .*node_modules/i,
|
|
3713
|
+
/npm (install|ci)\b[\s\S]*(added \d+ packages|audited \d+ packages)/i
|
|
3714
|
+
];
|
|
3715
|
+
function normalizeMemoryText(text) {
|
|
3716
|
+
return text.replace(/\r\n/g, "\n").replace(/[ \t]+$/gm, "").replace(/\n{4,}/g, "\n\n\n").trim();
|
|
3717
|
+
}
|
|
3718
|
+
function classifyMemoryType(input) {
|
|
3719
|
+
if (input.memory_type && input.memory_type.trim()) return input.memory_type.trim();
|
|
3720
|
+
const tool = input.tool_name.toLowerCase();
|
|
3721
|
+
const text = input.raw_text.toLowerCase();
|
|
3722
|
+
if (tool.includes("store_decision") || tool.includes("decision")) return "decision";
|
|
3723
|
+
if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
|
|
3724
|
+
if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
|
|
3725
|
+
if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
|
|
3726
|
+
if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
|
|
3727
|
+
if (tool === "store_memory" || tool === "manual") return "observation";
|
|
3728
|
+
return "raw";
|
|
3729
|
+
}
|
|
3730
|
+
function shouldDropMemory(text) {
|
|
3731
|
+
const normalized = normalizeMemoryText(text);
|
|
3732
|
+
if (normalized.length < 10) return { drop: true, reason: "too_short" };
|
|
3733
|
+
if (NOISE_DROP_PATTERNS.some((pattern) => pattern.test(normalized))) {
|
|
3734
|
+
return { drop: true, reason: "known_boilerplate_noise" };
|
|
3735
|
+
}
|
|
3736
|
+
return { drop: false };
|
|
3737
|
+
}
|
|
3738
|
+
function shouldSkipEmbedding(input) {
|
|
3739
|
+
const type = classifyMemoryType(input);
|
|
3740
|
+
if (HIGH_VALUE_SUPERSESSION_TYPES.has(type)) return false;
|
|
3741
|
+
if (type === "raw" && input.raw_text.length > 2e4) return true;
|
|
3742
|
+
if (SKIP_EMBED_PATTERNS.some((pattern) => pattern.test(input.raw_text))) return true;
|
|
3743
|
+
return false;
|
|
3744
|
+
}
|
|
3745
|
+
function hashMemoryContent(text) {
|
|
3746
|
+
return createHash("sha256").update(normalizeMemoryText(text)).digest("hex");
|
|
3747
|
+
}
|
|
3748
|
+
function scopedDedupArgs(input) {
|
|
3749
|
+
return [input.contentHash, input.agentId, input.projectName, input.memoryType];
|
|
3750
|
+
}
|
|
3751
|
+
function governMemoryRecord(record) {
|
|
3752
|
+
const normalized = normalizeMemoryText(record.raw_text);
|
|
3753
|
+
const memoryType = classifyMemoryType({
|
|
3754
|
+
raw_text: normalized,
|
|
3755
|
+
agent_id: record.agent_id,
|
|
3756
|
+
project_name: record.project_name,
|
|
3757
|
+
tool_name: record.tool_name,
|
|
3758
|
+
memory_type: record.memory_type
|
|
3759
|
+
});
|
|
3760
|
+
const drop = shouldDropMemory(normalized);
|
|
3761
|
+
const skipEmbedding = shouldSkipEmbedding({
|
|
3762
|
+
raw_text: normalized,
|
|
3763
|
+
agent_id: record.agent_id,
|
|
3764
|
+
project_name: record.project_name,
|
|
3765
|
+
tool_name: record.tool_name,
|
|
3766
|
+
memory_type: memoryType
|
|
3767
|
+
});
|
|
3768
|
+
return {
|
|
3769
|
+
record: {
|
|
3770
|
+
...record,
|
|
3771
|
+
raw_text: normalized,
|
|
3772
|
+
memory_type: memoryType,
|
|
3773
|
+
vector: skipEmbedding ? null : record.vector
|
|
3774
|
+
},
|
|
3775
|
+
contentHash: hashMemoryContent(normalized),
|
|
3776
|
+
shouldDrop: drop.drop,
|
|
3777
|
+
dropReason: drop.reason,
|
|
3778
|
+
skipEmbedding,
|
|
3779
|
+
hygiene: {
|
|
3780
|
+
dedup: true,
|
|
3781
|
+
supersession: HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)
|
|
3782
|
+
}
|
|
3783
|
+
};
|
|
3784
|
+
}
|
|
3785
|
+
async function findScopedDuplicate(input) {
|
|
3786
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3787
|
+
const client = getClient2();
|
|
3788
|
+
const args = scopedDedupArgs(input);
|
|
3789
|
+
let sql = `SELECT id FROM memories
|
|
3790
|
+
WHERE content_hash = ?
|
|
3791
|
+
AND agent_id = ?
|
|
3792
|
+
AND project_name = ?
|
|
3793
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
3794
|
+
AND COALESCE(status, 'active') != 'deleted'`;
|
|
3795
|
+
if (input.excludeId) {
|
|
3796
|
+
sql += " AND id != ?";
|
|
3797
|
+
args.push(input.excludeId);
|
|
3798
|
+
}
|
|
3799
|
+
sql += " ORDER BY timestamp DESC LIMIT 1";
|
|
3800
|
+
const result = await client.execute({ sql, args });
|
|
3801
|
+
return result.rows[0]?.id ? String(result.rows[0].id) : null;
|
|
3802
|
+
}
|
|
3803
|
+
async function runPostWriteMemoryHygiene(memoryId) {
|
|
3804
|
+
try {
|
|
3805
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3806
|
+
const client = getClient2();
|
|
3807
|
+
const current = await client.execute({
|
|
3808
|
+
sql: `SELECT id, agent_id, project_name, memory_type, content_hash, supersedes_id,
|
|
3809
|
+
importance, timestamp
|
|
3810
|
+
FROM memories
|
|
3811
|
+
WHERE id = ?
|
|
3812
|
+
LIMIT 1`,
|
|
3813
|
+
args: [memoryId]
|
|
3814
|
+
});
|
|
3815
|
+
const row = current.rows[0];
|
|
3816
|
+
if (!row) return;
|
|
3817
|
+
const memoryType = String(row.memory_type ?? "raw");
|
|
3818
|
+
const contentHash = row.content_hash ? String(row.content_hash) : null;
|
|
3819
|
+
const agentId = String(row.agent_id);
|
|
3820
|
+
const projectName = String(row.project_name);
|
|
3821
|
+
if (contentHash) {
|
|
3822
|
+
await client.execute({
|
|
3823
|
+
sql: `UPDATE memories
|
|
3824
|
+
SET status = 'deleted',
|
|
3825
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
3826
|
+
WHERE id != ?
|
|
3827
|
+
AND content_hash = ?
|
|
3828
|
+
AND agent_id = ?
|
|
3829
|
+
AND project_name = ?
|
|
3830
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
3831
|
+
AND COALESCE(status, 'active') = 'active'`,
|
|
3832
|
+
args: [memoryId, contentHash, agentId, projectName, memoryType]
|
|
3833
|
+
});
|
|
3834
|
+
}
|
|
3835
|
+
const supersedesId = row.supersedes_id ? String(row.supersedes_id) : null;
|
|
3836
|
+
if (supersedesId && HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)) {
|
|
3837
|
+
const old = await client.execute({
|
|
3838
|
+
sql: `SELECT importance FROM memories WHERE id = ? LIMIT 1`,
|
|
3839
|
+
args: [supersedesId]
|
|
3840
|
+
});
|
|
3841
|
+
const oldImportance = Number(old.rows[0]?.importance ?? 0);
|
|
3842
|
+
const newImportance = Number(row.importance ?? 0);
|
|
3843
|
+
await client.batch([
|
|
3844
|
+
{
|
|
3845
|
+
sql: `UPDATE memories
|
|
3846
|
+
SET status = 'archived',
|
|
3847
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
3848
|
+
WHERE id = ?`,
|
|
3849
|
+
args: [supersedesId]
|
|
3850
|
+
},
|
|
3851
|
+
{
|
|
3852
|
+
sql: `UPDATE memories
|
|
3853
|
+
SET importance = MAX(COALESCE(importance, 5), ?),
|
|
3854
|
+
parent_memory_id = COALESCE(parent_memory_id, ?)
|
|
3855
|
+
WHERE id = ?`,
|
|
3856
|
+
args: [Math.max(oldImportance, newImportance), supersedesId, memoryId]
|
|
3857
|
+
}
|
|
3858
|
+
], "write");
|
|
3859
|
+
}
|
|
3860
|
+
} catch (err) {
|
|
3861
|
+
process.stderr.write(
|
|
3862
|
+
`[memory-governor] post-write hygiene failed for ${memoryId}: ${err instanceof Error ? err.message : String(err)}
|
|
3863
|
+
`
|
|
3864
|
+
);
|
|
3865
|
+
}
|
|
3866
|
+
}
|
|
3867
|
+
function schedulePostWriteMemoryHygiene(memoryIds) {
|
|
3868
|
+
if (memoryIds.length === 0) return;
|
|
3869
|
+
const run = () => {
|
|
3870
|
+
void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
|
|
3871
|
+
};
|
|
3872
|
+
if (typeof setImmediate === "function") setImmediate(run);
|
|
3873
|
+
else setTimeout(run, 0);
|
|
3874
|
+
}
|
|
3875
|
+
|
|
3684
3876
|
// src/lib/store.ts
|
|
3685
3877
|
var INIT_MAX_RETRIES = 3;
|
|
3686
3878
|
var INIT_RETRY_DELAY_MS = 1e3;
|
|
@@ -3803,17 +3995,24 @@ async function writeMemory(record) {
|
|
|
3803
3995
|
`Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
|
|
3804
3996
|
);
|
|
3805
3997
|
}
|
|
3806
|
-
const
|
|
3807
|
-
if (
|
|
3998
|
+
const governed = governMemoryRecord(record);
|
|
3999
|
+
if (governed.shouldDrop) return;
|
|
4000
|
+
record = governed.record;
|
|
4001
|
+
const contentHash = governed.contentHash;
|
|
4002
|
+
const memoryType = record.memory_type ?? "raw";
|
|
4003
|
+
if (_pendingRecords.some(
|
|
4004
|
+
(r) => r.content_hash === contentHash && r.agent_id === record.agent_id && r.project_name === record.project_name && (r.memory_type ?? "raw") === memoryType
|
|
4005
|
+
)) {
|
|
3808
4006
|
return;
|
|
3809
4007
|
}
|
|
3810
4008
|
try {
|
|
3811
|
-
const
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
4009
|
+
const existing = await findScopedDuplicate({
|
|
4010
|
+
contentHash,
|
|
4011
|
+
agentId: record.agent_id,
|
|
4012
|
+
projectName: record.project_name,
|
|
4013
|
+
memoryType
|
|
3815
4014
|
});
|
|
3816
|
-
if (existing
|
|
4015
|
+
if (existing) return;
|
|
3817
4016
|
} catch {
|
|
3818
4017
|
}
|
|
3819
4018
|
const dbRow = {
|
|
@@ -3844,7 +4043,7 @@ async function writeMemory(record) {
|
|
|
3844
4043
|
tier: record.tier ?? classifyTier(record),
|
|
3845
4044
|
supersedes_id: record.supersedes_id ?? null,
|
|
3846
4045
|
draft: record.draft ? 1 : 0,
|
|
3847
|
-
memory_type:
|
|
4046
|
+
memory_type: memoryType,
|
|
3848
4047
|
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
3849
4048
|
content_hash: contentHash,
|
|
3850
4049
|
intent: record.intent ?? null,
|
|
@@ -4003,6 +4202,7 @@ async function flushBatch() {
|
|
|
4003
4202
|
const globalClient = getClient();
|
|
4004
4203
|
const globalStmts = batch.map(buildStmt);
|
|
4005
4204
|
await globalClient.batch(globalStmts, "write");
|
|
4205
|
+
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
4006
4206
|
_pendingRecords.splice(0, batch.length);
|
|
4007
4207
|
try {
|
|
4008
4208
|
const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
package/dist/bin/exe-boot.js
CHANGED
|
@@ -2365,6 +2365,14 @@ async function ensureSchema() {
|
|
|
2365
2365
|
);
|
|
2366
2366
|
} catch {
|
|
2367
2367
|
}
|
|
2368
|
+
try {
|
|
2369
|
+
await client.execute(
|
|
2370
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
|
|
2371
|
+
ON memories(content_hash, agent_id, project_name, memory_type)
|
|
2372
|
+
WHERE content_hash IS NOT NULL`
|
|
2373
|
+
);
|
|
2374
|
+
} catch {
|
|
2375
|
+
}
|
|
2368
2376
|
await client.executeMultiple(`
|
|
2369
2377
|
CREATE TABLE IF NOT EXISTS entities (
|
|
2370
2378
|
id TEXT PRIMARY KEY,
|
|
@@ -3474,6 +3482,14 @@ var init_state_bus = __esm({
|
|
|
3474
3482
|
}
|
|
3475
3483
|
});
|
|
3476
3484
|
|
|
3485
|
+
// src/lib/memory-write-governor.ts
|
|
3486
|
+
import { createHash } from "crypto";
|
|
3487
|
+
var init_memory_write_governor = __esm({
|
|
3488
|
+
"src/lib/memory-write-governor.ts"() {
|
|
3489
|
+
"use strict";
|
|
3490
|
+
}
|
|
3491
|
+
});
|
|
3492
|
+
|
|
3477
3493
|
// src/lib/shard-manager.ts
|
|
3478
3494
|
var shard_manager_exports = {};
|
|
3479
3495
|
__export(shard_manager_exports, {
|
|
@@ -3638,7 +3654,8 @@ async function ensureShardSchema(client) {
|
|
|
3638
3654
|
}
|
|
3639
3655
|
for (const idx of [
|
|
3640
3656
|
"CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
|
|
3641
|
-
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
|
|
3657
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
|
|
3658
|
+
"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"
|
|
3642
3659
|
]) {
|
|
3643
3660
|
try {
|
|
3644
3661
|
await client.execute(idx);
|
|
@@ -3797,7 +3814,6 @@ var init_shard_manager = __esm({
|
|
|
3797
3814
|
});
|
|
3798
3815
|
|
|
3799
3816
|
// src/lib/store.ts
|
|
3800
|
-
import { createHash } from "crypto";
|
|
3801
3817
|
function isBusyError2(err) {
|
|
3802
3818
|
if (err instanceof Error) {
|
|
3803
3819
|
const msg = err.message.toLowerCase();
|
|
@@ -3882,6 +3898,7 @@ var init_store = __esm({
|
|
|
3882
3898
|
init_keychain();
|
|
3883
3899
|
init_config();
|
|
3884
3900
|
init_state_bus();
|
|
3901
|
+
init_memory_write_governor();
|
|
3885
3902
|
INIT_MAX_RETRIES = 3;
|
|
3886
3903
|
INIT_RETRY_DELAY_MS = 1e3;
|
|
3887
3904
|
_pendingRecords = [];
|
|
@@ -7996,7 +8013,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
7996
8013
|
}
|
|
7997
8014
|
if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
|
|
7998
8015
|
if (agentRtConfig.runtime === "claude" && agentRtConfig.model) {
|
|
7999
|
-
|
|
8016
|
+
let ccModel = agentRtConfig.model.replace(/(\d+)\.(\d+)/g, "$1-$2");
|
|
8017
|
+
if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
|
|
8018
|
+
ccModel += "[1m]";
|
|
8019
|
+
}
|
|
8020
|
+
envPrefix = `${envPrefix} ANTHROPIC_MODEL=${ccModel}`;
|
|
8000
8021
|
}
|
|
8001
8022
|
}
|
|
8002
8023
|
let spawnCommand;
|
package/dist/bin/exe-dispatch.js
CHANGED
|
@@ -2867,6 +2867,14 @@ async function ensureSchema() {
|
|
|
2867
2867
|
);
|
|
2868
2868
|
} catch {
|
|
2869
2869
|
}
|
|
2870
|
+
try {
|
|
2871
|
+
await client.execute(
|
|
2872
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
|
|
2873
|
+
ON memories(content_hash, agent_id, project_name, memory_type)
|
|
2874
|
+
WHERE content_hash IS NOT NULL`
|
|
2875
|
+
);
|
|
2876
|
+
} catch {
|
|
2877
|
+
}
|
|
2870
2878
|
await client.executeMultiple(`
|
|
2871
2879
|
CREATE TABLE IF NOT EXISTS entities (
|
|
2872
2880
|
id TEXT PRIMARY KEY,
|
|
@@ -6399,7 +6407,11 @@ function spawnEmployee(employeeName2, exeSession2, projectDir2, opts) {
|
|
|
6399
6407
|
}
|
|
6400
6408
|
if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
|
|
6401
6409
|
if (agentRtConfig.runtime === "claude" && agentRtConfig.model) {
|
|
6402
|
-
|
|
6410
|
+
let ccModel = agentRtConfig.model.replace(/(\d+)\.(\d+)/g, "$1-$2");
|
|
6411
|
+
if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
|
|
6412
|
+
ccModel += "[1m]";
|
|
6413
|
+
}
|
|
6414
|
+
envPrefix = `${envPrefix} ANTHROPIC_MODEL=${ccModel}`;
|
|
6403
6415
|
}
|
|
6404
6416
|
}
|
|
6405
6417
|
let spawnCommand;
|
|
@@ -6713,6 +6725,196 @@ var init_keychain = __esm({
|
|
|
6713
6725
|
}
|
|
6714
6726
|
});
|
|
6715
6727
|
|
|
6728
|
+
// src/lib/memory-write-governor.ts
|
|
6729
|
+
import { createHash } from "crypto";
|
|
6730
|
+
function normalizeMemoryText(text) {
|
|
6731
|
+
return text.replace(/\r\n/g, "\n").replace(/[ \t]+$/gm, "").replace(/\n{4,}/g, "\n\n\n").trim();
|
|
6732
|
+
}
|
|
6733
|
+
function classifyMemoryType(input) {
|
|
6734
|
+
if (input.memory_type && input.memory_type.trim()) return input.memory_type.trim();
|
|
6735
|
+
const tool = input.tool_name.toLowerCase();
|
|
6736
|
+
const text = input.raw_text.toLowerCase();
|
|
6737
|
+
if (tool.includes("store_decision") || tool.includes("decision")) return "decision";
|
|
6738
|
+
if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
|
|
6739
|
+
if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
|
|
6740
|
+
if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
|
|
6741
|
+
if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
|
|
6742
|
+
if (tool === "store_memory" || tool === "manual") return "observation";
|
|
6743
|
+
return "raw";
|
|
6744
|
+
}
|
|
6745
|
+
function shouldDropMemory(text) {
|
|
6746
|
+
const normalized = normalizeMemoryText(text);
|
|
6747
|
+
if (normalized.length < 10) return { drop: true, reason: "too_short" };
|
|
6748
|
+
if (NOISE_DROP_PATTERNS.some((pattern) => pattern.test(normalized))) {
|
|
6749
|
+
return { drop: true, reason: "known_boilerplate_noise" };
|
|
6750
|
+
}
|
|
6751
|
+
return { drop: false };
|
|
6752
|
+
}
|
|
6753
|
+
function shouldSkipEmbedding(input) {
|
|
6754
|
+
const type = classifyMemoryType(input);
|
|
6755
|
+
if (HIGH_VALUE_SUPERSESSION_TYPES.has(type)) return false;
|
|
6756
|
+
if (type === "raw" && input.raw_text.length > 2e4) return true;
|
|
6757
|
+
if (SKIP_EMBED_PATTERNS.some((pattern) => pattern.test(input.raw_text))) return true;
|
|
6758
|
+
return false;
|
|
6759
|
+
}
|
|
6760
|
+
function hashMemoryContent(text) {
|
|
6761
|
+
return createHash("sha256").update(normalizeMemoryText(text)).digest("hex");
|
|
6762
|
+
}
|
|
6763
|
+
function scopedDedupArgs(input) {
|
|
6764
|
+
return [input.contentHash, input.agentId, input.projectName, input.memoryType];
|
|
6765
|
+
}
|
|
6766
|
+
function governMemoryRecord(record) {
|
|
6767
|
+
const normalized = normalizeMemoryText(record.raw_text);
|
|
6768
|
+
const memoryType = classifyMemoryType({
|
|
6769
|
+
raw_text: normalized,
|
|
6770
|
+
agent_id: record.agent_id,
|
|
6771
|
+
project_name: record.project_name,
|
|
6772
|
+
tool_name: record.tool_name,
|
|
6773
|
+
memory_type: record.memory_type
|
|
6774
|
+
});
|
|
6775
|
+
const drop = shouldDropMemory(normalized);
|
|
6776
|
+
const skipEmbedding = shouldSkipEmbedding({
|
|
6777
|
+
raw_text: normalized,
|
|
6778
|
+
agent_id: record.agent_id,
|
|
6779
|
+
project_name: record.project_name,
|
|
6780
|
+
tool_name: record.tool_name,
|
|
6781
|
+
memory_type: memoryType
|
|
6782
|
+
});
|
|
6783
|
+
return {
|
|
6784
|
+
record: {
|
|
6785
|
+
...record,
|
|
6786
|
+
raw_text: normalized,
|
|
6787
|
+
memory_type: memoryType,
|
|
6788
|
+
vector: skipEmbedding ? null : record.vector
|
|
6789
|
+
},
|
|
6790
|
+
contentHash: hashMemoryContent(normalized),
|
|
6791
|
+
shouldDrop: drop.drop,
|
|
6792
|
+
dropReason: drop.reason,
|
|
6793
|
+
skipEmbedding,
|
|
6794
|
+
hygiene: {
|
|
6795
|
+
dedup: true,
|
|
6796
|
+
supersession: HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)
|
|
6797
|
+
}
|
|
6798
|
+
};
|
|
6799
|
+
}
|
|
6800
|
+
async function findScopedDuplicate(input) {
|
|
6801
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
6802
|
+
const client = getClient2();
|
|
6803
|
+
const args = scopedDedupArgs(input);
|
|
6804
|
+
let sql = `SELECT id FROM memories
|
|
6805
|
+
WHERE content_hash = ?
|
|
6806
|
+
AND agent_id = ?
|
|
6807
|
+
AND project_name = ?
|
|
6808
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
6809
|
+
AND COALESCE(status, 'active') != 'deleted'`;
|
|
6810
|
+
if (input.excludeId) {
|
|
6811
|
+
sql += " AND id != ?";
|
|
6812
|
+
args.push(input.excludeId);
|
|
6813
|
+
}
|
|
6814
|
+
sql += " ORDER BY timestamp DESC LIMIT 1";
|
|
6815
|
+
const result2 = await client.execute({ sql, args });
|
|
6816
|
+
return result2.rows[0]?.id ? String(result2.rows[0].id) : null;
|
|
6817
|
+
}
|
|
6818
|
+
async function runPostWriteMemoryHygiene(memoryId) {
|
|
6819
|
+
try {
|
|
6820
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
6821
|
+
const client = getClient2();
|
|
6822
|
+
const current = await client.execute({
|
|
6823
|
+
sql: `SELECT id, agent_id, project_name, memory_type, content_hash, supersedes_id,
|
|
6824
|
+
importance, timestamp
|
|
6825
|
+
FROM memories
|
|
6826
|
+
WHERE id = ?
|
|
6827
|
+
LIMIT 1`,
|
|
6828
|
+
args: [memoryId]
|
|
6829
|
+
});
|
|
6830
|
+
const row = current.rows[0];
|
|
6831
|
+
if (!row) return;
|
|
6832
|
+
const memoryType = String(row.memory_type ?? "raw");
|
|
6833
|
+
const contentHash = row.content_hash ? String(row.content_hash) : null;
|
|
6834
|
+
const agentId = String(row.agent_id);
|
|
6835
|
+
const projectName = String(row.project_name);
|
|
6836
|
+
if (contentHash) {
|
|
6837
|
+
await client.execute({
|
|
6838
|
+
sql: `UPDATE memories
|
|
6839
|
+
SET status = 'deleted',
|
|
6840
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
6841
|
+
WHERE id != ?
|
|
6842
|
+
AND content_hash = ?
|
|
6843
|
+
AND agent_id = ?
|
|
6844
|
+
AND project_name = ?
|
|
6845
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
6846
|
+
AND COALESCE(status, 'active') = 'active'`,
|
|
6847
|
+
args: [memoryId, contentHash, agentId, projectName, memoryType]
|
|
6848
|
+
});
|
|
6849
|
+
}
|
|
6850
|
+
const supersedesId = row.supersedes_id ? String(row.supersedes_id) : null;
|
|
6851
|
+
if (supersedesId && HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)) {
|
|
6852
|
+
const old = await client.execute({
|
|
6853
|
+
sql: `SELECT importance FROM memories WHERE id = ? LIMIT 1`,
|
|
6854
|
+
args: [supersedesId]
|
|
6855
|
+
});
|
|
6856
|
+
const oldImportance = Number(old.rows[0]?.importance ?? 0);
|
|
6857
|
+
const newImportance = Number(row.importance ?? 0);
|
|
6858
|
+
await client.batch([
|
|
6859
|
+
{
|
|
6860
|
+
sql: `UPDATE memories
|
|
6861
|
+
SET status = 'archived',
|
|
6862
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
6863
|
+
WHERE id = ?`,
|
|
6864
|
+
args: [supersedesId]
|
|
6865
|
+
},
|
|
6866
|
+
{
|
|
6867
|
+
sql: `UPDATE memories
|
|
6868
|
+
SET importance = MAX(COALESCE(importance, 5), ?),
|
|
6869
|
+
parent_memory_id = COALESCE(parent_memory_id, ?)
|
|
6870
|
+
WHERE id = ?`,
|
|
6871
|
+
args: [Math.max(oldImportance, newImportance), supersedesId, memoryId]
|
|
6872
|
+
}
|
|
6873
|
+
], "write");
|
|
6874
|
+
}
|
|
6875
|
+
} catch (err) {
|
|
6876
|
+
process.stderr.write(
|
|
6877
|
+
`[memory-governor] post-write hygiene failed for ${memoryId}: ${err instanceof Error ? err.message : String(err)}
|
|
6878
|
+
`
|
|
6879
|
+
);
|
|
6880
|
+
}
|
|
6881
|
+
}
|
|
6882
|
+
function schedulePostWriteMemoryHygiene(memoryIds) {
|
|
6883
|
+
if (memoryIds.length === 0) return;
|
|
6884
|
+
const run = () => {
|
|
6885
|
+
void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
|
|
6886
|
+
};
|
|
6887
|
+
if (typeof setImmediate === "function") setImmediate(run);
|
|
6888
|
+
else setTimeout(run, 0);
|
|
6889
|
+
}
|
|
6890
|
+
var HIGH_VALUE_SUPERSESSION_TYPES, NOISE_DROP_PATTERNS, SKIP_EMBED_PATTERNS;
|
|
6891
|
+
var init_memory_write_governor = __esm({
|
|
6892
|
+
"src/lib/memory-write-governor.ts"() {
|
|
6893
|
+
"use strict";
|
|
6894
|
+
HIGH_VALUE_SUPERSESSION_TYPES = /* @__PURE__ */ new Set([
|
|
6895
|
+
"decision",
|
|
6896
|
+
"adr",
|
|
6897
|
+
"behavior",
|
|
6898
|
+
"procedure"
|
|
6899
|
+
]);
|
|
6900
|
+
NOISE_DROP_PATTERNS = [
|
|
6901
|
+
/^\s*\[📋\s+\d+\s+reviews?\s+pending\b/im,
|
|
6902
|
+
/^\s*<system-reminder>[\s\S]*?<\/system-reminder>\s*$/im,
|
|
6903
|
+
/^\s*The UserPromptSubmit hook checks the DB for new tasks/im,
|
|
6904
|
+
/^\s*Intercom is a speedup, not delivery/im,
|
|
6905
|
+
/^\s*Context bar reads as USAGE not remaining/im
|
|
6906
|
+
];
|
|
6907
|
+
SKIP_EMBED_PATTERNS = [
|
|
6908
|
+
/tmux capture-pane\b/i,
|
|
6909
|
+
/docker ps\b/i,
|
|
6910
|
+
/docker images\b/i,
|
|
6911
|
+
/git status\b/i,
|
|
6912
|
+
/grep .*node_modules/i,
|
|
6913
|
+
/npm (install|ci)\b[\s\S]*(added \d+ packages|audited \d+ packages)/i
|
|
6914
|
+
];
|
|
6915
|
+
}
|
|
6916
|
+
});
|
|
6917
|
+
|
|
6716
6918
|
// src/lib/shard-manager.ts
|
|
6717
6919
|
var shard_manager_exports = {};
|
|
6718
6920
|
__export(shard_manager_exports, {
|
|
@@ -6877,7 +7079,8 @@ async function ensureShardSchema(client) {
|
|
|
6877
7079
|
}
|
|
6878
7080
|
for (const idx of [
|
|
6879
7081
|
"CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
|
|
6880
|
-
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
|
|
7082
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
|
|
7083
|
+
"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"
|
|
6881
7084
|
]) {
|
|
6882
7085
|
try {
|
|
6883
7086
|
await client.execute(idx);
|
|
@@ -7302,7 +7505,6 @@ __export(store_exports, {
|
|
|
7302
7505
|
vectorToBlob: () => vectorToBlob,
|
|
7303
7506
|
writeMemory: () => writeMemory
|
|
7304
7507
|
});
|
|
7305
|
-
import { createHash } from "crypto";
|
|
7306
7508
|
function isBusyError2(err) {
|
|
7307
7509
|
if (err instanceof Error) {
|
|
7308
7510
|
const msg = err.message.toLowerCase();
|
|
@@ -7416,17 +7618,24 @@ async function writeMemory(record) {
|
|
|
7416
7618
|
`Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
|
|
7417
7619
|
);
|
|
7418
7620
|
}
|
|
7419
|
-
const
|
|
7420
|
-
if (
|
|
7621
|
+
const governed = governMemoryRecord(record);
|
|
7622
|
+
if (governed.shouldDrop) return;
|
|
7623
|
+
record = governed.record;
|
|
7624
|
+
const contentHash = governed.contentHash;
|
|
7625
|
+
const memoryType = record.memory_type ?? "raw";
|
|
7626
|
+
if (_pendingRecords.some(
|
|
7627
|
+
(r) => r.content_hash === contentHash && r.agent_id === record.agent_id && r.project_name === record.project_name && (r.memory_type ?? "raw") === memoryType
|
|
7628
|
+
)) {
|
|
7421
7629
|
return;
|
|
7422
7630
|
}
|
|
7423
7631
|
try {
|
|
7424
|
-
const
|
|
7425
|
-
|
|
7426
|
-
|
|
7427
|
-
|
|
7632
|
+
const existing = await findScopedDuplicate({
|
|
7633
|
+
contentHash,
|
|
7634
|
+
agentId: record.agent_id,
|
|
7635
|
+
projectName: record.project_name,
|
|
7636
|
+
memoryType
|
|
7428
7637
|
});
|
|
7429
|
-
if (existing
|
|
7638
|
+
if (existing) return;
|
|
7430
7639
|
} catch {
|
|
7431
7640
|
}
|
|
7432
7641
|
const dbRow = {
|
|
@@ -7457,7 +7666,7 @@ async function writeMemory(record) {
|
|
|
7457
7666
|
tier: record.tier ?? classifyTier(record),
|
|
7458
7667
|
supersedes_id: record.supersedes_id ?? null,
|
|
7459
7668
|
draft: record.draft ? 1 : 0,
|
|
7460
|
-
memory_type:
|
|
7669
|
+
memory_type: memoryType,
|
|
7461
7670
|
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
7462
7671
|
content_hash: contentHash,
|
|
7463
7672
|
intent: record.intent ?? null,
|
|
@@ -7616,6 +7825,7 @@ async function flushBatch() {
|
|
|
7616
7825
|
const globalClient = getClient();
|
|
7617
7826
|
const globalStmts = batch.map(buildStmt);
|
|
7618
7827
|
await globalClient.batch(globalStmts, "write");
|
|
7828
|
+
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
7619
7829
|
_pendingRecords.splice(0, batch.length);
|
|
7620
7830
|
try {
|
|
7621
7831
|
const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
@@ -7874,6 +8084,7 @@ var init_store = __esm({
|
|
|
7874
8084
|
init_keychain();
|
|
7875
8085
|
init_config();
|
|
7876
8086
|
init_state_bus();
|
|
8087
|
+
init_memory_write_governor();
|
|
7877
8088
|
INIT_MAX_RETRIES = 3;
|
|
7878
8089
|
INIT_RETRY_DELAY_MS = 1e3;
|
|
7879
8090
|
_pendingRecords = [];
|
package/dist/bin/exe-doctor.js
CHANGED
|
@@ -2073,6 +2073,14 @@ async function ensureSchema() {
|
|
|
2073
2073
|
);
|
|
2074
2074
|
} catch {
|
|
2075
2075
|
}
|
|
2076
|
+
try {
|
|
2077
|
+
await client.execute(
|
|
2078
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
|
|
2079
|
+
ON memories(content_hash, agent_id, project_name, memory_type)
|
|
2080
|
+
WHERE content_hash IS NOT NULL`
|
|
2081
|
+
);
|
|
2082
|
+
} catch {
|
|
2083
|
+
}
|
|
2076
2084
|
await client.executeMultiple(`
|
|
2077
2085
|
CREATE TABLE IF NOT EXISTS entities (
|
|
2078
2086
|
id TEXT PRIMARY KEY,
|
|
@@ -2742,7 +2750,8 @@ async function ensureShardSchema(client) {
|
|
|
2742
2750
|
}
|
|
2743
2751
|
for (const idx of [
|
|
2744
2752
|
"CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
|
|
2745
|
-
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
|
|
2753
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
|
|
2754
|
+
"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"
|
|
2746
2755
|
]) {
|
|
2747
2756
|
try {
|
|
2748
2757
|
await client.execute(idx);
|
|
@@ -3368,7 +3377,6 @@ import os6 from "os";
|
|
|
3368
3377
|
// src/lib/store.ts
|
|
3369
3378
|
init_memory();
|
|
3370
3379
|
init_database();
|
|
3371
|
-
import { createHash } from "crypto";
|
|
3372
3380
|
|
|
3373
3381
|
// src/lib/keychain.ts
|
|
3374
3382
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
@@ -3601,6 +3609,9 @@ var StateBus = class {
|
|
|
3601
3609
|
};
|
|
3602
3610
|
var orgBus = new StateBus();
|
|
3603
3611
|
|
|
3612
|
+
// src/lib/memory-write-governor.ts
|
|
3613
|
+
import { createHash } from "crypto";
|
|
3614
|
+
|
|
3604
3615
|
// src/lib/store.ts
|
|
3605
3616
|
var INIT_MAX_RETRIES = 3;
|
|
3606
3617
|
var INIT_RETRY_DELAY_MS = 1e3;
|