mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-05-19 04:57:28 +08:00
responses: retry on orphan tool-call 400 with sanitized history fallback
This commit is contained in:
@@ -65,7 +65,21 @@ func (p *HTTPProvider) Chat(ctx context.Context, messages []Message, tools []Too
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if statusCode != http.StatusOK {
|
if statusCode != http.StatusOK {
|
||||||
return nil, fmt.Errorf("API error (status %d, content-type %q): %s", statusCode, contentType, previewResponseBody(body))
|
preview := previewResponseBody(body)
|
||||||
|
if statusCode == http.StatusBadRequest && strings.Contains(strings.ToLower(preview), "no tool call found for function call output") {
|
||||||
|
// Retry once with sanitized history to avoid orphaned tool outputs causing hard-fail.
|
||||||
|
safeMessages := sanitizeResponsesRetryMessages(messages)
|
||||||
|
body2, status2, ctype2, err2 := p.callResponses(ctx, safeMessages, tools, model, options)
|
||||||
|
if err2 == nil && status2 == http.StatusOK && json.Valid(body2) {
|
||||||
|
logger.InfoCF("provider", "Recovered responses 400 by sanitizing tool outputs", map[string]interface{}{"messages_before": len(messages), "messages_after": len(safeMessages)})
|
||||||
|
return parseResponsesAPIResponse(body2)
|
||||||
|
}
|
||||||
|
if err2 != nil {
|
||||||
|
return nil, err2
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("API error (status %d, content-type %q): %s", status2, ctype2, previewResponseBody(body2))
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("API error (status %d, content-type %q): %s", statusCode, contentType, preview)
|
||||||
}
|
}
|
||||||
if !json.Valid(body) {
|
if !json.Valid(body) {
|
||||||
return nil, fmt.Errorf("API error (status %d, content-type %q): non-JSON response: %s", statusCode, contentType, previewResponseBody(body))
|
return nil, fmt.Errorf("API error (status %d, content-type %q): non-JSON response: %s", statusCode, contentType, previewResponseBody(body))
|
||||||
@@ -207,6 +221,22 @@ func toChatCompletionsContent(msg Message) []map[string]interface{} {
|
|||||||
return content
|
return content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sanitizeResponsesRetryMessages(messages []Message) []Message {
|
||||||
|
out := make([]Message, 0, len(messages))
|
||||||
|
for _, m := range messages {
|
||||||
|
if strings.EqualFold(strings.TrimSpace(m.Role), "tool") {
|
||||||
|
text := strings.TrimSpace(m.Content)
|
||||||
|
if text == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out = append(out, Message{Role: "user", Content: "[tool_result_fallback] " + text})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out = append(out, m)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
func toResponsesInputItems(msg Message) []map[string]interface{} {
|
func toResponsesInputItems(msg Message) []map[string]interface{} {
|
||||||
return toResponsesInputItemsWithState(msg, nil)
|
return toResponsesInputItemsWithState(msg, nil)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user