From 643c3c39f9b4ad851109c86973e54a6d9c5362ea Mon Sep 17 00:00:00 2001 From: Iqbal Date: Thu, 29 Oct 2026 11:50:39 +0700 Subject: [PATCH] Remove the Brain panel from the Brain and AI page The page is back to the chat and the plan side by side. With nothing to tick, new schedules always use the whole Brain. Co-Authored-By: Claude Opus 5.5 --- src/pages/Instruction.tsx | 155 +++++++++++++++++--------------------- 1 file changed, 71 insertions(+), 84 deletions(-) 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) }}> - -