mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-05 08:55:28 +08:00
153 lines
4.2 KiB
Go
153 lines
4.2 KiB
Go
package openai
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
)
|
|
|
|
func TestBuildResponseObjectToolCallsFollowChatShape(t *testing.T) {
|
|
obj := BuildResponseObject(
|
|
"resp_test",
|
|
"gpt-4o",
|
|
"prompt",
|
|
"",
|
|
`{"tool_calls":[{"name":"search","input":{"q":"golang"}}]}`,
|
|
[]string{"search"},
|
|
)
|
|
|
|
outputText, _ := obj["output_text"].(string)
|
|
if outputText != "" {
|
|
t.Fatalf("expected output_text to be hidden for tool calls, got %q", outputText)
|
|
}
|
|
|
|
output, _ := obj["output"].([]any)
|
|
if len(output) != 1 {
|
|
t.Fatalf("expected function_call output only, got %#v", obj["output"])
|
|
}
|
|
|
|
first, _ := output[0].(map[string]any)
|
|
if first["type"] != "function_call" {
|
|
t.Fatalf("expected first output item type function_call, got %#v", first["type"])
|
|
}
|
|
if first["call_id"] == "" {
|
|
t.Fatalf("expected function_call item to have call_id, got %#v", first)
|
|
}
|
|
if first["name"] != "search" {
|
|
t.Fatalf("unexpected function name: %#v", first["name"])
|
|
}
|
|
argsRaw, _ := first["arguments"].(string)
|
|
var args map[string]any
|
|
if err := json.Unmarshal([]byte(argsRaw), &args); err != nil {
|
|
t.Fatalf("arguments should be valid json string, got=%q err=%v", argsRaw, err)
|
|
}
|
|
if args["q"] != "golang" {
|
|
t.Fatalf("unexpected arguments: %#v", args)
|
|
}
|
|
}
|
|
|
|
func TestBuildResponseObjectTreatsMixedProseToolPayloadAsToolCall(t *testing.T) {
|
|
obj := BuildResponseObject(
|
|
"resp_test",
|
|
"gpt-4o",
|
|
"prompt",
|
|
"",
|
|
`示例格式:{"tool_calls":[{"name":"search","input":{"q":"golang"}}]},但这条是普通回答。`,
|
|
[]string{"search"},
|
|
)
|
|
|
|
outputText, _ := obj["output_text"].(string)
|
|
if outputText != "" {
|
|
t.Fatalf("expected output_text hidden once tool calls are detected, got %q", outputText)
|
|
}
|
|
|
|
output, _ := obj["output"].([]any)
|
|
if len(output) != 1 {
|
|
t.Fatalf("expected function_call output only, got %#v", obj["output"])
|
|
}
|
|
first, _ := output[0].(map[string]any)
|
|
if first["type"] != "function_call" {
|
|
t.Fatalf("expected first output type function_call, got %#v", first["type"])
|
|
}
|
|
}
|
|
|
|
func TestBuildResponseObjectFencedToolPayloadRemainsText(t *testing.T) {
|
|
obj := BuildResponseObject(
|
|
"resp_test",
|
|
"gpt-4o",
|
|
"prompt",
|
|
"",
|
|
"```json\n{\"tool_calls\":[{\"name\":\"search\",\"input\":{\"q\":\"golang\"}}]}\n```",
|
|
[]string{"search"},
|
|
)
|
|
|
|
outputText, _ := obj["output_text"].(string)
|
|
if outputText == "" {
|
|
t.Fatalf("expected output_text preserved for fenced example")
|
|
}
|
|
output, _ := obj["output"].([]any)
|
|
if len(output) != 1 {
|
|
t.Fatalf("expected one message output item, got %#v", obj["output"])
|
|
}
|
|
first, _ := output[0].(map[string]any)
|
|
if first["type"] != "message" {
|
|
t.Fatalf("expected message output type, got %#v", first["type"])
|
|
}
|
|
}
|
|
|
|
func TestBuildResponseObjectReasoningOnlyFallsBackToOutputText(t *testing.T) {
|
|
obj := BuildResponseObject(
|
|
"resp_test",
|
|
"gpt-4o",
|
|
"prompt",
|
|
"internal thinking content",
|
|
"",
|
|
nil,
|
|
)
|
|
|
|
outputText, _ := obj["output_text"].(string)
|
|
if outputText == "" {
|
|
t.Fatalf("expected output_text fallback from reasoning when final text is empty")
|
|
}
|
|
|
|
output, _ := obj["output"].([]any)
|
|
if len(output) != 1 {
|
|
t.Fatalf("expected one output item, got %#v", obj["output"])
|
|
}
|
|
first, _ := output[0].(map[string]any)
|
|
if first["type"] != "message" {
|
|
t.Fatalf("expected output type message, got %#v", first["type"])
|
|
}
|
|
content, _ := first["content"].([]any)
|
|
if len(content) == 0 {
|
|
t.Fatalf("expected reasoning content, got %#v", first["content"])
|
|
}
|
|
block0, _ := content[0].(map[string]any)
|
|
if block0["type"] != "reasoning" {
|
|
t.Fatalf("expected first content block reasoning, got %#v", block0["type"])
|
|
}
|
|
}
|
|
|
|
func TestBuildResponseObjectDetectsToolCallFromThinkingChannel(t *testing.T) {
|
|
obj := BuildResponseObject(
|
|
"resp_test",
|
|
"gpt-4o",
|
|
"prompt",
|
|
`{"tool_calls":[{"name":"search","input":{"q":"from-thinking"}}]}`,
|
|
"",
|
|
[]string{"search"},
|
|
)
|
|
|
|
output, _ := obj["output"].([]any)
|
|
if len(output) != 2 {
|
|
t.Fatalf("expected reasoning + function_call outputs, got %#v", obj["output"])
|
|
}
|
|
first, _ := output[0].(map[string]any)
|
|
if first["type"] != "reasoning" {
|
|
t.Fatalf("expected first output reasoning, got %#v", first["type"])
|
|
}
|
|
second, _ := output[1].(map[string]any)
|
|
if second["type"] != "function_call" {
|
|
t.Fatalf("expected second output function_call, got %#v", second["type"])
|
|
}
|
|
}
|