llama-stack-mirror/src/llama_stack_api
Sébastien Han 7f43051a63
feat: Implement FastAPI router system (#4191)
# What does this PR do?

This commit introduces a new FastAPI router-based system for defining
API endpoints, enabling a migration path away from the legacy @webmethod
decorator system. The implementation includes router infrastructure,
migration of the Batches API as the first example, and updates to
server, OpenAPI generation, and inspection systems to support both
routing approaches.

The router infrastructure consists of a router registry system that
allows APIs to register FastAPI router factories, which are then
automatically discovered and included in the server application.
Standard error responses are centralized in router_utils to ensure
consistent OpenAPI specification generation with proper $ref references
to component responses.

The Batches API has been migrated to demonstrate the new pattern. The
protocol definition and models remain in llama_stack_api/batches,
maintaining clear separation between API contracts and server
implementation. The FastAPI router implementation lives in
llama_stack/core/server/routers/batches, following the established
pattern where API contracts are defined in llama_stack_api and server
routing logic lives in
llama_stack/core/server.

The server now checks for registered routers before falling back to the
legacy webmethod-based route discovery, ensuring backward compatibility
during the migration period. The OpenAPI generator has been updated to
handle both router-based and webmethod-based routes, correctly
extracting metadata from FastAPI route decorators and Pydantic Field
descriptions. The inspect endpoint now includes routes from both
systems, with proper filtering for deprecated routes and API levels.

Response descriptions are now explicitly defined in router decorators,
ensuring the generated OpenAPI specification matches the previous
format. Error responses use $ref references to component responses
(BadRequest400, TooManyRequests429, etc.) as required by the
specification. This is neat and will allow us to remove a lot of boiler
plate code from our generator once the migration is done.

This implementation provides a foundation for incrementally migrating
other APIs to the router system while maintaining full backward
compatibility with existing webmethod-based APIs.

Closes: https://github.com/llamastack/llama-stack/issues/4188

## Test Plan

CI, the server should start, same routes should be visible.

```
curl http://localhost:8321/v1/inspect/routes | jq '.data[] | select(.route | contains("batches"))'
```

Also:

```
 uv run pytest tests/integration/batches/ -vv --stack-config=http://localhost:8321
================================================== test session starts ==================================================
platform darwin -- Python 3.12.8, pytest-8.4.2, pluggy-1.6.0 -- /Users/leseb/Documents/AI/llama-stack/.venv/bin/python3
cachedir: .pytest_cache
metadata: {'Python': '3.12.8', 'Platform': 'macOS-26.0.1-arm64-arm-64bit', 'Packages': {'pytest': '8.4.2', 'pluggy': '1.6.0'}, 'Plugins': {'anyio': '4.9.0', 'html': '4.1.1', 'socket': '0.7.0', 'asyncio': '1.1.0', 'json-report': '1.5.0', 'timeout': '2.4.0', 'metadata': '3.1.1', 'cov': '6.2.1', 'nbval': '0.11.0'}}
rootdir: /Users/leseb/Documents/AI/llama-stack
configfile: pyproject.toml
plugins: anyio-4.9.0, html-4.1.1, socket-0.7.0, asyncio-1.1.0, json-report-1.5.0, timeout-2.4.0, metadata-3.1.1, cov-6.2.1, nbval-0.11.0
asyncio: mode=Mode.AUTO, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function
collected 24 items                                                                                                      

tests/integration/batches/test_batches.py::TestBatchesIntegration::test_batch_creation_and_retrieval[None] SKIPPED [  4%]
tests/integration/batches/test_batches.py::TestBatchesIntegration::test_batch_listing[None] SKIPPED               [  8%]
tests/integration/batches/test_batches.py::TestBatchesIntegration::test_batch_immediate_cancellation[None] SKIPPED [ 12%]
tests/integration/batches/test_batches.py::TestBatchesIntegration::test_batch_e2e_chat_completions[None] SKIPPED  [ 16%]
tests/integration/batches/test_batches.py::TestBatchesIntegration::test_batch_e2e_completions[None] SKIPPED       [ 20%]
tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_batch_invalid_endpoint[None] SKIPPED [ 25%]
tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_batch_cancel_completed[None] SKIPPED [ 29%]
tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_batch_missing_required_fields[None] SKIPPED [ 33%]
tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_batch_invalid_completion_window[None] SKIPPED [ 37%]
tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_batch_streaming_not_supported[None] SKIPPED [ 41%]
tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_batch_mixed_streaming_requests[None] SKIPPED [ 45%]
tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_batch_endpoint_mismatch[None] SKIPPED [ 50%]
tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_batch_missing_required_body_fields[None] SKIPPED [ 54%]
tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_batch_invalid_metadata_types[None] SKIPPED [ 58%]
tests/integration/batches/test_batches.py::TestBatchesIntegration::test_batch_e2e_embeddings[None] SKIPPED        [ 62%]
tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_batch_nonexistent_file_id PASSED [ 66%]
tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_batch_malformed_jsonl PASSED     [ 70%]
tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_file_malformed_batch_file[empty] XFAIL [ 75%]
tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_file_malformed_batch_file[malformed] XFAIL [ 79%]
tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_batch_retrieve_nonexistent PASSED [ 83%]
tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_batch_cancel_nonexistent PASSED  [ 87%]
tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_batch_error_handling_invalid_model PASSED [ 91%]
tests/integration/batches/test_batches_idempotency.py::TestBatchesIdempotencyIntegration::test_idempotent_batch_creation_successful PASSED [ 95%]
tests/integration/batches/test_batches_idempotency.py::TestBatchesIdempotencyIntegration::test_idempotency_conflict_with_different_params PASSED [100%]

================================================= slowest 10 durations ==================================================
1.01s call     tests/integration/batches/test_batches_idempotency.py::TestBatchesIdempotencyIntegration::test_idempotent_batch_creation_successful
0.21s call     tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_batch_nonexistent_file_id
0.17s call     tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_batch_malformed_jsonl
0.12s call     tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_batch_error_handling_invalid_model
0.05s setup    tests/integration/batches/test_batches.py::TestBatchesIntegration::test_batch_creation_and_retrieval[None]
0.02s call     tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_file_malformed_batch_file[empty]
0.01s call     tests/integration/batches/test_batches_idempotency.py::TestBatchesIdempotencyIntegration::test_idempotency_conflict_with_different_params
0.01s call     tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_file_malformed_batch_file[malformed]
0.01s call     tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_batch_retrieve_nonexistent
0.00s call     tests/integration/batches/test_batches_errors.py::TestBatchesErrorHandling::test_batch_cancel_nonexistent
======================================= 7 passed, 15 skipped, 2 xfailed in 1.78s ========================================
```

---------

Signed-off-by: Sébastien Han <seb@redhat.com>
2025-12-03 12:25:54 +01:00
..
batches feat: Implement FastAPI router system (#4191) 2025-12-03 12:25:54 +01:00
common fix: remove telemetry_traceable (#4205) 2025-12-01 10:40:57 -08:00
internal refactor(storage): make { kvstore, sqlstore } as llama stack "internal" APIs (#4181) 2025-11-18 13:15:16 -08:00
__init__.py feat: Implement FastAPI router system (#4191) 2025-12-03 12:25:54 +01:00
agents.py feat: Add metadata field to request and response (#4237) 2025-12-01 10:48:53 -08:00
benchmarks.py feat(openapi): switch to fastapi-based generator (#3944) 2025-11-14 15:53:53 -08:00
conversations.py fix: remove telemetry_traceable (#4205) 2025-12-01 10:40:57 -08:00
datasetio.py fix: rename llama_stack_api dir (#4155) 2025-11-13 15:04:36 -08:00
datasets.py feat(openapi): switch to fastapi-based generator (#3944) 2025-11-14 15:53:53 -08:00
datatypes.py fix: rename llama_stack_api dir (#4155) 2025-11-13 15:04:36 -08:00
eval.py fix: rename llama_stack_api dir (#4155) 2025-11-13 15:04:36 -08:00
files.py fix: remove telemetry_traceable (#4205) 2025-12-01 10:40:57 -08:00
inference.py fix: remove telemetry_traceable (#4205) 2025-12-01 10:40:57 -08:00
inspect.py feat(openapi): switch to fastapi-based generator (#3944) 2025-11-14 15:53:53 -08:00
models.py fix: remove telemetry_traceable (#4205) 2025-12-01 10:40:57 -08:00
openai_responses.py feat: Add metadata field to request and response (#4237) 2025-12-01 10:48:53 -08:00
post_training.py feat(openapi): switch to fastapi-based generator (#3944) 2025-11-14 15:53:53 -08:00
prompts.py fix: remove telemetry_traceable (#4205) 2025-12-01 10:40:57 -08:00
providers.py feat(openapi): switch to fastapi-based generator (#3944) 2025-11-14 15:53:53 -08:00
py.typed fix: rename llama_stack_api dir (#4155) 2025-11-13 15:04:36 -08:00
pyproject.toml feat: Implement FastAPI router system (#4191) 2025-12-03 12:25:54 +01:00
rag_tool.py fix: rename llama_stack_api dir (#4155) 2025-11-13 15:04:36 -08:00
README.md fix: rename llama_stack_api dir (#4155) 2025-11-13 15:04:36 -08:00
resource.py fix: rename llama_stack_api dir (#4155) 2025-11-13 15:04:36 -08:00
router_utils.py feat: Implement FastAPI router system (#4191) 2025-12-03 12:25:54 +01:00
safety.py fix: remove telemetry_traceable (#4205) 2025-12-01 10:40:57 -08:00
schema_utils.py feat(openapi): switch to fastapi-based generator (#3944) 2025-11-14 15:53:53 -08:00
scoring.py fix: rename llama_stack_api dir (#4155) 2025-11-13 15:04:36 -08:00
scoring_functions.py feat(openapi): switch to fastapi-based generator (#3944) 2025-11-14 15:53:53 -08:00
shields.py fix: remove telemetry_traceable (#4205) 2025-12-01 10:40:57 -08:00
tools.py feat(api)!: deprecate toolgroup and tool_runtime apis (#4249) 2025-12-01 11:43:58 -08:00
uv.lock fix: rename llama_stack_api dir (#4155) 2025-11-13 15:04:36 -08:00
vector_io.py fix: remove telemetry_traceable (#4205) 2025-12-01 10:40:57 -08:00
vector_stores.py fix: rename llama_stack_api dir (#4155) 2025-11-13 15:04:36 -08:00
version.py fix: rename llama_stack_api dir (#4155) 2025-11-13 15:04:36 -08:00

llama-stack-api

API and Provider specifications for Llama Stack - a lightweight package with protocol definitions and provider specs.

Overview

llama-stack-api is a minimal dependency package that contains:

  • API Protocol Definitions: Type-safe protocol definitions for all Llama Stack APIs (inference, agents, safety, etc.)
  • Provider Specifications: Provider spec definitions for building custom providers
  • Data Types: Shared data types and models used across the Llama Stack ecosystem
  • Type Utilities: Strong typing utilities and schema validation

What This Package Does NOT Include

  • Server implementation (see llama-stack package)
  • Provider implementations (see llama-stack package)
  • CLI tools (see llama-stack package)
  • Runtime orchestration (see llama-stack package)

Use Cases

This package is designed for:

  1. Third-party Provider Developers: Build custom providers without depending on the full Llama Stack server
  2. Client Library Authors: Use type definitions without server dependencies
  3. Documentation Generation: Generate API docs from protocol definitions
  4. Type Checking: Validate implementations against the official specs

Installation

pip install llama-stack-api

Or with uv:

uv pip install llama-stack-api

Dependencies

Minimal dependencies:

  • pydantic>=2.11.9 - For data validation and serialization
  • jsonschema - For JSON schema utilities

Versioning

This package follows semantic versioning independently from the main llama-stack package:

  • Patch versions (0.1.x): Documentation, internal improvements
  • Minor versions (0.x.0): New APIs, backward-compatible changes
  • Major versions (x.0.0): Breaking changes to existing APIs

Current version: 0.4.0.dev0

Usage Example

from llama_stack_api.inference import Inference, ChatCompletionRequest
from llama_stack_api.providers.datatypes import ProviderSpec, InlineProviderSpec
from llama_stack_api.datatypes import Api


# Use protocol definitions for type checking
class MyInferenceProvider(Inference):
    async def chat_completion(self, request: ChatCompletionRequest):
        # Your implementation
        pass


# Define provider specifications
my_provider_spec = InlineProviderSpec(
    api=Api.inference,
    provider_type="inline::my-provider",
    pip_packages=["my-dependencies"],
    module="my_package.providers.inference",
    config_class="my_package.providers.inference.MyConfig",
)

Relationship to llama-stack

The main llama-stack package depends on llama-stack-api and provides:

  • Full server implementation
  • Built-in provider implementations
  • CLI tools for running and managing stacks
  • Runtime provider resolution and orchestration

Contributing

See the main Llama Stack repository for contribution guidelines.

License

MIT License - see LICENSE file for details.