Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion config/quality/file-size-baseline.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"_comment": "Catraca de tamanho (check-file-size.mjs). frozen so pode encolher; arquivos novos <= cap. --update ratcheta.",
"_rebaseline_2026_06_18_4180_gemini_default_thinking": "PR #4180 own growth: openai-to-gemini.ts 844->864 (+20 = default includeThoughts for modern Gemini 2.5+ at the existing openaiToGeminiBase chokepoint — when the client set no thinkingConfig, inject one (includeThoughts:true + a capped budget) so the model's reasoning is marked thought:true and routed to reasoning_content instead of leaking into visible content, #4170). Cohesive translator branch gated to gemini-2.5+/3 (excludes gemini-1.x and non-thinking 2.0); not extractable. Reconciled here because #4180 merged without the baseline bump.",
"_rebaseline_2026_06_18_4176_free_models": "PR #4176 own growth: AddApiKeyModal.tsx 845->866 (+21) and EditConnectionModal.tsx 1174->1204 (+30) = the 'import only free models' connection option — a free-models Toggle gated by providerHasFreeModels() plus its form-state wiring (importFreeModelsOnly field + providerSpecificData persistence, explicit-false on edit so the PUT merge doesn't keep a stale true) added to both connection modals, mirroring the prior per-modal toggle bumps #3879 (redact-thinking) and #2997 (disable-cooling). Detection lives in the new shared src/shared/utils/freeModels.ts (112 LOC, <cap); the duplicated Toggle is ~6 lines and the per-modal state wiring is intrinsic, so the remaining growth is cohesive UI, not an extractable block.",
"_rebaseline_2026_06_18_3931_qwen_web_models": "Issue #3931 (Problem #3) own growth: providers/[id]/models/route.ts 2512->2531 (+19 = one PROVIDER_MODELS_CONFIG entry for `qwen-web` + a 4-line comment). qwen-web was missing from the config map so its model-discovery page returned nothing (the OAuth fallback only fires for provider===qwen). Pure additive config entry pointing at the public chat.qwen.ai/api/v2/models endpoint; standard per-provider addition, not extractable.",
"_rebaseline_2026_06_18_4165_queue_timeout_msg": "Issue #4165 own growth: rateLimitManager.ts 1022->1035 (+13 at the existing withRateLimit catch chokepoint). Bottleneck's raw `This job timed out after <maxWaitMs> ms.` is rewritten into a clear OmniRoute-owned error (names resilienceSettings.requestQueue.maxWaitMs, disclaims upstream, keeps the original as `cause`, tags code=RATE_LIMIT_QUEUE_TIMEOUT) so queue-saturation 502s stop masquerading as provider outages. The branch already existed (it only logged); this adds the error construction at the same point. Not extractable — closes over provider/model/maxWaitMs locals of the single catch.",
Expand Down Expand Up @@ -75,7 +76,7 @@
"open-sse/services/rateLimitManager.ts": 1035,
"open-sse/services/tokenRefresh.ts": 1997,
"open-sse/services/usage.ts": 3408,
"open-sse/translator/request/openai-to-gemini.ts": 844,
"open-sse/translator/request/openai-to-gemini.ts": 864,
"open-sse/translator/response/openai-responses.ts": 903,
"open-sse/utils/cursorAgentProtobuf.ts": 1521,
"open-sse/utils/stream.ts": 2710,
Expand Down
6 changes: 6 additions & 0 deletions open-sse/config/providers/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,12 @@ export const KIMI_CODING_SHARED = {
maxOutputTokens: 262144,
},
...KIMI_K27_MODELS,
{
id: "moonshotai/kimi-k2.7-code",
name: "Kimi K2.7 Code",
contextLength: 262144,
maxOutputTokens: 262144,
},
] as RegistryModel[],
} as const;

Expand Down
116 changes: 116 additions & 0 deletions tests/unit/catalog-updates-v3829-kimi-qwen.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Regression guard for two catalog fixes shipped in v3.8.29:
//
// 1. Task 1 — moonshotai/kimi-k2.7-code added to the kimi-coding-apikey (kmca)
// provider catalog (KIMI_CODING_SHARED.models in open-sse/config/providers/shared.ts).
// Requested by @hana189 in discussion #3737.
//
// 2. Bug #3 (issue #3931) — qwen-web missing from PROVIDER_MODELS_CONFIG in
// src/app/api/providers/[id]/models/route.ts, so the model discovery page for
// the web-cookie provider returned nothing. Identified by @thezukiru in #3895.

import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";

import { getModelsByProviderId } from "../../open-sse/config/providerModels.ts";

// ── Task 1: kimi-k2.7-code in kmca (kimi-coding-apikey) ───────────────────────

