Skip to content

Commit 7d057bf

Browse files
committed
instruments assistant text to emit structured events
1 parent 6a4ec78 commit 7d057bf

File tree

9 files changed

+128
-255
lines changed

9 files changed

+128
-255
lines changed

crates/chat-cli-ui/src/conduit.rs

Lines changed: 26 additions & 204 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,6 @@ use crate::protocol::{
2020

2121
const TOOL_BULLET: &str = " ● ";
2222
const CONTINUATION_LINE: &str = " ⋮ ";
23-
const PURPOSE_ARROW: &str = " ↳ ";
24-
const SUCCESS_TICK: &str = " ✓ ";
25-
const ERROR_EXCLAMATION: &str = " ❗ ";
26-
const DELEGATE_NOTIFIER: &str = "[BACKGROUND TASK READY]";
2723

2824
#[derive(thiserror::Error, Debug)]
2925
pub enum ConduitError {
@@ -71,91 +67,23 @@ impl ViewEnd {
7167
stdout.flush()?;
7268
},
7369
},
74-
Event::RunStarted(run_started) => {
75-
let _ = execute!(
76-
stderr,
77-
Print(format!(
78-
"Run started - Thread: {}, Run: {}\n",
79-
run_started.thread_id, run_started.run_id
80-
))
81-
);
82-
},
83-
Event::RunFinished(run_finished) => {
84-
let result_info = run_finished
85-
.result
86-
.as_ref()
87-
.map(|r| format!(" with result: {:?}", r))
88-
.unwrap_or_default();
89-
let _ = execute!(
90-
stderr,
91-
Print(format!(
92-
"Run finished - Thread: {}, Run: {}{}\n",
93-
run_finished.thread_id, run_finished.run_id, result_info
94-
))
95-
);
96-
},
97-
Event::RunError(run_error) => {
98-
let code_info = run_error
99-
.code
100-
.as_ref()
101-
.map(|c| format!(" (Code: {})", c))
102-
.unwrap_or_default();
103-
let _ = execute!(
104-
stderr,
105-
Print(format!("Run error{}: {}\n", code_info, run_error.message))
106-
);
107-
},
108-
Event::StepStarted(step_started) => {
109-
let _ = execute!(stderr, Print(format!("Step started: {}\n", step_started.step_name)));
110-
},
111-
Event::StepFinished(step_finished) => {
112-
let _ = execute!(stderr, Print(format!("Step finished: {}\n", step_finished.step_name)));
113-
},
114-
Event::TextMessageStart(text_message_start) => {
115-
let _ = execute!(
116-
stderr,
117-
Print(format!(
118-
"Text message started - ID: {}, Role: {:?}\n",
119-
text_message_start.message_id, text_message_start.role
120-
))
121-
);
70+
Event::RunStarted(_run_started) => {},
71+
Event::RunFinished(_run_finished) => {},
72+
Event::RunError(_run_error) => {},
73+
Event::StepStarted(_step_started) => {},
74+
Event::StepFinished(_step_finished) => {},
75+
Event::TextMessageStart(_text_message_start) => {
76+
queue!(stdout, theme_source.success_fg(), Print("> "), theme_source.reset(),)?;
12277
},
12378
Event::TextMessageContent(text_message_content) => {
124-
let _ = execute!(
125-
stderr,
126-
Print(format!(
127-
"Text content ({}): {}\n",
128-
text_message_content.message_id, text_message_content.delta
129-
))
130-
);
131-
},
132-
Event::TextMessageEnd(text_message_end) => {
133-
let _ = execute!(
134-
stderr,
135-
Print(format!("Text message ended - ID: {}\n", text_message_end.message_id))
136-
);
79+
stdout.write_all(&text_message_content.delta)?;
80+
stdout.flush()?;
13781
},
138-
Event::TextMessageChunk(text_message_chunk) => {
139-
let message_id = text_message_chunk
140-
.message_id
141-
.as_ref()
142-
.map(|id| format!(" ID: {}", id))
143-
.unwrap_or_default();
144-
let role = text_message_chunk
145-
.role
146-
.as_ref()
147-
.map(|r| format!(" Role: {:?}", r))
148-
.unwrap_or_default();
149-
let delta = text_message_chunk
150-
.delta
151-
.as_ref()
152-
.map(|d| format!(" Content: {}", d))
153-
.unwrap_or_default();
154-
let _ = execute!(
155-
stderr,
156-
Print(format!("Text message chunk{}{}{}\n", message_id, role, delta))
157-
);
82+
Event::TextMessageEnd(_text_message_end) => {
83+
queue!(stderr, theme_source.reset(), theme_source.reset_attributes())?;
84+
execute!(stdout, style::Print("\n"))?;
15885
},
86+
Event::TextMessageChunk(_text_message_chunk) => {},
15987
Event::ToolCallStart(tool_call_start) => {
16088
let ToolCallStart {
16189
tool_call_name,
@@ -211,128 +139,22 @@ impl ViewEnd {
211139
Event::ToolCallResult(_tool_call_result) => {
212140
// noop for now (currently we don't show the tool call results to users)
213141
},
214-
Event::StateSnapshot(state_snapshot) => {
215-
let _ = execute!(
216-
stderr,
217-
Print(format!("State snapshot: {:?}\n", state_snapshot.snapshot))
218-
);
219-
},
142+
Event::StateSnapshot(_state_snapshot) => {},
220143
Event::StateDelta(state_delta) => {
221144
let _ = execute!(stderr, Print(format!("State delta: {:?}\n", state_delta.delta)));
222145
},
223-
Event::MessagesSnapshot(messages_snapshot) => {
224-
let _ = execute!(
225-
stderr,
226-
Print(format!(
227-
"Messages snapshot: {} messages\n",
228-
messages_snapshot.messages.len()
229-
))
230-
);
231-
},
232-
Event::Raw(raw) => {
233-
let source_info = raw.source.as_ref().map(|s| format!(" from {}", s)).unwrap_or_default();
234-
let _ = execute!(stderr, Print(format!("Raw event{}: {:?}\n", source_info, raw.event)));
235-
},
236-
Event::Custom(custom) => {
237-
let _ = execute!(
238-
stderr,
239-
Print(format!(
240-
"Custom event - Name: {}, Value: {:?}\n",
241-
custom.name, custom.value
242-
))
243-
);
244-
},
245-
Event::ActivitySnapshotEvent(activity_snapshot_event) => {
246-
let _ = execute!(
247-
stderr,
248-
Print(format!(
249-
"Activity snapshot - Message: {}, Type: {}, Content: {:?}\n",
250-
activity_snapshot_event.message_id,
251-
activity_snapshot_event.activity_type,
252-
activity_snapshot_event.content
253-
))
254-
);
255-
},
256-
Event::ActivityDeltaEvent(activity_delta_event) => {
257-
let _ = execute!(
258-
stderr,
259-
Print(format!(
260-
"Activity delta - Message: {}, Type: {}, Patch: {:?}\n",
261-
activity_delta_event.message_id,
262-
activity_delta_event.activity_type,
263-
activity_delta_event.patch
264-
))
265-
);
266-
},
267-
Event::ReasoningStart(reasoning_start) => {
268-
if let Some(info) = reasoning_start.encrypted_content.as_deref() {
269-
let _ = execute!(
270-
stderr,
271-
Print(format!(
272-
"Reasoning started - Message: {}{}\n",
273-
reasoning_start.message_id, info
274-
))
275-
);
276-
}
277-
},
278-
Event::ReasoningMessageStart(reasoning_message_start) => {
279-
let _ = execute!(
280-
stderr,
281-
Print(format!(
282-
"Reasoning message started - ID: {}, Role: {:?}\n",
283-
reasoning_message_start.message_id, reasoning_message_start.role
284-
))
285-
);
286-
},
287-
Event::ReasoningMessageContent(reasoning_message_content) => {
288-
let _ = execute!(
289-
stderr,
290-
Print(format!(
291-
"Reasoning content ({}): {}\n",
292-
reasoning_message_content.message_id, reasoning_message_content.delta
293-
))
294-
);
295-
},
296-
Event::ReasoningMessageEnd(reasoning_message_end) => {
297-
let _ = execute!(
298-
stderr,
299-
Print(format!(
300-
"Reasoning message ended - ID: {}\n",
301-
reasoning_message_end.message_id
302-
))
303-
);
304-
},
305-
Event::ReasoningMessageChunk(reasoning_message_chunk) => {
306-
let message_id = reasoning_message_chunk
307-
.message_id
308-
.as_ref()
309-
.map(|id| format!(" ID: {}", id))
310-
.unwrap_or_default();
311-
let delta = reasoning_message_chunk
312-
.delta
313-
.as_ref()
314-
.map(|d| format!(" Content: {}", d))
315-
.unwrap_or_default();
316-
let _ = execute!(
317-
stderr,
318-
Print(format!("Reasoning message chunk{}{}\n", message_id, delta))
319-
);
320-
},
321-
Event::ReasoningEnd(reasoning_end) => {
322-
let _ = execute!(
323-
stderr,
324-
Print(format!("Reasoning ended - Message: {}\n", reasoning_end.message_id))
325-
);
326-
},
327-
Event::MetaEvent(meta_event) => {
328-
let _ = execute!(
329-
stderr,
330-
Print(format!(
331-
"Meta event - Type: {}, Payload: {:?}\n",
332-
meta_event.meta_type, meta_event.payload
333-
))
334-
);
335-
},
146+
Event::MessagesSnapshot(_messages_snapshot) => {},
147+
Event::Raw(_raw) => {},
148+
Event::Custom(_custom) => {},
149+
Event::ActivitySnapshotEvent(_activity_snapshot_event) => {},
150+
Event::ActivityDeltaEvent(_activity_delta_event) => {},
151+
Event::ReasoningStart(_reasoning_start) => {},
152+
Event::ReasoningMessageStart(_reasoning_message_start) => {},
153+
Event::ReasoningMessageContent(_reasoning_message_content) => {},
154+
Event::ReasoningMessageEnd(_reasoning_message_end) => {},
155+
Event::ReasoningMessageChunk(_reasoning_message_chunk) => {},
156+
Event::ReasoningEnd(_reasoning_end) => {},
157+
Event::MetaEvent(_meta_event) => {},
336158
Event::ToolCallRejection(tool_call_rejection) => todo!(),
337159
}
338160
}

crates/chat-cli-ui/src/protocol.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ pub struct TextMessageStart {
101101
#[serde(rename_all = "camelCase")]
102102
pub struct TextMessageContent {
103103
pub message_id: String,
104-
pub delta: String,
104+
pub delta: Vec<u8>,
105105
}
106106

107107
/// Signals the end of a text message

crates/chat-cli/src/cli/agent/mod.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,11 @@ pub enum AgentConfigError {
9292
#[error("File URI not found: {uri} (resolved to {path})")]
9393
FileUriNotFound { uri: String, path: PathBuf },
9494
#[error("Failed to read file URI: {uri} (resolved to {path}): {error}")]
95-
FileUriReadError { uri: String, path: PathBuf, error: std::io::Error },
95+
FileUriReadError {
96+
uri: String,
97+
path: PathBuf,
98+
error: std::io::Error,
99+
},
96100
#[error("Invalid file URI format: {uri}")]
97101
InvalidFileUri { uri: String },
98102
}
@@ -314,26 +318,24 @@ impl Agent {
314318
Ok(content) => Ok(Some(content)),
315319
Err(file_uri::FileUriError::InvalidUri { uri }) => {
316320
Err(AgentConfigError::InvalidFileUri { uri })
317-
}
318-
Err(file_uri::FileUriError::FileNotFound { path }) => {
319-
Err(AgentConfigError::FileUriNotFound {
320-
uri: prompt_str.clone(),
321-
path
322-
})
323-
}
321+
},
322+
Err(file_uri::FileUriError::FileNotFound { path }) => Err(AgentConfigError::FileUriNotFound {
323+
uri: prompt_str.clone(),
324+
path,
325+
}),
324326
Err(file_uri::FileUriError::ReadError { path, source }) => {
325327
Err(AgentConfigError::FileUriReadError {
326328
uri: prompt_str.clone(),
327329
path,
328-
error: source
330+
error: source,
329331
})
330-
}
332+
},
331333
}
332334
} else {
333335
// Return the prompt as-is for backward compatibility
334336
Ok(Some(prompt_str.clone()))
335337
}
336-
}
338+
},
337339
}
338340
}
339341

