feat: status_reason field for workflows + proper failure logging
- Add status_reason column to workflows table (migration) - AgentUpdate::WorkflowStatus and WorkflowComplete carry reason - Dispatch failure logs to execution_log with reason - Worker disconnect marks orphaned workflows as failed with reason - All status transitions now have traceable cause
This commit is contained in:
16
src/sink.rs
16
src/sink.rs
@@ -14,12 +14,12 @@ use crate::state::{AgentState, Artifact};
|
||||
#[serde(tag = "kind")]
|
||||
pub enum AgentUpdate {
|
||||
PlanUpdate { workflow_id: String, steps: Vec<PlanStepInfo> },
|
||||
WorkflowStatus { workflow_id: String, status: String },
|
||||
WorkflowStatus { workflow_id: String, status: String, #[serde(default)] reason: String },
|
||||
Activity { workflow_id: String, activity: String },
|
||||
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 },
|
||||
WorkflowComplete { workflow_id: String, status: String, #[serde(default)] reason: String },
|
||||
ArtifactSave { workflow_id: String, step_order: i32, artifact: Artifact },
|
||||
RequirementUpdate { workflow_id: String, requirement: String },
|
||||
/// base64-encoded file content
|
||||
@@ -61,9 +61,9 @@ pub async fn handle_single_update(
|
||||
AgentUpdate::PlanUpdate { workflow_id, steps } => {
|
||||
bcast(broadcast_tx, WsMessage::PlanUpdate { workflow_id: workflow_id.clone(), steps: steps.clone() });
|
||||
}
|
||||
AgentUpdate::WorkflowStatus { workflow_id, status } => {
|
||||
let _ = sqlx::query("UPDATE workflows SET status = ? WHERE id = ?")
|
||||
.bind(status).bind(workflow_id).execute(pool).await;
|
||||
AgentUpdate::WorkflowStatus { workflow_id, status, reason } => {
|
||||
let _ = sqlx::query("UPDATE workflows SET status = ?, status_reason = ? WHERE id = ?")
|
||||
.bind(status).bind(reason).bind(workflow_id).execute(pool).await;
|
||||
bcast(broadcast_tx, WsMessage::WorkflowStatusUpdate { workflow_id: workflow_id.clone(), status: status.clone() });
|
||||
}
|
||||
AgentUpdate::Activity { workflow_id, activity } => {
|
||||
@@ -100,9 +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 } => {
|
||||
let _ = sqlx::query("UPDATE workflows SET status = ? WHERE id = ?")
|
||||
.bind(status).bind(workflow_id).execute(pool).await;
|
||||
AgentUpdate::WorkflowComplete { workflow_id, status, reason } => {
|
||||
let _ = sqlx::query("UPDATE workflows SET status = ?, status_reason = ? WHERE id = ?")
|
||||
.bind(status).bind(reason).bind(workflow_id).execute(pool).await;
|
||||
bcast(broadcast_tx, WsMessage::WorkflowStatusUpdate { workflow_id: workflow_id.clone(), status: status.clone() });
|
||||
}
|
||||
AgentUpdate::ArtifactSave { workflow_id, step_order, artifact } => {
|
||||
|
||||
Reference in New Issue
Block a user