nit: show dir in title, and less... jank (#7138)

This commit is contained in:
Michael Neale
2026-02-13 15:16:46 +11:00
committed by GitHub
parent 860c7d7b97
commit 85348d2745
8 changed files with 183 additions and 216 deletions
+1 -4
View File
@@ -410,10 +410,7 @@ impl Hinter for GooseCompleter {
} }
HintStatus::Default => { HintStatus::Default => {
let newline_key = super::input::get_newline_key().to_ascii_uppercase(); let newline_key = super::input::get_newline_key().to_ascii_uppercase();
Some(format!( Some(format!("Enter to send · Ctrl+{} newline", newline_key))
"Press Enter to send, Ctrl-{} for new line",
newline_key
))
} }
} }
} }
+6 -36
View File
@@ -398,18 +398,12 @@ fn parse_plan_command(input: String) -> Option<InputResult> {
Some(InputResult::Plan(options)) Some(InputResult::Plan(options))
} }
/// Generates the input prompt string for the CLI interface.
/// Returns a styled prompt with the goose face "( O)>" followed by a space.
/// On Windows, returns plain text without ANSI styling for better compatibility.
/// On other platforms, applies styling using ANSI escape codes.
fn get_input_prompt_string() -> String { fn get_input_prompt_string() -> String {
let goose = "( O)>"; let goose = "🪿";
if cfg!(target_os = "windows") { if cfg!(target_os = "windows") {
// Use plain text on Windows to avoid ANSI compatibility issues
format!("{goose} ") format!("{goose} ")
} else { } else {
// On other platforms, use styled prompt with ANSI colors format!("{} ", console::style(goose))
format!("{} ", console::style(goose).cyan().bold())
} }
} }
@@ -702,38 +696,14 @@ mod tests {
let prompt = get_input_prompt_string(); let prompt = get_input_prompt_string();
// Prompt should always end with a space // Prompt should always end with a space
assert!(prompt.ends_with(" ")); assert!(prompt.ends_with(' '));
// Prompt should contain the goose face // Prompt should contain the goose emoji
assert!(prompt.contains("( O)>")); assert!(prompt.contains("🪿"));
// On Windows, prompt should be plain text without ANSI codes
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
{ {
assert_eq!(prompt, "( O)> "); assert_eq!(prompt, "🪿 ");
// Ensure no ANSI escape sequences
assert!(!prompt.contains("\x1b["));
}
// On non-Windows, prompt behavior depends on terminal capabilities
#[cfg(not(target_os = "windows"))]
{
// In CI environments, console crate may strip ANSI codes
let is_ci = std::env::var("CI").is_ok();
if is_ci {
// In CI, just verify basic structure - console crate handles ANSI detection
assert!(prompt.len() >= "( O)> ".len());
} else {
// In interactive terminals, expect styling to be applied
// Note: This may still vary based on terminal capabilities
assert!(prompt.len() >= "( O)> ".len());
// If ANSI codes are present, they should be valid
if prompt.contains("\x1b[") {
assert!(prompt.contains("36") || prompt.contains("1"));
}
}
} }
} }
} }
+33 -58
View File
@@ -159,7 +159,7 @@ pub struct CliSession {
completion_cache: Arc<std::sync::RwLock<CompletionCache>>, completion_cache: Arc<std::sync::RwLock<CompletionCache>>,
debug: bool, debug: bool,
run_mode: RunMode, run_mode: RunMode,
scheduled_job_id: Option<String>, // ID of the scheduled job that triggered this session scheduled_job_id: Option<String>,
max_turns: Option<u32>, max_turns: Option<u32>,
edit_mode: Option<EditMode>, edit_mode: Option<EditMode>,
retry_config: Option<RetryConfig>, retry_config: Option<RetryConfig>,
@@ -479,7 +479,6 @@ impl CliSession {
loop { loop {
self.display_context_usage().await?; self.display_context_usage().await?;
// Convert conversation messages to strings for editor mode
let conversation_strings: Vec<String> = self let conversation_strings: Vec<String> = self
.messages .messages
.iter() .iter()
@@ -502,8 +501,9 @@ impl CliSession {
} }
println!( println!(
"Closing session. Session ID: {}", "\n {} {}",
console::style(&self.session_id).cyan() console::style("").red(),
console::style(format!("session closed · {}", &self.session_id)).dim()
); );
Ok(()) Ok(())
@@ -636,10 +636,7 @@ impl CliSession {
let elapsed = start_time.elapsed(); let elapsed = start_time.elapsed();
let elapsed_str = format_elapsed_time(elapsed); let elapsed_str = format_elapsed_time(elapsed);
println!( println!("{}", console::style(format!("{}", elapsed_str)).dim());
"\n{}",
console::style(format!("⏱️ Elapsed time: {}", elapsed_str)).dim()
);
} }
RunMode::Plan => { RunMode::Plan => {
let mut plan_messages = self.messages.clone(); let mut plan_messages = self.messages.clone();
@@ -1152,20 +1149,10 @@ impl CliSession {
.collect() .collect()
}); });
let interrupt_prompt = "Yes — what would you like me to do?";
if !tool_requests.is_empty() { if !tool_requests.is_empty() {
// Interrupted during a tool request
// Create tool responses for all interrupted tool requests
// TODO(Douwe): if we need this, it should happen in agent reply
let mut response_message = Message::user(); let mut response_message = Message::user();
let last_tool_name = tool_requests
.last()
.and_then(|(_, tool_call)| {
tool_call
.as_ref()
.ok()
.map(|tool| tool.name.to_string().clone())
})
.unwrap_or_else(|| "tool".to_string());
let notification = if interrupt { let notification = if interrupt {
"Interrupted by the user to make a correction".to_string() "Interrupted by the user to make a correction".to_string()
@@ -1183,36 +1170,29 @@ impl CliSession {
)); ));
} }
self.push_message(response_message); self.push_message(response_message);
let prompt = format!( self.push_message(Message::assistant().with_text(interrupt_prompt));
"The existing call to {} was interrupted. How would you like to proceed?", output::render_message(
last_tool_name &Message::assistant().with_text(interrupt_prompt),
self.debug,
); );
self.push_message(Message::assistant().with_text(&prompt)); } else if let Some(last_msg) = self.messages.last() {
output::render_message(&Message::assistant().with_text(&prompt), self.debug); if last_msg.role == rmcp::model::Role::User {
} else { match last_msg.content.first() {
// An interruption occurred outside of a tool request-response. Some(MessageContent::ToolResponse(_)) => {
if let Some(last_msg) = self.messages.last() { self.push_message(Message::assistant().with_text(interrupt_prompt));
if last_msg.role == rmcp::model::Role::User { output::render_message(
match last_msg.content.first() { &Message::assistant().with_text(interrupt_prompt),
Some(MessageContent::ToolResponse(_)) => { self.debug,
// Interruption occurred after a tool had completed but not assistant reply );
let prompt = "The tool calling loop was interrupted. How would you like to proceed?"; }
self.push_message(Message::assistant().with_text(prompt)); Some(_) => {
output::render_message( self.messages.pop();
&Message::assistant().with_text(prompt), let assistant_msg = Message::assistant().with_text(interrupt_prompt);
self.debug, self.push_message(assistant_msg.clone());
); output::render_message(&assistant_msg, self.debug);
} }
Some(_) => { None => {
// A real users message // Empty message content — nothing to do, just continue gracefully
self.messages.pop();
let prompt = "Interrupted before the model replied and removed the last message.";
output::render_message(
&Message::assistant().with_text(prompt),
self.debug,
);
}
None => panic!("No content in last message"),
} }
} }
} }
@@ -1271,11 +1251,10 @@ impl CliSession {
return; return;
} }
// Print session restored message
println!( println!(
"\n{} {} messages loaded into context.", "\n {} {}",
console::style("Session restored:").green().bold(), console::style("").cyan(),
console::style(self.messages.len()).green() console::style(format!("{} messages restored", self.messages.len())).dim()
); );
// Render each message // Render each message
@@ -1283,11 +1262,7 @@ impl CliSession {
output::render_message(message, self.debug); output::render_message(message, self.debug);
} }
// Add a visual separator after restored messages println!();
println!(
"\n{}\n",
console::style("──────── New Messages ────────").dim()
);
} }
pub async fn get_session(&self) -> Result<goose::session::Session> { pub async fn get_session(&self) -> Result<goose::session::Session> {
+130 -106
View File
@@ -120,16 +120,18 @@ pub struct ThinkingIndicator {
impl ThinkingIndicator { impl ThinkingIndicator {
pub fn show(&mut self) { pub fn show(&mut self) {
let spinner = cliclack::spinner(); let spinner = cliclack::spinner();
let hint = style("(Ctrl+C to interrupt)").dim();
if Config::global() if Config::global()
.get_param("RANDOM_THINKING_MESSAGES") .get_param("RANDOM_THINKING_MESSAGES")
.unwrap_or(true) .unwrap_or(true)
{ {
spinner.start(format!( spinner.start(format!(
"{}...", "{}... {}",
super::thinking::get_random_thinking_message() super::thinking::get_random_thinking_message(),
hint,
)); ));
} else { } else {
spinner.start("Thinking..."); spinner.start(format!("Thinking... {}", hint));
} }
self.spinner = Some(spinner); self.spinner = Some(spinner);
} }
@@ -467,17 +469,15 @@ pub fn render_builtin_error(names: &str, error: &str) {
fn render_text_editor_request(call: &CallToolRequestParams, debug: bool) { fn render_text_editor_request(call: &CallToolRequestParams, debug: bool) {
print_tool_header(call); print_tool_header(call);
// Print path first with special formatting
if let Some(args) = &call.arguments { if let Some(args) = &call.arguments {
if let Some(Value::String(path)) = args.get("path") { if let Some(Value::String(path)) = args.get("path") {
println!( println!(
"{}: {}", " {} {}",
style("path").dim(), style("path").dim(),
style(shorten_path(path, debug)).green() style(shorten_path(path, debug)).dim()
); );
} }
// Print other arguments normally, excluding path
if let Some(args) = &call.arguments { if let Some(args) = &call.arguments {
let mut other_args = serde_json::Map::new(); let mut other_args = serde_json::Map::new();
for (k, v) in args { for (k, v) in args {
@@ -486,7 +486,7 @@ fn render_text_editor_request(call: &CallToolRequestParams, debug: bool) {
} }
} }
if !other_args.is_empty() { if !other_args.is_empty() {
print_params(&Some(other_args), 0, debug); print_params(&Some(other_args), 1, debug);
} }
} }
} }
@@ -495,7 +495,7 @@ fn render_text_editor_request(call: &CallToolRequestParams, debug: bool) {
fn render_shell_request(call: &CallToolRequestParams, debug: bool) { fn render_shell_request(call: &CallToolRequestParams, debug: bool) {
print_tool_header(call); print_tool_header(call);
print_params(&call.arguments, 0, debug); print_params(&call.arguments, 1, debug);
println!(); println!();
} }
@@ -515,10 +515,11 @@ fn render_execute_code_request(call: &CallToolRequestParams, debug: bool) {
let plural = if count == 1 { "" } else { "s" }; let plural = if count == 1 { "" } else { "s" };
println!(); println!();
println!( println!(
"─── {} tool call{} | {} ──────────────────────────", " {} {} {} tool call{}",
style(count).cyan(), style("").dim(),
style("execute").dim(),
style(count).dim(),
plural, plural,
style("execute").magenta().dim()
); );
for (i, node) in tool_graph.iter().filter_map(Value::as_object).enumerate() { for (i, node) in tool_graph.iter().filter_map(Value::as_object).enumerate() {
@@ -544,10 +545,10 @@ fn render_execute_code_request(call: &CallToolRequestParams, debug: bool) {
format!(" (uses {})", deps.join(", ")) format!(" (uses {})", deps.join(", "))
}; };
println!( println!(
" {}. {}: {}{}", " {}. {} {}{}",
style(i + 1).dim(), style(i + 1).dim(),
style(tool).cyan(), style(tool).dim(),
style(desc).green(), style(desc).dim(),
style(deps_str).dim() style(deps_str).dim()
); );
} }
@@ -570,7 +571,7 @@ fn render_delegate_request(call: &CallToolRequestParams, debug: bool) {
if let Some(args) = &call.arguments { if let Some(args) = &call.arguments {
if let Some(Value::String(source)) = args.get("source") { if let Some(Value::String(source)) = args.get("source") {
println!("{}: {}", style("source").dim(), style(source).cyan()); println!(" {} {}", style("source").dim(), style(source).dim());
} }
if let Some(Value::String(instructions)) = args.get("instructions") { if let Some(Value::String(instructions)) = args.get("instructions") {
@@ -580,15 +581,15 @@ fn render_delegate_request(call: &CallToolRequestParams, debug: bool) {
instructions.clone() instructions.clone()
}; };
println!( println!(
"{}: {}", " {} {}",
style("instructions").dim(), style("instructions").dim(),
style(display).green() style(display).dim()
); );
} }
if let Some(Value::Object(params)) = args.get("parameters") { if let Some(Value::Object(params)) = args.get("parameters") {
println!("{}:", style("parameters").dim()); println!(" {}:", style("parameters").dim());
print_params(&Some(params.clone()), 1, debug); print_params(&Some(params.clone()), 2, debug);
} }
let skip_keys = ["source", "instructions", "parameters"]; let skip_keys = ["source", "instructions", "parameters"];
@@ -599,7 +600,7 @@ fn render_delegate_request(call: &CallToolRequestParams, debug: bool) {
} }
} }
if !other_args.is_empty() { if !other_args.is_empty() {
print_params(&Some(other_args), 0, debug); print_params(&Some(other_args), 1, debug);
} }
} }
@@ -611,7 +612,7 @@ fn render_todo_request(call: &CallToolRequestParams, _debug: bool) {
if let Some(args) = &call.arguments { if let Some(args) = &call.arguments {
if let Some(Value::String(content)) = args.get("content") { if let Some(Value::String(content)) = args.get("content") {
println!("{}: {}", style("content").dim(), style(content).green()); println!(" {} {}", style("content").dim(), style(content).dim());
} }
} }
println!(); println!();
@@ -619,7 +620,7 @@ fn render_todo_request(call: &CallToolRequestParams, _debug: bool) {
fn render_default_request(call: &CallToolRequestParams, debug: bool) { fn render_default_request(call: &CallToolRequestParams, debug: bool) {
print_tool_header(call); print_tool_header(call);
print_params(&call.arguments, 0, debug); print_params(&call.arguments, 1, debug);
println!(); println!();
} }
@@ -660,14 +661,13 @@ pub fn render_subagent_tool_call(
} }
} }
let tool_header = format!( let tool_header = format!(
"─── {} ──────────────────────────", " {} {}",
style(format_subagent_tool_call_message(subagent_id, tool_name)) style("").dim(),
.magenta() style(format_subagent_tool_call_message(subagent_id, tool_name)).dim(),
.dim()
); );
println!(); println!();
println!("{}", tool_header); println!("{}", tool_header);
print_params(&arguments.cloned(), 0, debug); print_params(&arguments.cloned(), 1, debug);
println!(); println!();
} }
@@ -677,11 +677,12 @@ fn render_subagent_tool_graph(subagent_id: &str, tool_graph: &[Value]) {
let plural = if count == 1 { "" } else { "s" }; let plural = if count == 1 { "" } else { "s" };
println!(); println!();
println!( println!(
"─── {} {} tool call{} | {} ──────────────────────────", " {} {} {} {} tool call{}",
style(format!("[subagent:{}]", short_id)).cyan(), style("").dim(),
style(count).cyan(), style(format!("[subagent:{}]", short_id)).dim(),
style("execute_code").dim(),
style(count).dim(),
plural, plural,
style("execute_code").magenta().dim()
); );
for (i, node) in tool_graph.iter().filter_map(Value::as_object).enumerate() { for (i, node) in tool_graph.iter().filter_map(Value::as_object).enumerate() {
@@ -707,10 +708,10 @@ fn render_subagent_tool_graph(subagent_id: &str, tool_graph: &[Value]) {
format!(" (uses {})", deps.join(", ")) format!(" (uses {})", deps.join(", "))
}; };
println!( println!(
" {}. {}: {}{}", " {}. {} {}{}",
style(i + 1).dim(), style(i + 1).dim(),
style(tool).cyan(), style(tool).dim(),
style(desc).green(), style(desc).dim(),
style(deps_str).dim() style(deps_str).dim()
); );
} }
@@ -721,11 +722,16 @@ fn render_subagent_tool_graph(subagent_id: &str, tool_graph: &[Value]) {
fn print_tool_header(call: &CallToolRequestParams) { fn print_tool_header(call: &CallToolRequestParams) {
let (tool, extension) = split_tool_name(&call.name); let (tool, extension) = split_tool_name(&call.name);
let tool_header = format!( let tool_header = if extension.is_empty() {
"─── {} | {} ──────────────────────────", format!(" {} {}", style("").dim(), style(&tool).dim())
style(tool), } else {
style(extension).magenta().dim(), format!(
); " {} {} {}",
style("").dim(),
style(&tool).dim(),
style(extension).magenta().dim(),
)
};
println!(); println!();
println!("{}", tool_header); println!("{}", tool_header);
} }
@@ -889,7 +895,6 @@ fn shorten_path(path: &str, debug: bool) -> String {
shortened.join("/") shortened.join("/")
} }
// Session display functions
pub fn display_session_info( pub fn display_session_info(
resume: bool, resume: bool,
provider: &str, provider: &str,
@@ -897,107 +902,126 @@ pub fn display_session_info(
session_id: &Option<String>, session_id: &Option<String>,
provider_instance: Option<&Arc<dyn goose::providers::base::Provider>>, provider_instance: Option<&Arc<dyn goose::providers::base::Provider>>,
) { ) {
let start_session_msg = if resume { let status = if resume {
"resuming session |" "resuming"
} else if session_id.is_none() { } else if session_id.is_none() {
"running without session |" "ephemeral"
} else { } else {
"starting session |" "new session"
}; };
// Check if we have lead/worker mode let model_display = if let Some(provider_inst) = provider_instance {
if let Some(provider_inst) = provider_instance {
if let Some(lead_worker) = provider_inst.as_lead_worker() { if let Some(lead_worker) = provider_inst.as_lead_worker() {
let (lead_model, worker_model) = lead_worker.get_model_info(); let (lead_model, worker_model) = lead_worker.get_model_info();
println!( format!("{}{}", lead_model, worker_model)
"{} {} {} {} {} {} {}",
style(start_session_msg).dim(),
style("provider:").dim(),
style(provider).cyan().dim(),
style("lead model:").dim(),
style(&lead_model).cyan().dim(),
style("worker model:").dim(),
style(&worker_model).cyan().dim(),
);
} else { } else {
println!( model.to_string()
"{} {} {} {} {}",
style(start_session_msg).dim(),
style("provider:").dim(),
style(provider).cyan().dim(),
style("model:").dim(),
style(model).cyan().dim(),
);
} }
} else { } else {
// Fallback to original behavior if no provider instance model.to_string()
println!( };
"{} {} {} {} {}",
style(start_session_msg).dim(), println!(
style("provider:").dim(), "\n {} {} {} {} {}",
style(provider).cyan().dim(), style("").green(),
style("model:").dim(), style(status).dim(),
style(model).cyan().dim(), style("·").dim(),
); style(provider).dim(),
} style(&model_display).cyan(),
);
let cwd_display = std::env::current_dir()
.ok()
.map(|p| p.display().to_string())
.unwrap_or_else(|| "unknown".to_string());
if let Some(id) = session_id { if let Some(id) = session_id {
println!( println!(
" {} {}", " {} {} {}",
style("session id:").dim(), style(" ").dim(),
style(id).cyan().dim() style(id).dim(),
style(format!("· {}", cwd_display)).dim(),
);
} else {
println!(
" {} {}",
style(" ").dim(),
style(format!(" {}", cwd_display)).dim(),
); );
} }
}
println!( pub fn set_terminal_title() {
" {} {}", if !std::io::stdout().is_terminal() {
style("working directory:").dim(), return;
style(std::env::current_dir().unwrap().display()) }
.cyan() let dir_name = std::env::current_dir()
.dim() .ok()
); .and_then(|p| p.file_name().map(|n| n.to_string_lossy().into_owned()))
.unwrap_or_default();
// Sanitize: strip control characters (ESC, BEL, etc.) to prevent terminal escape injection
let sanitized: String = dir_name.chars().filter(|c| !c.is_control()).collect();
// OSC 0 sets the terminal window/tab title
print!("\x1b]0;🪿 {}\x07", sanitized);
let _ = std::io::stdout().flush();
} }
pub fn display_greeting() { pub fn display_greeting() {
println!("\ngoose is running! Enter your instructions, or try asking what goose can do.\n"); set_terminal_title();
println!(
"\n{} {}\n",
style("🪿 goose").bold(),
style("ready — type a message to get started").dim()
);
} }
/// Display context window usage with both current and session totals
pub fn display_context_usage(total_tokens: usize, context_limit: usize) { pub fn display_context_usage(total_tokens: usize, context_limit: usize) {
use console::style; use console::style;
if context_limit == 0 { if context_limit == 0 {
println!("Context: Error - context limit is zero"); println!(
" {}",
style("context usage unavailable (context limit is 0)").dim()
);
return; return;
} }
// Calculate percentage used with bounds checking
let percentage = let percentage =
(((total_tokens as f64 / context_limit as f64) * 100.0).round() as usize).min(100); (((total_tokens as f64 / context_limit as f64) * 100.0).round() as usize).min(100);
// Create dot visualization with safety bounds let bar_width = 20;
let dot_count = 10; let filled = ((percentage as f64 / 100.0) * bar_width as f64).round() as usize;
let filled_dots = let empty = bar_width - filled.min(bar_width);
(((percentage as f64 / 100.0) * dot_count as f64).round() as usize).min(dot_count);
let empty_dots = dot_count - filled_dots;
let filled = "".repeat(filled_dots); let bar = format!("{}{}", "".repeat(filled), "".repeat(empty));
let empty = "".repeat(empty_dots); let colored_bar = if percentage < 50 {
style(bar).green().dim()
// Combine dots and apply color
let dots = format!("{}{}", filled, empty);
let colored_dots = if percentage < 50 {
style(dots).green()
} else if percentage < 85 { } else if percentage < 85 {
style(dots).yellow() style(bar).yellow()
} else { } else {
style(dots).red() style(bar).red()
}; };
// Print the status line fn format_tokens(n: usize) -> String {
if n >= 1_000_000 {
format!("{:.1}M", n as f64 / 1_000_000.0)
} else if n >= 1_000 {
format!("{:.0}k", n as f64 / 1_000.0)
} else {
n.to_string()
}
}
println!( println!(
"Context: {} {}% ({}/{} tokens)", " {} {} {}",
colored_dots, percentage, total_tokens, context_limit colored_bar,
style(format!("{}%", percentage)).dim(),
style(format!(
"{}/{}",
format_tokens(total_tokens),
format_tokens(context_limit)
))
.dim(),
); );
} }
+7 -7
View File
@@ -57,7 +57,7 @@ TMPFILE=$(mktemp)
(cd "$TESTDIR" && GOOSE_PROVIDER="$TEST_PROVIDER" GOOSE_MODEL="$TEST_MODEL" \ (cd "$TESTDIR" && GOOSE_PROVIDER="$TEST_PROVIDER" GOOSE_MODEL="$TEST_MODEL" \
"$GOOSE_BIN" run --recipe recipe.yaml 2>&1) | tee "$TMPFILE" "$GOOSE_BIN" run --recipe recipe.yaml 2>&1) | tee "$TMPFILE"
if grep -q "add | test_mcp" "$TMPFILE" && grep -q "100" "$TMPFILE"; then if grep -qE "(add \| test_mcp)|(▸.*add.*test_mcp)" "$TMPFILE" && grep -q "100" "$TMPFILE"; then
echo "✓ FastMCP stderr test passed" echo "✓ FastMCP stderr test passed"
RESULTS+=("✓ FastMCP stderr") RESULTS+=("✓ FastMCP stderr")
else else
@@ -73,20 +73,20 @@ TESTDIR=$(mktemp -d)
TMPFILE=$(mktemp) TMPFILE=$(mktemp)
(cd "$TESTDIR" && GOOSE_PROVIDER="$TEST_PROVIDER" GOOSE_MODEL="$TEST_MODEL" \ (cd "$TESTDIR" && GOOSE_PROVIDER="$TEST_PROVIDER" GOOSE_MODEL="$TEST_MODEL" \
"$GOOSE_BIN" run --text "Use the sampleLLM tool to ask for a quote from The Great Gatsby" \ "$GOOSE_BIN" run --text "Use the sampleLLM tool to ask for an original short poem about the ocean" \
--with-extension "npx -y @modelcontextprotocol/server-everything@2026.1.14" 2>&1) | tee "$TMPFILE" --with-extension "npx -y @modelcontextprotocol/server-everything@2026.1.14" 2>&1) | tee "$TMPFILE"
if grep -q "$MCP_SAMPLING_TOOL | " "$TMPFILE"; then if grep -qE "($MCP_SAMPLING_TOOL \| )|(▸.*$MCP_SAMPLING_TOOL)" "$TMPFILE"; then
JUDGE_PROMPT=$(cat <<EOF JUDGE_PROMPT=$(cat <<EOF
You are a validator. You will be given a transcript of a CLI run that used an MCP tool to initiate MCP sampling. You are a validator. You will be given a transcript of a CLI run that used an MCP tool to initiate MCP sampling.
The MCP server requests a quote from The Great Gatsby from the model via sampling. The MCP server requests an original short poem about the ocean from the model via sampling.
Task: Determine whether the transcript shows that the sampling request reached the model and that the output included either: Task: Determine whether the transcript shows that the sampling request reached the model and that the output included either:
• A recognizable quote, paraphrase, or reference from The Great Gatsby, or • A poem, verse, or creative text about the ocean or sea, or
• A clear attempt or explanation from the model about why the quote could not be returned. • A clear attempt or explanation from the model about the poem request.
If either of these conditions is true, respond PASS. If either of these conditions is true, respond PASS.
If there is no evidence that the model attempted or returned a Gatsby-related response, respond FAIL. If there is no evidence that the model attempted or returned a poem-related response, respond FAIL.
If uncertain, lean toward PASS. If uncertain, lean toward PASS.
Output format: Respond with exactly one word on a single line: Output format: Respond with exactly one word on a single line:
+1 -1
View File
@@ -40,7 +40,7 @@ run_test() {
echo "failure|test content not found by model" > "$result_file" echo "failure|test content not found by model" > "$result_file"
fi fi
else else
if ! grep -q "text_editor | developer" "$output_file"; then if ! grep -qE "(text_editor \| developer)|(▸.*text_editor.*developer)" "$output_file"; then
echo "failure|model did not use text_editor tool" > "$result_file" echo "failure|model did not use text_editor tool" > "$result_file"
elif ! grep -q "TEST-CONTENT-ABC123" "$output_file"; then elif ! grep -q "TEST-CONTENT-ABC123" "$output_file"; then
echo "failure|model did not return uppercased file content" > "$result_file" echo "failure|model did not return uppercased file content" > "$result_file"
+3 -2
View File
@@ -30,8 +30,9 @@ run_test() {
# Verify: code_execution tool must be called # Verify: code_execution tool must be called
# Matches: "execute | code_execution", "get_function_details | code_execution", # Matches: "execute | code_execution", "get_function_details | code_execution",
# "tool call | execute", "tool calls | execute" # "tool call | execute", "tool calls | execute" (old format)
if grep -qE "(execute \| code_execution)|(get_function_details \| code_execution)|(tool calls? \| execute)" "$output_file"; then # "▸ execute N tool call" (new format with tool_graph)
if grep -qE "(execute \| code_execution)|(get_function_details \| code_execution)|(tool calls? \| execute)|(▸.*execute.*tool call)" "$output_file"; then
echo "success|code_execution tool called" > "$result_file" echo "success|code_execution tool called" > "$result_file"
else else
echo "failure|no code_execution tool calls found" > "$result_file" echo "failure|no code_execution tool calls found" > "$result_file"
+2 -2
View File
@@ -77,8 +77,8 @@ check_recipe_output() {
local tmpfile=$1 local tmpfile=$1
local mode=$2 local mode=$2
# Check for delegate tool invocation (new format: "─── delegate |") # Check for delegate tool invocation (old: "─── delegate |", new: "▸ delegate")
if grep -q "─── delegate" "$tmpfile"; then if grep -qE "(─── delegate)|(▸.*delegate)" "$tmpfile"; then
echo "✓ SUCCESS: Delegate tool invoked" echo "✓ SUCCESS: Delegate tool invoked"
RESULTS+=("✓ Delegate tool invocation ($mode)") RESULTS+=("✓ Delegate tool invocation ($mode)")
else else