From fcfa824f54e85ab1d88e43e48b71dbcd48b950b3 Mon Sep 17 00:00:00 2001 From: Yoilun Date: Mon, 25 May 2026 23:48:17 +0800 Subject: [PATCH] fix: exclude conversation threads from agents --- web/src/api/normalizers.js | 27 ++++++++++++++++++++++++-- web/src/api/normalizers.test.mjs | 33 ++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/web/src/api/normalizers.js b/web/src/api/normalizers.js index fd1906a..4a64352 100644 --- a/web/src/api/normalizers.js +++ b/web/src/api/normalizers.js @@ -172,7 +172,7 @@ export function normalizeRuntime(payload = {}) { .filter((edge) => edge.toThreadId) .map((edge) => [edge.toThreadId, normalizeSpawnStatus(edge.reason || edge.status)]), ) - const agents = threads.map((thread) => { + const agents = threads.filter(isRuntimeAgentThread).map((thread) => { const source = normalizeSource(thread.source, payload.source) const threadGoals = goalsByThread.get(thread.id) ?? [] const status = thread.status || spawnStatusByThread.get(thread.id) || threadGoals.find((goal) => goal.status)?.status || 'unknown' @@ -189,7 +189,7 @@ export function normalizeRuntime(payload = {}) { status, statusZh: formatStatus(status), goal: goalText || '没有目标记录', - process: thread.title || thread.preview || 'SQLite 只读快照', + process: describeRuntimeProcess(thread), source: source.label, confidence: source.confidenceLabel, lastActivity: thread.updatedAt || thread.createdAt || '没有时间记录', @@ -209,6 +209,29 @@ export function normalizeRuntime(payload = {}) { } } +function isRuntimeAgentThread(thread) { + return Boolean( + thread?.agentNickname || + thread?.agentRole || + thread?.agentPath || + thread?.threadSource === 'subagent' || + thread?.role, + ) +} + +function describeRuntimeProcess(thread) { + if (thread.threadSource === 'subagent') { + return '子智能体线程' + } + if (thread.agentPath) { + return `智能体配置:${basename(thread.agentPath)}` + } + if (thread.agentNickname || thread.agentRole || thread.role) { + return '智能体线程' + } + return 'SQLite 只读快照' +} + export function filterRuntimeByProject(runtime = normalizeRuntime(), projectPath = '') { const targetPath = normalizePath(projectPath) const agents = runtime.agents.filter((agent) => belongsToProject(agent, targetPath)) diff --git a/web/src/api/normalizers.test.mjs b/web/src/api/normalizers.test.mjs index f5cb0e3..7894354 100644 --- a/web/src/api/normalizers.test.mjs +++ b/web/src/api/normalizers.test.mjs @@ -178,6 +178,39 @@ test('filters runtime to selected project and displays agent names from Codex me assert.equal(projectRuntime.agents[0].statusZh, '运行中') }) +test('does not turn ordinary conversation threads into agents', () => { + const runtime = normalizeRuntime({ + items: [ + { + id: 'conversation', + cwd: '/Users/yoilun', + title: '为什么点 yoilun 这个项目出来的都是对话的信息', + preview: '普通用户对话,不是智能体', + threadSource: 'user', + source: { kind: 'sqlite_table', confidence: 'high' }, + }, + { + id: 'reviewer', + cwd: '/Users/yoilun', + title: '审查 /Users/yoilun 项目', + agentNickname: 'Lorentz', + agentRole: '代码审查员', + threadSource: 'subagent', + source: { kind: 'sqlite_table', confidence: 'high' }, + }, + ], + source: { kind: 'sqlite_readonly', confidence: 'high' }, + }) + + const projectRuntime = filterRuntimeByProject(runtime, '/Users/yoilun') + + assert.equal(runtime.threads.length, 2) + assert.deepEqual(projectRuntime.agents.map((agent) => agent.id), ['reviewer']) + assert.equal(projectRuntime.agents[0].name, 'Lorentz') + assert.equal(projectRuntime.agents[0].process, '子智能体线程') + assert.doesNotMatch(projectRuntime.agents[0].process, /审查 \/Users\/yoilun/) +}) + test('keeps project threads when Codex cwd is an ancestor but metadata names the project path', () => { const runtime = normalizeRuntime({ items: [