From 50ec6aac499356fdd23608da55cc843e1284ed53 Mon Sep 17 00:00:00 2001 From: Anthony Umeh Date: Sat, 22 Aug 2026 20:17:47 -0500 Subject: [PATCH] fix(runtime-host-bridge): strip provider prefix from admission-probe model id Catalog model ids are provider-prefixed (deepseek/deepseek-v4-flash), but OpenAI-compatible vendors expect the bare upstream id (deepseek-v4-flash) on the wire. The chat-completions admission probe sent the prefixed form, so vendors returned 400 which was misclassified as vendor-down, leaving the endpoint permanently provider-unavailable and ineligible for benchmarking. Strip the leading provider segment before probing, mirroring resolveProviderLocalModelId in the OpenAI execution adapter. --- .../src/remote-health-probe.ts | 16 +++++++++++++++- .../test/remote-endpoint-admission-probe.test.ts | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/role-model-router/apps/runtime-host-bridge/src/remote-health-probe.ts b/role-model-router/apps/runtime-host-bridge/src/remote-health-probe.ts index 3e977b8f..d49e7b74 100644 --- a/role-model-router/apps/runtime-host-bridge/src/remote-health-probe.ts +++ b/role-model-router/apps/runtime-host-bridge/src/remote-health-probe.ts @@ -138,6 +138,20 @@ export function buildChatCompletionsProbeUrl(apiBase: string): string { return trimmed.endsWith("/v1") ? `${trimmed}/chat/completions` : `${trimmed}/v1/chat/completions`; } +/** + * Resolve the wire model id used by the chat-completions admission probe. + * + * Catalog model ids are provider-prefixed (e.g. ``deepseek/deepseek-v4-flash``), + * but OpenAI-compatible vendors expect the bare upstream id on the wire + * (``deepseek-v4-flash``). Sending the prefixed form makes the vendor reject + * the probe with a 400 that we previously misclassified as ``vendor-down``. + * Mirrors ``resolveProviderLocalModelId`` in the OpenAI execution adapter. + */ +function resolveProbeModelId(modelId: string): string { + const trimmed = modelId.trim(); + return trimmed.includes("/") ? trimmed.split("/").slice(1).join("/") : trimmed; +} + function isTimeoutError(error: unknown): boolean { return ( error instanceof Error && @@ -337,7 +351,7 @@ export async function probeRemoteEndpointAdmission( const probeUrl = buildChatCompletionsProbeUrl(context.apiBase); const body = { - model: context.modelId, + model: resolveProbeModelId(context.modelId), messages: [{ role: "user", content: "role-model admission readiness probe" }], max_tokens: 1, stream: false, diff --git a/role-model-router/apps/runtime-host-bridge/test/remote-endpoint-admission-probe.test.ts b/role-model-router/apps/runtime-host-bridge/test/remote-endpoint-admission-probe.test.ts index 59713d91..562c5f51 100644 --- a/role-model-router/apps/runtime-host-bridge/test/remote-endpoint-admission-probe.test.ts +++ b/role-model-router/apps/runtime-host-bridge/test/remote-endpoint-admission-probe.test.ts @@ -41,7 +41,7 @@ describe("remote endpoint admission probes", () => { }), ); expect(JSON.parse(String(calls[0]?.init?.body))).toEqual({ - model: "deepseek/deepseek-v4-flash", + model: "deepseek-v4-flash", messages: [{ role: "user", content: "role-model admission readiness probe" }], max_tokens: 1, stream: false,