The Brain and AI page lists Brain material (failed documents hidden) with search, open, delete and per-material or select-all ticks. New schedules use only the ticked material, kept through topic edits and resumes; nothing ticked means the whole Brain. With material ticked, the agent skips the content topic question and names the material in the chat and plan. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
97 lines
4.5 KiB
TypeScript
97 lines
4.5 KiB
TypeScript
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<AgentState>((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()
|
|
})
|
|
})
|