1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
//! Settling a tool window the §2.9 stop cascade felled.
//!
//! A stop landing in a **tool window** finds the step's model-output
//! entry already committed (§2.5 — the assistant entry lands before any
//! tool runs) while some of its `tool_use` blocks have no committed
//! `tool_result`. Left that way the branch tip is the §6 *one
//! non-replayable state*: `lernie advance` declines it loudly
//! (`Error::UnpairedToolUse`), so no deposit could ever revive the agent
//! — the stop would retire the branch instead of ending the work it
//! had in flight, contradicting §2.9 ("a stop is not a locked door … a message
//! into the stopped agent's inbox starts a driver and resumes the same
//! branch").
//!
//! So the stopped exit **settles its own window before it deposits**:
//! one in-band `is_error` `tool_result` per unanswered `tool_use` id —
//! the same shape a grant decline and a control refusal already commit
//! ([`super::refusal`], [`super::seam::refusal_text`]) — saying the
//! invocation was cut short. The tail is then settled, the warrant is
//! `ModelCallDue`, an ordinary deposit revives the agent, and the model
//! reads *in band* that it was interrupted, which is both the truthful
//! record and the useful one.
//!
//! Deleting the tail — what the dispatch commit does at a **fork**
//! ([`super::super::step_commit::unsettled`], §2.3 step 2) — is the
//! wrong repair here: that tail belongs to the agent's *own* branch,
//! where discarding it would throw away the assistant's reasoning and
//! leave the model with no evidence it was ever cut off.
//!
//! A **hold** is deliberately not settled (§3.3 *Tool control*): a
//! parked branch's unpaired tail is its state, and its mark asserts
//! nothing at or past the held block ran. Only the stop settles.
use transcript;
use ToolWindow;
use crate;
use Content;
use Path;
/// Commit an interrupted `tool_result` for every `tool_use` in
/// `assistant_content` still unanswered, and report the window stopped.
///
/// Idempotent by construction: the answered ids are read from the
/// transcript (the record, never a stored cursor — PRINCIPLES single
/// source of truth), so results committed before the stop keep the one
/// entry they already have.
pub
/// The in-band text an unanswered invocation carries as its `is_error`
/// `tool_result` — why there is no output, in the terms §2.9 gives it.
/// No result envelope and no exit code: nothing returned, so none is
/// invented (§3.3, the [`super::seam::refusal_text`] discipline).