freeloader: fix 404 tool_unsupported detection and FIFO-drain recovery

- backend: add HTTP 404 and "no endpoints found" to isToolUnsupported
  so OpenRouter 404s are correctly classified as tool_unsupported
- core: drain FIFO on error return from executeTurn so freeloader's
  resubmitted prompt (queued via fifo.in while running) is picked up

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Levi Neely 2026-04-28 18:47:34 +02:00
parent 9ce1e63788
commit c812f0882e
2 changed files with 6 additions and 1 deletions

View File

@ -987,6 +987,10 @@ func (s *agent) executeTurn(ctx context.Context, input string, handler EventHand
s.session.messages = snapMessages
}
handler(Event{Role: "error", Content: err.Error()})
// Drain one FIFO item — the turnError hook may have queued a recovery prompt.
if next, ok := s.fifo.Pop(); ok {
return next
}
return ""
}

View File

@ -159,7 +159,7 @@ func streamRequest(client *http.Client, req *http.Request, label string, parseFn
if resp.StatusCode == http.StatusBadRequest && isContextOverflow(msg) {
return nil, &ContextOverflowError{Message: fmt.Sprintf("%s HTTP %d: %s", label, resp.StatusCode, msg)}
}
if (resp.StatusCode == http.StatusBadRequest || resp.StatusCode == http.StatusUnprocessableEntity) && isToolUnsupported(msg) {
if (resp.StatusCode == http.StatusBadRequest || resp.StatusCode == http.StatusUnprocessableEntity || resp.StatusCode == http.StatusNotFound) && isToolUnsupported(msg) {
return nil, &ToolUnsupportedError{Message: fmt.Sprintf("%s HTTP %d: %s", label, resp.StatusCode, msg)}
}
return nil, fmt.Errorf("%s HTTP %d: %s", label, resp.StatusCode, msg)
@ -184,6 +184,7 @@ func isToolUnsupported(body string) bool {
"does not support function",
"tool_use is not enabled",
"not support tool",
"no endpoints found that support tool",
}
lower := strings.ToLower(body)
for _, m := range markers {