diff options
| author | soryu <soryu@soryu.co> | 2026-01-16 17:07:44 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2026-01-16 17:07:44 +0000 |
| commit | f84a7f2d820f6f432be2b1d78d6bf833b5b19380 (patch) | |
| tree | 06398f6a91ec6efe06d2c77e603a27728d72885c /makima/src/db | |
| parent | dcec90d2c233671e64e412a9f7b883d8db6783ec (diff) | |
| download | soryu-f84a7f2d820f6f432be2b1d78d6bf833b5b19380.tar.gz soryu-f84a7f2d820f6f432be2b1d78d6bf833b5b19380.zip | |
Fixup: fix history call and try to start pending tasks when a daemon is available
Diffstat (limited to 'makima/src/db')
| -rw-r--r-- | makima/src/db/models.rs | 38 | ||||
| -rw-r--r-- | makima/src/db/repository.rs | 21 |
2 files changed, 59 insertions, 0 deletions
diff --git a/makima/src/db/models.rs b/makima/src/db/models.rs index 6accb48..0e1303c 100644 --- a/makima/src/db/models.rs +++ b/makima/src/db/models.rs @@ -6,6 +6,42 @@ use sqlx::FromRow; use utoipa::ToSchema; use uuid::Uuid; +/// Flexible datetime deserialization module. +/// Accepts both date-only ("2026-01-15") and full ISO 8601 datetime ("2026-01-15T00:00:00Z") formats. +pub mod flexible_datetime { + use chrono::{DateTime, NaiveDate, NaiveTime, TimeZone, Utc}; + use serde::{self, Deserialize, Deserializer}; + + /// Deserializes a datetime from either date-only or full datetime format. + pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<DateTime<Utc>>, D::Error> + where + D: Deserializer<'de>, + { + let s: Option<String> = Option::deserialize(deserializer)?; + match s { + None => Ok(None), + Some(s) if s.is_empty() => Ok(None), + Some(s) => { + // Try full datetime first (RFC 3339 / ISO 8601) + if let Ok(dt) = DateTime::parse_from_rfc3339(&s) { + return Ok(Some(dt.with_timezone(&Utc))); + } + + // Try date-only format (YYYY-MM-DD) and convert to start of day UTC + if let Ok(date) = NaiveDate::parse_from_str(&s, "%Y-%m-%d") { + let datetime = date.and_time(NaiveTime::MIN); + return Ok(Some(Utc.from_utc_datetime(&datetime))); + } + + Err(serde::de::Error::custom(format!( + "Invalid datetime format '{}'. Expected ISO 8601 datetime (e.g., '2026-01-15T00:00:00Z') or date (e.g., '2026-01-15')", + s + ))) + } + } + } +} + /// TranscriptEntry stored in JSONB - matches frontend TranscriptEntry #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] @@ -1646,7 +1682,9 @@ pub struct ToolCallInfo { pub struct HistoryQueryFilters { pub phase: Option<String>, pub event_types: Option<Vec<String>>, + #[serde(default, deserialize_with = "flexible_datetime::deserialize")] pub from: Option<DateTime<Utc>>, + #[serde(default, deserialize_with = "flexible_datetime::deserialize")] pub to: Option<DateTime<Utc>>, pub limit: Option<i32>, pub cursor: Option<String>, diff --git a/makima/src/db/repository.rs b/makima/src/db/repository.rs index cb9d52f..2b069d5 100644 --- a/makima/src/db/repository.rs +++ b/makima/src/db/repository.rs @@ -789,6 +789,27 @@ pub async fn list_tasks_by_contract( .await } +/// Get pending tasks for a contract (non-supervisor tasks only). +pub async fn get_pending_tasks_for_contract( + pool: &PgPool, + contract_id: Uuid, + owner_id: Uuid, +) -> Result<Vec<Task>, sqlx::Error> { + sqlx::query_as::<_, Task>( + r#" + SELECT * FROM tasks + WHERE contract_id = $1 AND owner_id = $2 + AND status = 'pending' + AND is_supervisor = false + ORDER BY priority DESC, created_at ASC + "#, + ) + .bind(contract_id) + .bind(owner_id) + .fetch_all(pool) + .await +} + /// Update a task by ID with optimistic locking. pub async fn update_task( pool: &PgPool, |
