Skip to main content

llm/testing/
llm_response.rs

1use crate::{LlmResponse, StopReason};
2
3pub fn llm_response(message_id: &str) -> LlmResponseBuilder {
4    LlmResponseBuilder::new(message_id)
5}
6
7pub struct LlmResponseBuilder {
8    chunks: Vec<LlmResponse>,
9}
10
11impl LlmResponseBuilder {
12    pub fn new(message_id: &str) -> Self {
13        Self { chunks: vec![LlmResponse::start(message_id)] }
14    }
15
16    pub fn text(mut self, chunks: &[&str]) -> Self {
17        for chunk in chunks {
18            self.chunks.push(LlmResponse::text(chunk));
19        }
20
21        self
22    }
23
24    pub fn tool_call(mut self, id: &str, name: &str, argument_chunks: &[&str]) -> Self {
25        self.chunks.push(LlmResponse::tool_request_start(id, name));
26
27        for chunk in argument_chunks {
28            self.chunks.push(LlmResponse::tool_request_arg(id, chunk));
29        }
30
31        self.chunks.push(LlmResponse::tool_request_complete(id, name, &argument_chunks.join("")));
32
33        self
34    }
35
36    pub fn usage(mut self, input_tokens: u32, output_tokens: u32) -> Self {
37        self.chunks.push(LlmResponse::usage(input_tokens, output_tokens));
38        self
39    }
40
41    pub fn tool_call_with_invalid_json(mut self, id: &str, name: &str) -> Self {
42        self.chunks.push(LlmResponse::tool_request_start(id, name));
43        self.chunks.push(LlmResponse::tool_request_complete(id, name, "invalid json"));
44
45        self
46    }
47
48    pub fn build(mut self) -> Vec<LlmResponse> {
49        self.chunks.push(LlmResponse::done());
50        self.chunks
51    }
52
53    pub fn build_with_stop_reason(mut self, stop_reason: StopReason) -> Vec<LlmResponse> {
54        self.chunks.push(LlmResponse::done_with_stop_reason(stop_reason));
55        self.chunks
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn build_with_stop_reason_preserves_response_chunks() {
65        let response = llm_response("message").text(&["hello"]).usage(10, 2).build_with_stop_reason(StopReason::Length);
66
67        assert!(matches!(
68            response.as_slice(),
69            [
70                LlmResponse::Start { .. },
71                LlmResponse::Text { .. },
72                LlmResponse::Usage { .. },
73                LlmResponse::Done { stop_reason: Some(StopReason::Length) },
74            ]
75        ));
76    }
77}