1use std::collections::BTreeMap;
7
8use serde::{Deserialize, Serialize};
9use serde_json::Value;
10
11pub const ROUTING_REQUEST_SCHEMA_VERSION: &str = "switchyard.routing_request.v1";
13pub const ROUTING_DECISION_SCHEMA_VERSION: &str = "switchyard.routing_decision.v1";
15
16#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
18#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
19#[serde(rename_all = "snake_case")]
20pub enum RequestMaterialization {
21 None,
23 SummaryOnly,
25 LatestUserPrompt,
27 RecentMessageWindow,
29 AnnotatedRequest,
31 FullBody,
33}
34
35#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
37pub struct DecisionProfile {
38 pub profile_id: String,
40 pub request_materialization: RequestMaterialization,
42}
43
44#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
46pub struct RequestIdentity {
47 pub session_id: String,
49 pub request_id: String,
51 #[serde(skip_serializing_if = "Option::is_none")]
53 pub turn_id: Option<String>,
54 #[serde(skip_serializing_if = "Option::is_none")]
56 pub parent_scope_id: Option<String>,
57 #[serde(skip_serializing_if = "Option::is_none")]
59 pub root_scope_id: Option<String>,
60 pub harness: String,
62 pub source: String,
64 #[serde(skip_serializing_if = "Option::is_none")]
66 pub owner_id: Option<String>,
67 pub quality: String,
69}
70
71#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
73pub struct RequestProtocol {
74 pub inbound_profile: String,
76 pub inbound_endpoint: String,
78 pub desired_response_profile: String,
80}
81
82#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
84pub struct RequestSummary {
85 #[serde(skip_serializing_if = "Option::is_none")]
87 pub client_requested_model: Option<String>,
88 #[serde(skip_serializing_if = "Option::is_none")]
90 pub prompt_token_estimate: Option<u64>,
91 #[serde(skip_serializing_if = "Option::is_none")]
93 pub tool_count_in_payload: Option<u64>,
94 #[serde(skip_serializing_if = "Option::is_none")]
96 pub has_system_prompt: Option<bool>,
97}
98
99#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
101pub struct DecisionAttempt {
102 pub routing_attempt: u32,
104 pub max_routing_attempts: u32,
106 #[serde(skip_serializing_if = "Option::is_none")]
108 pub previous_route: Option<String>,
109 #[serde(skip_serializing_if = "Option::is_none")]
111 pub retry_reason: Option<String>,
112}
113
114#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
116pub struct RoutingRequest {
117 pub schema_version: String,
119 pub decision_profile: DecisionProfile,
121 pub identity: RequestIdentity,
123 pub protocol: RequestProtocol,
125 pub request_summary: RequestSummary,
127 #[serde(skip_serializing_if = "Option::is_none")]
129 pub current_request: Option<Value>,
130 pub attempt: DecisionAttempt,
132}
133
134#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
136pub struct DecisionProvider {
137 pub name: String,
139 pub version: String,
141}
142
143#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
145pub struct RoutingTarget {
146 pub tier: String,
148 pub target_model: String,
150 pub backend_id: String,
152 pub target_protocol_profile: String,
154 pub target_endpoint: String,
156}
157
158#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
160pub struct RoutingDecision {
161 pub schema_version: String,
163 pub decision_id: String,
165 pub router: DecisionProvider,
167 pub route: RoutingTarget,
169 #[serde(default, skip_serializing_if = "Option::is_none")]
171 pub baseline_route: Option<RoutingTarget>,
172 #[serde(default)]
174 pub confidence: Option<f64>,
175 #[serde(default)]
177 pub reason_code: Option<String>,
178 #[serde(default)]
180 pub reason_summary: Option<String>,
181 #[serde(default)]
183 pub metadata: BTreeMap<String, Value>,
184 #[serde(flatten)]
186 pub extra: BTreeMap<String, Value>,
187}