diff --git a/src/pages/Instruction.tsx b/src/pages/Instruction.tsx index 71d9872..f66f32a 100644 --- a/src/pages/Instruction.tsx +++ b/src/pages/Instruction.tsx @@ -3,7 +3,7 @@ import { Link } from 'react-router-dom' import { useQuery, useQueryClient } from '@tanstack/react-query' import { Icon, ruleIcon } from '../components/Icon' import { PageHead } from '../components/Page' -import { BrainPanel, choosable, useDocuments } from './Brain' +import { choosable, useDocuments } from './Brain' import { dayName, describeRule, kindLabel, KINDS, LANGUAGES, languageLabel, monthNote, videoCadence, weeklyTarget, type ContentKind, type ContentRule, type OutputLanguage, type ResearchRule, type Rule, @@ -36,14 +36,7 @@ export function InstructionPage() { const [agent, setAgent] = useState(EMPTY) const [messages, setMessages] = useState([]) const [saving, setSaving] = useState(false) - // Brain material the schedules are made from; none chosen means the whole Brain. - const [selected, setSelected] = useState>(new Set()) const docs = useDocuments() - // A chosen document that was deleted, or failed since, no longer counts. - const chosenDocs = choosable(docs.data).filter(d => selected.has(d.docId)) - const chosen = chosenDocs.map(d => d.docId) - // How the chat and the plan name the chosen material: by title when there is one. - const sources = chosenDocs.length === 1 ? `“${chosenDocs[0].title}”` : chosenDocs.length ? t('brainPanel.nChosen', { n: chosenDocs.length }) : null const [phase, setPhase] = useState('idle') // The live question whose typing has finished, so its reply options can show. const [typedLive, setTypedLive] = useState('') @@ -55,19 +48,16 @@ export function InstructionPage() { const later = (fn: () => void, ms: number) => { timers.current.push(window.setTimeout(fn, ms)) } useEffect(() => () => timers.current.forEach(clearTimeout), []) - // The agent sees the current choice, so ticking material in the Brain panel updates its question and plan. - const view: AgentState = { ...agent, sources } - const question = nextQuestion(view) + const question = nextQuestion(agent) const ready = agent.items.filter(i => canSchedule(i.rule)) - // Without a choice the whole Brain is attached, so every ready document counts. - const sourceCount = chosen.length || choosable(docs.data).length - const tooFewSources = sourceCount < MIN_PRODUCTION_SOURCES && ready.some(i => needsTwoSources(i.rule)) + // The whole Brain is attached, so every ready document counts. + const tooFewSources = choosable(docs.data).length < MIN_PRODUCTION_SOURCES && ready.some(i => needsTwoSources(i.rule)) const hasContent = agent.items.some(i => i.rule.type === 'content') // The agent's current turn: its question, or what it is waiting for. It stays live, so an edit in the plan updates it. const live = inLang(lang, () => saving ? { text: t('agent.approving'), options: [] as string[] } : question - ? ask(question, view) + ? ask(question, agent) : agent.items.length ? { text: hasContent && agent.language @@ -89,7 +79,7 @@ export function InstructionPage() { // A picked option is in the conversation's language already; typed text may switch it. const replyLang = live.options.includes(input) ? lang : chatLangOf(input) ?? lang setChatLang(replyLang) - const turn = inLang(replyLang, () => respond(view, input)) + const turn = inLang(replyLang, () => respond(agent, input)) // The question being answered is kept in the history, with the reply after it. setMessages(ms => [...ms, ...(live.text ? [{ role: 'agent' as const, text: live.text }] : []), { role: 'user', text: input.trim() }]) setText('') @@ -120,8 +110,8 @@ export function InstructionPage() { // One at a time so a failure (e.g. not an organization owner) is reported per schedule. for (const { id, rule } of items) { try { - await createSchedule(rule.type === 'content' ? { ...rule, language } : rule, chosen) - done.push({ rule: rule.type === 'content' && chosen.length ? { ...rule, chosen: true } : rule, ok: true }) + await createSchedule(rule.type === 'content' ? { ...rule, language } : rule) + done.push({ rule, ok: true }) created.add(id) } catch (e) { done.push({ rule, ok: false, message: (e as Error).message }) @@ -142,76 +132,73 @@ export function InstructionPage() { <> -
- -
-
-
-
- -

{t('agent.name')}

{phase === 'thinking' ? t('agent.statusThinking') : t('agent.status')}
-
+
+
+
+
+ +

{t('agent.name')}

{phase === 'thinking' ? t('agent.statusThinking') : t('agent.status')}
-
- {messages.map((m, i) => ( - - ))} - {phase === 'thinking' && } - {phase === 'pausing' && } - {idle && live.text && ( - setTypedLive(live.text)} onType={scroll} /> - )} -
- {showOptions && ( -
- {live.options.map((o, i) => ( - - ))} -
- )} -
{ e.preventDefault(); send(text) }}> - -