package llm import ( "context" "encoding/json/v2" "fmt" "io" "log/slog" "net/http" ) // ListModels returns available models from the LLM server. func (c *Client) ListModels(ctx context.Context) ([]Model, error) { ctx, cancel := context.WithTimeout(ctx, c.timeout) defer cancel() req, err := http.NewRequestWithContext( ctx, http.MethodGet, c.baseURL+"/models", nil, ) if err != nil { return nil, fmt.Errorf("create request: %w", err) } if c.key != "" { req.Header.Set("Authorization", "Bearer "+c.key) } req.Header.Set("Content-Type", "application/json") res, err := c.httpc.Do(req) if err != nil { return nil, fmt.Errorf("list models: %w", err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { body, err := io.ReadAll(res.Body) if err != nil { c.log.ErrorContext( ctx, "list models: failed to read error response body", slog.Any("error", err), ) return nil, fmt.Errorf( "list models: status code %d", res.StatusCode, ) } var apiError struct { Error *APIError `json:"error"` } if err := json.Unmarshal( body, &apiError, ); err == nil && apiError.Error != nil { c.log.ErrorContext( ctx, "list models: request error", slog.Int("status", res.StatusCode), slog.String("code", apiError.Error.Code), slog.String( "message", apiError.Error.Message, ), slog.String("type", apiError.Error.Type), ) return nil, fmt.Errorf("list models: %w", apiError.Error) } c.log.ErrorContext( ctx, "list models: API error", slog.Int("status", res.StatusCode), slog.String("body", string(body)), ) return nil, fmt.Errorf( "list models: %d: %s", res.StatusCode, string(body), ) } var body ModelsResponse if err := json.UnmarshalRead(res.Body, &body); err != nil { return nil, fmt.Errorf( "list models: decode response: %w", err, ) } return body.Data, nil }