fix(providers): normalize OpenAI responses terminal statuses
Treat padded failed and incomplete statuses consistently so responses parsing preserves server errors and finish reasons instead of misclassifying terminal responses.
This commit is contained in:
parent
8b64a99131
commit
d12fa3bfbc
2 changed files with 31 additions and 8 deletions
|
|
@ -691,6 +691,13 @@ func parseResponsesResponse(body io.Reader) (*LLMResponse, error) {
|
|||
if len(apiResponse.Output) == 0 {
|
||||
return nil, errors.New("openai responses returned terminal status with empty output")
|
||||
}
|
||||
case "failed":
|
||||
if apiResponse.Error != nil {
|
||||
if msg := strings.TrimSpace(apiResponse.Error.Message); msg != "" {
|
||||
return nil, errors.New(msg)
|
||||
}
|
||||
}
|
||||
return nil, errors.New("openai responses request failed")
|
||||
default:
|
||||
return nil, fmt.Errorf("openai responses returned unexpected or non-terminal status: %q", status)
|
||||
}
|
||||
|
|
@ -760,17 +767,10 @@ func parseResponsesResponse(body io.Reader) (*LLMResponse, error) {
|
|||
}
|
||||
}
|
||||
|
||||
if apiResponse.Status == "failed" {
|
||||
if apiResponse.Error != nil && apiResponse.Error.Message != "" {
|
||||
return nil, errors.New(apiResponse.Error.Message)
|
||||
}
|
||||
return nil, errors.New("openai responses request failed")
|
||||
}
|
||||
|
||||
finishReason := "stop"
|
||||
if len(toolCalls) > 0 {
|
||||
finishReason = "tool_calls"
|
||||
} else if apiResponse.Status == "incomplete" {
|
||||
} else if status == "incomplete" {
|
||||
finishReason = "length"
|
||||
if apiResponse.IncompleteDetails != nil && apiResponse.IncompleteDetails.Reason != "" && apiResponse.IncompleteDetails.Reason != "max_output_tokens" {
|
||||
finishReason = apiResponse.IncompleteDetails.Reason
|
||||
|
|
|
|||
|
|
@ -556,6 +556,29 @@ func TestProviderChat_ParsesRefusalFromResponses(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestParseResponsesResponse_FailedStatusUsesServerMessage(t *testing.T) {
|
||||
_, err := parseResponsesResponse(strings.NewReader(`{"status":" failed ","error":{"message":"responses failed"}}`))
|
||||
if err == nil {
|
||||
t.Fatal("expected error, got nil")
|
||||
}
|
||||
if err.Error() != "responses failed" {
|
||||
t.Fatalf("error = %q, want %q", err.Error(), "responses failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseResponsesResponse_UsesNormalizedIncompleteStatus(t *testing.T) {
|
||||
out, err := parseResponsesResponse(strings.NewReader(`{"status":" incomplete ","output":[{"type":"message","content":[{"type":"output_text","text":"partial answer"}]}],"incomplete_details":{"reason":"content_filter"}}`))
|
||||
if err != nil {
|
||||
t.Fatalf("parseResponsesResponse() error = %v", err)
|
||||
}
|
||||
if out.Content != "partial answer" {
|
||||
t.Fatalf("Content = %q, want %q", out.Content, "partial answer")
|
||||
}
|
||||
if out.FinishReason != "content_filter" {
|
||||
t.Fatalf("FinishReason = %q, want %q", out.FinishReason, "content_filter")
|
||||
}
|
||||
}
|
||||
|
||||
func TestProviderChat_UsesMaxCompletionTokensForGLM(t *testing.T) {
|
||||
var requestBody map[string]any
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue