1use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4
5pub use akribes_types::ast::{TypeField, TypeRef};
8
9#[derive(Serialize, Deserialize, Clone, Debug)]
12pub struct Project {
13 pub id: i64,
14 pub name: String,
15 pub created_at: String,
16}
17
18#[derive(Serialize, Deserialize, Clone, Debug)]
19pub struct Script {
20 pub id: i64,
21 pub project_id: i64,
22 pub name: String,
23 pub created_at: String,
24}
25
26#[derive(Serialize, Deserialize, Clone, Debug)]
27pub struct ScriptVersion {
28 pub id: i64,
29 pub script_id: i64,
30 pub source: String,
31 pub label: Option<String>,
32 pub published_by: Option<String>,
33 pub created_at: String,
34}
35
36#[derive(Deserialize, Clone, Debug)]
38pub(crate) struct PublishResponse {
39 pub version: ScriptVersion,
40 #[serde(default)]
48 pub rebased: Option<Vec<RebaseEntry>>,
49}
50
51#[derive(Serialize, Deserialize, Clone, Debug)]
53pub struct RebaseEntry {
54 pub kind: String,
55 pub count: usize,
56}
57
58#[derive(Clone, Debug)]
63pub struct PublishOutcome {
64 pub version: ScriptVersion,
65 pub rebased: Option<Vec<RebaseEntry>>,
66}
67
68#[derive(Serialize, Deserialize, Clone, Debug)]
69pub struct ScriptChannel {
70 pub id: i64,
71 pub script_id: i64,
72 pub name: String,
73 pub version_id: Option<i64>,
74 pub updated_at: Option<String>,
75}
76
77#[derive(Serialize, Deserialize, Clone, Debug)]
85pub struct Draft {
86 pub source: String,
87 #[serde(deserialize_with = "draft_de::deserialize_inputs")]
88 pub inputs: Vec<(String, String)>,
89 #[serde(default)]
90 pub type_defs: serde_json::Value,
91}
92
93mod draft_de {
94 use serde::de::Error as _;
95 use serde::{Deserialize, Deserializer};
96
97 pub(super) fn deserialize_inputs<'de, D>(d: D) -> Result<Vec<(String, String)>, D::Error>
103 where
104 D: Deserializer<'de>,
105 {
106 #[derive(Deserialize)]
107 #[serde(untagged)]
108 enum InputEntry {
109 Tuple(String, String),
110 Object(InputObject),
111 }
112
113 #[derive(Deserialize)]
114 struct InputObject {
115 name: String,
116 #[serde(alias = "type")]
117 ty: serde_json::Value,
118 #[serde(default)]
119 #[allow(dead_code)]
120 docs: Option<String>,
121 }
122
123 let raw: Vec<InputEntry> = Vec::deserialize(d)?;
124 raw.into_iter()
125 .map(|e| match e {
126 InputEntry::Tuple(name, ty) => Ok((name, ty)),
127 InputEntry::Object(o) => {
128 let display = type_display(&o.ty).ok_or_else(|| {
129 D::Error::custom(format!(
130 "input '{}' has unexpected `ty` shape: {}",
131 o.name, o.ty
132 ))
133 })?;
134 Ok((o.name, display))
135 }
136 })
137 .collect()
138 }
139
140 fn type_display(v: &serde_json::Value) -> Option<String> {
144 if let Some(s) = v.as_str() {
145 return Some(s.to_string());
146 }
147 let obj = v.as_object()?;
148 if let Some(arr) = obj.get("variants").and_then(|v| v.as_array()) {
149 let arms: Vec<String> = arr.iter().filter_map(type_display).collect();
150 if arms.len() == arr.len() {
151 return Some(arms.join(" | "));
152 }
153 }
154 if let Some(arr) = obj.get("choices").and_then(|v| v.as_array()) {
155 let arms: Vec<String> = arr
156 .iter()
157 .filter_map(|c| c.as_str().map(|s| format!("\"{s}\"")))
158 .collect();
159 if arms.len() == arr.len() {
160 return Some(arms.join(" | "));
161 }
162 }
163 let name = obj.get("name").and_then(|n| n.as_str())?;
164 if let Some(inner) = obj
165 .get("inner")
166 .and_then(|i| if i.is_null() { None } else { Some(i) })
167 {
168 if let Some(inner_display) = type_display(inner) {
169 return Some(format!("{name}[{inner_display}]"));
170 }
171 }
172 Some(name.to_string())
173 }
174}
175
176#[derive(Serialize, Deserialize, Clone, Debug)]
179pub struct LatestVersion {
180 pub id: i64,
181 pub script_id: i64,
182 pub source: String,
183 pub label: Option<String>,
184 pub published_by: Option<String>,
185 pub created_at: String,
186 #[serde(default)]
187 pub inputs: Vec<(String, String)>,
188}
189
190#[derive(Serialize, Deserialize, Clone, Debug)]
199pub struct ConvertResult {
200 pub markdown: String,
201 #[serde(default, skip_serializing_if = "Option::is_none")]
202 pub document_id: Option<String>,
203 #[serde(default, skip_serializing_if = "Option::is_none")]
204 pub filename: Option<String>,
205}
206
207#[derive(Serialize, Deserialize, Clone, Debug)]
209#[serde(untagged)]
210pub enum S3DocumentRef {
211 Presigned { presigned_url: String },
213 Credentials {
215 bucket: String,
216 key: String,
217 #[serde(skip_serializing_if = "Option::is_none")]
218 region: Option<String>,
219 access_key_id: String,
220 secret_access_key: String,
221 #[serde(skip_serializing_if = "Option::is_none")]
222 session_token: Option<String>,
223 },
224}
225
226#[derive(Serialize, Deserialize, Clone, Debug)]
230pub struct DocumentRef {
231 pub document_id: String,
232 pub filename: String,
233}
234
235#[derive(Serialize, Deserialize, Clone, Debug)]
237pub struct DocumentMeta {
238 pub id: String,
239 pub filename: String,
240 pub content_type: String,
241 pub size_bytes: i64,
242 pub content_hash: String,
243 pub conversion_status: String,
244 pub conversion_error: Option<String>,
245 pub created_at: String,
246}
247
248#[derive(Serialize, Deserialize, Clone, Debug)]
251pub struct RunResult {
252 pub execution_id: String,
253}
254
255#[derive(Serialize, Deserialize, Clone, Debug)]
256pub struct ExecutionStatus {
257 pub id: String,
258 pub project_id: i64,
259 pub script_name: String,
260 pub status: String,
261 pub started_at: Option<String>,
262 pub finished_at: Option<String>,
263 pub version_id: Option<i64>,
264 pub channel: Option<String>,
265 pub error: Option<String>,
266 pub error_kind: Option<String>,
267 pub result: Option<serde_json::Value>,
268 pub documents: Option<serde_json::Value>,
269 pub triggered_by: Option<String>,
270 #[serde(default)]
271 pub input_tokens: i64,
272 #[serde(default)]
273 pub output_tokens: i64,
274 #[serde(default)]
276 pub tool_tokens: i64,
277 pub cost_usd: Option<f64>,
278 #[serde(default)]
285 pub result_type: Option<TypeRef>,
286 #[serde(default)]
292 pub type_defs: Option<serde_json::Value>,
293 #[serde(default)]
296 pub parent_execution_id: Option<String>,
297 #[serde(default)]
300 pub parent_node_id: Option<String>,
301}
302
303#[derive(Serialize, Deserialize, Clone, Debug)]
304pub struct ExecutionOutput {
305 pub status: String,
306 pub error: Option<String>,
307 pub error_kind: Option<String>,
308 pub result: Option<serde_json::Value>,
309}
310
311#[derive(Serialize, Deserialize, Clone, Debug)]
315pub struct ExecutionChildSummary {
316 pub id: String,
317 pub parent_node_id: Option<String>,
318 pub status: String,
319 pub started_at: Option<String>,
320 pub finished_at: Option<String>,
321 pub script_name: String,
322}
323
324#[derive(Serialize, Deserialize, Clone, Debug)]
329pub struct ExecutionTaskSummary {
330 pub task_name: String,
331 pub model: Option<String>,
332 pub provider: Option<String>,
333 pub input_tokens: i64,
334 pub output_tokens: i64,
335 pub cached_input_tokens: i64,
336 pub cache_write_input_tokens: i64,
337 pub cost_usd: Option<f64>,
338 pub duration_ms: Option<i64>,
339 pub attempt: i32,
340 pub finished_at: String,
341}
342
343#[derive(Serialize, Deserialize, Clone, Debug)]
346pub struct ExecutionTasksResponse {
347 pub execution_id: String,
348 pub tasks: Vec<ExecutionTaskSummary>,
349}
350
351pub use akribes_types::event::{EngineEvent, TokenUsage};
359
360pub(crate) fn engine_event_type_name(evt: &EngineEvent) -> &'static str {
363 match evt {
364 EngineEvent::Log(_) => "Log",
365 EngineEvent::LogLevel { .. } => "LogLevel",
366 EngineEvent::StateUpdate(..) => "StateUpdate",
367 EngineEvent::WorkflowStart(_) => "WorkflowStart",
368 EngineEvent::TaskStart(..) => "TaskStart",
369 EngineEvent::TaskPrompt(..) => "TaskPrompt",
370 EngineEvent::TaskEnd { .. } => "TaskEnd",
371 EngineEvent::AgentOutput { .. } => "AgentOutput",
372 EngineEvent::AgentReasoning { .. } => "AgentReasoning",
373 EngineEvent::Suspended { .. } => "Suspended",
374 EngineEvent::Resumed { .. } => "Resumed",
375 EngineEvent::WorkflowEnd(akribes_types::event::WorkflowEndPayload { value: _, .. }) => {
376 "WorkflowEnd"
377 }
378 EngineEvent::Error { .. } => "Error",
379 EngineEvent::NodeStart(..) => "NodeStart",
380 EngineEvent::NodeEnd { .. } => "NodeEnd",
381 EngineEvent::Breakpoint { .. } => "Breakpoint",
382 EngineEvent::BreakpointResumed { .. } => "BreakpointResumed",
383 EngineEvent::ToolCallStart { .. } => "ToolCallStart",
384 EngineEvent::ToolCallEnd { .. } => "ToolCallEnd",
385 EngineEvent::McpServerDegraded { .. } => "McpServerDegraded",
386 EngineEvent::McpServerRecovered { .. } => "McpServerRecovered",
387 EngineEvent::ToolApprovalPending { .. } => "ToolApprovalPending",
388 EngineEvent::ToolApprovalResolved { .. } => "ToolApprovalResolved",
389 EngineEvent::ToolApprovalSkipped { .. } => "ToolApprovalSkipped",
390 EngineEvent::ToolReplayUncertain { .. } => "ToolReplayUncertain",
391 EngineEvent::LLMReplayCacheHit { .. } => "LLMReplayCacheHit",
392 EngineEvent::VerificationStart { .. } => "VerificationStart",
393 EngineEvent::VerificationResult { .. } => "VerificationResult",
394 EngineEvent::ValidationFailure { .. } => "ValidationFailure",
395 EngineEvent::SubScript { .. } => "SubScript",
396 EngineEvent::CachePlanned { .. } => "CachePlanned",
397 EngineEvent::LoopStart { .. } => "LoopStart",
398 EngineEvent::LoopTurn { .. } => "LoopTurn",
399 EngineEvent::LoopEnd { .. } => "LoopEnd",
400 EngineEvent::ContextCompacted { .. } => "ContextCompacted",
401 EngineEvent::ContextOverflow { .. } => "ContextOverflow",
402 EngineEvent::TaskCacheHit { .. } => "TaskCacheHit",
406 EngineEvent::LLMResponse { .. } => "LLMResponse",
407 EngineEvent::SubScriptSpawned { .. } => "SubScriptSpawned",
408 EngineEvent::SubScriptResult { .. } => "SubScriptResult",
409 EngineEvent::CheckpointResolution { .. } => "CheckpointResolution",
410 EngineEvent::RuntimeStart { .. } => "RuntimeStart",
419 EngineEvent::RuntimeStdout { .. } => "RuntimeStdout",
420 EngineEvent::RuntimeStderr { .. } => "RuntimeStderr",
421 EngineEvent::RuntimeEnd { .. } => "RuntimeEnd",
422 EngineEvent::RuntimeError { .. } => "RuntimeError",
423 }
424}
425
426#[derive(Serialize, Deserialize, Clone, Debug)]
427pub struct ExecutionEvents {
428 pub execution_id: String,
429 pub status: String,
430 pub complete: bool,
433 pub events: Vec<EngineEvent>,
434 #[serde(default)]
436 pub next_after_id: Option<i64>,
437 #[serde(default)]
439 pub has_more: bool,
440}
441
442#[derive(Serialize, Deserialize, Clone, Debug)]
445pub struct VersionCost {
446 pub version_id: Option<i64>,
447 pub executions: i64,
448 pub avg_cost_usd: f64,
449 pub total_cost_usd: f64,
450}
451
452#[derive(Serialize, Deserialize, Clone, Debug)]
453pub struct ProjectCost {
454 pub project_id: i64,
455 pub total_executions: i64,
456 pub total_cost_usd: f64,
457 pub avg_cost_usd: f64,
458 pub total_input_tokens: i64,
459 pub total_output_tokens: i64,
460}
461
462#[derive(Serialize, Deserialize, Clone, Debug)]
463pub struct CostAggregation {
464 pub total_executions: i64,
465 pub total_cost_usd: f64,
466 pub avg_cost_usd: f64,
467 pub total_input_tokens: i64,
468 pub total_output_tokens: i64,
469 #[serde(default)]
470 pub total_tool_tokens: i64,
471 #[serde(default)]
472 pub by_version: Vec<VersionCost>,
473}
474
475pub type ScriptCost = CostAggregation;
481
482#[derive(Serialize, Deserialize, Clone, Debug)]
485pub struct GraphNode {
486 pub id: usize,
487 pub op_type: String,
488 pub op_name: Option<String>,
489 pub target_var: Option<String>,
490 pub reads: Vec<String>,
491 pub line: usize,
492 pub col: usize,
493}
494
495#[derive(Serialize, Deserialize, Clone, Debug)]
496pub struct GraphEdge {
497 pub from: usize,
498 pub to: usize,
499}
500
501#[derive(Serialize, Deserialize, Clone, Debug)]
502pub struct GraphResponse {
503 pub nodes: Vec<GraphNode>,
504 pub edges: Vec<GraphEdge>,
505}
506
507pub type ScriptGraph = GraphResponse;
512
513#[derive(Serialize, Deserialize, Clone, Debug)]
516#[serde(tag = "type", content = "payload")]
517pub enum RegistryEvent {
518 ProjectCreated(Project),
519 ProjectUpdated(Project),
520 ProjectDeleted(i64),
521 ScriptCreated {
522 project_id: i64,
523 script: Script,
524 },
525 ScriptUpdated {
526 project_id: i64,
527 script_name: String,
528 version_id: i64,
529 #[serde(default)]
530 channel: Option<String>,
531 },
532 ScriptDeleted {
533 project_id: i64,
534 script_name: String,
535 },
536}
537
538#[derive(Serialize, Deserialize, Clone, Debug)]
544#[serde(tag = "type", content = "payload")]
545pub enum BenchEvent {
546 RunStarted {
549 project_id: i64,
550 script_name: String,
551 run: BenchRun,
552 },
553 ResultRecorded {
557 project_id: i64,
558 script_name: String,
559 run_id: i64,
560 result: BenchResult,
561 },
562 RunFinished {
565 project_id: i64,
566 script_name: String,
567 run: BenchRun,
568 },
569}
570
571#[derive(Serialize, Deserialize, Clone, Debug)]
572#[serde(tag = "type", content = "payload")]
573pub enum HubEvent {
574 Execution {
575 project_id: i64,
576 script_name: String,
577 #[serde(default, skip_serializing_if = "Option::is_none")]
584 execution_id: Option<String>,
585 event: EngineEvent,
586 #[serde(default, skip_serializing_if = "Option::is_none")]
591 seq: Option<i64>,
592 #[serde(default, skip_serializing_if = "Option::is_none")]
595 at: Option<String>,
596 },
597 Registry(RegistryEvent),
598 Bench(BenchEvent),
605}
606
607#[derive(Serialize, Deserialize, Clone, Debug)]
610pub struct PutDraftResponse {
611 #[serde(default)]
612 pub schema_warnings: Vec<ContractWarning>,
613}
614
615#[derive(Serialize, Deserialize, Clone, Debug)]
616pub struct ContractWarning {
617 pub client_id: String,
618 pub client_name: String,
619 pub channel: String,
620 pub mismatch: SchemaMismatch,
621}
622
623#[derive(Serialize, Deserialize, Clone, Debug)]
626pub struct DryRunResult {
627 pub dry_run: bool,
628 pub would_break: i64,
629 pub breaking_interests: Vec<BreakingInterest>,
630}
631
632#[derive(Serialize, Deserialize, Clone, Debug)]
633pub struct BreakingInterest {
634 pub client_id: String,
635 pub client_name: String,
636 pub channel: String,
637 pub lifetime: String,
638 pub mismatch: SchemaMismatch,
639}
640
641#[derive(Serialize, Deserialize, Clone, Debug)]
645pub struct ClientInfo {
646 pub id: String,
647 pub name: String,
648 pub last_seen: String,
649 #[serde(default)]
650 pub scripts: Vec<String>,
651}
652
653#[derive(Serialize, Deserialize, Clone, Debug)]
654pub struct ClientInterest {
655 pub script_name: String,
656 pub inputs: HashMap<String, String>,
657 #[serde(skip_serializing_if = "Option::is_none")]
658 pub channel: Option<String>,
659 #[serde(skip_serializing_if = "Option::is_none")]
660 pub lifetime: Option<String>,
661 #[serde(skip_serializing_if = "Option::is_none")]
662 pub strict: Option<bool>,
663}
664
665#[derive(Serialize, Deserialize, Clone, Debug)]
666pub struct RegisteredInterest {
667 pub script_name: String,
668 pub channel: String,
669 pub bound_version_id: Option<i64>,
670 #[serde(default)]
671 pub input_schema: Vec<(String, String)>,
672}
673
674#[derive(Serialize, Deserialize, Clone, Debug)]
675pub struct RegisterClientResponse {
676 #[serde(default)]
677 pub interests: Vec<RegisteredInterest>,
678}
679
680#[derive(Serialize, Deserialize, Clone, Debug)]
681pub struct SchemaMismatch {
682 #[serde(default)]
683 pub missing: Vec<(String, String)>,
684 #[serde(default)]
685 pub wrong_type: Vec<(String, String, String)>,
686 #[serde(default)]
687 pub extra: Vec<String>,
688}
689
690#[derive(Serialize, Deserialize, Clone, Debug)]
691pub struct ContractLockInfo {
692 pub id: i64,
693 pub client_id: String,
694 pub client_name: String,
695 pub script_name: String,
696 pub channel: String,
697 pub bound_version_id: Option<i64>,
698 pub lifetime: String,
699 pub drifted: bool,
700 pub created_by: Option<String>,
701 pub created_at: String,
702 pub input_schema: String,
703}
704
705#[derive(Serialize, Deserialize, Clone, Debug)]
708pub struct TokenScopes {
709 pub projects: ProjectScope,
710 pub role: TokenRole,
711 #[serde(skip_serializing_if = "Option::is_none")]
712 pub scripts: Option<Vec<String>>,
713 #[serde(skip_serializing_if = "Option::is_none")]
714 pub executions: Option<Vec<String>>,
715 #[serde(default)]
719 pub can_mint: bool,
720 #[serde(default, skip_serializing_if = "Vec::is_empty")]
723 pub features: Vec<String>,
724 #[serde(default, skip_serializing_if = "Option::is_none")]
728 pub org_id: Option<i64>,
729}
730
731#[derive(Serialize, Deserialize, Clone, Debug)]
732#[serde(untagged)]
733pub enum ProjectScope {
734 Wildcard(WildcardMarker),
735 Specific(Vec<i64>),
736}
737
738#[derive(Clone, Debug)]
740pub struct WildcardMarker;
741
742impl Serialize for WildcardMarker {
743 fn serialize<S: serde::Serializer>(
744 &self,
745 serializer: S,
746 ) -> std::result::Result<S::Ok, S::Error> {
747 serializer.serialize_str("*")
748 }
749}
750
751impl<'de> Deserialize<'de> for WildcardMarker {
752 fn deserialize<D: serde::Deserializer<'de>>(
753 deserializer: D,
754 ) -> std::result::Result<Self, D::Error> {
755 let s = String::deserialize(deserializer)?;
756 if s == "*" {
757 Ok(WildcardMarker)
758 } else {
759 Err(serde::de::Error::custom("expected \"*\""))
760 }
761 }
762}
763
764#[derive(Serialize, Deserialize, Clone, Debug)]
765#[serde(rename_all = "lowercase")]
766pub enum TokenRole {
767 Admin,
768 Editor,
769 Viewer,
770}
771
772#[derive(Serialize, Deserialize, Clone, Debug)]
773pub struct TokenInfo {
774 pub id: String,
775 pub label: String,
776 pub user_email: Option<String>,
777 pub scopes: TokenScopes,
778 pub minted_by: String,
779 pub expires_at: String,
780 pub revoked: bool,
781 pub created_at: String,
782 pub last_used_at: Option<String>,
783}
784
785#[derive(Serialize, Deserialize, Clone, Debug)]
787pub struct MintTokenResponse {
788 pub token: String,
789 pub token_id: String,
790 pub expires_at: String,
791}
792
793#[derive(Serialize, Deserialize, Clone, Debug)]
795pub struct MintTokenRequest {
796 #[serde(skip_serializing_if = "Option::is_none")]
797 pub user_email: Option<String>,
798 pub scopes: TokenScopes,
799 pub expires_in: i64,
800 pub label: String,
801}
802
803#[derive(Serialize, Deserialize, Clone, Debug)]
805pub struct RevokeByEmailResponse {
806 pub revoked: i64,
807}
808
809#[derive(Serialize, Deserialize, Clone, Debug)]
812pub struct AdhocRunResult {
813 pub execution_id: String,
814 pub project_id: i64,
815}
816
817#[derive(Serialize, Deserialize, Clone, Debug)]
820#[serde(rename_all = "lowercase")]
821pub enum McpOrigin {
822 Env,
823 Script,
824 Db,
825}
826
827#[derive(Serialize, Deserialize, Clone, Debug)]
828pub struct McpServerSummary {
829 pub alias: String,
830 pub url: String,
831 pub origin: McpOrigin,
832 pub is_registry: bool,
833 pub status: String,
834 pub tool_count: i64,
835}
836
837#[derive(Serialize, Deserialize, Clone, Debug)]
838pub struct McpToolSummary {
839 pub qualified_name: String,
840 pub server_alias: String,
841 #[serde(default, skip_serializing_if = "Option::is_none")]
842 pub description: Option<String>,
843 pub input_schema: serde_json::Value,
844}
845
846#[derive(Serialize, Deserialize, Clone, Debug)]
847pub struct McpHealth {
848 pub status: String,
849 #[serde(default, skip_serializing_if = "Option::is_none")]
850 pub last_error: Option<String>,
851 #[serde(default, skip_serializing_if = "Option::is_none")]
852 pub last_check_at: Option<String>,
853}
854
855#[derive(Deserialize, Clone, Debug)]
857pub(crate) struct SandboxProjectIdResponse {
858 pub project_id: i64,
859}
860
861#[derive(Serialize)]
864pub(crate) struct RegisterRequest {
865 pub id: String,
866 pub name: String,
867 pub interests: Vec<ClientInterest>,
868}
869
870#[derive(Serialize)]
871pub(crate) struct HeartbeatRequest {
872 pub client_id: String,
873}
874
875#[derive(Serialize, Default)]
876pub(crate) struct RunRequest {
877 #[serde(skip_serializing_if = "Option::is_none")]
878 pub inputs: Option<HashMap<String, serde_json::Value>>,
879 #[serde(skip_serializing_if = "Option::is_none")]
880 pub triggered_by: Option<String>,
881 #[serde(skip_serializing_if = "Option::is_none")]
882 pub breakpoint_lines: Option<Vec<usize>>,
883}
884
885#[derive(Serialize)]
886pub(crate) struct CreateProjectRequest<'a> {
887 pub name: &'a str,
888}
889
890#[derive(Serialize)]
891pub(crate) struct UpdateProjectRequest<'a> {
892 pub name: &'a str,
893}
894
895#[derive(Serialize)]
896pub(crate) struct CreateScriptBody<'a> {
897 pub source: &'a str,
898}
899
900#[derive(Serialize)]
901pub(crate) struct RenameScriptRequest<'a> {
902 pub new_name: &'a str,
903}
904
905#[derive(Serialize)]
906pub(crate) struct MoveScriptRequest {
907 pub target_project_id: i64,
908}
909
910#[derive(Serialize)]
911pub(crate) struct ReorderRequest {
912 pub order: Vec<i64>,
913}
914
915#[derive(Serialize, Deserialize, Clone, Debug)]
917pub struct McpRefreshResult {
918 pub refreshed: bool,
919 pub alias: String,
920 pub tool_count: usize,
921}
922
923#[derive(Serialize, Deserialize, Clone, Debug)]
925pub struct McpDriftResult {
926 pub drifted: bool,
927 #[serde(default)]
928 pub added: Vec<String>,
929 #[serde(default)]
930 pub removed: Vec<String>,
931 #[serde(default)]
932 pub reason: Option<String>,
933}
934
935#[derive(Serialize)]
936pub(crate) struct PutDraftRequest<'a> {
937 pub source: &'a str,
938}
939
940#[derive(Serialize, Default)]
941pub(crate) struct PublishRequest {
942 pub channels: Vec<String>,
943 #[serde(skip_serializing_if = "Option::is_none")]
944 pub label: Option<String>,
945 #[serde(skip_serializing_if = "Option::is_none")]
946 pub published_by: Option<String>,
947 #[serde(skip_serializing_if = "Option::is_none")]
948 pub force: Option<bool>,
949 #[serde(skip_serializing_if = "Option::is_none")]
950 pub dry_run: Option<bool>,
951}
952
953#[derive(Serialize)]
954pub(crate) struct CreateChannelRequest<'a> {
955 pub name: &'a str,
956}
957
958#[derive(Serialize)]
959pub(crate) struct MoveChannelRequest {
960 pub version_id: i64,
961 #[serde(skip_serializing_if = "Option::is_none")]
962 pub force: Option<bool>,
963}
964
965#[derive(Serialize)]
966pub(crate) struct RebindLockRequest {
967 pub version_id: Option<i64>,
968}
969
970#[derive(Serialize)]
971pub(crate) struct AdhocRunRequest<'a> {
972 pub source: &'a str,
973 #[serde(skip_serializing_if = "Option::is_none")]
974 pub inputs: Option<HashMap<String, serde_json::Value>>,
975 #[serde(skip_serializing_if = "Option::is_none")]
976 pub breakpoint_lines: Option<Vec<usize>>,
977 #[serde(skip_serializing_if = "Option::is_none")]
980 pub channel: Option<&'a str>,
981 #[serde(skip_serializing_if = "Option::is_none")]
983 pub triggered_by: Option<&'a str>,
984}
985
986#[derive(Serialize)]
987pub(crate) struct ResumeRequest {
988 pub token: String,
989 pub data: serde_json::Value,
990}
991
992#[derive(Serialize)]
993pub(crate) struct RunWithS3Request {
994 pub inputs: HashMap<String, S3DocumentRef>,
995 #[serde(skip_serializing_if = "Option::is_none")]
996 pub channel: Option<String>,
997 #[serde(skip_serializing_if = "Option::is_none")]
998 pub triggered_by: Option<String>,
999}
1000
1001#[derive(Serialize, Default)]
1002pub(crate) struct RunFromRequest {
1003 #[serde(skip_serializing_if = "Option::is_none")]
1004 pub inputs: Option<HashMap<String, serde_json::Value>>,
1005 pub seed_env: HashMap<String, serde_json::Value>,
1006 pub skip_node_ids: Vec<usize>,
1007 #[serde(skip_serializing_if = "Option::is_none")]
1008 pub triggered_by: Option<String>,
1009}
1010
1011#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
1018#[serde(rename_all = "snake_case")]
1019pub enum ConversionStatus {
1020 Text,
1021 Ready,
1022 Converting,
1023 Pending,
1024 Failed,
1025 #[serde(other)]
1026 Unknown,
1027}
1028
1029#[derive(Serialize, Deserialize, Clone, Debug)]
1030pub struct UploadResult {
1031 pub document_id: String,
1032 pub filename: String,
1033 pub content_hash: String,
1034 pub conversion_status: ConversionStatus,
1035}
1036
1037#[derive(Serialize, Deserialize, Clone, Debug)]
1041pub struct IngestProgress {
1042 pub done: u32,
1044 pub total: u32,
1046}
1047
1048#[derive(Deserialize)]
1050#[serde(tag = "state", rename_all = "snake_case")]
1051pub(crate) enum ProgressResponseWire {
1052 Converting { done_pages: u32, total_pages: u32 },
1053 Idle,
1054}
1055
1056#[derive(Clone, Debug)]
1057pub enum ClaimOutcome {
1058 Hit(UploadResult),
1059 Miss,
1060}
1061
1062#[derive(Serialize)]
1065pub(crate) struct ClaimRequest<'a> {
1066 pub content_hash: &'a str,
1067 pub filename: &'a str,
1068}
1069
1070#[derive(Deserialize)]
1072#[serde(tag = "status", rename_all = "snake_case")]
1073pub(crate) enum ClaimResponseWire {
1074 Hit {
1075 document_id: String,
1076 filename: String,
1077 content_hash: String,
1078 conversion_status: ConversionStatus,
1079 },
1080 Miss,
1081}
1082
1083#[derive(Serialize, Deserialize, Clone, Debug)]
1093pub struct Bench {
1094 pub id: i64,
1095 pub script_id: i64,
1096 #[serde(default)]
1097 pub judge_script_id: Option<i64>,
1098 pub judge_channel: String,
1099 pub config: serde_json::Value,
1100 pub created_at: String,
1101 pub updated_at: String,
1102}
1103
1104#[derive(Serialize, Deserialize, Clone, Debug)]
1107pub struct ProjectBenchSummary {
1108 pub bench_id: i64,
1109 pub script_id: i64,
1110 pub script_name: String,
1111 #[serde(default)]
1112 pub judge_script_id: Option<i64>,
1113 #[serde(default)]
1114 pub judge_script_name: Option<String>,
1115 pub judge_channel: String,
1116 pub case_count: i64,
1117 #[serde(default)]
1118 pub latest_run_id: Option<i64>,
1119 #[serde(default)]
1120 pub latest_run_status: Option<String>,
1121 #[serde(default)]
1122 pub latest_run_channel: Option<String>,
1123 #[serde(default)]
1124 pub latest_run_workflow_version_id: Option<i64>,
1125 #[serde(default)]
1126 pub latest_run_at: Option<String>,
1127 #[serde(default)]
1128 pub latest_run_mean_score: Option<f64>,
1129 #[serde(default)]
1130 pub latest_run_cost_usd: Option<f64>,
1131 pub updated_at: String,
1132}
1133
1134#[derive(Serialize, Deserialize, Clone, Debug)]
1138pub struct BenchRun {
1139 pub id: i64,
1140 pub bench_id: i64,
1141 pub channel: String,
1142 pub workflow_version_id: i64,
1143 pub judge_version_id: i64,
1144 pub status: String,
1145 #[serde(default)]
1146 pub triggered_by: Option<String>,
1147 pub triggered_at: String,
1148 #[serde(default)]
1149 pub completed_at: Option<String>,
1150 #[serde(default)]
1151 pub total_cost_usd: f64,
1152 #[serde(default)]
1153 pub total_cases: i32,
1154 #[serde(default)]
1155 pub cache_hit_cases: i32,
1156 #[serde(default)]
1157 pub notes: Option<String>,
1158 #[serde(default)]
1159 pub mcp_session_id: Option<String>,
1160 #[serde(default)]
1161 pub case_filter: Option<Vec<String>>,
1162 #[serde(default)]
1166 pub mean_headline_score: Option<f64>,
1167 #[serde(default)]
1170 pub ok_cases: Option<i64>,
1171 #[serde(default, skip_serializing_if = "Option::is_none")]
1177 pub status_breakdown: Option<std::collections::HashMap<String, i64>>,
1178 #[serde(default)]
1183 pub judge_script_name: Option<String>,
1184}
1185
1186#[derive(Serialize, Deserialize, Clone, Debug)]
1190pub struct BenchResult {
1191 pub id: i64,
1192 pub bench_run_id: i64,
1193 pub case_id: String,
1194 #[serde(default)]
1195 pub workflow_execution_id: Option<String>,
1196 #[serde(default)]
1197 pub judge_execution_id: Option<String>,
1198 #[serde(default)]
1199 pub score: Option<serde_json::Value>,
1200 #[serde(default)]
1201 pub headline_score: Option<f64>,
1202 pub status: String,
1203 #[serde(default)]
1204 pub cost_usd: f64,
1205 #[serde(default)]
1206 pub duration_ms: Option<i32>,
1207 #[serde(default)]
1208 pub cache_hit: bool,
1209 #[serde(default)]
1210 pub input_hash: Option<String>,
1211 #[serde(default)]
1216 pub error: Option<String>,
1217 pub created_at: String,
1218 #[serde(default)]
1226 pub workflow_output: Option<serde_json::Value>,
1227}
1228
1229#[derive(Serialize, Deserialize, Clone, Debug)]
1232pub struct BenchCase {
1233 pub id: String,
1234 pub project_id: i64,
1235 pub script_name: String,
1236 #[serde(default)]
1237 pub bench_id: Option<i64>,
1238 pub kind: String,
1239 pub frozen: bool,
1240 #[serde(default)]
1241 pub case_name: Option<String>,
1242 #[serde(default)]
1243 pub inputs: Option<serde_json::Value>,
1244 #[serde(default)]
1245 pub expected_output: Option<serde_json::Value>,
1246 #[serde(default)]
1247 pub ground_truth: Option<serde_json::Value>,
1248 #[serde(default)]
1251 pub input_hash: Option<String>,
1252 pub created_at: String,
1253}
1254
1255#[derive(Serialize, Deserialize, Clone, Debug)]
1257pub struct CompareCase {
1258 pub case_id: String,
1259 pub case_label: String,
1260 #[serde(default)]
1261 pub score_a: Option<f64>,
1262 #[serde(default)]
1263 pub score_b: Option<f64>,
1264 #[serde(default)]
1265 pub delta: Option<f64>,
1266 pub flag: String,
1268}
1269
1270#[derive(Serialize, Deserialize, Clone, Debug)]
1271pub struct CompareAggregate {
1272 pub mean_score_delta: f64,
1273 pub cost_delta_usd: f64,
1274 pub n_regressed: i32,
1275 pub n_improved: i32,
1276 pub n_unchanged: i32,
1277}
1278
1279#[derive(Serialize, Deserialize, Clone, Debug)]
1280pub struct CompareReport {
1281 pub run_a_id: i64,
1282 pub run_b_id: i64,
1283 pub aggregate: CompareAggregate,
1284 pub per_case: Vec<CompareCase>,
1285}
1286
1287#[derive(Serialize, Deserialize, Clone, Debug)]
1289pub struct DriftedCase {
1290 pub case_id: String,
1291 pub label: String,
1292 pub what_broke: String,
1293}
1294
1295#[derive(Serialize, Deserialize, Clone, Debug)]
1296pub struct DriftReport {
1297 pub drifted: Vec<DriftedCase>,
1298 #[serde(default)]
1299 pub script_version_id: Option<i64>,
1300 #[serde(default)]
1301 pub published_at: Option<String>,
1302 #[serde(default)]
1303 pub published_by: Option<String>,
1304 pub summary: String,
1305}
1306
1307#[derive(Serialize, Deserialize, Clone, Debug)]
1310pub struct BenchRunTagSessionResponse {
1311 pub tagged: bool,
1312 pub run_id: i64,
1313 pub mcp_session_id: String,
1314}
1315
1316#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1319pub struct CreateOrUpdateBenchRequest {
1320 #[serde(skip_serializing_if = "Option::is_none")]
1321 pub judge_script_id: Option<i64>,
1322 #[serde(skip_serializing_if = "Option::is_none")]
1323 pub judge_channel: Option<String>,
1324 #[serde(skip_serializing_if = "Option::is_none")]
1325 pub config: Option<serde_json::Value>,
1326}
1327
1328#[derive(Serialize, Deserialize, Clone, Debug)]
1329pub struct CreateBenchCaseRequest {
1330 pub inputs: serde_json::Value,
1331 #[serde(skip_serializing_if = "Option::is_none")]
1332 pub expected_output: Option<serde_json::Value>,
1333 #[serde(skip_serializing_if = "Option::is_none")]
1334 pub ground_truth: Option<serde_json::Value>,
1335 #[serde(skip_serializing_if = "Option::is_none")]
1336 pub name: Option<String>,
1337}
1338
1339#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1340pub struct PatchBenchCaseRequest {
1341 #[serde(skip_serializing_if = "Option::is_none")]
1342 pub inputs: Option<serde_json::Value>,
1343 #[serde(skip_serializing_if = "Option::is_none")]
1344 pub expected_output: Option<serde_json::Value>,
1345 #[serde(skip_serializing_if = "Option::is_none")]
1346 pub ground_truth: Option<serde_json::Value>,
1347 #[serde(skip_serializing_if = "Option::is_none")]
1348 pub name: Option<String>,
1349}
1350
1351#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1352pub struct PromoteCaseEdits {
1353 #[serde(skip_serializing_if = "Option::is_none")]
1354 pub inputs: Option<serde_json::Value>,
1355 #[serde(skip_serializing_if = "Option::is_none")]
1356 pub expected_output: Option<serde_json::Value>,
1357 #[serde(skip_serializing_if = "Option::is_none")]
1358 pub ground_truth: Option<serde_json::Value>,
1359}
1360
1361#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1362pub struct PromoteExecutionRequest {
1363 #[serde(default, skip_serializing_if = "Option::is_none")]
1364 pub edits: Option<PromoteCaseEdits>,
1365 #[serde(default, skip_serializing_if = "Option::is_none")]
1366 pub name: Option<String>,
1367}
1368
1369#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1370pub struct TriggerBenchRunRequest {
1371 pub channel: String,
1372 #[serde(skip_serializing_if = "Option::is_none")]
1373 pub notes: Option<String>,
1374 #[serde(default, skip_serializing_if = "Option::is_none")]
1376 pub case_ids: Option<Vec<String>>,
1377}
1378
1379#[derive(Clone, Debug)]
1398pub enum BenchRunEvent {
1399 Result(Box<BenchResult>),
1401 Lagged { dropped: u64 },
1403 Terminal { status: String },
1405}