pi-provider-litellm 4.0.0 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/package.json +1 -1
- package/src/backend-identity.ts +11 -8
- package/src/index.ts +2 -2
package/README.md
CHANGED
|
@@ -331,7 +331,7 @@ Each distinct availability diagnostic is written once per session on stderr. `LI
|
|
|
331
331
|
|
|
332
332
|
### Protocols and prompt caching
|
|
333
333
|
|
|
334
|
-
Discovery selects native Messages for proven Claude groups under the [Model transport](#model-transport) rules, Responses for OpenAI-family backends, and Chat Completions for other OpenAI-compatible backends. Azure deployments stay on Chat Completions unless an explicit Responses mode or a `supported_endpoints` list containing `/v1/responses` authorizes Responses; `api_version` alone does not prove support. Azure AI (`azure_ai/` prefix or `custom_llm_provider: azure_ai`) deployments additionally depend on the proxy version. On LiteLLM before v1.103.0, or when the version is unknown, they ignore a `supported_endpoints` list that contains `/v1/responses` and need an explicit `mode: "responses"`: those releases have no native Responses config for that provider, so they bridge `/v1/responses` through Chat Completions, and the bridge fails streaming with `list index out of range` on Azure's empty-choices chunks (BerriAI/litellm#34455) while the endpoint list, copied from the model cost map, still advertises `/v1/responses`. From v1.103.0 the list is honored again. Discovery reads the version from the `x-litellm-version` header of one extra request, `GET /v1/responses/resp_version_probe`, sent only when such a deployment is published; LiteLLM answers it with an error and calls no model. A pre-release counts as older than the release it names, and a proxy that omits the header keeps these deployments on Chat Completions. Azure is detected from the adapter field, an `azure/` or `azure_ai/` model prefix, or the reported provider; other adapters follow the backend family because LiteLLM bridges `/v1/responses` to Chat Completions when the provider has no native Responses config (`litellm/responses/main.py`, `_bridges_to_chat_completions`). A route whose model prefix and `custom_llm_provider` name different providers is treated as unidentified and stays on Chat Completions, so it also does not get the local 128-tool preflight. When `/model/info` supplies `supported_endpoints`, that list takes precedence, and `mode: "responses"` remains an explicit Responses signal. An evidence-free fallback entry—a bare `/v1/models` id or a `/health` entry with no detail row—takes its protocol from the Pi catalog entry for its id; both evidence-free fallback paths also inherit presentation metadata from the bounded catalog lookup. An unknown id stays on Chat Completions. The route name alone authorizes nothing. A concrete id expanded from wildcard `/model/info` routes inherits the deployment evidence of the wildcard route LiteLLM would select for it, with the requested id substituted into the row's `model` the way LiteLLM serves it; the id is omitted when that selected route is not a published chat-style route. Chat Completions and Responses use `<root>/v1`; native Messages uses the proxy root directly. All three protocols pass through the provider's host guard. When an evidence-free cached `(no metadata)` entry can be enriched from the Pi catalog, it is restored on Responses only for a catalog Responses model and otherwise on Chat Completions, never Anthropic Messages. A model supplied only through `models.json` whose `api` this provider does not implement takes Pi's global API fallback rather than this provider's host guard; the credential-root pin (see [Model host enforcement](#model-host-enforcement)) still keeps the credential on the active proxy.
|
|
334
|
+
Discovery selects native Messages for proven Claude groups under the [Model transport](#model-transport) rules, Responses for OpenAI-family backends, and Chat Completions for other OpenAI-compatible backends. Azure deployments stay on Chat Completions unless an explicit Responses mode or a `supported_endpoints` list containing `/v1/responses` authorizes Responses; `api_version` alone does not prove support. Azure AI (`azure_ai/` prefix or `custom_llm_provider: azure_ai`) deployments additionally depend on the proxy version. On LiteLLM before v1.103.0, or when the version is unknown, they ignore a `supported_endpoints` list that contains `/v1/responses` and need an explicit `mode: "responses"`: those releases have no native Responses config for that provider, so they bridge `/v1/responses` through Chat Completions, and the bridge fails streaming with `list index out of range` on Azure's empty-choices chunks (BerriAI/litellm#34455) while the endpoint list, copied from the model cost map, still advertises `/v1/responses`. From v1.103.0 the list is honored again. Discovery reads the version from the `x-litellm-version` header of one extra request, `GET /v1/responses/resp_version_probe`, sent only when such a deployment is published; LiteLLM answers it with an error and calls no model. A pre-release counts as older than the release it names, and a proxy that omits the header keeps these deployments on Chat Completions. Azure is detected from the adapter field, an `azure/` or `azure_ai/` model prefix, or the reported provider; other adapters follow the backend family because LiteLLM bridges `/v1/responses` to Chat Completions when the provider has no native Responses config (`litellm/responses/main.py`, `_bridges_to_chat_completions`). The family comes from the model id, not from LiteLLM's `openai/`, `openai_like/` or `custom_openai/` adapter prefix, so `openai/qwen3` stays on Chat Completions while `openai/gpt-5.5` uses Responses; a deployment opts into Responses with `mode: "responses"` or a `supported_endpoints` list containing `/v1/responses`. A route whose model prefix and `custom_llm_provider` name different providers is treated as unidentified and stays on Chat Completions, so it also does not get the local 128-tool preflight. When `/model/info` supplies `supported_endpoints`, that list takes precedence, and `mode: "responses"` remains an explicit Responses signal. An evidence-free fallback entry—a bare `/v1/models` id or a `/health` entry with no detail row—takes its protocol from the Pi catalog entry for its id; both evidence-free fallback paths also inherit presentation metadata from the bounded catalog lookup. An unknown id stays on Chat Completions. The route name alone authorizes nothing. A concrete id expanded from wildcard `/model/info` routes inherits the deployment evidence of the wildcard route LiteLLM would select for it, with the requested id substituted into the row's `model` the way LiteLLM serves it; the id is omitted when that selected route is not a published chat-style route. Chat Completions and Responses use `<root>/v1`; native Messages uses the proxy root directly. All three protocols pass through the provider's host guard. When an evidence-free cached `(no metadata)` entry can be enriched from the Pi catalog, it is restored on Responses only for a catalog Responses model and otherwise on Chat Completions, never Anthropic Messages. A model supplied only through `models.json` whose `api` this provider does not implement takes Pi's global API fallback rather than this provider's host guard; the credential-root pin (see [Model host enforcement](#model-host-enforcement)) still keeps the credential on the active proxy.
|
|
335
335
|
|
|
336
336
|
`cacheControlFormat: "anthropic"` applies only to Chat Completions, where Pi adds Anthropic `cache_control` markers. The Responses transport has a different compatibility type and uses native `prompt_cache_key` (plus supported retention fields), so Responses models must not receive `cacheControlFormat`. Freshly discovered OpenAI-family models forced onto Chat Completions are rejected locally when a request contains more than 128 tools; route them through Responses or reduce enabled extensions. Moonshot request-side reasoning suppression follows LiteLLM's routing provider, not `model_info.base_model`; response-side `<think>` normalization follows discovered Kimi-family evidence. Opaque aliases retain display normalization without sending Moonshot-only parameters to Azure- or Bedrock-hosted Kimi models. Strict tool-message repair requires every deployment to identify Kimi; Gemini effort normalization likewise requires consistent backend-family evidence.
|
|
337
337
|
|
|
@@ -382,7 +382,7 @@ The development probe runs against minimized snapshots with `npm run probe:proxy
|
|
|
382
382
|
| A configured or restored model fails to complete but never leaks the credential | Its `api` is absent from the current provider catalog, so Pi used global API fallback with the credential root pinned. Open `/model` against the active proxy to repopulate the protocol — see [Model host enforcement](#model-host-enforcement) |
|
|
383
383
|
| `LiteLLM discovery: ... route group(s) have missing or conflicting deployment provider evidence` | One or more deployments lack resolvable backend authority or resolve to different providers or concrete catalog models. Add consistent `litellm_params.model`, `model_info.base_model`, or adapter metadata; catalog-derived limits, pricing, and reasoning metadata are withheld meanwhile. This may be intentional for cross-host routes such as Vertex/Bedrock Claude. |
|
|
384
384
|
| `LiteLLM discovery: ... route group(s) mix chat-style and explicitly incompatible deployment modes` | A public route can select both a chat-style deployment and an incompatible deployment such as an embedding model. Give the embedding deployment its own `model_name`. |
|
|
385
|
-
| `LiteLLM (...):
|
|
385
|
+
| `LiteLLM (...): the request for "<route>" was answered by a fallback` | A successful HTTP response reports a LiteLLM router fallback (`x-litellm-attempted-fallbacks`). `/model/info` does not expose fallbacks, so protocol and model handling follow the requested route's own deployments. If the primary and fallback groups support Chat Completions, set `model_info.supported_endpoints: ["/v1/chat/completions"]` on the primary to avoid Responses-to-Chat bridging. This warning does not change routing or fix upstream bridging defects. It names only the requested route; LiteLLM reports the group and model that answered in the `x-litellm-model-group` and `x-litellm-model-name` response headers. Warned once per provider and route until the extension reloads; shown in the UI, or stderr without a UI. |
|
|
386
386
|
| A model is marked ` (incomplete metadata)` | `/model/info` or `/health` did not provide enough authoritative metadata. Explicit fields remain usable, but unknown cost fields are shown as zero and route-name cache enrichment stays disabled. |
|
|
387
387
|
| `401 Token expired` | Set `LITELLM_API_KEY_HELPER`. |
|
|
388
388
|
| No models with gcloud auth | Verify `gcloud auth application-default login` has been run or set `GOOGLE_APPLICATION_CREDENTIALS` to an `authorized_user` ADC file |
|
package/package.json
CHANGED
package/src/backend-identity.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const LITELLM_DISCOVERY_VERSION =
|
|
1
|
+
export const LITELLM_DISCOVERY_VERSION = 5 as const;
|
|
2
2
|
|
|
3
3
|
export type BackendFamily = "claude" | "deepseek" | "gemini" | "kimi" | "openai";
|
|
4
4
|
|
|
@@ -28,15 +28,17 @@ const PROVIDER_FAMILIES: Readonly<Record<string, BackendFamily>> = {
|
|
|
28
28
|
};
|
|
29
29
|
// Prefixes whose keyword match is trustworthy across the whole "prefix/modelId" string because
|
|
30
30
|
// the prefix itself names a vendor, not just some unrelated string that happens to contain one.
|
|
31
|
-
|
|
31
|
+
// `openai` is absent for the same reason as in PROVIDER_FAMILIES: it is an adapter, not a model.
|
|
32
|
+
const KNOWN_VENDOR_PREFIXES = new Set(Object.keys(PROVIDER_FAMILIES));
|
|
32
33
|
// First segments that are known to be model path, never a provider: Fireworks' account-scoped
|
|
33
34
|
// ids ("accounts/fireworks/models/x"). An allowlist fails closed: any other differing prefix,
|
|
34
35
|
// recognized provider or not, stays a conflict.
|
|
35
36
|
const MODEL_PATH_SEGMENTS = new Set(["accounts"]);
|
|
36
37
|
// `o\d` (OpenAI's o1/o3/o4-mini reasoning models) is only trustworthy at the start of the id or
|
|
37
38
|
// right after a provider path segment — an interior "-o1-" is as likely to be an unrelated
|
|
38
|
-
// product's own version marker (e.g. "custom-o1-clone").
|
|
39
|
-
|
|
39
|
+
// product's own version marker (e.g. "custom-o1-clone"). An OpenAI fine-tune id starts with
|
|
40
|
+
// "ft:" before its base model ("ft:gpt-4o-mini:org::id").
|
|
41
|
+
const OPENAI_FAMILY_PATTERN = /(?:^(?:ft:)?|[./_-])(?:openai|gpt|codex)(?:$|[./_:-])|(?:^(?:ft:)?|\/)o\d(?:$|[./_:-])/i;
|
|
40
42
|
|
|
41
43
|
export function isRecord(value: unknown): value is Record<string, unknown> {
|
|
42
44
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -83,10 +85,11 @@ export function resolveBackendIdentity(row: BackendIdentityRow): BackendIdentity
|
|
|
83
85
|
const provider = prefixProvider ?? customProvider;
|
|
84
86
|
const modelId = slash > 0 ? raw.slice(slash + 1) : raw;
|
|
85
87
|
// Scan the full "prefix/modelId" string only when the prefix is itself a whole known vendor
|
|
86
|
-
// name (e.g. "
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
|
|
88
|
+
// name (e.g. "moonshot/production"); otherwise scan modelId alone, so an adapter prefix
|
|
89
|
+
// ("openai/", "openai_like/", "custom_openai/") or an unrelated custom prefix that merely
|
|
90
|
+
// contains a vendor substring (e.g. "deepseek-proxy/gpt-4-turbo") can't contaminate the
|
|
91
|
+
// keyword match with its own name: "openai/qwen3" has no family, "openai/gpt-5.5" does.
|
|
92
|
+
const scanTarget = provider && KNOWN_VENDOR_PREFIXES.has(provider) ? raw : modelId;
|
|
90
93
|
const family = semanticFamily(scanTarget) ?? (provider ? PROVIDER_FAMILIES[provider] : undefined);
|
|
91
94
|
return {
|
|
92
95
|
...(provider ? { provider } : {}),
|
package/src/index.ts
CHANGED
|
@@ -2263,8 +2263,8 @@ export default async function (pi: ExtensionAPI): Promise<void> {
|
|
|
2263
2263
|
warnedFallbackRoutes.add(key);
|
|
2264
2264
|
const route = JSON.stringify(model.id);
|
|
2265
2265
|
const message =
|
|
2266
|
-
`LiteLLM (${JSON.stringify(model.provider)}):
|
|
2267
|
-
`for ${route}'s own deployments. If its fallbacks cross model families, pin the protocol with ` +
|
|
2266
|
+
`LiteLLM (${JSON.stringify(model.provider)}): the request for ${route} was answered by a fallback, but protocol and model handling were chosen ` +
|
|
2267
|
+
`for ${route}'s own deployments, not the fallback's. If its fallbacks cross model families, pin the protocol with ` +
|
|
2268
2268
|
"`model_info.supported_endpoints`.";
|
|
2269
2269
|
if (ctx.hasUI) ctx.ui.notify(message, "warning");
|
|
2270
2270
|
else process.stderr.write(`${message}\n`);
|