123 lines
4.3 KiB
JavaScript
123 lines
4.3 KiB
JavaScript
// Capability probe for the user's configured third-party models.
|
|
// For each model: (1) vision probe — send a tiny PNG via image_url; if the
|
|
// API accepts image content the call succeeds. (2) thinking probes — send
|
|
// three wire-dialect hints (reasoning_effort, enable_thinking, thinking.type)
|
|
// and report which are accepted and whether reasoning_content comes back.
|
|
import { readFileSync } from "node:fs";
|
|
|
|
const cred = readFileSync("C:/Users/12914/.dsh/.credentials.yaml", "utf8");
|
|
function keyFor(name) {
|
|
const m = cred.match(new RegExp(`${name}:\\s*([^\\s]+)`));
|
|
return m ? m[1] : "";
|
|
}
|
|
// refs section: " B_API_KEY: sk-..."
|
|
function refKey(name) {
|
|
const m = cred.match(new RegExp(`\\s${name}: ([^\\s]+)`));
|
|
return m ? m[1] : "";
|
|
}
|
|
|
|
const TINY_PNG = "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAFklEQVR42mP8z8AAw0BowY0wxx1jGQDFmA1jJ0nK1AAAAABJRU5ErkJggg==";
|
|
|
|
const providers = [
|
|
{
|
|
name: "b",
|
|
base: "http://156.225.30.43:65423/bai/v1",
|
|
key: refKey("B_API_KEY"),
|
|
models: ["glm-5.3-flash", "qwen3.8-flash", "hy3", "mimo-v2.5"]
|
|
},
|
|
{
|
|
name: "command-code",
|
|
base: "https://api.commandcode.ai/provider/v1",
|
|
key: refKey("COMMAND_CODE_API_KEY"),
|
|
models: [
|
|
"deepseek/deepseek-v4-flash",
|
|
"z-ai/glm-5.3-flash",
|
|
"xiaomi/mimo-v2.5",
|
|
"meituan/LongCat-2.0:free",
|
|
"poolside/laguna-s-2.1-free"
|
|
]
|
|
}
|
|
];
|
|
|
|
async function chat(base, key, body, timeoutMs = 45000) {
|
|
const ctl = new AbortController();
|
|
const t = setTimeout(() => ctl.abort(), timeoutMs);
|
|
try {
|
|
const r = await fetch(`${base}/chat/completions`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${key}` },
|
|
body: JSON.stringify(body),
|
|
signal: ctl.signal
|
|
});
|
|
const text = await r.text();
|
|
let json = null;
|
|
try { json = JSON.parse(text); } catch {}
|
|
return { status: r.status, json, text: text.slice(0, 300) };
|
|
} catch (e) {
|
|
return { status: 0, json: null, text: `${e}` };
|
|
} finally { clearTimeout(t); }
|
|
}
|
|
|
|
async function probeVision(base, key, model) {
|
|
const r = await chat(base, key, {
|
|
model,
|
|
messages: [{ role: "user", content: [
|
|
{ type: "text", text: "Reply with one word: what color dominates this image?" },
|
|
{ type: "image_url", image_url: { url: `data:image/png;base64,${TINY_PNG}` } }
|
|
] }],
|
|
max_tokens: 32
|
|
});
|
|
if (r.status === 200 && r.json?.choices?.length) {
|
|
return { vision: "YES", note: (r.json.choices[0].message?.content ?? "").slice(0, 40) };
|
|
}
|
|
const err = (r.json?.error?.message ?? r.text ?? "").slice(0, 90);
|
|
return { vision: r.status === 0 ? "TIMEOUT" : "no", note: err };
|
|
}
|
|
|
|
async function probeThinking(base, key, model, variant) {
|
|
const extra = variant === "effort" ? { reasoning_effort: "low" }
|
|
: variant === "enable" ? { enable_thinking: true }
|
|
: { thinking: { type: "enabled" } };
|
|
const r = await chat(base, key, {
|
|
model,
|
|
messages: [{ role: "user", content: "1+1=? Answer with just the number." }],
|
|
max_tokens: 512,
|
|
...extra
|
|
});
|
|
if (r.status === 0) return { verdict: "TIMEOUT", reasoning: false, note: "" };
|
|
if (r.status !== 200) {
|
|
const err = (r.json?.error?.message ?? r.text ?? "").slice(0, 80);
|
|
return { verdict: "rejected", reasoning: false, note: err };
|
|
}
|
|
const msg = r.json?.choices?.[0]?.message ?? {};
|
|
const hasReasoning = typeof msg.reasoning_content === "string" && msg.reasoning_content.length > 0;
|
|
const usage = r.json?.usage ?? {};
|
|
const reasoningTokens = usage.completion_tokens_details?.reasoning_tokens
|
|
?? usage.reasoning_tokens ?? null;
|
|
return {
|
|
verdict: "accepted",
|
|
reasoning: hasReasoning || (typeof reasoningTokens === "number" && reasoningTokens > 0),
|
|
note: `rt=${reasoningTokens ?? "-"}`
|
|
};
|
|
}
|
|
|
|
for (const p of providers) {
|
|
for (const model of p.models) {
|
|
const v = await probeVision(p.base, p.key, model);
|
|
const t1 = await probeThinking(p.base, p.key, model, "effort");
|
|
const t2 = await probeThinking(p.base, p.key, model, "enable");
|
|
const t3 = await probeThinking(p.base, p.key, model, "zai");
|
|
console.log(JSON.stringify({
|
|
provider: p.name, model,
|
|
vision: v.vision, visionNote: v.note,
|
|
thinking: {
|
|
reasoning_effort: `${t1.verdict}${t1.reasoning ? "+reasoning" : ""}`,
|
|
enable_thinking: `${t2.verdict}${t2.reasoning ? "+reasoning" : ""}`,
|
|
thinking_zai: `${t3.verdict}${t3.reasoning ? "+reasoning" : ""}`
|
|
},
|
|
hints: [t1.note, t2.note, t3.note].filter(n => n && n !== "rt=-").slice(0, 2)
|
|
}));
|
|
}
|
|
}
|
|
console.log("PROBE_DONE");
|