refactor(run): drop debug-only node artifact files

Remove API/CLI request and log artifact writes plus panic.txt now that
run state and events are store-backed. Update the direct tests to assert
returned behavior instead of on-disk debug files.
This commit is contained in:
Bryan Helmkamp 2026-04-03 11:23:14 -07:00
parent 679728a1a8
commit 58a1380865
No known key found for this signature in database
7 changed files with 20 additions and 103 deletions

View file

@ -25,8 +25,6 @@ async fn run_real_cli_test(provider: Provider, model: &str) {
let context = Context::new();
let emitter = Arc::new(EventEmitter::default());
let dir = tempfile::tempdir().unwrap();
let result = backend
.run(
&node,
@ -34,7 +32,7 @@ async fn run_real_cli_test(provider: Provider, model: &str) {
&context,
None,
&emitter,
dir.path(),
workspace.path(),
&env,
None,
)
@ -56,29 +54,6 @@ async fn run_real_cli_test(provider: Provider, model: &str) {
}
CodergenResult::Full(_) => panic!("expected Text result from {provider}/{model}"),
}
// Verify log files were written
let provider_path = dir.path().join("provider_used.json");
assert!(
provider_path.exists(),
"{provider}/{model}: provider_used.json should exist"
);
let provider_json: serde_json::Value =
serde_json::from_str(&std::fs::read_to_string(&provider_path).unwrap()).unwrap();
assert_eq!(provider_json["mode"], "cli");
assert_eq!(provider_json["provider"], provider.as_str());
// Verify CLI output was streamed to stage_dir during poll
let stdout_log = dir.path().join("cli_stdout.log");
assert!(
stdout_log.exists(),
"{provider}/{model}: cli_stdout.log should be written during poll"
);
let stdout_content = std::fs::read_to_string(&stdout_log).unwrap();
assert!(
!stdout_content.is_empty(),
"{provider}/{model}: cli_stdout.log should not be empty"
);
}
#[fabro_macros::e2e_test(live("ANTHROPIC_API_KEY"))]

View file

