buildGatewayChoices builds ModelChoice entries from the models served by the configured gateway, deduplicated against the explicitly configured models. The second return value reports whether discovery succeeded; when false (gateway unreachable, /v1/models unsupported, or an empty list that gives no
(ctx context.Context)
| 93 | // list that gives no usable signal) callers should fall back to the |
| 94 | // models.dev catalog. |
| 95 | func (r *LocalRuntime) buildGatewayChoices(ctx context.Context) ([]ModelChoice, bool) { |
| 96 | ids, err := r.listGatewayModels(ctx) |
| 97 | if err != nil { |
| 98 | slog.DebugContext(ctx, "Gateway model discovery failed, falling back to catalog", "error", err) |
| 99 | return nil, false |
| 100 | } |
| 101 | if len(ids) == 0 { |
| 102 | slog.DebugContext(ctx, "Gateway returned no models, falling back to catalog") |
| 103 | return nil, false |
| 104 | } |
| 105 | |
| 106 | existingRefs := make(map[string]bool, len(r.modelSwitcherCfg.Models)*2) |
| 107 | for name, cfg := range r.modelSwitcherCfg.Models { |
| 108 | existingRefs[name] = true |
| 109 | if cfg.Provider != "" && cfg.Model != "" { |
| 110 | existingRefs[cfg.Provider+"/"+cfg.Model] = true |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | choices := make([]ModelChoice, 0, len(ids)) |
| 115 | for _, id := range ids { |
| 116 | prov, model, ok := strings.Cut(id, "/") |
| 117 | if !ok { |
| 118 | // Bare IDs (no provider prefix) are served through the |
| 119 | // gateway's OpenAI-compatible endpoint, so route them |
| 120 | // through the openai provider. |
| 121 | prov, model = "openai", id |
| 122 | } |
| 123 | if _, err := latest.ParseModelRef(prov + "/" + model); err != nil { |
| 124 | continue |
| 125 | } |
| 126 | |
| 127 | // Resolve catalog metadata before the embedding filter so the |
| 128 | // catalog Family (e.g. "text-embedding") is consulted even when |
| 129 | // the model ID itself doesn't contain "embed". |
| 130 | var meta *modelsdev.Model |
| 131 | if r.modelsStore != nil { |
| 132 | if m, err := r.modelsStore.GetModel(ctx, modelsdev.NewID(prov, model)); err == nil { |
| 133 | meta = m |
| 134 | } |
| 135 | } |
| 136 | family := "" |
| 137 | if meta != nil { |
| 138 | family = meta.Family |
| 139 | } |
| 140 | if isEmbeddingModel(family, model) { |
| 141 | continue |
| 142 | } |
| 143 | |
| 144 | ref := prov + "/" + model |
| 145 | if existingRefs[ref] { |
| 146 | continue |
| 147 | } |
| 148 | existingRefs[ref] = true |
| 149 | |
| 150 | choice := ModelChoice{ |
| 151 | Name: model, |
| 152 | Ref: ref, |
no test coverage detected