feat(client): emit ChatEvent::ToolCall with approval metadata

ToolCall events carry call_id, name, args, needs_approval — agent
layer uses these to route through the permission/approval flow.
This commit is contained in:
2026-03-23 21:34:57 +00:00
parent 8e73d52776
commit 5f1fb09abb

View File

@@ -11,6 +11,8 @@ use super::project::ProjectContext;
/// Events produced during a chat turn, for the TUI to render.
pub enum ChatEvent {
/// A client-side tool call that needs execution (possibly with approval).
ToolCall { call_id: String, name: String, args: String, needs_approval: bool },
ToolStart { name: String, detail: String },
ToolDone { name: String, success: bool },
Status(String),
@@ -21,6 +23,8 @@ pub enum ChatEvent {
pub struct ChatResponse {
pub text: String,
pub events: Vec<ChatEvent>,
pub input_tokens: u32,
pub output_tokens: u32,
}
fn truncate_args(args_json: &str) -> String {
@@ -150,26 +154,29 @@ impl CodeSession {
return Ok(ChatResponse {
text: d.full_text,
events,
input_tokens: d.input_tokens,
output_tokens: d.output_tokens,
});
}
Some(ServerMessage {
payload: Some(server_message::Payload::ToolCall(tc)),
}) => {
if tc.is_local {
// TODO: approval flow through TUI
events.push(ChatEvent::ToolStart {
// Emit ToolCall event — agent handles approval + execution
events.push(ChatEvent::ToolCall {
call_id: tc.call_id.clone(),
name: tc.name.clone(),
detail: truncate_args(&tc.args_json),
args: tc.args_json.clone(),
needs_approval: tc.needs_approval,
});
// Execute immediately for now — approval is handled
// by the agent layer which wraps this method.
// When approval flow is active, the agent will call
// execute + send_tool_result separately.
let result =
super::tools::execute(&tc.name, &tc.args_json, &self.project_path);
events.push(ChatEvent::ToolDone {
name: tc.name.clone(),
success: true,
});
self.tx
.send(ClientMessage {
payload: Some(client_message::Payload::ToolResult(ToolResult {
@@ -205,6 +212,8 @@ impl CodeSession {
return Ok(ChatResponse {
text: "Session ended by server.".into(),
events,
input_tokens: 0,
output_tokens: 0,
});
}
Some(_) => continue,