use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct OlConfig {
#[serde(alias = "id")]
pub id: String,
#[serde(alias = "name")]
pub name: String,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "description"
)]
pub description: Option<String>,
#[serde(alias = "is_favorite")]
pub is_favorite: bool,
#[serde(alias = "config_json")]
pub config_json: serde_json::Value,
#[serde(alias = "created_at")]
pub created_at: String,
#[serde(alias = "updated_at")]
pub updated_at: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct CreateOlConfigRequest {
#[serde(alias = "name")]
pub name: String,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "description"
)]
pub description: Option<String>,
#[serde(alias = "config_json")]
pub config_json: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct UpdateOlConfigRequest {
#[serde(default, skip_serializing_if = "Option::is_none", alias = "name")]
pub name: Option<String>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "description"
)]
pub description: Option<String>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "is_favorite"
)]
pub is_favorite: Option<bool>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "config_json"
)]
pub config_json: Option<serde_json::Value>,
}
pub type LoopId = String;
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct StallDetectorConfig {
#[serde(alias = "max_repeated_actions")]
pub max_repeated_actions: u32,
#[serde(alias = "max_total_steps")]
pub max_total_steps: u32,
#[serde(alias = "stall_timeout_secs")]
pub stall_timeout_secs: u64,
#[serde(alias = "oscillation_window")]
pub oscillation_window: u32,
}
impl Default for StallDetectorConfig {
fn default() -> Self {
Self {
max_repeated_actions: 5,
max_total_steps: 100,
stall_timeout_secs: 300,
oscillation_window: 10,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct SummarizationConfig {
#[serde(alias = "enabled")]
pub enabled: bool,
#[serde(alias = "token_threshold_pct")]
pub token_threshold_pct: f32,
#[serde(alias = "max_tokens_budget")]
pub max_tokens_budget: usize,
#[serde(alias = "preserve_last_n_iterations")]
pub preserve_last_n_iterations: u32,
#[serde(alias = "summary_max_tokens")]
pub summary_max_tokens: usize,
}
impl Default for SummarizationConfig {
fn default() -> Self {
Self {
enabled: true,
token_threshold_pct: 0.75,
max_tokens_budget: 80000,
preserve_last_n_iterations: 2,
summary_max_tokens: 2000,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct DecomposerConfig {
#[serde(alias = "enabled")]
pub enabled: bool,
#[serde(alias = "min_subtasks")]
pub min_subtasks: u32,
#[serde(alias = "max_subtasks")]
pub max_subtasks: u32,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "model_override"
)]
pub model_override: Option<String>,
}
impl Default for DecomposerConfig {
fn default() -> Self {
Self {
enabled: true,
min_subtasks: 3,
max_subtasks: 7,
model_override: None,
}
}
}
fn default_supervisor_port() -> u16 {
9875
}
fn default_wait_for_fixer() -> bool {
true
}
fn default_capture_snapshot() -> bool {
true
}
fn default_snapshot_max_chars() -> usize {
8000
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct OrchestrationLoopConfig {
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "target_runner_port"
)]
pub target_runner_port: Option<u16>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "target_runner_id"
)]
pub target_runner_id: Option<String>,
#[serde(default = "default_supervisor_port", alias = "supervisor_port")]
pub supervisor_port: u16,
#[serde(default, alias = "workflow_id")]
pub workflow_id: String,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "max_iterations"
)]
pub max_iterations: Option<u32>,
#[serde(default, alias = "exit_strategy")]
pub exit_strategy: ExitStrategy,
#[serde(default, alias = "between_iterations")]
pub between_iterations: BetweenIterations,
#[serde(default, alias = "retry_on_failure")]
pub retry_on_failure: bool,
#[serde(default = "default_wait_for_fixer", alias = "wait_for_fixer")]
pub wait_for_fixer: bool,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "pipeline")]
pub pipeline: Option<PipelineConfig>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "stall_detection"
)]
pub stall_detection: Option<StallDetectorConfig>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "summarization"
)]
pub summarization: Option<SummarizationConfig>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "decomposition"
)]
pub decomposition: Option<DecomposerConfig>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct PipelineConfig {
#[serde(default, skip_serializing_if = "Option::is_none", alias = "build")]
pub build: Option<BuildPhaseConfig>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "implement_fixes"
)]
pub implement_fixes: Option<ImplementFixesConfig>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "diagnose")]
pub diagnose: Option<DiagnosePhaseConfig>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct BuildPhaseConfig {
#[serde(alias = "description")]
pub description: String,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "context")]
pub context: Option<String>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "context_ids"
)]
pub context_ids: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct ImplementFixesConfig {
#[serde(default, skip_serializing_if = "Option::is_none", alias = "model")]
pub model: Option<String>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "timeout_secs"
)]
pub timeout_secs: Option<u64>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "additional_context"
)]
pub additional_context: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct DiagnosePhaseConfig {
#[serde(default, skip_serializing_if = "Vec::is_empty", alias = "assertions")]
pub assertions: Vec<serde_json::Value>,
#[serde(default = "default_capture_snapshot", alias = "capture_snapshot")]
pub capture_snapshot: bool,
#[serde(default = "default_snapshot_max_chars", alias = "snapshot_max_chars")]
pub snapshot_max_chars: usize,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "model_override"
)]
pub model_override: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum RootCauseCategory {
BadUiRendering,
BadUiBridgeEvaluation,
BadVerificationSteps,
BadGenerationPrompt,
BadStateMachineLogic,
InfrastructureIssue,
Unknown,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct DiagnosticResult {
#[serde(alias = "passed")]
pub passed: bool,
#[serde(alias = "page_health")]
pub page_health: serde_json::Value,
#[serde(alias = "assertion_results")]
pub assertion_results: Vec<serde_json::Value>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "root_cause")]
pub root_cause: Option<RootCauseCategory>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "diagnosis")]
pub diagnosis: Option<String>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "prompt_rewrite_suggestion"
)]
pub prompt_rewrite_suggestion: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default, PartialEq, Eq)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ExitStrategy {
#[default]
Reflection,
WorkflowVerification,
FixedIterations,
DiagnosticEvaluation,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default, PartialEq, Eq)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum BetweenIterations {
RestartRunner {
#[serde(default)]
rebuild: bool,
},
RestartOnSignal {
#[serde(default)]
rebuild: bool,
},
WaitHealthy,
#[default]
None,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum LoopPhase {
#[default]
Idle,
BuildingWorkflow,
RunningWorkflow,
Diagnosing,
Reflecting,
ImplementingFixes,
EvaluatingExit,
WaitingForFixer,
BetweenIterations,
WaitingForRunner,
StallDetecting,
Planning,
DispatchingWorker,
Reconciling,
Elaborating,
Complete,
Stopped,
Error,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct OrchestrationLoopStatus {
#[serde(alias = "running")]
pub running: bool,
#[serde(alias = "phase")]
pub phase: LoopPhase,
#[serde(alias = "current_iteration")]
pub current_iteration: u32,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "max_iterations"
)]
pub max_iterations: Option<u32>,
#[serde(alias = "workflow_id")]
pub workflow_id: String,
#[serde(alias = "target_runner_port")]
pub target_runner_port: u16,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "target_runner_id"
)]
pub target_runner_id: Option<String>,
#[serde(alias = "is_pipeline")]
pub is_pipeline: bool,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "started_at")]
pub started_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "error")]
pub error: Option<String>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
alias = "iteration_results"
)]
pub iteration_results: Vec<IterationResult>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct IterationResult {
#[serde(alias = "iteration")]
pub iteration: u32,
#[serde(alias = "started_at")]
pub started_at: String,
#[serde(alias = "completed_at")]
pub completed_at: String,
#[serde(alias = "task_run_id")]
pub task_run_id: String,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "reflection_task_run_id"
)]
pub reflection_task_run_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "fix_count")]
pub fix_count: Option<u32>,
#[serde(alias = "exit_check")]
pub exit_check: ExitCheckResult,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "generated_workflow_id"
)]
pub generated_workflow_id: Option<String>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "fixes_implemented"
)]
pub fixes_implemented: Option<bool>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "rebuild_triggered"
)]
pub rebuild_triggered: Option<bool>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "stall_detected"
)]
pub stall_detected: Option<String>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "context_summarized"
)]
pub context_summarized: Option<bool>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "diagnostic_result"
)]
pub diagnostic_result: Option<DiagnosticResult>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct ExitCheckResult {
#[serde(alias = "should_exit")]
pub should_exit: bool,
#[serde(alias = "reason")]
pub reason: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct MultiLoopConfig {
#[serde(alias = "loops")]
pub loops: Vec<MultiLoopEntry>,
#[serde(default, alias = "stop_all_on_error")]
pub stop_all_on_error: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct MultiLoopEntry {
#[serde(alias = "loop_id")]
pub loop_id: LoopId,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "label")]
pub label: Option<String>,
#[serde(alias = "config")]
pub config: OrchestrationLoopConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct MultiLoopStatus {
#[serde(alias = "loops")]
pub loops: Vec<LoopInstanceStatus>,
#[serde(alias = "all_complete")]
pub all_complete: bool,
#[serde(alias = "any_error")]
pub any_error: bool,
#[serde(alias = "stop_all_on_error")]
pub stop_all_on_error: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct LoopInstanceStatus {
#[serde(alias = "loop_id")]
pub loop_id: LoopId,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "label")]
pub label: Option<String>,
#[serde(alias = "status")]
pub status: OrchestrationLoopStatus,
}