fix: retain submitted questions and answers in conversations
Preserve read-only question and answer reviews after successful submission or skipping, including multiple rounds and local conversation reloads. Keep failed submissions retryable and preserve newer questions and terminal states when responses arrive late. Validation: typecheck and lint passed; full suite had 3900 passes, 66 skips and one Agent package timeout that passed on isolated rerun. Real OpenCode UI acceptance was not run. Previously discarded answers cannot be recovered. Release note: 修复 OpenCode 提交回答后会话仅显示已提交的问题;现在保留原问题及对应答案,多轮问答和跳过记录在重新打开会话后仍可查看。
This commit is contained in:
@@ -273,6 +273,116 @@ describe('AssistantDatabase', () => {
|
||||
database.close()
|
||||
})
|
||||
|
||||
it('retains answeredQuestions through replacement, incremental saves, and reopening', async () => {
|
||||
const database = await createDatabase()
|
||||
const header = {
|
||||
id: '00000000-0000-4000-8000-000000000921',
|
||||
title: 'Answered questions',
|
||||
updatedAt: 1
|
||||
}
|
||||
const customAnswer = `Custom answer: ${'x'.repeat(1_001)}\nEnd of answer.`
|
||||
const answeredQuestions = [
|
||||
{
|
||||
questionId: 'question-choices',
|
||||
skipped: false,
|
||||
questions: [
|
||||
{
|
||||
header: 'Targets',
|
||||
question: 'Which platforms should be supported?',
|
||||
options: [
|
||||
{ label: 'Windows', description: 'Windows desktop' },
|
||||
{ label: 'Linux', description: 'Linux desktop' }
|
||||
],
|
||||
multiple: true,
|
||||
custom: false,
|
||||
answer: ['Windows', 'Linux']
|
||||
},
|
||||
{
|
||||
header: 'Details',
|
||||
question: 'What else should be included?',
|
||||
options: [],
|
||||
multiple: false,
|
||||
custom: true,
|
||||
answer: [customAnswer]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
questionId: 'question-skipped',
|
||||
skipped: true,
|
||||
questions: [
|
||||
{
|
||||
header: 'Timing',
|
||||
question: 'When should this ship?',
|
||||
options: [{ label: 'Now', description: 'Ship immediately' }],
|
||||
multiple: false,
|
||||
custom: true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
const message = {
|
||||
id: '00000000-0000-4000-8000-000000000922',
|
||||
role: 'assistant' as const,
|
||||
content: 'Recorded answers',
|
||||
createdAt: 1,
|
||||
state: 'complete' as const,
|
||||
answeredQuestions
|
||||
}
|
||||
|
||||
try {
|
||||
database.replaceConversations([{ ...header, messages: [message] }])
|
||||
expect(database.getConversation(header.id).messages).toEqual([message])
|
||||
database.close()
|
||||
database.initialize('C:\\Workspace')
|
||||
expect(database.getConversation(header.id).messages).toEqual([message])
|
||||
|
||||
const updatedMessage = {
|
||||
...message,
|
||||
answeredQuestions: [
|
||||
...answeredQuestions,
|
||||
{
|
||||
questionId: 'question-follow-up',
|
||||
skipped: false,
|
||||
questions: [
|
||||
{
|
||||
header: 'Confirm',
|
||||
question: 'Proceed with the selected platforms?',
|
||||
options: [{ label: 'Yes', description: 'Proceed' }],
|
||||
multiple: false,
|
||||
custom: false,
|
||||
answer: ['Yes']
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
const insertedMessage = {
|
||||
...message,
|
||||
id: '00000000-0000-4000-8000-000000000923',
|
||||
createdAt: 2
|
||||
}
|
||||
database.saveLocalConversations([
|
||||
{
|
||||
header: { ...header, updatedAt: 2 },
|
||||
messages: [updatedMessage, insertedMessage]
|
||||
}
|
||||
])
|
||||
expect(database.getConversation(header.id).messages).toEqual([
|
||||
updatedMessage,
|
||||
insertedMessage
|
||||
])
|
||||
database.close()
|
||||
database.initialize('C:\\Workspace')
|
||||
expect(database.getConversation(header.id).messages).toEqual([
|
||||
updatedMessage,
|
||||
insertedMessage
|
||||
])
|
||||
} finally {
|
||||
database.close()
|
||||
}
|
||||
})
|
||||
|
||||
it('persists complete Run history beyond the former Renderer limits', async () => {
|
||||
const directory = await mkdtemp(
|
||||
join(tmpdir(), 'goodbuddy-activity-history-')
|
||||
|
||||
@@ -275,6 +275,7 @@ type MessageMetadata = {
|
||||
imageContextNotice?: ConversationSnapshot['messages'][number]['imageContextNotice']
|
||||
task?: ConversationSnapshot['messages'][number]['task']
|
||||
attachments?: ConversationSnapshot['messages'][number]['attachments']
|
||||
answeredQuestions?: ConversationSnapshot['messages'][number]['answeredQuestions']
|
||||
}
|
||||
|
||||
const MAX_CHANNEL_OUTBOX_RETRY_BYTES = 20 * 1024 * 1024
|
||||
@@ -1163,7 +1164,8 @@ function toConversationSnapshot(
|
||||
artifactIds: metadata.artifactIds,
|
||||
imageContextNotice: metadata.imageContextNotice,
|
||||
task: metadata.task,
|
||||
attachments: metadata.attachments
|
||||
attachments: metadata.attachments,
|
||||
answeredQuestions: metadata.answeredQuestions
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1189,7 +1191,8 @@ function serializeConversationMessageMetadata(
|
||||
artifactIds: message.artifactIds,
|
||||
imageContextNotice: message.imageContextNotice,
|
||||
task: message.task,
|
||||
attachments: message.attachments
|
||||
attachments: message.attachments,
|
||||
answeredQuestions: message.answeredQuestions
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4633,7 +4636,8 @@ export class AssistantDatabase {
|
||||
knowledgeRetrieval: metadata.knowledgeRetrieval,
|
||||
artifactIds: metadata.artifactIds,
|
||||
task: metadata.task,
|
||||
attachments: metadata.attachments
|
||||
attachments: metadata.attachments,
|
||||
answeredQuestions: metadata.answeredQuestions
|
||||
})
|
||||
const failed = reduceRecoveredAgentEvent(current, {
|
||||
requestId: taskId,
|
||||
@@ -5041,7 +5045,8 @@ export class AssistantDatabase {
|
||||
knowledgeRetrieval: metadata.knowledgeRetrieval,
|
||||
artifactIds: metadata.artifactIds,
|
||||
task: metadata.task,
|
||||
attachments: metadata.attachments
|
||||
attachments: metadata.attachments,
|
||||
answeredQuestions: metadata.answeredQuestions
|
||||
})
|
||||
const reduced = reduceRecoveredAgentEvent(message, publicEvent)
|
||||
const messageUpdate = database
|
||||
|
||||
Reference in New Issue
Block a user