switchyard_libsy/algorithms/
passthrough.rs1use std::sync::Arc;
7
8use switchyard_protocol::{Request, Response};
9
10use crate::Result;
11use crate::core::algorithm::{Algorithm, Driver, LlmTarget};
12use switchyard_protocol::{Context, Decision};
13
14pub struct Passthrough {
16 target: LlmTarget,
17}
18
19impl Passthrough {
20 pub fn new(target: LlmTarget) -> Self {
22 Passthrough { target }
23 }
24}
25
26pub struct PassthroughDecision {
28 model_id: String,
29}
30
31impl Decision for PassthroughDecision {
32 fn selected_model(&self) -> &str {
33 &self.model_id
34 }
35 fn reasoning(&self) -> Option<&str> {
36 None
38 }
39 fn as_any(&self) -> &dyn std::any::Any {
40 self
41 }
42}
43
44#[async_trait::async_trait]
45impl Algorithm for Passthrough {
46 fn name(&self) -> &str {
47 "passthrough"
48 }
49
50 async fn create_run_task(
51 self: Arc<Self>,
52 ctx: Context,
53 driver: Driver,
54 request: Request,
55 ) -> Result<Response> {
56 let decision: Arc<dyn Decision> = Arc::new(PassthroughDecision {
57 model_id: self.target.semantic_name.clone(),
58 });
59 driver.info(ctx.clone(), decision.clone()).await?;
60 driver
61 .call_llm_target(ctx, &self.target, request, decision)
62 .await
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use std::sync::Arc;
69
70 use super::Passthrough;
71 use crate::core::algorithm::{Algorithm, LlmTarget};
72 use switchyard_protocol::{
73 Context, Decision, LlmResponse, Request, Response, RoutedLlmClient, completion_text,
74 text_request, text_response,
75 };
76
77 struct EchoClient;
80
81 #[async_trait::async_trait]
82 impl RoutedLlmClient for EchoClient {
83 async fn call(
84 &self,
85 _ctx: Context,
86 _request: Request,
87 decision: Arc<dyn Decision>,
88 ) -> std::result::Result<Response, switchyard_protocol::LlmClientError> {
89 Ok(Response {
90 llm_response: LlmResponse::Agg(text_response(None, decision.selected_model())),
91 metadata: None,
92 })
93 }
94 }
95
96 #[tokio::test]
97 async fn test_passthrough() -> crate::Result<()> {
98 const MODEL_ID: &str = "testing/passthrough";
99 let request = Request {
100 llm_request: text_request(Some("auto".to_string()), "hi"),
101 raw_request: None,
102 metadata: None,
103 };
104 let algorithm: Arc<dyn Algorithm> = Arc::new(Passthrough::new(LlmTarget {
105 semantic_name: MODEL_ID.to_string(),
106 llm_client: Some(Arc::new(EchoClient)),
107 }));
108 let (trace, response) = algorithm.run(Context::default(), request).await?;
109
110 assert_eq!(
111 response
112 .llm_response
113 .as_agg()
114 .map(completion_text)
115 .unwrap_or_default(),
116 MODEL_ID
117 );
118 assert_eq!(trace.len(), 1);
119 assert_eq!(trace[0].selected_model(), MODEL_ID);
120 Ok(())
121 }
122}