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

Method execute

src/tools/artifacts/artifact-tools.ts:325–385  ·  view source on GitHub ↗
(args: z.infer<typeof LiveArgs>, ctx: ToolContext)

Source from the content-addressed store, hash-verified

323 captureNote = cap.note;
324 }
325
326 // Ask a vision model to critique the screenshot. We reuse the vision_analyze tool so all
327 // the backend-selection + graceful "[VISION_NOT_CONFIGURED]" handling lives in one place.
328 const prompt = buildReviewPrompt({ type: manifest.type, title: manifest.title, intent: args.intent });
329 let visionAnswer = '';
330 let sawScreenshot = false;
331 if (screenshotPath) {
332 try {
333 const res = await this.visionFn({ imagePath: screenshotPath, prompt, ctx });
334 const text = typeof res.content === 'string' ? res.content : '';
335 if (res.isError || text.startsWith('[VISION_NOT_CONFIGURED]')) {
336 // Vision unavailable — we can still report runtime errors, just not a visual verdict.
337 visionAnswer = '';
338 sawScreenshot = false;
339 } else {
340 // vision_analyze prefixes every answer with `[via <backend>, <n>KB]\n\n`. That pushes the
341 // verdict token (LOOKS_GOOD/…) off the first line, so classifyVisionAnswer — which keys off
342 // the LEADING token — would misread a clean render as `unverified` and the loop would never
343 // confirm success. Strip the banner so the model's actual verdict is what gets classified.
344 visionAnswer = text.replace(/^\[via [^\]]*\]\s*/, '');
345 sawScreenshot = true;
346 }
347 } catch {
348 visionAnswer = '';
349 sawScreenshot = false;
350 }
351 }
352
353 const report = buildReviewReport({ visionAnswer, consoleErrors, pageErrors, sawScreenshot });
354
355 const out = formatReviewReport(manifest.id, version, report);
356 const notes: string[] = [];
357 if (captureNote) notes.push(captureNote);
358 if (!sawScreenshot && consoleErrors.length === 0 && pageErrors.length === 0 && screenshotPath) {
359 notes.push(
360 'No vision backend configured — captured the render but could not get a visual verdict. ' +
361 'Set QODEX_OLLAMA_VISION_MODEL / ANTHROPIC_API_KEY / OPENAI_API_KEY for one.',
362 );
363 }
364 const extra = notes.length ? '\n' + notes.map(n => `(${n})`).join('\n') : '';
365
366 return {
367 content: out + extra,
368 // `issues` + `screenshotPath` are echoed so a front-end (the bot card) can render the verdict,
369 // the concrete problems, and the rendered screenshot from this single tool result.
370 metadata: { artifactId: manifest.id, version, verdict: report.verdict, issues: report.issues, issueCount: report.issues.length, sawScreenshot, screenshotPath, title: manifest.title, type: manifest.type },
371 };
372 }
373}
374
375const LiveArgs = z.object({
376 id: z.string().optional().describe('The artifact id to serve live.'),
377 name: z.string().optional().describe('Alias for id — some models pass the artifact title here; id takes precedence.'),
378 share: z.enum(['local', 'network', 'tunnel']).optional().describe(
379 'Reach: "local" (default, localhost only) · "network" (same WiFi/LAN — teammates open ' +
380 'http://<your-ip>:port) · "tunnel" (a public https link via cloudflared/ngrok, plus LAN). ' +
381 'network/tunnel links carry a private access token, so only someone with the full URL gets in.'),
382 open: z.boolean().optional().describe(

Callers

nothing calls this directly

Calls 9

resolveArtifactIdFunction · 0.85
getArtifactFunction · 0.85
startLiveFunction · 0.85
livePortFunction · 0.85
makeAccessTokenFunction · 0.85
openUrlFunction · 0.85
liveServerNameFunction · 0.85
emitMethod · 0.45
pushMethod · 0.45

Tested by

no test coverage detected