test("kmca (kimi-coding-apikey) catalog includes moonshotai/kimi-k2.7-code", () => {
const models = getModelsByProviderId("kmca");
const ids = new Set(models.map((m) => m.id));
assert.ok(
ids.has("moonshotai/kimi-k2.7-code"),
"moonshotai/kimi-k2.7-code missing from kmca — add to KIMI_CODING_SHARED.models in shared.ts"
);
});

test("kmca kimi-k2.7-code has 262144 context length and maxOutputTokens", () => {
const models = getModelsByProviderId("kmca");
const model = models.find((m) => m.id === "moonshotai/kimi-k2.7-code");
assert.ok(model, "moonshotai/kimi-k2.7-code not found in kmca catalog");
assert.equal(model.contextLength, 262144, "kimi-k2.7-code contextLength must be 262144");
assert.equal(model.maxOutputTokens, 262144, "kimi-k2.7-code maxOutputTokens must be 262144");
});

test("kmca still exposes kimi-k2.6 and kimi-k2.6-thinking alongside the new model", () => {
const ids = new Set(getModelsByProviderId("kmca").map((m) => m.id));
assert.ok(ids.has("kimi-k2.6"), "kimi-k2.6 must still be present");
assert.ok(ids.has("kimi-k2.6-thinking"), "kimi-k2.6-thinking must still be present");
assert.ok(ids.has("moonshotai/kimi-k2.7-code"), "moonshotai/kimi-k2.7-code must be present");
});

// ── Bug #3 / issue #3931: qwen-web in PROVIDER_MODELS_CONFIG ──────────────────

const ROUTE_FILE = path.join("src", "app", "api", "providers", "[id]", "models", "route.ts");

test("PROVIDER_MODELS_CONFIG contains a qwen-web entry (issue #3931 bug #3)", () => {
const src = fs.readFileSync(ROUTE_FILE, "utf-8");
assert.match(
src,
/"qwen-web"\s*:/,
'"qwen-web" key missing from PROVIDER_MODELS_CONFIG in models/route.ts'
);
});

test("qwen-web PROVIDER_MODELS_CONFIG entry targets chat.qwen.ai/api/v2/models", () => {
const src = fs.readFileSync(ROUTE_FILE, "utf-8");
assert.match(
src,
/chat\.qwen\.ai\/api\/v2\/models/,
"qwen-web discovery URL must be https://chat.qwen.ai/api/v2/models"
);
});

test("qwen-web parseResponse handles Qwen nested data.data structure", () => {
const mockResponse = {
data: {
data: [
{ id: "qwen3.7-plus", name: "Qwen3.7-Plus", owned_by: "qwen" },
{ id: "qwen3-235b-a22b", name: "Qwen3-235B-A22B", owned_by: "qwen" },
{ id: "qwen3-coder-480b", name: "Qwen3-Coder-480B" },
],
},
};

// parseResponse logic matches PROVIDER_MODELS_CONFIG["qwen-web"].parseResponse
const innerData: Array<Record<string, unknown>> =
(mockResponse?.data?.data as Array<Record<string, unknown>>) ||
(mockResponse?.data as unknown as Array<Record<string, unknown>>) ||
[];
const models = innerData
.map((item) => ({
id: (item.id || item.name) as string,
name: (item.name || item.id) as string,
owned_by: (item.owned_by || "qwen") as string,
}))
.filter((m) => m.id);
Comment on lines +77 to +88

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This test copy-pastes the parsing logic from route.ts instead of importing and testing the actual production implementation. This creates a testing anti-pattern where the test will continue to pass even if the production implementation in route.ts is broken or modified.

To fix this, consider exporting PROVIDER_MODELS_CONFIG (or a specific helper) from src/app/api/providers/[id]/models/route.ts and importing it here to run the assertions directly against the production code.


assert.equal(models.length, 3);
assert.equal(models[0].id, "qwen3.7-plus");
assert.equal(models[0].name, "Qwen3.7-Plus");
assert.equal(models[0].owned_by, "qwen");
assert.equal(models[2].owned_by, "qwen", "owned_by defaults to 'qwen' when absent");
});

test("qwen-web parseResponse handles flat data array fallback", () => {
const mockResponse = {
data: [{ id: "qwen3.7-plus", name: "Qwen3.7-Plus" }],
};

const innerData: Array<Record<string, unknown>> =
(mockResponse?.data as unknown as { data?: Array<Record<string, unknown>> })?.data ||
(mockResponse?.data as unknown as Array<Record<string, unknown>>) ||
[];
const models = innerData
.map((item) => ({
id: (item.id || item.name) as string,
name: (item.name || item.id) as string,
owned_by: (item.owned_by || "qwen") as string,
}))
.filter((m) => m.id);

assert.equal(models.length, 1);
assert.equal(models[0].id, "qwen3.7-plus");
});
Loading