package convert import ( "encoding/json" "fmt" ) // ChatToMessages converts a Chat Completions request to Anthropic Messages format func ChatToMessages(req *ChatCompletionRequest) (*MessagesRequest, error) { msgs := make([]Message, 0, len(req.Messages)) var systemParts []ContentPart for _, m := range req.Messages { if m.Role == "system" { // Extract system message content switch v := m.Content.(type) { case string: systemParts = append(systemParts, ContentPart{ Type: "text", Text: v, }) case []interface{}: for _, part := range v { if p, ok := part.(map[string]interface{}); ok { if t, ok := p["type"].(string); ok && t == "text" { if text, ok := p["text"].(string); ok { systemParts = append(systemParts, ContentPart{ Type: "text", Text: text, }) } } } } } continue } msgs = append(msgs, m) } out := &MessagesRequest{ Model: req.Model, Messages: msgs, Stream: req.Stream, } if len(systemParts) > 0 { out.System = systemParts } if req.MaxTokens != nil { out.MaxTokens = *req.MaxTokens } else { defaultMax := 4096 out.MaxTokens = defaultMax } if req.Temperature != nil { out.Temperature = req.Temperature } if req.TopP != nil { out.TopP = req.TopP } if req.Tools != nil { out.Tools = req.Tools } return out, nil } // MessagesToChat converts an Anthropic Messages response to Chat Completions format func MessagesToChat(resp *MessagesResponse) (*ChatCompletionResponse, error) { choices := make([]Choice, 0) for _, block := range resp.Content { switch block.Type { case "text": choices = append(choices, Choice{ Index: len(choices), Message: Message{ Role: "assistant", Content: block.Text, }, FinishReason: mapStopReason(resp.StopReason), }) case "tool_use": toolCall := ToolCall{ ID: block.ID, Type: "function", Function: FunctionCall{ Name: block.Name, Arguments: toJSON(block.Input), }, } if len(choices) == 0 { choices = append(choices, Choice{ Index: 0, Message: Message{ Role: "assistant", ToolCalls: []ToolCall{toolCall}, }, FinishReason: "tool_calls", }) } else { choices[0].Message.ToolCalls = append(choices[0].Message.ToolCalls, toolCall) choices[0].FinishReason = "tool_calls" } } } if len(choices) == 0 { choices = append(choices, Choice{ Index: 0, Message: Message{ Role: "assistant", Content: "", }, FinishReason: "stop", }) } return &ChatCompletionResponse{ ID: resp.ID, Object: "chat.completion", Model: resp.Model, Choices: choices, Usage: &Usage{ PromptTokens: resp.Usage.PromptTokens, CompletionTokens: resp.Usage.CompletionTokens, TotalTokens: resp.Usage.PromptTokens + resp.Usage.CompletionTokens, }, }, nil } // MessagesStreamToChatStream converts Anthropic streaming chunks to Chat Completions format func MessagesStreamToChatStream(anthropicEvents []AnthropicStreamEvent, model string) []ChatCompletionStreamChunk { var chunks []ChatCompletionStreamChunk id := fmt.Sprintf("chatcmpl-%d", len(anthropicEvents)) for _, event := range anthropicEvents { switch event.Type { case "message_start": // Initial chunk with role chunks = append(chunks, ChatCompletionStreamChunk{ ID: id, Object: "chat.completion.chunk", Model: model, Choices: []StreamChoice{{ Index: 0, Delta: StreamDelta{ Role: "assistant", }, }}, }) case "content_block_delta": if event.Delta != nil && event.Delta.Text != "" { chunks = append(chunks, ChatCompletionStreamChunk{ ID: id, Object: "chat.completion.chunk", Model: model, Choices: []StreamChoice{{ Index: 0, Delta: StreamDelta{ Content: event.Delta.Text, }, }}, }) } case "message_delta": finishReason := "stop" if event.Delta != nil && event.Delta.StopReason != "" { finishReason = mapStopReason(event.Delta.StopReason) } chunk := ChatCompletionStreamChunk{ ID: id, Object: "chat.completion.chunk", Model: model, Choices: []StreamChoice{{ Index: 0, FinishReason: &finishReason, }}, } if event.Usage != nil { chunk.Usage = event.Usage } chunks = append(chunks, chunk) } } return chunks } func mapStopReason(reason string) string { switch reason { case "end_turn", "stop_sequence": return "stop" case "tool_use": return "tool_calls" case "max_tokens": return "length" default: return "stop" } } func toJSON(v interface{}) string { b, err := json.Marshal(v) if err != nil { return "{}" } return string(b) }