package convert import ( "encoding/json" "errors" "openteam/server/internal/proxy/openai" ) // responsesInputToChat converts Responses API input items into chat messages. func responsesInputToChat(raw json.RawMessage) ([]openai.ChatMessage, error) { var msgs []openai.ChatMessage // `input` may be a plain string. var s string if json.Unmarshal(raw, &s) == nil { content, _ := json.Marshal(s) msgs = append(msgs, openai.ChatMessage{Role: "user", Content: content}) return msgs, nil } // Or an array of content parts (text/image). var parts []map[string]json.RawMessage if json.Unmarshal(raw, &parts) == nil { chat, err := contentPartsToChat(parts) if err == nil { return chat, nil } } var items []map[string]json.RawMessage if err := json.Unmarshal(raw, &items); err != nil { return nil, err } for _, item := range items { var typ string _ = json.Unmarshal(item["type"], &typ) switch typ { case "message": var role string _ = json.Unmarshal(item["role"], &role) content, err := contentPartsToText(item["content"]) if err != nil { continue } msgs = append(msgs, openai.ChatMessage{Role: role, Content: content}) case "function_call": tc := map[string]any{ "id": rawString(item["call_id"]), "type": "function", "function": map[string]any{ "name": rawString(item["name"]), "arguments": rawString(item["arguments"]), }, } tcArr, _ := json.Marshal([]any{tc}) msgs = append(msgs, openai.ChatMessage{Role: "assistant", ToolCalls: tcArr}) case "function_call_output": content, _ := json.Marshal(rawString(item["output"])) msgs = append(msgs, openai.ChatMessage{Role: "tool", ToolCallID: rawString(item["call_id"]), Content: content}) case "reasoning", "computer_call", "web_search_call": // Not representable in chat; drop. } } if len(msgs) == 0 { content, _ := json.Marshal("") msgs = append(msgs, openai.ChatMessage{Role: "user", Content: content}) } return msgs, nil } // contentPartsToText flattens an array of content parts into a string. func contentPartsToText(raw json.RawMessage) (json.RawMessage, error) { var parts []map[string]json.RawMessage if err := json.Unmarshal(raw, &parts); err != nil { var s string if err := json.Unmarshal(raw, &s); err == nil { c, _ := json.Marshal(s) return c, nil } return nil, err } var buf string for _, p := range parts { var typ string _ = json.Unmarshal(p["type"], &typ) switch typ { case "input_text", "output_text", "text": buf += rawString(p["text"]) } } c, _ := json.Marshal(buf) return c, nil } func contentPartsToChat(parts []map[string]json.RawMessage) ([]openai.ChatMessage, error) { out := []map[string]any{} for _, p := range parts { var typ string _ = json.Unmarshal(p["type"], &typ) switch typ { case "input_text", "output_text", "text": out = append(out, map[string]any{"type": "text", "text": rawString(p["text"])}) case "input_image": out = append(out, map[string]any{ "type": "image_url", "image_url": map[string]any{ "url": "data:" + rawString(p["media_type"]) + ";base64," + rawString(p["image_url"]), }, }) } } if len(out) == 0 { return nil, jsonError("empty content") } arr, _ := json.Marshal(out) msg := openai.ChatMessage{Role: "user", Content: arr} return []openai.ChatMessage{msg}, nil } // chatToResponsesOutput builds Responses output items from a chat completion. func chatToResponsesOutput(cc *openai.ChatCompletion) ([]map[string]any, string) { var items []map[string]any var status = "completed" if len(cc.Choices) == 0 { return items, status } ch := cc.Choices[0] if ch.FinishReason == "length" { status = "incomplete" } content := []map[string]any{} if text := contentString(ch.Message.Content); text != "" { content = append(content, map[string]any{"type": "output_text", "text": text}) } items = append(items, map[string]any{"type": "message", "role": "assistant", "content": content}) if len(ch.Message.ToolCalls) > 0 { var calls []struct { ID string `json:"id"` Function struct { Name string `json:"name"` Arguments json.RawMessage `json:"arguments"` } `json:"function"` } if json.Unmarshal(ch.Message.ToolCalls, &calls) == nil { for _, call := range calls { items = append(items, map[string]any{ "type": "function_call", "call_id": call.ID, "name": call.Function.Name, "arguments": rawString(call.Function.Arguments), }) } } } return items, status } func jsonError(msg string) error { return errors.New(msg) }