Compare commits
10 Commits
jochen-g3-
...
jochen-fas
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbeaaea2e3 | ||
|
|
7e1ce36a4b | ||
|
|
9f6592efc2 | ||
|
|
99125fc39e | ||
|
|
a2a82a2526 | ||
|
|
5170744099 | ||
|
|
fb0aabb5c4 | ||
|
|
4655516c15 | ||
|
|
c58aa80932 | ||
|
|
c837308148 |
@@ -183,6 +183,7 @@ use rustyline::error::ReadlineError;
|
||||
use rustyline::DefaultEditor;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::process::exit;
|
||||
use sha2::{Digest, Sha256};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tracing::{error, info};
|
||||
@@ -298,6 +299,10 @@ pub async fn run() -> Result<()> {
|
||||
return run_flock_mode(project_dir.clone(), flock_workspace.clone(), num_segments, cli.flock_max_turns).await;
|
||||
}
|
||||
|
||||
if cli.codebase_fast_start.is_some() {
|
||||
print!("codebase_fast_start is temporarily disabled.");
|
||||
exit(1);
|
||||
}
|
||||
// Otherwise, continue with normal mode
|
||||
|
||||
// Only initialize logging if not in retro mode
|
||||
@@ -1761,16 +1766,6 @@ async fn run_autonomous(
|
||||
let loop_start = Instant::now();
|
||||
output.print("🔄 Starting coach-player feedback loop...");
|
||||
|
||||
// Check if implementation files already exist
|
||||
let skip_first_player = project.has_implementation_files();
|
||||
if skip_first_player {
|
||||
output.print("📂 Detected existing implementation files in workspace");
|
||||
output.print("⏭️ Skipping first player turn - proceeding directly to coach review");
|
||||
} else {
|
||||
output.print("📂 No existing implementation files detected");
|
||||
output.print("🎯 Starting with player implementation");
|
||||
}
|
||||
|
||||
// Load fast-discovery messages before the loop starts (if enabled)
|
||||
let (discovery_messages, discovery_working_dir): (Vec<g3_providers::Message>, Option<String>) =
|
||||
if let Some(ref codebase_path) = codebase_fast_start {
|
||||
@@ -1811,8 +1806,7 @@ async fn run_autonomous(
|
||||
loop {
|
||||
let turn_start_time = Instant::now();
|
||||
let turn_start_tokens = agent.get_context_window().used_tokens;
|
||||
// Skip player turn if it's the first turn and implementation files exist
|
||||
if !(turn == 1 && skip_first_player) {
|
||||
|
||||
output.print(&format!(
|
||||
"\n=== TURN {}/{} - PLAYER MODE ===",
|
||||
turn, max_turns
|
||||
@@ -2006,7 +2000,6 @@ async fn run_autonomous(
|
||||
|
||||
// Give some time for file operations to complete
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
|
||||
}
|
||||
|
||||
// Create a new agent instance for coach mode to ensure fresh context
|
||||
// Use the same config with overrides that was passed to the player agent
|
||||
|
||||
@@ -1087,6 +1087,14 @@ impl<W: UiWriter> Agent<W> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Count how many cache_control annotations exist in the conversation history
|
||||
fn count_cache_controls_in_history(&self) -> usize {
|
||||
self.context_window.conversation_history
|
||||
.iter()
|
||||
.filter(|msg| msg.cache_control.is_some())
|
||||
.count()
|
||||
}
|
||||
|
||||
/// Get the configured max_tokens for a provider from top-level config
|
||||
fn provider_max_tokens(config: &Config, provider_name: &str) -> Option<u32> {
|
||||
match provider_name {
|
||||
@@ -1404,7 +1412,21 @@ impl<W: UiWriter> Agent<W> {
|
||||
}
|
||||
|
||||
// Add user message to context window
|
||||
let user_message = Message::new(MessageRole::User, format!("Task: {}", description));
|
||||
let user_message = {
|
||||
// Check if we should use cache control (every 10 tool calls)
|
||||
// But only if we haven't already added 4 cache_control annotations
|
||||
let provider = self.providers.get(None)?;
|
||||
if let Some(cache_config) = match provider.name() {
|
||||
"anthropic" => self.config.providers.anthropic.as_ref()
|
||||
.and_then(|c| c.cache_config.as_ref())
|
||||
.and_then(|config| Self::parse_cache_control(config)),
|
||||
_ => None,
|
||||
} {
|
||||
Message::with_cache_control_validated(MessageRole::User, format!("Task: {}", description), cache_config, provider)
|
||||
} else {
|
||||
Message::new(MessageRole::User, format!("Task: {}", description))
|
||||
}
|
||||
};
|
||||
self.context_window.add_message(user_message);
|
||||
|
||||
// Execute fast-discovery tool calls if provided (immediately after user message)
|
||||
@@ -1426,7 +1448,7 @@ impl<W: UiWriter> Agent<W> {
|
||||
|
||||
// Add cache_control to the last user message if provider supports it (anthropic)
|
||||
let is_last = idx == message_count - 1;
|
||||
let result_message = if is_last && supports_cache {
|
||||
let result_message = if supports_cache && is_last && self.count_cache_controls_in_history() < 4 {
|
||||
Message::with_cache_control(
|
||||
MessageRole::User,
|
||||
format!("Tool result: {}", result),
|
||||
@@ -1506,24 +1528,7 @@ impl<W: UiWriter> Agent<W> {
|
||||
// Add assistant response to context window only if not empty
|
||||
// This prevents the "Skipping empty message" warning when only tools were executed
|
||||
if !response_content.trim().is_empty() {
|
||||
let assistant_message = {
|
||||
// Check if we should use cache control (every 10 tool calls)
|
||||
if self.tool_call_count > 0 && self.tool_call_count % 10 == 0 {
|
||||
let provider = self.providers.get(None)?;
|
||||
if let Some(cache_config) = match provider.name() {
|
||||
"anthropic" => self.config.providers.anthropic.as_ref()
|
||||
.and_then(|c| c.cache_config.as_ref())
|
||||
.and_then(|config| Self::parse_cache_control(config)),
|
||||
_ => None,
|
||||
} {
|
||||
Message::with_cache_control_validated(MessageRole::Assistant, response_content.clone(), cache_config, provider)
|
||||
} else {
|
||||
Message::new(MessageRole::Assistant, response_content.clone())
|
||||
}
|
||||
} else {
|
||||
Message::new(MessageRole::Assistant, response_content.clone())
|
||||
}
|
||||
};
|
||||
let assistant_message = Message::new(MessageRole::Assistant, response_content.clone());
|
||||
self.context_window.add_message(assistant_message);
|
||||
} else {
|
||||
debug!("Assistant response was empty (likely only tool execution), skipping message addition");
|
||||
@@ -3372,7 +3377,25 @@ impl<W: UiWriter> Agent<W> {
|
||||
tool_call.tool, tool_call.args
|
||||
))
|
||||
};
|
||||
let result_message = Message::new(MessageRole::User, format!("Tool result: {}", tool_result));
|
||||
let result_message = {
|
||||
// Check if we should use cache control (every 10 tool calls)
|
||||
// But only if we haven't already added 4 cache_control annotations
|
||||
if self.tool_call_count > 0 && self.tool_call_count % 10 == 0 && self.count_cache_controls_in_history() < 4 {
|
||||
let provider = self.providers.get(None)?;
|
||||
if let Some(cache_config) = match provider.name() {
|
||||
"anthropic" => self.config.providers.anthropic.as_ref()
|
||||
.and_then(|c| c.cache_config.as_ref())
|
||||
.and_then(|config| Self::parse_cache_control(config)),
|
||||
_ => None,
|
||||
} {
|
||||
Message::with_cache_control_validated(MessageRole::User, format!("Tool result: {}", tool_result), cache_config, provider)
|
||||
} else {
|
||||
Message::new(MessageRole::User, format!("Tool result: {}", tool_result))
|
||||
}
|
||||
} else {
|
||||
Message::new(MessageRole::User, format!("Tool result: {}", tool_result))
|
||||
}
|
||||
};
|
||||
|
||||
self.context_window.add_message(tool_message);
|
||||
self.context_window.add_message(result_message);
|
||||
@@ -3722,24 +3745,7 @@ impl<W: UiWriter> Agent<W> {
|
||||
.replace("<</SYS>>", "");
|
||||
|
||||
if !raw_clean.trim().is_empty() {
|
||||
let assistant_message = {
|
||||
// Check if we should use cache control (every 10 tool calls)
|
||||
if self.tool_call_count > 0 && self.tool_call_count % 10 == 0 {
|
||||
let provider = self.providers.get(None)?;
|
||||
if let Some(cache_config) = match provider.name() {
|
||||
"anthropic" => self.config.providers.anthropic.as_ref()
|
||||
.and_then(|c| c.cache_config.as_ref())
|
||||
.and_then(|config| Self::parse_cache_control(config)),
|
||||
_ => None,
|
||||
} {
|
||||
Message::with_cache_control_validated(MessageRole::Assistant, raw_clean, cache_config, provider)
|
||||
} else {
|
||||
Message::new(MessageRole::Assistant, raw_clean)
|
||||
}
|
||||
} else {
|
||||
Message::new(MessageRole::Assistant, raw_clean)
|
||||
}
|
||||
};
|
||||
let assistant_message = Message::new(MessageRole::Assistant, raw_clean);
|
||||
self.context_window.add_message(assistant_message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,49 +98,6 @@ impl Project {
|
||||
self.requirements_text.is_some() || self.requirements_path.is_some()
|
||||
}
|
||||
|
||||
/// Check if implementation files exist in the workspace
|
||||
pub fn has_implementation_files(&self) -> bool {
|
||||
self.check_dir_for_implementation_files(&self.workspace_dir)
|
||||
}
|
||||
|
||||
/// Recursively check a directory for implementation files
|
||||
#[allow(clippy::only_used_in_recursion)]
|
||||
fn check_dir_for_implementation_files(&self, dir: &Path) -> bool {
|
||||
// Common source file extensions
|
||||
let extensions = vec![
|
||||
"swift", "rs", "py", "js", "ts", "java", "cpp", "c",
|
||||
"go", "rb", "php", "cs", "kt", "scala", "m", "h"
|
||||
];
|
||||
|
||||
if let Ok(entries) = std::fs::read_dir(dir) {
|
||||
for entry in entries.flatten() {
|
||||
let path = entry.path();
|
||||
|
||||
if path.is_file() {
|
||||
// Check if it's a source file
|
||||
if let Some(ext) = path.extension() {
|
||||
if let Some(ext_str) = ext.to_str() {
|
||||
if extensions.contains(&ext_str) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if path.is_dir() {
|
||||
// Skip hidden directories and common non-source directories
|
||||
if let Some(name) = path.file_name().and_then(|n| n.to_str()) {
|
||||
if !name.starts_with('.') && name != "logs" && name != "target" && name != "node_modules" {
|
||||
// Recursively check subdirectories
|
||||
if self.check_dir_for_implementation_files(&path) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Read the requirements file content
|
||||
pub fn read_requirements(&self) -> Result<Option<String>> {
|
||||
// Prioritize requirements text override
|
||||
|
||||
Reference in New Issue
Block a user