vv_agent/
model_settings.rs1use std::collections::BTreeMap;
2use std::time::Duration;
3
4use serde::{Deserialize, Serialize};
5use serde_json::{Map, Value};
6
7#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
8pub struct ModelSettings {
9 pub temperature: Option<f32>,
10 pub top_p: Option<f32>,
11 pub max_output_tokens: Option<u32>,
12 pub tool_choice: Option<ToolChoice>,
13 pub parallel_tool_calls: Option<bool>,
14 pub reasoning: Option<Value>,
15 pub response_format: Option<ResponseFormat>,
16 #[serde(skip)]
17 pub timeout: Option<Duration>,
18 pub retry: Option<RetryPolicy>,
19 pub extra_headers: BTreeMap<String, String>,
20 pub extra_body: Map<String, Value>,
21}
22
23impl ModelSettings {
24 pub fn builder() -> ModelSettingsBuilder {
25 ModelSettingsBuilder::default()
26 }
27
28 pub fn merge(&self, override_settings: &ModelSettings) -> ModelSettings {
29 let mut merged = self.clone();
30 if override_settings.temperature.is_some() {
31 merged.temperature = override_settings.temperature;
32 }
33 if override_settings.top_p.is_some() {
34 merged.top_p = override_settings.top_p;
35 }
36 if override_settings.max_output_tokens.is_some() {
37 merged.max_output_tokens = override_settings.max_output_tokens;
38 }
39 if override_settings.tool_choice.is_some() {
40 merged.tool_choice = override_settings.tool_choice.clone();
41 }
42 if override_settings.parallel_tool_calls.is_some() {
43 merged.parallel_tool_calls = override_settings.parallel_tool_calls;
44 }
45 if override_settings.reasoning.is_some() {
46 merged.reasoning = override_settings.reasoning.clone();
47 }
48 if override_settings.response_format.is_some() {
49 merged.response_format = override_settings.response_format.clone();
50 }
51 if override_settings.timeout.is_some() {
52 merged.timeout = override_settings.timeout;
53 }
54 if override_settings.retry.is_some() {
55 merged.retry = override_settings.retry.clone();
56 }
57 merged
58 .extra_headers
59 .extend(override_settings.extra_headers.clone());
60 merged
61 .extra_body
62 .extend(override_settings.extra_body.clone());
63 merged
64 }
65
66 pub fn to_value(&self) -> Value {
67 serde_json::to_value(self).unwrap_or(Value::Null)
68 }
69}
70
71#[derive(Debug, Clone, Default)]
72pub struct ModelSettingsBuilder {
73 settings: ModelSettings,
74}
75
76impl ModelSettingsBuilder {
77 pub fn temperature(mut self, temperature: f32) -> Self {
78 self.settings.temperature = Some(temperature);
79 self
80 }
81
82 pub fn top_p(mut self, top_p: f32) -> Self {
83 self.settings.top_p = Some(top_p);
84 self
85 }
86
87 pub fn max_output_tokens(mut self, max_output_tokens: u32) -> Self {
88 self.settings.max_output_tokens = Some(max_output_tokens);
89 self
90 }
91
92 pub fn tool_choice(mut self, tool_choice: ToolChoice) -> Self {
93 self.settings.tool_choice = Some(tool_choice);
94 self
95 }
96
97 pub fn parallel_tool_calls(mut self, parallel_tool_calls: bool) -> Self {
98 self.settings.parallel_tool_calls = Some(parallel_tool_calls);
99 self
100 }
101
102 pub fn reasoning(mut self, reasoning: Value) -> Self {
103 self.settings.reasoning = Some(reasoning);
104 self
105 }
106
107 pub fn response_format(mut self, response_format: ResponseFormat) -> Self {
108 self.settings.response_format = Some(response_format);
109 self
110 }
111
112 pub fn timeout(mut self, timeout: Duration) -> Self {
113 self.settings.timeout = Some(timeout);
114 self
115 }
116
117 pub fn retry(mut self, retry: RetryPolicy) -> Self {
118 self.settings.retry = Some(retry);
119 self
120 }
121
122 pub fn extra_header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
123 self.settings.extra_headers.insert(key.into(), value.into());
124 self
125 }
126
127 pub fn extra_body(mut self, key: impl Into<String>, value: Value) -> Self {
128 self.settings.extra_body.insert(key.into(), value);
129 self
130 }
131
132 pub fn build(self) -> ModelSettings {
133 self.settings
134 }
135}
136
137#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
138#[serde(rename_all = "snake_case")]
139pub enum ToolChoice {
140 Auto,
141 None,
142 Required,
143 Tool(String),
144}
145
146#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
147#[serde(tag = "type", rename_all = "snake_case")]
148pub enum ResponseFormat {
149 Text,
150 JsonObject,
151 JsonSchema { schema: Value },
152}
153
154#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
155pub struct RetryPolicy {
156 pub max_retries: u32,
157}
158
159impl RetryPolicy {
160 pub fn new(max_retries: u32) -> Self {
161 Self { max_retries }
162 }
163}