Skip to content

Commit

Permalink
address pr comments: import config; cyan output; chat mode verbiage
Browse files Browse the repository at this point in the history
  • Loading branch information
wendytang committed Feb 22, 2025
1 parent f5d5c7e commit 994ea01
Show file tree
Hide file tree
Showing 11 changed files with 62 additions and 64 deletions.
34 changes: 12 additions & 22 deletions crates/goose-cli/src/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use anyhow::Result;
use etcetera::choose_app_strategy;
use goose::agents::extension::{Envs, ExtensionConfig};
use goose::agents::Agent;
use goose::config::Config;
use goose::message::{Message, MessageContent};
use mcp_core::handler::ToolError;
use rand::{distributions::Alphanumeric, Rng};
Expand Down Expand Up @@ -122,18 +121,15 @@ impl Session {
}
}
}
let config = Config::global();
output::display_greeting();
loop {
let goose_mode = config.get("GOOSE_MODE").unwrap_or("auto".to_string());
match input::get_input(&mut editor)? {
input::InputResult::Message(content) => {
self.messages.push(Message::user().with_text(&content));
storage::persist_messages(&self.session_file, &self.messages)?;

output::show_thinking();
self.process_agent_response(&mut editor, Some(goose_mode.clone()))
.await?;
self.process_agent_response(&mut editor).await?;
output::hide_thinking();
}
input::InputResult::Exit => break,
Expand Down Expand Up @@ -189,25 +185,19 @@ impl Session {
}

pub async fn headless_start(&mut self, initial_message: String) -> Result<()> {
// Load settings from config
let config = Config::global();
let goose_mode = config.get("GOOSE_MODE").unwrap_or("auto".to_string());

self.messages
.push(Message::user().with_text(&initial_message));
storage::persist_messages(&self.session_file, &self.messages)?;
let mut editor = Editor::<(), rustyline::history::DefaultHistory>::new()?;
self.process_agent_response(&mut editor, Some(goose_mode.clone()))
.await?;
self.process_agent_response(&mut editor).await?;
Ok(())
}

async fn process_agent_response(
&mut self,
editor: &mut Editor<(), rustyline::history::DefaultHistory>,
goose_mode: Option<String>,
) -> Result<()> {
let mut stream = self.agent.reply(&self.messages, goose_mode).await?;
let mut stream = self.agent.reply(&self.messages).await?;

use futures::StreamExt;
loop {
Expand All @@ -222,11 +212,16 @@ impl Session {

// Format the confirmation prompt
let prompt = format!(
"Goose would like to call the tool: {}\nWith arguments: {}\nAllow? (y/n): ",
confirmation.tool_name,
serde_json::to_string_pretty(&confirmation.arguments).unwrap_or_default()
"Goose would like to call the above tool. Allow? (y/n): ",
);

let confirmation_request = Message::user().with_tool_confirmation_request(
confirmation.id.clone(),
confirmation.tool_name.clone(),
confirmation.arguments.clone(),
Some(prompt.clone())
);
output::render_message(&Message::assistant().with_text(&prompt));
output::render_message(&confirmation_request);

// Get confirmation from user
let confirmed = match input::get_input(editor)? {
Expand All @@ -235,11 +230,6 @@ impl Session {
}
_ => false,
};
let confirmation_request = Message::user().with_tool_confirmation_request(
confirmation.id.clone(),
confirmation.tool_name.clone(),
confirmation.arguments.clone(),
);

self.agent.handle_confirmation(confirmation.id.clone(), confirmed).await;

Expand Down
17 changes: 15 additions & 2 deletions crates/goose-cli/src/session/output.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bat::WrappingMode;
use console::style;
use goose::config::Config;
use goose::message::{Message, MessageContent, ToolRequest, ToolResponse};
use goose::message::{Message, MessageContent, ToolConfirmationRequest, ToolRequest, ToolResponse};
use mcp_core::tool::ToolCall;
use serde_json::Value;
use std::cell::RefCell;
Expand Down Expand Up @@ -94,7 +94,9 @@ pub fn render_message(message: &Message) {
MessageContent::Text(text) => print_markdown(&text.text, theme),
MessageContent::ToolRequest(req) => render_tool_request(req, theme),
MessageContent::ToolResponse(resp) => render_tool_response(resp, theme),
MessageContent::ToolConfirmationRequest(_) => {}
MessageContent::ToolConfirmationRequest(req) => {
render_tool_confirmation_request(req, theme)
}
MessageContent::Image(image) => {
println!("Image: [data: {}, type: {}]", image.data, image.mime_type);
}
Expand Down Expand Up @@ -148,6 +150,17 @@ fn render_tool_response(resp: &ToolResponse, theme: Theme) {
}
}

fn render_tool_confirmation_request(req: &ToolConfirmationRequest, theme: Theme) {
match &req.prompt {
Some(prompt) => {
let colored_prompt =
prompt.replace("Allow? (y/n)", &format!("{}", style("Allow? (y/n)").cyan()));
println!("{}", colored_prompt);
}
None => print_markdown(&"No prompt provided".to_string(), theme),
}
}

pub fn render_error(message: &str) {
println!("\n {} {}\n", style("error:").red().bold(), message);
}
Expand Down
11 changes: 5 additions & 6 deletions crates/goose-server/src/routes/reply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,14 +248,13 @@ async fn stream_message(
}
}
MessageContent::ToolConfirmationRequest(_) => {
// TODO
// skip tool confirmation requests
}
MessageContent::Image(_) => {
// TODO
// skip images
}
MessageContent::ToolResponse(_) => {
// Tool responses should only come from the user
continue;
// skip tool responses
}
}
}
Expand Down Expand Up @@ -310,7 +309,7 @@ async fn handler(
}
};

let mut stream = match agent.reply(&messages, Some("auto".to_string())).await {
let mut stream = match agent.reply(&messages).await {
Ok(stream) => stream,
Err(e) => {
tracing::error!("Failed to start reply stream: {:?}", e);
Expand Down Expand Up @@ -397,7 +396,7 @@ async fn ask_handler(

// Get response from agent
let mut response_text = String::new();
let mut stream = match agent.reply(&messages, Some("auto".to_string())).await {
let mut stream = match agent.reply(&messages).await {
Ok(stream) => stream,
Err(e) => {
tracing::error!("Failed to start reply stream: {:?}", e);
Expand Down
6 changes: 1 addition & 5 deletions crates/goose/src/agents/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@ use crate::providers::base::ProviderUsage;
#[async_trait]
pub trait Agent: Send + Sync {
/// Create a stream that yields each message as it's generated by the agent
async fn reply(
&self,
messages: &[Message],
goose_mode: Option<String>,
) -> Result<BoxStream<'_, Result<Message>>>;
async fn reply(&self, messages: &[Message]) -> Result<BoxStream<'_, Result<Message>>>;

/// Add a new MCP client to the agent
async fn add_extension(&mut self, config: ExtensionConfig) -> ExtensionResult<()>;
Expand Down
1 change: 0 additions & 1 deletion crates/goose/src/agents/reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ impl Agent for ReferenceAgent {
async fn reply(
&self,
messages: &[Message],
_goose_mode: Option<String>,
) -> anyhow::Result<BoxStream<'_, anyhow::Result<Message>>> {
let mut messages = messages.to_vec();
let reply_span = tracing::Span::current();
Expand Down
21 changes: 17 additions & 4 deletions crates/goose/src/agents/truncate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use tracing::{debug, error, instrument, warn};
use super::Agent;
use crate::agents::capabilities::Capabilities;
use crate::agents::extension::{ExtensionConfig, ExtensionResult};
use crate::config::Config;
use crate::message::{Message, ToolRequest};
use crate::providers::base::Provider;
use crate::providers::base::ProviderUsage;
Expand Down Expand Up @@ -140,14 +141,17 @@ impl Agent for TruncateAgent {
async fn reply(
&self,
messages: &[Message],
goose_mode: Option<String>,
) -> anyhow::Result<BoxStream<'_, anyhow::Result<Message>>> {
let mut messages = messages.to_vec();
let reply_span = tracing::Span::current();
let mut capabilities = self.capabilities.lock().await;
let mut tools = capabilities.get_prefixed_tools().await?;
let mut truncation_attempt: usize = 0;

// Load settings from config
let config = Config::global();
let goose_mode = config.get("GOOSE_MODE").unwrap_or("auto".to_string());

// we add in the 2 resource tools if any extensions support resources
// TODO: make sure there is no collision with another extension's tool name
let read_resource_tool = Tool::new(
Expand Down Expand Up @@ -233,10 +237,10 @@ impl Agent for TruncateAgent {
break;
}

// Process each tool request sequentially, asking for confirmation
// Process tool requests depending on goose_mode
let mut message_tool_response = Message::user();
// Clone goose_mode once before the match to avoid move issues
let mode = goose_mode.clone().unwrap_or_else(|| "auto".to_string());
let mode = goose_mode.clone();
match mode.as_str() {
"approve" => {
// Process each tool request sequentially with confirmation
Expand All @@ -246,6 +250,7 @@ impl Agent for TruncateAgent {
request.id.clone(),
tool_call.name.clone(),
tool_call.arguments.clone(),
Some("Goose would like to call the tool: {}\nAllow? (y/n): ".to_string()),
);
yield confirmation;

Expand Down Expand Up @@ -277,7 +282,15 @@ impl Agent for TruncateAgent {
for request in &tool_requests {
message_tool_response = message_tool_response.with_tool_response(
request.id.clone(),
Ok(vec![Content::text("Tool call skipped in Goose chat mode")]),
Ok(vec![Content::text(
"The following tool call was skipped in Goose chat mode. \
In chat mode, you cannot run tool calls, instead, you can \
only provide a detailed plan to the user. Provide an \
explanation of the proposed tool call as if it were a plan. \
Only if the user asks, provide a short explanation to the \
user that they could consider running the tool above on \
their own or with a different goose mode."
)]),
);
}
},
Expand Down
6 changes: 5 additions & 1 deletion crates/goose/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub struct ToolConfirmationRequest {
pub id: String,
pub tool_name: String,
pub arguments: Value,
pub prompt: Option<String>,
}

#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
Expand Down Expand Up @@ -77,11 +78,13 @@ impl MessageContent {
id: S,
tool_name: String,
arguments: Value,
prompt: Option<String>,
) -> Self {
MessageContent::ToolConfirmationRequest(ToolConfirmationRequest {
id: id.into(),
tool_name,
arguments,
prompt,
})
}
pub fn as_tool_request(&self) -> Option<&ToolRequest> {
Expand Down Expand Up @@ -212,9 +215,10 @@ impl Message {
id: S,
tool_name: String,
arguments: Value,
prompt: Option<String>,
) -> Self {
self.with_content(MessageContent::tool_confirmation_request(
id, tool_name, arguments,
id, tool_name, arguments, prompt,
))
}

Expand Down
10 changes: 2 additions & 8 deletions crates/goose/src/providers/formats/anthropic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,8 @@ pub fn format_messages(messages: &[Message]) -> Vec<Value> {
}));
}
}
MessageContent::ToolConfirmationRequest(tool_confirmation_request) => {
content.push(json!({
"type": "text",
"text": format!("Do you want to run tool '{}' with id '{}' and input '{}'?",
tool_confirmation_request.tool_name,
tool_confirmation_request.id,
tool_confirmation_request.arguments),
}));
MessageContent::ToolConfirmationRequest(_tool_confirmation_request) => {
// Skip tool confirmation requests
}
MessageContent::Image(_) => continue, // Anthropic doesn't support image content yet
}
Expand Down
9 changes: 2 additions & 7 deletions crates/goose/src/providers/formats/bedrock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,8 @@ pub fn to_bedrock_message(message: &Message) -> Result<bedrock::Message> {
pub fn to_bedrock_message_content(content: &MessageContent) -> Result<bedrock::ContentBlock> {
Ok(match content {
MessageContent::Text(text) => bedrock::ContentBlock::Text(text.text.to_string()),
MessageContent::ToolConfirmationRequest(tool_confirmation_request) => {
bedrock::ContentBlock::Text(format!(
"Do you want to run tool '{}' with id '{}' and input '{}'?",
tool_confirmation_request.tool_name,
tool_confirmation_request.id,
tool_confirmation_request.arguments
))
MessageContent::ToolConfirmationRequest(_tool_confirmation_request) => {
bedrock::ContentBlock::Text("".to_string())
}
MessageContent::Image(_) => {
bail!("Image content is not supported by Bedrock provider yet")
Expand Down
9 changes: 2 additions & 7 deletions crates/goose/src/providers/formats/openai.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,8 @@ pub fn format_messages(messages: &[Message], image_format: &ImageFormat) -> Vec<
}
}
}
MessageContent::ToolConfirmationRequest(tool_confirmation_request) => {
converted["content"] = json!(format!(
"Do you want to run tool '{}' with id '{}' and input '{}'?",
tool_confirmation_request.tool_name,
tool_confirmation_request.id,
tool_confirmation_request.arguments
));
MessageContent::ToolConfirmationRequest(_) => {
// Skip tool confirmation requests
}
MessageContent::Image(image) => {
// Handle direct image content
Expand Down
2 changes: 1 addition & 1 deletion crates/goose/tests/truncate_agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ async fn run_truncate_test(
),
];

let reply_stream = agent.reply(&messages, Some("auto".to_string())).await?;
let reply_stream = agent.reply(&messages).await?;
tokio::pin!(reply_stream);

let mut responses = Vec::new();
Expand Down

0 comments on commit 994ea01

Please sign in to comment.