use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use starweaver_context::ResumableState;
use starweaver_core::{CheckpointId, ConversationId, Metadata, RunId, SessionId, TraceContext};
use crate::input::InputPart;
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum SessionStatus {
#[default]
Active,
Archived,
Failed,
}
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum RunStatus {
#[default]
Queued,
Running,
Waiting,
Completed,
Failed,
Cancelled,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum ExecutionStatus {
Pending,
Running,
Waiting,
Completed,
Failed,
Cancelled,
}
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct EnvironmentStateRef {
pub provider: String,
pub reference: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub revision: Option<String>,
#[serde(default, skip_serializing_if = "Metadata::is_empty")]
pub metadata: Metadata,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct CheckpointRef {
pub checkpoint_id: CheckpointId,
pub run_id: RunId,
pub sequence: usize,
pub node: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub storage_ref: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub stream_cursor: Option<usize>,
pub created_at: DateTime<Utc>,
#[serde(default, skip_serializing_if = "Metadata::is_empty")]
pub metadata: Metadata,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct StreamCursorRef {
pub family: String,
pub scope: String,
pub sequence: usize,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
pub created_at: DateTime<Utc>,
#[serde(default, skip_serializing_if = "Metadata::is_empty")]
pub metadata: Metadata,
}
impl StreamCursorRef {
#[must_use]
pub fn new(family: impl Into<String>, scope: impl Into<String>, sequence: usize) -> Self {
Self {
family: family.into(),
scope: scope.into(),
sequence,
cursor: None,
created_at: Utc::now(),
metadata: Metadata::default(),
}
}
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct SessionRecord {
pub session_id: SessionId,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub workspace: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub profile: Option<String>,
#[serde(default)]
pub status: SessionStatus,
#[serde(default)]
pub state: ResumableState,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub environment_state: Option<EnvironmentStateRef>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub stream_cursors: Vec<StreamCursorRef>,
#[serde(default, skip_serializing_if = "TraceContext::is_empty")]
pub trace_context: TraceContext,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub parent_session_id: Option<SessionId>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub head_run_id: Option<RunId>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub head_success_run_id: Option<RunId>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub active_run_id: Option<RunId>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
#[serde(default, skip_serializing_if = "Metadata::is_empty")]
pub metadata: Metadata,
}
impl SessionRecord {
#[must_use]
pub fn new(session_id: SessionId) -> Self {
let now = Utc::now();
Self {
session_id,
title: None,
workspace: None,
profile: None,
status: SessionStatus::Active,
state: ResumableState::default(),
environment_state: None,
stream_cursors: Vec::new(),
trace_context: TraceContext::default(),
parent_session_id: None,
head_run_id: None,
head_success_run_id: None,
active_run_id: None,
created_at: now,
updated_at: now,
metadata: Metadata::default(),
}
}
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct RunRecord {
pub session_id: SessionId,
pub run_id: RunId,
pub conversation_id: ConversationId,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub input: Vec<InputPart>,
#[serde(default)]
pub status: RunStatus,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub output_preview: Option<String>,
#[serde(default, skip_serializing_if = "Value::is_null")]
pub structured_output: Value,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub latest_checkpoint: Option<CheckpointRef>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub environment_state: Option<EnvironmentStateRef>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub stream_cursors: Vec<StreamCursorRef>,
#[serde(default, skip_serializing_if = "TraceContext::is_empty")]
pub trace_context: TraceContext,
#[serde(default)]
pub sequence_no: usize,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub restore_from_run_id: Option<RunId>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub trigger_type: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub profile: Option<String>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
#[serde(default, skip_serializing_if = "Metadata::is_empty")]
pub metadata: Metadata,
}
impl RunRecord {
#[must_use]
pub fn new(session_id: SessionId, run_id: RunId, conversation_id: ConversationId) -> Self {
let now = Utc::now();
Self {
session_id,
run_id,
conversation_id,
input: Vec::new(),
status: RunStatus::Queued,
output_preview: None,
structured_output: Value::Null,
latest_checkpoint: None,
environment_state: None,
stream_cursors: Vec::new(),
trace_context: TraceContext::default(),
sequence_no: 0,
restore_from_run_id: None,
trigger_type: None,
profile: None,
created_at: now,
updated_at: now,
metadata: Metadata::default(),
}
}
}