package probe import ( "bytes" "context" "encoding/json" "fmt" "net/http" "strings" "time" ) type CompletionResult struct { Model string HTTPStatus int LatencyMs int64 Classification string Error string } func ResolveSmokeModel(requested []string, rawModels []string, profile *CapabilityProfile) (string, []string, error) { recommended := RecommendModels(requested, rawModels) for _, candidate := range recommended { if profileAllowsSmoke(profile, candidate) { return candidate, recommended, nil } } for _, rawModel := range rawModels { if strings.TrimSpace(rawModel) == "" { continue } if profileAllowsSmoke(profile, rawModel) { return rawModel, recommended, nil } } if len(rawModels) > 0 && strings.TrimSpace(rawModels[0]) != "" { return rawModels[0], recommended, nil } return "", recommended, fmt.Errorf("no smoke model available") } func SmokeCompletion(ctx context.Context, baseURL, apiKey, model string, profile *CapabilityProfile) (*CompletionResult, error) { model = strings.TrimSpace(model) if model == "" { return nil, fmt.Errorf("model is required") } path := "/v1/chat/completions" classification := "chat_completions" payload := map[string]any{ "model": model, "messages": []map[string]string{ {"role": "user", "content": "ping"}, }, "max_tokens": 8, "temperature": 0, } if profile != nil && profile.TransportProfile.SupportsOpenAIResponses { path = "/v1/responses" classification = "responses" payload = map[string]any{ "model": model, "input": "ping", } } requestURL, err := joinGatewayPath(baseURL, path) if err != nil { return nil, fmt.Errorf("resolve smoke endpoint: %w", err) } var body bytes.Buffer if err := json.NewEncoder(&body).Encode(payload); err != nil { return nil, fmt.Errorf("encode smoke payload: %w", err) } req, err := http.NewRequestWithContext(ctx, http.MethodPost, requestURL, &body) if err != nil { return nil, fmt.Errorf("build smoke request: %w", err) } req.Header.Set("Content-Type", "application/json") if token := strings.TrimSpace(apiKey); token != "" { req.Header.Set("Authorization", "Bearer "+token) } startedAt := time.Now() resp, err := (&http.Client{Timeout: 15 * time.Second}).Do(req) if err != nil { return nil, fmt.Errorf("request smoke completion: %w", err) } defer resp.Body.Close() result := &CompletionResult{ Model: model, HTTPStatus: resp.StatusCode, LatencyMs: time.Since(startedAt).Milliseconds(), Classification: classification, } if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices { result.Error = fmt.Sprintf("unexpected_status_%d", resp.StatusCode) } return result, nil } func profileAllowsSmoke(profile *CapabilityProfile, rawModel string) bool { if profile == nil || len(profile.ModelProfiles) == 0 { return true } targetRaw := strings.TrimSpace(rawModel) targetCanonical := CanonicalModelFamily(rawModel) for _, modelProfile := range profile.ModelProfiles { if strings.TrimSpace(modelProfile.RawModelID) == targetRaw || modelProfile.CanonicalModelFamily == targetCanonical { return modelProfile.SmokeChatOK } } return false }