feat(providers): add TypeSafe System One client for Jev routing (#15278)

Adds the non-chat `typesafe` credential provider, a bounded fail-open System One client (`evaluateSystemOneChoice`) and a key validator that probes System One. Credential + client only: no public /v1/systemone route, no chat models (#15276 prerequisite slice of #13987 Part 1).

⚠️ base-red inherited: #15306
This commit is contained in:
Miguel Enes 2026-10-10 00:12:23 +01:00 • committed by GitHub
parent e80dfd00ae
commit 4e348e8a45
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 598 additions and 1 deletions

View file

@ -0,0 +1,276 @@
/**
* TypeSafe System One client — typed evaluation against api.typesafe.ai.
*
* Used by the jev combo strategy (#15276) to ask Jev which configured model
* should handle a request. Not a chat executor: System One answers noul /
* choice / score questions and returns calibrated probabilities.
*
* Docs: https://docs.typesafe.ai/api
*/
import { sanitizeErrorMessage } from "../../utils/error.ts";
export const TYPESAFE_PROVIDER_ID = "typesafe";
export const TYPESAFE_SYSTEM_ONE_BASE_URL = "https://api.typesafe.ai";
export const TYPESAFE_SYSTEM_ONE_PATH = "/v1/systemone";
export const TYPESAFE_DEFAULT_MODEL = "jev-latest";
/** Hard ceiling so a hung TypeSafe call cannot stall combo dispatch. */
export const TYPESAFE_SYSTEM_ONE_TIMEOUT_MS = 8_000;
/** TypeSafe choice questions accept at most 255 options. */
export const TYPESAFE_MAX_CHOICE_OPTIONS = 255;
/** Cap on `state` so a long transcript cannot be forwarded wholesale. */
export const TYPESAFE_MAX_STATE_CHARS = 8_000;
type FetchLike = typeof fetch;
export type SystemOneChoiceCriteria = Readonly<Record<string, string | null>>;
export type SystemOneChoiceSuccess = {
ok: true;
choice: string;
probabilities: Record<string, number>;
confidence: number;
model: string | null;
inputTokens: number | null;
outputTokens: number | null;
};
export type SystemOneUnavailableReason =
| "missing_api_key"
| "empty_criteria"
| "timeout"
| "http_error"
| "invalid_response"
| "network_error";
export type SystemOneChoiceUnavailable = {
ok: false;
reason: SystemOneUnavailableReason;
status: number | null;
/** Sanitized, safe to log or put in a decision-trace detail field. */
detail: string;
};
export type SystemOneChoiceResult = SystemOneChoiceSuccess | SystemOneChoiceUnavailable;
export type EvaluateSystemOneChoiceOptions = {
apiKey: string | null | undefined;
state: string;
criteria: SystemOneChoiceCriteria;
/** Defaults to a routing-oriented instruction. */
instructions?: string;
model?: string;
timeoutMs?: number;
fetchImpl?: FetchLike;
baseUrl?: string;
/** Aborted when the caller cancels; combined with the timeout. */
signal?: AbortSignal | null;
};
const DEFAULT_INSTRUCTIONS =
"Which of these configured models is the most appropriate for this request?";
function unavailable(
reason: SystemOneUnavailableReason,
detail: string,
status: number | null = null
): SystemOneChoiceUnavailable {
return {
ok: false,
reason,
status,
detail: sanitizeErrorMessage(detail) || reason,
};
}
function isRecord(value: unknown): value is Record<string, unknown> {
return !!value && typeof value === "object" && !Array.isArray(value);
}
function toFiniteNumber(value: unknown): number | null {
const n = typeof value === "number" ? value : typeof value === "string" ? Number(value) : NaN;
return Number.isFinite(n) ? n : null;
}
function parseProbabilities(value: unknown): Record<string, number> | null {
if (!isRecord(value)) return null;
const out: Record<string, number> = {};
for (const [key, raw] of Object.entries(value)) {
const n = toFiniteNumber(raw);
if (n === null || n < 0) return null;
out[key] = n;
}
return out;
}
/**
* Parse a System One response body into a choice result. Pure — no I/O.
* Exported for unit tests.
*/
export function parseSystemOneChoiceResponse(body: unknown): SystemOneChoiceResult {
if (!isRecord(body)) {
return unavailable("invalid_response", "System One response was not a JSON object");
}
const answers = body.answers;
if (!isRecord(answers)) {
return unavailable("invalid_response", "System One response missing answers");
}
const route = answers.route;
if (!isRecord(route)) {
return unavailable("invalid_response", "System One response missing answers.route");
}
if (route.type !== "choice") {
return unavailable(
"invalid_response",
`System One answers.route.type was ${String(route.type)}, expected choice`
);
}
const choice = typeof route.choice === "string" ? route.choice.trim() : "";
if (!choice) {
return unavailable("invalid_response", "System One choice answer had an empty choice");
}
const probabilities = parseProbabilities(route.probabilities);
if (!probabilities) {
return unavailable("invalid_response", "System One choice answer missing probabilities");
}
const confidence = toFiniteNumber(route.confidence);
if (confidence === null || confidence < 0 || confidence > 1) {
return unavailable("invalid_response", "System One choice answer missing confidence");
}
const usage = isRecord(body.usage) ? body.usage : null;
return {
ok: true,
choice,
probabilities,
confidence,
model: typeof body.model === "string" ? body.model : null,
inputTokens: usage ? toFiniteNumber(usage.input_tokens) : null,
outputTokens: usage ? toFiniteNumber(usage.output_tokens) : null,
};
}
/**
* Ask System One (Jev) to pick one option from `criteria`.
*
* Never throws. Missing key, timeout, HTTP errors, and malformed bodies all
* return `{ ok: false, reason, ... }` so combo dispatch can fall open.
*/
export async function evaluateSystemOneChoice(
options: EvaluateSystemOneChoiceOptions
): Promise<SystemOneChoiceResult> {
const apiKey = typeof options.apiKey === "string" ? options.apiKey.trim() : "";
if (!apiKey) {
return unavailable("missing_api_key", "No TypeSafe API key configured");
}
const criteriaEntries = Object.entries(options.criteria || {}).filter(
([key]) => typeof key === "string" && key.trim().length > 0
);
if (criteriaEntries.length === 0) {
return unavailable("empty_criteria", "System One choice requires at least one criterion");
}
if (criteriaEntries.length > TYPESAFE_MAX_CHOICE_OPTIONS) {
return unavailable(
"invalid_response",
`System One choice accepts at most ${TYPESAFE_MAX_CHOICE_OPTIONS} options`
);
}
const criteria: Record<string, string | null> = {};
for (const [key, value] of criteriaEntries) {
criteria[key.trim()] =
typeof value === "string"
? value
: value === null || value === undefined
? null
: String(value);
}
const rawState = typeof options.state === "string" ? options.state : "";
const state =
rawState.length > TYPESAFE_MAX_STATE_CHARS
? rawState.slice(0, TYPESAFE_MAX_STATE_CHARS)
: rawState;
const instructions =
typeof options.instructions === "string" && options.instructions.trim().length > 0
? options.instructions.trim()
: DEFAULT_INSTRUCTIONS;
const model =
typeof options.model === "string" && options.model.trim().length > 0
? options.model.trim()
: TYPESAFE_DEFAULT_MODEL;
const timeoutMs =
typeof options.timeoutMs === "number" &&
Number.isFinite(options.timeoutMs) &&
options.timeoutMs > 0
? options.timeoutMs
: TYPESAFE_SYSTEM_ONE_TIMEOUT_MS;
const baseUrl = (options.baseUrl || TYPESAFE_SYSTEM_ONE_BASE_URL).replace(/\/+$/, "");
const fetchImpl = options.fetchImpl ?? fetch;
if (options.signal?.aborted) {
return unavailable("timeout", "System One call aborted before it started");
}
const controller = new AbortController();
const onAbort = () => controller.abort();
options.signal?.addEventListener("abort", onAbort, { once: true });
const timer = setTimeout(() => controller.abort(), timeoutMs);
try {
const response = await fetchImpl(`${baseUrl}${TYPESAFE_SYSTEM_ONE_PATH}`, {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model,
state,
questions: {
route: {
type: "choice",
instructions,
criteria,
},
},
}),
signal: controller.signal,
});
if (!response.ok) {
// Status only. Upstream bodies can echo the state or the key.
return unavailable(
"http_error",
`System One returned HTTP ${response.status}`,
response.status
);
}
let json: unknown;
try {
json = await response.json();
} catch (err) {
const message = err instanceof Error ? err.message : "invalid JSON";
return unavailable("invalid_response", `System One response was not JSON: ${message}`);
}
return parseSystemOneChoiceResponse(json);
} catch (err) {
if (err instanceof Error && err.name === "AbortError") {
return unavailable("timeout", `System One timed out after ${timeoutMs}ms`);
}
return unavailable("network_error", "System One request failed");
} finally {
clearTimeout(timer);
options.signal?.removeEventListener("abort", onAbort);
}
}

