fix: keep chat replies out of results
Completed local and channel replies were duplicated into Results as Markdown artifacts, making the panel a second conversation history. Replies now stay in their conversations, legacy duplicates are filtered without deleting data, and standalone images, scheduled jobs, headless delegations, heartbeats, and imports remain visible. Release note: 普通本地与消息通道回复不再重复出现在成果栏;已有重复内容仅从列表隐藏,不会删除历史数据。
This commit is contained in:
@@ -974,19 +974,6 @@ describe('AssistantDatabase', () => {
|
||||
status: 'completed',
|
||||
completedAt: expect.any(String)
|
||||
})
|
||||
const artifact = database.createTextArtifact({
|
||||
projectId: project.id,
|
||||
taskId,
|
||||
title: '发布说明',
|
||||
content: '# 发布说明\n\n内容'
|
||||
})
|
||||
expect(database.listArtifacts(project.id)).toEqual([
|
||||
expect.objectContaining({
|
||||
id: artifact.id,
|
||||
kind: 'markdown',
|
||||
content: '# 发布说明\n\n内容'
|
||||
})
|
||||
])
|
||||
const memory = database.createMemory({
|
||||
scope: 'project',
|
||||
scopeId: project.id,
|
||||
@@ -2205,6 +2192,99 @@ describe('AssistantDatabase', () => {
|
||||
durable.close()
|
||||
})
|
||||
|
||||
it('keeps duplicate chat replies out of artifact listings', async () => {
|
||||
const database = await createDatabase()
|
||||
const project = database.listProjects()[0]!
|
||||
const chatTaskId = '00000000-0000-4000-8000-000000000231'
|
||||
const channelTaskId = '00000000-0000-4000-8000-000000000232'
|
||||
const scheduleTaskId = '00000000-0000-4000-8000-000000000233'
|
||||
const delegationTaskId = '00000000-0000-4000-8000-000000000234'
|
||||
database.createTask({
|
||||
id: chatTaskId,
|
||||
projectId: project.id,
|
||||
conversationId: 'conversation-chat',
|
||||
title: '普通对话',
|
||||
instructions: '回答问题',
|
||||
workMode: 'ask'
|
||||
})
|
||||
database.createTask({
|
||||
id: channelTaskId,
|
||||
projectId: project.id,
|
||||
conversationId: 'conversation-channel',
|
||||
title: '远程对话',
|
||||
instructions: '回答远程消息',
|
||||
workMode: 'ask',
|
||||
origin: 'delegation'
|
||||
})
|
||||
database.createTask({
|
||||
id: scheduleTaskId,
|
||||
projectId: project.id,
|
||||
conversationId: 'schedule:daily',
|
||||
title: '每日报告',
|
||||
instructions: '生成报告',
|
||||
workMode: 'ask',
|
||||
origin: 'schedule'
|
||||
})
|
||||
database.createTask({
|
||||
id: delegationTaskId,
|
||||
projectId: project.id,
|
||||
conversationId: 'delegation:weekly-report',
|
||||
title: '委派报告',
|
||||
instructions: '生成远程委派报告',
|
||||
workMode: 'ask',
|
||||
origin: 'delegation'
|
||||
})
|
||||
const chatReply = database.createTextArtifact({
|
||||
projectId: project.id,
|
||||
taskId: chatTaskId,
|
||||
title: '普通对话',
|
||||
content: '普通回复'
|
||||
})
|
||||
const channelReply = database.createTextArtifact({
|
||||
projectId: project.id,
|
||||
taskId: channelTaskId,
|
||||
title: '远程对话',
|
||||
content: '远程回复'
|
||||
})
|
||||
const scheduledReport = database.createTextArtifact({
|
||||
projectId: project.id,
|
||||
taskId: scheduleTaskId,
|
||||
title: '每日报告',
|
||||
content: '# 每日报告'
|
||||
})
|
||||
const delegatedReport = database.createTextArtifact({
|
||||
projectId: project.id,
|
||||
taskId: delegationTaskId,
|
||||
title: '委派报告',
|
||||
content: '# 委派报告'
|
||||
})
|
||||
const generatedImage = database.createImageArtifact({
|
||||
projectId: project.id,
|
||||
taskId: chatTaskId,
|
||||
title: '生成图片',
|
||||
mimeType: 'image/png',
|
||||
base64: 'iVBORw0KGgo='
|
||||
})
|
||||
|
||||
const visibleArtifactIds = database
|
||||
.listArtifacts(project.id)
|
||||
.map((artifact) => artifact.id)
|
||||
expect(visibleArtifactIds).toEqual(
|
||||
expect.arrayContaining([
|
||||
scheduledReport.id,
|
||||
delegatedReport.id,
|
||||
generatedImage.id
|
||||
])
|
||||
)
|
||||
expect(visibleArtifactIds).not.toContain(chatReply.id)
|
||||
expect(visibleArtifactIds).not.toContain(channelReply.id)
|
||||
expect(database.getArtifact(chatReply.id)).toMatchObject({
|
||||
id: chatReply.id,
|
||||
content: '普通回复'
|
||||
})
|
||||
database.close()
|
||||
})
|
||||
|
||||
it('loads image artifact content only when requested by id', async () => {
|
||||
const database = await createDatabase()
|
||||
const artifact = database.createInlineArtifact({
|
||||
|
||||
@@ -3166,11 +3166,25 @@ export class AssistantDatabase {
|
||||
CASE WHEN kind = 'image' THEN NULL
|
||||
ELSE inline_content END AS inline_content,
|
||||
byte_size, created_at, updated_at`
|
||||
const visibleArtifact = `NOT (
|
||||
kind = 'markdown' AND EXISTS (
|
||||
SELECT 1
|
||||
FROM tasks
|
||||
WHERE tasks.id = artifacts.task_id
|
||||
AND tasks.conversation_id IS NOT NULL
|
||||
AND (
|
||||
tasks.origin = 'user' OR (
|
||||
tasks.origin = 'delegation'
|
||||
AND tasks.conversation_id NOT LIKE 'delegation:%'
|
||||
)
|
||||
)
|
||||
)
|
||||
)`
|
||||
const rows = projectId
|
||||
? this.requireDatabase()
|
||||
.prepare(
|
||||
`SELECT ${columns} FROM artifacts
|
||||
WHERE project_id = ?
|
||||
WHERE project_id = ? AND ${visibleArtifact}
|
||||
ORDER BY created_at DESC
|
||||
LIMIT ?`
|
||||
)
|
||||
@@ -3178,6 +3192,7 @@ export class AssistantDatabase {
|
||||
: this.requireDatabase()
|
||||
.prepare(
|
||||
`SELECT ${columns} FROM artifacts
|
||||
WHERE ${visibleArtifact}
|
||||
ORDER BY created_at DESC
|
||||
LIMIT ?`
|
||||
)
|
||||
|
||||
@@ -3213,12 +3213,7 @@ describe('registerIpcHandlers agent terminal state', () => {
|
||||
).toBe(expectedOutput)
|
||||
expect(
|
||||
harness.assistantDatabase.createTextArtifact
|
||||
).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
taskId: requestId,
|
||||
content: expectedOutput
|
||||
})
|
||||
)
|
||||
).not.toHaveBeenCalled()
|
||||
await harness.dispose()
|
||||
})
|
||||
|
||||
@@ -4663,6 +4658,9 @@ describe('registerIpcHandlers agent terminal state', () => {
|
||||
'base64'
|
||||
).toString('utf8')
|
||||
).toBe('# 本周报告\n\n已完成。')
|
||||
expect(
|
||||
harness.assistantDatabase.createTextArtifact
|
||||
).not.toHaveBeenCalled()
|
||||
await harness.dispose()
|
||||
})
|
||||
|
||||
|
||||
+5
-23
@@ -1551,7 +1551,7 @@ export function registerIpcHandlers(
|
||||
})
|
||||
}
|
||||
}
|
||||
if (output.trim()) {
|
||||
if (origin !== 'channel' && output.trim()) {
|
||||
assistantDatabase.createTextArtifact({
|
||||
projectId: schedule.projectId,
|
||||
taskId: requestId,
|
||||
@@ -1568,7 +1568,9 @@ export function registerIpcHandlers(
|
||||
body:
|
||||
origin === 'channel'
|
||||
? '结果已回复,并保存到远程通道会话。'
|
||||
: '结果已保存到 GoodBuddy 成果工作栏。'
|
||||
: origin === 'schedule'
|
||||
? '结果已保存到 GoodBuddy 成果工作栏。'
|
||||
: '结果已保存到成果工作栏和委派记录。'
|
||||
})
|
||||
return {
|
||||
status: 'completed',
|
||||
@@ -2413,7 +2415,6 @@ export function registerIpcHandlers(
|
||||
activeRequests.set(request.requestId, controller)
|
||||
|
||||
const execution = (async () => {
|
||||
let outputText = ''
|
||||
let completed = false
|
||||
let runtimeErrorEvent:
|
||||
| Extract<AgentEvent, { type: 'error' }>
|
||||
@@ -2784,15 +2785,6 @@ export function registerIpcHandlers(
|
||||
.slice(0, 120)
|
||||
})
|
||||
: agentEvent
|
||||
if (
|
||||
publicEvent.type === 'text' &&
|
||||
outputText.length < 1_000_000
|
||||
) {
|
||||
outputText += publicEvent.delta.slice(
|
||||
0,
|
||||
1_000_000 - outputText.length
|
||||
)
|
||||
}
|
||||
if (publicEvent.type === 'tool') {
|
||||
toolStates.set(publicEvent.callId, publicEvent)
|
||||
}
|
||||
@@ -2831,23 +2823,13 @@ export function registerIpcHandlers(
|
||||
}
|
||||
if (publicEvent.type === 'done') {
|
||||
completed = true
|
||||
if (outputText.trim()) {
|
||||
assistantDatabase.createTextArtifact({
|
||||
projectId: request.projectId,
|
||||
taskId: request.requestId,
|
||||
title: parsedRequest.prompt
|
||||
.split(/\r?\n/, 1)[0]!
|
||||
.slice(0, 120),
|
||||
content: outputText
|
||||
})
|
||||
}
|
||||
assistantDatabase.updateTaskStatus(
|
||||
request.requestId,
|
||||
'completed'
|
||||
)
|
||||
showDesktopNotificationWhenUnfocused(window, {
|
||||
title: 'GoodBuddy 任务已完成',
|
||||
body: '任务结果已保存到成果工作栏。'
|
||||
body: '回复已生成,可返回会话查看。'
|
||||
})
|
||||
if (!window.isDestroyed()) {
|
||||
window.webContents.send(
|
||||
|
||||
Reference in New Issue
Block a user