package openai import ( "encoding/json" "strings" "ds2api/internal/prompt" ) func normalizeOpenAIMessagesForPrompt(raw []any, traceID string) []map[string]any { _ = traceID out := make([]map[string]any, 0, len(raw)) for _, item := range raw { msg, ok := item.(map[string]any) if !ok { continue } role := strings.ToLower(strings.TrimSpace(asString(msg["role"]))) switch role { case "assistant": content := normalizeOpenAIContentForPrompt(msg["content"]) if content == "" { continue } out = append(out, map[string]any{ "role": "assistant", "content": content, }) case "tool", "function": content := normalizeOpenAIContentForPrompt(msg["content"]) if content == "" { content = "null" } out = append(out, map[string]any{ "role": "user", "content": content, }) case "user", "system", "developer": out = append(out, map[string]any{ "role": normalizeOpenAIRoleForPrompt(role), "content": normalizeOpenAIContentForPrompt(msg["content"]), }) default: content := normalizeOpenAIContentForPrompt(msg["content"]) if content == "" { continue } if role == "" { role = "user" } out = append(out, map[string]any{ "role": normalizeOpenAIRoleForPrompt(role), "content": content, }) } } return out } func normalizeOpenAIContentForPrompt(v any) string { return prompt.NormalizeContent(v) } func normalizeToolArgumentString(raw string) string { trimmed := strings.TrimSpace(raw) if trimmed == "" { return "" } if looksLikeConcatenatedJSON(trimmed) { // Keep original payload to avoid silent argument rewrites. return raw } return trimmed } func normalizeOpenAIRoleForPrompt(role string) string { role = strings.ToLower(strings.TrimSpace(role)) if role == "developer" { return "system" } return role } func asString(v any) string { if s, ok := v.(string); ok { return s } return "" } func looksLikeConcatenatedJSON(raw string) bool { trimmed := strings.TrimSpace(raw) if trimmed == "" { return false } if strings.Contains(trimmed, "}{") || strings.Contains(trimmed, "][") { return true } dec := json.NewDecoder(strings.NewReader(trimmed)) var first any if err := dec.Decode(&first); err != nil { return false } var second any return dec.Decode(&second) == nil }