use serde::{Deserialize, Serialize};
use super::helpers::now_millis;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiError {
pub code: String,
pub message: String,
}
impl ApiError {
pub fn new(code: impl Into<String>, message: impl Into<String>) -> Self {
Self {
code: code.into(),
message: message.into(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RuntimeRecord {
pub runtime_id: String,
pub display_name: String,
pub codex_home: Option<String>,
pub codex_binary: String,
pub is_primary: bool,
pub auto_start: bool,
pub created_at_ms: i64,
pub updated_at_ms: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AppServerHandshakeSummary {
pub state: String,
pub protocol: String,
pub transport: String,
pub experimental_api_enabled: bool,
pub notification_mode: String,
#[serde(default)]
pub opt_out_notification_methods: Vec<String>,
pub detail: Option<String>,
pub updated_at_ms: i64,
}
impl Default for AppServerHandshakeSummary {
fn default() -> Self {
Self::inactive()
}
}
impl AppServerHandshakeSummary {
pub fn new(
state: impl Into<String>,
experimental_api_enabled: bool,
opt_out_notification_methods: Vec<String>,
detail: Option<String>,
) -> Self {
let notification_mode = if opt_out_notification_methods.is_empty() {
"full".to_string()
} else {
"optimized".to_string()
};
Self {
state: state.into(),
protocol: "jsonrpc2.0".to_string(),
transport: "stdio".to_string(),
experimental_api_enabled,
notification_mode,
opt_out_notification_methods,
detail,
updated_at_ms: now_millis(),
}
}
pub fn inactive() -> Self {
Self::new("inactive", false, Vec::new(), None)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RuntimeStatusSnapshot {
pub runtime_id: String,
pub status: String,
pub codex_home: Option<String>,
pub user_agent: Option<String>,
pub platform_family: Option<String>,
pub platform_os: Option<String>,
pub last_error: Option<String>,
pub pid: Option<u32>,
#[serde(default)]
pub app_server_handshake: AppServerHandshakeSummary,
pub updated_at_ms: i64,
}
impl RuntimeStatusSnapshot {
pub fn stopped(runtime_id: impl Into<String>) -> Self {
Self {
runtime_id: runtime_id.into(),
status: "stopped".to_string(),
codex_home: None,
user_agent: None,
platform_family: None,
platform_os: None,
last_error: None,
pid: None,
app_server_handshake: AppServerHandshakeSummary::inactive(),
updated_at_ms: now_millis(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RuntimeSummary {
pub runtime_id: String,
pub display_name: String,
pub codex_home: Option<String>,
pub codex_binary: String,
pub is_primary: bool,
pub auto_start: bool,
pub created_at_ms: i64,
pub updated_at_ms: i64,
pub status: RuntimeStatusSnapshot,
}
impl RuntimeSummary {
pub fn from_parts(record: &RuntimeRecord, status: RuntimeStatusSnapshot) -> Self {
Self {
runtime_id: record.runtime_id.clone(),
display_name: record.display_name.clone(),
codex_home: record.codex_home.clone(),
codex_binary: record.codex_binary.clone(),
is_primary: record.is_primary,
auto_start: record.auto_start,
created_at_ms: record.created_at_ms,
updated_at_ms: record.updated_at_ms,
status,
}
}
}