feat(llm): HTTPError -- a status code to branch on, a bounded body in the text (review F3)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-02 16:39:38 +02:00
co-authored by Claude Sonnet 5.5
parent 81f3d7ffc6
commit 2608ad2f09
+24 -1
View File
@@ -55,6 +55,29 @@ func WithMaxTokens(n int) Option {
} }
} }
// maxErrorBody bounds how much of a failing response ends up in an error message.
const maxErrorBody = 512
// HTTPError is a non-200 answer from the gateway. Its text keeps the form callers that
// log it already rely on, with the body bounded; its Code is what code may branch on and
// what errkind turns into a kind. The body is provider text and can echo the prompt, so
// nothing private may persist or display Error() (ADR-035 review F3).
type HTTPError struct {
Code int
Body string
}
func (e *HTTPError) Error() string {
body := e.Body
if len(body) > maxErrorBody {
body = body[:maxErrorBody] + "…"
}
return fmt.Sprintf("LLM returned %d: %s", e.Code, body)
}
// HTTPStatus implements errkind.HTTPStatuser.
func (e *HTTPError) HTTPStatus() int { return e.Code }
// WithTemperature overrides the sampling temperature. Zero IS a valid value and is sent // WithTemperature overrides the sampling temperature. Zero IS a valid value and is sent
// as zero: the reconciler's accuracy was measured at temperature 0 and must run there. // as zero: the reconciler's accuracy was measured at temperature 0 and must run there.
func WithTemperature(t float64) Option { func WithTemperature(t float64) Option {
@@ -166,7 +189,7 @@ func (c *Client) Complete(ctx context.Context, system, user string) (string, err
return "", fmt.Errorf("read response: %w", err) return "", fmt.Errorf("read response: %w", err)
} }
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("LLM returned %d: %s", resp.StatusCode, out) return "", &HTTPError{Code: resp.StatusCode, Body: string(out)}
} }
var cr chatResponse var cr chatResponse