codex_convert_proxy/providers/
glm.rs1use crate::providers::trait_::Provider;
4use crate::types::chat_api::{ChatRequest, ChatResponse, ChatStreamChunk};
5
6pub struct GLMProvider;
13
14impl Default for GLMProvider {
15 fn default() -> Self {
16 Self
17 }
18}
19
20impl GLMProvider {
21 pub fn new() -> Self {
22 Self
23 }
24}
25
26impl Provider for GLMProvider {
27 fn name(&self) -> &'static str {
28 "glm"
29 }
30
31 fn chat_completions_path(&self) -> String {
32 "/chat/completions".to_string()
35 }
36
37 fn transform_request(&self, request: &mut ChatRequest) {
38 request.tools = None;
40 request.tool_choice = None;
41
42 for message in &mut request.messages {
44 if message.role == crate::types::chat_api::MessageRole::Developer {
46 message.role = crate::types::chat_api::MessageRole::User;
47 }
48 let text = message.content.as_text();
49 message.content = crate::types::chat_api::Content::String(text);
50 }
51 }
52
53 fn transform_response(&self, response: &mut ChatResponse) {
54 for choice in &mut response.choices {
56 let text = choice.message.content.as_text();
57 choice.message.content = crate::types::chat_api::Content::String(text);
58 }
59 }
60
61 fn transform_stream_chunk(&self, chunk: &mut ChatStreamChunk) {
62 for choice in &mut chunk.choices {
64 if let Some(delta) = &mut choice.delta
65 && let Some(content) = &delta.content {
66 let text = content.as_text();
67 if !text.is_empty() {
68 delta.content = Some(crate::types::chat_api::Content::String(text));
69 }
70 }
71 }
72 }
73
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use crate::types::chat_api::{ChatMessage, Content, MessageRole};
80
81 #[test]
82 fn test_glm_removes_tools() {
83 let mut request = ChatRequest {
84 model: "glm-4".to_string(),
85 messages: vec![ChatMessage {
86 role: MessageRole::User,
87 content: Content::String("Hello".to_string()),
88 name: None,
89 annotations: None,
90 tool_calls: None,
91 tool_call_id: None,
92 function_call: None,
93 refusal: None,
94 }],
95 tools: Some(vec![]),
96 tool_choice: None,
97 stream: Some(false),
98 temperature: None,
99 max_tokens: None,
100 top_p: None,
101 user: None,
102 stream_options: None,
103 frequency_penalty: None,
104 presence_penalty: None,
105 logit_bias: None,
106 logprobs: None,
107 top_logprobs: None,
108 n: None,
109 stop: None,
110 response_format: None,
111 reasoning_effort: None,
112 parallel_tool_calls: None,
113 seed: None,
114 service_tier: None,
115 web_search_options: None,
116 modalities: None,
117 prediction: None,
118 audio: None,
119 };
120
121 let provider = GLMProvider;
122 provider.transform_request(&mut request);
123
124 assert!(request.tools.is_none());
125 assert!(request.tool_choice.is_none());
126 }
127
128 #[test]
129 fn test_glm_flattens_content() {
130 let mut request = ChatRequest {
131 model: "glm-4".to_string(),
132 messages: vec![ChatMessage {
133 role: MessageRole::User,
134 content: Content::Array(vec![crate::types::chat_api::ContentBlock {
135 block_type: "text".to_string(),
136 text: Some("Hello".to_string()),
137 image_url: None,
138 input_audio: None,
139 file: None,
140 refusal: None,
141 }]),
142 name: None,
143 annotations: None,
144 tool_calls: None,
145 tool_call_id: None,
146 function_call: None,
147 refusal: None,
148 }],
149 tools: None,
150 tool_choice: None,
151 stream: Some(false),
152 temperature: None,
153 max_tokens: None,
154 top_p: None,
155 user: None,
156 stream_options: None,
157 frequency_penalty: None,
158 presence_penalty: None,
159 logit_bias: None,
160 logprobs: None,
161 top_logprobs: None,
162 n: None,
163 stop: None,
164 response_format: None,
165 reasoning_effort: None,
166 parallel_tool_calls: None,
167 seed: None,
168 service_tier: None,
169 web_search_options: None,
170 modalities: None,
171 prediction: None,
172 audio: None,
173 };
174
175 let provider = GLMProvider;
176 provider.transform_request(&mut request);
177
178 let msg = request.messages.first().unwrap();
179 assert!(matches!(msg.content, Content::String(_)));
180 assert_eq!(msg.content.as_text(), "Hello");
181 }
182}