Skip to main content

ds_api/api/
request.rs

1//! ApiRequest builder module.
2//!
3//! Provides a safe, chainable request builder that wraps the internal
4//! `crate::raw::ChatCompletionRequest`.
5
6use crate::raw::{ChatCompletionRequest, Message, ResponseFormat, ResponseFormatType, Tool};
7
8/// A safe, chainable request builder that wraps `ChatCompletionRequest`.
9///
10/// Use [`with_model`][ApiRequest::with_model] to set an arbitrary model string,
11/// or the convenience constructors [`deepseek_chat`][ApiRequest::deepseek_chat]
12/// and [`deepseek_reasoner`][ApiRequest::deepseek_reasoner] for the standard
13/// DeepSeek models.
14#[derive(Debug)]
15pub struct ApiRequest {
16    raw: ChatCompletionRequest,
17}
18
19impl ApiRequest {
20    /// Start a new builder with default values.
21    pub fn builder() -> Self {
22        Self {
23            raw: ChatCompletionRequest::default(),
24        }
25    }
26
27    /// Set the model by string (builder-style).
28    ///
29    /// Accepts any model identifier — a named DeepSeek model or any
30    /// OpenAI-compatible model string:
31    ///
32    /// ```
33    /// use ds_api::ApiRequest;
34    ///
35    /// let req = ApiRequest::builder().with_model("deepseek-chat");
36    /// let req = ApiRequest::builder().with_model("gpt-4o");
37    /// ```
38    pub fn with_model(mut self, name: impl Into<String>) -> Self {
39        self.raw.model = crate::raw::Model::Custom(name.into());
40        self
41    }
42
43    /// Convenience constructor: deepseek-chat + messages
44    pub fn deepseek_chat(messages: Vec<Message>) -> Self {
45        let mut r = Self::builder();
46        r.raw.messages = messages;
47        r.raw.model = crate::raw::Model::DeepseekChat;
48        r
49    }
50
51    /// Convenience constructor: deepseek-reasoner + messages
52    pub fn deepseek_reasoner(messages: Vec<Message>) -> Self {
53        let mut r = Self::builder();
54        r.raw.messages = messages;
55        r.raw.model = crate::raw::Model::DeepseekReasoner;
56        r
57    }
58
59    /// Add a message to the request.
60    pub fn add_message(mut self, msg: Message) -> Self {
61        self.raw.messages.push(msg);
62        self
63    }
64
65    /// Replace messages.
66    pub fn messages(mut self, msgs: Vec<Message>) -> Self {
67        self.raw.messages = msgs;
68        self
69    }
70
71    /// Request response as JSON object.
72    pub fn json(mut self) -> Self {
73        self.raw.response_format = Some(ResponseFormat {
74            r#type: ResponseFormatType::JsonObject,
75        });
76        self
77    }
78
79    /// Request response as plain text.
80    pub fn text(mut self) -> Self {
81        self.raw.response_format = Some(ResponseFormat {
82            r#type: ResponseFormatType::Text,
83        });
84        self
85    }
86
87    /// Set temperature.
88    pub fn temperature(mut self, t: f32) -> Self {
89        self.raw.temperature = Some(t);
90        self
91    }
92
93    /// Set max tokens.
94    pub fn max_tokens(mut self, n: u32) -> Self {
95        self.raw.max_tokens = Some(n);
96        self
97    }
98
99    /// Add a raw tool definition (from `crate::raw::Tool`).
100    pub fn add_tool(mut self, tool: Tool) -> Self {
101        if let Some(ref mut v) = self.raw.tools {
102            v.push(tool);
103        } else {
104            self.raw.tools = Some(vec![tool]);
105        }
106        self
107    }
108
109    /// Set tool choice to Auto.
110    pub fn tool_choice_auto(mut self) -> Self {
111        use crate::raw::request::tool_choice::{ToolChoice, ToolChoiceType};
112        self.raw.tool_choice = Some(ToolChoice::String(ToolChoiceType::Auto));
113        self
114    }
115
116    /// Enable/disable streaming (stream: true).
117    pub fn stream(mut self, enabled: bool) -> Self {
118        self.raw.stream = Some(enabled);
119        self
120    }
121
122    /// Build and return the internal raw request (crate-internal use).
123    pub(crate) fn into_raw(self) -> ChatCompletionRequest {
124        self.raw
125    }
126}