feat: file sync from worker to server + report.md convention
- Add AgentUpdate::FileSync (base64-encoded) for file transfer
- Worker syncs all workspace files to server after workflow completes
(skips .venv, __pycache__, .git, node_modules, files > 1MB)
- Server writes synced files to /app/data/workspaces/{project_id}/
- Remove report field from WorkflowComplete (use report.md convention)
- Update prompts: last step should generate report.md, remove KB/worker tool references
This commit is contained in:
22
src/sink.rs
22
src/sink.rs
@@ -19,9 +19,11 @@ pub enum AgentUpdate {
|
||||
ExecutionLog { workflow_id: String, step_order: i32, tool_name: String, tool_input: String, output: String, status: String },
|
||||
LlmCallLog { workflow_id: String, step_order: i32, phase: String, messages_count: i32, tools_count: i32, tool_calls: String, text_response: String, prompt_tokens: Option<u32>, completion_tokens: Option<u32>, latency_ms: i64 },
|
||||
StateSnapshot { workflow_id: String, step_order: i32, state: AgentState },
|
||||
WorkflowComplete { workflow_id: String, status: String, report: Option<String> },
|
||||
WorkflowComplete { workflow_id: String, status: String },
|
||||
ArtifactSave { workflow_id: String, step_order: i32, artifact: Artifact },
|
||||
RequirementUpdate { workflow_id: String, requirement: String },
|
||||
/// base64-encoded file content
|
||||
FileSync { project_id: String, path: String, data_b64: String },
|
||||
Error { message: String },
|
||||
}
|
||||
|
||||
@@ -98,14 +100,9 @@ pub async fn handle_single_update(
|
||||
"INSERT INTO agent_state_snapshots (id, workflow_id, step_order, state_json, created_at) VALUES (?, ?, ?, ?, datetime('now'))"
|
||||
).bind(&id).bind(workflow_id).bind(step_order).bind(&json).execute(pool).await;
|
||||
}
|
||||
AgentUpdate::WorkflowComplete { workflow_id, status, report } => {
|
||||
AgentUpdate::WorkflowComplete { workflow_id, status } => {
|
||||
let _ = sqlx::query("UPDATE workflows SET status = ? WHERE id = ?")
|
||||
.bind(status).bind(workflow_id).execute(pool).await;
|
||||
if let Some(r) = report {
|
||||
let _ = sqlx::query("UPDATE workflows SET report = ? WHERE id = ?")
|
||||
.bind(r).bind(workflow_id).execute(pool).await;
|
||||
bcast(broadcast_tx, WsMessage::ReportReady { workflow_id: workflow_id.clone() });
|
||||
}
|
||||
bcast(broadcast_tx, WsMessage::WorkflowStatusUpdate { workflow_id: workflow_id.clone(), status: status.clone() });
|
||||
}
|
||||
AgentUpdate::ArtifactSave { workflow_id, step_order, artifact } => {
|
||||
@@ -120,6 +117,17 @@ pub async fn handle_single_update(
|
||||
.bind(requirement).bind(workflow_id).execute(pool).await;
|
||||
bcast(broadcast_tx, WsMessage::RequirementUpdate { workflow_id: workflow_id.clone(), requirement: requirement.clone() });
|
||||
}
|
||||
AgentUpdate::FileSync { project_id, path, data_b64 } => {
|
||||
use base64::Engine;
|
||||
let base = format!("/app/data/workspaces/{}", project_id);
|
||||
let full = std::path::Path::new(&base).join(path);
|
||||
if let Some(parent) = full.parent() {
|
||||
let _ = tokio::fs::create_dir_all(parent).await;
|
||||
}
|
||||
if let Ok(bytes) = base64::engine::general_purpose::STANDARD.decode(data_b64) {
|
||||
let _ = tokio::fs::write(&full, &bytes).await;
|
||||
}
|
||||
}
|
||||
AgentUpdate::Error { message } => {
|
||||
bcast(broadcast_tx, WsMessage::Error { message: message.clone() });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user