Select any of the transcript, and take a queued message back
Two things a reader could not do to what is on screen.
**Selection.** Nothing in the transcript was selectable at all, so a
command, a path or an error message could be read and not copied. One
`SelectionContainer` around the whole list rather than one per row: a
transcript is one body of text to a reader, and a selection has to be able
to run from a reply into the tool output under it. Per row it also could
not, and whatever was drawn without a container would have been silently
unselectable -- a state nothing on screen reports. Rows keep their tap
handlers; checked on the emulator that expanding a tool call, scrolling and
flinging are all unaffected, since a selection is a long press.
**Taking a message back.** A message sent into a running turn sits as a
bubble waiting to be read, and there was no way to change your mind: it is
tappable now, and the server answers `POST /sessions/{id}/unqueue`.
The answer has three states, and the middle one is the point. Claude's
driver writes a steer into the CLI's stdin the instant it arrives -- that
is what makes it reach the model at the next tool boundary rather than at
the end of the turn, and it was measured -- so the line is already gone and
`AlreadySent` is the only honest answer it can give. Holding the write
until a boundary would make the drop real and cost a steer one model call,
which is the latency the immediate write exists to remove; rejected on that
trade, with the reasoning in PLAN.md. The refusal is drawn on the bubble
that was pressed rather than in the error row under the header, a screen
away from it.
Where a driver really does hold its queue -- echo today -- the message goes
for good, and it goes as an `Event::MessageDropped` rather than as a return
value: every device watching the session loses the bubble, and a phone that
reconnects and replays the `messageQueued` does not put back one that was
cancelled with nothing left to resolve it.
This commit is contained in:
1 parent
778b2e3b04
commit
82401cd887
12 files changed
+439
-48
No files matched your search
@@ -57,7 +57,7 @@ use serde_json::{Value, json};
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use super::driver::{Driver, Event, EventSink, ImageRef, SessionStatus};
|
||||
use super::driver::{Driver, Event, EventSink, ImageRef, SessionStatus, Unqueued};
|
||||
use super::process;
|
||||
use super::transport::{Launch, Streams, Transport};
|
||||
use crate::config::{ProviderConfig, SessionConfig};
|
||||
@@ -595,6 +595,24 @@ impl Driver for ClaudeDriver {
|
||||
self.send_line(line);
|
||||
}
|
||||
|
||||
/// Never droppable, and that is a property of the design rather than
|
||||
/// an omission.
|
||||
///
|
||||
/// A message queued here has already been written to the CLI's stdin
|
||||
/// -- see [`Queue`], where only the *announcement* waits -- because
|
||||
/// that is what makes a steer reach the model at the next tool
|
||||
/// boundary instead of at the end of the turn. A line in the fifo
|
||||
/// cannot be recalled, so the only honest answers are "the session has
|
||||
/// already been told" and "nothing is waiting under that id".
|
||||
fn unqueue(&self, id: &str) -> Unqueued {
|
||||
let queue = self.queue.lock().unwrap();
|
||||
if queue.awaiting.iter().any(|(waiting, ..)| waiting == id) {
|
||||
Unqueued::AlreadySent
|
||||
} else {
|
||||
Unqueued::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
fn answer_question(&self, id: &str, answers: &[String]) {
|
||||
let response = {
|
||||
let mut state = self.state.lock().unwrap();
|
||||
|
||||
Reference in new issue
Block a user