@askexenow/exe-os 0.9.34 → 0.9.36
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 +212 -11
- package/dist/bin/backfill-responses.js +212 -11
- package/dist/bin/backfill-vectors.js +14 -3
- package/dist/bin/cleanup-stale-review-tasks.js +224 -12
- package/dist/bin/cli.js +265 -23
- package/dist/bin/exe-agent.js +1 -1
- package/dist/bin/exe-assign.js +217 -12
- package/dist/bin/exe-boot.js +25 -4
- package/dist/bin/exe-call.js +7 -5
- package/dist/bin/exe-dispatch.js +229 -13
- package/dist/bin/exe-doctor.js +14 -3
- package/dist/bin/exe-export-behaviors.js +301 -14
- package/dist/bin/exe-forget.js +245 -21
- package/dist/bin/exe-gateway.js +229 -13
- package/dist/bin/exe-heartbeat.js +224 -12
- package/dist/bin/exe-kill.js +224 -12
- package/dist/bin/exe-launch-agent.js +177 -9
- package/dist/bin/exe-link.js +8 -0
- package/dist/bin/exe-new-employee.js +26 -2
- package/dist/bin/exe-pending-messages.js +224 -12
- package/dist/bin/exe-pending-notifications.js +224 -12
- package/dist/bin/exe-pending-reviews.js +224 -12
- package/dist/bin/exe-rename.js +9 -1
- package/dist/bin/exe-review.js +224 -12
- package/dist/bin/exe-search.js +246 -21
- package/dist/bin/exe-session-cleanup.js +229 -13
- package/dist/bin/exe-start-codex.js +161 -5
- package/dist/bin/exe-start-opencode.js +172 -5
- package/dist/bin/exe-status.js +224 -12
- package/dist/bin/exe-team.js +224 -12
- package/dist/bin/git-sweep.js +229 -13
- package/dist/bin/graph-backfill.js +94 -3
- package/dist/bin/graph-export.js +224 -12
- package/dist/bin/install.js +25 -1
- package/dist/bin/intercom-check.js +229 -13
- package/dist/bin/scan-tasks.js +229 -13
- package/dist/bin/setup.js +15 -5
- package/dist/bin/shard-migrate.js +94 -3
- package/dist/gateway/index.js +229 -13
- package/dist/hooks/bug-report-worker.js +229 -13
- package/dist/hooks/codex-stop-task-finalizer.js +224 -12
- package/dist/hooks/commit-complete.js +229 -13
- package/dist/hooks/error-recall.js +246 -21
- package/dist/hooks/ingest.js +224 -12
- package/dist/hooks/instructions-loaded.js +224 -12
- package/dist/hooks/notification.js +224 -12
- package/dist/hooks/post-compact.js +224 -12
- package/dist/hooks/post-tool-combined.js +246 -21
- package/dist/hooks/pre-compact.js +229 -13
- package/dist/hooks/pre-tool-use.js +234 -18
- package/dist/hooks/prompt-submit.js +346 -23
- package/dist/hooks/session-end.js +229 -13
- package/dist/hooks/session-start.js +418 -42
- package/dist/hooks/stop.js +224 -12
- package/dist/hooks/subagent-stop.js +224 -12
- package/dist/hooks/summary-worker.js +15 -2
- package/dist/index.js +229 -13
- 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/employee-templates.js +7 -5
- package/dist/lib/exe-daemon.js +1776 -1433
- package/dist/lib/hybrid-search.js +246 -21
- package/dist/lib/schedules.js +14 -3
- package/dist/lib/store.js +217 -12
- package/dist/lib/tasks.js +5 -1
- package/dist/lib/tmux-routing.js +5 -1
- package/dist/mcp/server.js +331 -37
- package/dist/mcp/tools/create-task.js +5 -1
- package/dist/mcp/tools/update-task.js +5 -1
- package/dist/runtime/index.js +229 -13
- package/dist/tui/App.js +229 -13
- package/package.json +1 -1
- package/src/commands/exe/save.md +48 -0
package/dist/mcp/server.js
CHANGED
|
@@ -2720,6 +2720,14 @@ async function ensureSchema() {
|
|
|
2720
2720
|
);
|
|
2721
2721
|
} catch {
|
|
2722
2722
|
}
|
|
2723
|
+
try {
|
|
2724
|
+
await client.execute(
|
|
2725
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
|
|
2726
|
+
ON memories(content_hash, agent_id, project_name, memory_type)
|
|
2727
|
+
WHERE content_hash IS NOT NULL`
|
|
2728
|
+
);
|
|
2729
|
+
} catch {
|
|
2730
|
+
}
|
|
2723
2731
|
await client.executeMultiple(`
|
|
2724
2732
|
CREATE TABLE IF NOT EXISTS entities (
|
|
2725
2733
|
id TEXT PRIMARY KEY,
|
|
@@ -3580,6 +3588,197 @@ var init_state_bus = __esm({
|
|
|
3580
3588
|
}
|
|
3581
3589
|
});
|
|
3582
3590
|
|
|
3591
|
+
// src/lib/memory-write-governor.ts
|
|
3592
|
+
import { createHash } from "crypto";
|
|
3593
|
+
function normalizeMemoryText(text) {
|
|
3594
|
+
return text.replace(/\r\n/g, "\n").replace(/[ \t]+$/gm, "").replace(/\n{4,}/g, "\n\n\n").trim();
|
|
3595
|
+
}
|
|
3596
|
+
function classifyMemoryType(input) {
|
|
3597
|
+
if (input.memory_type && input.memory_type.trim()) return input.memory_type.trim();
|
|
3598
|
+
const tool = input.tool_name.toLowerCase();
|
|
3599
|
+
const text = input.raw_text.toLowerCase();
|
|
3600
|
+
if (tool.includes("store_decision") || tool.includes("decision")) return "decision";
|
|
3601
|
+
if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
|
|
3602
|
+
if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
|
|
3603
|
+
if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
|
|
3604
|
+
if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
|
|
3605
|
+
if (tool === "store_memory" || tool === "manual") return "observation";
|
|
3606
|
+
return "raw";
|
|
3607
|
+
}
|
|
3608
|
+
function shouldDropMemory(text) {
|
|
3609
|
+
const normalized = normalizeMemoryText(text);
|
|
3610
|
+
if (normalized.length < 10) return { drop: true, reason: "too_short" };
|
|
3611
|
+
if (NOISE_DROP_PATTERNS.some((pattern) => pattern.test(normalized))) {
|
|
3612
|
+
return { drop: true, reason: "known_boilerplate_noise" };
|
|
3613
|
+
}
|
|
3614
|
+
return { drop: false };
|
|
3615
|
+
}
|
|
3616
|
+
function shouldSkipEmbedding(input) {
|
|
3617
|
+
const type = classifyMemoryType(input);
|
|
3618
|
+
if (HIGH_VALUE_SUPERSESSION_TYPES.has(type)) return false;
|
|
3619
|
+
if (type === "raw" && input.raw_text.length > 2e4) return true;
|
|
3620
|
+
if (SKIP_EMBED_PATTERNS.some((pattern) => pattern.test(input.raw_text))) return true;
|
|
3621
|
+
return false;
|
|
3622
|
+
}
|
|
3623
|
+
function hashMemoryContent(text) {
|
|
3624
|
+
return createHash("sha256").update(normalizeMemoryText(text)).digest("hex");
|
|
3625
|
+
}
|
|
3626
|
+
function scopedDedupArgs(input) {
|
|
3627
|
+
return [input.contentHash, input.agentId, input.projectName, input.memoryType];
|
|
3628
|
+
}
|
|
3629
|
+
function governMemoryRecord(record) {
|
|
3630
|
+
const normalized = normalizeMemoryText(record.raw_text);
|
|
3631
|
+
const memoryType = classifyMemoryType({
|
|
3632
|
+
raw_text: normalized,
|
|
3633
|
+
agent_id: record.agent_id,
|
|
3634
|
+
project_name: record.project_name,
|
|
3635
|
+
tool_name: record.tool_name,
|
|
3636
|
+
memory_type: record.memory_type
|
|
3637
|
+
});
|
|
3638
|
+
const drop = shouldDropMemory(normalized);
|
|
3639
|
+
const skipEmbedding = shouldSkipEmbedding({
|
|
3640
|
+
raw_text: normalized,
|
|
3641
|
+
agent_id: record.agent_id,
|
|
3642
|
+
project_name: record.project_name,
|
|
3643
|
+
tool_name: record.tool_name,
|
|
3644
|
+
memory_type: memoryType
|
|
3645
|
+
});
|
|
3646
|
+
return {
|
|
3647
|
+
record: {
|
|
3648
|
+
...record,
|
|
3649
|
+
raw_text: normalized,
|
|
3650
|
+
memory_type: memoryType,
|
|
3651
|
+
vector: skipEmbedding ? null : record.vector
|
|
3652
|
+
},
|
|
3653
|
+
contentHash: hashMemoryContent(normalized),
|
|
3654
|
+
shouldDrop: drop.drop,
|
|
3655
|
+
dropReason: drop.reason,
|
|
3656
|
+
skipEmbedding,
|
|
3657
|
+
hygiene: {
|
|
3658
|
+
dedup: true,
|
|
3659
|
+
supersession: HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)
|
|
3660
|
+
}
|
|
3661
|
+
};
|
|
3662
|
+
}
|
|
3663
|
+
async function findScopedDuplicate(input) {
|
|
3664
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3665
|
+
const client = getClient2();
|
|
3666
|
+
const args = scopedDedupArgs(input);
|
|
3667
|
+
let sql = `SELECT id FROM memories
|
|
3668
|
+
WHERE content_hash = ?
|
|
3669
|
+
AND agent_id = ?
|
|
3670
|
+
AND project_name = ?
|
|
3671
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
3672
|
+
AND COALESCE(status, 'active') != 'deleted'`;
|
|
3673
|
+
if (input.excludeId) {
|
|
3674
|
+
sql += " AND id != ?";
|
|
3675
|
+
args.push(input.excludeId);
|
|
3676
|
+
}
|
|
3677
|
+
sql += " ORDER BY timestamp DESC LIMIT 1";
|
|
3678
|
+
const result = await client.execute({ sql, args });
|
|
3679
|
+
return result.rows[0]?.id ? String(result.rows[0].id) : null;
|
|
3680
|
+
}
|
|
3681
|
+
async function runPostWriteMemoryHygiene(memoryId) {
|
|
3682
|
+
try {
|
|
3683
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3684
|
+
const client = getClient2();
|
|
3685
|
+
const current = await client.execute({
|
|
3686
|
+
sql: `SELECT id, agent_id, project_name, memory_type, content_hash, supersedes_id,
|
|
3687
|
+
importance, timestamp
|
|
3688
|
+
FROM memories
|
|
3689
|
+
WHERE id = ?
|
|
3690
|
+
LIMIT 1`,
|
|
3691
|
+
args: [memoryId]
|
|
3692
|
+
});
|
|
3693
|
+
const row = current.rows[0];
|
|
3694
|
+
if (!row) return;
|
|
3695
|
+
const memoryType = String(row.memory_type ?? "raw");
|
|
3696
|
+
const contentHash2 = row.content_hash ? String(row.content_hash) : null;
|
|
3697
|
+
const agentId = String(row.agent_id);
|
|
3698
|
+
const projectName = String(row.project_name);
|
|
3699
|
+
if (contentHash2) {
|
|
3700
|
+
await client.execute({
|
|
3701
|
+
sql: `UPDATE memories
|
|
3702
|
+
SET status = 'deleted',
|
|
3703
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
3704
|
+
WHERE id != ?
|
|
3705
|
+
AND content_hash = ?
|
|
3706
|
+
AND agent_id = ?
|
|
3707
|
+
AND project_name = ?
|
|
3708
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
3709
|
+
AND COALESCE(status, 'active') = 'active'`,
|
|
3710
|
+
args: [memoryId, contentHash2, agentId, projectName, memoryType]
|
|
3711
|
+
});
|
|
3712
|
+
}
|
|
3713
|
+
const supersedesId = row.supersedes_id ? String(row.supersedes_id) : null;
|
|
3714
|
+
if (supersedesId && HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)) {
|
|
3715
|
+
const old = await client.execute({
|
|
3716
|
+
sql: `SELECT importance FROM memories WHERE id = ? LIMIT 1`,
|
|
3717
|
+
args: [supersedesId]
|
|
3718
|
+
});
|
|
3719
|
+
const oldImportance = Number(old.rows[0]?.importance ?? 0);
|
|
3720
|
+
const newImportance = Number(row.importance ?? 0);
|
|
3721
|
+
await client.batch([
|
|
3722
|
+
{
|
|
3723
|
+
sql: `UPDATE memories
|
|
3724
|
+
SET status = 'archived',
|
|
3725
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
3726
|
+
WHERE id = ?`,
|
|
3727
|
+
args: [supersedesId]
|
|
3728
|
+
},
|
|
3729
|
+
{
|
|
3730
|
+
sql: `UPDATE memories
|
|
3731
|
+
SET importance = MAX(COALESCE(importance, 5), ?),
|
|
3732
|
+
parent_memory_id = COALESCE(parent_memory_id, ?)
|
|
3733
|
+
WHERE id = ?`,
|
|
3734
|
+
args: [Math.max(oldImportance, newImportance), supersedesId, memoryId]
|
|
3735
|
+
}
|
|
3736
|
+
], "write");
|
|
3737
|
+
}
|
|
3738
|
+
} catch (err) {
|
|
3739
|
+
process.stderr.write(
|
|
3740
|
+
`[memory-governor] post-write hygiene failed for ${memoryId}: ${err instanceof Error ? err.message : String(err)}
|
|
3741
|
+
`
|
|
3742
|
+
);
|
|
3743
|
+
}
|
|
3744
|
+
}
|
|
3745
|
+
function schedulePostWriteMemoryHygiene(memoryIds) {
|
|
3746
|
+
if (process.env.EXE_SKIP_MEMORY_HYGIENE === "1") return;
|
|
3747
|
+
if (memoryIds.length === 0) return;
|
|
3748
|
+
const run = () => {
|
|
3749
|
+
void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
|
|
3750
|
+
};
|
|
3751
|
+
if (typeof setImmediate === "function") setImmediate(run);
|
|
3752
|
+
else setTimeout(run, 0);
|
|
3753
|
+
}
|
|
3754
|
+
var HIGH_VALUE_SUPERSESSION_TYPES, NOISE_DROP_PATTERNS, SKIP_EMBED_PATTERNS;
|
|
3755
|
+
var init_memory_write_governor = __esm({
|
|
3756
|
+
"src/lib/memory-write-governor.ts"() {
|
|
3757
|
+
"use strict";
|
|
3758
|
+
HIGH_VALUE_SUPERSESSION_TYPES = /* @__PURE__ */ new Set([
|
|
3759
|
+
"decision",
|
|
3760
|
+
"adr",
|
|
3761
|
+
"behavior",
|
|
3762
|
+
"procedure"
|
|
3763
|
+
]);
|
|
3764
|
+
NOISE_DROP_PATTERNS = [
|
|
3765
|
+
/^\s*\[📋\s+\d+\s+reviews?\s+pending\b/im,
|
|
3766
|
+
/^\s*<system-reminder>[\s\S]*?<\/system-reminder>\s*$/im,
|
|
3767
|
+
/^\s*The UserPromptSubmit hook checks the DB for new tasks/im,
|
|
3768
|
+
/^\s*Intercom is a speedup, not delivery/im,
|
|
3769
|
+
/^\s*Context bar reads as USAGE not remaining/im
|
|
3770
|
+
];
|
|
3771
|
+
SKIP_EMBED_PATTERNS = [
|
|
3772
|
+
/tmux capture-pane\b/i,
|
|
3773
|
+
/docker ps\b/i,
|
|
3774
|
+
/docker images\b/i,
|
|
3775
|
+
/git status\b/i,
|
|
3776
|
+
/grep .*node_modules/i,
|
|
3777
|
+
/npm (install|ci)\b[\s\S]*(added \d+ packages|audited \d+ packages)/i
|
|
3778
|
+
];
|
|
3779
|
+
}
|
|
3780
|
+
});
|
|
3781
|
+
|
|
3583
3782
|
// src/lib/shard-manager.ts
|
|
3584
3783
|
var shard_manager_exports = {};
|
|
3585
3784
|
__export(shard_manager_exports, {
|
|
@@ -3744,7 +3943,8 @@ async function ensureShardSchema(client) {
|
|
|
3744
3943
|
}
|
|
3745
3944
|
for (const idx of [
|
|
3746
3945
|
"CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
|
|
3747
|
-
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
|
|
3946
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
|
|
3947
|
+
"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"
|
|
3748
3948
|
]) {
|
|
3749
3949
|
try {
|
|
3750
3950
|
await client.execute(idx);
|
|
@@ -3938,7 +4138,7 @@ var init_platform_procedures = __esm({
|
|
|
3938
4138
|
title: "Chain of command \u2014 who talks to whom",
|
|
3939
4139
|
domain: "workflow",
|
|
3940
4140
|
priority: "p0",
|
|
3941
|
-
content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the
|
|
4141
|
+
content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
|
|
3942
4142
|
},
|
|
3943
4143
|
{
|
|
3944
4144
|
title: "Single dispatch path \u2014 create_task only",
|
|
@@ -4169,7 +4369,6 @@ __export(store_exports, {
|
|
|
4169
4369
|
vectorToBlob: () => vectorToBlob,
|
|
4170
4370
|
writeMemory: () => writeMemory
|
|
4171
4371
|
});
|
|
4172
|
-
import { createHash } from "crypto";
|
|
4173
4372
|
function isBusyError2(err) {
|
|
4174
4373
|
if (err instanceof Error) {
|
|
4175
4374
|
const msg = err.message.toLowerCase();
|
|
@@ -4283,17 +4482,24 @@ async function writeMemory(record) {
|
|
|
4283
4482
|
`Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
|
|
4284
4483
|
);
|
|
4285
4484
|
}
|
|
4286
|
-
const
|
|
4287
|
-
if (
|
|
4485
|
+
const governed = governMemoryRecord(record);
|
|
4486
|
+
if (governed.shouldDrop) return;
|
|
4487
|
+
record = governed.record;
|
|
4488
|
+
const contentHash2 = governed.contentHash;
|
|
4489
|
+
const memoryType = record.memory_type ?? "raw";
|
|
4490
|
+
if (_pendingRecords.some(
|
|
4491
|
+
(r) => r.content_hash === contentHash2 && r.agent_id === record.agent_id && r.project_name === record.project_name && (r.memory_type ?? "raw") === memoryType
|
|
4492
|
+
)) {
|
|
4288
4493
|
return;
|
|
4289
4494
|
}
|
|
4290
4495
|
try {
|
|
4291
|
-
const
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4496
|
+
const existing = await findScopedDuplicate({
|
|
4497
|
+
contentHash: contentHash2,
|
|
4498
|
+
agentId: record.agent_id,
|
|
4499
|
+
projectName: record.project_name,
|
|
4500
|
+
memoryType
|
|
4295
4501
|
});
|
|
4296
|
-
if (existing
|
|
4502
|
+
if (existing) return;
|
|
4297
4503
|
} catch {
|
|
4298
4504
|
}
|
|
4299
4505
|
const dbRow = {
|
|
@@ -4324,7 +4530,7 @@ async function writeMemory(record) {
|
|
|
4324
4530
|
tier: record.tier ?? classifyTier(record),
|
|
4325
4531
|
supersedes_id: record.supersedes_id ?? null,
|
|
4326
4532
|
draft: record.draft ? 1 : 0,
|
|
4327
|
-
memory_type:
|
|
4533
|
+
memory_type: memoryType,
|
|
4328
4534
|
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
4329
4535
|
content_hash: contentHash2,
|
|
4330
4536
|
intent: record.intent ?? null,
|
|
@@ -4483,6 +4689,7 @@ async function flushBatch() {
|
|
|
4483
4689
|
const globalClient = getClient();
|
|
4484
4690
|
const globalStmts = batch.map(buildStmt);
|
|
4485
4691
|
await globalClient.batch(globalStmts, "write");
|
|
4692
|
+
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
4486
4693
|
_pendingRecords.splice(0, batch.length);
|
|
4487
4694
|
try {
|
|
4488
4695
|
const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
@@ -4603,7 +4810,11 @@ async function searchMemories(queryVector, agentId, options) {
|
|
|
4603
4810
|
sql += ` AND timestamp >= ?`;
|
|
4604
4811
|
args.push(options.since);
|
|
4605
4812
|
}
|
|
4606
|
-
if (options?.
|
|
4813
|
+
if (options?.memoryTypes && options.memoryTypes.length > 0) {
|
|
4814
|
+
const uniqueTypes = [...new Set(options.memoryTypes)];
|
|
4815
|
+
sql += ` AND memory_type IN (${uniqueTypes.map(() => "?").join(",")})`;
|
|
4816
|
+
args.push(...uniqueTypes);
|
|
4817
|
+
} else if (options?.memoryType) {
|
|
4607
4818
|
sql += ` AND memory_type = ?`;
|
|
4608
4819
|
args.push(options.memoryType);
|
|
4609
4820
|
}
|
|
@@ -4741,6 +4952,7 @@ var init_store = __esm({
|
|
|
4741
4952
|
init_keychain();
|
|
4742
4953
|
init_config();
|
|
4743
4954
|
init_state_bus();
|
|
4955
|
+
init_memory_write_governor();
|
|
4744
4956
|
INIT_MAX_RETRIES = 3;
|
|
4745
4957
|
INIT_RETRY_DELAY_MS = 1e3;
|
|
4746
4958
|
_pendingRecords = [];
|
|
@@ -5832,6 +6044,17 @@ __export(hybrid_search_exports, {
|
|
|
5832
6044
|
rrfMerge: () => rrfMerge,
|
|
5833
6045
|
rrfMergeMulti: () => rrfMergeMulti
|
|
5834
6046
|
});
|
|
6047
|
+
function appendMemoryTypeFilter(sql, args, column, options) {
|
|
6048
|
+
if (options?.memoryTypes && options.memoryTypes.length > 0) {
|
|
6049
|
+
const uniqueTypes = [...new Set(options.memoryTypes)];
|
|
6050
|
+
sql += ` AND ${column} IN (${uniqueTypes.map(() => "?").join(",")})`;
|
|
6051
|
+
args.push(...uniqueTypes);
|
|
6052
|
+
} else if (options?.memoryType) {
|
|
6053
|
+
sql += ` AND ${column} = ?`;
|
|
6054
|
+
args.push(options.memoryType);
|
|
6055
|
+
}
|
|
6056
|
+
return sql;
|
|
6057
|
+
}
|
|
5835
6058
|
async function hybridSearch(queryText, agentId, options) {
|
|
5836
6059
|
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
5837
6060
|
const config2 = await loadConfig2();
|
|
@@ -6060,6 +6283,7 @@ async function estimateCardinality(agentId, options) {
|
|
|
6060
6283
|
sql += ` AND timestamp >= ?`;
|
|
6061
6284
|
args.push(options.since);
|
|
6062
6285
|
}
|
|
6286
|
+
sql = appendMemoryTypeFilter(sql, args, "memory_type", options);
|
|
6063
6287
|
try {
|
|
6064
6288
|
const result = await client.execute({ sql, args });
|
|
6065
6289
|
return Number(result.rows[0]?.cnt) || 0;
|
|
@@ -6181,10 +6405,7 @@ async function ftsQuery(client, matchExpr, agentId, options, limit) {
|
|
|
6181
6405
|
sql += ` AND m.timestamp >= ?`;
|
|
6182
6406
|
args.push(options.since);
|
|
6183
6407
|
}
|
|
6184
|
-
|
|
6185
|
-
sql += ` AND m.memory_type = ?`;
|
|
6186
|
-
args.push(options.memoryType);
|
|
6187
|
-
}
|
|
6408
|
+
sql = appendMemoryTypeFilter(sql, args, "m.memory_type", options);
|
|
6188
6409
|
sql += ` ORDER BY rank LIMIT ?`;
|
|
6189
6410
|
args.push(limit);
|
|
6190
6411
|
const result = await client.execute({ sql, args });
|
|
@@ -6241,9 +6462,16 @@ async function recentRecords(agentId, options, limit, textFilter) {
|
|
|
6241
6462
|
AND timestamp >= ? AND timestamp <= ?
|
|
6242
6463
|
AND COALESCE(status, 'active') = 'active'
|
|
6243
6464
|
AND ${options?.includeRaw === false ? "COALESCE(memory_type, 'raw') != 'raw'" : "1 = 1"}
|
|
6465
|
+
${options?.memoryTypes?.length ? `AND memory_type IN (${options.memoryTypes.map(() => "?").join(",")})` : options?.memoryType ? "AND memory_type = ?" : ""}
|
|
6244
6466
|
AND COALESCE(confidence, 0.7) >= 0.3
|
|
6245
6467
|
ORDER BY timestamp DESC LIMIT ?`,
|
|
6246
|
-
args: [
|
|
6468
|
+
args: [
|
|
6469
|
+
agentId,
|
|
6470
|
+
windowStart,
|
|
6471
|
+
killedAt,
|
|
6472
|
+
...options?.memoryTypes?.length ? [...new Set(options.memoryTypes)] : options?.memoryType ? [options.memoryType] : [],
|
|
6473
|
+
boundarySlots
|
|
6474
|
+
]
|
|
6247
6475
|
});
|
|
6248
6476
|
for (const row of boundaryResult.rows) {
|
|
6249
6477
|
sessionBoundaryMemories.push(rowToMemoryRecord(row));
|
|
@@ -6289,10 +6517,7 @@ async function recentRecords(agentId, options, limit, textFilter) {
|
|
|
6289
6517
|
sql += ` AND timestamp >= ?`;
|
|
6290
6518
|
args.push(options.since);
|
|
6291
6519
|
}
|
|
6292
|
-
|
|
6293
|
-
sql += ` AND memory_type = ?`;
|
|
6294
|
-
args.push(options.memoryType);
|
|
6295
|
-
}
|
|
6520
|
+
sql = appendMemoryTypeFilter(sql, args, "memory_type", options);
|
|
6296
6521
|
if (textFilter) {
|
|
6297
6522
|
sql += ` AND raw_text LIKE '%' || ? || '%'`;
|
|
6298
6523
|
args.push(textFilter);
|
|
@@ -8973,7 +9198,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
8973
9198
|
}
|
|
8974
9199
|
if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
|
|
8975
9200
|
if (agentRtConfig.runtime === "claude" && agentRtConfig.model) {
|
|
8976
|
-
|
|
9201
|
+
let ccModel = agentRtConfig.model.replace(/(\d+)\.(\d+)/g, "$1-$2");
|
|
9202
|
+
if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
|
|
9203
|
+
ccModel += "[1m]";
|
|
9204
|
+
}
|
|
9205
|
+
envPrefix = `${envPrefix} ANTHROPIC_MODEL=${ccModel}`;
|
|
8977
9206
|
}
|
|
8978
9207
|
}
|
|
8979
9208
|
let spawnCommand;
|
|
@@ -12474,6 +12703,63 @@ init_hybrid_search();
|
|
|
12474
12703
|
init_store();
|
|
12475
12704
|
init_active_agent();
|
|
12476
12705
|
import { z } from "zod";
|
|
12706
|
+
|
|
12707
|
+
// src/lib/memory-retrieval-modes.ts
|
|
12708
|
+
var RETRIEVAL_MODES = [
|
|
12709
|
+
"all",
|
|
12710
|
+
"decisions_only",
|
|
12711
|
+
"behaviors_only",
|
|
12712
|
+
"procedures_only",
|
|
12713
|
+
"operational",
|
|
12714
|
+
"no_raw",
|
|
12715
|
+
"recent_high_value"
|
|
12716
|
+
];
|
|
12717
|
+
var RETRIEVAL_MODE_DESCRIPTIONS = {
|
|
12718
|
+
all: "All visible memory types.",
|
|
12719
|
+
decisions_only: "Only decisions and ADRs.",
|
|
12720
|
+
behaviors_only: "Only durable behavior/correction memories.",
|
|
12721
|
+
procedures_only: "Only procedures/runbooks.",
|
|
12722
|
+
operational: "Raw operational/debug/tool output.",
|
|
12723
|
+
no_raw: "All non-raw memory types.",
|
|
12724
|
+
recent_high_value: "High-value durable memory types, intended for recency recovery."
|
|
12725
|
+
};
|
|
12726
|
+
function applyRetrievalMode(base, mode) {
|
|
12727
|
+
if (!mode || mode === "all") return base;
|
|
12728
|
+
const next = { ...base };
|
|
12729
|
+
switch (mode) {
|
|
12730
|
+
case "decisions_only":
|
|
12731
|
+
next.memoryTypes = ["decision", "adr"];
|
|
12732
|
+
next.includeRaw = false;
|
|
12733
|
+
break;
|
|
12734
|
+
case "behaviors_only":
|
|
12735
|
+
next.memoryTypes = ["behavior"];
|
|
12736
|
+
next.includeRaw = false;
|
|
12737
|
+
break;
|
|
12738
|
+
case "procedures_only":
|
|
12739
|
+
next.memoryTypes = ["procedure"];
|
|
12740
|
+
next.includeRaw = false;
|
|
12741
|
+
break;
|
|
12742
|
+
case "operational":
|
|
12743
|
+
next.memoryTypes = ["raw", "observation"];
|
|
12744
|
+
next.includeRaw = true;
|
|
12745
|
+
break;
|
|
12746
|
+
case "no_raw":
|
|
12747
|
+
next.includeRaw = false;
|
|
12748
|
+
break;
|
|
12749
|
+
case "recent_high_value":
|
|
12750
|
+
next.memoryTypes = ["decision", "adr", "behavior", "procedure"];
|
|
12751
|
+
next.includeRaw = false;
|
|
12752
|
+
break;
|
|
12753
|
+
default:
|
|
12754
|
+
return next;
|
|
12755
|
+
}
|
|
12756
|
+
return next;
|
|
12757
|
+
}
|
|
12758
|
+
function formatRetrievalModes() {
|
|
12759
|
+
return RETRIEVAL_MODES.map((mode) => `${mode}: ${RETRIEVAL_MODE_DESCRIPTIONS[mode]}`).join("; ");
|
|
12760
|
+
}
|
|
12761
|
+
|
|
12762
|
+
// src/mcp/tools/recall-my-memory.ts
|
|
12477
12763
|
function formatSourceLine(record) {
|
|
12478
12764
|
const doc2 = record.document_metadata;
|
|
12479
12765
|
if (!doc2) return "";
|
|
@@ -12509,7 +12795,8 @@ function registerRecallMyMemory(server2) {
|
|
|
12509
12795
|
),
|
|
12510
12796
|
include_source: z.boolean().optional().default(false).describe(
|
|
12511
12797
|
"When true, attach parent document metadata (filename, mime, source_type) to each result. Default false."
|
|
12512
|
-
)
|
|
12798
|
+
),
|
|
12799
|
+
retrieval_mode: z.enum(RETRIEVAL_MODES).optional().default("all").describe(`Typed retrieval mode. ${formatRetrievalModes()}`)
|
|
12513
12800
|
}
|
|
12514
12801
|
},
|
|
12515
12802
|
async ({
|
|
@@ -12523,7 +12810,8 @@ function registerRecallMyMemory(server2) {
|
|
|
12523
12810
|
include_archived,
|
|
12524
12811
|
workspace_id,
|
|
12525
12812
|
user_id,
|
|
12526
|
-
include_source
|
|
12813
|
+
include_source,
|
|
12814
|
+
retrieval_mode
|
|
12527
12815
|
}) => {
|
|
12528
12816
|
try {
|
|
12529
12817
|
if (!recent && !query) {
|
|
@@ -12533,7 +12821,7 @@ function registerRecallMyMemory(server2) {
|
|
|
12533
12821
|
};
|
|
12534
12822
|
}
|
|
12535
12823
|
const { agentId } = getActiveAgent();
|
|
12536
|
-
const searchOptions = {
|
|
12824
|
+
const searchOptions = applyRetrievalMode({
|
|
12537
12825
|
projectName: project_name,
|
|
12538
12826
|
hasError: has_error,
|
|
12539
12827
|
toolName: tool_name,
|
|
@@ -12544,7 +12832,7 @@ function registerRecallMyMemory(server2) {
|
|
|
12544
12832
|
includeSource: include_source,
|
|
12545
12833
|
includeDrafts: true,
|
|
12546
12834
|
...user_id !== void 0 ? { userId: user_id } : {}
|
|
12547
|
-
};
|
|
12835
|
+
}, retrieval_mode);
|
|
12548
12836
|
let results;
|
|
12549
12837
|
if (recent) {
|
|
12550
12838
|
results = await recentRecords(agentId, searchOptions, limit, query);
|
|
@@ -12632,10 +12920,11 @@ function registerAskTeamMemory(server2) {
|
|
|
12632
12920
|
),
|
|
12633
12921
|
include_raw: z2.boolean().optional().default(false).describe(
|
|
12634
12922
|
"Include raw technical memories when ACL allows it (default: non-raw memories only for cross-agent reads)"
|
|
12635
|
-
)
|
|
12923
|
+
),
|
|
12924
|
+
retrieval_mode: z2.enum(RETRIEVAL_MODES).optional().default("all").describe(`Typed retrieval mode. Raw visibility is still ACL-gated. ${formatRetrievalModes()}`)
|
|
12636
12925
|
}
|
|
12637
12926
|
},
|
|
12638
|
-
async ({ team_member, query, project_name, limit, since, include_archived, include_raw: _include_raw }) => {
|
|
12927
|
+
async ({ team_member, query, project_name, limit, since, include_archived, include_raw: _include_raw, retrieval_mode }) => {
|
|
12639
12928
|
try {
|
|
12640
12929
|
const { agentId: queryingAgentId, agentRole: queryingAgentRole } = getActiveAgent();
|
|
12641
12930
|
const employees = loadEmployeesSync();
|
|
@@ -12644,16 +12933,18 @@ function registerAskTeamMemory(server2) {
|
|
|
12644
12933
|
const targetRole = targetEmployee?.role ?? "";
|
|
12645
12934
|
const hasRawAccess = canSeeRaw(queryingRole, targetRole);
|
|
12646
12935
|
const effectiveIncludeRaw = _include_raw && hasRawAccess;
|
|
12647
|
-
const
|
|
12936
|
+
const requestedMode = retrieval_mode ?? "all";
|
|
12937
|
+
const safeMode = !effectiveIncludeRaw && ["all", "operational"].includes(requestedMode) ? "no_raw" : requestedMode;
|
|
12938
|
+
const searchOptions = applyRetrievalMode({
|
|
12648
12939
|
projectName: project_name,
|
|
12649
12940
|
limit,
|
|
12650
12941
|
since,
|
|
12651
12942
|
includeArchived: include_archived,
|
|
12652
12943
|
includeDrafts: false,
|
|
12653
|
-
includeRaw: effectiveIncludeRaw
|
|
12654
|
-
|
|
12655
|
-
|
|
12656
|
-
|
|
12944
|
+
includeRaw: effectiveIncludeRaw
|
|
12945
|
+
}, safeMode);
|
|
12946
|
+
if (!effectiveIncludeRaw) searchOptions.includeRaw = false;
|
|
12947
|
+
const results = await hybridSearch(query, team_member, searchOptions);
|
|
12657
12948
|
if (results.length === 0) {
|
|
12658
12949
|
return {
|
|
12659
12950
|
content: [
|
|
@@ -15484,7 +15775,7 @@ created_by: system
|
|
|
15484
15775
|
---
|
|
15485
15776
|
## Identity
|
|
15486
15777
|
|
|
15487
|
-
You are {{agent_name}}, the
|
|
15778
|
+
You are {{agent_name}}, the {{title}} at {{company_name}}.
|
|
15488
15779
|
|
|
15489
15780
|
You are {{founder_name}}'s most reliable teammate in business \u2014 the knowledgeable older sibling who has been through it all. You have seen projects succeed and fail. You know what matters and what is noise. You do not get anxious about problems; you see them coming, stay calm, and handle them.
|
|
15490
15781
|
|
|
@@ -15571,11 +15862,13 @@ All memory, tasks, behaviors, documents, and wiki content belonging to {{company
|
|
|
15571
15862
|
var CLIENT_COO_PLACEHOLDERS = [
|
|
15572
15863
|
"agent_name",
|
|
15573
15864
|
"company_name",
|
|
15574
|
-
"founder_name"
|
|
15865
|
+
"founder_name",
|
|
15866
|
+
"title"
|
|
15575
15867
|
];
|
|
15576
15868
|
function renderClientCOOTemplate(vars) {
|
|
15869
|
+
const resolved = { ...vars, title: vars.title || "Chief Operating Officer" };
|
|
15577
15870
|
for (const key of CLIENT_COO_PLACEHOLDERS) {
|
|
15578
|
-
const value =
|
|
15871
|
+
const value = resolved[key];
|
|
15579
15872
|
if (typeof value !== "string" || value.length === 0) {
|
|
15580
15873
|
throw new Error(
|
|
15581
15874
|
`renderClientCOOTemplate: missing required variable "${key}"`
|
|
@@ -15584,7 +15877,7 @@ function renderClientCOOTemplate(vars) {
|
|
|
15584
15877
|
}
|
|
15585
15878
|
let out = CLIENT_COO_TEMPLATE;
|
|
15586
15879
|
for (const key of CLIENT_COO_PLACEHOLDERS) {
|
|
15587
|
-
out = out.split(`{{${key}}}`).join(
|
|
15880
|
+
out = out.split(`{{${key}}}`).join(resolved[key]);
|
|
15588
15881
|
}
|
|
15589
15882
|
if (vars.industry_context) {
|
|
15590
15883
|
out += "\n" + vars.industry_context;
|
|
@@ -15750,6 +16043,7 @@ ${vars}`);
|
|
|
15750
16043
|
agent_name,
|
|
15751
16044
|
company_name,
|
|
15752
16045
|
founder_name,
|
|
16046
|
+
title: "Chief Operating Officer",
|
|
15753
16047
|
industry_context: pack.identityContext ?? void 0
|
|
15754
16048
|
});
|
|
15755
16049
|
cooSummaryLines = [
|
|
@@ -2628,7 +2628,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2628
2628
|
}
|
|
2629
2629
|
if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
|
|
2630
2630
|
if (agentRtConfig.runtime === "claude" && agentRtConfig.model) {
|
|
2631
|
-
|
|
2631
|
+
let ccModel = agentRtConfig.model.replace(/(\d+)\.(\d+)/g, "$1-$2");
|
|
2632
|
+
if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
|
|
2633
|
+
ccModel += "[1m]";
|
|
2634
|
+
}
|
|
2635
|
+
envPrefix = `${envPrefix} ANTHROPIC_MODEL=${ccModel}`;
|
|
2632
2636
|
}
|
|
2633
2637
|
}
|
|
2634
2638
|
let spawnCommand;
|
|
@@ -2392,7 +2392,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2392
2392
|
}
|
|
2393
2393
|
if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
|
|
2394
2394
|
if (agentRtConfig.runtime === "claude" && agentRtConfig.model) {
|
|
2395
|
-
|
|
2395
|
+
let ccModel = agentRtConfig.model.replace(/(\d+)\.(\d+)/g, "$1-$2");
|
|
2396
|
+
if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
|
|
2397
|
+
ccModel += "[1m]";
|
|
2398
|
+
}
|
|
2399
|
+
envPrefix = `${envPrefix} ANTHROPIC_MODEL=${ccModel}`;
|
|
2396
2400
|
}
|
|
2397
2401
|
}
|
|
2398
2402
|
let spawnCommand;
|