Files
OmniRoute/open-sse/config/codexClient.ts
Praveen K Palaniswamy 65e81158ab fix(ollama): route models by advertised capability (#11088)
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host.

Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean.

Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
2026-08-23 11:45:01 -03:00

92 lines
3.1 KiB
TypeScript

import {
CODEX_CLI_RS_ORIGINATOR,
DEFAULT_CODEX_CLIENT_VERSION,
getCodexCliRsHeaders as buildCodexCliRsHeaders,
} from "@/shared/constants/codexClient";
export {
DEFAULT_CODEX_CLIENT_VERSION,
CODEX_CLI_RS_ORIGINATOR,
} from "@/shared/constants/codexClient";
const DEFAULT_CODEX_USER_AGENT_PLATFORM = "Windows 10.0.26200";
const DEFAULT_CODEX_USER_AGENT_ARCH = "x64";
const CODEX_VERSION_OVERRIDE_ENV = "CODEX_CLIENT_VERSION";
const CODEX_USER_AGENT_OVERRIDE_ENV = "CODEX_USER_AGENT";
const SAFE_HEADER_TOKEN_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$/;
const SAFE_HEADER_VALUE_PATTERN = /^[\x20-\x7E]{1,200}$/;
const SAFE_CODEX_SESSION_ID_PATTERN = /^[A-Za-z0-9._:-]{1,200}$/;
function getSafeEnvValue(name: string, pattern: RegExp): string | null {
const raw = process.env[name];
if (typeof raw !== "string") return null;
const normalized = raw.trim();
if (!normalized || !pattern.test(normalized)) {
return null;
}
return normalized;
}
export function getCodexClientVersion(): string {
return (
getSafeEnvValue(CODEX_VERSION_OVERRIDE_ENV, SAFE_HEADER_TOKEN_PATTERN) ||
DEFAULT_CODEX_CLIENT_VERSION
);
}
export function getCodexUserAgent(): string {
const override = getSafeEnvValue(CODEX_USER_AGENT_OVERRIDE_ENV, SAFE_HEADER_VALUE_PATTERN);
if (override) {
return override;
}
return `codex-cli/${getCodexClientVersion()} (${DEFAULT_CODEX_USER_AGENT_PLATFORM}; ${DEFAULT_CODEX_USER_AGENT_ARCH})`;
}
export function getCodexDefaultHeaders(): Record<string, string> {
return {
Version: getCodexClientVersion(),
"Openai-Beta": "responses=experimental",
"X-Codex-Beta-Features": "responses_websockets",
"User-Agent": getCodexUserAgent(),
};
}
export function getCodexCliRsHeaders(): Record<string, string> {
return buildCodexCliRsHeaders(getCodexClientVersion());
}
/**
* Identity for the credential face (auth.openai.com: token exchange / refresh).
* The real Codex client sends only `originator` + `User-Agent` on that face
* (codex-rs login/default_client.rs default_headers()); the `Version` header
* gate exists only on the chatgpt.com/backend-api inference face, so it is
* deliberately omitted here. Mirrors sub2api v0.1.178
* ApplyCodexCanonicalAuthIdentity.
*/
export function getCodexAuthIdentityHeaders(): Record<string, string> {
return {
"User-Agent": getCodexUserAgent(),
originator: CODEX_CLI_RS_ORIGINATOR,
};
}
/**
* Canonical Codex CLI identity for server-initiated calls against the
* chatgpt.com/backend-api face that are not tied to one end-client request
* (usage / quota / models manifest / reset-credits). Same UA/version chain as
* inference so these calls do not show up upstream as anonymous half-identities.
*/
export function getCodexBackendIdentityHeaders(): Record<string, string> {
return {
"User-Agent": getCodexUserAgent(),
originator: CODEX_CLI_RS_ORIGINATOR,
Version: getCodexClientVersion(),
};
}
export function normalizeCodexSessionId(value: unknown): string | null {
if (typeof value !== "string") return null;
const normalized = value.trim();
return SAFE_CODEX_SESSION_ID_PATTERN.test(normalized) ? normalized : null;
}