use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate::{context::RequestContext, idempotency::RetryMetadata};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Envelope<T> {
pub ok: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub request_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub context: Option<RequestContext>,
pub trace_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub data: Option<T>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub error: Option<WarmplaneError>,
pub retry: RetryMetadata,
}
impl<T> Envelope<T> {
pub fn success(
trace_id: String,
request_id: Option<String>,
context: Option<RequestContext>,
data: T,
retry: RetryMetadata,
) -> Self {
Self {
ok: true,
request_id,
context,
trace_id,
data: Some(data),
error: None,
retry,
}
}
pub fn failure(
trace_id: String,
request_id: Option<String>,
context: Option<RequestContext>,
error: WarmplaneError,
retry: RetryMetadata,
) -> Self {
Self {
ok: false,
request_id,
context,
trace_id,
data: None,
error: Some(error),
retry,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct WarmplaneError {
pub code: String,
pub message: String,
pub retryable: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub operator: Option<String>,
}
impl WarmplaneError {
pub fn new(code: impl Into<String>, message: impl Into<String>, retryable: bool) -> Self {
Self {
code: code.into(),
message: message.into(),
retryable,
operator: None,
}
}
pub fn operator_rejected(operator: impl Into<String>, reason: Option<String>) -> Self {
let op = operator.into();
let reason_str = reason.map(|r| format!(": {}", r)).unwrap_or_default();
Self {
code: "OPERATION_REJECTED_BY_OPERATOR".to_string(),
message: format!("Human operator rejected execution{}", reason_str),
retryable: false,
operator: Some(op),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CapabilitySummary {
pub id: String,
pub summary: String,
pub server: String,
pub tool: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub tags: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CapabilityDetail {
pub id: String,
pub server: String,
pub tool: String,
pub description: String,
pub input_schema: Value,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub examples: Vec<Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CapabilitiesListResponse {
pub version: String,
pub capabilities: Vec<CapabilitySummary>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CapabilitySearchResponse {
pub version: String,
pub catalog_version: String,
pub query: String,
pub total: usize,
pub capabilities: Vec<crate::search::hybrid::CapabilitySearchResult>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CapabilityDescribeResponse {
pub version: String,
pub capability: CapabilityDetail,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ResourceSummary {
pub id: String,
pub server: String,
pub uri: String,
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub mime_type: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub tags: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ResourcesListResponse {
pub version: String,
pub resources: Vec<ResourceSummary>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct PromptSummary {
pub id: String,
pub server: String,
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub arguments: Vec<Value>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub tags: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct PromptsListResponse {
pub version: String,
pub prompts: Vec<PromptSummary>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct EngineHealthStatus {
pub catalog_version: String,
pub server_statuses: std::collections::HashMap<String, Value>,
pub circuit_breakers: std::collections::HashMap<String, crate::circuit_breaker::CircuitState>,
pub total_tool_calls: u64,
pub total_tool_duration_us: u64,
}
#[derive(Debug, Clone, Default)]
pub struct ExecutionOptions {
pub request_id: Option<String>,
pub context: Option<RequestContext>,
pub idempotency_key: Option<String>,
pub input_responses: Option<std::collections::BTreeMap<String, Value>>,
pub request_state: Option<String>,
pub profile: Option<String>,
}
impl ExecutionOptions {
pub fn new() -> Self {
Self::default()
}
pub fn with_request_id(mut self, id: impl Into<String>) -> Self {
self.request_id = Some(id.into());
self
}
pub fn with_profile(mut self, profile: impl Into<String>) -> Self {
self.profile = Some(profile.into());
self
}
pub fn with_idempotency_key(mut self, key: impl Into<String>) -> Self {
self.idempotency_key = Some(key.into());
self
}
}
#[derive(Debug, Clone, Default)]
pub struct ReadResourceOptions {
pub request_id: Option<String>,
pub context: Option<RequestContext>,
pub input_responses: Option<std::collections::BTreeMap<String, Value>>,
pub request_state: Option<String>,
pub profile: Option<String>,
}
#[derive(Debug, Clone, Default)]
pub struct GetPromptOptions {
pub request_id: Option<String>,
pub context: Option<RequestContext>,
pub arguments: Option<Value>,
pub input_responses: Option<std::collections::BTreeMap<String, Value>>,
pub request_state: Option<String>,
pub profile: Option<String>,
}