feat: introduce /admin API for stack administration and operations (#4401)

# What does this PR do?

- Add new /admin API (v1alpha) for administrative operations including
provider management, health checks, version info, and route listing
- Implement using FastAPI routers following batches pattern with proper
request/response models
- Endpoints: /admin/providers, /admin/providers/{id},
/admin/inspect/routes, /admin/health, /admin/version
- Create admin module structure: models.py, api.py, fastapi_routes.py,
init.py
- Add AdminImpl in llama_stack/core combining provider and inspect
functionality
- Deprecate standalone /providers and /inspect APIs (remain functional
for backward compatibility)
- Consolidate duplicate types: ProviderInfo, HealthInfo, RouteInfo, etc.
now defined once in admin.models

## Test Plan

new admin integration suite, uses generated stainless SDK, and records
new tests on this PR.

Signed-off-by: Charlie Doern <cdoern@redhat.com>
This commit is contained in:
Charlie Doern 2025-12-22 12:11:49 -05:00 committed by GitHub
parent d684ec91cc
commit 258c52c84c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 3306 additions and 2078 deletions

View file

@ -163,6 +163,12 @@ resources:
sampling_params: SamplingParams
scoring_result: ScoringResult
system_message: SystemMessage
health_info: HealthInfo
provider_info: ProviderInfo
list_providers_response: ListProvidersResponse
route_info: RouteInfo
list_routes_response: ListRoutesResponse
version_info: VersionInfo
toolgroups:
models:
tool_group: ToolGroup
@ -261,11 +267,6 @@ resources:
type: http
endpoint: delete /v1/conversations/{conversation_id}/items/{item_id}
inspect:
models:
healthInfo: HealthInfo
providerInfo: ProviderInfo
routeInfo: RouteInfo
versionInfo: VersionInfo
methods:
health: get /v1/health
version: get /v1/version
@ -357,16 +358,12 @@ resources:
paginated: false
endpoint: get /v1/models
providers:
models:
list_providers_response: ListProvidersResponse
methods:
list:
paginated: false
endpoint: get /v1/providers
retrieve: get /v1/providers/{provider_id}
routes:
models:
list_routes_response: ListRoutesResponse
methods:
list:
paginated: false
@ -474,6 +471,13 @@ resources:
cancel: delete /v1alpha/eval/benchmarks/{benchmark_id}/jobs/{job_id}
status: get /v1alpha/eval/benchmarks/{benchmark_id}/jobs/{job_id}
retrieve: get /v1alpha/eval/benchmarks/{benchmark_id}/jobs/{job_id}/result
admin:
methods:
list_providers: get /v1alpha/admin/providers
inspect_provider: get /v1alpha/admin/providers/{provider_id}
list_routes: get /v1alpha/admin/inspect/routes
health: get /v1alpha/admin/health
version: get /v1alpha/admin/version
beta:
subresources:
datasets:

File diff suppressed because it is too large Load diff

View file

@ -9773,26 +9773,64 @@ components:
- $ref: '#/components/schemas/OpenAIResponseContentPartReasoningText'
title: OpenAIResponseContentPartReasoningText
title: OpenAIResponseContentPartOutputText | OpenAIResponseContentPartRefusal | OpenAIResponseContentPartReasoningText
MetricInResponse:
description: A metric value included in API responses.
ListBenchmarksRequest:
description: Request model for listing benchmarks.
properties: {}
title: ListBenchmarksRequest
type: object
GetBenchmarkRequest:
description: Request model for getting a benchmark.
properties:
metric:
title: Metric
benchmark_id:
description: The ID of the benchmark to get.
title: Benchmark Id
type: string
value:
anyOf:
- type: integer
- type: number
title: integer | number
unit:
anyOf:
- type: string
- type: 'null'
nullable: true
required:
- metric
- value
title: MetricInResponse
- benchmark_id
title: GetBenchmarkRequest
type: object
UnregisterBenchmarkRequest:
description: Request model for unregistering a benchmark.
properties:
benchmark_id:
description: The ID of the benchmark to unregister.
title: Benchmark Id
type: string
required:
- benchmark_id
title: UnregisterBenchmarkRequest
type: object
GetDatasetRequest:
description: Request model for getting a dataset by ID.
properties:
dataset_id:
description: The ID of the dataset to get.
title: Dataset Id
type: string
required:
- dataset_id
title: GetDatasetRequest
type: object
UnregisterDatasetRequest:
description: Request model for unregistering a dataset.
properties:
dataset_id:
description: The ID of the dataset to unregister.
title: Dataset Id
type: string
required:
- dataset_id
title: UnregisterDatasetRequest
type: object
DialogType:
description: Parameter type for dialog data with semantic output labels.
properties:
type:
const: dialog
default: dialog
title: Type
type: string
title: DialogType
type: object
TextDelta:
description: A text content delta for streaming responses.
@ -9825,6 +9863,362 @@ components:
- image
title: ImageDelta
type: object
ToolGroupInput:
description: Input data for registering a tool group.
properties:
toolgroup_id:
title: Toolgroup Id
type: string
provider_id:
title: Provider Id
type: string
args:
anyOf:
- additionalProperties: true
type: object
- type: 'null'
nullable: true
mcp_endpoint:
anyOf:
- $ref: '#/components/schemas/URL'
title: URL
- type: 'null'
nullable: true
title: URL
required:
- toolgroup_id
- provider_id
title: ToolGroupInput
type: object
Api:
description: Enumeration of all available APIs in the Llama Stack system.
enum:
- providers
- inference
- safety
- agents
- batches
- vector_io
- datasetio
- scoring
- eval
- post_training
- tool_runtime
- models
- shields
- vector_stores
- datasets
- scoring_functions
- benchmarks
- tool_groups
- files
- prompts
- conversations
- connectors
- inspect
- admin
title: Api
type: string
ProviderSpec:
properties:
api:
$ref: '#/components/schemas/Api'
provider_type:
title: Provider Type
type: string
config_class:
description: Fully-qualified classname of the config for this provider
title: Config Class
type: string
api_dependencies:
description: Higher-level API surfaces may depend on other providers to provide their functionality
items:
$ref: '#/components/schemas/Api'
title: Api Dependencies
type: array
optional_api_dependencies:
items:
$ref: '#/components/schemas/Api'
title: Optional Api Dependencies
type: array
deprecation_warning:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated, specify the warning message here
nullable: true
deprecation_error:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated and does NOT work, specify the error message here
nullable: true
module:
anyOf:
- type: string
- type: 'null'
description: |2-
Fully-qualified name of the module to import. The module is expected to have:
- `get_adapter_impl(config, deps)`: returns the adapter implementation
Example: `module: ramalama_stack`
nullable: true
pip_packages:
description: The pip dependencies needed for this implementation
items:
type: string
title: Pip Packages
type: array
provider_data_validator:
anyOf:
- type: string
- type: 'null'
nullable: true
is_external:
default: false
description: Notes whether this provider is an external provider.
title: Is External
type: boolean
deps__:
items:
type: string
title: Deps
type: array
required:
- api
- provider_type
- config_class
title: ProviderSpec
type: object
InlineProviderSpec:
properties:
api:
$ref: '#/components/schemas/Api'
provider_type:
title: Provider Type
type: string
config_class:
description: Fully-qualified classname of the config for this provider
title: Config Class
type: string
api_dependencies:
description: Higher-level API surfaces may depend on other providers to provide their functionality
items:
$ref: '#/components/schemas/Api'
title: Api Dependencies
type: array
optional_api_dependencies:
items:
$ref: '#/components/schemas/Api'
title: Optional Api Dependencies
type: array
deprecation_warning:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated, specify the warning message here
nullable: true
deprecation_error:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated and does NOT work, specify the error message here
nullable: true
module:
anyOf:
- type: string
- type: 'null'
description: |2-
Fully-qualified name of the module to import. The module is expected to have:
- `get_adapter_impl(config, deps)`: returns the adapter implementation
Example: `module: ramalama_stack`
nullable: true
pip_packages:
description: The pip dependencies needed for this implementation
items:
type: string
title: Pip Packages
type: array
provider_data_validator:
anyOf:
- type: string
- type: 'null'
nullable: true
is_external:
default: false
description: Notes whether this provider is an external provider.
title: Is External
type: boolean
deps__:
items:
type: string
title: Deps
type: array
container_image:
anyOf:
- type: string
- type: 'null'
description: |2
The container image to use for this implementation. If one is provided, pip_packages will be ignored.
If a provider depends on other providers, the dependencies MUST NOT specify a container image.
nullable: true
description:
anyOf:
- type: string
- type: 'null'
description: |2
A description of the provider. This is used to display in the documentation.
nullable: true
required:
- api
- provider_type
- config_class
title: InlineProviderSpec
type: object
RemoteProviderSpec:
properties:
api:
$ref: '#/components/schemas/Api'
provider_type:
title: Provider Type
type: string
config_class:
description: Fully-qualified classname of the config for this provider
title: Config Class
type: string
api_dependencies:
description: Higher-level API surfaces may depend on other providers to provide their functionality
items:
$ref: '#/components/schemas/Api'
title: Api Dependencies
type: array
optional_api_dependencies:
items:
$ref: '#/components/schemas/Api'
title: Optional Api Dependencies
type: array
deprecation_warning:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated, specify the warning message here
nullable: true
deprecation_error:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated and does NOT work, specify the error message here
nullable: true
module:
anyOf:
- type: string
- type: 'null'
description: |2-
Fully-qualified name of the module to import. The module is expected to have:
- `get_adapter_impl(config, deps)`: returns the adapter implementation
Example: `module: ramalama_stack`
nullable: true
pip_packages:
description: The pip dependencies needed for this implementation
items:
type: string
title: Pip Packages
type: array
provider_data_validator:
anyOf:
- type: string
- type: 'null'
nullable: true
is_external:
default: false
description: Notes whether this provider is an external provider.
title: Is External
type: boolean
deps__:
items:
type: string
title: Deps
type: array
adapter_type:
description: Unique identifier for this adapter
title: Adapter Type
type: string
description:
anyOf:
- type: string
- type: 'null'
description: |2
A description of the provider. This is used to display in the documentation.
nullable: true
required:
- api
- provider_type
- config_class
- adapter_type
title: RemoteProviderSpec
type: object
ListRoutesRequest:
description: Request to list API routes.
properties:
api_filter:
anyOf:
- enum:
- v1
- v1alpha
- v1beta
- deprecated
type: string
- type: 'null'
description: Filter to control which routes are returned. Can be an API level ('v1', 'v1alpha', 'v1beta') to show non-deprecated routes at that level, or 'deprecated' to show deprecated routes across all levels. If not specified, returns all non-deprecated routes.
nullable: true
title: ListRoutesRequest
type: object
InspectProviderRequest:
description: Request to inspect a specific provider.
properties:
provider_id:
description: The ID of the provider to inspect.
title: Provider Id
type: string
required:
- provider_id
title: InspectProviderRequest
type: object
MetricInResponse:
description: A metric value included in API responses.
properties:
metric:
title: Metric
type: string
value:
anyOf:
- type: integer
- type: number
title: integer | number
unit:
anyOf:
- type: string
- type: 'null'
nullable: true
required:
- metric
- value
title: MetricInResponse
type: object
Fp8QuantizationConfig:
description: Configuration for 8-bit floating point quantization.
properties:
@ -10170,70 +10564,6 @@ components:
- batch_id
title: CancelBatchRequest
type: object
ListBenchmarksRequest:
description: Request model for listing benchmarks.
properties: {}
title: ListBenchmarksRequest
type: object
GetBenchmarkRequest:
description: Request model for getting a benchmark.
properties:
benchmark_id:
description: The ID of the benchmark to get.
title: Benchmark Id
type: string
required:
- benchmark_id
title: GetBenchmarkRequest
type: object
UnregisterBenchmarkRequest:
description: Request model for unregistering a benchmark.
properties:
benchmark_id:
description: The ID of the benchmark to unregister.
title: Benchmark Id
type: string
required:
- benchmark_id
title: UnregisterBenchmarkRequest
type: object
DialogType:
description: Parameter type for dialog data with semantic output labels.
properties:
type:
const: dialog
default: dialog
title: Type
type: string
title: DialogType
type: object
ToolGroupInput:
description: Input data for registering a tool group.
properties:
toolgroup_id:
title: Toolgroup Id
type: string
provider_id:
title: Provider Id
type: string
args:
anyOf:
- additionalProperties: true
type: object
- type: 'null'
nullable: true
mcp_endpoint:
anyOf:
- $ref: '#/components/schemas/URL'
title: URL
- type: 'null'
nullable: true
title: URL
required:
- toolgroup_id
- provider_id
title: ToolGroupInput
type: object
ConnectorInput:
description: Input for creating a connector
properties:
@ -10348,308 +10678,6 @@ components:
- items
title: ConversationItemCreateRequest
type: object
GetDatasetRequest:
description: Request model for getting a dataset by ID.
properties:
dataset_id:
description: The ID of the dataset to get.
title: Dataset Id
type: string
required:
- dataset_id
title: GetDatasetRequest
type: object
UnregisterDatasetRequest:
description: Request model for unregistering a dataset.
properties:
dataset_id:
description: The ID of the dataset to unregister.
title: Dataset Id
type: string
required:
- dataset_id
title: UnregisterDatasetRequest
type: object
Api:
description: Enumeration of all available APIs in the Llama Stack system.
enum:
- providers
- inference
- safety
- agents
- batches
- vector_io
- datasetio
- scoring
- eval
- post_training
- tool_runtime
- models
- shields
- vector_stores
- datasets
- scoring_functions
- benchmarks
- tool_groups
- files
- prompts
- conversations
- connectors
- inspect
title: Api
type: string
ProviderSpec:
properties:
api:
$ref: '#/components/schemas/Api'
provider_type:
title: Provider Type
type: string
config_class:
description: Fully-qualified classname of the config for this provider
title: Config Class
type: string
api_dependencies:
description: Higher-level API surfaces may depend on other providers to provide their functionality
items:
$ref: '#/components/schemas/Api'
title: Api Dependencies
type: array
optional_api_dependencies:
items:
$ref: '#/components/schemas/Api'
title: Optional Api Dependencies
type: array
deprecation_warning:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated, specify the warning message here
nullable: true
deprecation_error:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated and does NOT work, specify the error message here
nullable: true
module:
anyOf:
- type: string
- type: 'null'
description: |2-
Fully-qualified name of the module to import. The module is expected to have:
- `get_adapter_impl(config, deps)`: returns the adapter implementation
Example: `module: ramalama_stack`
nullable: true
pip_packages:
description: The pip dependencies needed for this implementation
items:
type: string
title: Pip Packages
type: array
provider_data_validator:
anyOf:
- type: string
- type: 'null'
nullable: true
is_external:
default: false
description: Notes whether this provider is an external provider.
title: Is External
type: boolean
deps__:
items:
type: string
title: Deps
type: array
required:
- api
- provider_type
- config_class
title: ProviderSpec
type: object
InlineProviderSpec:
properties:
api:
$ref: '#/components/schemas/Api'
provider_type:
title: Provider Type
type: string
config_class:
description: Fully-qualified classname of the config for this provider
title: Config Class
type: string
api_dependencies:
description: Higher-level API surfaces may depend on other providers to provide their functionality
items:
$ref: '#/components/schemas/Api'
title: Api Dependencies
type: array
optional_api_dependencies:
items:
$ref: '#/components/schemas/Api'
title: Optional Api Dependencies
type: array
deprecation_warning:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated, specify the warning message here
nullable: true
deprecation_error:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated and does NOT work, specify the error message here
nullable: true
module:
anyOf:
- type: string
- type: 'null'
description: |2-
Fully-qualified name of the module to import. The module is expected to have:
- `get_adapter_impl(config, deps)`: returns the adapter implementation
Example: `module: ramalama_stack`
nullable: true
pip_packages:
description: The pip dependencies needed for this implementation
items:
type: string
title: Pip Packages
type: array
provider_data_validator:
anyOf:
- type: string
- type: 'null'
nullable: true
is_external:
default: false
description: Notes whether this provider is an external provider.
title: Is External
type: boolean
deps__:
items:
type: string
title: Deps
type: array
container_image:
anyOf:
- type: string
- type: 'null'
description: |2
The container image to use for this implementation. If one is provided, pip_packages will be ignored.
If a provider depends on other providers, the dependencies MUST NOT specify a container image.
nullable: true
description:
anyOf:
- type: string
- type: 'null'
description: |2
A description of the provider. This is used to display in the documentation.
nullable: true
required:
- api
- provider_type
- config_class
title: InlineProviderSpec
type: object
RemoteProviderSpec:
properties:
api:
$ref: '#/components/schemas/Api'
provider_type:
title: Provider Type
type: string
config_class:
description: Fully-qualified classname of the config for this provider
title: Config Class
type: string
api_dependencies:
description: Higher-level API surfaces may depend on other providers to provide their functionality
items:
$ref: '#/components/schemas/Api'
title: Api Dependencies
type: array
optional_api_dependencies:
items:
$ref: '#/components/schemas/Api'
title: Optional Api Dependencies
type: array
deprecation_warning:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated, specify the warning message here
nullable: true
deprecation_error:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated and does NOT work, specify the error message here
nullable: true
module:
anyOf:
- type: string
- type: 'null'
description: |2-
Fully-qualified name of the module to import. The module is expected to have:
- `get_adapter_impl(config, deps)`: returns the adapter implementation
Example: `module: ramalama_stack`
nullable: true
pip_packages:
description: The pip dependencies needed for this implementation
items:
type: string
title: Pip Packages
type: array
provider_data_validator:
anyOf:
- type: string
- type: 'null'
nullable: true
is_external:
default: false
description: Notes whether this provider is an external provider.
title: Is External
type: boolean
deps__:
items:
type: string
title: Deps
type: array
adapter_type:
description: Unique identifier for this adapter
title: Adapter Type
type: string
description:
anyOf:
- type: string
- type: 'null'
description: |2
A description of the provider. This is used to display in the documentation.
nullable: true
required:
- api
- provider_type
- config_class
- adapter_type
title: RemoteProviderSpec
type: object
PostTrainingJobLogStream:
description: Stream of logs from a finetuning job.
properties:
@ -10715,17 +10743,6 @@ components:
- logger_config
title: PostTrainingRLHFRequest
type: object
InspectProviderRequest:
description: Request model for inspecting a provider by ID.
properties:
provider_id:
description: The ID of the provider to inspect.
title: Provider Id
type: string
required:
- provider_id
title: InspectProviderRequest
type: object
responses:
BadRequest400:
description: The request was invalid or malformed

File diff suppressed because it is too large Load diff

View file

@ -11268,26 +11268,64 @@ components:
- $ref: '#/components/schemas/OpenAIResponseContentPartReasoningText'
title: OpenAIResponseContentPartReasoningText
title: OpenAIResponseContentPartOutputText | OpenAIResponseContentPartRefusal | OpenAIResponseContentPartReasoningText
MetricInResponse:
description: A metric value included in API responses.
ListBenchmarksRequest:
description: Request model for listing benchmarks.
properties: {}
title: ListBenchmarksRequest
type: object
GetBenchmarkRequest:
description: Request model for getting a benchmark.
properties:
metric:
title: Metric
benchmark_id:
description: The ID of the benchmark to get.
title: Benchmark Id
type: string
value:
anyOf:
- type: integer
- type: number
title: integer | number
unit:
anyOf:
- type: string
- type: 'null'
nullable: true
required:
- metric
- value
title: MetricInResponse
- benchmark_id
title: GetBenchmarkRequest
type: object
UnregisterBenchmarkRequest:
description: Request model for unregistering a benchmark.
properties:
benchmark_id:
description: The ID of the benchmark to unregister.
title: Benchmark Id
type: string
required:
- benchmark_id
title: UnregisterBenchmarkRequest
type: object
GetDatasetRequest:
description: Request model for getting a dataset by ID.
properties:
dataset_id:
description: The ID of the dataset to get.
title: Dataset Id
type: string
required:
- dataset_id
title: GetDatasetRequest
type: object
UnregisterDatasetRequest:
description: Request model for unregistering a dataset.
properties:
dataset_id:
description: The ID of the dataset to unregister.
title: Dataset Id
type: string
required:
- dataset_id
title: UnregisterDatasetRequest
type: object
DialogType:
description: Parameter type for dialog data with semantic output labels.
properties:
type:
const: dialog
default: dialog
title: Type
type: string
title: DialogType
type: object
TextDelta:
description: A text content delta for streaming responses.
@ -11320,6 +11358,359 @@ components:
- image
title: ImageDelta
type: object
ToolGroupInput:
description: Input data for registering a tool group.
properties:
toolgroup_id:
title: Toolgroup Id
type: string
provider_id:
title: Provider Id
type: string
args:
anyOf:
- additionalProperties: true
type: object
- type: 'null'
nullable: true
mcp_endpoint:
anyOf:
- $ref: '#/components/schemas/URL'
title: URL
- type: 'null'
nullable: true
title: URL
required:
- toolgroup_id
- provider_id
title: ToolGroupInput
type: object
Api:
description: Enumeration of all available APIs in the Llama Stack system.
enum:
- providers
- inference
- safety
- agents
- batches
- vector_io
- datasetio
- scoring
- eval
- post_training
- tool_runtime
- models
- shields
- vector_stores
- datasets
- scoring_functions
- benchmarks
- tool_groups
- files
- prompts
- conversations
- connectors
- inspect
- admin
title: Api
type: string
ProviderSpec:
properties:
api:
$ref: '#/components/schemas/Api'
provider_type:
title: Provider Type
type: string
config_class:
description: Fully-qualified classname of the config for this provider
title: Config Class
type: string
api_dependencies:
description: Higher-level API surfaces may depend on other providers to provide their functionality
items:
$ref: '#/components/schemas/Api'
title: Api Dependencies
type: array
optional_api_dependencies:
items:
$ref: '#/components/schemas/Api'
title: Optional Api Dependencies
type: array
deprecation_warning:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated, specify the warning message here
nullable: true
deprecation_error:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated and does NOT work, specify the error message here
nullable: true
module:
anyOf:
- type: string
- type: 'null'
description: |2-
Fully-qualified name of the module to import. The module is expected to have:
- `get_adapter_impl(config, deps)`: returns the adapter implementation
Example: `module: ramalama_stack`
nullable: true
pip_packages:
description: The pip dependencies needed for this implementation
items:
type: string
title: Pip Packages
type: array
provider_data_validator:
anyOf:
- type: string
- type: 'null'
nullable: true
is_external:
default: false
description: Notes whether this provider is an external provider.
title: Is External
type: boolean
deps__:
items:
type: string
title: Deps
type: array
required:
- api
- provider_type
- config_class
title: ProviderSpec
type: object
InlineProviderSpec:
properties:
api:
$ref: '#/components/schemas/Api'
provider_type:
title: Provider Type
type: string
config_class:
description: Fully-qualified classname of the config for this provider
title: Config Class
type: string
api_dependencies:
description: Higher-level API surfaces may depend on other providers to provide their functionality
items:
$ref: '#/components/schemas/Api'
title: Api Dependencies
type: array
optional_api_dependencies:
items:
$ref: '#/components/schemas/Api'
title: Optional Api Dependencies
type: array
deprecation_warning:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated, specify the warning message here
nullable: true
deprecation_error:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated and does NOT work, specify the error message here
nullable: true
module:
anyOf:
- type: string
- type: 'null'
description: |2-
Fully-qualified name of the module to import. The module is expected to have:
- `get_adapter_impl(config, deps)`: returns the adapter implementation
Example: `module: ramalama_stack`
nullable: true
pip_packages:
description: The pip dependencies needed for this implementation
items:
type: string
title: Pip Packages
type: array
provider_data_validator:
anyOf:
- type: string
- type: 'null'
nullable: true
is_external:
default: false
description: Notes whether this provider is an external provider.
title: Is External
type: boolean
deps__:
items:
type: string
title: Deps
type: array
container_image:
anyOf:
- type: string
- type: 'null'
description: |2
The container image to use for this implementation. If one is provided, pip_packages will be ignored.
If a provider depends on other providers, the dependencies MUST NOT specify a container image.
nullable: true
description:
anyOf:
- type: string
- type: 'null'
description: |2
A description of the provider. This is used to display in the documentation.
nullable: true
required:
- api
- provider_type
- config_class
title: InlineProviderSpec
type: object
RemoteProviderSpec:
properties:
api:
$ref: '#/components/schemas/Api'
provider_type:
title: Provider Type
type: string
config_class:
description: Fully-qualified classname of the config for this provider
title: Config Class
type: string
api_dependencies:
description: Higher-level API surfaces may depend on other providers to provide their functionality
items:
$ref: '#/components/schemas/Api'
title: Api Dependencies
type: array
optional_api_dependencies:
items:
$ref: '#/components/schemas/Api'
title: Optional Api Dependencies
type: array
deprecation_warning:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated, specify the warning message here
nullable: true
deprecation_error:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated and does NOT work, specify the error message here
nullable: true
module:
anyOf:
- type: string
- type: 'null'
description: |2-
Fully-qualified name of the module to import. The module is expected to have:
- `get_adapter_impl(config, deps)`: returns the adapter implementation
Example: `module: ramalama_stack`
nullable: true
pip_packages:
description: The pip dependencies needed for this implementation
items:
type: string
title: Pip Packages
type: array
provider_data_validator:
anyOf:
- type: string
- type: 'null'
nullable: true
is_external:
default: false
description: Notes whether this provider is an external provider.
title: Is External
type: boolean
deps__:
items:
type: string
title: Deps
type: array
adapter_type:
description: Unique identifier for this adapter
title: Adapter Type
type: string
description:
anyOf:
- type: string
- type: 'null'
description: |2
A description of the provider. This is used to display in the documentation.
nullable: true
required:
- api
- provider_type
- config_class
- adapter_type
title: RemoteProviderSpec
type: object
ListRoutesRequest:
description: Request to list API routes.
properties:
api_filter:
anyOf:
- enum:
- v1
- v1alpha
- v1beta
- deprecated
type: string
- type: 'null'
description: Filter to control which routes are returned. Can be an API level ('v1', 'v1alpha', 'v1beta') to show non-deprecated routes at that level, or 'deprecated' to show deprecated routes across all levels. If not specified, returns all non-deprecated routes.
nullable: true
title: ListRoutesRequest
type: object
InspectProviderRequest:
description: Request to inspect a specific provider.
properties:
provider_id:
description: The ID of the provider to inspect.
title: Provider Id
type: string
required:
- provider_id
title: InspectProviderRequest
type: object
MetricInResponse:
description: A metric value included in API responses.
properties:
metric:
title: Metric
type: string
value:
anyOf:
- type: integer
- type: number
title: integer | number
unit:
anyOf:
- type: string
- type: 'null'
nullable: true
required:
- metric
- value
title: MetricInResponse
type: object
Fp8QuantizationConfig:
description: Configuration for 8-bit floating point quantization.
properties:
@ -11665,70 +12056,6 @@ components:
- batch_id
title: CancelBatchRequest
type: object
ListBenchmarksRequest:
description: Request model for listing benchmarks.
properties: {}
title: ListBenchmarksRequest
type: object
GetBenchmarkRequest:
description: Request model for getting a benchmark.
properties:
benchmark_id:
description: The ID of the benchmark to get.
title: Benchmark Id
type: string
required:
- benchmark_id
title: GetBenchmarkRequest
type: object
UnregisterBenchmarkRequest:
description: Request model for unregistering a benchmark.
properties:
benchmark_id:
description: The ID of the benchmark to unregister.
title: Benchmark Id
type: string
required:
- benchmark_id
title: UnregisterBenchmarkRequest
type: object
DialogType:
description: Parameter type for dialog data with semantic output labels.
properties:
type:
const: dialog
default: dialog
title: Type
type: string
title: DialogType
type: object
ToolGroupInput:
description: Input data for registering a tool group.
properties:
toolgroup_id:
title: Toolgroup Id
type: string
provider_id:
title: Provider Id
type: string
args:
anyOf:
- additionalProperties: true
type: object
- type: 'null'
nullable: true
mcp_endpoint:
anyOf:
- $ref: '#/components/schemas/URL'
title: URL
- type: 'null'
nullable: true
title: URL
required:
- toolgroup_id
- provider_id
title: ToolGroupInput
type: object
ConnectorInput:
description: Input for creating a connector
properties:
@ -11843,305 +12170,6 @@ components:
- items
title: ConversationItemCreateRequest
type: object
GetDatasetRequest:
description: Request model for getting a dataset by ID.
properties:
dataset_id:
description: The ID of the dataset to get.
title: Dataset Id
type: string
required:
- dataset_id
title: GetDatasetRequest
type: object
UnregisterDatasetRequest:
description: Request model for unregistering a dataset.
properties:
dataset_id:
description: The ID of the dataset to unregister.
title: Dataset Id
type: string
required:
- dataset_id
title: UnregisterDatasetRequest
type: object
Api:
description: Enumeration of all available APIs in the Llama Stack system.
enum:
- providers
- inference
- safety
- agents
- batches
- vector_io
- datasetio
- scoring
- eval
- post_training
- tool_runtime
- models
- shields
- vector_stores
- datasets
- scoring_functions
- benchmarks
- tool_groups
- files
- prompts
- conversations
- connectors
- inspect
title: Api
type: string
ProviderSpec:
properties:
api:
$ref: '#/components/schemas/Api'
provider_type:
title: Provider Type
type: string
config_class:
description: Fully-qualified classname of the config for this provider
title: Config Class
type: string
api_dependencies:
description: Higher-level API surfaces may depend on other providers to provide their functionality
items:
$ref: '#/components/schemas/Api'
title: Api Dependencies
type: array
optional_api_dependencies:
items:
$ref: '#/components/schemas/Api'
title: Optional Api Dependencies
type: array
deprecation_warning:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated, specify the warning message here
nullable: true
deprecation_error:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated and does NOT work, specify the error message here
nullable: true
module:
anyOf:
- type: string
- type: 'null'
description: |2-
Fully-qualified name of the module to import. The module is expected to have:
- `get_adapter_impl(config, deps)`: returns the adapter implementation
Example: `module: ramalama_stack`
nullable: true
pip_packages:
description: The pip dependencies needed for this implementation
items:
type: string
title: Pip Packages
type: array
provider_data_validator:
anyOf:
- type: string
- type: 'null'
nullable: true
is_external:
default: false
description: Notes whether this provider is an external provider.
title: Is External
type: boolean
deps__:
items:
type: string
title: Deps
type: array
required:
- api
- provider_type
- config_class
title: ProviderSpec
type: object
InlineProviderSpec:
properties:
api:
$ref: '#/components/schemas/Api'
provider_type:
title: Provider Type
type: string
config_class:
description: Fully-qualified classname of the config for this provider
title: Config Class
type: string
api_dependencies:
description: Higher-level API surfaces may depend on other providers to provide their functionality
items:
$ref: '#/components/schemas/Api'
title: Api Dependencies
type: array
optional_api_dependencies:
items:
$ref: '#/components/schemas/Api'
title: Optional Api Dependencies
type: array
deprecation_warning:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated, specify the warning message here
nullable: true
deprecation_error:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated and does NOT work, specify the error message here
nullable: true
module:
anyOf:
- type: string
- type: 'null'
description: |2-
Fully-qualified name of the module to import. The module is expected to have:
- `get_adapter_impl(config, deps)`: returns the adapter implementation
Example: `module: ramalama_stack`
nullable: true
pip_packages:
description: The pip dependencies needed for this implementation
items:
type: string
title: Pip Packages
type: array
provider_data_validator:
anyOf:
- type: string
- type: 'null'
nullable: true
is_external:
default: false
description: Notes whether this provider is an external provider.
title: Is External
type: boolean
deps__:
items:
type: string
title: Deps
type: array
container_image:
anyOf:
- type: string
- type: 'null'
description: |2
The container image to use for this implementation. If one is provided, pip_packages will be ignored.
If a provider depends on other providers, the dependencies MUST NOT specify a container image.
nullable: true
description:
anyOf:
- type: string
- type: 'null'
description: |2
A description of the provider. This is used to display in the documentation.
nullable: true
required:
- api
- provider_type
- config_class
title: InlineProviderSpec
type: object
RemoteProviderSpec:
properties:
api:
$ref: '#/components/schemas/Api'
provider_type:
title: Provider Type
type: string
config_class:
description: Fully-qualified classname of the config for this provider
title: Config Class
type: string
api_dependencies:
description: Higher-level API surfaces may depend on other providers to provide their functionality
items:
$ref: '#/components/schemas/Api'
title: Api Dependencies
type: array
optional_api_dependencies:
items:
$ref: '#/components/schemas/Api'
title: Optional Api Dependencies
type: array
deprecation_warning:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated, specify the warning message here
nullable: true
deprecation_error:
anyOf:
- type: string
- type: 'null'
description: If this provider is deprecated and does NOT work, specify the error message here
nullable: true
module:
anyOf:
- type: string
- type: 'null'
description: |2-
Fully-qualified name of the module to import. The module is expected to have:
- `get_adapter_impl(config, deps)`: returns the adapter implementation
Example: `module: ramalama_stack`
nullable: true
pip_packages:
description: The pip dependencies needed for this implementation
items:
type: string
title: Pip Packages
type: array
provider_data_validator:
anyOf:
- type: string
- type: 'null'
nullable: true
is_external:
default: false
description: Notes whether this provider is an external provider.
title: Is External
type: boolean
deps__:
items:
type: string
title: Deps
type: array
adapter_type:
description: Unique identifier for this adapter
title: Adapter Type
type: string
description:
anyOf:
- type: string
- type: 'null'
description: |2
A description of the provider. This is used to display in the documentation.
nullable: true
required:
- api
- provider_type
- config_class
- adapter_type
title: RemoteProviderSpec
type: object
PostTrainingJobLogStream:
description: Stream of logs from a finetuning job.
properties:
@ -12207,17 +12235,6 @@ components:
- logger_config
title: PostTrainingRLHFRequest
type: object
InspectProviderRequest:
description: Request model for inspecting a provider by ID.
properties:
provider_id:
description: The ID of the provider to inspect.
title: Provider Id
type: string
required:
- provider_id
title: InspectProviderRequest
type: object
responses:
BadRequest400:
description: The request was invalid or malformed

File diff suppressed because it is too large Load diff

View file

@ -210,6 +210,12 @@ ALL_RESOURCES = {
"sampling_params": "SamplingParams",
"scoring_result": "ScoringResult",
"system_message": "SystemMessage",
"health_info": "HealthInfo",
"provider_info": "ProviderInfo",
"list_providers_response": "ListProvidersResponse",
"route_info": "RouteInfo",
"list_routes_response": "ListRoutesResponse",
"version_info": "VersionInfo",
}
},
"toolgroups": {
@ -335,12 +341,6 @@ ALL_RESOURCES = {
},
},
"inspect": {
"models": {
"healthInfo": "HealthInfo",
"providerInfo": "ProviderInfo",
"routeInfo": "RouteInfo",
"versionInfo": "VersionInfo",
},
"methods": {"health": "get /v1/health", "version": "get /v1/version"},
},
"embeddings": {
@ -444,14 +444,12 @@ ALL_RESOURCES = {
"subresources": {"openai": {"methods": {"list": {"paginated": False, "endpoint": "get /v1/models"}}}},
},
"providers": {
"models": {"list_providers_response": "ListProvidersResponse"},
"methods": {
"list": {"paginated": False, "endpoint": "get /v1/providers"},
"retrieve": "get /v1/providers/{provider_id}",
},
},
"routes": {
"models": {"list_routes_response": "ListRoutesResponse"},
"methods": {"list": {"paginated": False, "endpoint": "get /v1/inspect/routes"}},
},
"moderations": {
@ -576,6 +574,15 @@ ALL_RESOURCES = {
}
},
},
"admin": {
"methods": {
"list_providers": "get /v1alpha/admin/providers",
"inspect_provider": "get /v1alpha/admin/providers/{provider_id}",
"list_routes": "get /v1alpha/admin/inspect/routes",
"health": "get /v1alpha/admin/health",
"version": "get /v1alpha/admin/version",
},
},
}
},
"beta": {

View file

@ -0,0 +1,267 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under the terms described in the LICENSE file in
# the root directory of this source tree.
import asyncio
from importlib.metadata import version
from typing import Any
from pydantic import BaseModel
from llama_stack.core.datatypes import StackConfig
from llama_stack.core.external import load_external_apis
from llama_stack.core.server.fastapi_router_registry import (
_ROUTER_FACTORIES,
build_fastapi_router,
get_router_routes,
)
from llama_stack.core.server.routes import get_all_api_routes
from llama_stack.core.utils.config import redact_sensitive_fields
from llama_stack.log import get_logger
from llama_stack_api import (
Admin,
Api,
HealthInfo,
HealthResponse,
HealthStatus,
InspectProviderRequest,
ListProvidersResponse,
ListRoutesRequest,
ListRoutesResponse,
ProviderInfo,
RouteInfo,
VersionInfo,
)
logger = get_logger(name=__name__, category="core")
class AdminImplConfig(BaseModel):
config: StackConfig
async def get_provider_impl(config, deps):
impl = AdminImpl(config, deps)
await impl.initialize()
return impl
class AdminImpl(Admin):
def __init__(self, config: AdminImplConfig, deps):
self.config = config
self.deps = deps
async def initialize(self) -> None:
pass
async def shutdown(self) -> None:
logger.debug("AdminImpl.shutdown")
pass
# Provider management methods
async def list_providers(self) -> ListProvidersResponse:
config = self.config.config
safe_config = StackConfig(**redact_sensitive_fields(config.model_dump()))
providers_health = await self.get_providers_health()
ret = []
for api, providers in safe_config.providers.items():
for p in providers:
# Skip providers that are not enabled
if p.provider_id is None:
continue
ret.append(
ProviderInfo(
api=api,
provider_id=p.provider_id,
provider_type=p.provider_type,
config=p.config,
health=providers_health.get(api, {}).get(
p.provider_id,
HealthResponse(
status=HealthStatus.NOT_IMPLEMENTED, message="Provider does not implement health check"
),
),
)
)
return ListProvidersResponse(data=ret)
async def inspect_provider(self, request: InspectProviderRequest) -> ProviderInfo:
all_providers = await self.list_providers()
for p in all_providers.data:
if p.provider_id == request.provider_id:
return p
raise ValueError(f"Provider {request.provider_id} not found")
async def get_providers_health(self) -> dict[str, dict[str, HealthResponse]]:
"""Get health status for all providers.
Returns:
Dict[str, Dict[str, HealthResponse]]: A dictionary mapping API names to provider health statuses.
Each API maps to a dictionary of provider IDs to their health responses.
"""
providers_health: dict[str, dict[str, HealthResponse]] = {}
# The timeout has to be long enough to allow all the providers to be checked, especially in
# the case of the inference router health check since it checks all registered inference
# providers.
# The timeout must not be equal to the one set by health method for a given implementation,
# otherwise we will miss some providers.
timeout = 3.0
async def check_provider_health(impl: Any) -> tuple[str, HealthResponse] | None:
# Skip special implementations (inspect/providers/admin) that don't have provider specs
if not hasattr(impl, "__provider_spec__"):
return None
api_name = impl.__provider_spec__.api.name
if not hasattr(impl, "health"):
return (
api_name,
HealthResponse(
status=HealthStatus.NOT_IMPLEMENTED, message="Provider does not implement health check"
),
)
try:
health = await asyncio.wait_for(impl.health(), timeout=timeout)
return api_name, health
except TimeoutError:
return (
api_name,
HealthResponse(
status=HealthStatus.ERROR, message=f"Health check timed out after {timeout} seconds"
),
)
except Exception as e:
return (
api_name,
HealthResponse(status=HealthStatus.ERROR, message=f"Health check failed: {str(e)}"),
)
# Create tasks for all providers
tasks = [check_provider_health(impl) for impl in self.deps.values()]
# Wait for all health checks to complete
results = await asyncio.gather(*tasks)
# Organize results by API and provider ID
for result in results:
if result is None: # Skip special implementations
continue
api_name, health_response = result
providers_health[api_name] = health_response
return providers_health
# Inspect methods
async def list_routes(self, request: ListRoutesRequest) -> ListRoutesResponse:
config: StackConfig = self.config.config
api_filter = request.api_filter
# Helper function to determine if a route should be included based on api_filter
# TODO: remove this once we've migrated all APIs to FastAPI routers
def should_include_route(webmethod) -> bool:
if api_filter is None:
# Default: only non-deprecated APIs
return not webmethod.deprecated
elif api_filter == "deprecated":
# Special filter: show deprecated routes regardless of their actual level
return bool(webmethod.deprecated)
else:
# Filter by API level (non-deprecated routes only)
return not webmethod.deprecated and webmethod.level == api_filter
# Helper function to get provider types for an API
def _get_provider_types(api: Api) -> list[str]:
if api.value in ["providers", "inspect", "admin"]:
return [] # These APIs don't have "real" providers - they're internal to the stack
providers = config.providers.get(api.value, [])
return [p.provider_type for p in providers] if providers else []
# Helper function to determine if a router route should be included based on api_filter
def _should_include_router_route(route, router_prefix: str | None) -> bool:
"""Check if a router-based route should be included based on api_filter."""
# Check deprecated status
route_deprecated = getattr(route, "deprecated", False) or False
if api_filter is None:
# Default: only non-deprecated routes
return not route_deprecated
elif api_filter == "deprecated":
# Special filter: show deprecated routes regardless of their actual level
return route_deprecated
else:
# Filter by API level (non-deprecated routes only)
# Extract level from router prefix (e.g., "/v1" -> "v1")
if router_prefix:
prefix_level = router_prefix.lstrip("/")
return not route_deprecated and prefix_level == api_filter
return not route_deprecated
ret = []
external_apis = load_external_apis(config)
all_endpoints = get_all_api_routes(external_apis)
# Process routes from APIs with FastAPI routers
for api_name in _ROUTER_FACTORIES.keys():
api = Api(api_name)
router = build_fastapi_router(api, None) # we don't need the impl here, just the routes
if router:
router_routes = get_router_routes(router)
for route in router_routes:
if _should_include_router_route(route, router.prefix):
if route.methods is not None:
available_methods = [m for m in route.methods if m != "HEAD"]
if available_methods:
ret.append(
RouteInfo(
route=route.path,
method=available_methods[0],
provider_types=_get_provider_types(api),
)
)
# Process routes from legacy webmethod-based APIs
for api, endpoints in all_endpoints.items():
# Skip APIs that have routers (already processed above)
if api.value in _ROUTER_FACTORIES:
continue
# Always include provider, inspect, and admin APIs, filter others based on run config
if api.value in ["providers", "inspect", "admin"]:
ret.extend(
[
RouteInfo(
route=e.path,
method=next(iter([m for m in e.methods if m != "HEAD"])),
provider_types=[], # These APIs don't have "real" providers - they're internal to the stack
)
for e, webmethod in endpoints
if e.methods is not None and should_include_route(webmethod)
]
)
else:
providers = config.providers.get(api.value, [])
if providers: # Only process if there are providers for this API
ret.extend(
[
RouteInfo(
route=e.path,
method=next(iter([m for m in e.methods if m != "HEAD"])),
provider_types=[p.provider_type for p in providers],
)
for e, webmethod in endpoints
if e.methods is not None and should_include_route(webmethod)
]
)
return ListRoutesResponse(data=ret)
async def health(self) -> HealthInfo:
return HealthInfo(status=HealthStatus.OK)
async def version(self) -> VersionInfo:
return VersionInfo(version=version("llama-stack"))

View file

@ -63,7 +63,7 @@ def configure_api_providers(config: StackConfig, build_spec: DistributionSpec) -
if config.apis:
apis_to_serve = config.apis
else:
apis_to_serve = [a.value for a in Api if a not in (Api.inspect, Api.providers)]
apis_to_serve = [a.value for a in Api if a not in (Api.inspect, Api.providers, Api.admin)]
for api_str in apis_to_serve:
api = Api(api_str)

View file

@ -25,7 +25,7 @@ from llama_stack_api import (
logger = get_logger(name=__name__, category="core")
INTERNAL_APIS = {Api.inspect, Api.providers, Api.prompts, Api.conversations, Api.connectors}
INTERNAL_APIS = {Api.inspect, Api.providers, Api.prompts, Api.conversations, Api.connectors, Api.admin}
def stack_apis() -> list[Api]:

View file

@ -24,6 +24,7 @@ from llama_stack.core.utils.dynamic import instantiate_class_type
from llama_stack.log import get_logger
from llama_stack_api import (
LLAMA_STACK_API_V1ALPHA,
Admin,
Agents,
Api,
Batches,
@ -80,6 +81,7 @@ def api_protocol_map(external_apis: dict[Api, ExternalApiSpec] | None = None) ->
Dictionary mapping API types to their protocol classes
"""
protocols = {
Api.admin: Admin,
Api.providers: ProvidersAPI,
Api.agents: Agents,
Api.inference: Inference,

View file

@ -16,13 +16,14 @@ from typing import Any, cast
from fastapi import APIRouter
from fastapi.routing import APIRoute
from llama_stack_api import batches, benchmarks, datasets, inspect_api, providers
from llama_stack_api import admin, batches, benchmarks, datasets, inspect_api, providers
# Router factories for APIs that have FastAPI routers
# Add new APIs here as they are migrated to the router system
from llama_stack_api.datatypes import Api
_ROUTER_FACTORIES: dict[str, Callable[[Any], APIRouter]] = {
"admin": admin.fastapi_routes.create_router,
"batches": batches.fastapi_routes.create_router,
"benchmarks": benchmarks.fastapi_routes.create_router,
"datasets": datasets.fastapi_routes.create_router,

View file

@ -469,6 +469,7 @@ def create_app() -> StackApp:
continue
apis_to_serve.add(inf.routing_table_api.value)
apis_to_serve.add("admin")
apis_to_serve.add("inspect")
apis_to_serve.add("providers")
apis_to_serve.add("prompts")

View file

@ -15,6 +15,7 @@ from typing import Any, get_type_hints
import yaml
from pydantic import BaseModel
from llama_stack.core.admin import AdminImpl, AdminImplConfig
from llama_stack.core.conversations.conversations import ConversationServiceConfig, ConversationServiceImpl
from llama_stack.core.datatypes import Provider, QualifiedModel, SafetyConfig, StackConfig, VectorStoresConfig
from llama_stack.core.distribution import get_provider_registry
@ -453,8 +454,7 @@ def cast_image_name_to_string(config_dict: dict[str, Any]) -> dict[str, Any]:
def add_internal_implementations(impls: dict[Api, Any], config: StackConfig) -> None:
"""Add internal implementations (inspect and providers) to the implementations dictionary.
"""Add internal implementations (inspect, providers, and admin) to the implementations dictionary.
Args:
impls: Dictionary of API implementations
run_config: Stack run configuration
@ -471,6 +471,12 @@ def add_internal_implementations(impls: dict[Api, Any], config: StackConfig) ->
)
impls[Api.providers] = providers_impl
admin_impl = AdminImpl(
AdminImplConfig(config=config),
deps=impls,
)
impls[Api.admin] = admin_impl
prompts_impl = PromptServiceImpl(
PromptServiceConfig(config=config),
deps=impls,

View file

@ -23,6 +23,18 @@ __version__ = "0.4.0.dev0"
# Import submodules for those who need them
from . import common # noqa: F401
from .admin import (
Admin,
ApiFilter,
HealthInfo,
InspectProviderRequest,
ListProvidersResponse,
ListRoutesRequest,
ListRoutesResponse,
ProviderInfo,
RouteInfo,
VersionInfo,
)
# Import all public API symbols
from .agents import Agents, ResponseGuardrail, ResponseGuardrailSpec, ResponseItemInclude
@ -220,14 +232,7 @@ from .inference import (
TopPSamplingStrategy,
UserMessage,
)
from .inspect_api import (
ApiFilter,
HealthInfo,
Inspect,
ListRoutesResponse,
RouteInfo,
VersionInfo,
)
from .inspect_api import Inspect
from .models import (
CommonModelFields,
ListModelsResponse,
@ -359,12 +364,7 @@ from .post_training import (
TrainingConfig,
)
from .prompts import ListPromptsResponse, Prompt, Prompts
from .providers import (
InspectProviderRequest,
ListProvidersResponse,
ProviderInfo,
Providers,
)
from .providers import Providers
from .rag_tool import (
DefaultRAGQueryGeneratorConfig,
LLMRAGQueryGeneratorConfig,
@ -578,6 +578,8 @@ __all__ = [
"InferenceProvider",
"InlineProviderSpec",
"Inspect",
"InspectProviderRequest",
"Admin",
"Int4QuantizationConfig",
"InterleavedContent",
"InterleavedContentItem",
@ -616,7 +618,7 @@ __all__ = [
"ListPostTrainingJobsResponse",
"ListPromptsResponse",
"ListProvidersResponse",
"InspectProviderRequest",
"ListRoutesRequest",
"ListRoutesResponse",
"ListScoringFunctionsResponse",
"ListShieldsResponse",

View file

@ -0,0 +1,45 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under the terms described in the LICENSE file in
# the root directory of this source tree.
"""Admin API protocol and models.
This module contains the Admin protocol definition.
Pydantic models are defined in llama_stack_api.admin.models.
The FastAPI router is defined in llama_stack_api.admin.fastapi_routes.
"""
# Import fastapi_routes for router factory access
from . import fastapi_routes
# Import protocol for re-export
from .api import Admin
# Import models for re-export
from .models import (
ApiFilter,
HealthInfo,
InspectProviderRequest,
ListProvidersResponse,
ListRoutesRequest,
ListRoutesResponse,
ProviderInfo,
RouteInfo,
VersionInfo,
)
__all__ = [
"Admin",
"ApiFilter",
"HealthInfo",
"InspectProviderRequest",
"ListProvidersResponse",
"ListRoutesRequest",
"ListRoutesResponse",
"ProviderInfo",
"RouteInfo",
"VersionInfo",
"fastapi_routes",
]

View file

@ -0,0 +1,72 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under the terms described in the LICENSE file in
# the root directory of this source tree.
from typing import Protocol, runtime_checkable
from .models import (
HealthInfo,
InspectProviderRequest,
ListProvidersResponse,
ListRoutesRequest,
ListRoutesResponse,
ProviderInfo,
VersionInfo,
)
@runtime_checkable
class Admin(Protocol):
"""Admin
Admin API for stack operations only available to administrative users.
"""
async def list_providers(self) -> ListProvidersResponse:
"""List providers.
List all available providers.
:returns: A ListProvidersResponse containing information about all providers.
"""
...
async def inspect_provider(self, request: InspectProviderRequest) -> ProviderInfo:
"""Get provider.
Get detailed information about a specific provider.
:param request: Request containing the provider ID to inspect
:returns: A ProviderInfo object containing the provider's details.
"""
...
async def list_routes(self, request: ListRoutesRequest) -> ListRoutesResponse:
"""List routes.
List all available API routes with their methods and implementing providers.
:param request: Request containing optional filter parameters
:returns: Response containing information about all available routes.
"""
...
async def health(self) -> HealthInfo:
"""Get health status.
Get the current health status of the service.
:returns: Health information indicating if the service is operational.
"""
...
async def version(self) -> VersionInfo:
"""Get version.
Get the version of the service.
:returns: Version information containing the service version number.
"""
...

View file

@ -0,0 +1,117 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under the terms described in the LICENSE file in
# the root directory of this source tree.
"""FastAPI router for the Admin API.
This module defines the FastAPI router for the Admin API using standard
FastAPI route decorators. The router is defined in the API package to keep
all API-related code together.
"""
from typing import Annotated
from fastapi import APIRouter, Depends
from llama_stack_api.router_utils import create_path_dependency, create_query_dependency, standard_responses
from llama_stack_api.version import LLAMA_STACK_API_V1ALPHA
from .api import Admin
from .models import (
HealthInfo,
InspectProviderRequest,
ListProvidersResponse,
ListRoutesRequest,
ListRoutesResponse,
ProviderInfo,
VersionInfo,
)
# Automatically generate dependency functions from Pydantic models
get_inspect_provider_request = create_path_dependency(InspectProviderRequest)
get_list_routes_request = create_query_dependency(ListRoutesRequest)
def create_router(impl: Admin) -> APIRouter:
"""Create a FastAPI router for the Admin API.
Args:
impl: The Admin implementation instance
Returns:
APIRouter configured for the Admin API
"""
router = APIRouter(
prefix=f"/{LLAMA_STACK_API_V1ALPHA}",
tags=["Admin"],
responses=standard_responses,
)
@router.get(
"/admin/providers",
response_model=ListProvidersResponse,
summary="List all available providers",
description="List all available providers with their configuration and health status.",
responses={
200: {"description": "A list of provider information objects."},
},
)
async def list_providers() -> ListProvidersResponse:
return await impl.list_providers()
@router.get(
"/admin/providers/{provider_id}",
response_model=ProviderInfo,
summary="Get provider details",
description="Get detailed information about a specific provider.",
responses={
200: {"description": "The provider information object."},
404: {"description": "Provider not found."},
},
)
async def inspect_provider(
request: Annotated[InspectProviderRequest, Depends(get_inspect_provider_request)],
) -> ProviderInfo:
return await impl.inspect_provider(request)
@router.get(
"/admin/inspect/routes",
response_model=ListRoutesResponse,
summary="List all available API routes",
description="List all available API routes with their methods and implementing providers.",
responses={
200: {"description": "A list of route information objects."},
},
)
async def list_routes(
request: Annotated[ListRoutesRequest, Depends(get_list_routes_request)],
) -> ListRoutesResponse:
return await impl.list_routes(request)
@router.get(
"/admin/health",
response_model=HealthInfo,
summary="Get service health status",
description="Get the current health status of the service.",
responses={
200: {"description": "Health information object."},
},
)
async def health() -> HealthInfo:
return await impl.health()
@router.get(
"/admin/version",
response_model=VersionInfo,
summary="Get service version",
description="Get the version of the service.",
responses={
200: {"description": "Version information object."},
},
)
async def version() -> VersionInfo:
return await impl.version()
return router

View file

@ -0,0 +1,113 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under the terms described in the LICENSE file in
# the root directory of this source tree.
from typing import Any, Literal
from pydantic import BaseModel, Field
from llama_stack_api.datatypes import HealthResponse, HealthStatus
from llama_stack_api.schema_utils import json_schema_type
# Valid values for the route filter parameter.
# Actual API levels: v1, v1alpha, v1beta (filters by level, excludes deprecated)
# Special filter value: "deprecated" (shows deprecated routes regardless of level)
ApiFilter = Literal["v1", "v1alpha", "v1beta", "deprecated"]
@json_schema_type
class RouteInfo(BaseModel):
"""Information about an API route including its path, method, and implementing providers.
:param route: The API endpoint path
:param method: HTTP method for the route
:param provider_types: List of provider types that implement this route
"""
route: str = Field(description="The API route path")
method: str = Field(description="The HTTP method for the route")
provider_types: list[str] = Field(description="List of provider types implementing this route")
@json_schema_type
class HealthInfo(BaseModel):
"""Health status information for the service.
:param status: Current health status of the service
"""
status: HealthStatus = Field(description="The health status of the service")
@json_schema_type
class VersionInfo(BaseModel):
"""Version information for the service.
:param version: Version number of the service
"""
version: str = Field(description="The version string of the service")
@json_schema_type
class ListRoutesResponse(BaseModel):
"""Response containing a list of all available API routes.
:param data: List of available route information objects
"""
data: list[RouteInfo] = Field(description="List of available API routes")
@json_schema_type
class ProviderInfo(BaseModel):
"""Information about a registered provider including its configuration and health status.
:param api: The API name this provider implements
:param provider_id: Unique identifier for the provider
:param provider_type: The type of provider implementation
:param config: Configuration parameters for the provider
:param health: Current health status of the provider
"""
api: str = Field(..., description="The API name this provider implements")
provider_id: str = Field(..., description="Unique identifier for the provider")
provider_type: str = Field(..., description="The type of provider implementation")
config: dict[str, Any] = Field(..., description="Configuration parameters for the provider")
health: HealthResponse = Field(..., description="Current health status of the provider")
@json_schema_type
class ListProvidersResponse(BaseModel):
"""Response containing a list of all available providers.
:param data: List of provider information objects
"""
data: list[ProviderInfo] = Field(..., description="List of provider information objects")
# Request models for FastAPI
@json_schema_type
class ListRoutesRequest(BaseModel):
"""Request to list API routes.
:param api_filter: Optional filter to control which routes are returned
"""
api_filter: ApiFilter | None = Field(
default=None,
description="Filter to control which routes are returned. Can be an API level ('v1', 'v1alpha', 'v1beta') to show non-deprecated routes at that level, or 'deprecated' to show deprecated routes across all levels. If not specified, returns all non-deprecated routes.",
)
@json_schema_type
class InspectProviderRequest(BaseModel):
"""Request to inspect a specific provider.
:param provider_id: The ID of the provider to inspect
"""
provider_id: str = Field(..., description="The ID of the provider to inspect.")

View file

@ -141,6 +141,7 @@ class Api(Enum, metaclass=DynamicApiMeta):
# built-in API
inspect = "inspect"
admin = "admin"
@json_schema_type

View file

@ -6,48 +6,23 @@
"""Pydantic models for Inspect API requests and responses.
This module defines the request and response models for the Inspect API
using Pydantic with Field descriptions for OpenAPI schema generation.
This module re-exports models from llama_stack_api.admin.models to ensure
a single source of truth and avoid type conflicts.
"""
from typing import Literal
# Import and re-export shared models from admin
from llama_stack_api.admin.models import (
ApiFilter,
HealthInfo,
ListRoutesResponse,
RouteInfo,
VersionInfo,
)
from pydantic import BaseModel, Field
from llama_stack_api.datatypes import HealthStatus
from llama_stack_api.schema_utils import json_schema_type
# Valid values for the route filter parameter.
# Actual API levels: v1, v1alpha, v1beta (filters by level, excludes deprecated)
# Special filter value: "deprecated" (shows deprecated routes regardless of level)
ApiFilter = Literal["v1", "v1alpha", "v1beta", "deprecated"]
@json_schema_type
class RouteInfo(BaseModel):
"""Information about an API route including its path, method, and implementing providers."""
route: str = Field(description="The API route path")
method: str = Field(description="The HTTP method for the route")
provider_types: list[str] = Field(description="List of provider types implementing this route")
@json_schema_type
class HealthInfo(BaseModel):
"""Health status information for the service."""
status: HealthStatus = Field(description="The health status of the service")
@json_schema_type
class VersionInfo(BaseModel):
"""Version information for the service."""
version: str = Field(description="The version string of the service")
@json_schema_type
class ListRoutesResponse(BaseModel):
"""Response containing a list of all available API routes."""
data: list[RouteInfo] = Field(description="List of available API routes")
__all__ = [
"ApiFilter",
"RouteInfo",
"HealthInfo",
"VersionInfo",
"ListRoutesResponse",
]

View file

@ -6,38 +6,19 @@
"""Pydantic models for Providers API requests and responses.
This module defines the request and response models for the Providers API
using Pydantic with Field descriptions for OpenAPI schema generation.
This module re-exports models from llama_stack_api.admin.models to ensure
a single source of truth and avoid type conflicts.
"""
from typing import Any
# Import and re-export shared models from admin
from llama_stack_api.admin.models import (
InspectProviderRequest,
ListProvidersResponse,
ProviderInfo,
)
from pydantic import BaseModel, Field
from llama_stack_api.datatypes import HealthResponse
from llama_stack_api.schema_utils import json_schema_type
@json_schema_type
class ProviderInfo(BaseModel):
"""Information about a registered provider including its configuration and health status."""
api: str = Field(..., description="The API name this provider implements")
provider_id: str = Field(..., description="Unique identifier for the provider")
provider_type: str = Field(..., description="The type of provider implementation")
config: dict[str, Any] = Field(..., description="Configuration parameters for the provider")
health: HealthResponse = Field(..., description="Current health status of the provider")
@json_schema_type
class ListProvidersResponse(BaseModel):
"""Response containing a list of all available providers."""
data: list[ProviderInfo] = Field(..., description="List of provider information objects")
@json_schema_type
class InspectProviderRequest(BaseModel):
"""Request model for inspecting a provider by ID."""
provider_id: str = Field(..., description="The ID of the provider to inspect.")
__all__ = [
"ProviderInfo",
"ListProvidersResponse",
"InspectProviderRequest",
]

View file

@ -0,0 +1,5 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under the terms described in the LICENSE file in
# the root directory of this source tree.

View file

@ -0,0 +1,73 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under the terms described in the LICENSE file in
# the root directory of this source tree.
from llama_stack_client import LlamaStackClient
from llama_stack.core.library_client import LlamaStackAsLibraryClient
class TestAdmin:
def test_admin_providers_list(self, llama_stack_client: LlamaStackAsLibraryClient | LlamaStackClient):
provider_list = llama_stack_client.alpha.admin.list_providers()
assert provider_list is not None
assert len(provider_list) > 0
for provider in provider_list:
pid = provider.provider_id
provider = llama_stack_client.alpha.admin.inspect_provider(pid)
assert provider is not None
def test_health(self, llama_stack_client: LlamaStackAsLibraryClient | LlamaStackClient):
health = llama_stack_client.alpha.admin.health()
assert health is not None
assert health.status == "OK"
def test_version(self, llama_stack_client: LlamaStackAsLibraryClient | LlamaStackClient):
version = llama_stack_client.alpha.admin.version()
assert version is not None
assert version.version is not None
def test_list_routes_default(self, llama_stack_client: LlamaStackAsLibraryClient | LlamaStackClient):
"""Test list_routes with default filter (non-deprecated v1 routes)."""
routes = llama_stack_client.alpha.admin.list_routes()
assert routes is not None
assert len(routes) > 0
# All routes should be non-deprecated
# Check that we don't see any /openai/ routes (which are deprecated)
openai_routes = [r for r in routes if "/openai/" in r.route]
assert len(openai_routes) == 0, "Default filter should not include deprecated /openai/ routes"
# Should see standard v1 routes like /inspect/routes, /health, /version
paths = [r.route for r in routes]
assert "/inspect/routes" in paths or "/v1/inspect/routes" in paths
assert "/health" in paths or "/v1/health" in paths
def test_list_routes_filter_by_deprecated(self, llama_stack_client: LlamaStackAsLibraryClient | LlamaStackClient):
"""Test list_routes with deprecated filter."""
routes = llama_stack_client.alpha.admin.list_routes(api_filter="deprecated")
assert routes is not None
# When filtering for deprecated, we should get deprecated routes
# Verify we get some deprecated routes (e.g., /toolgroups, /shields, /models, etc.)
assert len(routes) > 0, "Deprecated filter should return some deprecated routes"
def test_list_routes_filter_by_v1(self, llama_stack_client: LlamaStackAsLibraryClient | LlamaStackClient):
"""Test list_routes with v1 filter."""
routes = llama_stack_client.alpha.admin.list_routes(api_filter="v1")
assert routes is not None
assert len(routes) > 0
# Should not include deprecated routes
openai_routes = [r for r in routes if "/openai/" in r.route]
assert len(openai_routes) == 0
# Should include v1 routes
paths = [r.route for r in routes]
assert any(
"/v1/" in p or p.startswith("/inspect/") or p.startswith("/health") or p.startswith("/version")
for p in paths
)