import { describe, it, expect } from 'vitest'; import { SyntheticClient } from './synthetic.js'; import type { ChatRequest } from './types.js'; function makeRequest(text: string): ChatRequest { return { messages: [{ role: 'user', content: text }], }; } describe('SyntheticClient', () => { it('echoes the last user message by default', async () => { const client = new SyntheticClient({ model: 'echo' }); const res = await client.chat(makeRequest('hello')); expect(res.content).toBe('hello'); expect(res.stopReason).toBe('end_turn'); expect(res.toolCalls).toBeUndefined(); expect(res.usage.inputTokens).toBeGreaterThan(0); expect(res.usage.outputTokens).toBeGreaterThan(0); }); it('supports fixed responses via model=fixed:', async () => { const client = new SyntheticClient({ model: 'fixed:ok' }); const res = await client.chat(makeRequest('ignored')); expect(res.content).toBe('ok'); expect(res.stopReason).toBe('end_turn'); }); it('supports tool calls via @tool directive', async () => { const client = new SyntheticClient({ model: 'echo' }); const res = await client.chat(makeRequest('@tool memory.read {"namespace":"global"}')); expect(res.stopReason).toBe('tool_use'); expect(res.content).toBe(''); expect(res.toolCalls?.length).toBe(1); expect(res.toolCalls?.[0]?.name).toBe('memory.read'); expect(res.toolCalls?.[0]?.args).toEqual({ namespace: 'global' }); }); it('streams content + done', async () => { const client = new SyntheticClient({ model: 'fixed:stream-me' }); const events: string[] = []; if (!client.chatStream) { throw new Error('Expected streaming support'); } for await (const ev of client.chatStream(makeRequest('x'))) { events.push(ev.type); } expect(events).toEqual(['content', 'done']); }); it('streams tool_use + done for @tool directives', async () => { const client = new SyntheticClient({ model: 'echo' }); const types: string[] = []; const toolNames: string[] = []; if (!client.chatStream) { throw new Error('Expected streaming support'); } for await (const ev of client.chatStream(makeRequest('@tool file.read {"path":"README.md"}'))) { types.push(ev.type); if (ev.type === 'tool_use' && ev.toolCall) { toolNames.push(ev.toolCall.name); } } expect(types).toEqual(['tool_use', 'done']); expect(toolNames).toEqual(['file.read']); }); });