import { describe, expect, it } from 'vitest' import { chatLangOf, EMPTY, nextQuestion, respond, type AgentState } from './agent' import { t } from '../i18n' const say = (...inputs: string[]) => inputs.reduce((s, input) => respond(s, input).state, EMPTY) const rules = (s: AgentState) => s.items.map(i => i.rule) describe('instruction agent', () => { it('needs no question when the instruction is complete', () => { const s = say('make 2 summaries per day about leadership in english') expect(s.language).toBe('English') expect(nextQuestion(s)).toBeNull() expect(respond(s, 'yes').approve).toBe(true) }) it('asks for a topic, and takes the reply as the topic', () => { const s = say('make 3 quizzes per week') expect(nextQuestion(s)?.type).toBe('topic') expect(rules(say('make 3 quizzes per week', 'negotiation'))[0]).toMatchObject({ topic: 'negotiation' }) }) it('stops asking for a topic once the whole Brain is chosen', () => { expect(nextQuestion(say('make 3 quizzes per week', t('agent.optWholeBrain')))?.type).toBe('language') }) it('asks no topic for content when material is chosen, and names that material in the plan', () => { const s = { ...say('make 1 scorm per week'), sources: '“LLM”' } expect(nextQuestion(s)?.type).toBe('language') expect(respond({ ...EMPTY, sources: '“LLM”' }, 'make 1 scorm per week').reply).toMatch(/from “LLM”/) }) it('still asks what to research on the internet when material is chosen', () => { expect(nextQuestion({ ...say('research every day'), sources: '“LLM”' })?.type).toBe('topic') }) it('asks about a video count that has no cadence', () => { const s = say('3 videos per week about onboarding') expect(nextQuestion(s)?.type).toBe('video') expect(rules(say('3 videos per week about onboarding', t('agent.optPerDay')))[0]).toMatchObject({ count: 1, per: 'day' }) }) it('asks which day weekly research runs when none was named', () => { const s = say('research every week about sales') expect(nextQuestion(s)?.type).toBe('weekday') const answered = say('research every week about sales', 'thursday') expect(rules(answered)[0]).toMatchObject({ weekday: 3, weekdayGuessed: undefined }) expect(nextQuestion(answered)).toBeNull() }) it('asks about parts it did not understand, and can skip them', () => { const s = say('2 summaries per day about sales. hello there') expect(nextQuestion(s)).toMatchObject({ type: 'unknown', text: 'hello there' }) expect(nextQuestion(say('2 summaries per day about sales. hello there', 'skip'))?.type).toBe('language') }) it('asks which language the content is written in', () => { expect(nextQuestion(say('3 quizzes per week about sales'))?.type).toBe('language') expect(say('3 quizzes per week about sales', 'mandarin').language).toBe('中文') expect(say('3 quizzes per week about sales', 'indo').language).toBe('Bahasa Indonesia') expect(nextQuestion(say('3 quizzes per week about sales', '中文 (Mandarin)'))).toBeNull() }) it('reads the language from the instruction without leaving it in the topic', () => { const s = say('bikin 3 kuis per minggu soal negosiasi pakai bahasa inggris') expect(s.language).toBe('English') expect(rules(s)[0]).toMatchObject({ topic: 'negosiasi' }) expect(s.unknown).toEqual([]) }) it('does not ask about the language for research alone', () => { expect(nextQuestion(say('research every day about sales in China'))).toBeNull() }) it('treats a reply with a frequency as a new request', () => { const s = say('make 3 quizzes per week', '1 video per week about onboarding') expect(rules(s).map(r => r.type === 'content' && r.kind)).toEqual(['quiz', 'video']) }) it('caps a schedule that is over the weekly limit', () => { const s = say('10 summaries per day about sales') expect(nextQuestion(s)?.type).toBe('tooMany') expect(rules(say('10 summaries per day about sales', '30 per week'))[0]).toMatchObject({ count: 30, per: 'week' }) }) it('takes "dari file X" as the topic', () => { expect(rules(say('Saya mau buat video dari file LLM'))[0]).toMatchObject({ kind: 'video', topic: 'LLM' }) }) }) describe('chatLangOf', () => { it('tells Indonesian from English, and stays undecided on short replies', () => { expect(chatLangOf('Saya mau buat video dari file LLM')).toBe('id') expect(chatLangOf('I want to make 2 quizzes per week')).toBe('en') expect(chatLangOf('LLM')).toBeNull() }) })