Attach Brain material without blocking a schedule's status
Saving a topic or resuming sent one PUT per ready document (about 150), and a topic change left the schedule in draft (shown as paused) until all of them were done. Creating a schedule waited on the same loop with no sign of progress. A topic change now re-activates (or keeps paused) right after the PATCH, and resuming is one activate; both then attach only the documents the schedule does not have yet. Creating a schedule still attaches every ready document, three at a time and paced under the proxy's rate limit, retrying a busy answer instead of skipping it, and the Instruction chat shows how many are done. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -36,6 +36,8 @@ export function InstructionPage() {
|
||||
const [agent, setAgent] = useState<AgentState>(EMPTY)
|
||||
const [messages, setMessages] = useState<Message[]>([])
|
||||
const [saving, setSaving] = useState(false)
|
||||
// While schedules are created: which one, and how many Brain documents it has been given so far.
|
||||
const [progress, setProgress] = useState<{ n: number; count: number; done: number; total: number } | null>(null)
|
||||
const docs = useDocuments()
|
||||
const [phase, setPhase] = useState<Phase>('idle')
|
||||
// The live question whose typing has finished, so its reply options can show.
|
||||
@@ -108,9 +110,10 @@ export function InstructionPage() {
|
||||
// Approving from the plan before the agent asked about the language uses the conversation's language.
|
||||
const language: OutputLanguage = state.language ?? (replyLang === 'id' ? 'Bahasa Indonesia' : 'English')
|
||||
// One at a time so a failure (e.g. not an organization owner) is reported per schedule.
|
||||
for (const { id, rule } of items) {
|
||||
for (const [i, { id, rule }] of items.entries()) {
|
||||
try {
|
||||
await createSchedule(rule.type === 'content' ? { ...rule, language } : rule)
|
||||
await createSchedule(rule.type === 'content' ? { ...rule, language } : rule, undefined,
|
||||
(d, total) => setProgress({ n: i + 1, count: items.length, done: d, total }))
|
||||
done.push({ rule, ok: true })
|
||||
created.add(id)
|
||||
} catch (e) {
|
||||
@@ -118,6 +121,7 @@ export function InstructionPage() {
|
||||
}
|
||||
}
|
||||
setSaving(false)
|
||||
setProgress(null)
|
||||
// A new schedule may start producing right away; the dashboard shows it under content in progress.
|
||||
await Promise.all([queryClient.invalidateQueries({ queryKey: ['schedules'] }), queryClient.invalidateQueries({ queryKey: ['results'] })])
|
||||
const ok = done.filter(o => o.ok).length
|
||||
@@ -148,6 +152,7 @@ export function InstructionPage() {
|
||||
{phase === 'pausing' && <Typing />}
|
||||
{idle && live.text && (
|
||||
<Bubble key={live.text} message={{ role: 'agent', text: live.text, typed: true }} lang={lang} busy={saving}
|
||||
note={saving && progress?.total ? inLang(lang, () => t('agent.attaching', progress)) : undefined}
|
||||
onTyped={() => setTypedLive(live.text)} onType={scroll} />
|
||||
)}
|
||||
</div>
|
||||
@@ -221,8 +226,8 @@ function useTyped(text: string, enabled: boolean, onDone?: () => void, onType?:
|
||||
return text.slice(0, shown)
|
||||
}
|
||||
|
||||
function Bubble({ message, lang, busy, onTyped, onType }: {
|
||||
message: Message; lang: Lang; busy?: boolean; onTyped?: () => void; onType?: () => void
|
||||
function Bubble({ message, lang, busy, note, onTyped, onType }: {
|
||||
message: Message; lang: Lang; busy?: boolean; note?: string; onTyped?: () => void; onType?: () => void
|
||||
}) {
|
||||
const text = useTyped(message.text, !!message.typed, onTyped, onType)
|
||||
const typing = text.length < message.text.length
|
||||
@@ -232,6 +237,7 @@ function Bubble({ message, lang, busy, onTyped, onType }: {
|
||||
<div className="ai-bubble">
|
||||
{message.thought && <small className="ai-thought">{inLang(lang, () => t('agent.thought', { s: message.thought! }))}</small>}
|
||||
<p className={typing ? 'typing' : undefined}>{text}</p>
|
||||
{note && <small className="ai-thought" role="status">{note}</small>}
|
||||
{message.outcomes && !typing && (
|
||||
<ul className="rule-outcomes appear">
|
||||
{message.outcomes.map((o, i) => (
|
||||
|
||||
Reference in New Issue
Block a user