core: type agent timestamps

This commit is contained in:
a.tolmachev
2026-04-19 07:11:55 +00:00
parent dddbbac745
commit 8d1f5284ba
9 changed files with 134 additions and 79 deletions
+59 -4
View File
@@ -1,5 +1,6 @@
use serde::{Deserialize, Serialize};
use serde_json::Value;
use time::OffsetDateTime;
use crate::ids::{AgentId, OperationId, WorkspaceId};
@@ -21,9 +22,12 @@ pub struct Agent {
pub status: AgentStatus,
pub current_draft_version: u32,
pub latest_published_version: Option<u32>,
pub created_at: String,
pub updated_at: String,
pub published_at: Option<String>,
#[serde(with = "time::serde::rfc3339")]
pub created_at: OffsetDateTime,
#[serde(with = "time::serde::rfc3339")]
pub updated_at: OffsetDateTime,
#[serde(with = "time::serde::rfc3339::option")]
pub published_at: Option<OffsetDateTime>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
@@ -33,7 +37,8 @@ pub struct AgentVersion {
pub status: AgentStatus,
pub instructions: Value,
pub tool_selection_policy: Value,
pub created_at: String,
#[serde(with = "time::serde::rfc3339")]
pub created_at: OffsetDateTime,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
@@ -45,3 +50,53 @@ pub struct AgentOperationBinding {
pub tool_description_override: Option<String>,
pub enabled: bool,
}
#[cfg(test)]
mod tests {
use serde_json::json;
use time::{OffsetDateTime, format_description::well_known::Rfc3339};
use super::{Agent, AgentStatus, AgentVersion};
use crate::ids::{AgentId, WorkspaceId};
#[test]
fn agent_serializes_timestamps_as_rfc3339() {
let agent = Agent {
id: AgentId::new("agent_01"),
workspace_id: WorkspaceId::new("ws_01"),
slug: "triage".to_owned(),
display_name: "Triage".to_owned(),
description: "Triage agent".to_owned(),
status: AgentStatus::Published,
current_draft_version: 2,
latest_published_version: Some(2),
created_at: OffsetDateTime::parse("2026-03-25T12:00:00Z", &Rfc3339).unwrap(),
updated_at: OffsetDateTime::parse("2026-03-25T12:05:00Z", &Rfc3339).unwrap(),
published_at: Some(OffsetDateTime::parse("2026-03-25T12:10:00Z", &Rfc3339).unwrap()),
};
let value = serde_json::to_value(&agent).unwrap();
assert_eq!(value["created_at"], json!("2026-03-25T12:00:00Z"));
assert_eq!(value["updated_at"], json!("2026-03-25T12:05:00Z"));
assert_eq!(value["published_at"], json!("2026-03-25T12:10:00Z"));
}
#[test]
fn agent_version_deserializes_created_at_from_rfc3339() {
let version: AgentVersion = serde_json::from_value(json!({
"agent_id": "agent_01",
"version": 1,
"status": "draft",
"instructions": {"system": "triage"},
"tool_selection_policy": {"mode": "allow_list"},
"created_at": "2026-03-25T12:00:00Z"
}))
.unwrap();
assert_eq!(
version.created_at,
OffsetDateTime::parse("2026-03-25T12:00:00Z", &Rfc3339).unwrap()
);
}
}
+5 -5
View File
@@ -170,9 +170,9 @@ pub struct AgentSummary {
pub status: AgentStatus,
pub current_draft_version: u32,
pub latest_published_version: Option<u32>,
pub created_at: String,
pub updated_at: String,
pub published_at: Option<String>,
pub created_at: OffsetDateTime,
pub updated_at: OffsetDateTime,
pub published_at: Option<OffsetDateTime>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
@@ -181,7 +181,7 @@ pub struct AgentVersionRecord {
pub workspace_id: WorkspaceId,
pub version: u32,
pub status: AgentStatus,
pub created_at: String,
pub created_at: OffsetDateTime,
pub snapshot: AgentVersion,
pub bindings: Vec<AgentOperationBinding>,
}
@@ -419,7 +419,7 @@ pub struct PublishAgentRequest<'a> {
pub workspace_id: &'a WorkspaceId,
pub agent_id: &'a AgentId,
pub version: u32,
pub published_at: &'a str,
pub published_at: &'a OffsetDateTime,
pub published_by: Option<&'a str>,
}
+13 -13
View File
@@ -15,9 +15,9 @@ impl PostgresRegistry {
status,
current_draft_version,
latest_published_version,
to_char(created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"created_at!\",
to_char(updated_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"updated_at!\",
to_char(published_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as published_at
created_at as \"created_at!: time::OffsetDateTime\",
updated_at as \"updated_at!: time::OffsetDateTime\",
published_at as \"published_at: time::OffsetDateTime\"
from agents
where workspace_id = $1
order by slug asc",
@@ -60,9 +60,9 @@ impl PostgresRegistry {
status,
current_draft_version,
latest_published_version,
to_char(created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"created_at!\",
to_char(updated_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"updated_at!\",
to_char(published_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as published_at
created_at as \"created_at!: time::OffsetDateTime\",
updated_at as \"updated_at!: time::OffsetDateTime\",
published_at as \"published_at: time::OffsetDateTime\"
from agents
where workspace_id = $1 and id = $2",
workspace_id.as_str(),
@@ -117,9 +117,9 @@ impl PostgresRegistry {
.bind(serialize_enum_text(&request.agent.status, "status")?)
.bind(to_db_version(request.agent.current_draft_version))
.bind(request.agent.latest_published_version.map(to_db_version))
.bind(&request.agent.created_at)
.bind(&request.agent.updated_at)
.bind(request.agent.published_at.as_deref())
.bind(request.agent.created_at)
.bind(request.agent.updated_at)
.bind(request.agent.published_at)
.execute(&mut *tx)
.await?;
@@ -154,7 +154,7 @@ impl PostgresRegistry {
status,
instructions_json,
tool_selection_policy_json,
to_char(created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"created_at!\"
created_at as \"created_at!: time::OffsetDateTime\"
from agent_versions
where agent_id = $1 and version = $2",
agent_id.as_str(),
@@ -212,7 +212,7 @@ impl PostgresRegistry {
slug: &str,
display_name: &str,
description: &str,
updated_at: &str,
updated_at: &time::OffsetDateTime,
) -> Result<(), RegistryError> {
let result = sqlx::query(
"update agents
@@ -331,7 +331,7 @@ impl PostgresRegistry {
&self,
workspace_id: &WorkspaceId,
agent_id: &AgentId,
updated_at: &str,
updated_at: &time::OffsetDateTime,
) -> Result<(), RegistryError> {
let mut tx = self.pool.begin().await?;
@@ -384,7 +384,7 @@ impl PostgresRegistry {
&self,
workspace_id: &WorkspaceId,
agent_id: &AgentId,
updated_at: &str,
updated_at: &time::OffsetDateTime,
) -> Result<(), RegistryError> {
let mut tx = self.pool.begin().await?;
+11 -11
View File
@@ -414,7 +414,7 @@ async fn insert_agent_version_row(
.bind(serialize_enum_text(&version.status, "status")?)
.bind(Json(version.instructions.clone()))
.bind(Json(version.tool_selection_policy.clone()))
.bind(&version.created_at)
.bind(version.created_at)
.execute(&mut **tx)
.await?;
@@ -684,9 +684,9 @@ fn build_agent_summary(
status: String,
current_draft_version: i32,
latest_published_version: Option<i32>,
created_at: String,
updated_at: String,
published_at: Option<String>,
created_at: OffsetDateTime,
updated_at: OffsetDateTime,
published_at: Option<OffsetDateTime>,
) -> Result<AgentSummary, RegistryError> {
Ok(AgentSummary {
id: AgentId::new(id),
@@ -798,7 +798,7 @@ fn build_agent_version_record(
status: String,
instructions_json: Value,
tool_selection_policy_json: Value,
created_at: String,
created_at: OffsetDateTime,
bindings: Vec<AgentOperationBinding>,
) -> Result<AgentVersionRecord, RegistryError> {
let version = from_db_version(version, "version")?;
@@ -809,7 +809,7 @@ fn build_agent_version_record(
workspace_id: summary.workspace_id.clone(),
version,
status,
created_at: created_at.clone(),
created_at,
bindings,
snapshot: AgentVersion {
agent_id: summary.id.clone(),
@@ -1842,7 +1842,7 @@ mod tests {
workspace_id: &test_workspace_id(),
agent_id: &agent.id,
version: version.version,
published_at: "2026-03-25T12:11:00Z",
published_at: &timestamp("2026-03-25T12:11:00Z"),
published_by: Some("alice"),
})
.await
@@ -1922,7 +1922,7 @@ mod tests {
workspace_id: &test_workspace_id(),
agent_id: &agent.id,
version: version.version,
published_at: "2026-03-25T12:11:00Z",
published_at: &timestamp("2026-03-25T12:11:00Z"),
published_by: Some("alice"),
})
.await
@@ -2449,8 +2449,8 @@ mod tests {
status,
current_draft_version: 1,
latest_published_version: None,
created_at: "2026-03-25T11:58:00Z".to_owned(),
updated_at: "2026-03-25T12:00:00Z".to_owned(),
created_at: timestamp("2026-03-25T11:58:00Z"),
updated_at: timestamp("2026-03-25T12:00:00Z"),
published_at: None,
}
}
@@ -2468,7 +2468,7 @@ mod tests {
"mode": "allow_list",
"max_tools": 8
}),
created_at: "2026-03-25T12:00:00Z".to_owned(),
created_at: timestamp("2026-03-25T12:00:00Z"),
}
}