Require two materials for content schedules and scope readiness copy
The engine plans each production piece from a pair of documents, so a summary, quiz or similar schedule with one material can never plan. Approving such a plan is now blocked with a note to choose or upload another material, and the engine's refusal on an existing schedule is explained in plain language. Video and research schedules still work with one material. The engine now checks only a schedule's own material before a run, so the run error and Upload texts no longer say the whole Library or Brain is checked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,7 +13,7 @@ import { locale, t } from '../i18n'
|
||||
type Phase = 'ready' | 'working' | 'answer' | 'failed'
|
||||
|
||||
function phaseOf(s: Source): Phase {
|
||||
// A failed document blocks every whole-Brain schedule in the engine, even with a built knowledge base.
|
||||
// A failed document blocks every schedule that uses it, even with a built knowledge base.
|
||||
if (s.status === 'failed' || s.knowledge === 'failed') return 'failed'
|
||||
// A reprocessed document keeps its built knowledge while it is read again, and still blocks schedules.
|
||||
if (s.status !== 'completed') return 'working'
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
} from '../express/parse'
|
||||
import { ask, chatLangOf, editRule, EMPTY, nextQuestion, removeRule, respond, type AgentState } from '../express/agent'
|
||||
import { inLang, t, useLang, type Key, type Lang } from '../i18n'
|
||||
import { budgetFor, canSchedule, createSchedule, VIDEO, videoQuote } from '../express/schedules'
|
||||
import { budgetFor, canSchedule, createSchedule, MIN_PRODUCTION_SOURCES, needsTwoSources, VIDEO, videoQuote } from '../express/schedules'
|
||||
|
||||
const EXAMPLES: Key[] = ['ins.ex1', 'ins.ex2', 'ins.ex3', 'ins.ex4', 'ins.ex5']
|
||||
const THINKING: Key[] = ['agent.think1', 'agent.think2', 'agent.think3']
|
||||
@@ -59,6 +59,9 @@ export function InstructionPage() {
|
||||
const view: AgentState = { ...agent, sources }
|
||||
const question = nextQuestion(view)
|
||||
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))
|
||||
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
|
||||
@@ -108,7 +111,7 @@ export function InstructionPage() {
|
||||
|
||||
async function approve(state = agent, replyLang = lang) {
|
||||
const items = state.items.filter(i => canSchedule(i.rule))
|
||||
if (!items.length) return
|
||||
if (!items.length || tooFewSources) return
|
||||
setSaving(true)
|
||||
const done: Outcome[] = []
|
||||
const created = new Set<number>()
|
||||
@@ -201,8 +204,9 @@ export function InstructionPage() {
|
||||
<small>
|
||||
<b className="rule-sources"><Icon name="brain" />{chosen.length ? t('ins.sourcesChosen', { n: chosen.length }) : t('ins.sourcesAll')}</b>
|
||||
{t('ins.approveNote')}
|
||||
{tooFewSources && <span className="error">{t(chosen.length ? 'ins.tooFewChosen' : 'ins.tooFewInBrain', { n: MIN_PRODUCTION_SOURCES })}</span>}
|
||||
</small>
|
||||
<button className="btn primary" disabled={saving || !idle} onClick={() => approve()}>
|
||||
<button className="btn primary" disabled={saving || !idle || tooFewSources} onClick={() => approve()}>
|
||||
<Icon name="check" />{saving ? t('ins.approving') : t('ins.approve', { n: ready.length })}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,7 @@ import { describeRule } from '../express/parse'
|
||||
import { locale, t, type Key } from '../i18n'
|
||||
import {
|
||||
archiveSchedule, confirmProduction, isRunSchedule, knowledgeReadiness, listRuns, listSchedules, pauseSchedule, PLAN_ACTIVE, productionStatus, quoteProduction, resumeSchedule,
|
||||
planProgress, runNow as startRun, updateTopic, type ContentPlan, type RunSummary, type Schedule,
|
||||
planProgress, productionError, runNow as startRun, updateTopic, type ContentPlan, type RunSummary, type Schedule,
|
||||
} from '../express/schedules'
|
||||
|
||||
const STUDIO_URL: string = import.meta.env.VITE_STUDIO_URL
|
||||
@@ -201,7 +201,7 @@ function ProducePanel({ schedule: { agent, rule }, onClose }: { schedule: Schedu
|
||||
<input type="number" min={1} max={remaining} value={n} onChange={e => setCount(Number(e.target.value) || 1)} />
|
||||
</label>
|
||||
)}
|
||||
{error && <span className="error">{error.message}</span>}
|
||||
{error && <span className="error">{productionError(error.message)}</span>}
|
||||
<div className="produce-actions">
|
||||
{!running && remaining > 0 && (quote.data
|
||||
? <button className="btn small primary" disabled={start.isPending} onClick={() => start.mutate(quote.data)}>{start.isPending ? t('sch.starting') : t('sch.startProduction')}</button>
|
||||
|
||||
Reference in New Issue
Block a user