vtcode_commons/ui_protocol/tool_summary.rs
1//! Data exchanged by compact per-call tool summaries.
2
3use crate::tool_types::CompactStr;
4
5/// Session-local key for a complete tool-output capture.
6///
7/// This is deliberately a UI protocol identifier. It is not persisted in
8/// `ThreadEvent` data and must not be treated as a tool-call identity outside
9/// the live terminal session.
10pub type ToolOutputId = u64;
11
12/// Presentation metadata for a compact command activity row.
13///
14/// The complete command output is sent through `RecordToolOutput` separately.
15/// Keeping this small metadata object independent means compact rendering can
16/// replace a row without truncating, reordering, or otherwise changing the
17/// captured stdout, stderr, PTY, or spool-backed transcript.
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct CompactActivityMetadata {
20 /// Identifier shared by all rows in one contiguous successful-command group.
21 pub group_id: u64,
22 /// Number of successful commands represented by the row.
23 pub command_count: usize,
24 /// The command text for a single-command row. Grouped rows leave this empty.
25 pub command: Option<CompactStr>,
26 /// Number of complete output lines hidden behind the review affordance.
27 pub hidden_line_count: usize,
28 /// Optional status or artifact text that remains visible in the row.
29 pub suffix: Option<CompactStr>,
30 /// First complete capture represented by the row, used as the review focus.
31 pub review_anchor: Option<ToolOutputId>,
32 /// All complete captures represented by the row, in render order.
33 ///
34 /// `review_anchor` remains the first capture for compatibility with the
35 /// click protocol; this list lets the UI re-anchor every member of a
36 /// grouped row without guessing from transcript text.
37 pub review_anchors: Vec<ToolOutputId>,
38}
39
40impl CompactActivityMetadata {
41 /// Return the compact row text without the UI-only review affordance.
42 pub fn display_text(&self) -> String {
43 let mut text = if self.command_count > 1 {
44 format!("• Ran {} commands", self.command_count)
45 } else {
46 format!("• Ran {}", self.command.as_deref().unwrap_or("command"))
47 };
48
49 if self.command_count == 1 && self.hidden_line_count > 0 {
50 text.push_str(&format!(" · … +{} lines", self.hidden_line_count));
51 }
52 if let Some(suffix) = self.suffix.as_deref().filter(|suffix| !suffix.is_empty()) {
53 text.push_str(" · ");
54 text.push_str(suffix);
55 }
56 text
57 }
58}
59
60/// UI-only payload that reopens a completed-edit diff as full-viewport review.
61///
62/// Not part of `ThreadEvent`. The transcript notice text is the activation
63/// target; `unified` is the retained preview used when before/after are absent.
64#[derive(Debug, Clone, PartialEq, Eq)]
65pub struct DiffReviewAnchor {
66 /// Workspace-visible file path for the review header.
67 pub file_path: String,
68 /// Retained unified preview body.
69 pub unified: String,
70 /// Rows omitted from the compact transcript body, when known.
71 pub omitted_lines: u64,
72 /// Exact notice text that should activate this review.
73 pub notice: String,
74}
75
76#[cfg(test)]
77mod tests {
78 use super::CompactActivityMetadata;
79
80 #[test]
81 fn compact_activity_display_includes_single_command_output_count() {
82 let activity = CompactActivityMetadata {
83 group_id: 1,
84 command_count: 1,
85 command: Some("cargo check".into()),
86 hidden_line_count: 3,
87 suffix: None,
88 review_anchor: Some(7),
89 review_anchors: vec![7],
90 };
91
92 assert_eq!(activity.display_text(), "• Ran cargo check · … +3 lines");
93 }
94
95 #[test]
96 fn compact_activity_display_collapses_grouped_commands() {
97 let activity = CompactActivityMetadata {
98 group_id: 2,
99 command_count: 4,
100 command: None,
101 hidden_line_count: 12,
102 suffix: Some("output retained".into()),
103 review_anchor: Some(9),
104 review_anchors: vec![9],
105 };
106
107 assert_eq!(activity.display_text(), "• Ran 4 commands · output retained");
108 }
109}
110
111#[derive(Debug, Clone, PartialEq, Eq)]
112pub struct CompactToolSummaryLine {
113 pub kind: CompactToolSummaryLineKind,
114 pub text: String,
115}
116
117#[derive(Debug, Clone, Copy, PartialEq, Eq)]
118pub enum CompactToolSummaryLineKind {
119 Info,
120 Detail,
121}