fix(commandcode): preserve images and reasoning_effort on /alpha/generate

Command Code dropped vision and ignored client effort through the router:
image blocks became "[image omitted]", HTTP image URLs were never inlined,
and reasoning_effort landed on the envelope wrapper instead of params (so the
DeepSeek family mapping remapped low -> high). The catalog also treated
deepseek/deepseek-v4.1-flash as text-only, so the vision adapter stole those
requests to another provider.

- Map OpenAI image_url / Claude image blocks (base64 or data-URI) to the
  native {type:"image", image:"data:...;base64,...", mimeType} generate block.
- Add FORMATS.COMMANDCODE to TARGETS_NEED_BASE64 so remote http(s) images are
  inlined by the existing SSRF-safe fetcher before translation.
- Write reasoning_effort inside params for targetFormat commandcode and pass
  low|medium|high|xhigh|max through unmapped; allow it in thinkingLevels.
- Provider-scoped capabilities for commandcode/cmc: vision except the CLI
  text-only denylist, thinkingFormat commandcode, so family patterns
  (deepseek-v4 -> thinkingFormat deepseek, vision false) no longer win.
- Quota Tracker: whoami + billing credits/subscriptions (credits vs plan cap,
  5h and weekly windows), labels from AI_PROVIDERS[].name.
This commit is contained in:
KhuatHieu
2026-09-16 20:16:32 +07:00
committed by decolua
parent 9300121366
commit 13b468b889
16 changed files with 529 additions and 17 deletions

View File

@@ -8,6 +8,7 @@ import { fetchImageAsBase64, parseDataUri } from "./image.js";
const TARGETS_NEED_BASE64 = new Set([
FORMATS.GEMINI, FORMATS.GEMINI_CLI, FORMATS.VERTEX,
FORMATS.ANTIGRAVITY, FORMATS.OLLAMA, FORMATS.KIRO,
FORMATS.COMMANDCODE,
]);
function isRemoteUrl(url) {

View File

@@ -19,6 +19,7 @@ const FORMAT_TO_NATIVE = {
vertex: "gemini-budget",
antigravity: "gemini-budget",
kiro: "kiro",
commandcode: "commandcode",
};
// Strip a trailing thinking suffix "model(value)" → "model" (no-op when absent).
@@ -108,6 +109,7 @@ export const captureThinking = extractThinking;
const NATIVE_ONLY_FORMATS = new Set(["gemini-level", "gemini-budget", "claude-budget", "claude-adaptive", "kiro"]);
function resolveFormat(targetFormat, model, provider) {
if (targetFormat === "commandcode") return "commandcode";
const providerFmt = provider ? PROVIDERS[provider]?.thinkingFormat : null;
if (providerFmt) return providerFmt;
const caps = getCapabilitiesForModel(provider, model);
@@ -223,6 +225,10 @@ function stripAll(body) {
delete body.output_config;
if (body.generationConfig) delete body.generationConfig.thinkingConfig;
if (body.request?.generationConfig) delete body.request.generationConfig.thinkingConfig;
if (body.params && typeof body.params === "object") {
delete body.params.reasoning_effort;
delete body.params.thinking;
}
}
// Apply unified thinking config to body in the resolved provider-native format.
@@ -336,6 +342,17 @@ function applyFormat(fmt, body, cfg, caps, supportedLevels) {
case "kiro":
// Kiro thinking handled via system-tag injection in openai-to-kiro.js; no body field here.
break;
case "commandcode": {
// Native CLI sends reasoning_effort inside params of the /alpha/generate envelope.
if (!body.params || typeof body.params !== "object") body.params = {};
if (none && canDisable) {
delete body.params.reasoning_effort;
break;
}
const level = toLevel(eff);
if (level) body.params.reasoning_effort = level;
break;
}
default:
break;
}