resolveVisionDescribeModel picks the provider+model used to caption images for the describe-fallback. Resolution order: 1. explicit CHATCLI_VISION_PROVIDER + CHATCLI_VISION_MODEL env override; 2. a vision-capable model on the CURRENT provider (cheapest auth-wise); 3. the first vision-capable model o
()
| 140 | // |
| 141 | // Returns ok=false when no available provider exposes a vision model. |
| 142 | func (cli *ChatCLI) resolveVisionDescribeModel() (string, string, bool) { |
| 143 | if p := strings.TrimSpace(os.Getenv("CHATCLI_VISION_PROVIDER")); p != "" { |
| 144 | if m := strings.TrimSpace(os.Getenv("CHATCLI_VISION_MODEL")); m != "" { |
| 145 | return p, m, true |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | available := cli.manager.GetAvailableProviders() |
| 150 | |
| 151 | // Prefer the current provider so we reuse already-configured credentials. |
| 152 | ordered := make([]string, 0, len(available)+1) |
| 153 | if cli.Provider != "" { |
| 154 | ordered = append(ordered, cli.Provider) |
| 155 | } |
| 156 | for _, p := range available { |
| 157 | if !strings.EqualFold(p, cli.Provider) { |
| 158 | ordered = append(ordered, p) |
| 159 | } |
| 160 | } |
| 161 | |
| 162 | for _, p := range ordered { |
| 163 | if !providerAvailable(available, p) { |
| 164 | continue |
| 165 | } |
| 166 | for _, meta := range catalog.ListByProvider(p) { |
| 167 | if metaHasVision(meta) { |
| 168 | return p, meta.ID, true |
| 169 | } |
| 170 | } |
| 171 | } |
| 172 | return "", "", false |
| 173 | } |
| 174 | |
| 175 | func providerAvailable(available []string, p string) bool { |
| 176 | for _, a := range available { |
no test coverage detected