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:
@@ -11,6 +11,8 @@ use super::project::ProjectContext;
|
|||||||
|
|
||||||
/// Events produced during a chat turn, for the TUI to render.
|
/// Events produced during a chat turn, for the TUI to render.
|
||||||
pub enum ChatEvent {
|
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 },
|
ToolStart { name: String, detail: String },
|
||||||
ToolDone { name: String, success: bool },
|
ToolDone { name: String, success: bool },
|
||||||
Status(String),
|
Status(String),
|
||||||
@@ -21,6 +23,8 @@ pub enum ChatEvent {
|
|||||||
pub struct ChatResponse {
|
pub struct ChatResponse {
|
||||||
pub text: String,
|
pub text: String,
|
||||||
pub events: Vec<ChatEvent>,
|
pub events: Vec<ChatEvent>,
|
||||||
|
pub input_tokens: u32,
|
||||||
|
pub output_tokens: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn truncate_args(args_json: &str) -> String {
|
fn truncate_args(args_json: &str) -> String {
|
||||||
@@ -150,26 +154,29 @@ impl CodeSession {
|
|||||||
return Ok(ChatResponse {
|
return Ok(ChatResponse {
|
||||||
text: d.full_text,
|
text: d.full_text,
|
||||||
events,
|
events,
|
||||||
|
input_tokens: d.input_tokens,
|
||||||
|
output_tokens: d.output_tokens,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Some(ServerMessage {
|
Some(ServerMessage {
|
||||||
payload: Some(server_message::Payload::ToolCall(tc)),
|
payload: Some(server_message::Payload::ToolCall(tc)),
|
||||||
}) => {
|
}) => {
|
||||||
if tc.is_local {
|
if tc.is_local {
|
||||||
// TODO: approval flow through TUI
|
// Emit ToolCall event — agent handles approval + execution
|
||||||
events.push(ChatEvent::ToolStart {
|
events.push(ChatEvent::ToolCall {
|
||||||
|
call_id: tc.call_id.clone(),
|
||||||
name: tc.name.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 =
|
let result =
|
||||||
super::tools::execute(&tc.name, &tc.args_json, &self.project_path);
|
super::tools::execute(&tc.name, &tc.args_json, &self.project_path);
|
||||||
|
|
||||||
events.push(ChatEvent::ToolDone {
|
|
||||||
name: tc.name.clone(),
|
|
||||||
success: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
self.tx
|
self.tx
|
||||||
.send(ClientMessage {
|
.send(ClientMessage {
|
||||||
payload: Some(client_message::Payload::ToolResult(ToolResult {
|
payload: Some(client_message::Payload::ToolResult(ToolResult {
|
||||||
@@ -205,6 +212,8 @@ impl CodeSession {
|
|||||||
return Ok(ChatResponse {
|
return Ok(ChatResponse {
|
||||||
text: "Session ended by server.".into(),
|
text: "Session ended by server.".into(),
|
||||||
events,
|
events,
|
||||||
|
input_tokens: 0,
|
||||||
|
output_tokens: 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Some(_) => continue,
|
Some(_) => continue,
|
||||||
|
|||||||
Reference in New Issue
Block a user