chore: use typed notifications from rmcp (#3653)
This commit is contained in:
@@ -36,7 +36,8 @@ use goose::providers::pricing::initialize_pricing_cache;
|
||||
use goose::session;
|
||||
use input::InputResult;
|
||||
use mcp_core::handler::ToolError;
|
||||
use rmcp::model::{JsonRpcMessage, JsonRpcNotification, Notification, PromptMessage};
|
||||
use rmcp::model::PromptMessage;
|
||||
use rmcp::model::ServerNotification;
|
||||
|
||||
use rand::{distributions::Alphanumeric, Rng};
|
||||
use rustyline::EditMode;
|
||||
@@ -1023,126 +1024,115 @@ impl Session {
|
||||
}
|
||||
}
|
||||
Some(Ok(AgentEvent::McpNotification((_id, message)))) => {
|
||||
if let JsonRpcMessage::Notification( JsonRpcNotification {
|
||||
notification: Notification {
|
||||
method,
|
||||
params: o,..
|
||||
},..
|
||||
}) = message {
|
||||
match method.as_str() {
|
||||
"notifications/message" => {
|
||||
let data = o.get("data").unwrap_or(&Value::Null);
|
||||
let (formatted_message, subagent_id, message_notification_type) = match data {
|
||||
Value::String(s) => (s.clone(), None, None),
|
||||
Value::Object(o) => {
|
||||
// Check for subagent notification structure first
|
||||
if let Some(Value::String(msg)) = o.get("message") {
|
||||
// Extract subagent info for better display
|
||||
let subagent_id = o.get("subagent_id")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("unknown");
|
||||
let notification_type = o.get("type")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
match &message {
|
||||
ServerNotification::LoggingMessageNotification(notification) => {
|
||||
let data = ¬ification.params.data;
|
||||
let (formatted_message, subagent_id, message_notification_type) = match data {
|
||||
Value::String(s) => (s.clone(), None, None),
|
||||
Value::Object(o) => {
|
||||
// Check for subagent notification structure first
|
||||
if let Some(Value::String(msg)) = o.get("message") {
|
||||
// Extract subagent info for better display
|
||||
let subagent_id = o.get("subagent_id")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("unknown");
|
||||
let notification_type = o.get("type")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
|
||||
let formatted = match notification_type {
|
||||
"subagent_created" | "completed" | "terminated" => {
|
||||
format!("🤖 {}", msg)
|
||||
}
|
||||
"tool_usage" | "tool_completed" | "tool_error" => {
|
||||
format!("🔧 {}", msg)
|
||||
}
|
||||
"message_processing" | "turn_progress" => {
|
||||
format!("💭 {}", msg)
|
||||
}
|
||||
"response_generated" => {
|
||||
// Check verbosity setting for subagent response content
|
||||
let config = Config::global();
|
||||
let min_priority = config
|
||||
.get_param::<f32>("GOOSE_CLI_MIN_PRIORITY")
|
||||
.ok()
|
||||
.unwrap_or(0.5);
|
||||
let formatted = match notification_type {
|
||||
"subagent_created" | "completed" | "terminated" => {
|
||||
format!("🤖 {}", msg)
|
||||
}
|
||||
"tool_usage" | "tool_completed" | "tool_error" => {
|
||||
format!("🔧 {}", msg)
|
||||
}
|
||||
"message_processing" | "turn_progress" => {
|
||||
format!("💭 {}", msg)
|
||||
}
|
||||
"response_generated" => {
|
||||
// Check verbosity setting for subagent response content
|
||||
let config = Config::global();
|
||||
let min_priority = config
|
||||
.get_param::<f32>("GOOSE_CLI_MIN_PRIORITY")
|
||||
.ok()
|
||||
.unwrap_or(0.5);
|
||||
|
||||
if min_priority > 0.1 && !self.debug {
|
||||
// High/Medium verbosity: show truncated response
|
||||
if let Some(response_content) = msg.strip_prefix("Responded: ") {
|
||||
format!("🤖 Responded: {}", safe_truncate(response_content, 100))
|
||||
} else {
|
||||
format!("🤖 {}", msg)
|
||||
}
|
||||
if min_priority > 0.1 && !self.debug {
|
||||
// High/Medium verbosity: show truncated response
|
||||
if let Some(response_content) = msg.strip_prefix("Responded: ") {
|
||||
format!("🤖 Responded: {}", safe_truncate(response_content, 100))
|
||||
} else {
|
||||
// All verbosity or debug: show full response
|
||||
format!("🤖 {}", msg)
|
||||
}
|
||||
} else {
|
||||
// All verbosity or debug: show full response
|
||||
format!("🤖 {}", msg)
|
||||
}
|
||||
_ => {
|
||||
msg.to_string()
|
||||
}
|
||||
};
|
||||
(formatted, Some(subagent_id.to_string()), Some(notification_type.to_string()))
|
||||
} else if let Some(Value::String(output)) = o.get("output") {
|
||||
// Fallback for other MCP notification types
|
||||
(output.to_owned(), None, None)
|
||||
} else if let Some(result) = format_task_execution_notification(data) {
|
||||
result
|
||||
} else {
|
||||
(data.to_string(), None, None)
|
||||
}
|
||||
},
|
||||
v => {
|
||||
(v.to_string(), None, None)
|
||||
},
|
||||
};
|
||||
}
|
||||
_ => {
|
||||
msg.to_string()
|
||||
}
|
||||
};
|
||||
(formatted, Some(subagent_id.to_string()), Some(notification_type.to_string()))
|
||||
} else if let Some(Value::String(output)) = o.get("output") {
|
||||
// Fallback for other MCP notification types
|
||||
(output.to_owned(), None, None)
|
||||
} else if let Some(result) = format_task_execution_notification(data) {
|
||||
result
|
||||
} else {
|
||||
(data.to_string(), None, None)
|
||||
}
|
||||
},
|
||||
v => {
|
||||
(v.to_string(), None, None)
|
||||
},
|
||||
};
|
||||
|
||||
// Handle subagent notifications - show immediately
|
||||
if let Some(_id) = subagent_id {
|
||||
// TODO: proper display for subagent notifications
|
||||
// Handle subagent notifications - show immediately
|
||||
if let Some(_id) = subagent_id {
|
||||
// TODO: proper display for subagent notifications
|
||||
if interactive {
|
||||
let _ = progress_bars.hide();
|
||||
println!("{}", console::style(&formatted_message).green().dim());
|
||||
} else {
|
||||
progress_bars.log(&formatted_message);
|
||||
}
|
||||
} else if let Some(ref notification_type) = message_notification_type {
|
||||
if notification_type == TASK_EXECUTION_NOTIFICATION_TYPE {
|
||||
if interactive {
|
||||
let _ = progress_bars.hide();
|
||||
println!("{}", console::style(&formatted_message).green().dim());
|
||||
print!("{}", formatted_message);
|
||||
std::io::stdout().flush().unwrap();
|
||||
} else {
|
||||
progress_bars.log(&formatted_message);
|
||||
}
|
||||
} else if let Some(ref notification_type) = message_notification_type {
|
||||
if notification_type == TASK_EXECUTION_NOTIFICATION_TYPE {
|
||||
if interactive {
|
||||
let _ = progress_bars.hide();
|
||||
print!("{}", formatted_message);
|
||||
std::io::stdout().flush().unwrap();
|
||||
} else {
|
||||
print!("{}", formatted_message);
|
||||
std::io::stdout().flush().unwrap();
|
||||
}
|
||||
print!("{}", formatted_message);
|
||||
std::io::stdout().flush().unwrap();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Non-subagent notification, display immediately with compact spacing
|
||||
if interactive {
|
||||
let _ = progress_bars.hide();
|
||||
println!("{}", console::style(&formatted_message).green().dim());
|
||||
} else {
|
||||
progress_bars.log(&formatted_message);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Non-subagent notification, display immediately with compact spacing
|
||||
if interactive {
|
||||
let _ = progress_bars.hide();
|
||||
println!("{}", console::style(&formatted_message).green().dim());
|
||||
} else {
|
||||
progress_bars.log(&formatted_message);
|
||||
}
|
||||
},
|
||||
"notifications/progress" => {
|
||||
let progress = o.get("progress").and_then(|v| v.as_f64());
|
||||
let token = o.get("progressToken").map(|v| v.to_string());
|
||||
let message = o.get("message").and_then(|v| v.as_str());
|
||||
let total = o
|
||||
.get("total")
|
||||
.and_then(|v| v.as_f64());
|
||||
if let (Some(progress), Some(token)) = (progress, token) {
|
||||
progress_bars.update(
|
||||
token.as_str(),
|
||||
progress,
|
||||
total,
|
||||
message,
|
||||
);
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
},
|
||||
ServerNotification::ProgressNotification(notification) => {
|
||||
let progress = notification.params.progress;
|
||||
let text = notification.params.message.as_deref();
|
||||
let total = notification.params.total;
|
||||
let token = ¬ification.params.progress_token;
|
||||
progress_bars.update(
|
||||
&token.0.to_string(),
|
||||
progress,
|
||||
total,
|
||||
text,
|
||||
);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
Some(Ok(AgentEvent::ModelChange { model, mode })) => {
|
||||
|
||||
@@ -799,11 +799,11 @@ impl McpSpinners {
|
||||
spinner.set_message(message.to_string());
|
||||
}
|
||||
|
||||
pub fn update(&mut self, token: &str, value: f64, total: Option<f64>, message: Option<&str>) {
|
||||
pub fn update(&mut self, token: &str, value: u32, total: Option<u32>, message: Option<&str>) {
|
||||
let bar = self.bars.entry(token.to_string()).or_insert_with(|| {
|
||||
if let Some(total) = total {
|
||||
self.multi_bar.add(
|
||||
ProgressBar::new((total * 100.0) as u64).with_style(
|
||||
ProgressBar::new((total * 100) as u64).with_style(
|
||||
ProgressStyle::with_template("[{elapsed}] {bar:40} {pos:>3}/{len:3} {msg}")
|
||||
.unwrap(),
|
||||
),
|
||||
@@ -812,7 +812,7 @@ impl McpSpinners {
|
||||
self.multi_bar.add(ProgressBar::new_spinner())
|
||||
}
|
||||
});
|
||||
bar.set_position((value * 100.0) as u64);
|
||||
bar.set_position((value * 100) as u64);
|
||||
if let Some(msg) = message {
|
||||
bar.set_message(msg.to_string());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user