fix: preserve replies after session recovery
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import { extractConversationMessageText } from './conversation-memory.mjs';
|
||||
import { mergeConversationSnapshot } from './chat-finish-sync.mjs';
|
||||
|
||||
export function parseStoredConversationRow(row) {
|
||||
if (!row) return null;
|
||||
@@ -215,6 +216,15 @@ export function repairConversationFromDbRows(gooseMessages, dbRows) {
|
||||
return Array.isArray(gooseMessages) ? gooseMessages : [];
|
||||
}
|
||||
if (dbBuilt.length === 0) return Array.isArray(gooseMessages) ? gooseMessages : [];
|
||||
const goose = Array.isArray(gooseMessages) ? gooseMessages : [];
|
||||
const dbIds = new Set(dbBuilt.map((message) => message?.id).filter(Boolean));
|
||||
const hasSharedAnchor = goose.some((message) => message?.id && dbIds.has(message.id));
|
||||
if (hasSharedAnchor) {
|
||||
// A recovered Goose session can contain only the last DB-backed user turn
|
||||
// plus replies created after rotation. Prefer DB content for shared history,
|
||||
// while retaining every Goose-only reply and follow-up around that anchor.
|
||||
return mergeConversationSnapshot(goose, dbBuilt);
|
||||
}
|
||||
return dbBuilt;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,70 @@ test('shouldRepairConversationFromDb when goose has empty placeholders', () => {
|
||||
assert.match(repaired[1].content[0].text, /中考/);
|
||||
});
|
||||
|
||||
test('repairConversationFromDbRows retains the fresh Goose tail after session recovery', () => {
|
||||
const goose = [
|
||||
gooseMsg('recovery-user', 'user', '【Memind 任务编排】继续修改页面'),
|
||||
gooseMsg('fresh-assistant', 'assistant', '第一轮修改已完成'),
|
||||
gooseMsg('followup-user', 'user', '再加一个页脚'),
|
||||
gooseMsg('followup-assistant', 'assistant', '页脚也已完成'),
|
||||
];
|
||||
const dbRows = [
|
||||
{
|
||||
message_key: 'old-user',
|
||||
role: 'user',
|
||||
text: '写一首诗并做成页面',
|
||||
created_at: 1,
|
||||
sequence_no: 0,
|
||||
},
|
||||
{
|
||||
message_key: 'old-assistant',
|
||||
role: 'assistant',
|
||||
text: '初版页面已完成',
|
||||
created_at: 2,
|
||||
sequence_no: 1,
|
||||
},
|
||||
{
|
||||
message_key: 'old-followup-user',
|
||||
role: 'user',
|
||||
text: '把标题改成金色',
|
||||
created_at: 3,
|
||||
sequence_no: 2,
|
||||
},
|
||||
{
|
||||
message_key: 'old-followup-assistant',
|
||||
role: 'assistant',
|
||||
text: '标题已改成金色',
|
||||
created_at: 4,
|
||||
sequence_no: 3,
|
||||
},
|
||||
{
|
||||
message_key: 'recovery-user',
|
||||
role: 'user',
|
||||
text: '继续修改页面',
|
||||
created_at: 5,
|
||||
sequence_no: 4,
|
||||
},
|
||||
];
|
||||
|
||||
const repaired = repairConversationFromDbRows(goose, dbRows);
|
||||
|
||||
assert.deepEqual(
|
||||
repaired.map((message) => message.id),
|
||||
[
|
||||
'old-user',
|
||||
'old-assistant',
|
||||
'old-followup-user',
|
||||
'old-followup-assistant',
|
||||
'recovery-user',
|
||||
'fresh-assistant',
|
||||
'followup-user',
|
||||
'followup-assistant',
|
||||
],
|
||||
);
|
||||
assert.equal(repaired[4].content[0].text, '继续修改页面');
|
||||
assert.equal(repaired[7].content[0].text, '页脚也已完成');
|
||||
});
|
||||
|
||||
test('shouldRepairConversationFromDb returns false when goose is complete', () => {
|
||||
const goose = [
|
||||
gooseMsg('u1', 'user', 'hello'),
|
||||
|
||||
@@ -211,6 +211,19 @@ runtime 也必须和发布 manifest 的 git commit 对齐。
|
||||
- 源码静态检查:`npm run verify:chat-finish-sync`
|
||||
- 文档:本文件
|
||||
|
||||
### 恢复会话快照:禁止用旧 DB 历史覆盖新回复
|
||||
|
||||
视觉上下文不兼容等故障会把 Agent Run 旋转到新 Goose session。新 session
|
||||
可能只包含最后一条数据库已同步的用户消息,以及旋转后新生成的助手回复和后续追问;
|
||||
此时数据库旧历史条数通常更多。
|
||||
|
||||
- `conversation-repair.mjs` 发现 Goose 与 DB 存在共同消息 ID 时,必须以该 ID
|
||||
为锚点合并:共享历史采用 DB 内容,同时保留 Goose 独有的新回复、后续追问和修改结果
|
||||
- 只有双方没有共同消息 ID,且 Goose 确实是空占位/残缺记录时,才允许用 DB 历史整体修复
|
||||
- Portal 保存 session snapshot 前不得把“当前同步计数”与“旧 messages_json”组合成伪最新快照
|
||||
|
||||
守卫:`conversation-repair.test.mjs` 中的 session recovery fresh-tail 用例。
|
||||
|
||||
---
|
||||
|
||||
## 3. 页面需求澄清:禁止误报“未生成 public HTML”
|
||||
|
||||
Reference in New Issue
Block a user