Skip to content
Closed
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
1 change: 1 addition & 0 deletions scripts/test-layout/layout.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"version": 1,
"root": "tests",
"explicit": {
"jev-decision-scope.test.ts": "server",
"claude-intercept-on-demand.test.ts": "claude-integration",
"main-account-hard-lock-thresholds.test.ts": "codex-integration",
"main-account-external-usage.test.ts": "codex-integration",
Expand Down
16 changes: 13 additions & 3 deletions src/combos/jev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ export interface ResolveJevDecisionOptions {
* any other id names a configured `jev-decision` row (for example a self-hosted Ollama `tev1`).
*/
decisionProvider?: string;
/** Request-local authorization of the concrete decision destination, before credential access. */
isDestinationAllowed?: (providerName: string, modelId: string) => boolean;
/** Decision deadline; values outside 1000..120000 ms keep the four-second default. */
timeoutMs?: number;
signal?: AbortSignal;
Expand Down Expand Up @@ -674,14 +676,20 @@ function selfHostedApiKey(name: string, apiKey: string | undefined): string | un
* custom destination. Any other id must be an enabled `jev-decision` row whose baseUrl is a
* `/systemone` endpoint and which names its own model; only its own key may accompany it, so no
* TypeSafe credential can reach a self-hosted service. `undefined` means no usable decision
* service (reported through the existing `missing_key` gate).
* service (reported through the existing `missing_key` gate); `null` means the request's
* destination scope refused it before any credential access.
*/
function jevDecisionEndpoint(config: OcxConfig, decisionProvider: string): JevDecisionEndpoint | undefined {
function jevDecisionEndpoint(
config: OcxConfig,
decisionProvider: string,
isDestinationAllowed?: ResolveJevDecisionOptions["isDestinationAllowed"],
): JevDecisionEndpoint | undefined | null {
const configured = Object.hasOwn(config.providers, decisionProvider)
? config.providers[decisionProvider]
: undefined;
if (configured?.disabled === true) return undefined;
if (decisionProvider === JEV_PROVIDER_ID) {
if (isDestinationAllowed?.(JEV_PROVIDER_ID, JEV_MODEL) === false) return null;
const configuredOwnsJev = configured
&& providerMatchesRegistryTransport(JEV_PROVIDER_ID, configured);
const apiKey = (
Expand All @@ -704,6 +712,7 @@ function jevDecisionEndpoint(config: OcxConfig, decisionProvider: string): JevDe
// `jev-latest` is TypeSafe's model name; a self-hosted host must name its own.
const model = configured.defaultModel?.trim() || configured.models?.[0]?.trim();
if (!model) return undefined;
if (isDestinationAllowed?.(decisionProvider, model) === false) return null;
const apiKey = selfHostedApiKey(decisionProvider, configured.apiKey);
if (apiKey === null) return undefined;
return {
Expand Down Expand Up @@ -733,7 +742,8 @@ export async function resolveJevDecision(options: ResolveJevDecisionOptions): Pr
if (options.candidates.length === 0) return failed("no_choices");
if (!candidatesFitRequestBounds(options.candidates)) return failed("invalid");

const endpoint = jevDecisionEndpoint(options.config, options.decisionProvider ?? JEV_PROVIDER_ID);
const endpoint = jevDecisionEndpoint(options.config, options.decisionProvider ?? JEV_PROVIDER_ID, options.isDestinationAllowed);
if (endpoint === null) return failed("invalid");
if (!endpoint) return failed("missing_key");

let requestBody: string;
Expand Down
4 changes: 4 additions & 0 deletions src/server/responses/core-combo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
isDeclaredReasoningEffort,
resolveEffortAtOrBelow,
} from "../../reasoning-effort";
import { resolveAdmissionModelScope, routeAllowedByScope } from "../admission-model-scope";
import { recordAttemptRequestedEffort } from "../request-log";
import {
CODEX_TEXT_GUARDED_BUDGET_POLICY,
Expand Down Expand Up @@ -572,6 +573,9 @@ export async function executeComboResponses(
candidates: choices.map(choice => choice.candidate),
fallback,
config,
isDestinationAllowed: (providerName, modelId) => routeAllowedByScope(
resolveAdmissionModelScope(config, options.admission), { providerName, modelId },
),
...(combo.decisionProvider ? { decisionProvider: combo.decisionProvider } : {}),
...(combo.decisionModel
? {
Expand Down
4 changes: 4 additions & 0 deletions structure/providers/jev-decision.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ the JEV credential are excluded. It owns the joint target/effort choice map, str
validation, canonical `jev-latest` destination, default four-second deadline, no-redirect policy, bounded response,
and caller-cancellation propagation. Missing credentials or safe state, transport failures, and invalid
answers fail open to the first eligible target; no response can escape the configured choice map.
The direct TypeSafe and System One decision destinations are checked against the parent API key's
resolved provider/model scope before reading decision credentials or extracting state. A denied
optional decision uses the existing fail-open inference target without sending a decision request;
management probes and unrestricted admissions retain their existing behavior.
Telemetry never retains extracted state or credentials.

The optional `targets[].modelProfile` note is validated at the Combo management input
Expand Down
1 change: 1 addition & 0 deletions tests/fixtures/test-layout-expected.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"jev-decision-scope.test.ts": "server",
"claude-intercept-on-demand.test.ts": "claude-integration",
"main-account-hard-lock-thresholds.test.ts": "codex-integration",
"main-account-external-usage.test.ts": "codex-integration",
Expand Down
100 changes: 100 additions & 0 deletions tests/server/jev-decision-scope.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { afterEach, describe, expect, test } from "bun:test";
import { clearComboSelectionState, clearComboTargetCooldowns, resolveJevDecision } from "../../src/combos";
import { createTranslatorBudget } from "../../src/lib/translator-budget";
import { executeComboResponses } from "../../src/server/responses/core-combo";
import { admissionModelScopeOf, routeAllowedByScope } from "../../src/server/admission-model-scope";
import type { DataPlaneAdmission } from "../../src/server/auth-cors";
import type { OcxConfig, OcxProviderConfig } from "../../src/types";

const admission: DataPlaneAdmission = { kind: "configured", keyId: "fixture-key", source: "bearer" };
afterEach(() => { clearComboSelectionState(); clearComboTargetCooldowns(); });

function fixture(scope: { allowedProviders?: string[]; allowedModels?: string[] }, decisionProvider = "decider") {
let keyReads = 0;
let sends = 0;
const decision: OcxProviderConfig = {
adapter: "jev-decision", baseUrl: "https://decider.example/v1/systemone", defaultModel: "tev1:4b", liveModels: false,
get apiKey() { keyReads++; return "fixture-decision-key"; },
fetch: (async () => {
sends++;
return Response.json({ answers: { route: { choice: "a/m2:low", confidence: 0.9 } } });
}) as typeof fetch,
};
const config: OcxConfig = {
port: 0, defaultProvider: "a",
apiKeys: [{ id: "fixture-key", key: "fixture-admission-key", name: "fixture", createdAt: "2026-01-01T00:00:00.000Z", ...scope }],
providers: {
a: { adapter: "openai-chat", baseUrl: "https://inference.example/v1", apiKey: "fixture-inference-key", liveModels: false,
models: ["m1", "m2"], modelReasoningEfforts: { m1: ["low"], m2: ["low"] } },
[decisionProvider]: decision,
},
combos: { auto: { alias: "auto", strategy: "jev", decisionProvider, targets: [{ provider: "a", model: "m1" }, { provider: "a", model: "m2" }] } },
};
return { config, decision, keyReads: () => keyReads, sends: () => sends };
}

async function run(config: OcxConfig) {
const body = { model: "auto", input: "Choose an appropriate model for this task.", stream: false };
const budget = createTranslatorBudget();
const children: string[] = [];
try {
const response = await executeComboResponses(new Request("http://127.0.0.1/v1/responses", {
method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body),
}), body, "auto", config, { model: "", provider: "" }, { translatorBudget: budget, admission }, {
async handleResponses(request, _config, _log, options) {
expect(options?.admission).toEqual(admission);
const child = await request.json() as { model: string };
children.push(child.model);
return Response.json({ id: "resp_fixture", object: "response", status: "completed", output: [] });
},
async handleComboResponses() { throw new Error("unexpected nested combo"); },
});
expect(response.status).toBe(200);
await response.text();
return children;
} finally { budget.dispose(); }
}

describe("JEV decision destination scope", () => {
test("a denied provider performs no credential work or send and keeps the inference fallback", async () => {
const f = fixture({ allowedProviders: ["a"], allowedModels: ["a/m1"] });
expect(await run(f.config)).toEqual(["a/m1"]);
expect(f.keyReads()).toBe(0);
expect(f.sends()).toBe(0);
});
test("model-only restrictions also prevent a decision send", async () => {
const f = fixture({ allowedModels: ["a/m1"] });
expect(await run(f.config)).toEqual(["a/m1"]);
expect(f.keyReads()).toBe(0);
expect(f.sends()).toBe(0);
});
test("an allowed normalized provider/model still decides the inference target", async () => {
const f = fixture({ allowedProviders: [" A ", " DECIDER "], allowedModels: ["a/m1", "a/m2", " DECIDER/TEV1:4B "] });
expect(await run(f.config)).toEqual(["a/m2"]);
expect(f.keyReads()).toBeGreaterThan(0);
expect(f.sends()).toBe(1);
});
for (const decisionProvider of [undefined, "jev", "decider"]) {
test(`${decisionProvider ?? "default jev"}: checks the concrete destination before credentials`, async () => {
const name = decisionProvider ?? "jev";
const f = fixture({}, name);
if (name === "jev") f.decision.baseUrl = "https://api.typesafe.ai/v1/systemone";
const seen: string[] = [];
const result = await resolveJevDecision({
config: f.config, decisionProvider,
body: { input: "hello" },
candidates: [{ key: "a/m1", provider: "a", model: "m1", reasoningEfforts: ["low"] },
{ key: "a/m2", provider: "a", model: "m2", reasoningEfforts: ["low"] }],
fallback: { targetKey: "a/m1", effort: "low" },
isDestinationAllowed(providerName, modelId) { seen.push(`${providerName}/${modelId}`); return false; },
});
expect(seen).toEqual([name === "jev" ? "jev/jev-latest" : "decider/tev1:4b"]);
expect(result).toMatchObject({ targetKey: "a/m1", gate: "invalid" });
expect(f.keyReads()).toBe(0);
expect(f.sends()).toBe(0);
});
}
test("bare model allowlists preserve their existing meaning", () => {
expect(routeAllowedByScope(admissionModelScopeOf({ allowedModels: ["TEV1:4B"] }), { providerName: "decider", modelId: "tev1:4b" })).toBe(true);
});
});
Loading