import { describe, expect, test } from 'bun:test'; import type { Message, Part } from '@opencode-ai/sdk/v2/client'; import type { State } from './types'; import { EMPTY_USER_MESSAGE_HISTORY_SNAPSHOT, buildUserMessageHistorySnapshot } from './user-message-history'; const message = (id: string, role: 'user' | 'assistant'): Message => ({ id, role, sessionID: 'ses_1', time: { created: 1 }, } as Message); const textPart = (id: string, text: string): Part => ({ id, type: 'text', text, } as Part); const state = (partial: Partial): Pick => ({ session: [], message: {}, part: {}, ...partial, }); describe('buildUserMessageHistorySnapshot', () => { test('returns a shared empty snapshot without a session id', () => { expect(buildUserMessageHistorySnapshot(state({}), '')).toBe(EMPTY_USER_MESSAGE_HISTORY_SNAPSHOT); }); test('keeps history stable when assistant parts change', () => { const user = message('user_1', 'user'); const assistant = message('assistant_1', 'assistant'); const userParts = [textPart('part_user', 'hello')]; const first = buildUserMessageHistorySnapshot( state({ message: { ses_1: [user, assistant] }, part: { user_1: userParts, assistant_1: [textPart('part_a', 'stream')] }, }), 'ses_1', ); const second = buildUserMessageHistorySnapshot( state({ message: { ses_1: [user, assistant] }, part: { user_1: userParts, assistant_1: [textPart('part_a2', 'streaming')] }, }), 'ses_1', first, ); expect(second).toBe(first); expect(second.history).toEqual(['hello']); }); test('updates history when a user part changes', () => { const user = message('user_1', 'user'); const first = buildUserMessageHistorySnapshot( state({ message: { ses_1: [user] }, part: { user_1: [textPart('part_user', 'hello')] }, }), 'ses_1', ); const second = buildUserMessageHistorySnapshot( state({ message: { ses_1: [user] }, part: { user_1: [textPart('part_user_updated', 'updated')] }, }), 'ses_1', first, ); expect(second).not.toBe(first); expect(second.history).toEqual(['updated']); }); test('excludes user messages hidden by session revert state', () => { const beforeRevert = message('msg_ffffffffffffBefore', 'user'); const reverted = message('msg_000000000000Reverted', 'user'); const snapshot = buildUserMessageHistorySnapshot( state({ session: [{ id: 'ses_1', revert: { messageID: reverted.id } } as State['session'][number]], message: { ses_1: [beforeRevert, reverted] }, part: { [beforeRevert.id]: [textPart('part_user_1', 'kept')], [reverted.id]: [textPart('part_user_2', 'reverted')], }, }), 'ses_1', ); expect(snapshot.history).toEqual(['kept']); }); });