From 928f2bfa9d1870c3b463528609e9e4d41e86e72f Mon Sep 17 00:00:00 2001 From: Jochen Date: Tue, 2 Dec 2025 21:23:50 +1100 Subject: [PATCH] actually record coach feedback and use it --- crates/g3-cli/src/lib.rs | 22 ++++++++++- crates/g3-core/src/lib.rs | 77 ++++++++++++++++++++++----------------- 2 files changed, 63 insertions(+), 36 deletions(-) diff --git a/crates/g3-cli/src/lib.rs b/crates/g3-cli/src/lib.rs index 3dd6248..18d6f76 100644 --- a/crates/g3-cli/src/lib.rs +++ b/crates/g3-cli/src/lib.rs @@ -163,15 +163,33 @@ fn extract_coach_feedback_from_logs( if let Some(context_window) = log_json.get("context_window") { if let Some(conversation_history) = context_window.get("conversation_history") { if let Some(messages) = conversation_history.as_array() { - // Simply get the last message content - this is the coach's final feedback + // Get the last message which contains the final_output tool result + // The last message is a USER message with format "Tool result: {summary}" if let Some(last_message) = messages.last() { if let Some(content) = last_message.get("content") { if let Some(content_str) = content.as_str() { + // Strip the "Tool result: " prefix if present + let feedback = if content_str.starts_with("Tool result: ") { + content_str.strip_prefix("Tool result: ") + .unwrap_or(content_str) + .to_string() + } else { + content_str.to_string() + }; + + // Log the extraction for debugging + output.print(&format!( + "Coach feedback extracted: {} characters (from {} total)", + feedback.len(), + content_str.len() + )); + output.print(&format!("Coach feedback:\n{}", feedback)); + output.print(&format!( "✅ Extracted coach feedback from session: {}", session_id )); - return Ok(content_str.to_string()); + return Ok(feedback); } } } diff --git a/crates/g3-core/src/lib.rs b/crates/g3-core/src/lib.rs index 6da2b44..91fd74a 100644 --- a/crates/g3-core/src/lib.rs +++ b/crates/g3-core/src/lib.rs @@ -3604,40 +3604,6 @@ impl Agent { } } - // Check if this was a final_output tool call - if tool_call.tool == "final_output" { - // The summary was already displayed via print_final_output - // Don't add it to full_response to avoid duplicate printing - // full_response is intentionally left empty/unchanged - self.ui_writer.println(""); - let _ttft = - first_token_time.unwrap_or_else(|| stream_start.elapsed()); - - // Add timing if needed - let final_response = if show_timing { - format!( - "🕝 {} | 💭 {}", - Self::format_duration(stream_start.elapsed()), - Self::format_duration(_ttft) - ) - } else { - // Return empty string since content was already displayed - String::new() - }; - - return Ok(TaskResult::new( - final_response, - self.context_window.clone(), - )); - } - - // Closure marker with timing - if tool_call.tool != "final_output" { - self.ui_writer - .print_tool_timing(&Self::format_duration(exec_duration)); - self.ui_writer.print_agent_prompt(); - } - // Add the tool call and result to the context window using RAW unfiltered content // This ensures the log file contains the true raw content including JSON tool calls let tool_message = if !raw_content_for_log.trim().is_empty() { @@ -3701,6 +3667,43 @@ impl Agent { self.context_window.add_message(tool_message); self.context_window.add_message(result_message); + // Check if this was a final_output tool call + if tool_call.tool == "final_output" { + // Save context window BEFORE returning so the session log includes final_output + self.save_context_window("completed"); + + // The summary was already displayed via print_final_output + // Don't add it to full_response to avoid duplicate printing + // full_response is intentionally left empty/unchanged + self.ui_writer.println(""); + let _ttft = + first_token_time.unwrap_or_else(|| stream_start.elapsed()); + + // Add timing if needed + let final_response = if show_timing { + format!( + "🕝 {} | 💭 {}", + Self::format_duration(stream_start.elapsed()), + Self::format_duration(_ttft) + ) + } else { + // Return empty string since content was already displayed + String::new() + }; + + return Ok(TaskResult::new( + final_response, + self.context_window.clone(), + )); + } + + // Closure marker with timing + if tool_call.tool != "final_output" { + self.ui_writer + .print_tool_timing(&Self::format_duration(exec_duration)); + self.ui_writer.print_agent_prompt(); + } + // Update the request with the new context for next iteration request.messages = self.context_window.conversation_history.clone(); @@ -3922,6 +3925,9 @@ impl Agent { full_response = String::new(); self.ui_writer.println(""); + + // Save context window BEFORE returning + self.save_context_window("completed"); let _ttft = first_token_time.unwrap_or_else(|| stream_start.elapsed()); @@ -4060,6 +4066,9 @@ impl Agent { } } + // Save context window BEFORE returning + self.save_context_window("completed"); + // Add timing if needed let final_response = if show_timing { format!(