errorMessageFromBody extracts the user-facing string from a non-2xx body. hamrpass wraps errors as `{"error":{"message":...,"provider_hint":...}}`; we prefer provider_hint (providers stash the human diagnostic there), fall back to message, then to the raw first line so non-hamrpass backends still su
(b []byte)
| 443 | buf, err := json.Marshal(body) |
| 444 | if err != nil { |
| 445 | return nil, cloud.BudgetStatus{}, nil, err |
| 446 | } |
| 447 | req, err := http.NewRequestWithContext(parent, "POST", c.BaseURL+"/v1/chat/completions", bytes.NewReader(buf)) |
| 448 | if err != nil { |
| 449 | return nil, cloud.BudgetStatus{}, nil, err |
| 450 | } |
| 451 | req.Header.Set("Content-Type", "application/json") |
| 452 | req.Header.Set("Accept", "text/event-stream") |
| 453 | if c.Token != "" { |
| 454 | req.Header.Set("Authorization", cloud.AuthHeader(c.Token)) |
| 455 | } |
| 456 | resp, err := c.HTTP.Do(req) |
| 457 | if err != nil { |
| 458 | return nil, cloud.BudgetStatus{}, nil, cloud.ErrUnreachable{Err: err} |
| 459 | } |
| 460 | if resp.StatusCode == 200 { |
| 461 | return resp, cloud.BudgetStatus{}, nil, nil |
| 462 | } |
| 463 | defer resp.Body.Close() |
| 464 | switch resp.StatusCode { |