MCPcopy Create free account
hub / github.com/QodeXcli/QodeX / callLocal

Function callLocal

src/tools/vision/vision-analyze.ts:277–332  ·  view source on GitHub ↗
(base64: string, mime: string, prompt: string)

Source from the content-addressed store, hash-verified

275}
276
277async function callLocal(base64: string, mime: string, prompt: string): Promise<string> {
278 // CRITICAL: only call this if the user has EXPLICITLY configured a vision model.
279 // Otherwise the request hits whatever text model is currently loaded in LM Studio
280 // (e.g. Qwen3-Coder, which is text-only), and the model returns a confused
281 // "I can't see images" response that LOOKS like a real analysis to the parent agent.
282 //
283 // We therefore require QODEX_LOCAL_VISION_MODEL to be set. The default LM Studio
284 // port is fine, but the model id MUST be explicit — there's no way for us to
285 // tell from the response alone whether the loaded model supports vision.
286 const explicitModel = resolveLocalVisionModel();
287 if (!explicitModel) {
288 throw new Error(
289 'Local vision backend not configured. Set QODEX_LOCAL_VISION_MODEL to the id ' +
290 'of a vision-capable model loaded in LM Studio (e.g. "qwen2.5-vl-7b" or "qwen3-vl-32b"), ' +
291 'point roles.vision at an openai-provider model, or run a vision-capable primary model. ' +
292 'Without this, requests would hit your text model and return fake analysis.',
293 );
294 }
295 const baseUrl = process.env.QODEX_LOCAL_VISION_URL ?? 'http://127.0.0.1:1234/v1';
296 const res = await fetch(`${baseUrl}/chat/completions`, {
297 method: 'POST',
298 headers: { 'Content-Type': 'application/json' },
299 body: JSON.stringify({
300 model: explicitModel,
301 max_tokens: 1024,
302 messages: [
303 {
304 role: 'user',
305 content: [
306 { type: 'text', text: prompt },
307 { type: 'image_url', image_url: { url: `data:${mime};base64,${base64}` } },
308 ],
309 },
310 ],
311 }),
312 });
313 if (!res.ok) {
314 const errText = await res.text().catch(() => '');
315 throw new Error(`Local vision backend HTTP ${res.status}: ${errText.slice(0, 300)}. Ensure a vision-capable model is loaded in LM Studio.`);
316 }
317 const body = await res.json() as { choices?: Array<{ message?: { content?: string } }> };
318 const content = body.choices?.[0]?.message?.content ?? '';
319
320 // Heuristic: if the response sounds like a text-only model apologizing about not
321 // being able to see images, treat it as a backend failure so the chain falls through.
322 // This catches the case where the user set QODEX_LOCAL_VISION_MODEL but actually
323 // a non-vision model is loaded under that id (LM Studio doesn't enforce capabilities).
324 if (looksLikeTextOnlyRefusal(content)) {
325 throw new Error(
326 `Local model '${explicitModel}' responded as if it can't see images. ` +
327 `Verify a real vision model is loaded in LM Studio (Qwen2.5-VL, Qwen3-VL, etc) — ` +
328 `the model id alone isn't enough; the loaded weights must support vision.`,
329 );
330 }
331 return content;
332}
333
334/**

Callers 1

executeMethod · 0.85

Calls 2

resolveLocalVisionModelFunction · 0.85
looksLikeTextOnlyRefusalFunction · 0.85

Tested by

no test coverage detected