use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use crate::client::Client;
use crate::error::Result;
#[derive(Debug, Clone, Serialize, Default)]
pub struct MissionCreateRequest {
pub goal: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub strategy: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub conductor_model: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub conductor_tier: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub workers: Option<HashMap<String, MissionWorkerConfig>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_steps: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub system_prompt: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub session_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct MissionWorkerConfig {
pub model: String,
#[serde(default)]
pub tier: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub escalate_to: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_retries: Option<i32>,
}
#[derive(Debug, Clone, Serialize)]
pub struct MissionChatRequest {
pub message: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub stream: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct MissionPlanUpdate {
#[serde(skip_serializing_if = "Option::is_none")]
pub tasks: Option<Vec<HashMap<String, serde_json::Value>>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub workers: Option<HashMap<String, MissionWorkerConfig>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub system_prompt: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_steps: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub context: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct MissionConfirmStructure {
pub confirmed: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub feedback: Option<String>,
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct MissionApproveRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub commit_sha: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub comment: Option<String>,
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct MissionImportRequest {
pub goal: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub strategy: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub conductor_model: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub workers: Option<HashMap<String, MissionWorkerConfig>>,
#[serde(default)]
pub tasks: Vec<HashMap<String, serde_json::Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub system_prompt: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_steps: Option<i32>,
#[serde(default)]
pub auto_execute: bool,
}
#[derive(Debug, Clone, Deserialize)]
pub struct MissionCreateResponse {
pub mission_id: String,
#[serde(default)]
pub status: String,
#[serde(default)]
pub session_id: Option<String>,
#[serde(default)]
pub conductor_model: Option<String>,
#[serde(default)]
pub strategy: Option<String>,
#[serde(default)]
pub workers: Option<HashMap<String, MissionWorkerConfig>>,
#[serde(default)]
pub created_at: Option<String>,
#[serde(default)]
pub request_id: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct MissionDetail {
#[serde(default)]
pub id: Option<String>,
#[serde(default)]
pub user_id: Option<String>,
#[serde(default)]
pub goal: Option<String>,
#[serde(default)]
pub strategy: Option<String>,
#[serde(default)]
pub conductor_model: Option<String>,
#[serde(default)]
pub status: Option<String>,
#[serde(default)]
pub created_at: Option<String>,
#[serde(default)]
pub started_at: Option<String>,
#[serde(default)]
pub completed_at: Option<String>,
#[serde(default)]
pub error: Option<String>,
#[serde(default)]
pub cost_ticks: i64,
#[serde(default)]
pub total_steps: i32,
#[serde(default)]
pub session_id: Option<String>,
#[serde(default)]
pub result: Option<String>,
#[serde(default)]
pub tasks: Vec<MissionTask>,
#[serde(default)]
pub approved: bool,
#[serde(default)]
pub commit_sha: Option<String>,
}
#[derive(Debug, Clone, Deserialize, Default)]
pub struct MissionTask {
#[serde(default)]
pub id: Option<String>,
#[serde(default)]
pub name: Option<String>,
#[serde(default)]
pub description: Option<String>,
#[serde(default)]
pub worker: Option<String>,
#[serde(default)]
pub model: Option<String>,
#[serde(default)]
pub status: Option<String>,
#[serde(default)]
pub result: Option<String>,
#[serde(default)]
pub error: Option<String>,
#[serde(default)]
pub step: i32,
#[serde(default)]
pub tokens_in: i32,
#[serde(default)]
pub tokens_out: i32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct MissionListResponse {
#[serde(default)]
pub missions: Vec<MissionDetail>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct MissionChatResponse {
#[serde(default)]
pub mission_id: Option<String>,
#[serde(default)]
pub content: Option<String>,
#[serde(default)]
pub model: Option<String>,
#[serde(default)]
pub cost_ticks: i64,
#[serde(default)]
pub usage: Option<MissionChatUsage>,
}
#[derive(Debug, Clone, Deserialize, Default)]
pub struct MissionChatUsage {
#[serde(default)]
pub input_tokens: i32,
#[serde(default)]
pub output_tokens: i32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct MissionCheckpoint {
#[serde(default)]
pub id: Option<String>,
#[serde(default)]
pub commit_sha: Option<String>,
#[serde(default)]
pub message: Option<String>,
#[serde(default)]
pub created_at: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct MissionCheckpointsResponse {
#[serde(default)]
pub mission_id: Option<String>,
#[serde(default)]
pub checkpoints: Vec<MissionCheckpoint>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct MissionStatusResponse {
#[serde(default)]
pub mission_id: Option<String>,
#[serde(default)]
pub status: Option<String>,
#[serde(default)]
pub confirmed: Option<bool>,
#[serde(default)]
pub approved: Option<bool>,
#[serde(default)]
pub deleted: Option<bool>,
#[serde(default)]
pub updated: Option<bool>,
#[serde(default)]
pub commit_sha: Option<String>,
}
impl Client {
pub async fn mission_create(&self, req: &MissionCreateRequest) -> Result<MissionCreateResponse> {
let (resp, _) = self.post_json("/qai/v1/missions/create", req).await?;
Ok(resp)
}
pub async fn mission_list(&self, status: Option<&str>) -> Result<MissionListResponse> {
let path = match status {
Some(s) => format!("/qai/v1/missions/list?status={}", s),
None => "/qai/v1/missions/list".into(),
};
let (resp, _) = self.get_json(&path).await?;
Ok(resp)
}
pub async fn mission_get(&self, mission_id: &str) -> Result<MissionDetail> {
let (resp, _) = self.get_json(&format!("/qai/v1/missions/{}", mission_id)).await?;
Ok(resp)
}
pub async fn mission_delete(&self, mission_id: &str) -> Result<MissionStatusResponse> {
let (resp, _) = self.delete_json(&format!("/qai/v1/missions/{}", mission_id)).await?;
Ok(resp)
}
pub async fn mission_cancel(&self, mission_id: &str) -> Result<MissionStatusResponse> {
let (resp, _) = self.post_json_empty(&format!("/qai/v1/missions/{}/cancel", mission_id)).await?;
Ok(resp)
}
pub async fn mission_pause(&self, mission_id: &str) -> Result<MissionStatusResponse> {
let (resp, _) = self.post_json_empty(&format!("/qai/v1/missions/{}/pause", mission_id)).await?;
Ok(resp)
}
pub async fn mission_resume(&self, mission_id: &str) -> Result<MissionStatusResponse> {
let (resp, _) = self.post_json_empty(&format!("/qai/v1/missions/{}/resume", mission_id)).await?;
Ok(resp)
}
pub async fn mission_chat(&self, mission_id: &str, req: &MissionChatRequest) -> Result<MissionChatResponse> {
let (resp, _) = self.post_json(&format!("/qai/v1/missions/{}/chat", mission_id), req).await?;
Ok(resp)
}
pub async fn mission_retry_task(&self, mission_id: &str, task_id: &str) -> Result<MissionStatusResponse> {
let (resp, _) = self.post_json_empty(&format!("/qai/v1/missions/{}/retry/{}", mission_id, task_id)).await?;
Ok(resp)
}
pub async fn mission_approve(&self, mission_id: &str, req: &MissionApproveRequest) -> Result<MissionStatusResponse> {
let (resp, _) = self.post_json(&format!("/qai/v1/missions/{}/approve", mission_id), req).await?;
Ok(resp)
}
pub async fn mission_update_plan(&self, mission_id: &str, req: &MissionPlanUpdate) -> Result<MissionStatusResponse> {
let (resp, _) = self.put_json(&format!("/qai/v1/missions/{}/plan", mission_id), req).await?;
Ok(resp)
}
pub async fn mission_confirm_structure(&self, mission_id: &str, req: &MissionConfirmStructure) -> Result<MissionStatusResponse> {
let (resp, _) = self.post_json(&format!("/qai/v1/missions/{}/confirm-structure", mission_id), req).await?;
Ok(resp)
}
pub async fn mission_checkpoints(&self, mission_id: &str) -> Result<MissionCheckpointsResponse> {
let (resp, _) = self.get_json(&format!("/qai/v1/missions/{}/checkpoints", mission_id)).await?;
Ok(resp)
}
pub async fn mission_import(&self, req: &MissionImportRequest) -> Result<MissionCreateResponse> {
let (resp, _) = self.post_json("/qai/v1/missions/import", req).await?;
Ok(resp)
}
}