import assert from 'node:assert/strict' import test from 'node:test' import { deleteAiWorkbenchConversation, loadAiWorkbenchConversationHistory, saveAiWorkbenchConversation } from '../src/utils/aiWorkbenchConversationStore.js' function installLocalStorageMock() { const store = new Map() globalThis.window = { localStorage: { getItem(key) { return store.has(key) ? store.get(key) : null }, setItem(key, value) { store.set(key, String(value)) }, removeItem(key) { store.delete(key) }, clear() { store.clear() } } } return store } test('AI workbench conversation store persists scoped history for sidebar sessions', () => { installLocalStorageMock() const user = { username: 'caoxiaozhu', email: 'caoxiaozhu@xf.com', name: '曹笑竹' } const anotherUser = { username: 'budget-user' } saveAiWorkbenchConversation(user, { id: 'conv-first', title: '', updatedAt: Date.now() - 3000, messages: [ { id: 'u1', role: 'user', content: '帮我核对差旅报销口径' }, { id: 'a1', role: 'assistant', content: '我会根据制度和票据要求继续核对。' } ] }) saveAiWorkbenchConversation(user, { id: 'conv-second', title: '预算占用分析', updatedAt: Date.now(), stewardState: { intent: 'budget_check' }, messages: [ { id: 'u2', role: 'user', content: '分析本月预算占用' }, { id: 'a2', role: 'assistant', content: '本月预算占用需要结合部门额度和已提交单据。' } ] }) const history = loadAiWorkbenchConversationHistory(user) assert.equal(history.length, 2) assert.equal(history[0].id, 'conv-second') assert.equal(history[0].title, '预算占用分析') assert.equal(history[0].stewardState.intent, 'budget_check') assert.equal(history[1].title, '帮我核对差旅报销口径') assert.equal(history[1].prompt, '帮我核对差旅报销口径') assert.ok(history[0].time) assert.deepEqual(loadAiWorkbenchConversationHistory(anotherUser), []) const nextHistory = deleteAiWorkbenchConversation(user, 'conv-second') assert.equal(nextHistory.length, 1) assert.equal(nextHistory[0].id, 'conv-first') }) test('AI workbench conversation store preserves stewardRemainingTasks on messages', () => { installLocalStorageMock() const user = { username: 'caoxiaozhu' } const remainingTasks = [ { task_id: 't2', task_type: 'reimbursement', ontology_fields: { expense_type: 'meal' } } ] saveAiWorkbenchConversation(user, { id: 'conv-multi-task', title: '出差+招待费', updatedAt: Date.now(), messages: [ { id: 'u1', role: 'user', content: '出差+报销招待费' }, { id: 'a1', role: 'assistant', content: '申请草稿已保存', stewardRemainingTasks: remainingTasks } ] }) const history = loadAiWorkbenchConversationHistory(user) assert.equal(history.length, 1) // 历史摘要不要求保留 stewardRemainingTasks,但加载完整会话时消息上应保留。 // 这里通过 saveAiWorkbenchConversation 的往返确认 normalizeMessage 不会丢弃该字段。 const stored = JSON.parse(globalThis.window.localStorage.getItem( 'x-financial:workbench-ai-conversations:caoxiaozhu' )) const conversation = stored.find((item) => item.id === 'conv-multi-task') const persistedMessage = conversation.messages.find((m) => m.id === 'a1') assert.deepEqual(persistedMessage.stewardRemainingTasks, remainingTasks) })