remove get_task_result, remove bool defaults, RECIPE_TASK_TYPE constant, cloneable RecipeFile

This commit is contained in:
Tyler Longwell
2025-10-21 21:39:15 -04:00
parent c344549c40
commit f07b81e30c
8 changed files with 31 additions and 77 deletions
@@ -57,15 +57,13 @@ fn create_tasks_from_params(
sub_recipe: &SubRecipe,
command_params: &[std::collections::HashMap<String, String>],
) -> Result<Vec<Task>> {
let recipe_file = load_local_recipe_file(&sub_recipe.path)
.map_err(|e| anyhow::anyhow!("Failed to load recipe {}: {}", sub_recipe.path, e))?;
let mut tasks = Vec::new();
for task_command_param in command_params {
// Load the recipe file for each task (can't clone RecipeFile)
let recipe_file = load_local_recipe_file(&sub_recipe.path)
.map_err(|e| anyhow::anyhow!("Failed to load recipe {}: {}", sub_recipe.path, e))?;
let recipe = build_recipe_from_template(
recipe_file.content,
recipe_file.content.clone(),
&recipe_file.parent_dir,
task_command_param
.iter()
@@ -17,6 +17,8 @@ use crate::agents::subagent_execution_tool::utils::{count_by_status, get_task_na
use crate::utils::is_token_cancelled;
use tokio::sync::mpsc::Sender;
const RECIPE_TASK_TYPE: &str = "recipe";
#[derive(Debug, Clone, PartialEq)]
pub enum DisplayMode {
MultipleTasksOutput,
@@ -148,13 +150,15 @@ impl TaskExecutionTracker {
async fn format_line(&self, task_info: Option<&TaskInfo>, line: &str) -> String {
if let Some(task_info) = task_info {
let task_name = get_task_name(task_info);
let task_type = "recipe";
let metadata = format_task_metadata(task_info);
if metadata.is_empty() {
format!("[{} ({})] {}", task_name, task_type, line)
format!("[{} ({})] {}", task_name, RECIPE_TASK_TYPE, line)
} else {
format!("[{} ({}) {}] {}", task_name, task_type, metadata, line)
format!(
"[{} ({}) {}] {}",
task_name, RECIPE_TASK_TYPE, metadata, line
)
}
} else {
line.to_string()
@@ -229,7 +233,7 @@ impl TaskExecutionTracker {
}
}),
current_output: task_info.current_output.clone(),
task_type: "recipe".to_string(),
task_type: RECIPE_TASK_TYPE.to_string(),
task_name: get_task_name(task_info).to_string(),
task_metadata: format_task_metadata(task_info),
error: task_info.error().cloned(),
@@ -20,9 +20,7 @@ pub enum ExecutionMode {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TaskPayload {
pub recipe: Recipe,
#[serde(default)]
pub return_last_only: bool,
#[serde(default)]
pub sequential_when_repeated: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub parameter_values: Option<HashMap<String, String>>,
@@ -8,18 +8,11 @@ use crate::agents::subagent_task_config::TaskConfig;
pub async fn process_task(
task: &Task,
task_execution_tracker: Arc<TaskExecutionTracker>,
_task_execution_tracker: Arc<TaskExecutionTracker>,
task_config: TaskConfig,
cancellation_token: CancellationToken,
) -> TaskResult {
match get_task_result(
task.clone(),
task_execution_tracker,
task_config,
cancellation_token,
)
.await
{
match handle_recipe_task(task.clone(), task_config, cancellation_token).await {
Ok(data) => TaskResult {
task_id: task.id.clone(),
status: TaskStatus::Completed,
@@ -35,15 +28,6 @@ pub async fn process_task(
}
}
async fn get_task_result(
task: Task,
_task_execution_tracker: Arc<TaskExecutionTracker>,
task_config: TaskConfig,
cancellation_token: CancellationToken,
) -> Result<Value, String> {
handle_recipe_task(task, task_config, cancellation_token).await
}
async fn handle_recipe_task(
task: Task,
mut task_config: TaskConfig,
@@ -3,7 +3,6 @@ use std::collections::HashMap;
use crate::agents::subagent_execution_tool::task_types::{TaskInfo, TaskStatus};
pub fn get_task_name(task_info: &TaskInfo) -> &str {
// Return the recipe title (always present as it's a required field)
&task_info.task.payload.recipe.title
}
@@ -12,7 +12,6 @@ use std::future::Future;
use std::pin::Pin;
use tracing::{debug, info};
// Type alias for the complex return type
type AgentMessagesFuture =
Pin<Box<dyn Future<Output = Result<(Conversation, Option<String>)>> + Send>>;
@@ -1,6 +1,8 @@
use anyhow::{anyhow, Result};
use std::fs;
use std::path::{Path, PathBuf};
#[derive(Clone)]
pub struct RecipeFile {
pub content: String,
pub parent_dir: PathBuf,
+15 -45
View File
@@ -14,11 +14,11 @@ use std::collections::HashMap;
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use tokio::sync::{Mutex, OnceCell};
use tokio::sync::OnceCell;
use tracing::{info, warn};
use utoipa::ToSchema;
const CURRENT_SCHEMA_VERSION: i32 = 3;
const CURRENT_SCHEMA_VERSION: i32 = 2;
static SESSION_STORAGE: OnceCell<Arc<SessionStorage>> = OnceCell::const_new();
@@ -245,7 +245,6 @@ impl SessionManager {
pub struct SessionStorage {
pool: Pool<Sqlite>,
create_session_mutex: Arc<Mutex<()>>,
}
pub fn ensure_session_dir() -> Result<PathBuf> {
@@ -354,7 +353,8 @@ impl SessionStorage {
let options = SqliteConnectOptions::new()
.filename(db_path)
.create_if_missing(create_if_missing)
.busy_timeout(std::time::Duration::from_secs(5));
.busy_timeout(std::time::Duration::from_secs(5))
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal);
sqlx::SqlitePool::connect_with(options).await.map_err(|e| {
anyhow::anyhow!(
@@ -368,10 +368,7 @@ impl SessionStorage {
async fn open(db_path: &Path) -> Result<Self> {
let pool = Self::get_pool(db_path, false).await?;
let storage = Self {
pool,
create_session_mutex: Arc::new(Mutex::new(())),
};
let storage = Self { pool };
storage.run_migrations().await?;
Ok(storage)
}
@@ -428,8 +425,7 @@ impl SessionStorage {
content_json TEXT NOT NULL,
created_timestamp INTEGER NOT NULL,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
tokens INTEGER,
metadata_json TEXT
tokens INTEGER
)
"#,
)
@@ -446,10 +442,7 @@ impl SessionStorage {
.execute(&pool)
.await?;
Ok(Self {
pool,
create_session_mutex: Arc::new(Mutex::new(())),
})
Ok(Self { pool })
}
async fn import_legacy(&self, session_dir: &PathBuf) -> Result<()> {
@@ -617,15 +610,6 @@ impl SessionStorage {
.execute(&self.pool)
.await?;
}
3 => {
sqlx::query(
r#"
ALTER TABLE messages ADD COLUMN metadata_json TEXT
"#,
)
.execute(&self.pool)
.await?;
}
_ => {
anyhow::bail!("Unknown migration version: {}", version);
}
@@ -635,9 +619,6 @@ impl SessionStorage {
}
async fn create_session(&self, working_dir: PathBuf, description: String) -> Result<Session> {
// Mutex to prevent concurrent session creation race conditions
let _guard = self.create_session_mutex.lock().await;
let today = chrono::Utc::now().format("%Y%m%d").to_string();
Ok(sqlx::query_as(
r#"
@@ -787,15 +768,15 @@ impl SessionStorage {
}
async fn get_conversation(&self, session_id: &str) -> Result<Conversation> {
let rows = sqlx::query_as::<_, (String, String, i64, Option<String>)>(
"SELECT role, content_json, created_timestamp, metadata_json FROM messages WHERE session_id = ? ORDER BY timestamp",
let rows = sqlx::query_as::<_, (String, String, i64)>(
"SELECT role, content_json, created_timestamp FROM messages WHERE session_id = ? ORDER BY timestamp",
)
.bind(session_id)
.fetch_all(&self.pool)
.await?;
let mut messages = Vec::new();
for (role_str, content_json, created_timestamp, metadata_json) in rows {
for (role_str, content_json, created_timestamp) in rows {
let role = match role_str.as_str() {
"user" => Role::User,
"assistant" => Role::Assistant,
@@ -803,12 +784,7 @@ impl SessionStorage {
};
let content = serde_json::from_str(&content_json)?;
let metadata = metadata_json
.and_then(|json| serde_json::from_str(&json).ok())
.unwrap_or_default();
let mut message = Message::new(role, created_timestamp, content);
message.metadata = metadata;
let message = Message::new(role, created_timestamp, content);
messages.push(message);
}
@@ -816,19 +792,16 @@ impl SessionStorage {
}
async fn add_message(&self, session_id: &str, message: &Message) -> Result<()> {
let metadata_json = serde_json::to_string(&message.metadata)?;
sqlx::query(
r#"
INSERT INTO messages (session_id, role, content_json, created_timestamp, metadata_json)
VALUES (?, ?, ?, ?, ?)
INSERT INTO messages (session_id, role, content_json, created_timestamp)
VALUES (?, ?, ?, ?)
"#,
)
.bind(session_id)
.bind(role_to_string(&message.role))
.bind(serde_json::to_string(&message.content)?)
.bind(message.created)
.bind(metadata_json)
.execute(&self.pool)
.await?;
@@ -853,19 +826,16 @@ impl SessionStorage {
.await?;
for message in conversation.messages() {
let metadata_json = serde_json::to_string(&message.metadata)?;
sqlx::query(
r#"
INSERT INTO messages (session_id, role, content_json, created_timestamp, metadata_json)
VALUES (?, ?, ?, ?, ?)
INSERT INTO messages (session_id, role, content_json, created_timestamp)
VALUES (?, ?, ?, ?)
"#,
)
.bind(session_id)
.bind(role_to_string(&message.role))
.bind(serde_json::to_string(&message.content)?)
.bind(message.created)
.bind(metadata_json)
.execute(&mut *tx)
.await?;
}