Files
OmniRoute/open-sse/handlers/chatCore/requestFormat.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

127 lines
4.5 KiB
TypeScript

/**
* chatCore request endpoint/format resolvers (Quality Gate v2 / Fase 9 — chatCore god-file
* decomposition, #3501).
*
* Pure slice of handleChatCore's request-setup phase: derives the wire-format facts of an inbound
* request from its endpoint, body, provider, and user-agent — the source format, whether it targets
* the Responses endpoint, native-Codex passthrough eligibility, Droid CLI / Copilot detection, and
* the effective client response format (an OpenAI Responses shape off a non-/responses, non-Droid
* endpoint collapses back to plain OpenAI). Side-effect-free; behaviour is byte-identical to the
* previous inline block. Sits alongside resolveChatCoreRequestSetup as the request-setup phase grows.
*/
import { detectFormatFromEndpoint } from "../../services/provider.ts";
import {
shouldUseNativeCodexPassthrough,
shouldUseNativeXaiResponsesPassthrough,
} from "./passthroughHelpers.ts";
import { FORMATS } from "../../translator/formats.ts";
/** True when the request originates from a Copilot client (matched by user-agent or any header). */
function isCopilotClient(
headers: Headers | Record<string, unknown> | null | undefined,
userAgent?: string | null
) {
const isMatch = (value: unknown) =>
typeof value === "string" && value.toLowerCase().includes("copilot");
if (isMatch(userAgent)) return true;
if (headers instanceof Headers) {
for (const [key, value] of headers as unknown as Iterable<[string, string]>) {
if (isMatch(key) || isMatch(value)) return true;
}
} else if (headers && typeof headers === "object") {
for (const [key, value] of Object.entries(headers)) {
if (isMatch(key) || isMatch(value)) return true;
}
}
return false;
}
function isOpencodeClient(
headers: Headers | Record<string, unknown> | null | undefined,
userAgent?: string | null
): boolean {
const matchesUserAgent = (value: unknown) =>
typeof value === "string" && value.toLowerCase().includes("opencode");
const matchesHeaderKey = (key: string) => key.toLowerCase().startsWith("x-opencode-");
if (matchesUserAgent(userAgent)) return true;
if (headers instanceof Headers) {
for (const [key, value] of headers as unknown as Iterable<[string, string]>) {
if (
matchesHeaderKey(key) ||
(key.toLowerCase() === "user-agent" && matchesUserAgent(value))
) {
return true;
}
}
} else if (headers && typeof headers === "object") {
for (const [key, value] of Object.entries(headers)) {
if (
matchesHeaderKey(key) ||
(key.toLowerCase() === "user-agent" && matchesUserAgent(value))
) {
return true;
}
}
}
return false;
}
/**
* Resolve the per-request endpoint/format facts at the top of handleChatCore. Pure: a function of
* the inbound endpoint, the (possibly already-mutated) body, the resolved provider, and the
* user-agent.
*/
export function resolveChatCoreRequestFormat(opts: {
clientRawRequest:
{ endpoint?: unknown; headers?: Headers | Record<string, unknown> | null } | null | undefined;
body: unknown;
provider: string | null | undefined;
userAgent: string | null | undefined;
}) {
const { clientRawRequest, body, provider, userAgent } = opts;
const endpointPath = String(clientRawRequest?.endpoint || "");
const sourceFormat = detectFormatFromEndpoint(body, endpointPath);
const isResponsesEndpoint =
/\/responses(?=\/|$)/i.test(endpointPath) || /^responses(?=\/|$)/i.test(endpointPath);
const nativeCodexPassthrough = shouldUseNativeCodexPassthrough({
provider,
sourceFormat,
endpointPath,
body,
headers: clientRawRequest?.headers,
});
const nativeXaiResponsesPassthrough = shouldUseNativeXaiResponsesPassthrough({
provider,
sourceFormat,
endpointPath,
});
const isDroidCLI =
userAgent?.toLowerCase().includes("droid") || userAgent?.toLowerCase().includes("codex-cli");
const copilotCompatibleReasoning = isCopilotClient(clientRawRequest?.headers, userAgent);
const isOpencodeClientRequest = isOpencodeClient(clientRawRequest?.headers, userAgent);
const clientResponseFormat =
sourceFormat === FORMATS.OPENAI_RESPONSES && !isResponsesEndpoint && !isDroidCLI
? FORMATS.OPENAI
: sourceFormat;
return {
endpointPath,
sourceFormat,
isResponsesEndpoint,
nativeCodexPassthrough,
nativeXaiResponsesPassthrough,
isDroidCLI,
copilotCompatibleReasoning,
isOpencodeClient: isOpencodeClientRequest,
clientResponseFormat,
};
}
export type ChatCoreRequestFormat = ReturnType<typeof resolveChatCoreRequestFormat>;