Take subagent reports out of the main transcript, and separate turns with a rule
A row per finished background task is a screenful of dividers about work the reader was not asking after, and one of them turned out to be a whole shell command drawn as centred prose, because its words came from somewhere with no reason to keep them short. `Event::TaskNote` is gone entirely, along with the row that drew it. A subagent's closing report is recorded as that subagent's own transcript's closing text and is read in the subcard, which is where it was already going; what the parent gets a row for is a message a subagent genuinely sends it, which arrives by the peer path and has had one all along. What remains is the actual defect and the smallest thing that fixes it. The fold still refuses to grow a settled reply, so a turn boundary is always a message boundary, and where two replies then abut it puts a `TurnBreak` between them: a hairline, no words, no colour. Made by the fold rather than sent by the server, because it is not something that happened -- it is the boundary between two things that did. `joinPages` puts one in at a page seam, which the fold never gets to see. The task notification is still what closes a task in `Status::Waiting`'s bookkeeping, and the registry lookup that recognises one this translator never saw start is what makes that work for a session adopted across a restart. Verified on the emulator: three replies, three rules, and nothing about the helpers anywhere in the parent. 170 server tests, 85 JVM tests, ktfmt, clippy, rustfmt and Android lint clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ef1aad8776
commit
1bbb642973
13 files changed
+171
-407
No files matched your search
@@ -53,9 +53,10 @@
|
||||
//! streamed reply, one Bash call, then it finishes about three seconds
|
||||
//! later, the same lifecycle a real Task call has -- see `SUBAGENTS.md`.
|
||||
//! The parent's own turn ends in `waiting` rather than `idle` while they
|
||||
//! run, each one reports back with a `TaskNote`, and the parent answers it
|
||||
//! -- which is the whole of the shape a real background Task produces, and
|
||||
//! the one where two replies used to be drawn as one paragraph.
|
||||
//! run, each records its closing report in its own transcript, and the
|
||||
//! parent then runs a turn answering it -- which is the whole of the shape a
|
||||
//! real background Task produces, and the one where two replies used to be
|
||||
//! drawn as one paragraph.
|
||||
//!
|
||||
//! `/slow` earns its place: a queued message, a Stop button and a spinner are
|
||||
//! states that only exist mid-turn, and the obvious way to get one -- ask a
|
||||
@@ -956,18 +957,14 @@ async fn run_helper(
|
||||
);
|
||||
subagents.finish(&id);
|
||||
let _ = sink.send(Event::ToolEnd {
|
||||
id: id.clone(),
|
||||
id,
|
||||
output: "subagent finished".to_string(),
|
||||
});
|
||||
// The boundary the session's next turn begins at, and then that turn: the
|
||||
// And then the turn the session runs because the task reported back. The
|
||||
// parent has to say something afterwards, since the defect this
|
||||
// reproduces is two replies meeting with nothing between them.
|
||||
let _ = sink.send(Event::TaskNote {
|
||||
about: id,
|
||||
title: Some(title.clone()),
|
||||
status: "completed".to_string(),
|
||||
summary: Some(summary),
|
||||
});
|
||||
// reproduces is two replies meeting with nothing between them -- and
|
||||
// nothing at all about the helper goes into the *parent's* transcript,
|
||||
// which is the shape being reproduced.
|
||||
let _ = sink.send(Event::Status {
|
||||
state: SessionStatus::Running,
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user