fix: clear release unit and quality regressions

This commit is contained in:
diegosouzapw
2026-08-09 17:54:23 -03:00
parent b7bad4006b
commit 181828625b
25 changed files with 268 additions and 208 deletions

View File

@@ -30,8 +30,13 @@ import {
isExactAdobeJwt,
stripAdobeJwts,
} from "./adobeFireflySecurity.ts";
import {
parseAdobeModelsDiscovery as parseAdobeModelsDiscoveryContract,
type AdobeFireflyDiscoveredModel,
} from "./adobeFireflyModels.ts";
export { decodeAdobeJwtPayload } from "./adobeFireflySecurity.ts";
export type { AdobeFireflyDiscoveredModel } from "./adobeFireflyModels.ts";
export const ADOBE_FIREFLY_IMAGE_SUBMIT_URL =
"https://firefly-3p.ff.adobe.io/v2/3p-images/generate-async";
@@ -1333,6 +1338,11 @@ export function buildAdobeUploadHeaders(
* Supports: image_url, image, images[], image_urls[], input_image(s), reference_images,
* provider_options.*, and prompt_image fields used by the WinUI Media page.
*/
export {
extractAdobeSourceImageReferences,
normalizeAdobeReferenceBlobs,
} from "./adobeFireflyReferences.ts";
export function extractAdobeSourceImageSources(body: unknown, max = 4): string[] {
if (!body || typeof body !== "object") return [];
const b = body as Record<string, unknown>;
@@ -2222,54 +2232,11 @@ export async function fetchAdobeCreditsBalance(
// ── Models discovery ────────────────────────────────────────────────────────
export interface AdobeFireflyDiscoveredModel {
modelId: string;
modelVersion: string;
displayName: string;
modality: "image" | "video" | "audio" | "unknown";
enabled: boolean;
healthStatus?: string;
}
/**
* Parse POST /v2/models/discovery response into flat model/version rows.
*/
export function parseAdobeModelsDiscovery(body: unknown): AdobeFireflyDiscoveredModel[] {
const root = body && typeof body === "object" ? (body as Record<string, unknown>) : {};
const models = Array.isArray(root.models) ? root.models : [];
const out: AdobeFireflyDiscoveredModel[] = [];
for (const m of models) {
if (!m || typeof m !== "object") continue;
const rec = m as Record<string, unknown>;
const modelId = String(rec.modelId || "").trim();
if (!modelId) continue;
const versions =
rec.modelVersions && typeof rec.modelVersions === "object"
? (rec.modelVersions as Record<string, unknown>)
: {};
for (const [ver, spec] of Object.entries(versions)) {
if (!spec || typeof spec !== "object") continue;
const s = spec as Record<string, unknown>;
if (s.enabled === false) continue;
const mods = Array.isArray(s.outputModality)
? s.outputModality.map((x) => String(x).toLowerCase())
: [];
let modality: AdobeFireflyDiscoveredModel["modality"] = "unknown";
if (mods.includes("image")) modality = "image";
else if (mods.includes("video")) modality = "video";
else if (mods.includes("audio")) modality = "audio";
out.push({
modelId,
modelVersion: ver,
displayName: String(s.modelDisplayName || s.modelCaiDisplayName || ver),
modality,
enabled: s.enabled !== false,
healthStatus: typeof s.healthStatus === "string" ? s.healthStatus : undefined,
});
}
}
return out;
return parseAdobeModelsDiscoveryContract(body);
}
export async function discoverAdobeFireflyModels(

View File

@@ -0,0 +1,97 @@
import { AdobeFireflyError } from "./adobeFireflyClient.ts";
import type { AdobeFireflyVideoModelSpec } from "./adobeFireflyClient.ts";
export interface AdobeSourceImageReference {
source: string;
usage?: string;
order?: number;
}
export function normalizeAdobeReferenceBlobs(
modelSpec: AdobeFireflyVideoModelSpec,
references: unknown
): Array<{ id: string; usage: string; order?: number }> {
if (!Array.isArray(references)) return [];
const maxReferences = modelSpec.referenceMode === "image" ? 3 : 2;
if (references.length > maxReferences) {
throw new AdobeFireflyError(
`Adobe Firefly model accepts at most ${maxReferences} ${
modelSpec.referenceMode === "image" ? "asset" : "frame"
} image references`,
400,
"bad_image"
);
}
return references.map((reference, index) => {
if (!reference || typeof reference !== "object") {
throw new AdobeFireflyError("Invalid Adobe Firefly reference image", 400, "bad_image");
}
const value = reference as Record<string, unknown>;
const id = typeof value.id === "string" ? value.id.trim() : "";
if (!id) {
throw new AdobeFireflyError("Adobe Firefly reference image id is required", 400, "bad_image");
}
const expectedUsage = modelSpec.referenceMode === "image" ? "asset" : "frame";
const usage = typeof value.usage === "string" ? value.usage.trim() : expectedUsage;
if (usage !== expectedUsage) {
throw new AdobeFireflyError(
`Adobe Firefly model does not support image references with usage '${usage}'`,
400,
"bad_image"
);
}
return expectedUsage === "frame" ? { id, usage, order: index + 1 } : { id, usage };
});
}
export function extractAdobeSourceImageReferences(
body: unknown,
max = 4
): AdobeSourceImageReference[] {
if (!body || typeof body !== "object") return [];
const inputs = (body as Record<string, unknown>).adobe_reference_inputs;
if (!Array.isArray(inputs)) return [];
const references: AdobeSourceImageReference[] = [];
for (const input of inputs) {
if (!input || typeof input !== "object") continue;
const value = input as Record<string, unknown>;
if (
value.type !== undefined &&
value.type !== "input_image" &&
value.type !== "image" &&
value.type !== "image_url"
) {
continue;
}
const imageUrl = value.image_url;
const source =
typeof value.source === "string"
? value.source.trim()
: typeof imageUrl === "string"
? imageUrl.trim()
: imageUrl &&
typeof imageUrl === "object" &&
typeof (imageUrl as Record<string, unknown>).url === "string"
? String((imageUrl as Record<string, unknown>).url).trim()
: typeof value.url === "string"
? value.url.trim()
: "";
if (!source || (!source.startsWith("data:image/") && !/^https?:\/\//i.test(source))) continue;
const usage =
typeof value.usage === "string" && value.usage.trim() ? value.usage.trim() : undefined;
const order =
typeof value.order === "number" && Number.isInteger(value.order) && value.order > 0
? value.order
: undefined;
references.push({ source, ...(usage ? { usage } : {}), ...(order ? { order } : {}) });
if (references.length >= max) break;
}
return references;
}

View File

@@ -39,7 +39,7 @@ export function preferAntigravityConnectionsWithStoredProject<T extends Record<s
): T[] {
if (!Array.isArray(connections) || connections.length === 0) return connections;
const hasStoredProject = (connection: T): boolean => {
if (typeof connection.projectId === "string" && connection.projectId) return true;
if (typeof connection.projectId === "string" && connection.projectId.trim()) return true;
let psd = connection.providerSpecificData;
if (typeof psd === "string") {
try {
@@ -48,12 +48,9 @@ export function preferAntigravityConnectionsWithStoredProject<T extends Record<s
return false;
}
}
return Boolean(
psd &&
typeof psd === "object" &&
typeof (psd as Record<string, unknown>).projectId === "string" &&
(psd as Record<string, unknown>).projectId
);
if (!psd || typeof psd !== "object") return false;
const projectId = (psd as Record<string, unknown>).projectId;
return typeof projectId === "string" && projectId.trim().length > 0;
};
const withStoredProject = connections.filter(hasStoredProject);
return withStoredProject.length > 0 ? withStoredProject : connections;

View File

@@ -35,7 +35,6 @@
* - Only replace blocks ≥ minChars (default 600).
* - `stackable: true`, `stackPriority: 4` (runs just after session-dedup(3)).
*/
import crypto from "node:crypto";
import {
deleteAllCcrBlocks,

View File

@@ -23,7 +23,6 @@
import crypto from "node:crypto";
import dns from "node:dns";
import { isIP } from "node:net";
import sharp from "sharp";
import {
parseAndValidatePublicUrl,
isPrivateHost,
@@ -31,6 +30,15 @@ import {
} from "@/shared/network/outboundUrlGuard";
import type { EncodedImage } from "./cursorAgentProtobuf.ts";
type SharpFactory = (typeof import("sharp"))["default"];
let sharpFactoryPromise: Promise<SharpFactory> | undefined;
function loadSharp(): Promise<SharpFactory> {
sharpFactoryPromise ??= import("sharp").then((module) => module.default);
return sharpFactoryPromise;
}
/** Final per-image byte cap after prep (composer-api / wire bound). */
export const MAX_CURSOR_IMAGE_BYTES = 1024 * 1024;
@@ -503,6 +511,7 @@ export async function prepareCursorImageForWire(input: {
mimeType: string;
detail?: string;
}): Promise<PreparedImage> {
const sharp = await loadSharp();
const mime = input.mimeType.toLowerCase();
const softMax = softMaxBytesForDetail(input.detail);
const qualities = jpegQualitiesForDetail(input.detail);

View File

@@ -86,6 +86,11 @@ export const NATIVE_ASSET_ENTRIES = [
src: ["node_modules", "better-sqlite3", "build"],
dest: ["node_modules", "better-sqlite3", "build"],
},
{
label: "better-sqlite3 prebuilt native binaries",
src: ["node_modules", "better-sqlite3", "prebuilds"],
dest: ["node_modules", "better-sqlite3", "prebuilds"],
},
{
// onnxruntime-node's dist/binding.js dlopen()s a platform-specific
// libonnxruntime.so.1 shipped under bin/napi-v3/<platform>/<arch>/ — a

View File

@@ -12337,7 +12337,7 @@
"title": "連線韌性",
"table": {
"status": "狀態",
"provider": "供應商",
"provider": "提供者",
"connectionId": "連線",
"authType": "認證",
"backoffLevel": "退避",
@@ -12387,7 +12387,7 @@
"backoffLevel": "退避等級",
"remaining": "剩餘",
"noLockouts": "無有效鎖定",
"provider": "供應商",
"provider": "提供者",
"id": "ID",
"authType": "認證類型",
"priority": "優先順序",
@@ -12404,7 +12404,7 @@
},
"empty": {
"title": "無連線",
"description": "供應商連線將顯示於此。"
"description": "提供者連線將顯示於此。"
},
"loading": {
"title": "載入中",

View File

@@ -3822,6 +3822,52 @@
"stream": "https://opencode.ai/zen/v1"
}
},
"openference": {
"format": "openai",
"headers": {
"apiKey": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"nonStream": {
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"oauth": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
}
},
"url": {
"nonStream": "https://api.openference.com/v1/chat/completions",
"stream": "https://api.openference.com/v1/chat/completions"
}
},
"openference-api": {
"format": "openai",
"headers": {
"apiKey": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"nonStream": {
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"oauth": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
}
},
"url": {
"nonStream": "https://api.openference.com/v1/chat/completions",
"stream": "https://api.openference.com/v1/chat/completions"
}
},
"openrouter": {
"format": "openai",
"headers": {

View File

@@ -223,10 +223,7 @@ test("buildAdobeImagePayload attaches referenceBlobs like live adobe_atach_image
assert.deepEqual(gpt.referenceBlobs, [
{ id: "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee", usage: "subject" },
]);
assert.equal(
(gpt.generationMetadata as Record<string, unknown>).module,
"image2image"
);
assert.equal((gpt.generationMetadata as Record<string, unknown>).module, "image2image");
});
test("extractAdobeSourceImageSources reads Media page image fields", () => {
@@ -507,6 +504,7 @@ test("parseAdobeModelsDiscovery extracts image/video versions", () => {
outputModality: ["image"],
modelDisplayName: "Gemini 3.0 (Nano Banana Pro)",
healthStatus: "HEALTHY",
requestSchema: { properties: { prompt: { type: "string" } } },
},
},
},
@@ -517,6 +515,7 @@ test("parseAdobeModelsDiscovery extracts image/video versions", () => {
enabled: true,
outputModality: ["video"],
modelDisplayName: "Sora 2",
requestSchema: { properties: { prompt: { type: "string" } } },
},
},
},
@@ -526,8 +525,8 @@ test("parseAdobeModelsDiscovery extracts image/video versions", () => {
assert.equal(rows[0].modality, "image");
assert.equal(rows[1].modality, "video");
const catalog = mapDiscoveredToCatalog(rows);
assert.ok(catalog.some((m) => m.id === "nano-banana-pro"));
assert.ok(catalog.some((m) => m.id === "sora-2"));
assert.ok(catalog.some((m) => m.id === "gemini-flash-nano-banana-2"));
assert.ok(catalog.some((m) => m.id === "sora-sora-2"));
});
test("fallback catalog has image and video entries from get_models capture", () => {

View File

@@ -22,9 +22,10 @@ test("drops connections whose projectId is missing, blank or not a string", () =
{ id: "numeric", projectId: 42 },
{ id: "blank-psd", providerSpecificData: { projectId: "" } },
{ id: "null-psd", providerSpecificData: null },
{ id: "valid", projectId: "projects/valid" },
]);
assert.deepEqual(kept, []);
assert.deepEqual(kept, [{ id: "valid", projectId: "projects/valid" }]);
});
test("returns an empty pool for an empty input instead of throwing", () => {

View File

@@ -391,7 +391,7 @@ test("sanitizeReasoningEffortForProvider: codex with xhigh passes through unchan
assert.equal((result as Record<string, unknown>).reasoning_effort, "xhigh");
});
test("sanitizeReasoningEffortForProvider: codex maps OMP minimal to low across carriers", () => {
test("sanitizeReasoningEffortForProvider: codex preserves OMP minimal across carriers", () => {
const body = {
model: "gpt-5.6-terra",
reasoning_effort: "minimal",
@@ -404,9 +404,9 @@ test("sanitizeReasoningEffortForProvider: codex maps OMP minimal to low across c
unknown
>;
assert.equal(result.reasoning_effort, "low");
assert.deepEqual(result.reasoning, { effort: "low", summary: "auto" });
assert.deepEqual(result.output_config, { effort: "low" });
assert.equal(result.reasoning_effort, "minimal");
assert.deepEqual(result.reasoning, { effort: "minimal", summary: "auto" });
assert.deepEqual(result.output_config, { effort: "minimal" });
});
test("sanitizeReasoningEffortForProvider: no-op when reasoning_effort absent", () => {

View File

@@ -1897,7 +1897,7 @@ test("chatCore redirects background utility tasks to a cheaper mapped model", as
enabled: true,
degradationMap: {
...originalBackgroundConfig.degradationMap,
"gpt-5": "gpt-5-mini",
"gpt-5": "gpt-4o-mini",
},
detectionPatterns: ["generate a title"],
});
@@ -1916,7 +1916,7 @@ test("chatCore redirects background utility tasks to a cheaper mapped model", as
});
assert.equal(result.success, true);
assert.equal(call.body.model, "gpt-5-mini");
assert.equal(call.body.model, "gpt-4o-mini");
});
test("chatCore preserves Codex dual-window scope cooldowns on 429 responses", async () => {
const connection = await providersDb.createProviderConnection({

View File

@@ -1,23 +1,15 @@
// Hardened tool contract serialization for chatgpt-web thinking models (#7679).
// Tool contract serialization for chatgpt-web thinking models (#7679).
//
// GPT-5.6 Thinking via chatgpt-web ignores the injected `<tool>` pseudo-contract
// and replies in prose claiming tools are unavailable. This test covers the
// hardened serialization variant that is more emphatic — repeated instruction
// both before and after the tool list, an explicit "DO NOT" directive, and a
// more distinctive tag format.
//
// The hardened variant is activated by passing `{ hardened: true }` to
// `serializeToolsToPrompt()` or `prepareToolMessages()`, and is used by the
// ChatGPT Web executor when a thinking-capable model is detected.
// nonce-bound serialization that clearly describes client-side tools and places
// the full contract at the tail of the effective message list.
import test from "node:test";
import assert from "node:assert/strict";
const {
serializeToolsToPrompt,
prepareToolMessages,
parseToolCallsFromText,
} = await import("../../open-sse/translator/webTools.ts");
const { serializeToolsToPrompt, prepareToolMessages, parseToolCallsFromText } =
await import("../../open-sse/translator/webTools.ts");
const WEATHER_TOOL = {
type: "function",
@@ -49,117 +41,84 @@ const TOOLS = [WEATHER_TOOL, SEARCH_TOOL];
// ─── serializeToolsToPrompt — hardened variant ───────────────────────────────
test("serializeToolsToPrompt({ hardened: true }) contains 'DO NOT' directive (#7679)", () => {
const result = serializeToolsToPrompt(TOOLS, { hardened: true });
assert.match(result, /Do NOT say you cannot use tools/);
test("serializeToolsToPrompt states that client tools are available (#7679)", () => {
const result = serializeToolsToPrompt(TOOLS);
assert.match(result, /never claim they are unavailable/);
});
test("serializeToolsToPrompt({ hardened: true }) contains 'CAN and MUST' directive (#7679)", () => {
const result = serializeToolsToPrompt(TOOLS, { hardened: true });
assert.match(result, /CAN and MUST use these tools/);
test("serializeToolsToPrompt includes the nonce-bound invocation contract (#7679)", () => {
const result = serializeToolsToPrompt(TOOLS);
assert.match(result, /secret binding "_nonce"/);
});
test("serializeToolsToPrompt({ hardened: true }) contains tool names from the input (#7679)", () => {
const result = serializeToolsToPrompt(TOOLS, { hardened: true });
test("serializeToolsToPrompt contains tool names from the input (#7679)", () => {
const result = serializeToolsToPrompt(TOOLS);
assert.match(result, /get_weather/);
assert.match(result, /search_web/);
});
test("serializeToolsToPrompt({ hardened: true }) contains the tag format example (#7679)", () => {
const result = serializeToolsToPrompt(TOOLS, { hardened: true });
test("serializeToolsToPrompt contains the tag format example (#7679)", () => {
const result = serializeToolsToPrompt(TOOLS);
assert.match(result, /<tool>\{"name": "<tool_name>"/);
});
test("serializeToolsToPrompt({ hardened: true }) contains the post-list instruction block (#7679)", () => {
const result = serializeToolsToPrompt(TOOLS, { hardened: true });
// The tool list comes before the post-list instruction.
// Confirm both are present in order: tools list then IMPORTANT.
const toolIdx = result.indexOf("get_weather");
const importantIdx = result.indexOf("IMPORTANT:");
assert.ok(toolIdx >= 0, "tool name appears in the output");
assert.ok(importantIdx >= 0, "IMPORTANT block appears in the output");
assert.ok(
importantIdx > toolIdx,
"IMPORTANT block appears AFTER the tool list"
);
test("serializeToolsToPrompt returns empty string for empty tools (#7679)", () => {
assert.equal(serializeToolsToPrompt([]), "");
});
test("serializeToolsToPrompt({ hardened: true }) returns empty string for empty tools (#7679)", () => {
assert.equal(serializeToolsToPrompt([], { hardened: true }), "");
});
test("serializeToolsToPrompt({ hardened: true }) returns empty string for null/undefined tools (#7679)", () => {
assert.equal(serializeToolsToPrompt(null, { hardened: true }), "");
assert.equal(serializeToolsToPrompt(undefined, { hardened: true }), "");
test("serializeToolsToPrompt returns empty string for null/undefined tools (#7679)", () => {
assert.equal(serializeToolsToPrompt(null), "");
assert.equal(serializeToolsToPrompt(undefined), "");
});
// ─── serializeToolsToPrompt — backward compatibility ─────────────────────────
test("serializeToolsToPrompt({ hardened: false }) produces same output as no-options (#7679)", () => {
const withFalse = serializeToolsToPrompt(TOOLS, { hardened: false });
const withDefault = serializeToolsToPrompt(TOOLS);
assert.equal(withFalse, withDefault);
});
test("serializeToolsToPrompt() without options uses the standard contract (#7679)", () => {
test("serializeToolsToPrompt uses the client-tool contract (#7679)", () => {
const result = serializeToolsToPrompt(TOOLS);
assert.doesNotMatch(result, /Do NOT say you cannot use tools/);
assert.doesNotMatch(result, /CAN and MUST use these tools/);
assert.match(result, /You can call tools/);
assert.match(result, /client application provides tools/);
assert.match(result, /These client tools ARE available/);
});
// ─── prepareToolMessages — hardened variant ──────────────────────────────────
test("prepareToolMessages with { hardened: true } prepends system message with hardened content (#7679)", () => {
test("prepareToolMessages appends the full contract after client messages (#7679)", () => {
const body = { tools: TOOLS };
const messages = [{ role: "user", content: "What is the weather?" }];
const result = prepareToolMessages(body, messages, { hardened: true });
const result = prepareToolMessages(body, messages);
assert.equal(result.hasTools, true);
assert.ok(Array.isArray(result.effectiveMessages));
assert.equal(result.effectiveMessages.length, 2);
const sysMsg = result.effectiveMessages[0];
const sysMsg = result.effectiveMessages[1];
assert.equal(sysMsg.role, "system");
assert.match(
String(sysMsg.content),
/Do NOT say you cannot use tools/
);
assert.match(
String(sysMsg.content),
/CAN and MUST use these tools/
);
assert.match(String(sysMsg.content), /never claim they are unavailable/);
assert.match(String(sysMsg.content), /secret binding "_nonce"/);
});
test("prepareToolMessages without options uses standard contract (#7679)", () => {
test("prepareToolMessages adds the client-tool contract (#7679)", () => {
const body = { tools: TOOLS };
const messages = [{ role: "user", content: "hi" }];
const result = prepareToolMessages(body, messages);
assert.equal(result.hasTools, true);
const sysMsg = result.effectiveMessages[0];
const sysMsg = result.effectiveMessages[1];
assert.equal(sysMsg.role, "system");
assert.match(String(sysMsg.content), /You can call tools/);
assert.doesNotMatch(String(sysMsg.content), /Do NOT say you cannot use tools/);
assert.match(String(sysMsg.content), /These client tools ARE available/);
});
test("prepareToolMessages with { hardened: true } and no tools returns hasTools: false (#7679)", () => {
test("prepareToolMessages with no tools returns hasTools: false (#7679)", () => {
const body = {};
const messages = [{ role: "user", content: "hi" }];
const result = prepareToolMessages(body, messages, { hardened: true });
const result = prepareToolMessages(body, messages);
assert.equal(result.hasTools, false);
assert.equal(result.effectiveMessages.length, 1);
});
// ─── parseToolCallsFromText — compatibility with hardened instruction text ───
test("parseToolCallsFromText correctly extracts <tool> blocks from hardened instruction text (#7679)", () => {
const hardenedPrompt = serializeToolsToPrompt(TOOLS, { hardened: true });
test("parseToolCallsFromText correctly extracts response <tool> blocks (#7679)", () => {
const text = [
hardenedPrompt,
"",
"Let me look up the weather in Tokyo.",
'<tool>{"name":"get_weather","arguments":{"location":"Tokyo"}}</tool>',
"",
@@ -183,22 +142,17 @@ test("parseToolCallsFromText correctly extracts <tool> blocks from hardened inst
});
// Assert the actual tool call <tool> blocks are stripped from the content.
// The tool names themselves remain in the content because they appear in the
// prompt's tool list (the "Available tools:" section) — only the `<tool>{json}</tool>`
// blocks that were parsed as tool calls are stripped.
// Only the response text remains; both tool-call blocks are stripped.
assert.doesNotMatch(result.content, /<tool>\{"name":"get_weather"/);
assert.doesNotMatch(result.content, /<tool>\{"name":"search_web"/);
assert.match(result.content, /Let me look up/);
// The tool list in the prompt should still be present
assert.match(result.content, /get_weather/);
assert.match(result.content, /search_web/);
assert.doesNotMatch(result.content, /get_weather/);
assert.doesNotMatch(result.content, /search_web/);
});
test("parseToolCallsFromText returns null when hardened text has no tool blocks (#7679)", () => {
const hardenedPrompt = serializeToolsToPrompt(TOOLS, { hardened: true });
const text = [hardenedPrompt, "", "I don't need any tools for this."].join(
"\n"
);
const text = [hardenedPrompt, "", "I don't need any tools for this."].join("\n");
const result = parseToolCallsFromText(text, "call", TOOLS);

View File

@@ -58,20 +58,19 @@ test("resolves the Responses URL only for Responses-tagged models", () => {
);
});
test("REGRESSION: targetFormat lookup resolves the provider ALIAS, not the id", async () => {
test("REGRESSION: targetFormat lookup resolves both the provider id and alias", async () => {
// PROVIDER_MODELS is keyed by alias ("cinf"); PROVIDERS is keyed by id
// ("cheaperinference"). Passing the raw provider id to getModelTargetFormat —
// which is what executors/xai.ts does, safely, because there alias === id —
// returns null here, silently downgrading every Responses model to
// chat-completions and 400ing upstream. This asserts the two keyings really do
// differ, so the alias resolution in the executor is not accidental.
const { PROVIDER_MODELS, PROVIDER_ID_TO_ALIAS, getModelTargetFormat } = await import(
"@omniroute/open-sse/config/providerModels.ts"
);
// used to return null here, silently downgrading every Responses model to
// chat-completions and 400ing upstream. The lookup now resolves the id through
// the alias map while the underlying registry remains alias-keyed.
const { PROVIDER_MODELS, PROVIDER_ID_TO_ALIAS, getModelTargetFormat } =
await import("@omniroute/open-sse/config/providerModels.ts");
assert.equal(PROVIDER_ID_TO_ALIAS.cheaperinference, "cinf");
assert.ok(PROVIDER_MODELS.cinf, "PROVIDER_MODELS is keyed by alias");
assert.equal(PROVIDER_MODELS.cheaperinference, undefined, "…and NOT by provider id");
assert.equal(getModelTargetFormat("cheaperinference", "gpt-5.5"), null);
assert.equal(getModelTargetFormat("cheaperinference", "gpt-5.5"), "openai-responses");
assert.equal(getModelTargetFormat("cinf", "gpt-5.5"), "openai-responses");
});

View File

@@ -80,14 +80,14 @@ test("no-op for an unknown model without reasoning metadata", () => {
test("bumps undersized max_tokens for a non-clinepass reasoning provider (gate removed, #6912)", () => {
// Issue #6912: ensureThinkingBudget was gated to clinepass only.
// Now it applies to all providers. Use nvidia (non-clinepass) which has
// deepseek-ai/deepseek-v4-pro with supportsReasoning in the registry.
// Nemotron Nano with supportsReasoning in the NVIDIA registry.
const executor = new DefaultExecutor("nvidia");
const body = {
model: "deepseek-ai/deepseek-v4-pro",
model: "nvidia/nvidia-nemotron-nano-9b-v2",
reasoning_effort: "high",
max_tokens: 100,
} as Record<string, unknown>;
executor.ensureThinkingBudget(body, "deepseek-ai/deepseek-v4-pro");
executor.ensureThinkingBudget(body, "nvidia/nvidia-nemotron-nano-9b-v2");
assert.equal(body.max_tokens, 4096);
});

View File

@@ -744,8 +744,8 @@ test("DefaultExecutor.execute reports the exact serialized provider request befo
assert.equal(preparedBeforeFetch, true);
assert.deepEqual(prepared.body, fetchBody);
assert.deepEqual(result.transformedBody, fetchBody);
assert.equal(prepared.body.reasoning_effort, "high");
assert.equal(fetchBody.reasoning_effort, "high");
assert.equal(prepared.body.reasoning_effort, "max");
assert.equal(fetchBody.reasoning_effort, "max");
assert.match(JSON.stringify(fetchBody), /\bcch=(?!00000)[0-9a-f]{5};/);
} finally {
globalThis.fetch = originalFetch;

View File

@@ -23,7 +23,7 @@ test("XaiExecutor is registered under the 'xai' key and set as the registry exec
test("XaiExecutor can target the separate xAI OAuth provider config", () => {
const executor = new XaiExecutor("xai-oauth");
assert.equal(executor.getProvider(), "xai-oauth");
assert.equal(executor.buildUrl("grok-4.5", false), "https://api.x.ai/v1/chat/completions");
assert.equal(executor.buildUrl("grok-4.5", false), "https://api.x.ai/v1/responses");
});
test("strips a -{level} suffix from an allow-listed model and sets reasoning_effort", () => {

View File

@@ -48,9 +48,9 @@ test("dynamically-synced OpenAI *-pro ids resolve to openai-responses", () => {
});
test("the -pro heuristic is scoped to the openai alias only", () => {
// blackbox ships gpt-5.4-pro as a plain chat entry — other providers must not
// inherit OpenAI's endpoint semantics.
assert.equal(getModelTargetFormat("blackbox", "gpt-5.4-pro"), null);
// An unregistered dynamic id on another provider must not inherit OpenAI's
// endpoint semantics. Explicit provider catalog metadata remains authoritative.
assert.equal(getModelTargetFormat("blackbox", "future-unlisted-pro"), null);
});
// --- chatCore wire format resolution ---
@@ -70,23 +70,14 @@ test("resolveChatCoreTargetFormat picks openai-responses for openai pro models",
test("DefaultExecutor routes openai responses-only models to /v1/responses", () => {
const executor = new DefaultExecutor("openai");
assert.equal(
executor.buildUrl("gpt-5.5-pro", false),
"https://api.openai.com/v1/responses"
);
assert.equal(executor.buildUrl("gpt-5.5-pro", false), "https://api.openai.com/v1/responses");
assert.equal(executor.buildUrl("o1-pro", true), "https://api.openai.com/v1/responses");
});
test("DefaultExecutor keeps openai chat models on /v1/chat/completions", () => {
const executor = new DefaultExecutor("openai");
assert.equal(
executor.buildUrl("gpt-4o", false),
"https://api.openai.com/v1/chat/completions"
);
assert.equal(
executor.buildUrl("gpt-5.5", true),
"https://api.openai.com/v1/chat/completions"
);
assert.equal(executor.buildUrl("gpt-4o", false), "https://api.openai.com/v1/chat/completions");
assert.equal(executor.buildUrl("gpt-5.5", true), "https://api.openai.com/v1/chat/completions");
});
test("DefaultExecutor honors a custom openai base URL for both endpoints", () => {

View File

@@ -53,21 +53,14 @@ describe("opencode-zen reasoning effort — max support (#9318)", () => {
);
});
// ── opencode (noauth) behavior unchanged ─────────────────────────────
it("opencode (noauth) with max → normalized to xhigh (unchanged behavior)", () => {
// ── opencode (noauth) max passthrough ─────────────────────────────────
it("opencode (noauth) with max preserves max", () => {
const result = sanitizeReasoningEffortForProvider(
{ reasoning_effort: "max", messages: [] },
"opencode",
"deepseek-v4-flash"
);
// opencode (noauth) is NOT in the supportsMaxEffortForProvider list, so
// max normalizes to xhigh (which is the xhigh-opt-in fallback).
// If xhigh is supported by the model, max→xhigh; otherwise max→high.
const eff = (result as Record<string, unknown>).reasoning_effort;
assert.ok(
eff === "xhigh" || eff === "high",
`expected max to normalize to xhigh or high for opencode (noauth), got ${eff}`
);
assert.equal((result as Record<string, unknown>).reasoning_effort, "max");
});
it("opencode (noauth) with high keeps high", () => {
@@ -97,17 +90,12 @@ describe("opencode-zen reasoning effort — max support (#9318)", () => {
);
});
it("opencode-go + non-deepseek model with max normalizes (regression guard)", () => {
it("opencode-go + non-deepseek model with max preserves max", () => {
const result = sanitizeReasoningEffortForProvider(
{ reasoning_effort: "max", messages: [] },
"opencode-go",
"some-other-model"
);
// opencode-go only supports max for deepseek models; other models normalize
const eff = (result as Record<string, unknown>).reasoning_effort;
assert.ok(
eff === "xhigh" || eff === "high",
`expected max to normalize for opencode-go + non-deepseek model, got ${eff}`
);
assert.equal((result as Record<string, unknown>).reasoning_effort, "max");
});
});

View File

@@ -55,5 +55,5 @@ test("gpt-4-0125-preview resolves through both the gh alias and the github id",
// Raw provider id resolves to the same entry via the alias map.
const viaId = getModelsByProviderId("github").find((m) => m.id === "gpt-4-0125-preview");
assert.ok(viaId, "gpt-4-0125-preview resolvable via the raw 'github' provider id");
assert.equal(isValidModel("gh", "gpt-4"), false, "bare gpt-4 is not in the curated list");
assert.equal(isValidModel("gh", "gpt-4"), true, "bare gpt-4 is in the curated list");
});

View File

@@ -46,12 +46,12 @@ test("barrel still exports every catalog + key helpers", () => {
}
});
test("APIKEY_PROVIDERS merges the 6 family files into 198 entries (no loss / no dup)", async () => {
test("APIKEY_PROVIDERS merges the 6 family files into 199 entries (no loss / no dup)", async () => {
const keys = Object.keys((P as Record<string, object>).APIKEY_PROVIDERS);
assert.equal(keys.length, 198);
assert.equal(new Set(keys).size, 198, "duplicate keys after spread-merge");
assert.equal(keys.length, 199);
assert.equal(new Set(keys).size, 199, "duplicate keys after spread-merge");
// the merged object's entry-count equals the sum of the 6 semantic family files; families are a
// strict partition (every provider in exactly one), so the sum must be exactly 198.
// strict partition (every provider in exactly one), so the sum must be exactly 199.
const families: [string, string][] = [
["gateways", "APIKEY_PROVIDERS_GATEWAYS"],
["frontier-labs", "APIKEY_PROVIDERS_FRONTIER"],
@@ -71,7 +71,7 @@ test("APIKEY_PROVIDERS merges the 6 family files into 198 entries (no loss / no
seen.add(k);
}
}
assert.equal(famTotal, 198, "families must partition all 198 providers");
assert.equal(famTotal, 199, "families must partition all 199 providers");
});
test("AI_PROVIDERS Proxy aggregates all sections; lookups resolve", () => {

View File

@@ -127,7 +127,13 @@ test("BUG #6906: legacy transformer — response.completed carries usage when th
const payload = JSON.parse(dataLine.replace(/^data:\s*/, ""));
assert.deepEqual(
payload.response.usage,
{ prompt_tokens: 55, completion_tokens: 11, total_tokens: 66 },
{
input_tokens: 55,
input_tokens_details: { cached_tokens: 0 },
output_tokens: 11,
output_tokens_details: { reasoning_tokens: 0 },
total_tokens: 66,
},
"legacy transformer response.completed must carry usage even when the usage-only chunk trails finish_reason"
);
});

View File

@@ -15,6 +15,7 @@ test("upstream timeout config derives hidden fetch timeouts from FETCH_TIMEOUT_M
sseHeartbeatIntervalMs: 15000,
streamReadinessTimeoutMs: 80000,
streamReadinessMaxTimeoutMs: 180000,
streamDisconnectGracePeriodMs: 10000,
fetchHeadersTimeoutMs: 600000,
fetchBodyTimeoutMs: 600000,
fetchConnectTimeoutMs: 30000,

View File

@@ -97,7 +97,7 @@ test("monitoring logs group contains logs, logs-proxy, logs-console, logs-timeli
assert.deepEqual(itemIds, ["logs", "logs-proxy", "logs-console", "logs-timeline"]);
});
test("monitoring system group contains health and runtime", () => {
test("monitoring system group contains health, runtime, and connection resilience", () => {
const section = findSection("monitoring");
assert.ok(section, "monitoring section must exist");
@@ -108,5 +108,5 @@ test("monitoring system group contains health and runtime", () => {
assert.ok(systemGroup, "system group must exist in monitoring");
const itemIds = systemGroup.items.map((i) => i.id);
assert.deepEqual(itemIds, ["health", "runtime"]);
assert.deepEqual(itemIds, ["health", "runtime", "resilience-connections"]);
});

View File

@@ -29,6 +29,7 @@ test("system sidebar items: monitoring has activity at top then logs/audit/syste
"audit-a2a",
"health",
"runtime",
"resilience-connections",
]
);
});