Remove machine mode entirely from g3

- Delete machine_ui_writer.rs
- Remove --machine CLI flag from cli_args.rs
- Remove run_machine_mode(), run_interactive_machine(), run_autonomous_machine() functions
- Remove handle_machine_command() function
- Simplify OutputMode enum to just use SimpleOutput directly
- Simplify SimpleOutput struct (remove machine_mode field)
- Remove machine_mode parameter from setup_workspace_directory()
- Remove test_machine_option_accepted test
- Disable ACD by default in agent_mode (requires --acd flag)
- Change 'memory checkpoint' message formatting
- Remove dehydration status message
This commit is contained in:
Dhanji R. Prasanna
2026-01-12 06:01:31 +05:30
parent b9cdb99557
commit f10374c925
11 changed files with 26 additions and 685 deletions

View File

@@ -209,9 +209,6 @@ pub async fn run_agent_mode(
// This prompts the LLM to save discoveries to project memory after each turn
agent.set_auto_memory(true);
// Enable ACD in agent mode for longer sessions
agent.set_acd_enabled(true);
// If resuming a session, restore context and TODO
let initial_task = if let Some(ref incomplete_session) = resuming_session {
// Restore the session context

View File

@@ -11,7 +11,6 @@ use g3_core::project::Project;
use g3_core::{Agent, DiscoveryOptions};
use crate::coach_feedback;
use crate::machine_ui_writer::MachineUiWriter;
use crate::metrics::{format_elapsed_time, generate_turn_histogram, TurnMetrics};
use crate::simple_output::SimpleOutput;
use crate::ui_writer_impl::ConsoleUiWriter;
@@ -264,60 +263,6 @@ pub async fn run_autonomous(
Ok(agent)
}
/// Run autonomous mode with machine-friendly output.
pub async fn run_autonomous_machine(
mut agent: Agent<MachineUiWriter>,
project: Project,
show_prompt: bool,
show_code: bool,
max_turns: usize,
_quiet: bool,
_codebase_fast_start: Option<PathBuf>,
) -> Result<()> {
println!("AUTONOMOUS_MODE_STARTED");
println!("WORKSPACE: {}", project.workspace().display());
println!("MAX_TURNS: {}", max_turns);
// Check if requirements exist
if !project.has_requirements() {
println!("ERROR: requirements.md not found in workspace directory");
return Ok(());
}
// Read requirements
let requirements = match project.read_requirements()? {
Some(content) => content,
None => {
println!("ERROR: Could not read requirements");
return Ok(());
}
};
println!("REQUIREMENTS_LOADED");
// For now, just execute a simple autonomous loop
// This is a simplified version - full implementation would need coach-player loop
let task = format!(
"You are G3 in implementation mode. Read and implement the following requirements:\n\n{}\n\nImplement this step by step, creating all necessary files and code.",
requirements
);
println!("TASK_START");
let result = agent
.execute_task_with_timing(&task, None, false, show_prompt, show_code, true, None)
.await?;
println!("AGENT_RESPONSE:");
println!("{}", result.response);
println!("END_AGENT_RESPONSE");
println!("TASK_END");
// Save session continuation for resume capability
agent.save_session_continuation(Some(result.response.clone()));
println!("AUTONOMOUS_MODE_ENDED");
Ok(())
}
// --- Helper types and functions ---
enum PlayerTurnResult {

View File

@@ -55,10 +55,6 @@ pub struct Cli {
#[arg(long)]
pub chat: bool,
/// Enable machine-friendly output mode with JSON markers and stats
#[arg(long)]
pub machine: bool,
/// Override the configured provider (anthropic, databricks, embedded, openai)
#[arg(long, value_name = "PROVIDER")]
pub provider: Option<String>,

View File

@@ -10,10 +10,9 @@ use tracing::{debug, error};
use g3_core::ui_writer::UiWriter;
use g3_core::Agent;
use crate::machine_ui_writer::MachineUiWriter;
use crate::project_files::extract_readme_heading;
use crate::simple_output::SimpleOutput;
use crate::task_execution::{execute_task_with_retry, OutputMode};
use crate::task_execution::execute_task_with_retry;
use crate::utils::display_context_progress;
/// Run interactive mode with console output.
@@ -206,7 +205,7 @@ pub async fn run_interactive<W: UiWriter>(
&input,
show_prompt,
show_code,
OutputMode::Console(&output),
&output,
)
.await;
@@ -242,7 +241,7 @@ pub async fn run_interactive<W: UiWriter>(
&input,
show_prompt,
show_code,
OutputMode::Console(&output),
&output,
)
.await;
@@ -287,95 +286,6 @@ pub async fn run_interactive<W: UiWriter>(
Ok(())
}
/// Run interactive mode with machine-friendly output.
pub async fn run_interactive_machine(
mut agent: Agent<MachineUiWriter>,
show_prompt: bool,
show_code: bool,
) -> Result<()> {
println!("INTERACTIVE_MODE_STARTED");
// Display provider and model information
match agent.get_provider_info() {
Ok((provider, model)) => {
println!("PROVIDER: {}", provider);
println!("MODEL: {}", model);
}
Err(e) => {
println!("ERROR: Failed to get provider info: {}", e);
}
}
// Initialize rustyline editor with history
let mut rl = DefaultEditor::new()?;
// Try to load history from a file in the user's home directory
let history_file = dirs::home_dir().map(|mut path| {
path.push(".g3_history");
path
});
if let Some(ref history_path) = history_file {
let _ = rl.load_history(history_path);
}
loop {
let readline = rl.readline("");
match readline {
Ok(line) => {
let input = line.trim().to_string();
if input.is_empty() {
continue;
}
if input == "exit" || input == "quit" {
break;
}
// Add to history
rl.add_history_entry(&input)?;
// Check for control commands
if input.starts_with('/') {
if handle_machine_command(&input, &mut agent).await? {
continue;
}
}
// Execute task
println!("TASK_START");
execute_task_with_retry(&mut agent, &input, show_prompt, show_code, OutputMode::Machine)
.await;
// Send auto-memory reminder if enabled and tools were called
if let Err(e) = agent.send_auto_memory_reminder().await {
debug!("Auto-memory reminder failed: {}", e);
}
println!("TASK_END");
}
Err(ReadlineError::Interrupted) => continue,
Err(ReadlineError::Eof) => break,
Err(err) => {
println!("ERROR: {:?}", err);
break;
}
}
}
// Save history before exiting
if let Some(ref history_path) = history_file {
let _ = rl.save_history(history_path);
}
// Save session continuation for resume capability
agent.save_session_continuation(None);
println!("INTERACTIVE_MODE_ENDED");
Ok(())
}
/// Handle a control command. Returns true if the command was handled and the loop should continue.
async fn handle_command<W: UiWriter>(
input: &str,
@@ -648,204 +558,3 @@ async fn handle_command<W: UiWriter>(
}
}
}
/// Handle a control command in machine mode. Returns true if the command was handled.
async fn handle_machine_command(
input: &str,
agent: &mut Agent<MachineUiWriter>,
) -> Result<bool> {
match input {
"/compact" => {
println!("COMMAND: compact");
match agent.force_compact().await {
Ok(true) => println!("RESULT: Compaction completed"),
Ok(false) => println!("RESULT: Compaction failed"),
Err(e) => println!("ERROR: {}", e),
}
Ok(true)
}
"/thinnify" => {
println!("COMMAND: thinnify");
let summary = agent.force_thin();
println!("{}", summary);
Ok(true)
}
"/skinnify" => {
println!("COMMAND: skinnify");
let summary = agent.force_thin_all();
println!("{}", summary);
Ok(true)
}
"/fragments" => {
println!("COMMAND: fragments");
if let Some(session_id) = agent.get_session_id() {
match g3_core::acd::list_fragments(session_id) {
Ok(fragments) => {
println!("FRAGMENT_COUNT: {}", fragments.len());
for fragment in &fragments {
println!("FRAGMENT_ID: {}", fragment.fragment_id);
println!("FRAGMENT_MESSAGES: {}", fragment.message_count);
println!("FRAGMENT_TOKENS: {}", fragment.estimated_tokens);
}
}
Err(e) => {
println!("ERROR: {}", e);
}
}
} else {
println!("ERROR: No active session");
}
Ok(true)
}
cmd if cmd.starts_with("/rehydrate") => {
println!("COMMAND: rehydrate");
let parts: Vec<&str> = cmd.splitn(2, ' ').collect();
if parts.len() < 2 || parts[1].trim().is_empty() {
println!("ERROR: Usage: /rehydrate <fragment_id>");
} else {
let fragment_id = parts[1].trim();
println!("FRAGMENT_ID: {}", fragment_id);
println!("RESULT: Use the rehydrate tool to restore fragment content");
}
Ok(true)
}
"/dump" => {
println!("COMMAND: dump");
let dump_dir = std::path::Path::new("tmp");
if !dump_dir.exists() {
if let Err(e) = std::fs::create_dir_all(dump_dir) {
println!("ERROR: Failed to create tmp directory: {}", e);
return Ok(true);
}
}
let timestamp = chrono::Utc::now().format("%Y%m%d_%H%M%S");
let dump_path = dump_dir.join(format!("context_dump_{}.txt", timestamp));
let context = agent.get_context_window();
let mut dump_content = String::new();
dump_content.push_str("# Context Window Dump\n");
dump_content.push_str(&format!("# Timestamp: {}\n", chrono::Utc::now()));
dump_content.push_str(&format!(
"# Messages: {}\n",
context.conversation_history.len()
));
dump_content.push_str(&format!(
"# Used tokens: {} / {} ({:.1}%)\n\n",
context.used_tokens,
context.total_tokens,
context.percentage_used()
));
for (i, msg) in context.conversation_history.iter().enumerate() {
dump_content.push_str(&format!(
"=== Message {} ===\nRole: {:?}\nKind: {:?}\nContent ({} chars):\n{}\n\n",
i,
msg.role,
msg.kind,
msg.content.len(),
msg.content
));
}
match std::fs::write(&dump_path, &dump_content) {
Ok(_) => println!("RESULT: Context dumped to {}", dump_path.display()),
Err(e) => println!("ERROR: Failed to write dump: {}", e),
}
Ok(true)
}
"/clear" => {
println!("COMMAND: clear");
agent.clear_session();
println!("RESULT: Session cleared");
Ok(true)
}
"/readme" => {
println!("COMMAND: readme");
match agent.reload_readme() {
Ok(true) => println!("RESULT: README content reloaded successfully"),
Ok(false) => println!("RESULT: No README was loaded at startup, cannot reload"),
Err(e) => println!("ERROR: {}", e),
}
Ok(true)
}
"/stats" => {
println!("COMMAND: stats");
let stats = agent.get_stats();
// Emit stats as structured data (name: value pairs)
println!("{}", stats);
Ok(true)
}
"/help" => {
println!("COMMAND: help");
println!("AVAILABLE_COMMANDS: /compact /thinnify /skinnify /clear /dump /fragments /rehydrate /resume /readme /stats /help");
Ok(true)
}
"/resume" => {
println!("COMMAND: resume");
match g3_core::list_sessions_for_directory() {
Ok(sessions) => {
if sessions.is_empty() {
println!("RESULT: No sessions found");
return Ok(true);
}
println!("SESSIONS_START");
for (i, session) in sessions.iter().enumerate() {
let time_str = g3_core::format_session_time(&session.created_at);
let has_todos = if session.has_incomplete_todos() {
"true"
} else {
"false"
};
println!(
"SESSION: {} | {} | {} | {:.0}% | {}",
i + 1,
session.session_id,
time_str,
session.context_percentage,
has_todos
);
}
println!("SESSIONS_END");
println!("HINT: Use /resume <number> to switch to a session");
}
Err(e) => println!("ERROR: {}", e),
}
Ok(true)
}
_ => {
// Check for /resume <number> pattern
if input.starts_with("/resume ") {
let num_str = input.strip_prefix("/resume ").unwrap().trim();
if let Ok(num) = num_str.parse::<usize>() {
println!("COMMAND: resume {}", num);
match g3_core::list_sessions_for_directory() {
Ok(sessions) => {
if num >= 1 && num <= sessions.len() {
let selected = &sessions[num - 1];
match agent.switch_to_session(selected) {
Ok(true) => println!(
"RESULT: Full context restored from session {}",
selected.session_id
),
Ok(false) => println!(
"RESULT: Session {} restored from summary",
selected.session_id
),
Err(e) => println!("ERROR: {}", e),
}
} else {
println!("ERROR: Invalid session number");
}
}
Err(e) => println!("ERROR: {}", e),
}
return Ok(true);
}
}
println!("ERROR: Unknown command: {}", input);
Ok(true)
}
}
}

View File

@@ -11,7 +11,6 @@ mod autonomous;
mod cli_args;
mod coach_feedback;
mod interactive;
mod machine_ui_writer;
mod simple_output;
mod task_execution;
mod ui_writer_impl;
@@ -30,9 +29,8 @@ use clap::Parser;
use accumulative::run_accumulative_mode;
use agent_mode::run_agent_mode;
use autonomous::{run_autonomous, run_autonomous_machine};
use interactive::{run_interactive, run_interactive_machine};
use machine_ui_writer::MachineUiWriter;
use autonomous::run_autonomous;
use interactive::run_interactive;
use project_files::{read_agents_config, read_project_memory, read_project_readme};
use simple_output::SimpleOutput;
use ui_writer_impl::ConsoleUiWriter;
@@ -110,12 +108,7 @@ pub async fn run() -> Result<()> {
// Combine AGENTS.md, README, and memory content
let combined_content = combine_project_content(agents_content, readme_content, memory_content);
// Execute based on mode
if cli.machine {
run_machine_mode(cli, config, project, combined_content).await
} else {
run_console_mode(cli, config, project, combined_content, workspace_dir).await
}
run_console_mode(cli, config, project, combined_content, workspace_dir).await
}
// --- Helper functions ---
@@ -123,10 +116,7 @@ pub async fn run() -> Result<()> {
fn initialize_logging(cli: &Cli) {
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
let filter = if cli.machine {
// In machine mode, suppress ALL logs
EnvFilter::from_default_env().add_directive("off".parse().unwrap())
} else if cli.verbose {
let filter = if cli.verbose {
EnvFilter::from_default_env()
.add_directive(format!("{}=debug", env!("CARGO_PKG_NAME")).parse().unwrap())
.add_directive("g3_core=debug".parse().unwrap())
@@ -154,7 +144,7 @@ fn determine_workspace_dir(cli: &Cli) -> Result<PathBuf> {
if let Some(ws) = &cli.workspace {
Ok(ws.clone())
} else if cli.autonomous {
setup_workspace_directory(cli.machine)
setup_workspace_directory()
} else {
Ok(std::env::current_dir()?)
}
@@ -243,69 +233,6 @@ fn combine_project_content(
}
}
async fn run_machine_mode(
cli: Cli,
config: Config,
project: Project,
combined_content: Option<String>,
) -> Result<()> {
let ui_writer = MachineUiWriter::new();
let mut agent = if cli.autonomous {
Agent::new_autonomous_with_readme_and_quiet(
config.clone(),
ui_writer,
combined_content.clone(),
cli.quiet,
)
.await?
} else {
Agent::new_with_readme_and_quiet(
config.clone(),
ui_writer,
combined_content.clone(),
cli.quiet,
)
.await?
};
if cli.auto_memory {
agent.set_auto_memory(true);
}
if cli.acd {
agent.set_acd_enabled(true);
}
if cli.autonomous {
run_autonomous_machine(
agent,
project,
cli.show_prompt,
cli.show_code,
cli.max_turns,
cli.quiet,
cli.codebase_fast_start.clone(),
)
.await
} else if let Some(task) = cli.task {
// Single-shot mode
let result = agent
.execute_task_with_timing(&task, None, false, cli.show_prompt, cli.show_code, true, None)
.await?;
println!("AGENT_RESPONSE:");
println!("{}", result.response);
println!("END_AGENT_RESPONSE");
if let Err(e) = agent.send_auto_memory_reminder().await {
debug!("Auto-memory reminder failed: {}", e);
}
agent.save_session_continuation(Some(result.response.clone()));
Ok(())
} else {
run_interactive_machine(agent, cli.show_prompt, cli.show_code).await
}
}
async fn run_console_mode(
cli: Cli,
config: Config,

View File

@@ -1,111 +0,0 @@
use g3_core::ui_writer::UiWriter;
use std::io::{self, Write};
/// Machine-mode implementation of UiWriter that prints plain, unformatted output
/// This is designed for programmatic consumption and outputs everything verbatim
pub struct MachineUiWriter;
impl MachineUiWriter {
pub fn new() -> Self {
Self
}
}
impl UiWriter for MachineUiWriter {
fn print(&self, message: &str) {
print!("{}", message);
}
fn println(&self, message: &str) {
println!("{}", message);
}
fn print_inline(&self, message: &str) {
print!("{}", message);
let _ = io::stdout().flush();
}
fn print_system_prompt(&self, prompt: &str) {
println!("SYSTEM_PROMPT:");
println!("{}", prompt);
println!("END_SYSTEM_PROMPT");
println!();
}
fn print_context_status(&self, message: &str) {
println!("CONTEXT_STATUS: {}", message);
}
fn print_context_thinning(&self, message: &str) {
println!("CONTEXT_THINNING: {}", message);
}
fn print_tool_header(&self, tool_name: &str, _tool_args: Option<&serde_json::Value>) {
println!("TOOL_CALL: {}", tool_name);
}
fn print_tool_arg(&self, key: &str, value: &str) {
println!("TOOL_ARG: {} = {}", key, value);
}
fn print_tool_output_header(&self) {
println!("TOOL_OUTPUT:");
}
fn update_tool_output_line(&self, line: &str) {
println!("{}", line);
}
fn print_tool_output_line(&self, line: &str) {
println!("{}", line);
}
fn print_tool_output_summary(&self, count: usize) {
println!("TOOL_OUTPUT_LINES: {}", count);
}
fn print_tool_timing(&self, duration_str: &str, tokens_delta: u32, context_percentage: f32) {
println!("TOOL_DURATION: {}", duration_str);
println!("TOKENS_DELTA: {}", tokens_delta);
println!("CONTEXT_PERCENTAGE: {:.0}", context_percentage);
println!("END_TOOL_OUTPUT");
println!();
}
fn print_agent_prompt(&self) {
println!("AGENT_RESPONSE:");
let _ = io::stdout().flush();
}
fn print_agent_response(&self, content: &str) {
print!("{}", content);
let _ = io::stdout().flush();
}
fn notify_sse_received(&self) {
// No-op for machine mode
}
fn flush(&self) {
let _ = io::stdout().flush();
}
fn wants_full_output(&self) -> bool {
true // Machine mode wants complete, untruncated output
}
fn prompt_user_yes_no(&self, message: &str) -> bool {
// In machine mode, we can't interactively prompt, so we log the request and return true
// to allow automation to proceed.
println!("PROMPT_USER_YES_NO: {}", message);
true
}
fn prompt_user_choice(&self, message: &str, options: &[&str]) -> usize {
println!("PROMPT_USER_CHOICE: {}", message);
println!("OPTIONS: {:?}", options);
// Default to first option (index 0) for automation
0
}
}

View File

@@ -1,30 +1,18 @@
/// Simple output helper for printing messages
#[derive(Clone)]
pub struct SimpleOutput {
machine_mode: bool,
}
pub struct SimpleOutput;
impl SimpleOutput {
pub fn new() -> Self {
SimpleOutput {
machine_mode: false,
}
}
pub fn new_with_mode(machine_mode: bool) -> Self {
SimpleOutput { machine_mode }
SimpleOutput
}
pub fn print(&self, message: &str) {
if !self.machine_mode {
println!("{}", message);
}
println!("{}", message);
}
pub fn print_smart(&self, message: &str) {
if !self.machine_mode {
println!("{}", message);
}
println!("{}", message);
}
}

View File

@@ -11,101 +11,17 @@ use crate::simple_output::SimpleOutput;
/// Maximum number of retry attempts for timeout errors
const MAX_TIMEOUT_RETRIES: u32 = 3;
/// Output mode for task execution feedback
pub enum OutputMode<'a> {
/// Console mode with SimpleOutput for user-friendly messages
Console(&'a SimpleOutput),
/// Machine mode with structured output markers
Machine,
}
impl<'a> OutputMode<'a> {
fn print_thinking(&self) {
match self {
OutputMode::Console(output) => output.print("🤔 Thinking..."),
OutputMode::Machine => {} // No thinking indicator in machine mode
}
}
fn print_cancelled(&self) {
match self {
OutputMode::Console(output) => output.print("\n⚠️ Operation cancelled by user (Ctrl+C)"),
OutputMode::Machine => println!("CANCELLED"),
}
}
fn print_cancelled_simple(&self) {
match self {
OutputMode::Console(output) => output.print("⚠️ Operation cancelled by user"),
OutputMode::Machine => println!("CANCELLED"),
}
}
fn print_retry_success(&self, attempt: u32) {
match self {
OutputMode::Console(output) => {
output.print(&format!("✅ Request succeeded after {} attempts", attempt))
}
OutputMode::Machine => println!("RETRY_SUCCESS: attempt {}", attempt),
}
}
fn print_response(&self, response: &str, output: Option<&SimpleOutput>) {
match self {
OutputMode::Console(o) => o.print_smart(response),
OutputMode::Machine => {
println!("AGENT_RESPONSE:");
println!("{}", response);
println!("END_AGENT_RESPONSE");
// Ignore the output parameter in machine mode
let _ = output;
}
}
}
fn print_timeout_retry(&self, attempt: u32, delay: std::time::Duration) {
match self {
OutputMode::Console(output) => {
output.print(&format!(
"⏱️ Timeout error detected (attempt {}/{}). Retrying in {:?}...",
attempt, MAX_TIMEOUT_RETRIES, delay
));
}
OutputMode::Machine => {
println!(
"TIMEOUT: attempt {} of {}, retrying in {:?}",
attempt, MAX_TIMEOUT_RETRIES, delay
);
}
}
}
fn print_error(&self, e: &anyhow::Error, attempt: u32) {
match self {
OutputMode::Console(_) => {} // Handled by handle_execution_error
OutputMode::Machine => {
println!("ERROR: {}", e);
if attempt > 1 {
println!("FAILED_AFTER_RETRIES: {}", attempt);
}
}
}
}
}
/// Execute a task with retry logic for timeout errors.
///
/// This is the unified implementation used by both console and machine modes.
pub async fn execute_task_with_retry<W: UiWriter>(
agent: &mut Agent<W>,
input: &str,
show_prompt: bool,
show_code: bool,
mode: OutputMode<'_>,
output: &SimpleOutput,
) {
let mut attempt = 0;
mode.print_thinking();
output.print("🤔 Thinking...");
// Create cancellation token for this request
let cancellation_token = CancellationToken::new();
@@ -123,7 +39,7 @@ pub async fn execute_task_with_retry<W: UiWriter>(
}
_ = tokio::signal::ctrl_c() => {
cancel_token_clone.cancel();
mode.print_cancelled();
output.print("\n⚠️ Operation cancelled by user (Ctrl+C)");
return;
}
};
@@ -131,17 +47,14 @@ pub async fn execute_task_with_retry<W: UiWriter>(
match execution_result {
Ok(result) => {
if attempt > 1 {
mode.print_retry_success(attempt);
output.print(&format!("✅ Request succeeded after {} attempts", attempt));
}
mode.print_response(&result.response, match &mode {
OutputMode::Console(o) => Some(*o),
OutputMode::Machine => None,
});
output.print_smart(&result.response);
return;
}
Err(e) => {
if e.to_string().contains("cancelled") {
mode.print_cancelled_simple();
output.print("⚠️ Operation cancelled by user");
return;
}
@@ -157,7 +70,10 @@ pub async fn execute_task_with_retry<W: UiWriter>(
let delay_ms = 1000 * (2_u64.pow(attempt - 1));
let delay = std::time::Duration::from_millis(delay_ms);
mode.print_timeout_retry(attempt, delay);
output.print(&format!(
"⏱️ Timeout error detected (attempt {}/{}). Retrying in {:?}...",
attempt, MAX_TIMEOUT_RETRIES, delay
));
// Wait before retrying
tokio::time::sleep(delay).await;
@@ -165,14 +81,7 @@ pub async fn execute_task_with_retry<W: UiWriter>(
}
// For non-timeout errors or after max retries
match &mode {
OutputMode::Console(output) => {
handle_execution_error(&e, input, output, attempt);
}
OutputMode::Machine => {
mode.print_error(&e, attempt);
}
}
handle_execution_error(&e, input, output, attempt);
return;
}
}

View File

@@ -67,7 +67,7 @@ pub fn display_context_progress<W: UiWriter>(agent: &Agent<W>, _output: &SimpleO
/// Set up the workspace directory for autonomous mode.
/// Uses G3_WORKSPACE environment variable or defaults to ~/tmp/workspace.
pub fn setup_workspace_directory(machine_mode: bool) -> Result<PathBuf> {
pub fn setup_workspace_directory() -> Result<PathBuf> {
let workspace_dir = if let Ok(env_workspace) = std::env::var("G3_WORKSPACE") {
PathBuf::from(env_workspace)
} else {
@@ -80,7 +80,7 @@ pub fn setup_workspace_directory(machine_mode: bool) -> Result<PathBuf> {
// Create the directory if it doesn't exist
if !workspace_dir.exists() {
std::fs::create_dir_all(&workspace_dir)?;
let output = SimpleOutput::new_with_mode(machine_mode);
let output = SimpleOutput::new();
output.print(&format!(
"📁 Created workspace directory: {}",
workspace_dir.display()

View File

@@ -275,20 +275,3 @@ fn test_quiet_option_accepted() {
"--quiet option should be recognized"
);
}
// =============================================================================
// Test: Machine mode option is accepted
// =============================================================================
#[test]
fn test_machine_option_accepted() {
let output = Command::new(get_g3_binary())
.args(["--machine", "--help"])
.output()
.expect("Failed to execute g3 with machine option");
assert!(
output.status.success(),
"--machine option should be recognized"
);
}

View File

@@ -1452,8 +1452,6 @@ impl<W: UiWriter> Agent<W> {
return; // Don't modify context if save failed
}
println!("💾 Dehydrated {} messages to fragment {}", fragment.message_count, fragment.fragment_id);
// Now replace the context: keep system messages + previous stubs/summaries, add new stub, add new summary
// Extract messages to keep: system messages + everything up to (but not including) dehydrate_start
let messages_to_keep: Vec<_> = self.context_window
@@ -1524,7 +1522,7 @@ impl<W: UiWriter> Agent<W> {
let tools_called = std::mem::take(&mut self.tool_calls_this_turn);
debug!("Auto-memory: Sending reminder to LLM ({} tools called this turn: {:?})", tools_called.len(), tools_called);
self.ui_writer.print_context_status("\n*memory checkpoint:* ");
self.ui_writer.print_context_status("\nMemory checkpoint: ");
let reminder = "SYSTEM REMINDER: You used tools during this turn. If you discovered any key code locations, patterns, or entry points that aren't already in Project Memory, please call the `remember` tool now to save them. If you didn't discover anything new worth remembering, you can skip this. Respond briefly after deciding.";