100 lines
3.2 KiB
JavaScript
100 lines
3.2 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
|
|
import {
|
|
buildConversationFromDbRows,
|
|
countNonEmptyConversationMessages,
|
|
filterUserVisibleConversation,
|
|
parseStoredConversationRow,
|
|
repairConversationFromDbRows,
|
|
shouldRepairConversationFromDb,
|
|
} from './conversation-repair.mjs';
|
|
|
|
const gooseMsg = (id, role, text) => ({
|
|
id,
|
|
role,
|
|
metadata: { userVisible: true },
|
|
content: text ? [{ type: 'text', text }] : [],
|
|
});
|
|
|
|
test('parseStoredConversationRow prefers raw_json', () => {
|
|
const row = {
|
|
message_key: 'abc',
|
|
role: 'user',
|
|
text: 'fallback',
|
|
raw_json: JSON.stringify({
|
|
id: 'abc',
|
|
role: 'user',
|
|
content: [{ type: 'text', text: 'from raw' }],
|
|
metadata: { userVisible: true, displayText: '可见文案' },
|
|
}),
|
|
created_at: 1_700_000_000_000,
|
|
};
|
|
const parsed = parseStoredConversationRow(row);
|
|
assert.equal(parsed.content[0].text, 'from raw');
|
|
assert.equal(parsed.metadata.displayText, '可见文案');
|
|
});
|
|
|
|
test('shouldRepairConversationFromDb when goose has empty placeholders', () => {
|
|
const goose = [
|
|
gooseMsg('u1', 'user', '编排前缀'),
|
|
gooseMsg('a1', 'assistant', '好的'),
|
|
gooseMsg('msg_empty1', 'assistant', ''),
|
|
gooseMsg('msg_empty2', 'user', ''),
|
|
];
|
|
const dbRows = [
|
|
{
|
|
message_key: 'u-real',
|
|
role: 'user',
|
|
text: '小朋友在上海读初中',
|
|
created_at: 1,
|
|
sequence_no: 0,
|
|
},
|
|
{
|
|
message_key: 'a-real',
|
|
role: 'assistant',
|
|
text: '关于中考选择的分析…',
|
|
created_at: 2,
|
|
sequence_no: 1,
|
|
},
|
|
];
|
|
assert.equal(shouldRepairConversationFromDb(goose, dbRows), true);
|
|
const repaired = repairConversationFromDbRows(goose, dbRows);
|
|
assert.equal(countNonEmptyConversationMessages(repaired), 2);
|
|
assert.match(repaired[0].content[0].text, /上海读初中/);
|
|
assert.match(repaired[1].content[0].text, /中考/);
|
|
});
|
|
|
|
test('shouldRepairConversationFromDb returns false when goose is complete', () => {
|
|
const goose = [
|
|
gooseMsg('u1', 'user', 'hello'),
|
|
gooseMsg('a1', 'assistant', 'hi there'),
|
|
];
|
|
const dbRows = [
|
|
{ message_key: 'u1', role: 'user', text: 'hello', created_at: 1, sequence_no: 0 },
|
|
];
|
|
assert.equal(shouldRepairConversationFromDb(goose, dbRows), false);
|
|
});
|
|
|
|
test('buildConversationFromDbRows dedupes by message_key', () => {
|
|
const rows = [
|
|
{ message_key: 'same', role: 'user', text: 'first', created_at: 1, sequence_no: 0 },
|
|
{ message_key: 'same', role: 'user', text: 'second', created_at: 2, sequence_no: 0 },
|
|
];
|
|
const built = buildConversationFromDbRows(rows);
|
|
assert.equal(built.length, 1);
|
|
assert.equal(built[0].content[0].text, 'second');
|
|
});
|
|
|
|
test('filterUserVisibleConversation keeps messages without explicit userVisible flag', () => {
|
|
const messages = [
|
|
{ role: 'user', content: [{ type: 'text', text: '请记住别名' }] },
|
|
{ role: 'assistant', metadata: { userVisible: true }, content: [{ type: 'text', text: '已记住' }] },
|
|
{ role: 'system', metadata: { userVisible: false }, content: [{ type: 'text', text: 'hidden' }] },
|
|
];
|
|
const visible = filterUserVisibleConversation(messages);
|
|
assert.equal(visible.length, 2);
|
|
assert.equal(visible[0].role, 'user');
|
|
assert.equal(visible[1].role, 'assistant');
|
|
});
|