Skip to main content

switchyard_libsy/algorithms/
noop.rs

1// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Test-only algorithm that returns a hard-coded response without calling a backend.
5
6use std::sync::Arc;
7
8use switchyard_protocol::{
9    AggLlmResponse, ContentBlock, LlmResponse, ModelId, Request, Response, ResponseOutput, Role,
10    StopReason,
11};
12
13use crate::Result;
14use crate::core::algorithm::{Algorithm, Driver};
15use switchyard_protocol::Decision;
16
17/// Test helper that returns a hard-coded response without routing or model I/O.
18pub struct Noop {}
19
20#[async_trait::async_trait]
21impl Algorithm for Noop {
22    fn name(&self) -> &str {
23        "noop"
24    }
25
26    async fn route(self: Arc<Self>, driver: Driver, request: Request) -> Result<Response> {
27        let model_id = request
28            .model_id()
29            .unwrap_or_else(|| ModelId::from("switchyard/noop"));
30        tracing::info!(target = %model_id, "noop returned its synthetic response");
31        let decision: Decision = Decision::new(model_id.clone(), true);
32        driver.decide(decision.clone()).await?;
33
34        let llm_response = LlmResponse::Agg(AggLlmResponse {
35            id: Some("switchyard-noop".to_string()),
36            model: Some(model_id.to_string()),
37            outputs: vec![ResponseOutput {
38                role: Role::Assistant,
39                content: vec![ContentBlock::Text {
40                    text: "OK".to_string(),
41                }],
42                stop_reason: Some(StopReason::EndTurn),
43            }],
44            ..Default::default()
45        });
46        let response = Response {
47            llm_response,
48            metadata: request.metadata.clone(),
49        };
50        Ok(response)
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use switchyard_protocol::{LlmRequest, Message, Role};
57
58    use super::*;
59    use crate::core::testing::{echo, test_drive};
60
61    #[tokio::test]
62    async fn test_noop_algo() -> Result<()> {
63        const TEST_MODEL: &str = "test_noop_algo";
64        let request = Request {
65            llm_request: LlmRequest {
66                model: Some(TEST_MODEL.to_string()),
67                messages: vec![Message::text(Role::User, "hi")],
68                ..LlmRequest::default()
69            },
70            raw_request: None,
71            metadata: None,
72        };
73
74        // `Noop` synthesizes its own response and never offloads a call, so `echo` is
75        // never reached.
76        let a: Arc<dyn Algorithm> = Arc::new(Noop {});
77        let (decisions, response) = test_drive(a, request, echo()).await?;
78        let Some(decision) = decisions.first() else {
79            panic!("Expected exactly one Decision");
80        };
81        assert_eq!(decision.selected_model_id(), TEST_MODEL);
82        assert!(decision.is_answer_call());
83        assert_eq!(response.selected_model(), Some(TEST_MODEL));
84        Ok(())
85    }
86}