Send an OpenAI-compatible vision request to the user's configured provider (Gemini's * OpenAI endpoint, OpenRouter, a custom-baseURL openai, …) whose primary/sub-agent model * can see. This is the "you already configured a vision-capable model — use it" backend.
(base64: string, mime: string, prompt: string)
| 340 | * OpenAI endpoint, OpenRouter, a custom-baseURL openai, …) whose primary/sub-agent model |
| 341 | * can see. This is the "you already configured a vision-capable model — use it" backend. */ |
| 342 | async function callConfigured(base64: string, mime: string, prompt: string): Promise<string> { |
| 343 | const v = resolveConfiguredVisionModel(); |
| 344 | if (!v) throw new Error('No configured vision-capable model (primary/sub-agent is text-only or its provider has no key).'); |
| 345 | const res = await fetch(`${v.baseUrl}/chat/completions`, { |
| 346 | method: 'POST', |
| 347 | headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${v.apiKey}`, 'User-Agent': 'qodex-cli' }, |
| 348 | body: JSON.stringify({ |
| 349 | model: v.model, |
| 350 | max_tokens: 1024, |
| 351 | messages: [{ role: 'user', content: [ |
| 352 | { type: 'text', text: prompt }, |
| 353 | { type: 'image_url', image_url: { url: `data:${mime};base64,${base64}` } }, |
| 354 | ] }], |
| 355 | }), |
| 356 | }); |
| 357 | if (!res.ok) { |
| 358 | const t = await res.text().catch(() => ''); |
| 359 | throw new Error(`Configured vision backend HTTP ${res.status}: ${t.slice(0, 300)}`); |
| 360 | } |
| 361 | const body = await res.json() as { choices?: Array<{ message?: { content?: string } }> }; |
| 362 | const content = body.choices?.[0]?.message?.content ?? ''; |
| 363 | if (looksLikeTextOnlyRefusal(content)) { |
| 364 | throw new Error(`Configured model '${v.model}' responded as if it can't see images — its weights may be text-only despite the id.`); |
| 365 | } |
| 366 | return content; |
| 367 | } |
| 368 | |
| 369 | function looksLikeTextOnlyRefusal(text: string): boolean { |
| 370 | const lower = text.toLowerCase(); |
no test coverage detected