mirror of
https://github.com/meta-llama/llama-stack.git
synced 2025-12-03 09:53:45 +00:00
feat: add custom_metadata to OpenAIModel to unify /v1/models with /v1/openai/v1/models (#4051)
We need to remove `/v1/openai/v1` paths shortly. There is one trouble -- our current `/v1/openai/v1/models` endpoint provides different data than `/v1/models`. Unfortunately our tests target the latter (llama-stack customized) behavior. We need to get to true OpenAI compatibility. This is step 1: adding `custom_metadata` field to `OpenAIModel` that includes all the extra stuff we add in the native `/v1/models` response. This can be extracted on the consumer end by look at `__pydantic_extra__` or other similar fields. This PR: - Adds `custom_metadata` field to `OpenAIModel` class in `src/llama_stack/apis/models/models.py` - Modified `openai_list_models()` in `src/llama_stack/core/routing_tables/models.py` to populate custom_metadata Next Steps 1. Update stainless client to use `/v1/openai/v1/models` instead of `/v1/models` 2. Migrate tests to read from `custom_metadata` 3. Remove `/v1/openai/v1/` prefix entirely and consolidate to single `/v1/models` endpoint
This commit is contained in:
parent
2381714904
commit
44096512b5
7 changed files with 218 additions and 61 deletions
|
|
@ -1129,6 +1129,31 @@ paths:
|
||||||
$ref: '#/components/schemas/RunModerationRequest'
|
$ref: '#/components/schemas/RunModerationRequest'
|
||||||
required: true
|
required: true
|
||||||
deprecated: false
|
deprecated: false
|
||||||
|
/v1/openai/v1/models:
|
||||||
|
get:
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: A OpenAIListModelsResponse.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/OpenAIListModelsResponse'
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/responses/BadRequest400'
|
||||||
|
'429':
|
||||||
|
$ref: >-
|
||||||
|
#/components/responses/TooManyRequests429
|
||||||
|
'500':
|
||||||
|
$ref: >-
|
||||||
|
#/components/responses/InternalServerError500
|
||||||
|
default:
|
||||||
|
$ref: '#/components/responses/DefaultError'
|
||||||
|
tags:
|
||||||
|
- Models
|
||||||
|
summary: List models using the OpenAI API.
|
||||||
|
description: List models using the OpenAI API.
|
||||||
|
parameters: []
|
||||||
|
deprecated: false
|
||||||
/v1/prompts:
|
/v1/prompts:
|
||||||
get:
|
get:
|
||||||
responses:
|
responses:
|
||||||
|
|
@ -7029,6 +7054,48 @@ components:
|
||||||
- metadata
|
- metadata
|
||||||
title: ModerationObjectResults
|
title: ModerationObjectResults
|
||||||
description: A moderation object.
|
description: A moderation object.
|
||||||
|
OpenAIModel:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
object:
|
||||||
|
type: string
|
||||||
|
const: model
|
||||||
|
default: model
|
||||||
|
created:
|
||||||
|
type: integer
|
||||||
|
owned_by:
|
||||||
|
type: string
|
||||||
|
custom_metadata:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
oneOf:
|
||||||
|
- type: 'null'
|
||||||
|
- type: boolean
|
||||||
|
- type: number
|
||||||
|
- type: string
|
||||||
|
- type: array
|
||||||
|
- type: object
|
||||||
|
additionalProperties: false
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- object
|
||||||
|
- created
|
||||||
|
- owned_by
|
||||||
|
title: OpenAIModel
|
||||||
|
description: A model from OpenAI.
|
||||||
|
OpenAIListModelsResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
data:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/OpenAIModel'
|
||||||
|
additionalProperties: false
|
||||||
|
required:
|
||||||
|
- data
|
||||||
|
title: OpenAIListModelsResponse
|
||||||
Prompt:
|
Prompt:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|
|
||||||
60
docs/static/deprecated-llama-stack-spec.yaml
vendored
60
docs/static/deprecated-llama-stack-spec.yaml
vendored
|
|
@ -1561,31 +1561,6 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
deprecated: true
|
deprecated: true
|
||||||
/v1/openai/v1/models:
|
|
||||||
get:
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: A OpenAIListModelsResponse.
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/OpenAIListModelsResponse'
|
|
||||||
'400':
|
|
||||||
$ref: '#/components/responses/BadRequest400'
|
|
||||||
'429':
|
|
||||||
$ref: >-
|
|
||||||
#/components/responses/TooManyRequests429
|
|
||||||
'500':
|
|
||||||
$ref: >-
|
|
||||||
#/components/responses/InternalServerError500
|
|
||||||
default:
|
|
||||||
$ref: '#/components/responses/DefaultError'
|
|
||||||
tags:
|
|
||||||
- Models
|
|
||||||
summary: List models using the OpenAI API.
|
|
||||||
description: List models using the OpenAI API.
|
|
||||||
parameters: []
|
|
||||||
deprecated: true
|
|
||||||
/v1/openai/v1/moderations:
|
/v1/openai/v1/moderations:
|
||||||
post:
|
post:
|
||||||
responses:
|
responses:
|
||||||
|
|
@ -6516,38 +6491,6 @@ components:
|
||||||
Response:
|
Response:
|
||||||
type: object
|
type: object
|
||||||
title: Response
|
title: Response
|
||||||
OpenAIModel:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
id:
|
|
||||||
type: string
|
|
||||||
object:
|
|
||||||
type: string
|
|
||||||
const: model
|
|
||||||
default: model
|
|
||||||
created:
|
|
||||||
type: integer
|
|
||||||
owned_by:
|
|
||||||
type: string
|
|
||||||
additionalProperties: false
|
|
||||||
required:
|
|
||||||
- id
|
|
||||||
- object
|
|
||||||
- created
|
|
||||||
- owned_by
|
|
||||||
title: OpenAIModel
|
|
||||||
description: A model from OpenAI.
|
|
||||||
OpenAIListModelsResponse:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
data:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: '#/components/schemas/OpenAIModel'
|
|
||||||
additionalProperties: false
|
|
||||||
required:
|
|
||||||
- data
|
|
||||||
title: OpenAIListModelsResponse
|
|
||||||
RunModerationRequest:
|
RunModerationRequest:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|
@ -10768,8 +10711,6 @@ tags:
|
||||||
- Rerank models: these models reorder the documents based on their relevance
|
- Rerank models: these models reorder the documents based on their relevance
|
||||||
to a query.
|
to a query.
|
||||||
x-displayName: Inference
|
x-displayName: Inference
|
||||||
- name: Models
|
|
||||||
description: ''
|
|
||||||
- name: PostTraining (Coming Soon)
|
- name: PostTraining (Coming Soon)
|
||||||
description: ''
|
description: ''
|
||||||
- name: Safety
|
- name: Safety
|
||||||
|
|
@ -10788,7 +10729,6 @@ x-tagGroups:
|
||||||
- Eval
|
- Eval
|
||||||
- Files
|
- Files
|
||||||
- Inference
|
- Inference
|
||||||
- Models
|
|
||||||
- PostTraining (Coming Soon)
|
- PostTraining (Coming Soon)
|
||||||
- Safety
|
- Safety
|
||||||
- VectorIO
|
- VectorIO
|
||||||
|
|
|
||||||
67
docs/static/llama-stack-spec.yaml
vendored
67
docs/static/llama-stack-spec.yaml
vendored
|
|
@ -1126,6 +1126,31 @@ paths:
|
||||||
$ref: '#/components/schemas/RunModerationRequest'
|
$ref: '#/components/schemas/RunModerationRequest'
|
||||||
required: true
|
required: true
|
||||||
deprecated: false
|
deprecated: false
|
||||||
|
/v1/openai/v1/models:
|
||||||
|
get:
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: A OpenAIListModelsResponse.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/OpenAIListModelsResponse'
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/responses/BadRequest400'
|
||||||
|
'429':
|
||||||
|
$ref: >-
|
||||||
|
#/components/responses/TooManyRequests429
|
||||||
|
'500':
|
||||||
|
$ref: >-
|
||||||
|
#/components/responses/InternalServerError500
|
||||||
|
default:
|
||||||
|
$ref: '#/components/responses/DefaultError'
|
||||||
|
tags:
|
||||||
|
- Models
|
||||||
|
summary: List models using the OpenAI API.
|
||||||
|
description: List models using the OpenAI API.
|
||||||
|
parameters: []
|
||||||
|
deprecated: false
|
||||||
/v1/prompts:
|
/v1/prompts:
|
||||||
get:
|
get:
|
||||||
responses:
|
responses:
|
||||||
|
|
@ -5816,6 +5841,48 @@ components:
|
||||||
- metadata
|
- metadata
|
||||||
title: ModerationObjectResults
|
title: ModerationObjectResults
|
||||||
description: A moderation object.
|
description: A moderation object.
|
||||||
|
OpenAIModel:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
object:
|
||||||
|
type: string
|
||||||
|
const: model
|
||||||
|
default: model
|
||||||
|
created:
|
||||||
|
type: integer
|
||||||
|
owned_by:
|
||||||
|
type: string
|
||||||
|
custom_metadata:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
oneOf:
|
||||||
|
- type: 'null'
|
||||||
|
- type: boolean
|
||||||
|
- type: number
|
||||||
|
- type: string
|
||||||
|
- type: array
|
||||||
|
- type: object
|
||||||
|
additionalProperties: false
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- object
|
||||||
|
- created
|
||||||
|
- owned_by
|
||||||
|
title: OpenAIModel
|
||||||
|
description: A model from OpenAI.
|
||||||
|
OpenAIListModelsResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
data:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/OpenAIModel'
|
||||||
|
additionalProperties: false
|
||||||
|
required:
|
||||||
|
- data
|
||||||
|
title: OpenAIListModelsResponse
|
||||||
Prompt:
|
Prompt:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|
|
||||||
67
docs/static/stainless-llama-stack-spec.yaml
vendored
67
docs/static/stainless-llama-stack-spec.yaml
vendored
|
|
@ -1129,6 +1129,31 @@ paths:
|
||||||
$ref: '#/components/schemas/RunModerationRequest'
|
$ref: '#/components/schemas/RunModerationRequest'
|
||||||
required: true
|
required: true
|
||||||
deprecated: false
|
deprecated: false
|
||||||
|
/v1/openai/v1/models:
|
||||||
|
get:
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: A OpenAIListModelsResponse.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/OpenAIListModelsResponse'
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/responses/BadRequest400'
|
||||||
|
'429':
|
||||||
|
$ref: >-
|
||||||
|
#/components/responses/TooManyRequests429
|
||||||
|
'500':
|
||||||
|
$ref: >-
|
||||||
|
#/components/responses/InternalServerError500
|
||||||
|
default:
|
||||||
|
$ref: '#/components/responses/DefaultError'
|
||||||
|
tags:
|
||||||
|
- Models
|
||||||
|
summary: List models using the OpenAI API.
|
||||||
|
description: List models using the OpenAI API.
|
||||||
|
parameters: []
|
||||||
|
deprecated: false
|
||||||
/v1/prompts:
|
/v1/prompts:
|
||||||
get:
|
get:
|
||||||
responses:
|
responses:
|
||||||
|
|
@ -7029,6 +7054,48 @@ components:
|
||||||
- metadata
|
- metadata
|
||||||
title: ModerationObjectResults
|
title: ModerationObjectResults
|
||||||
description: A moderation object.
|
description: A moderation object.
|
||||||
|
OpenAIModel:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
object:
|
||||||
|
type: string
|
||||||
|
const: model
|
||||||
|
default: model
|
||||||
|
created:
|
||||||
|
type: integer
|
||||||
|
owned_by:
|
||||||
|
type: string
|
||||||
|
custom_metadata:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
oneOf:
|
||||||
|
- type: 'null'
|
||||||
|
- type: boolean
|
||||||
|
- type: number
|
||||||
|
- type: string
|
||||||
|
- type: array
|
||||||
|
- type: object
|
||||||
|
additionalProperties: false
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- object
|
||||||
|
- created
|
||||||
|
- owned_by
|
||||||
|
title: OpenAIModel
|
||||||
|
description: A model from OpenAI.
|
||||||
|
OpenAIListModelsResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
data:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/OpenAIModel'
|
||||||
|
additionalProperties: false
|
||||||
|
required:
|
||||||
|
- data
|
||||||
|
title: OpenAIListModelsResponse
|
||||||
Prompt:
|
Prompt:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|
|
||||||
|
|
@ -90,12 +90,14 @@ class OpenAIModel(BaseModel):
|
||||||
:object: The object type, which will be "model"
|
:object: The object type, which will be "model"
|
||||||
:created: The Unix timestamp in seconds when the model was created
|
:created: The Unix timestamp in seconds when the model was created
|
||||||
:owned_by: The owner of the model
|
:owned_by: The owner of the model
|
||||||
|
:custom_metadata: Llama Stack-specific metadata including model_type, provider info, and additional metadata
|
||||||
"""
|
"""
|
||||||
|
|
||||||
id: str
|
id: str
|
||||||
object: Literal["model"] = "model"
|
object: Literal["model"] = "model"
|
||||||
created: int
|
created: int
|
||||||
owned_by: str
|
owned_by: str
|
||||||
|
custom_metadata: dict[str, Any] | None = None
|
||||||
|
|
||||||
|
|
||||||
class OpenAIListModelsResponse(BaseModel):
|
class OpenAIListModelsResponse(BaseModel):
|
||||||
|
|
@ -113,7 +115,7 @@ class Models(Protocol):
|
||||||
"""
|
"""
|
||||||
...
|
...
|
||||||
|
|
||||||
@webmethod(route="/openai/v1/models", method="GET", level=LLAMA_STACK_API_V1, deprecated=True)
|
@webmethod(route="/openai/v1/models", method="GET", level=LLAMA_STACK_API_V1)
|
||||||
async def openai_list_models(self) -> OpenAIListModelsResponse:
|
async def openai_list_models(self) -> OpenAIListModelsResponse:
|
||||||
"""List models using the OpenAI API.
|
"""List models using the OpenAI API.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,12 @@ class ModelsRoutingTable(CommonRoutingTableImpl, Models):
|
||||||
object="model",
|
object="model",
|
||||||
created=int(time.time()),
|
created=int(time.time()),
|
||||||
owned_by="llama_stack",
|
owned_by="llama_stack",
|
||||||
|
custom_metadata={
|
||||||
|
"model_type": model.model_type,
|
||||||
|
"provider_id": model.provider_id,
|
||||||
|
"provider_resource_id": model.provider_resource_id,
|
||||||
|
**model.metadata,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
for model in all_models
|
for model in all_models
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,14 @@ async def test_models_routing_table(cached_disk_dist_registry):
|
||||||
assert "test_provider/test-model" in openai_model_ids
|
assert "test_provider/test-model" in openai_model_ids
|
||||||
assert "test_provider/test-model-2" in openai_model_ids
|
assert "test_provider/test-model-2" in openai_model_ids
|
||||||
|
|
||||||
|
# Verify custom_metadata is populated with Llama Stack-specific data
|
||||||
|
for openai_model in openai_models.data:
|
||||||
|
assert openai_model.custom_metadata is not None
|
||||||
|
assert "model_type" in openai_model.custom_metadata
|
||||||
|
assert "provider_id" in openai_model.custom_metadata
|
||||||
|
assert "provider_resource_id" in openai_model.custom_metadata
|
||||||
|
assert openai_model.custom_metadata["provider_id"] == "test_provider"
|
||||||
|
|
||||||
# Test get_object_by_identifier
|
# Test get_object_by_identifier
|
||||||
model = await table.get_object_by_identifier("model", "test_provider/test-model")
|
model = await table.get_object_by_identifier("model", "test_provider/test-model")
|
||||||
assert model is not None
|
assert model is not None
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue