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
9 changes: 7 additions & 2 deletions src/server/responses/input-admission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import { nativeOpenAiContextWindow, nativeOpenAiMaxInputTokens, type NativeContextLimitsInput } from "../../codex/catalog/metadata";
import { estimateTokens } from "../../lib/token-estimate";
import { isCanonicalOpenAiForwardProvider, OPENAI_CODEX_PROVIDER_ID } from "../../providers/openai-tiers";
import { modelRecordValue } from "../../reasoning-effort";
import type { OcxContentPart, OcxParsedRequest, OcxProviderConfig } from "../../types";

/**
Expand Down Expand Up @@ -133,7 +134,11 @@ export function resolveInputCeiling(
// config here so this stays pure: no filesystem, no catalog, no registry scan.
nativeContextCap?: NativeContextLimitsInput,
): number | null {
const configured = positive(provider.modelContextWindows?.[modelId]) ?? positive(provider.contextWindow);
// `modelRecordValue`, not a bare lookup: the catalog resolves these same two maps that
// way, so a `gpt-oss` entry covers `gpt-oss:120b`. Reading raw here made the gate fall
// back to the provider-wide window and refuse turns the model can plainly hold.
const configured = positive(modelRecordValue(provider.modelContextWindows, modelId))
?? positive(provider.contextWindow);

// The canonical `openai` registry entry declares no context fields, so without this the
// gate would be inert on the default Codex route. All three clauses are load-bearing: a
Expand All @@ -156,7 +161,7 @@ export function resolveInputCeiling(

const window = canonicalNativeBare ? native : configured;
// modelMaxInputTokens is an input-only cap, so it can only tighten the window.
const configuredMaxInput = positive(provider.modelMaxInputTokens?.[modelId]);
const configuredMaxInput = positive(modelRecordValue(provider.modelMaxInputTokens, modelId));
const limits = [window, configuredMaxInput, nativeMaxInput].filter((v): v is number => v !== null);
return limits.length === 0 ? null : Math.min(...limits);
}
Expand Down
37 changes: 37 additions & 0 deletions tests/input-admission.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
estimateInputTokens,
resolveInputCeiling,
} from "../src/server/responses/input-admission";
import { modelRecordValue } from "../src/reasoning-effort";
import type { OcxMessage, OcxParsedRequest, OcxProviderConfig, OcxTool } from "../src/types";

const CANONICAL_NATIVE: OcxProviderConfig = {
Expand Down Expand Up @@ -91,6 +92,42 @@ describe("resolveInputCeiling", () => {
const pinned: OcxProviderConfig = { ...CANONICAL_NATIVE, modelContextWindows: { "gpt-5.6-sol": 50_000 } };
expect(resolveInputCeiling(pinned, "openai", "gpt-5.6-sol")).toBe(50_000);
});

test("a family entry covers its tagged siblings, like the catalog", () => {
// The catalog resolves modelContextWindows through modelRecordValue, so it advertises
// 131_072 for gpt-oss:120b off this config. A bare lookup here resolved nothing and
// fell back to contextWindow, leaving the gate refusing turns the model can hold.
const provider: OcxProviderConfig = {
adapter: "openai-chat",
baseUrl: "https://example.test/v1",
contextWindow: 8_000,
modelContextWindows: { "gpt-oss": 131_072 },
};
expect(modelRecordValue(provider.modelContextWindows, "gpt-oss:120b")).toBe(131_072);
expect(resolveInputCeiling(provider, "custom", "gpt-oss:120b")).toBe(131_072);
// An id with no tag and no entry still falls back to the provider-wide window.
expect(resolveInputCeiling(provider, "custom", "other")).toBe(8_000);
});

test("an exact entry still beats the family entry", () => {
const provider: OcxProviderConfig = {
adapter: "openai-chat",
baseUrl: "https://example.test/v1",
modelContextWindows: { "gpt-oss": 131_072, "gpt-oss:20b": 32_000 },
};
expect(resolveInputCeiling(provider, "custom", "gpt-oss:20b")).toBe(32_000);
expect(resolveInputCeiling(provider, "custom", "gpt-oss:120b")).toBe(131_072);
});

test("a family modelMaxInputTokens tightens its tagged siblings", () => {
const provider: OcxProviderConfig = {
adapter: "openai-chat",
baseUrl: "https://example.test/v1",
modelContextWindows: { "gpt-oss": 131_072 },
modelMaxInputTokens: { "gpt-oss": 40_000 },
};
expect(resolveInputCeiling(provider, "custom", "gpt-oss:120b")).toBe(40_000);
});
});

describe("estimateInputTokens", () => {
Expand Down
Loading