A tool call can say it failed, and what it is for, without a renderer

P1b's pure half (docs/RUST.md). Three pieces, all testable with no
widget in sight:

- `event_model::Event::ToolEnd` gains `is_error`, read from the CLI's own
  `tool_result` field by both the live translator and the import replay
  (`import::tool_result_is_error`, one reader so the two cannot disagree
  about the same conversation). Without it a result is all a card has,
  and a broken call draws exactly as confidently as one that worked --
  the missing state, not a wrong one. `#[serde(default)]`, so an older
  transcript reads back as "not reported to have failed".
- `client_core::transcript_fold::ToolState`: Running, Deciding,
  Succeeded, Failed, NoResult. The pair it exists for is the last two
  against Succeeded-with-empty-output -- a call that printed nothing and
  a call whose result never arrived leave the same empty string, and only
  the session's status separates "still going" from "nobody found out".
- `client_core::tool_summary::parse_tool_input` and
  `client_core::durations`: `ToolInput.kt`'s subject/description/timeout
  split and `Durations.kt`'s span formatting, ported with their tests.

The echo driver's three-call run now has a failing middle call, so the
failed appearance is reachable from `ui-sandbox.sh` at all.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
irisandClaude Fable 5.1 committed 2026-09-06 19:46:21 -04:00
1 parent 69525bd131
commit 9079276ec8
9 files changed
+679 -4

No files matched your search

+13
View File
@@ -150,6 +150,19 @@ pub enum Event {
ToolEnd {
id: String,
output: String,
/// Whether the tool reported that the call *failed*, from the
/// CLI's own `is_error` on the `tool_result`.
///
/// Added 2026-09-06 with the tool-call cards (RUST.md's P1b),
/// because without it a result is the only thing a card has and a
/// failed call is drawn as confidently as a successful one -- the
/// missing state, not a wrong one. `#[serde(default)]` so a
/// transcript written before this field, or a peer on an older
/// build, reads back as "not reported to have failed" rather than
/// failing to parse; that is the same claim the field's absence
/// used to make implicitly.
#[serde(default)]
is_error: bool,
},
/// An image the session produced or was sent, saved under the session
/// dir and referenced by id; the phone fetches it by URL.