profileShare

rasmusjy / voicetask

Read-only snapshot

No repository description.

main default branch 105 files Expires Sep 13, 2026, 9:06 AM
llmAnthropic.test.ts 2,674 bytes
1 import { describe, expect, it } from 'vitest'
2 import { initialCoverage, type Segment } from '../../shared/types'
3 import { buildInterviewSystemPrompt, buildInterviewUserMessage } from './llmAnthropic'
4 import type { InterviewContext } from './types'
5
6 function segment(id: string, speaker: Segment['speaker'], text: string): Segment {
7 return { id, ts: new Date().toISOString(), speaker, text }
8 }
9
10 describe('buildInterviewSystemPrompt', () => {
11 it('names the weakest category as the required target of the next question', () => {
12 const context: InterviewContext = {
13 summary: '',
14 segments: [],
15 coverage: { ...initialCoverage(), goal: 'clear' },
16 }
17 const prompt = buildInterviewSystemPrompt(context)
18 expect(prompt).toContain('weakest category right now is "users"')
19 })
20
21 it('states every category is covered when nothing is weak', () => {
22 const allClear = Object.fromEntries(
23 Object.keys(initialCoverage()).map((c) => [c, 'clear']),
24 ) as ReturnType<typeof initialCoverage>
25 const context: InterviewContext = { summary: '', segments: [], coverage: allClear }
26 expect(buildInterviewSystemPrompt(context)).toContain('Every category is already "clear"')
27 })
28
29 it('instructs the exact-match "done" rule and the contradiction rule', () => {
30 const context: InterviewContext = { summary: '', segments: [], coverage: initialCoverage() }
31 const prompt = buildInterviewSystemPrompt(context)
32 expect(prompt).toContain('exactly "done"')
33 expect(prompt).toContain('contradiction')
34 })
35
36 it('instructs plain, jargon-free language for a non-technical user', () => {
37 const context: InterviewContext = { summary: '', segments: [], coverage: initialCoverage() }
38 const prompt = buildInterviewSystemPrompt(context)
39 expect(prompt).toContain('no jargon')
40 expect(prompt).toContain('may not be a developer')
41 })
42 })
43
44 describe('buildInterviewUserMessage', () => {
45 it('includes the running summary and every recent segment with its id and speaker', () => {
46 const context: InterviewContext = {
47 summary: 'earlier: building a todo app',
48 segments: [segment('S1', 'user', 'it should sync across devices')],
49 coverage: initialCoverage(),
50 }
51 const message = buildInterviewUserMessage(context)
52 expect(message).toContain('earlier: building a todo app')
53 expect(message).toContain('[S1] user: it should sync across devices')
54 })
55
56 it('omits the summary section when there is no summary yet', () => {
57 const context: InterviewContext = { summary: '', segments: [], coverage: initialCoverage() }
58 expect(buildInterviewUserMessage(context)).not.toContain('Running summary')
59 })
60 })
61