From 6429c76ac7918503303df2e36a12b80e3e0d302c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Thu, 16 Apr 2026 22:56:16 -0400 Subject: [PATCH] fix(run-housekeeping): gate auto knowledge_base writes on task type or department --- src/main/run-housekeeping.ts | 58 ++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/src/main/run-housekeeping.ts b/src/main/run-housekeeping.ts index 850a403f..1e2e7271 100644 --- a/src/main/run-housekeeping.ts +++ b/src/main/run-housekeeping.ts @@ -7,6 +7,53 @@ interface RunHousekeepingDeps { threadIntegration: ThreadIntegrationService; } +/** + * Task types whose successful runs produce durable lessons worth capturing + * into the knowledge base. Ad-hoc code tasks, chores, and one-off ops + * produce runtime noise that pollutes the knowledge table if auto-saved. + */ +const KNOWLEDGE_PRODUCING_TASK_TYPES: ReadonlySet = new Set([ + "research", + "analysis", + "planning", + "strategy", + "review", +]); + +/** + * Agent departments whose output is routinely curated as corporate + * knowledge regardless of task type. + */ +const KNOWLEDGE_PRODUCING_DEPARTMENTS: ReadonlySet = new Set([ + "research", + "strategy", + "management", +]); + +function shouldProduceKnowledge( + db: AppDatabase, + taskId: string, + agentId: string, +): boolean { + try { + const taskTypeRow = db.queryAll<{ taskType: string | null }>( + "SELECT task_type as taskType FROM tasks WHERE id = ? LIMIT 1", + taskId, + )[0]; + if (taskTypeRow?.taskType && KNOWLEDGE_PRODUCING_TASK_TYPES.has(taskTypeRow.taskType)) { + return true; + } + } catch { + // Task deleted; fall through to agent check + } + try { + const agent = db.getAgent(agentId); + return Boolean(agent.department && KNOWLEDGE_PRODUCING_DEPARTMENTS.has(agent.department)); + } catch { + return false; + } +} + export function createRunHousekeeping({ db, logger, threadIntegration }: RunHousekeepingDeps) { return { onRunCompleted( @@ -25,8 +72,15 @@ export function createRunHousekeeping({ db, logger, threadIntegration }: RunHous logger.error(`[run-housekeeping] threadIntegration.onRunFinished failed: ${err instanceof Error ? err.message : String(err)}`); } - // 2. On success with a meaningful summary, create a knowledge candidate - if (status === "succeeded" && summary && summary.length > 50) { + // 2. On success with a meaningful summary, create a knowledge candidate — + // gated on the task type or the producing agent's department so + // ad-hoc runs do not flood the knowledge table with summaries. + if ( + status === "succeeded" && + summary && + summary.length > 50 && + shouldProduceKnowledge(db, taskId, agentId) + ) { try { let topic = `Run ${runId.slice(0, 8)}`; try {