@ -13,7 +13,6 @@ use fabro_llm::types::{Message, Request, Usage};
use fabro_mcp::config::McpServerSettings;
use fabro_model::FallbackTarget;
use fabro_model::Provider;
use tokio::fs;
use tokio::sync::Mutex as TokioMutex;
use super::super::agent::{CodergenBackend, CodergenResult};
@ -269,7 +268,7 @@ impl CodergenBackend for AgentApiBackend {
node: &Node,
prompt: &str,
system_prompt: Option<&str>,
stage_dir: &std::path::Path,
_stage_dir: &std::path::Path,
) -> Result<CodergenResult, FabroError> {
let client = Client::from_env()
.await
@ -310,11 +309,6 @@ impl CodergenBackend for AgentApiBackend {
provider_options: None,
};
let _ = fs::create_dir_all(stage_dir).await;
if let Ok(json) = serde_json::to_string_pretty(&request) {
let _ = fs::write(stage_dir.join("api_request.json"), json).await;
}
// Build per-request fallback chain: if the node overrides the provider,
// no failover is available; otherwise use the backend's.
let fallback_chain: &[FallbackTarget] = if node.provider().is_some() {
@ -391,10 +385,6 @@ impl CodergenBackend for AgentApiBackend {
Err(sdk_err) => return Err(FabroError::Llm(sdk_err)),
};
if let Ok(json) = serde_json::to_string_pretty(&response) {
let _ = fs::write(stage_dir.join("api_response.json"), json).await;
}
let mut stage_usage = StageUsage {
model: actual_model,
input_tokens: response.usage.input_tokens,

View file

@ -6,7 +6,6 @@ use async_trait::async_trait;
use fabro_agent::Sandbox;
use fabro_agent::sandbox::ExecResult;
use fabro_model::Provider;
use tokio::fs;
use tokio::time::sleep;
use super::super::agent::{CodergenBackend, CodergenResult};
@ -466,7 +465,7 @@ impl CodergenBackend for AgentCliBackend {
_context: &Context,
_thread_id: Option<&str>,
emitter: &Arc<EventEmitter>,
stage_dir: &Path,
_stage_dir: &Path,
sandbox: &Arc<dyn Sandbox>,
_tool_hooks: Option<Arc<dyn fabro_agent::ToolHookCallback>>,
) -> Result<CodergenResult, FabroError> {
@ -508,8 +507,6 @@ impl CodergenBackend for AgentCliBackend {
command: command.clone(),
});
let _ = fs::create_dir_all(stage_dir).await;
// Forward provider API key and custom env vars so the CLI tool can authenticate.
// Build a HashMap to pass via exec_command's env_vars parameter — this
// prepends `export` statements directly into the base64-encoded command,
@ -602,21 +599,6 @@ impl CodergenBackend for AgentCliBackend {
.map_err(|e| FabroError::handler(format!("Failed to poll CLI command: {e}")))?;
let status = poll_result.stdout.trim();
// Sync CLI output to stage_dir for visibility (best-effort)
for (remote, local) in [
(&stdout_path, "cli_stdout.log"),
(&stderr_path, "cli_stderr.log"),
] {
if let Ok(r) = sandbox
.exec_command(&format!("cat {remote}"), 30_000, None, None, None)
.await
{
if !r.stdout.is_empty() {
let _ = fs::write(stage_dir.join(local), &r.stdout).await;
}
}
}
if status != "running" {
break status.parse::<i32>().unwrap_or(-1);
}
@ -653,19 +635,7 @@ impl CodergenBackend for AgentCliBackend {
.exec_command(&format!("rm -f {tmp_prefix}_*"), 30_000, None, None, None)
.await;
if let Ok(json) = serde_json::to_string_pretty(&serde_json::json!({
"exit_code": result.exit_code,
"stdout_len": result.stdout.len(),
"stderr_len": result.stderr.len(),
"duration_ms": result.duration_ms,
})) {
let _ = fs::write(stage_dir.join("cli_result_meta.json"), json).await;
}
if result.exit_code != 0 {
let _ = fs::write(stage_dir.join("cli_stdout.log"), &result.stdout).await;
let _ = fs::write(stage_dir.join("cli_stderr.log"), &result.stderr).await;
let tail = |s: &str, n: usize| -> String {
s.chars()
.rev()

View file

@ -17,7 +17,6 @@ use crate::graph::WorkflowNode;
use crate::handler::{EngineServices, dispatch_handler, format_panic_message};
use crate::outcome::{Outcome, StageStatus};
use crate::retry::build_retry_policy;
use crate::run_dir;
use fabro_graphviz::graph::types::Graph as GvGraph;
use tokio::time::timeout;
@ -100,10 +99,6 @@ impl NodeHandler<WorkflowGraph> for WorkflowNodeHandler {
}
Err(panic_payload) => {
let msg = format_panic_message(&panic_payload);
let visit = context.node_visit_count().max(1);
let panic_dir = run_dir::node_dir(&self.run_dir, &gv_node.id, visit);
let _ = std::fs::create_dir_all(&panic_dir);
let _ = std::fs::write(panic_dir.join("panic.txt"), &msg);
Err(CoreError::handler(HandlerErrorDetail {
message: msg,
retryable: false,

View file

@ -768,7 +768,7 @@ async fn max_node_visits_errors_on_cycle() {
}
#[tokio::test]
async fn panic_handler_writes_panic_txt() {
async fn panic_handler_returns_panic_message() {
let dir = tempfile::tempdir().unwrap();
let mut g = Graph::new("panic_test");
let mut start = Node::new("start");
@ -790,7 +790,7 @@ async fn panic_handler_writes_panic_txt() {
let mut registry = make_registry();
registry.register("panicker", Box::new(PanickingHandler));
let _ = run_graph(
let result = run_graph(
registry,
test_emitter_arc("test-run"),
local_env(),
@ -799,10 +799,10 @@ async fn panic_handler_writes_panic_txt() {
)
.await;
let outcome = result.expect("runner should convert panic into a failed outcome");
assert_eq!(outcome.status, StageStatus::Fail);
let panic_path = dir.path().join("nodes").join("boom").join("panic.txt");
assert!(panic_path.exists());
let content = std::fs::read_to_string(&panic_path).unwrap();
assert!(content.contains("test panic message"));
assert!(!panic_path.exists(), "panic.txt should not be written");
}
#[tokio::test]

View file

@ -982,16 +982,6 @@ async fn run_daytona_cli_test(provider: Provider, model: &str, install_command:
Err(e) => panic!("{provider}/{model} on Daytona failed: {e}"),
}
// Verify log files
let provider_path = dir.path().join("provider_used.json");
assert!(
provider_path.exists(),
"{provider}/{model}: provider_used.json should exist"
);
let provider_json: serde_json::Value =
serde_json::from_str(&std::fs::read_to_string(&provider_path).unwrap()).unwrap();
assert_eq!(provider_json["mode"], "cli");
env.cleanup().await.unwrap();
}

View file

@ -9475,7 +9475,7 @@ async fn cli_backend_run_uses_node_provider_override() {
}
#[tokio::test]
async fn cli_backend_run_writes_provider_used_json() {
async fn cli_backend_run_returns_text_and_usage() {
let claude_output =
r#"{"type":"result","result":"done","usage":{"input_tokens":10,"output_tokens":5}}"#;
let env: Arc<dyn fabro_agent::Sandbox> = Arc::new(CliTestEnv::new(claude_output));
@ -9487,7 +9487,7 @@ async fn cli_backend_run_writes_provider_used_json() {
let emitter = Arc::new(EventEmitter::default());
let dir = tempfile::tempdir().unwrap();
backend
let result = backend
.run(
&node,
"test",
@ -9501,19 +9501,16 @@ async fn cli_backend_run_writes_provider_used_json() {
.await
.expect("should succeed");
let provider_path = dir.path().join("provider_used.json");
assert!(provider_path.exists(), "should write provider_used.json");
let provider_json: serde_json::Value =
serde_json::from_str(&std::fs::read_to_string(&provider_path).unwrap()).unwrap();
assert_eq!(provider_json["mode"], "cli");
assert_eq!(provider_json["provider"], "anthropic");
assert_eq!(provider_json["model"], "claude-opus-4-6");
assert!(
provider_json["command"]
.as_str()
.unwrap()
.contains("claude")
);
match result {
CodergenResult::Text { text, usage, .. } => {
assert_eq!(text, "done");
let usage = usage.expect("CLI backend should report usage");
assert_eq!(usage.input_tokens, 10);
assert_eq!(usage.output_tokens, 5);
assert_eq!(usage.model, "claude-opus-4-6");
}
CodergenResult::Full(_) => panic!("expected Text result"),
}
}
// -- BackendRouter e2e: delegates to correct backend --