synth_ai_core/orchestration/
schemas.rs1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3use std::collections::HashMap;
4
5pub use super::progress::{SeedInfo, StageInfo, TokenUsage};
6
7pub const MAX_INSTRUCTION_LENGTH: usize = 4000;
8pub const MAX_ROLLOUT_SAMPLES: usize = 5;
9pub const MAX_SEED_INFO_COUNT: usize = 50;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct MutationTypeStats {
13 pub attempts: i64,
14 pub acceptances: i64,
15 pub acceptance_rate: f64,
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct MutationSummary {
20 pub by_mutation_type: HashMap<String, MutationTypeStats>,
21 pub total_attempts: i64,
22 pub total_acceptances: i64,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct SeedAnalysis {
27 pub hard_seeds: Vec<i64>,
28 pub easy_seeds: Vec<i64>,
29 pub baseline_failures: Vec<i64>,
30 pub total_seeds_evaluated: i64,
31 pub total_candidates: i64,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct PhaseSummary {
36 pub phase: String,
37 #[serde(default)]
38 pub duration_seconds: Option<f64>,
39 #[serde(default)]
40 pub rollouts_completed: Option<i64>,
41 #[serde(default)]
42 pub candidates_evaluated: Option<i64>,
43 #[serde(default)]
44 #[serde(alias = "best_score")]
45 pub best_reward: Option<f64>,
46 #[serde(default)]
47 pub extra: HashMap<String, Value>,
48}
49
50fn default_mutation_type() -> String {
51 "unknown".to_string()
52}
53
54fn default_status() -> String {
55 "evaluated".to_string()
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct ProgramCandidate {
60 pub candidate_id: String,
61 pub generation: i64,
62 #[serde(default)]
63 pub stages: HashMap<String, StageInfo>,
64 #[serde(default)]
65 pub parent_id: Option<String>,
66 #[serde(default = "default_mutation_type")]
67 pub mutation_type: String,
68 #[serde(default)]
69 pub mutation_params: Option<Value>,
70 #[serde(default, alias = "accuracy")]
71 pub reward: f64,
72 #[serde(default, alias = "val_accuracy")]
73 pub val_reward: Option<f64>,
74 #[serde(default, alias = "minibatch_score")]
75 pub minibatch_reward: Option<f64>,
76 #[serde(default, alias = "seed_scores")]
77 pub seed_rewards: Option<Vec<Value>>,
78 #[serde(default)]
79 pub seed_info: Option<Vec<SeedInfo>>,
80 #[serde(default, alias = "instance_scores")]
81 pub instance_rewards: Option<Vec<Value>>,
82 #[serde(default)]
83 pub objectives: Option<Value>,
84 #[serde(default)]
85 pub instance_objectives: Option<Value>,
86 #[serde(default)]
87 pub newly_solved_seeds: Option<Vec<i64>>,
88 #[serde(default)]
89 pub artifact_refs: Option<Vec<Value>>,
90 #[serde(default)]
91 pub success_statuses: Option<Vec<Value>>,
92 #[serde(default)]
93 pub token_usage: Option<TokenUsage>,
94 #[serde(default)]
95 pub cost_usd: Option<f64>,
96 #[serde(default)]
97 pub timestamp_ms: Option<i64>,
98 #[serde(default)]
99 pub evaluation_duration_ms: Option<i64>,
100 #[serde(default)]
101 pub transformation: Option<Value>,
102 #[serde(default)]
103 pub prompt_length: Option<i64>,
104 #[serde(default = "default_status")]
105 pub status: String,
106 #[serde(default)]
107 pub context_override_bundle_id: Option<String>,
108 #[serde(default)]
109 pub context_overrides: Option<Vec<Value>>,
110 #[serde(default)]
111 pub override_application_status: Option<String>,
112 #[serde(default)]
113 pub override_application_errors: Option<Vec<Value>>,
114 #[serde(default)]
115 pub context_snapshot_ref: Option<String>,
116}
117
118impl ProgramCandidate {
119 pub fn prompt_summary(&self, max_length: usize) -> String {
120 if self.stages.is_empty() {
121 return String::new();
122 }
123
124 let mut keys: Vec<&String> = self.stages.keys().collect();
125 keys.sort();
126
127 let mut parts: Vec<String> = Vec::new();
128 for key in keys {
129 if let Some(stage) = self.stages.get(key) {
130 let mut instruction = stage.instruction.clone();
131 if instruction.len() > MAX_INSTRUCTION_LENGTH {
132 instruction.truncate(MAX_INSTRUCTION_LENGTH);
133 instruction.push_str("...");
134 }
135 if !instruction.is_empty() {
136 parts.push(format!("[{}]: {}", key.to_uppercase(), instruction));
137 }
138 }
139 }
140
141 let mut summary = parts.join("\n\n");
142 if summary.len() > max_length {
143 summary.truncate(max_length);
144 summary.push_str("...");
145 }
146 summary
147 }
148}