@@ -990,8 +992,9 @@ fn validate_agent_name(name: &str) -> eyre::Result<()> {
990992

991993
#[cfg(test)]
992994
mod tests {
993-
use serde_json::json;
994995
use std::fs;
996+
997+
use serde_json::json;
995998
use tempfile::TempDir;
996999

9971000
use super::*;

crates/chat-cli/src/cli/chat/checkpoint.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ use serde::{
2727
};
2828
use tracing::debug;
2929

30-
use crate::cli::ConversationState;
3130
use super::util::truncate_safe;
31+
use crate::cli::ConversationState;
3232
use crate::cli::chat::conversation::HistoryEntry;
3333
use crate::os::Os;
3434

crates/chat-cli/src/cli/chat/custom_spinner.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,7 @@ pub struct Spinners {
1919
impl Spinners {
2020
pub fn new(message: String) -> Self {
2121
// Hide the cursor when starting the spinner
22-
let _ = execute!(
23-
std::io::stderr(),
24-
cursor::Hide
25-
);
22+
let _ = execute!(std::io::stderr(), style::Print("\n"), cursor::Hide);
2623

2724
let pb = ProgressBar::new_spinner();
2825
pb.set_style(
@@ -62,7 +59,6 @@ impl Drop for Spinners {
6259
std::io::stderr(),
6360
cursor::MoveToColumn(0),
6461
terminal::Clear(terminal::ClearType::CurrentLine),
65-
style::Print("\n"),
6662
cursor::Show
6763
);
6864
}

0 commit comments

Comments
 (0)