package promptcompat import ( "fmt" "strings" ) func ResponsesMessagesFromRequest(req map[string]any) []any { if msgs, ok := req["messages"].([]any); ok && len(msgs) > 0 { return prependInstructionMessage(msgs, req["instructions"]) } if rawInput, ok := req["input"]; ok { if msgs := NormalizeResponsesInputAsMessages(rawInput); len(msgs) > 0 { return prependInstructionMessage(msgs, req["instructions"]) } } return nil } func prependInstructionMessage(messages []any, instructions any) []any { sys, _ := instructions.(string) sys = strings.TrimSpace(sys) if sys == "" { return messages } out := make([]any, 0, len(messages)+1) out = append(out, map[string]any{"role": "system", "content": sys}) out = append(out, messages...) return out } func NormalizeResponsesInputAsMessages(input any) []any { switch v := input.(type) { case string: if strings.TrimSpace(v) == "" { return nil } return []any{map[string]any{"role": "user", "content": v}} case []any: return normalizeResponsesInputArray(v) case map[string]any: if msg := normalizeResponsesInputItem(v); msg != nil { return []any{msg} } if txt, _ := v["text"].(string); strings.TrimSpace(txt) != "" { return []any{map[string]any{"role": "user", "content": txt}} } if content, ok := v["content"]; ok { if strings.TrimSpace(NormalizeOpenAIContentForPrompt(content)) != "" { return []any{map[string]any{"role": "user", "content": content}} } } } return nil } func normalizeResponsesInputArray(items []any) []any { if len(items) == 0 { return nil } out := make([]any, 0, len(items)) callNameByID := map[string]string{} fallbackParts := make([]string, 0, len(items)) pendingAssistantReasoning := "" flushFallback := func() { if len(fallbackParts) == 0 { return } if pendingAssistantReasoning != "" { out = append(out, map[string]any{"role": "assistant", "reasoning_content": pendingAssistantReasoning}) pendingAssistantReasoning = "" } out = append(out, map[string]any{"role": "user", "content": strings.Join(fallbackParts, "\n")}) fallbackParts = fallbackParts[:0] } flushPendingReasoning := func() { if pendingAssistantReasoning == "" { return } out = append(out, map[string]any{"role": "assistant", "reasoning_content": pendingAssistantReasoning}) pendingAssistantReasoning = "" } for _, item := range items { switch x := item.(type) { case map[string]any: if msg := normalizeResponsesInputItemWithState(x, callNameByID); msg != nil { if reasoning := assistantReasoningOnlyContent(msg); reasoning != "" { if pendingAssistantReasoning == "" { pendingAssistantReasoning = reasoning } else { pendingAssistantReasoning += "\n" + reasoning } continue } if isAssistantToolCallMessage(msg) && pendingAssistantReasoning != "" { if strings.TrimSpace(normalizeOpenAIReasoningContentForPrompt(msg["reasoning_content"])) == "" { msg["reasoning_content"] = pendingAssistantReasoning } pendingAssistantReasoning = "" } else { flushPendingReasoning() } flushFallback() if isAssistantToolCallMessage(msg) && len(out) > 0 { if merged := mergeResponsesAssistantToolCalls(out[len(out)-1], msg); merged { continue } } out = append(out, msg) continue } if s := normalizeResponsesFallbackPart(x); s != "" { fallbackParts = append(fallbackParts, s) } default: if s := strings.TrimSpace(fmt.Sprintf("%v", item)); s != "" { fallbackParts = append(fallbackParts, s) } } } flushPendingReasoning() flushFallback() if len(out) == 0 { return nil } return out } func assistantReasoningOnlyContent(msg map[string]any) string { if !isAssistantMessage(msg) || isAssistantToolCallMessage(msg) { return "" } if _, hasContent := msg["content"]; hasContent { normalizedContent := strings.TrimSpace(NormalizeOpenAIContentForPrompt(msg["content"])) reasoningFromContent := strings.TrimSpace(extractOpenAIReasoningContentFromMessage(msg["content"])) if normalizedContent != "" && normalizedContent != reasoningFromContent { return "" } if reasoningFromContent != "" { return reasoningFromContent } } return strings.TrimSpace(normalizeOpenAIReasoningContentForPrompt(msg["reasoning_content"])) } func isAssistantMessage(msg map[string]any) bool { return strings.EqualFold(strings.TrimSpace(asString(msg["role"])), "assistant") } func isAssistantToolCallMessage(msg map[string]any) bool { if !isAssistantMessage(msg) { return false } toolCalls, ok := msg["tool_calls"].([]any) return ok && len(toolCalls) > 0 } func mergeResponsesAssistantToolCalls(prev any, next map[string]any) bool { prevMsg, ok := prev.(map[string]any) if !ok || !isAssistantToolCallMessage(prevMsg) || !isAssistantToolCallMessage(next) { return false } prevCalls, _ := prevMsg["tool_calls"].([]any) nextCalls, _ := next["tool_calls"].([]any) prevMsg["tool_calls"] = append(prevCalls, nextCalls...) if strings.TrimSpace(normalizeOpenAIReasoningContentForPrompt(prevMsg["reasoning_content"])) == "" { if reasoning := strings.TrimSpace(normalizeOpenAIReasoningContentForPrompt(next["reasoning_content"])); reasoning != "" { prevMsg["reasoning_content"] = reasoning } } return true }