View file

@ -80,6 +80,7 @@ import {
validateNousResearchProvider,
validatePoeProvider,
} from "./validation/audioMiscProviders";
import { validateTypesafeProvider } from "./validation/typesafe";
import { validateZaiWebProvider } from "./validation/zaiWeb";
import { validateSearchProvider, SEARCH_VALIDATOR_CONFIGS } from "./validation/searchProviders";
import {
@ -326,6 +327,7 @@ export async function validateProviderApiKey({
nlpcloud: validateNlpCloudProvider,
oneminai: validateOneMinAiProvider,
runwayml: validateRunwayProvider,
typesafe: ({ apiKey }: any) => validateTypesafeProvider({ apiKey }),
snowflake: validateSnowflakeProvider,
gigachat: validateGigachatProvider,
"deepseek-web": validateDeepSeekWebProvider,

View file

@ -0,0 +1,67 @@
/**
* TypeSafe AI (System One / Jev) API-key validation.
*
* Probes POST /v1/systemone with a tiny choice question. A 2xx with a parseable
* choice means the key works; 401/403 means invalid; everything else is treated
* as unavailable (credentials may still be fine).
*/
import {
evaluateSystemOneChoice,
type SystemOneChoiceUnavailable,
} from "@omniroute/open-sse/services/typesafe/systemOne.ts";
export async function validateTypesafeProvider({
apiKey,
fetchImpl,
}: {
apiKey?: string | null;
fetchImpl?: typeof fetch;
}) {
const result = await evaluateSystemOneChoice({
apiKey,
state: "ping",
instructions: "Pick any option.",
criteria: {
ok: "A valid routing destination",
other: "Any other destination",
},
timeoutMs: 10_000,
fetchImpl,
});
if (result.ok) {
return { valid: true, error: null, method: "typesafe_systemone" };
}
// `strict: false` does not narrow the union by the boolean `ok`; past the early return it is the failure arm.
const failure = result as SystemOneChoiceUnavailable;
if (failure.reason === "missing_api_key") {
return { valid: false, error: "API key is required" };
}
if (failure.reason === "http_error" && (failure.status === 401 || failure.status === 403)) {
return { valid: false, error: "Invalid API key" };
}
if (failure.reason === "http_error" && failure.status === 429) {
return {
valid: true,
error: null,
method: "typesafe_systemone",
warning: "Rate limited, but credentials appear valid",
};
}
if (failure.reason === "timeout" || failure.reason === "network_error") {
return {
valid: false,
error: `TypeSafe unreachable (${failure.reason})`,
};
}
return {
valid: false,
error: failure.detail || `TypeSafe validation failed (${failure.reason})`,
};
}

View file

@ -166,6 +166,23 @@ export const APIKEY_PROVIDERS_SPECIALTY = {
hasFree: true,
freeNote: "10M free tokens on signup (non-commercial), no credit card required",
},
// Decision / evaluation API (System One / Jev). Not a chat provider — no
// chat models in the registry. Used by the jev combo strategy (#15276) and
// by any future System One passthrough (#13987).
typesafe: {
id: "typesafe",
serviceKinds: [],
alias: "typesafe",
name: "TypeSafe AI",
icon: "psychology",
color: "#4F46E5",
textIcon: "TS",
website: "https://docs.typesafe.ai",
authHint:
"Bearer API key for api.typesafe.ai. OmniRoute uses it for System One evaluation (Jev) — not chat completions. Store the key here; the jev combo strategy reads it at request time.",
apiHint:
"TypeSafe System One answers typed questions (noul / choice / score) against a state. OmniRoute does not expose TypeSafe models in chat pickers or combos.",
},
"fal-ai": {
id: "fal-ai",
serviceKinds: [],

View file

@ -46,6 +46,7 @@
// Unifically (gateways, #14182) adds one apikey entry — 244.
// BeatAPI (#14875) extracts one aggregator gateway into apikey/beatapi.ts and spreads it
// from the barrel — 245.
// TypeSafe System One (#15278, non-chat `typesafe` credential provider) adds one specialty-media entry — 249.
import { test } from "node:test";
import assert from "node:assert/strict";
@ -53,7 +54,7 @@ const P = await import("../../src/shared/constants/providers.ts");
// Apmix (#14821) adds one apikey/regional entry — 246.
// Token Market (#13191) adds one apikey/gateways entry — measured 248 on the #13191 branch.
const APIKEY_PROVIDER_COUNT = 248;
const APIKEY_PROVIDER_COUNT = 249;
test("barrel still exports every catalog + key helpers", () => {
for (const name of [

View file

@ -0,0 +1,234 @@
/**
* TypeSafe System One client + provider registration tests (#15276 PR 1).
*/
import test from "node:test";
import assert from "node:assert/strict";
import {
evaluateSystemOneChoice,
parseSystemOneChoiceResponse,
TYPESAFE_MAX_CHOICE_OPTIONS,
TYPESAFE_MAX_STATE_CHARS,
TYPESAFE_PROVIDER_ID,
TYPESAFE_SYSTEM_ONE_PATH,
} from "../../open-sse/services/typesafe/systemOne.ts";
import { APIKEY_PROVIDERS } from "../../src/shared/constants/providers.ts";
import { getRegistryEntry } from "../../open-sse/config/providerRegistry.ts";
import { getStaticModelsForProvider } from "../../src/lib/providers/staticModels.ts";
import { getProviderModels } from "../../open-sse/config/providerModels.ts";
import { filterChatSelectableModels } from "../../open-sse/services/modelEndpointPolicy.ts";
import { validateTypesafeProvider } from "../../src/lib/providers/validation/typesafe.ts";
test("typesafe is registered as an API-key specialty provider with no chat serviceKinds", () => {
const entry = APIKEY_PROVIDERS.typesafe;
assert.ok(entry, "typesafe must exist in APIKEY_PROVIDERS");
assert.equal(entry.id, TYPESAFE_PROVIDER_ID);
assert.deepEqual(entry.serviceKinds, []);
assert.match(String(entry.authHint || ""), /Bearer/i);
});
test("typesafe has no chat registry models and no static catalog", () => {
assert.equal(getRegistryEntry(TYPESAFE_PROVIDER_ID), null);
assert.equal(getStaticModelsForProvider(TYPESAFE_PROVIDER_ID), undefined);
assert.deepEqual(getProviderModels(TYPESAFE_PROVIDER_ID), []);
});
test("typesafe models are absent from chat-selectable filtering", () => {
// Even if a stray model row were imported, empty serviceKinds + no registry
// means operators should never see typesafe in combo chat pickers. An empty
// catalog filters to empty.
const filtered = filterChatSelectableModels(TYPESAFE_PROVIDER_ID, []);
assert.deepEqual(filtered, []);
});
test("parseSystemOneChoiceResponse accepts a valid choice answer", () => {
const result = parseSystemOneChoiceResponse({
model: "jev-1.13.0",
answers: {
route: {
type: "choice",
choice: "step-a",
probabilities: { "step-a": 0.72, "step-b": 0.2, "step-c": 0.08 },
confidence: 0.84,
},
},
usage: { input_tokens: 120, output_tokens: 18 },
});
assert.equal(result.ok, true);
if (!result.ok) return;
assert.equal(result.choice, "step-a");
assert.equal(result.confidence, 0.84);
assert.equal(result.probabilities["step-a"], 0.72);
assert.equal(result.model, "jev-1.13.0");
assert.equal(result.inputTokens, 120);
assert.equal(result.outputTokens, 18);
});
test("parseSystemOneChoiceResponse rejects a malformed body", () => {
const result = parseSystemOneChoiceResponse({ answers: {} });
assert.equal(result.ok, false);
if (result.ok) return;
assert.equal(result.reason, "invalid_response");
});
test("evaluateSystemOneChoice returns missing_api_key without calling fetch", async () => {
let called = false;
const result = await evaluateSystemOneChoice({
apiKey: " ",
state: "hi",
criteria: { a: "A" },
fetchImpl: async () => {
called = true;
return new Response("{}", { status: 200 });
},
});
assert.equal(called, false);
assert.equal(result.ok, false);
if (result.ok) return;
assert.equal(result.reason, "missing_api_key");
});
test("evaluateSystemOneChoice posts a choice question and parses the answer", async () => {
const calls: Array<{ url: string; init: RequestInit }> = [];
const result = await evaluateSystemOneChoice({
apiKey: "ts_test_key",
state: "rewrite this email",
criteria: { opus: "Claude Opus", glm: "GLM" },
fetchImpl: async (url, init) => {
calls.push({ url: String(url), init: init || {} });
return new Response(
JSON.stringify({
model: "jev-1.13.0",
answers: {
route: {
type: "choice",
choice: "glm",
probabilities: { opus: 0.1, glm: 0.9 },
confidence: 0.91,
},
},
usage: { input_tokens: 40, output_tokens: 10 },
}),
{ status: 200, headers: { "Content-Type": "application/json" } }
);
},
});
assert.equal(calls.length, 1);
assert.ok(calls[0].url.endsWith(TYPESAFE_SYSTEM_ONE_PATH));
const headers = calls[0].init.headers as Record<string, string>;
assert.equal(headers.Authorization, "Bearer ts_test_key");
const body = JSON.parse(String(calls[0].init.body));
assert.equal(body.model, "jev-latest");
assert.equal(body.state, "rewrite this email");
assert.equal(body.questions.route.type, "choice");
assert.deepEqual(body.questions.route.criteria, { opus: "Claude Opus", glm: "GLM" });
assert.equal(result.ok, true);
if (!result.ok) return;
assert.equal(result.choice, "glm");
assert.equal(result.confidence, 0.91);
});
test("evaluateSystemOneChoice maps HTTP 401 to unavailable without throwing", async () => {
const result = await evaluateSystemOneChoice({
apiKey: "bad",
state: "hi",
criteria: { a: "A" },
fetchImpl: async () => new Response(JSON.stringify({ error: "unauthorized" }), { status: 401 }),
});
assert.equal(result.ok, false);
if (result.ok) return;
assert.equal(result.reason, "http_error");
assert.equal(result.status, 401);
assert.equal(result.detail, "System One returned HTTP 401");
assert.doesNotMatch(result.detail, /unauthorized|Bearer |sk-|ts_test/);
});
test("evaluateSystemOneChoice maps AbortError to timeout without throwing", async () => {
const result = await evaluateSystemOneChoice({
apiKey: "key",
state: "hi",
criteria: { a: "A" },
timeoutMs: 5,
fetchImpl: async (_url, init) => {
const signal = init?.signal;
return await new Promise((_resolve, reject) => {
const onAbort = () => {
const err = new Error("aborted");
err.name = "AbortError";
reject(err);
};
if (signal?.aborted) onAbort();
else signal?.addEventListener("abort", onAbort, { once: true });
});
},
});
assert.equal(result.ok, false);
if (result.ok) return;
assert.equal(result.reason, "timeout");
});
test("evaluateSystemOneChoice truncates state and refuses more than 255 options", async () => {
let posted = "";
const long = "x".repeat(TYPESAFE_MAX_STATE_CHARS + 50);
const result = await evaluateSystemOneChoice({
apiKey: "key",
state: long,
criteria: { a: "A" },
fetchImpl: async (_url, init) => {
posted = String(init?.body);
return new Response(
JSON.stringify({
answers: {
route: { type: "choice", choice: "a", probabilities: { a: 1 }, confidence: 1 },
},
}),
{ status: 200 }
);
},
});
assert.equal(result.ok, true);
assert.equal(JSON.parse(posted).state.length, TYPESAFE_MAX_STATE_CHARS);
let called = false;
const criteria: Record<string, string> = {};
for (let i = 0; i < TYPESAFE_MAX_CHOICE_OPTIONS + 1; i++) criteria[`k${i}`] = `L${i}`;
const tooMany = await evaluateSystemOneChoice({
apiKey: "key",
state: "hi",
criteria,
fetchImpl: async () => {
called = true;
return new Response("no", { status: 500 });
},
});
assert.equal(called, false);
assert.equal(tooMany.ok, false);
});
test("validateTypesafeProvider maps a probe without sending the key to the error", async () => {
const valid = await validateTypesafeProvider({
apiKey: "ts_live_key",
fetchImpl: async () =>
new Response(
JSON.stringify({
answers: {
route: { type: "choice", choice: "ok", probabilities: { ok: 1 }, confidence: 1 },
},
}),
{ status: 200 }
),
});
assert.equal(valid.valid, true);
const invalid = await validateTypesafeProvider({
apiKey: "ts_live_key",
fetchImpl: async () =>
new Response(JSON.stringify({ error: "nope ts_live_key" }), { status: 401 }),
});
assert.equal(invalid.valid, false);
assert.equal(invalid.error, "Invalid API key");
assert.doesNotMatch(JSON.stringify(invalid), /ts_live_key/);
});