Merge pull request #7635 from wucm667/fix/issue-7629-responses-message-type

fix(apicompat): mark converted Chat role items as Responses messages
This commit is contained in:
Wesley Liddick
2026-09-28 09:50:34 +08:00
committed by GitHub
3 changed files with 54 additions and 4 deletions
@@ -92,6 +92,56 @@ func TestChatCompletionsToResponses_SystemMessage(t *testing.T) {
assert.Equal(t, "user", items[1].Role)
}
func TestChatCompletionsToResponses_MessageTypesWithReasoningAndTools(t *testing.T) {
req := &ChatCompletionsRequest{
Model: "step-5-preview",
Messages: []ChatMessage{
{Role: "system", Content: json.RawMessage(`"You are helpful."`)},
{Role: "user", Content: json.RawMessage(`"Check the directory"`)},
{
Role: "assistant",
Content: json.RawMessage(`"I will check."`),
ReasoningContent: "Need to inspect the directory.",
ToolCalls: []ChatToolCall{{
ID: "call_1", Type: "function",
Function: ChatFunctionCall{Name: "bash", Arguments: `{"cmd":"pwd"}`},
}},
},
{Role: "tool", ToolCallID: "call_1", Content: json.RawMessage(`"/tmp"`)},
{Role: "assistant", ReasoningContent: "The tool returned /tmp."},
{Role: "user", Content: json.RawMessage(`"Continue"`)},
},
}
resp, err := ChatCompletionsToResponses(req)
require.NoError(t, err)
var items []ResponsesInputItem
require.NoError(t, json.Unmarshal(resp.Input, &items))
require.Len(t, items, 7)
for i, want := range []struct{ typ, role string }{
{"message", "system"},
{"message", "user"},
{"message", "assistant"},
{"function_call", ""},
{"function_call_output", ""},
{"message", "assistant"},
{"message", "user"},
} {
assert.Equal(t, want.typ, items[i].Type, "input item %d type", i)
assert.Equal(t, want.role, items[i].Role, "input item %d role", i)
}
var assistantContent, reasoningOnlyContent []ResponsesContentPart
require.NoError(t, json.Unmarshal(items[2].Content, &assistantContent))
require.NoError(t, json.Unmarshal(items[5].Content, &reasoningOnlyContent))
require.Len(t, assistantContent, 1)
require.Len(t, reasoningOnlyContent, 1)
assert.Equal(t, "<thinking>Need to inspect the directory.</thinking>\nI will check.", assistantContent[0].Text)
assert.Equal(t, "<thinking>The tool returned /tmp.</thinking>", reasoningOnlyContent[0].Text)
assert.Equal(t, "call_1", items[3].CallID)
assert.Equal(t, "call_1", items[4].CallID)
}
func TestChatCompletionsToResponses_ToolCalls(t *testing.T) {
req := &ChatCompletionsRequest{
Model: "gpt-4o",
@@ -143,7 +143,7 @@ func chatSystemToResponses(m ChatMessage) ([]ResponsesInputItem, error) {
if err != nil {
return nil, err
}
return []ResponsesInputItem{{Role: "system", Content: content}}, nil
return []ResponsesInputItem{{Type: "message", Role: "system", Content: content}}, nil
}
// chatUserToResponses converts a user message, handling both plain strings and
@@ -157,7 +157,7 @@ func chatUserToResponses(m ChatMessage) ([]ResponsesInputItem, error) {
if err != nil {
return nil, err
}
return []ResponsesInputItem{{Role: "user", Content: content}}, nil
return []ResponsesInputItem{{Type: "message", Role: "user", Content: content}}, nil
}
// chatAssistantToResponses converts an assistant message. If there is both
@@ -192,7 +192,7 @@ func chatAssistantToResponses(m ChatMessage) ([]ResponsesInputItem, error) {
if err != nil {
return nil, err
}
items = append(items, ResponsesInputItem{Role: "assistant", Content: partsJSON})
items = append(items, ResponsesInputItem{Type: "message", Role: "assistant", Content: partsJSON})
}
// Emit one function_call item per tool_call.
+1 -1
View File
@@ -263,7 +263,7 @@ type ResponsesText struct {
// The Type field determines which other fields are populated.
type ResponsesInputItem struct {
// Common
Type string `json:"type,omitempty"` // "" for role-based messages
Type string `json:"type,omitempty"` // "message" for role-based messages
// Role-based messages (developer/system/user/assistant)
Role string `json:"role,omitempty"`