Demo agents: visible model failures, one agent per document, folded reasoning - #105
Open
jpcamara wants to merge 19 commits into
Open
Demo agents: visible model failures, one agent per document, folded reasoning#105jpcamara wants to merge 19 commits into
jpcamara wants to merge 19 commits into
Conversation
… reasoning
A model failure used to fall back to the stub's canned text, so a broken key
or a timeout read as the agent's own words. LlmReviewer now raises a
ModelError with a short reason; StreamJob records it, and the agents report
it in the ledger ("couldn't finish the review: the model timed out"), take
out the heading or blank lines opened for a draft that never came, put the
task back on the list unchecked, and leave passing changes alone for thirty
seconds. A failure while reacting to a request no longer ends the agent.
Task scans run on the agent's own schedule (SCAN_EVERY and the backoff)
instead of every idle tick; before, a failed draft was retried two seconds
later, opening a new empty heading each time.
The controller keeps a registry of running agents, so a second invite for
the same document returns 409. The page disables the invite button while an
agent is in the roster, and the bar says "the agent left" once it goes.
Reasoning is filed per stream: a StreamJob carries a label ("the review",
the section title) through its thread, the presence keeps a hash of
reasoning by label, and the ledger renders one folded block per label that
follows the current entry while the stream runs. Folded blocks show the last
few lines; a click opens them. A detail-less repeat of a recent status no
longer makes a new entry.
Caret updates while streaming are sent at most four times a second and only
when something moved; a stream's last step no longer presents an empty
status. "@agent" with nothing after it (or "@agent take" alone) is a request
still being typed and is left alone; in the Lexxy agent, a burst that ends
with Enter acts on the @agent line rather than the empty block after it.
"paused" survives the status fade. Shorter introduction, plus a hint under
the buttons on both pages. The consider prompt asks for notes without block
numbers.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017TeaovH2jyHARHJSyQ8Afo
A task that asks for a line got two to four paragraphs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TeaovH2jyHARHJSyQ8Afo
…r in the document The GLM router took 5 to 18 seconds before its first word because it reasoned at length first. Reviews and drafts now ask for medium reasoning effort (first text in about a second, some reasoning still streamed to the ledger) and answers, edit plans, and the look at a change ask for low (under a second). AGENT_REASONING and AGENT_QUICK_REASONING set them; AGENT_FAST_MODEL is optional now and unset by default, since the same model at low effort is as quick as the separate one was. Up to two drafts run at once, each a Draft value with its own writer, job, heading, and title, so a second task no longer waits for the first. A draft yields only while someone is at the point being written (the block the words go into or the one after it, or the line either side of it in markdown) instead of anywhere in the section. Streams at the end of the document anchor to their own heading (Lexxy) or to the closing newline (markdown) rather than to "the end", so two streams no longer interleave. The ledger is stored in the document: the agent appends each status to a Y.Array named agent-log (capped at 200), and the pages render from it, so every page shows the same history and a reload keeps it. Reasoning still comes from presence and attaches to the newest entry. Caret moves and the heartbeat's fade to "listening" are not logged. The invite button and the agent's own controls no longer hold follow, and the page shows the agent's caret once when it arrives. An empty document no longer crashes the Lexxy agent on its greeting. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TeaovH2jyHARHJSyQ8Afo
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TeaovH2jyHARHJSyQ8Afo
A document invited more than once appended a new "Agent review" heading each time. A new review now goes at the end of the existing section, and the heading is only removed on failure when the agent added it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TeaovH2jyHARHJSyQ8Afo
Several streams at once shared the one caret, so text grew in places with no cursor beside it. The review now finishes before the first task, and tasks run one after another. AGENT_DRAFTS raises the number of drafts at once for anyone who wants the parallel mode back. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TeaovH2jyHARHJSyQ8Afo
… up, ledger under the editor Four things found by using the markdown page as a person would: The remote caret and highlight vanished after a click and never came back. The page scrolled the editor to the agent from inside an awareness event; when that event fired during the editor's own update (a click sets the local cursor into awareness from inside one), CodeMirror threw "Calls to EditorView.update are not allowed while an update is in progress" and disabled the remote-cursor plugin for the rest of the page's life. The scroll is deferred now. Requests after the agent's work often did nothing visible. Every @agent line now gets an immediate "on it" status with the request in it. A request is answered once per line, not once per wording, so asking the same thing again works. "this document" is no longer read as a selection; with nothing selected, "rewrite this" means the paragraph the request was typed under, including when the request sits right below it with no blank line. The author of a request is the person whose caret is on the line or the one after it (they pressed Enter), or the only other person here. A rewrite of a selection inside a paragraph is held to those words. The request line's deletion no longer leaves a double blank line. Follow: typing holds it for eight seconds and a click or scroll for three; when the hold ends the page catches up with the agent if it moved; the editor scrolls inside itself and then the page scrolls so the spot is on screen. The ledger goes back under the editor. Per-step statuses while answering or applying an edit are no longer written to it. Lexxy: the caret at the end of a list is placed on the last item, which Lexical can draw; the same request changes, untested there for now. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TeaovH2jyHARHJSyQ8Afo
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TeaovH2jyHARHJSyQ8Afo
The page-level scroll referenced a variable scoped to the deferred editor scroll. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TeaovH2jyHARHJSyQ8Afo
No page header or nav; the people here and the invite button sit on one row at the top; the editor and preview stop at 42vh so what is under them stays in view; the invite button is a filled pill. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TeaovH2jyHARHJSyQ8Afo
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TeaovH2jyHARHJSyQ8Afo
Both sized to their own content before, so they ended at different heights. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TeaovH2jyHARHJSyQ8Afo
Cards with soft shadows on an off-white ground, a pulsing dot while the agent is in, chip buttons, a labelled activity ledger, and the editor without a hard border. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TeaovH2jyHARHJSyQ8Afo
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TeaovH2jyHARHJSyQ8Afo
On joining, the agent says hello and goes straight to the task list, or to listening when there is none. "@agent review" (and a button on the markdown page) writes a review of the document as it is; AGENT_REVIEW=1 restores the review on joining. Two fixes that surfaced without the review running first: the first caret update read a timestamp that was never set, which crashed the work loop, and the crash path stopped the stream in a way that counted the draft as done. The caret timestamp defaults to zero, and a crashed draft now puts its task back on the list and says so. "up next" is no longer logged twice when the announcement and the pickup agree. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TeaovH2jyHARHJSyQ8Afo
…ction "Tackle any grammar or spelling issues" produced a section listing the issues. A task whose wording asks for a change to what is there (fix, correct, tighten, rename, spelling, grammar, and so on) now runs as an edit plan over the document, applied in place with the task list itself left alone, and is checked off with "changed N paragraphs in place". Tasks that start with draft, write, add, create, outline, or prepare still open a section. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TeaovH2jyHARHJSyQ8Afo
The agent wrote at a steady pace, but the page received it in clumps: the preview was re-parsed and replaced on nearly every update and the page scrolled on every caret move, which blocked the browser's main thread for a second or more at a time, so incoming updates piled up and then landed together. The preview now renders at most twice a second and only when the text changed, and the page scrolls only when the caret is off screen. On the agent side, three related changes: the loop takes a turn every tenth of a second while writing (a word or so per turn) instead of every forty milliseconds (two characters, each its own store insert and broadcast); the pacer never pays out more than half a second of text after a stall; and an incoming update that leaves the text as it was is not treated as a change, which was costing a settle wait mid-draft. A paragraph replacement retypes only the part that differs, so a spelling fix is a small change in place rather than the paragraph wiped and written again. A loop stall of over half a second while writing is logged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TeaovH2jyHARHJSyQ8Afo
Whichever key is set is used: FIREWORKS_API_KEY, OPENROUTER_API_KEY, or ANTHROPIC_API_KEY, with AGENT_PROVIDER to choose when several are and AGENT_MODEL to override the model. OpenRouter goes through ruby_llm's own provider and defaults to "openrouter/free", which routes across their free models so no single one takes all the requests. Two failures free models produce often now read plainly in the document: a rate limit says to try again in a minute, and a rejected key says so instead of repeating the provider's wording. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TeaovH2jyHARHJSyQ8Afo
"openrouter/free" routes to a different provider on each call. Over three calls it picked three, and one of them answered an edit-plan request by echoing the JSON template, which the grammar-fix task cannot use. The default is now nex-agi/nex-n2.5-mini:free, measured through the reviewer at about a second to the first word of an answer, a correct edit plan in under one, and three seconds to the first word of a draft. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TeaovH2jyHARHJSyQ8Afo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Polish on the demo agents (Lexxy and markdown pages), from a round of hands-on testing.
LlmReviewerraisesModelErrorwith a short reason;StreamJobrecords it; the agents say "couldn't finish the review: …", remove the heading or blank lines they opened for a draft that never came, put the task back on the list unchecked, and back off from passing changes for thirty seconds. A failure while reacting to a request no longer ends the agent.SCAN_EVERYand the backoff instead of running every idle tick. A failed draft used to be retried two seconds later, opening a new empty heading each time.StreamJobcarries a label through its thread, the presence keeps reasoning by label, and the ledger renders one folded block per label (last few lines, click to open). The review's and a draft's reasoning no longer interleave. Detail-less repeats of a recent status do not make new ledger entries.@agentor@agent takealone) are left alone until there is something after them. In the Lexxy agent, a typing burst that ends with Enter acts on the@agentline rather than the empty block after it.public/markdown.jsis now ignored likelexxy.js.🤖 Generated with Claude Code
https://claude.ai/code/session_017TeaovH2jyHARHJSyQ8Afo