gate rejects → revise
retries
over limit
Queued
Running
heartbeat before every search
Chunked writing
≤1,500 chars/chunk · every 1–2 chunks
Save gates
≥800 chars · ≥3 links · still running
Done
Orphan recovery
no heartbeat > 6 min
Requeue
≤8 attempts · last two simplified
Failed
with an honest note
Queue and dispatch
A submitted request is written to Postgres asstatus: queued. A cron-driven dispatcher claims queued rows on a schedule, marks the claimed row running, and hands it to the Briefing agent on the durable agent runtime. The web app doesn’t wait around for the agent to finish — it dispatches and moves on; completion is observed later, either by the agent’s own save call marking the row done, or by the same heartbeat-aware recovery that watches course production.
Research, fanned out across angles
The agent researches a fixed set of angles, skipping any whose input field is empty:- Domain crash course — what this field is, explained plainly, and its core concepts.
- Institution profile — background, reputation, and recent moves of the host organization.
- Speaker profile — recent public statements and notable positions.
- Controversies and hot topics — what practitioners are debating recently, anchored to a date the dispatcher injects mechanically so the agent can’t misjudge “recent” by guessing the wrong year.
- Bilingual term table — the heaviest angle by design, and the interpreter’s core asset from the briefing. The agent actively searches authoritative bilingual sources (government white papers, Ministry of Foreign Affairs bilingual transcripts, UN parallel texts) for each concept, and grades every rendering official or reference depending on whether it actually found a citable bilingual source — never upgraded on confidence alone.
- Further reading — three to eight entries, every one a real, working link the agent actually fetched or searched to, never a placeholder.
Writing in chunks, not one shot
The agent doesn’t compose the whole document in memory and hand it over in a single write. It appends the briefing to a sandbox file in chunks — roughly 1,500 characters at a time — and reports progress after every chunk or two. This exists because writing a multi-thousand-character document in one model turn, with no intermediate signal, looks identical from the outside to a stalled agent: nothing observable happens for minutes at a time. Chunked writing turns “no visible progress for ten minutes” into “a heartbeat every thirty seconds,” which is what makes it possible to tell a slow-but-alive agent apart from a dead one.The save gate
When the file is complete, the agent calls a save tool that reads the finished file and applies gates before it’s allowed to reachdone:
- A minimum length — a briefing under roughly 800 characters is judged too thin to be useful and rejected rather than saved.
- A further-reading floor — at least three real, clickable links, or the save is rejected. A briefing with zero further reading fails this gate outright; the normal mode always requires it (a simplified fallback mode, used only after repeated retries, is explicitly exempt and says so in the document itself).
- A running-status write guard — the save only succeeds if the row is still
runningwhen it commits. This exists specifically to stop an old, previously-orphaned session from overwriting a briefing that a newer retry already finished (see Truth Layer for why that guard was added).