package anthropic import ( "cursor-api-proxy/internal/openai" "encoding/json" "fmt" "strings" ) type MessageParam struct { Role string `json:"role"` Content interface{} `json:"content"` } type MessagesRequest struct { Model string `json:"model"` MaxTokens int `json:"max_tokens"` Messages []MessageParam `json:"messages"` System interface{} `json:"system"` Stream bool `json:"stream"` Tools []interface{} `json:"tools"` } func systemToText(system interface{}) string { if system == nil { return "" } switch v := system.(type) { case string: return strings.TrimSpace(v) case []interface{}: var parts []string for _, p := range v { if m, ok := p.(map[string]interface{}); ok { if m["type"] == "text" { if t, ok := m["text"].(string); ok { parts = append(parts, t) } } } } return strings.Join(parts, "\n") } return "" } func anthropicBlockToText(p interface{}) string { if p == nil { return "" } switch v := p.(type) { case string: return v case map[string]interface{}: typ, _ := v["type"].(string) switch typ { case "text": if t, ok := v["text"].(string); ok { return t } case "image": if src, ok := v["source"].(map[string]interface{}); ok { srcType, _ := src["type"].(string) switch srcType { case "base64": mt, _ := src["media_type"].(string) if mt == "" { mt = "image" } return "[Image: base64 " + mt + "]" case "url": url, _ := src["url"].(string) return "[Image: " + url + "]" } } return "[Image]" case "document": title, _ := v["title"].(string) if title == "" { if src, ok := v["source"].(map[string]interface{}); ok { title, _ = src["url"].(string) } } if title != "" { return "[Document: " + title + "]" } return "[Document]" case "tool_use": name, _ := v["name"].(string) id, _ := v["id"].(string) input := v["input"] inputJSON, _ := json.Marshal(input) if inputJSON == nil { inputJSON = []byte("{}") } tag := fmt.Sprintf("\n{\"name\": \"%s\", \"arguments\": %s}\n", name, string(inputJSON)) if id != "" { tag = fmt.Sprintf("[tool_use_id=%s] ", id) + tag } return tag case "tool_result": toolUseID, _ := v["tool_use_id"].(string) content := v["content"] var contentText string switch c := content.(type) { case string: contentText = c case []interface{}: var parts []string for _, block := range c { if bm, ok := block.(map[string]interface{}); ok { if bm["type"] == "text" { if t, ok := bm["text"].(string); ok { parts = append(parts, t) } } } } contentText = strings.Join(parts, "\n") } label := "Tool result" if toolUseID != "" { label += " [id=" + toolUseID + "]" } return label + ": " + contentText } } return "" } func anthropicContentToText(content interface{}) string { switch v := content.(type) { case string: return v case []interface{}: var parts []string for _, p := range v { if t := anthropicBlockToText(p); t != "" { parts = append(parts, t) } } return strings.Join(parts, " ") } return "" } func BuildPromptFromAnthropicMessages(messages []MessageParam, system interface{}) string { var oaiMessages []interface{} systemText := systemToText(system) if systemText != "" { oaiMessages = append(oaiMessages, map[string]interface{}{ "role": "system", "content": systemText, }) } for _, m := range messages { text := anthropicContentToText(m.Content) if text == "" { continue } role := m.Role if role != "user" && role != "assistant" { role = "user" } oaiMessages = append(oaiMessages, map[string]interface{}{ "role": role, "content": text, }) } return openai.BuildPromptFromMessages(oaiMessages) }