mentionToItem.test.tsx2.7 KBView on GitHub import { DEFAULT_THREAD_ID } from '@/modules/cedar-os/src/store/messages/MessageTypes';
import { useCedarStore } from '@/modules/cedar-os/src/store/CedarStore';
import mentionSuggestion from '@/modules/cedar-os/src/components/chatInput/mentionSuggestion';
import type { MentionProvider } from '@/modules/cedar-os/src/store/agentContext/AgentContextTypes';
/**
* Phase 8 (design: chat-thread-store) — selecting an @-mention is an explicit attach:
* mentionSuggestion.command commits a ContextItem (addContextItem) to the active thread's
* context set, instead of writing to the legacy additionalContext channel.
*/
// Minimal TipTap editor chain stub — records the inserted mention node's attrs.
function makeEditorStub() {
const inserted: unknown[] = [];
const chain = {
focus: () => chain,
insertContentAt: (_range: unknown, content: unknown) => {
inserted.push(content);
return chain;
},
run: () => true,
};
return { editor: { chain: () => chain }, inserted };
}
const conversationProvider: MentionProvider = {
id: 'conversations',
trigger: '@',
contextKind: 'conversation',
getItems: () => [],
toContextEntry: (item) => ({ id: item.id ?? 'x', source: 'mention', data: {} }),
};
describe('mentionSuggestion.command — mention → committed ContextItem', () => {
beforeEach(() => {
useCedarStore.setState((state) => ({
...state,
threadMap: {
[DEFAULT_THREAD_ID]: { id: DEFAULT_THREAD_ID, messages: [], chatContext: { items: [] } },
},
mainThreadId: DEFAULT_THREAD_ID,
activeThreadId: DEFAULT_THREAD_ID,
messages: [],
}));
useCedarStore.getState().registerMentionProvider(conversationProvider);
});
it('adds a conversation ContextItem to the active thread and stamps { kind, id } on the node', () => {
const { editor, inserted } = makeEditorStub();
mentionSuggestion.command({
editor: editor as never,
range: { from: 0, to: 0 } as never,
props: { id: 'conv_1', label: 'Numeral', providerId: 'conversations' } as never,
});
// Committed to chatContext.items as an explicit user attach (optimistic upsert).
const items = useCedarStore.getState().threadMap[DEFAULT_THREAD_ID].chatContext?.items ?? [];
const attached = items.find((i) => i.kind === 'conversation' && i.id === 'conv_1');
expect(attached).toBeTruthy();
expect(attached?.label).toBe('Numeral');
expect(attached?.addedBy).toBe('user');
// The mention node carries the structured { kind, id } for the transcript chip (Phase 9).
const node = (inserted[0] as Array<{ type: string; attrs?: Record<string, unknown> }>)[0];
expect(node.type).toBe('mention');
expect(node.attrs?.kind).toBe('conversation');
expect(node.attrs?.id).toBe('conv_1');
});
});