|
3 | 3 | package ollama |
4 | 4 |
|
5 | 5 | import ( |
6 | | - "encoding/base64" |
7 | | - "encoding/json" |
8 | | - "strings" |
9 | | - |
10 | 6 | "github.com/maximhq/bifrost/core/schemas" |
11 | 7 | ) |
12 | 8 |
|
@@ -126,6 +122,11 @@ func ToOllamaChatRequest(bifrostReq *schemas.BifrostChatRequest) *OllamaChatRequ |
126 | 122 | if keepAlive, ok := schemas.SafeExtractStringPointer(bifrostReq.Params.ExtraParams["keep_alive"]); ok { |
127 | 123 | ollamaReq.KeepAlive = keepAlive |
128 | 124 | } |
| 125 | + |
| 126 | + // Enable thinking mode (for thinking-specific models) |
| 127 | + if think, ok := schemas.SafeExtractBoolPointer(bifrostReq.Params.ExtraParams["think"]); ok { |
| 128 | + ollamaReq.Think = think |
| 129 | + } |
129 | 130 | } |
130 | 131 |
|
131 | 132 | if hasOptions { |
@@ -153,146 +154,6 @@ func ToOllamaChatRequest(bifrostReq *schemas.BifrostChatRequest) *OllamaChatRequ |
153 | 154 | return ollamaReq |
154 | 155 | } |
155 | 156 |
|
156 | | -// convertMessagesToOllama converts Bifrost messages to Ollama format. |
157 | | -func convertMessagesToOllama(messages []schemas.ChatMessage) []OllamaMessage { |
158 | | - var ollamaMessages []OllamaMessage |
159 | | - |
160 | | - for _, msg := range messages { |
161 | | - ollamaMsg := OllamaMessage{ |
162 | | - Role: string(msg.Role), |
163 | | - } |
164 | | - |
165 | | - // Handle content |
166 | | - if msg.Content != nil { |
167 | | - if msg.Content.ContentStr != nil { |
168 | | - ollamaMsg.Content = *msg.Content.ContentStr |
169 | | - } else if msg.Content.ContentBlocks != nil { |
170 | | - var textParts []string |
171 | | - var images []string |
172 | | - |
173 | | - for _, block := range msg.Content.ContentBlocks { |
174 | | - switch block.Type { |
175 | | - case schemas.ChatContentBlockTypeText: |
176 | | - if block.Text != nil { |
177 | | - textParts = append(textParts, *block.Text) |
178 | | - } |
179 | | - case schemas.ChatContentBlockTypeImage: |
180 | | - if block.ImageURLStruct != nil { |
181 | | - // Handle image URLs - extract base64 data |
182 | | - imageData := extractBase64Image(block.ImageURLStruct.URL) |
183 | | - if imageData != "" { |
184 | | - images = append(images, imageData) |
185 | | - } |
186 | | - } |
187 | | - } |
188 | | - } |
189 | | - |
190 | | - ollamaMsg.Content = strings.Join(textParts, "\n") |
191 | | - if len(images) > 0 { |
192 | | - ollamaMsg.Images = images |
193 | | - } |
194 | | - } |
195 | | - } |
196 | | - |
197 | | - // Handle tool calls for assistant messages |
198 | | - if msg.ChatAssistantMessage != nil && msg.ChatAssistantMessage.ToolCalls != nil { |
199 | | - for _, tc := range msg.ChatAssistantMessage.ToolCalls { |
200 | | - var args map[string]interface{} |
201 | | - if tc.Function.Arguments != "" { |
202 | | - _ = json.Unmarshal([]byte(tc.Function.Arguments), &args) |
203 | | - } |
204 | | - if args == nil { |
205 | | - args = make(map[string]interface{}) |
206 | | - } |
207 | | - |
208 | | - name := "" |
209 | | - if tc.Function.Name != nil { |
210 | | - name = *tc.Function.Name |
211 | | - } |
212 | | - |
213 | | - ollamaMsg.ToolCalls = append(ollamaMsg.ToolCalls, OllamaToolCall{ |
214 | | - Function: OllamaToolCallFunction{ |
215 | | - Name: name, |
216 | | - Arguments: args, |
217 | | - }, |
218 | | - }) |
219 | | - } |
220 | | - } |
221 | | - |
222 | | - // Handle tool response messages |
223 | | - if msg.Role == schemas.ChatMessageRoleTool && msg.ChatToolMessage != nil { |
224 | | - // In Ollama, tool responses are regular messages with role "tool" |
225 | | - // The content is the tool's response |
226 | | - if msg.Content != nil && msg.Content.ContentStr != nil { |
227 | | - ollamaMsg.Content = *msg.Content.ContentStr |
228 | | - } |
229 | | - } |
230 | | - |
231 | | - ollamaMessages = append(ollamaMessages, ollamaMsg) |
232 | | - } |
233 | | - |
234 | | - return ollamaMessages |
235 | | -} |
236 | | - |
237 | | -// extractBase64Image extracts base64 data from a data URL or returns the URL as-is for base64. |
238 | | -func extractBase64Image(url string) string { |
239 | | - // Handle data URLs: data:image/jpeg;base64,/9j/4AAQ... |
240 | | - if strings.HasPrefix(url, "data:") { |
241 | | - parts := strings.SplitN(url, ",", 2) |
242 | | - if len(parts) == 2 { |
243 | | - return parts[1] // Return just the base64 data |
244 | | - } |
245 | | - } |
246 | | - |
247 | | - // If it's already base64 encoded (no prefix), return as-is |
248 | | - if isBase64(url) { |
249 | | - return url |
250 | | - } |
251 | | - |
252 | | - // For regular URLs, Ollama doesn't support them directly |
253 | | - // The caller should handle URL-to-base64 conversion if needed |
254 | | - return "" |
255 | | -} |
256 | | - |
257 | | -// isBase64 checks if a string is likely base64 encoded. |
258 | | -func isBase64(s string) bool { |
259 | | - if len(s) < 4 { |
260 | | - return false |
261 | | - } |
262 | | - _, err := base64.StdEncoding.DecodeString(s) |
263 | | - return err == nil |
264 | | -} |
265 | | - |
266 | | -// convertToolsToOllama converts Bifrost tools to Ollama format. |
267 | | -func convertToolsToOllama(tools []schemas.ChatTool) []OllamaTool { |
268 | | - var ollamaTools []OllamaTool |
269 | | - |
270 | | - for _, tool := range tools { |
271 | | - if tool.Function == nil { |
272 | | - continue |
273 | | - } |
274 | | - |
275 | | - ollamaTool := OllamaTool{ |
276 | | - Type: "function", |
277 | | - Function: OllamaToolFunction{ |
278 | | - Name: tool.Function.Name, |
279 | | - }, |
280 | | - } |
281 | | - |
282 | | - if tool.Function.Description != nil { |
283 | | - ollamaTool.Function.Description = *tool.Function.Description |
284 | | - } |
285 | | - |
286 | | - if tool.Function.Parameters != nil { |
287 | | - ollamaTool.Function.Parameters = tool.Function.Parameters |
288 | | - } |
289 | | - |
290 | | - ollamaTools = append(ollamaTools, ollamaTool) |
291 | | - } |
292 | | - |
293 | | - return ollamaTools |
294 | | -} |
295 | | - |
296 | 157 | // ToBifrostChatRequest converts an Ollama chat request to Bifrost format. |
297 | 158 | // This is used for passthrough/reverse conversion scenarios. |
298 | 159 | func (r *OllamaChatRequest) ToBifrostChatRequest() *schemas.BifrostChatRequest { |
@@ -360,88 +221,3 @@ func (r *OllamaChatRequest) ToBifrostChatRequest() *schemas.BifrostChatRequest { |
360 | 221 |
|
361 | 222 | return bifrostReq |
362 | 223 | } |
363 | | - |
364 | | -// convertMessagesFromOllama converts Ollama messages to Bifrost format. |
365 | | -func convertMessagesFromOllama(messages []OllamaMessage) []schemas.ChatMessage { |
366 | | - var bifrostMessages []schemas.ChatMessage |
367 | | - |
368 | | - for _, msg := range messages { |
369 | | - bifrostMsg := schemas.ChatMessage{ |
370 | | - Role: schemas.ChatMessageRole(msg.Role), |
371 | | - Content: &schemas.ChatMessageContent{ |
372 | | - ContentStr: &msg.Content, |
373 | | - }, |
374 | | - } |
375 | | - |
376 | | - // Handle tool calls |
377 | | - if len(msg.ToolCalls) > 0 { |
378 | | - var toolCalls []schemas.ChatAssistantMessageToolCall |
379 | | - for i, tc := range msg.ToolCalls { |
380 | | - args, _ := json.Marshal(tc.Function.Arguments) |
381 | | - toolCalls = append(toolCalls, schemas.ChatAssistantMessageToolCall{ |
382 | | - Index: uint16(i), |
383 | | - Type: schemas.Ptr("function"), |
384 | | - ID: schemas.Ptr(tc.Function.Name), |
385 | | - Function: schemas.ChatAssistantMessageToolCallFunction{ |
386 | | - Name: &tc.Function.Name, |
387 | | - Arguments: string(args), |
388 | | - }, |
389 | | - }) |
390 | | - } |
391 | | - bifrostMsg.ChatAssistantMessage = &schemas.ChatAssistantMessage{ |
392 | | - ToolCalls: toolCalls, |
393 | | - } |
394 | | - } |
395 | | - |
396 | | - // Handle images |
397 | | - if len(msg.Images) > 0 { |
398 | | - var contentBlocks []schemas.ChatContentBlock |
399 | | - |
400 | | - // Add text content if present |
401 | | - if msg.Content != "" { |
402 | | - contentBlocks = append(contentBlocks, schemas.ChatContentBlock{ |
403 | | - Type: schemas.ChatContentBlockTypeText, |
404 | | - Text: &msg.Content, |
405 | | - }) |
406 | | - } |
407 | | - |
408 | | - // Add images |
409 | | - for _, img := range msg.Images { |
410 | | - dataURL := "data:image/jpeg;base64," + img |
411 | | - contentBlocks = append(contentBlocks, schemas.ChatContentBlock{ |
412 | | - Type: schemas.ChatContentBlockTypeImage, |
413 | | - ImageURLStruct: &schemas.ChatInputImage{ |
414 | | - URL: dataURL, |
415 | | - }, |
416 | | - }) |
417 | | - } |
418 | | - |
419 | | - bifrostMsg.Content = &schemas.ChatMessageContent{ |
420 | | - ContentBlocks: contentBlocks, |
421 | | - } |
422 | | - } |
423 | | - |
424 | | - bifrostMessages = append(bifrostMessages, bifrostMsg) |
425 | | - } |
426 | | - |
427 | | - return bifrostMessages |
428 | | -} |
429 | | - |
430 | | -// convertToolsFromOllama converts Ollama tools to Bifrost format. |
431 | | -func convertToolsFromOllama(tools []OllamaTool) []schemas.ChatTool { |
432 | | - var bifrostTools []schemas.ChatTool |
433 | | - |
434 | | - for _, tool := range tools { |
435 | | - bifrostTool := schemas.ChatTool{ |
436 | | - Type: schemas.ChatToolTypeFunction, |
437 | | - Function: &schemas.ChatToolFunction{ |
438 | | - Name: tool.Function.Name, |
439 | | - Description: &tool.Function.Description, |
440 | | - Parameters: tool.Function.Parameters, |
441 | | - }, |
442 | | - } |
443 | | - bifrostTools = append(bifrostTools, bifrostTool) |
444 | | - } |
445 | | - |
446 | | - return bifrostTools |
447 | | -} |
0 commit comments