From 2aed3c06c812ac4280f56553708c32a8301616f6 Mon Sep 17 00:00:00 2001 From: Louis Knight-Webb Date: Tue, 1 Jul 2025 17:45:12 +0100 Subject: [PATCH] Save assistant message (vibe-kanban) (#47) * Task attempt bc7ef54d-3955-4902-8086-6676c7924f1b - Final changes * Task attempt bc7ef54d-3955-4902-8086-6676c7924f1b - Final changes * Task attempt bc7ef54d-3955-4902-8086-6676c7924f1b - Final changes * Task attempt bc7ef54d-3955-4902-8086-6676c7924f1b - Final changes * Task attempt bc7ef54d-3955-4902-8086-6676c7924f1b - Final changes * Cargo fmt --- ...7932224dc325b23476cb84153d690227fd8b.json} | 14 ++- ...31a2ba93d95a27bcbbef0058d4726af8a733.json} | 14 ++- ...8f7ef23177431eaed82dc08c94c3e5944340e.json | 12 ++ ...d700f06ae08821fee00c9a5b60492b05259c.json} | 14 ++- ...085452e24260f48844b588152b532ca5d6e7.json} | 16 ++- ...assistant_message_to_executor_sessions.sql | 2 + backend/src/execution_monitor.rs | 48 +++++++- backend/src/executor.rs | 115 ++++++++++++++++++ backend/src/models/executor_session.rs | 34 +++++- shared/types.ts | 4 +- 10 files changed, 247 insertions(+), 26 deletions(-) rename backend/.sqlx/{query-3b65c0f6215229f3c8d487c204bca5a1a8e327d9b469b47d833befa95377dfab.json => query-417a8b1ff4e51de82aea0159a3b97932224dc325b23476cb84153d690227fd8b.json} (72%) rename backend/.sqlx/{query-06ca282915d0db9125769b1bca92f7a5bd7f81ad8faf0f9fcbb5f1c2d35dd67f.json => query-89a6db6a4b318736dca5c1b8921631a2ba93d95a27bcbbef0058d4726af8a733.json} (74%) create mode 100644 backend/.sqlx/query-8a67b3b3337248f06a57bdf8a908f7ef23177431eaed82dc08c94c3e5944340e.json rename backend/.sqlx/{query-0468aa522ed7fd2675bcf278f6be38ce16752cb73adf0fafc5b497a88f32f531.json => query-a31fff84f3b8e532fd1160447d89d700f06ae08821fee00c9a5b60492b05259c.json} (75%) rename backend/.sqlx/{query-a528a9926fab1c819a5a1fa1cde87ea9d354da0873af22e888d0bf8e0c7f306a.json => query-d0d71fd65c0f9f1bd0df2588d313085452e24260f48844b588152b532ca5d6e7.json} (55%) create mode 100644 backend/migrations/20250701120000_add_assistant_message_to_executor_sessions.sql diff --git a/backend/.sqlx/query-3b65c0f6215229f3c8d487c204bca5a1a8e327d9b469b47d833befa95377dfab.json b/backend/.sqlx/query-417a8b1ff4e51de82aea0159a3b97932224dc325b23476cb84153d690227fd8b.json similarity index 72% rename from backend/.sqlx/query-3b65c0f6215229f3c8d487c204bca5a1a8e327d9b469b47d833befa95377dfab.json rename to backend/.sqlx/query-417a8b1ff4e51de82aea0159a3b97932224dc325b23476cb84153d690227fd8b.json index c68f35ad..94241165 100644 --- a/backend/.sqlx/query-3b65c0f6215229f3c8d487c204bca5a1a8e327d9b469b47d833befa95377dfab.json +++ b/backend/.sqlx/query-417a8b1ff4e51de82aea0159a3b97932224dc325b23476cb84153d690227fd8b.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT \n id as \"id!: Uuid\", \n task_attempt_id as \"task_attempt_id!: Uuid\", \n execution_process_id as \"execution_process_id!: Uuid\", \n session_id, \n prompt,\n created_at as \"created_at!: DateTime\", \n updated_at as \"updated_at!: DateTime\"\n FROM executor_sessions \n WHERE id = $1", + "query": "SELECT \n id as \"id!: Uuid\", \n task_attempt_id as \"task_attempt_id!: Uuid\", \n execution_process_id as \"execution_process_id!: Uuid\", \n session_id, \n prompt,\n summary,\n created_at as \"created_at!: DateTime\", \n updated_at as \"updated_at!: DateTime\"\n FROM executor_sessions \n WHERE task_attempt_id = $1 \n ORDER BY created_at ASC", "describe": { "columns": [ { @@ -29,14 +29,19 @@ "type_info": "Text" }, { - "name": "created_at!: DateTime", + "name": "summary", "ordinal": 5, "type_info": "Text" }, { - "name": "updated_at!: DateTime", + "name": "created_at!: DateTime", "ordinal": 6, "type_info": "Text" + }, + { + "name": "updated_at!: DateTime", + "ordinal": 7, + "type_info": "Text" } ], "parameters": { @@ -48,9 +53,10 @@ false, true, true, + true, false, false ] }, - "hash": "3b65c0f6215229f3c8d487c204bca5a1a8e327d9b469b47d833befa95377dfab" + "hash": "417a8b1ff4e51de82aea0159a3b97932224dc325b23476cb84153d690227fd8b" } diff --git a/backend/.sqlx/query-06ca282915d0db9125769b1bca92f7a5bd7f81ad8faf0f9fcbb5f1c2d35dd67f.json b/backend/.sqlx/query-89a6db6a4b318736dca5c1b8921631a2ba93d95a27bcbbef0058d4726af8a733.json similarity index 74% rename from backend/.sqlx/query-06ca282915d0db9125769b1bca92f7a5bd7f81ad8faf0f9fcbb5f1c2d35dd67f.json rename to backend/.sqlx/query-89a6db6a4b318736dca5c1b8921631a2ba93d95a27bcbbef0058d4726af8a733.json index aaa01c38..7463d080 100644 --- a/backend/.sqlx/query-06ca282915d0db9125769b1bca92f7a5bd7f81ad8faf0f9fcbb5f1c2d35dd67f.json +++ b/backend/.sqlx/query-89a6db6a4b318736dca5c1b8921631a2ba93d95a27bcbbef0058d4726af8a733.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT \n id as \"id!: Uuid\", \n task_attempt_id as \"task_attempt_id!: Uuid\", \n execution_process_id as \"execution_process_id!: Uuid\", \n session_id, \n prompt,\n created_at as \"created_at!: DateTime\", \n updated_at as \"updated_at!: DateTime\"\n FROM executor_sessions \n WHERE task_attempt_id = $1 \n ORDER BY created_at ASC", + "query": "SELECT \n id as \"id!: Uuid\", \n task_attempt_id as \"task_attempt_id!: Uuid\", \n execution_process_id as \"execution_process_id!: Uuid\", \n session_id, \n prompt,\n summary,\n created_at as \"created_at!: DateTime\", \n updated_at as \"updated_at!: DateTime\"\n FROM executor_sessions \n WHERE execution_process_id = $1", "describe": { "columns": [ { @@ -29,14 +29,19 @@ "type_info": "Text" }, { - "name": "created_at!: DateTime", + "name": "summary", "ordinal": 5, "type_info": "Text" }, { - "name": "updated_at!: DateTime", + "name": "created_at!: DateTime", "ordinal": 6, "type_info": "Text" + }, + { + "name": "updated_at!: DateTime", + "ordinal": 7, + "type_info": "Text" } ], "parameters": { @@ -48,9 +53,10 @@ false, true, true, + true, false, false ] }, - "hash": "06ca282915d0db9125769b1bca92f7a5bd7f81ad8faf0f9fcbb5f1c2d35dd67f" + "hash": "89a6db6a4b318736dca5c1b8921631a2ba93d95a27bcbbef0058d4726af8a733" } diff --git a/backend/.sqlx/query-8a67b3b3337248f06a57bdf8a908f7ef23177431eaed82dc08c94c3e5944340e.json b/backend/.sqlx/query-8a67b3b3337248f06a57bdf8a908f7ef23177431eaed82dc08c94c3e5944340e.json new file mode 100644 index 00000000..996a68f1 --- /dev/null +++ b/backend/.sqlx/query-8a67b3b3337248f06a57bdf8a908f7ef23177431eaed82dc08c94c3e5944340e.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "UPDATE executor_sessions \n SET summary = $1, updated_at = datetime('now') \n WHERE execution_process_id = $2", + "describe": { + "columns": [], + "parameters": { + "Right": 2 + }, + "nullable": [] + }, + "hash": "8a67b3b3337248f06a57bdf8a908f7ef23177431eaed82dc08c94c3e5944340e" +} diff --git a/backend/.sqlx/query-0468aa522ed7fd2675bcf278f6be38ce16752cb73adf0fafc5b497a88f32f531.json b/backend/.sqlx/query-a31fff84f3b8e532fd1160447d89d700f06ae08821fee00c9a5b60492b05259c.json similarity index 75% rename from backend/.sqlx/query-0468aa522ed7fd2675bcf278f6be38ce16752cb73adf0fafc5b497a88f32f531.json rename to backend/.sqlx/query-a31fff84f3b8e532fd1160447d89d700f06ae08821fee00c9a5b60492b05259c.json index da199ecc..b8d73868 100644 --- a/backend/.sqlx/query-0468aa522ed7fd2675bcf278f6be38ce16752cb73adf0fafc5b497a88f32f531.json +++ b/backend/.sqlx/query-a31fff84f3b8e532fd1160447d89d700f06ae08821fee00c9a5b60492b05259c.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT \n id as \"id!: Uuid\", \n task_attempt_id as \"task_attempt_id!: Uuid\", \n execution_process_id as \"execution_process_id!: Uuid\", \n session_id, \n prompt,\n created_at as \"created_at!: DateTime\", \n updated_at as \"updated_at!: DateTime\"\n FROM executor_sessions \n WHERE execution_process_id = $1", + "query": "SELECT \n id as \"id!: Uuid\", \n task_attempt_id as \"task_attempt_id!: Uuid\", \n execution_process_id as \"execution_process_id!: Uuid\", \n session_id, \n prompt,\n summary,\n created_at as \"created_at!: DateTime\", \n updated_at as \"updated_at!: DateTime\"\n FROM executor_sessions \n WHERE id = $1", "describe": { "columns": [ { @@ -29,14 +29,19 @@ "type_info": "Text" }, { - "name": "created_at!: DateTime", + "name": "summary", "ordinal": 5, "type_info": "Text" }, { - "name": "updated_at!: DateTime", + "name": "created_at!: DateTime", "ordinal": 6, "type_info": "Text" + }, + { + "name": "updated_at!: DateTime", + "ordinal": 7, + "type_info": "Text" } ], "parameters": { @@ -48,9 +53,10 @@ false, true, true, + true, false, false ] }, - "hash": "0468aa522ed7fd2675bcf278f6be38ce16752cb73adf0fafc5b497a88f32f531" + "hash": "a31fff84f3b8e532fd1160447d89d700f06ae08821fee00c9a5b60492b05259c" } diff --git a/backend/.sqlx/query-a528a9926fab1c819a5a1fa1cde87ea9d354da0873af22e888d0bf8e0c7f306a.json b/backend/.sqlx/query-d0d71fd65c0f9f1bd0df2588d313085452e24260f48844b588152b532ca5d6e7.json similarity index 55% rename from backend/.sqlx/query-a528a9926fab1c819a5a1fa1cde87ea9d354da0873af22e888d0bf8e0c7f306a.json rename to backend/.sqlx/query-d0d71fd65c0f9f1bd0df2588d313085452e24260f48844b588152b532ca5d6e7.json index 1437e561..2db01a88 100644 --- a/backend/.sqlx/query-a528a9926fab1c819a5a1fa1cde87ea9d354da0873af22e888d0bf8e0c7f306a.json +++ b/backend/.sqlx/query-d0d71fd65c0f9f1bd0df2588d313085452e24260f48844b588152b532ca5d6e7.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "INSERT INTO executor_sessions (\n id, task_attempt_id, execution_process_id, session_id, prompt, \n created_at, updated_at\n ) \n VALUES ($1, $2, $3, $4, $5, $6, $7) \n RETURNING \n id as \"id!: Uuid\", \n task_attempt_id as \"task_attempt_id!: Uuid\", \n execution_process_id as \"execution_process_id!: Uuid\", \n session_id, \n prompt,\n created_at as \"created_at!: DateTime\", \n updated_at as \"updated_at!: DateTime\"", + "query": "INSERT INTO executor_sessions (\n id, task_attempt_id, execution_process_id, session_id, prompt, summary,\n created_at, updated_at\n ) \n VALUES ($1, $2, $3, $4, $5, $6, $7, $8) \n RETURNING \n id as \"id!: Uuid\", \n task_attempt_id as \"task_attempt_id!: Uuid\", \n execution_process_id as \"execution_process_id!: Uuid\", \n session_id, \n prompt,\n summary,\n created_at as \"created_at!: DateTime\", \n updated_at as \"updated_at!: DateTime\"", "describe": { "columns": [ { @@ -29,18 +29,23 @@ "type_info": "Text" }, { - "name": "created_at!: DateTime", + "name": "summary", "ordinal": 5, "type_info": "Text" }, { - "name": "updated_at!: DateTime", + "name": "created_at!: DateTime", "ordinal": 6, "type_info": "Text" + }, + { + "name": "updated_at!: DateTime", + "ordinal": 7, + "type_info": "Text" } ], "parameters": { - "Right": 7 + "Right": 8 }, "nullable": [ true, @@ -48,9 +53,10 @@ false, true, true, + true, false, false ] }, - "hash": "a528a9926fab1c819a5a1fa1cde87ea9d354da0873af22e888d0bf8e0c7f306a" + "hash": "d0d71fd65c0f9f1bd0df2588d313085452e24260f48844b588152b532ca5d6e7" } diff --git a/backend/migrations/20250701120000_add_assistant_message_to_executor_sessions.sql b/backend/migrations/20250701120000_add_assistant_message_to_executor_sessions.sql new file mode 100644 index 00000000..a6e37a22 --- /dev/null +++ b/backend/migrations/20250701120000_add_assistant_message_to_executor_sessions.sql @@ -0,0 +1,2 @@ +-- Add summary column to executor_sessions table +ALTER TABLE executor_sessions ADD COLUMN summary TEXT; diff --git a/backend/src/execution_monitor.rs b/backend/src/execution_monitor.rs index eab5cdfc..a4761e5d 100644 --- a/backend/src/execution_monitor.rs +++ b/backend/src/execution_monitor.rs @@ -17,9 +17,11 @@ use crate::{ async fn commit_execution_changes( worktree_path: &str, attempt_id: Uuid, + summary: Option<&str>, ) -> Result<(), Box> { // Run git operations in a blocking task since git2 is synchronous let worktree_path = worktree_path.to_string(); + let summary = summary.map(|s| s.to_string()); tokio::task::spawn_blocking(move || { let worktree_repo = Repository::open(&worktree_path)?; @@ -55,7 +57,11 @@ async fn commit_execution_changes( let tree = worktree_repo.find_tree(tree_id)?; // Create commit for the changes - let commit_message = format!("Task attempt {} - Final changes", attempt_id); + let commit_message = if let Some(ref summary_msg) = summary { + summary_msg.clone() + } else { + format!("Task attempt {} - Final changes", attempt_id) + }; worktree_repo.commit( Some("HEAD"), &signature, @@ -580,7 +586,7 @@ async fn handle_coding_agent_completion( app_state: &AppState, task_attempt_id: Uuid, execution_process_id: Uuid, - _execution_process: ExecutionProcess, + execution_process: ExecutionProcess, success: bool, exit_code: Option, ) { @@ -590,6 +596,37 @@ async fn handle_coding_agent_completion( String::new() }; + // Extract and store assistant message from execution logs + let summary = if let Some(stdout) = &execution_process.stdout { + if let Some(assistant_message) = crate::executor::parse_assistant_message_from_logs(stdout) + { + if let Err(e) = crate::models::executor_session::ExecutorSession::update_summary( + &app_state.db_pool, + execution_process_id, + &assistant_message, + ) + .await + { + tracing::error!( + "Failed to update summary for execution process {}: {}", + execution_process_id, + e + ); + None + } else { + tracing::info!( + "Successfully stored summary for execution process {}", + execution_process_id + ); + Some(assistant_message) + } + } else { + None + } + } else { + None + }; + // Play sound notification if enabled if app_state.get_sound_alerts_enabled().await { let sound_file = app_state.get_sound_file().await; @@ -612,7 +649,12 @@ async fn handle_coding_agent_completion( TaskAttempt::find_by_id(&app_state.db_pool, task_attempt_id).await { // Commit any unstaged changes after execution completion - if let Err(e) = commit_execution_changes(&task_attempt.worktree_path, task_attempt_id).await + if let Err(e) = commit_execution_changes( + &task_attempt.worktree_path, + task_attempt_id, + summary.as_deref(), + ) + .await { tracing::error!( "Failed to commit execution changes for attempt {}: {}", diff --git a/backend/src/executor.rs b/backend/src/executor.rs index 4d163a2c..bffa7bda 100644 --- a/backend/src/executor.rs +++ b/backend/src/executor.rs @@ -436,6 +436,90 @@ pub async fn stream_output_to_db( } } +/// Parse assistant message from executor logs (JSONL format) +pub fn parse_assistant_message_from_logs(logs: &str) -> Option { + use serde_json::Value; + + let mut last_assistant_message = None; + + for line in logs.lines() { + let trimmed = line.trim(); + if trimmed.is_empty() { + continue; + } + + // Try to parse as JSON + if let Ok(json) = serde_json::from_str::(trimmed) { + // Check for Claude format: {"type":"assistant","message":{"content":[...]}} + if let Some(msg_type) = json.get("type").and_then(|t| t.as_str()) { + if msg_type == "assistant" { + if let Some(message) = json.get("message") { + if let Some(content) = message.get("content").and_then(|c| c.as_array()) { + // Extract text content from Claude assistant message + let mut text_parts = Vec::new(); + for content_item in content { + if let Some(content_type) = + content_item.get("type").and_then(|t| t.as_str()) + { + if content_type == "text" { + if let Some(text) = + content_item.get("text").and_then(|t| t.as_str()) + { + text_parts.push(text); + } + } + } + } + if !text_parts.is_empty() { + last_assistant_message = Some(text_parts.join("\n")); + } + } + } + continue; + } + } + + // Check for AMP format: {"type":"messages","messages":[[1,{"role":"assistant",...}]]} + if let Some(messages) = json.get("messages").and_then(|m| m.as_array()) { + for message_entry in messages { + if let Some(message_data) = message_entry.as_array().and_then(|arr| arr.get(1)) + { + if let Some(role) = message_data.get("role").and_then(|r| r.as_str()) { + if role == "assistant" { + if let Some(content) = + message_data.get("content").and_then(|c| c.as_array()) + { + // Extract text content from AMP assistant message + let mut text_parts = Vec::new(); + for content_item in content { + if let Some(content_type) = + content_item.get("type").and_then(|t| t.as_str()) + { + if content_type == "text" { + if let Some(text) = content_item + .get("text") + .and_then(|t| t.as_str()) + { + text_parts.push(text); + } + } + } + } + if !text_parts.is_empty() { + last_assistant_message = Some(text_parts.join("\n")); + } + } + } + } + } + } + } + } + } + + last_assistant_message +} + /// Parse session_id from Claude or thread_id from Amp from the first JSONL line fn parse_session_id_from_line(line: &str) -> Option { use serde_json::Value; @@ -502,4 +586,35 @@ mod tests { assert_eq!(parse_session_id_from_line(""), None); assert_eq!(parse_session_id_from_line(" "), None); } + + #[test] + fn test_parse_assistant_message_from_logs() { + // Test AMP format + let amp_logs = r#"{"type":"initial","threadID":"T-e7af5516-e5a5-4754-8e34-810dc658716e"} +{"type":"messages","messages":[[0,{"role":"user","content":[{"type":"text","text":"Task title: Test task"}],"meta":{"sentAt":1751385490573}}]],"toolResults":[]} +{"type":"messages","messages":[[1,{"role":"assistant","content":[{"type":"thinking","thinking":"Testing"},{"type":"text","text":"The Pythagorean theorem states that in a right triangle, the square of the hypotenuse equals the sum of squares of the other two sides: **a² + b² = c²**."}],"state":{"type":"complete","stopReason":"end_turn"}}]],"toolResults":[]} +{"type":"state","state":"idle"} +{"type":"shutdown"}"#; + + let result = parse_assistant_message_from_logs(amp_logs); + assert!(result.is_some()); + assert!(result.as_ref().unwrap().contains("Pythagorean theorem")); + assert!(result.as_ref().unwrap().contains("a² + b² = c²")); + } + + #[test] + fn test_parse_claude_assistant_message_from_logs() { + // Test Claude format + let claude_logs = r#"{"type":"system","subtype":"init","cwd":"/private/tmp","session_id":"e988eeea-3712-46a1-82d4-84fbfaa69114","tools":[],"model":"claude-sonnet-4-20250514"} +{"type":"assistant","message":{"id":"msg_123","type":"message","role":"assistant","model":"claude-sonnet-4-20250514","content":[{"type":"text","text":"I'll explain the Pythagorean theorem for you.\n\nThe Pythagorean theorem states that in a right triangle, the square of the hypotenuse equals the sum of the squares of the other two sides.\n\n**Formula:** a² + b² = c²"}],"stop_reason":null},"session_id":"e988eeea-3712-46a1-82d4-84fbfaa69114"} +{"type":"result","subtype":"success","is_error":false,"duration_ms":6059,"result":"Final result"}"#; + + let result = parse_assistant_message_from_logs(claude_logs); + assert!(result.is_some()); + assert!(result.as_ref().unwrap().contains("Pythagorean theorem")); + assert!(result + .as_ref() + .unwrap() + .contains("**Formula:** a² + b² = c²")); + } } diff --git a/backend/src/models/executor_session.rs b/backend/src/models/executor_session.rs index 4fb84e8e..7e625fae 100644 --- a/backend/src/models/executor_session.rs +++ b/backend/src/models/executor_session.rs @@ -12,6 +12,7 @@ pub struct ExecutorSession { pub execution_process_id: Uuid, pub session_id: Option, // External session ID from Claude/Amp pub prompt: Option, // The prompt sent to the executor + pub summary: Option, // Final assistant message/summary pub created_at: DateTime, pub updated_at: DateTime, } @@ -30,6 +31,7 @@ pub struct CreateExecutorSession { pub struct UpdateExecutorSession { pub session_id: Option, pub prompt: Option, + pub summary: Option, } impl ExecutorSession { @@ -44,6 +46,7 @@ impl ExecutorSession { execution_process_id as "execution_process_id!: Uuid", session_id, prompt, + summary, created_at as "created_at!: DateTime", updated_at as "updated_at!: DateTime" FROM executor_sessions @@ -67,6 +70,7 @@ impl ExecutorSession { execution_process_id as "execution_process_id!: Uuid", session_id, prompt, + summary, created_at as "created_at!: DateTime", updated_at as "updated_at!: DateTime" FROM executor_sessions @@ -91,6 +95,7 @@ impl ExecutorSession { execution_process_id as "execution_process_id!: Uuid", session_id, prompt, + summary, created_at as "created_at!: DateTime", updated_at as "updated_at!: DateTime" FROM executor_sessions @@ -113,16 +118,17 @@ impl ExecutorSession { sqlx::query_as!( ExecutorSession, r#"INSERT INTO executor_sessions ( - id, task_attempt_id, execution_process_id, session_id, prompt, + id, task_attempt_id, execution_process_id, session_id, prompt, summary, created_at, updated_at ) - VALUES ($1, $2, $3, $4, $5, $6, $7) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING id as "id!: Uuid", task_attempt_id as "task_attempt_id!: Uuid", execution_process_id as "execution_process_id!: Uuid", session_id, prompt, + summary, created_at as "created_at!: DateTime", updated_at as "updated_at!: DateTime""#, session_id, @@ -130,8 +136,9 @@ impl ExecutorSession { data.execution_process_id, None::, // session_id initially None until parsed from output data.prompt, - now, // created_at - now // updated_at + None::, // summary initially None + now, // created_at + now // updated_at ) .fetch_one(pool) .await @@ -176,6 +183,25 @@ impl ExecutorSession { Ok(()) } + /// Update executor session summary + pub async fn update_summary( + pool: &SqlitePool, + execution_process_id: Uuid, + summary: &str, + ) -> Result<(), sqlx::Error> { + sqlx::query!( + r#"UPDATE executor_sessions + SET summary = $1, updated_at = datetime('now') + WHERE execution_process_id = $2"#, + summary, + execution_process_id + ) + .execute(pool) + .await?; + + Ok(()) + } + /// Delete executor sessions for a task attempt (cleanup) #[allow(dead_code)] pub async fn delete_by_task_attempt_id( diff --git a/shared/types.ts b/shared/types.ts index 5673529d..03f541e4 100644 --- a/shared/types.ts +++ b/shared/types.ts @@ -94,11 +94,11 @@ export type CreateExecutionProcess = { task_attempt_id: string, process_type: Ex export type UpdateExecutionProcess = { status: ExecutionProcessStatus | null, exit_code: bigint | null, completed_at: string | null, }; -export type ExecutorSession = { id: string, task_attempt_id: string, execution_process_id: string, session_id: string | null, prompt: string | null, created_at: string, updated_at: string, }; +export type ExecutorSession = { id: string, task_attempt_id: string, execution_process_id: string, session_id: string | null, prompt: string | null, summary: string | null, created_at: string, updated_at: string, }; export type CreateExecutorSession = { task_attempt_id: string, execution_process_id: string, prompt: string | null, }; -export type UpdateExecutorSession = { session_id: string | null, prompt: string | null, }; +export type UpdateExecutorSession = { session_id: string | null, prompt: string | null, summary: string | null, }; // Generated constants export const EXECUTOR_TYPES: string[] = [