huskies: merge 540_bug_get_agent_output_mcp_tool_returns_no_agent_for_exited_agents_instead_of_reading_session_logs_from_disk
This commit is contained in:
@@ -219,10 +219,42 @@ fn handle_agent_output_sse(
|
||||
|
||||
let mut rx = match ctx.agents.subscribe(&story_id, &agent_name) {
|
||||
Ok(rx) => rx,
|
||||
Err(e) => return to_sse_response(JsonRpcResponse::success(
|
||||
id,
|
||||
json!({ "content": [{"type": "text", "text": e}], "isError": true }),
|
||||
)),
|
||||
Err(_) => {
|
||||
// Agent not in pool (exited or never started) — fall back to disk logs.
|
||||
let text = if let Ok(project_root) = ctx.agents.get_project_root(&ctx.state) {
|
||||
use crate::agent_log;
|
||||
let log_files = agent_log::list_story_log_files(
|
||||
&project_root,
|
||||
&story_id,
|
||||
Some(&agent_name),
|
||||
);
|
||||
if log_files.is_empty() {
|
||||
format!("No log files found for story '{story_id}' agent '{agent_name}'.")
|
||||
} else {
|
||||
let mut all_lines: Vec<String> = Vec::new();
|
||||
for path in &log_files {
|
||||
let file_name =
|
||||
path.file_name().and_then(|n| n.to_str()).unwrap_or("?");
|
||||
all_lines.push(format!(
|
||||
"=== {} ===",
|
||||
file_name.trim_end_matches(".log")
|
||||
));
|
||||
match agent_log::read_log_as_readable_lines(path) {
|
||||
Ok(lines) => all_lines.extend(lines),
|
||||
Err(e) => all_lines.push(format!("[ERROR reading log: {e}]")),
|
||||
}
|
||||
all_lines.push(String::new());
|
||||
}
|
||||
all_lines.join("\n")
|
||||
}
|
||||
} else {
|
||||
format!("No log files found for story '{story_id}' agent '{agent_name}'.")
|
||||
};
|
||||
return to_sse_response(JsonRpcResponse::success(
|
||||
id,
|
||||
json!({ "content": [{"type": "text", "text": text}] }),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let final_id = id;
|
||||
@@ -1799,7 +1831,8 @@ mod tests {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn mcp_post_sse_get_agent_output_no_agent_returns_sse_error() {
|
||||
async fn mcp_post_sse_get_agent_output_no_agent_no_logs_returns_not_found() {
|
||||
// Agent not in pool and no log files → SSE success with "No log files found" message.
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let ctx = std::sync::Arc::new(test_ctx(tmp.path()));
|
||||
let cli = poem::test::TestClient::new(test_mcp_app(ctx));
|
||||
@@ -1816,5 +1849,40 @@ mod tests {
|
||||
);
|
||||
let body = resp.0.into_body().into_string().await.unwrap();
|
||||
assert!(body.contains("data:"), "expected SSE data prefix: {body}");
|
||||
// Must NOT return isError — should be a success result with "No log files found"
|
||||
assert!(!body.contains("isError"), "expected no isError for missing agent: {body}");
|
||||
assert!(body.contains("No log files found"), "expected not-found message: {body}");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn mcp_post_sse_get_agent_output_exited_agent_reads_disk_logs() {
|
||||
use crate::agent_log::AgentLogWriter;
|
||||
use crate::agents::AgentEvent;
|
||||
// Agent has exited (not in pool) but wrote logs to disk.
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let root = tmp.path();
|
||||
let mut writer =
|
||||
AgentLogWriter::new(root, "42_story_foo", "coder-1", "sess-sse").unwrap();
|
||||
writer
|
||||
.write_event(&AgentEvent::Output {
|
||||
story_id: "42_story_foo".to_string(),
|
||||
agent_name: "coder-1".to_string(),
|
||||
text: "disk output".to_string(),
|
||||
})
|
||||
.unwrap();
|
||||
drop(writer);
|
||||
|
||||
let ctx = std::sync::Arc::new(test_ctx(root));
|
||||
let cli = poem::test::TestClient::new(test_mcp_app(ctx));
|
||||
let resp = cli
|
||||
.post("/mcp")
|
||||
.header("content-type", "application/json")
|
||||
.header("accept", "text/event-stream")
|
||||
.body(r#"{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_agent_output","arguments":{"story_id":"42_story_foo","agent_name":"coder-1"}}}"#)
|
||||
.send()
|
||||
.await;
|
||||
let body = resp.0.into_body().into_string().await.unwrap();
|
||||
assert!(body.contains("disk output"), "expected disk log content in SSE response: {body}");
|
||||
assert!(!body.contains("isError"), "expected no error for exited agent with logs: {body}");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user