chore(giellie): add MiniMax vision/tool-call probe
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
662610ca28
commit
0eb9653359
1 changed files with 85 additions and 0 deletions
85
scripts/smoke/giellie-vision-probe.ts
Normal file
85
scripts/smoke/giellie-vision-probe.ts
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/**
|
||||
* Probe: does the configured MiniMax endpoint accept (a) image blocks and
|
||||
* (b) tool calls, and what content-block types come back?
|
||||
*
|
||||
* Read-only against PB (reads ai_settings); makes two small LLM calls.
|
||||
*
|
||||
* Run with: npx tsx scripts/smoke/giellie-vision-probe.ts
|
||||
* Requires AI enabled + key set at /settings/ai.
|
||||
*/
|
||||
import "./_env"; // MUST be first
|
||||
import Anthropic from "@anthropic-ai/sdk";
|
||||
import { createCanvas } from "@napi-rs/canvas";
|
||||
import { getActiveAiConfig } from "../../src/lib/server/ai-settings-service";
|
||||
|
||||
async function main() {
|
||||
const cfg = await getActiveAiConfig();
|
||||
const client = new Anthropic({
|
||||
apiKey: cfg.apiKey,
|
||||
...(cfg.baseUrl ? { baseURL: cfg.baseUrl } : {}),
|
||||
});
|
||||
console.log(`[probe] model=${cfg.modelId} baseUrl=${cfg.baseUrl || "(default)"}`);
|
||||
|
||||
// (a) Vision: render "PRICE 4471" to a PNG and ask for the number.
|
||||
const canvas = createCanvas(400, 120);
|
||||
const ctx = canvas.getContext("2d");
|
||||
ctx.fillStyle = "#fff";
|
||||
ctx.fillRect(0, 0, 400, 120);
|
||||
ctx.fillStyle = "#000";
|
||||
ctx.font = "48px sans-serif";
|
||||
ctx.fillText("PRICE 4471", 20, 75);
|
||||
const png = canvas.toBuffer("image/png").toString("base64");
|
||||
|
||||
try {
|
||||
const res = await client.messages.create({
|
||||
model: cfg.modelId,
|
||||
max_tokens: 1024,
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "image", source: { type: "base64", media_type: "image/png", data: png } },
|
||||
{ type: "text", text: "What number is written in the image? Reply with just the number." },
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
const text = res.content.map((b) => (b.type === "text" ? b.text : "")).join("");
|
||||
const types = res.content.map((b) => b.type).join(",");
|
||||
console.log(`[probe] VISION block types=[${types}] answer=${JSON.stringify(text.trim())}`);
|
||||
console.log(text.includes("4471") ? "[probe] VISION: PASS" : "[probe] VISION: FAIL (answer wrong)");
|
||||
} catch (e) {
|
||||
console.log("[probe] VISION: FAIL (request rejected):", e instanceof Error ? e.message : e);
|
||||
}
|
||||
|
||||
// (b) Tool calling.
|
||||
try {
|
||||
const res = await client.messages.create({
|
||||
model: cfg.modelId,
|
||||
max_tokens: 1024,
|
||||
tools: [
|
||||
{
|
||||
name: "orders__get",
|
||||
description: "Get an order by order number.",
|
||||
input_schema: {
|
||||
type: "object",
|
||||
properties: { order_number: { type: "string" } },
|
||||
required: ["order_number"],
|
||||
},
|
||||
},
|
||||
],
|
||||
messages: [{ role: "user", content: "What is the status of order 12345? Use the tool." }],
|
||||
});
|
||||
const types = res.content.map((b) => b.type).join(",");
|
||||
const tu = res.content.find((b) => b.type === "tool_use");
|
||||
console.log(`[probe] TOOLS block types=[${types}] stop_reason=${res.stop_reason}`);
|
||||
console.log(tu ? `[probe] TOOLS: PASS input=${JSON.stringify((tu as { input: unknown }).input)}` : "[probe] TOOLS: FAIL (no tool_use)");
|
||||
} catch (e) {
|
||||
console.log("[probe] TOOLS: FAIL (request rejected):", e instanceof Error ? e.message : e);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
Loading…
Reference in a new issue