Skip to content

Commit a4eb3c0

Browse files
committed
fix(openrouter): use a direct comparison for the K3 profile guard
Replace the per-call Set allocation in applyOpenRouterMoonshotK3Profile with the same direct-comparison shape as the gpt-6-astra guard in parseOpenRouterModel (review feedback: the Set was allocated on every non-K3 call before the early return). Add direct unit tests covering both catalogue ids (including the tilde-prefixed rolling alias ~moonshotai/kimi-latest) and the non-K3 pass-through, so the guard's mutants stay killed at the lowest layer.
1 parent 6108884 commit a4eb3c0

2 files changed

Lines changed: 52 additions & 2 deletions

File tree

‎src/api/providers/__tests__/openrouter.spec.ts‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ import { Anthropic } from "@anthropic-ai/sdk"
1818
import OpenAI from "openai"
1919

2020
import { providerIdentifiers } from "@roo-code/types"
21+
import type { ModelInfo } from "@roo-code/types"
22+
23+
import { applyOpenRouterMoonshotK3Profile } from "../fetchers/openrouter"
2124

2225
import { OpenRouterHandler } from "../openrouter"
2326
import { Package } from "../../../shared/package"
@@ -335,6 +338,51 @@ describe("OpenRouterHandler", () => {
335338
})
336339
})
337340

341+
describe("applyOpenRouterMoonshotK3Profile", () => {
342+
// Stale cache record shape: fabricated 0.2 context-window max_tokens and a
343+
// boolean supportsReasoningEffort with no default effort (pre-profile).
344+
const staleK3Record: ModelInfo = {
345+
maxTokens: 209_716,
346+
contextWindow: 1_000_000,
347+
supportsImages: true,
348+
supportsPromptCache: true,
349+
inputPrice: 0.6,
350+
outputPrice: 3,
351+
description: "Kimi K3 (stale cache)",
352+
supportsReasoningEffort: true,
353+
}
354+
355+
it("applies the profile to the exact moonshotai/kimi-k3 id", () => {
356+
const result = applyOpenRouterMoonshotK3Profile("moonshotai/kimi-k3", { ...staleK3Record })
357+
358+
expect(result.maxTokens).toBe(32_768)
359+
expect(result.supportsReasoningEffort).toEqual(["low", "high", "max"])
360+
expect(result.reasoningEffort).toBe("high")
361+
expect(result.supportsTemperature).toBe(true)
362+
expect(result.defaultTemperature).toBe(1.0)
363+
// Unprofiled fields pass through from the (stale) record
364+
expect(result.contextWindow).toBe(1_000_000)
365+
expect(result.description).toBe("Kimi K3 (stale cache)")
366+
})
367+
368+
it("applies the profile to the tilde-prefixed rolling alias", () => {
369+
const result = applyOpenRouterMoonshotK3Profile("~moonshotai/kimi-latest", { ...staleK3Record })
370+
371+
// The catalogue keeps the ~ prefix on the rolling alias id, so the profile
372+
// must recognize the exact string rather than a stripped or bare alias
373+
expect(result.maxTokens).toBe(32_768)
374+
expect(result.supportsReasoningEffort).toEqual(["low", "high", "max"])
375+
expect(result.reasoningEffort).toBe("high")
376+
expect(result.supportsTemperature).toBe(true)
377+
expect(result.defaultTemperature).toBe(1.0)
378+
})
379+
380+
it("leaves non-K3 model records untouched", () => {
381+
const record: ModelInfo = { ...staleK3Record }
382+
383+
expect(applyOpenRouterMoonshotK3Profile("moonshotai/kimi-k2-thinking", record)).toBe(record)
384+
})
385+
})
338386
describe("createMessage", () => {
339387
it("generates correct stream chunks", async () => {
340388
const handler = new OpenRouterHandler(mockOptions)

‎src/api/providers/fetchers/openrouter.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,10 @@ export async function getOpenRouterModelEndpoints(
207207
* `moonshotai/kimi-k3` id.
208208
*/
209209
export const applyOpenRouterMoonshotK3Profile = (modelId: string, modelInfo: ModelInfo): ModelInfo => {
210-
const moonshotK3Models = new Set<string>(["moonshotai/kimi-k3", "~moonshotai/kimi-latest"])
211-
if (!moonshotK3Models.has(modelId)) {
210+
// Direct comparisons instead of a Set: this runs for every model record during parsing and
211+
// again at consumption time, so the common non-K3 case must not pay a per-call allocation.
212+
// Same shape as the gpt-6-astra guard in parseOpenRouterModel.
213+
if (modelId !== "moonshotai/kimi-k3" && modelId !== "~moonshotai/kimi-latest") {
212214
return modelInfo
213215
}
214216
const moonshotK3Profile: Partial<ModelInfo> = {

0 commit comments

Comments
 (0)