feat!: multi-SDK response shapes for /v1/models - #5522
Conversation
|
@mattf @franciscojavierarceo @cdoern just draft let me know if you like the approach. |
✱ Stainless preview buildsThis PR will update the
|
mattf
left a comment
There was a problem hiding this comment.
+1 providing a client appropriate response from /v1/models
i've seen other systems respond w/ multiple formats at the same time
| if request is None: | ||
| return SdkType.OPENAI | ||
| headers = request.headers | ||
| if headers.get("anthropic-version"): | ||
| return SdkType.ANTHROPIC | ||
| if headers.get("x-goog-api-key"): | ||
| return SdkType.GOOGLE | ||
| return SdkType.OPENAI |
There was a problem hiding this comment.
which llm likes this structure instead of -
if request:
headers = request.headers
if headers.get(...):
return SdkType....
return SdkType.OPENAI
| all_models = await self._get_all_models() | ||
| google_models = [ | ||
| GoogleModelInfo( | ||
| name=f"models/{model.identifier}", |
There was a problem hiding this comment.
does this work across all the various google apis (gemini / vertex / others(?))?
cc @major
This comment was marked as spam.
This comment was marked as spam.
1 similar comment
This comment was marked as spam.
This comment was marked as spam.
|
This pull request has merge conflicts that must be resolved before it can be merged. @leseb please rebase it. https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork |
49b99e0 to
a91ff1e
Compare
|
This pull request has merge conflicts that must be resolved before it can be merged. @leseb please rebase it. https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork |
2d77524 to
cb1dae4
Compare
cb1dae4 to
3996d8a
Compare
06e823c to
662350a
Compare
|
This pull request has merge conflicts that must be resolved before it can be merged. @leseb please rebase it. https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork |
The /v1/models and /v1/models/{model_id} endpoints now return
SDK-appropriate response formats based on request headers. When the
Anthropic SDK calls with the anthropic-version header, the response
uses the Anthropic ModelInfo shape. When the Google AI SDK calls with
the x-goog-api-key header, the response uses the Google Model shape.
The default remains the OpenAI format for backward compatibility.
The OpenAPI spec documents all three response shapes using oneOf with
the SDK detection headers as optional parameters, making the spec
self-documenting for consumers of any SDK.
BREAKING CHANGE: the /v1/models response schema changed from a single
OpenAIListModelsResponse to a oneOf with OpenAI, Anthropic, and Google
variants. Existing OpenAI SDK consumers are unaffected since the
default response shape is unchanged.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Sébastien Han <seb@redhat.com>
…ilds Use FastAPI's standard Request injection (auto-resolved, no need for optional parameter) and add sdk_detection module to the llama-stack-api package manifest so it is included in distribution builds. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Sébastien Han <seb@redhat.com>
The library client expects Pydantic model return values, not JSONResponse wrappers. Only use JSONResponse for Anthropic/Google paths that need custom headers or different response shapes. The OpenAI default path returns the Pydantic model directly, matching the original behavior. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Sébastien Han <seb@redhat.com>
Replace direct Request parameter with a Depends-based SDK detection function that uses Header() injection. This allows the library client to call route functions without a Request object - the sdk parameter defaults to SdkType.OPENAI when not injected by FastAPI. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Sébastien Han <seb@redhat.com>
The library client's _convert_body tries to construct Depends return types from body params, which fails for non-Pydantic types like SdkType enum. Use direct Header() parameters with None defaults instead - the library client simply skips these optional params and the route falls through to OpenAI default behavior. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Sébastien Han <seb@redhat.com>
Address review feedback:
- Delete sdk_detection.py which became dead code after switching to
direct Header() params for SDK detection
- Remove sdk_detection from pyproject.toml py-modules since it should
not be part of the public API surface
- Add comment clarifying that the Google models/{id} format is specific
to the Gemini API and Vertex AI would need provider-aware translation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Sébastien Han <seb@redhat.com>
…tions. Signed-off-by: Sébastien Han <seb@redhat.com>
Signed-off-by: Sébastien Han <seb@redhat.com>
…sts. Signed-off-by: Sébastien Han <seb@redhat.com>
…olution for multi-SDK routes. Signed-off-by: Sébastien Han <seb@redhat.com>
Signed-off-by: Sébastien Han <seb@redhat.com>
…eam merge. Signed-off-by: Sébastien Han <seb@redhat.com>
Signed-off-by: Sébastien Han <seb@redhat.com>
…eam merge. Signed-off-by: Sébastien Han <seb@redhat.com>
…arison-v2 Signed-off-by: Sébastien Han <seb@redhat.com>
662350a to
939296a
Compare
Signed-off-by: Sébastien Han <seb@redhat.com>
cdoern
left a comment
There was a problem hiding this comment.
lgtm, this makes sense as we add other SDK support beyond openai.
Summary
/v1/modelsand/v1/models/{model_id}now return SDK-appropriate response formats based on request headersanthropic-versionheader → AnthropicModelInfoshape (id,type,display_name,created_at)x-goog-api-keyheader → GoogleModelshape (name,display_name,description)oneOfwith header parametersMotivation
Llama Stack supports three SDK front-ends (OpenAI, Anthropic Messages, Google Interactions) but
/v1/modelsonly returned OpenAI-shaped responses. When developers point their Anthropic or Google SDK at a Llama Stack server,client.models.list()would fail or return unexpected shapes. This makes the models endpoint work natively with all three SDKs.Changes
src/llama_stack_api/sdk_detection.pysrc/llama_stack_api/models/models.pysrc/llama_stack_api/models/api.pysrc/llama_stack/core/routing_tables/models.py_get_all_modelshelpersrc/llama_stack_api/models/fastapi_routes.pyscripts/openapi_generator/multi_sdk.pyoneOfresponse schemasTest plan
uv run pytest tests/unit/core/ tests/unit/providers/inline/messages/ -x- all passuv run pre-commit run --all-files- all passcurl /v1/models→ OpenAI shapecurl -H "anthropic-version: 2023-06-01" /v1/models→ Anthropic shapecurl -H "x-goog-api-key: test" /v1/models→ Google shapeBreaking change
The OpenAPI spec for
/v1/modelschanged from a singleOpenAIListModelsResponseto aoneOfwith three variants. Runtime behavior for existing OpenAI SDK consumers is unchanged since the default response shape is preserved.🤖 Generated with Claude Code