diff --git a/docs/openapi.json b/docs/openapi.json index bd1137da..ed3ca918 100644 --- a/docs/openapi.json +++ b/docs/openapi.json @@ -74,7 +74,7 @@ "models" ], "summary": "Models Endpoint Handler", - "description": "Handle requests to the /models endpoint.", + "description": "Handle requests to the /models endpoint.\n\nProcess GET requests to the /models endpoint, returning a list of available\nmodels from the Llama Stack service.\n\nRaises:\n HTTPException: If unable to connect to the Llama Stack server or if\n model retrieval fails for any reason.\n\nReturns:\n ModelsResponse: An object containing the list of available models.", "operationId": "models_endpoint_handler_v1_models_get", "responses": { "200": { @@ -300,7 +300,7 @@ "feedback" ], "summary": "Feedback Endpoint Handler", - "description": "Handle feedback requests.\n\nArgs:\n feedback_request: The request containing feedback information.\n ensure_feedback_enabled: The feedback handler (FastAPI Depends) that\n will handle feedback status checks.\n auth: The Authentication handler (FastAPI Depends) that will\n handle authentication Logic.\n\nReturns:\n Response indicating the status of the feedback storage request.", + "description": "Handle feedback requests.\n\nProcesses a user feedback submission, storing the feedback and\nreturning a confirmation response.\n\nArgs:\n feedback_request: The request containing feedback information.\n ensure_feedback_enabled: The feedback handler (FastAPI Depends) that\n will handle feedback status checks.\n auth: The Authentication handler (FastAPI Depends) that will\n handle authentication Logic.\n\nReturns:\n Response indicating the status of the feedback storage request.\n\nRaises:\n HTTPException: Returns HTTP 500 if feedback storage fails.", "operationId": "feedback_endpoint_handler_v1_feedback_post", "requestBody": { "content": { @@ -372,7 +372,7 @@ "feedback" ], "summary": "Feedback Status", - "description": "Handle feedback status requests.\n\nReturns:\n Response indicating the status of the feedback.", + "description": "Handle feedback status requests.\n\nReturn the current enabled status of the feedback\nfunctionality.\n\nReturns:\n StatusResponse: Indicates whether feedback collection is enabled.", "operationId": "feedback_status_v1_feedback_status_get", "responses": { "200": { @@ -441,7 +441,7 @@ "conversations" ], "summary": "Get Conversation Endpoint Handler", - "description": "Handle request to retrieve a conversation by ID.", + "description": "Handle request to retrieve a conversation by ID.\n\nRetrieve a conversation's chat history by its ID. Then fetches\nthe conversation session from the Llama Stack backend,\nsimplifies the session data to essential chat history, and\nreturns it in a structured response. Raises HTTP 400 for\ninvalid IDs, 404 if not found, 503 if the backend is\nunavailable, and 500 for unexpected errors.\n\nParameters:\n conversation_id (str): Unique identifier of the conversation to retrieve.\n\nReturns:\n ConversationResponse: Structured response containing the conversation\n ID and simplified chat history.", "operationId": "get_conversation_endpoint_handler_v1_conversations__conversation_id__get", "parameters": [ { @@ -513,7 +513,7 @@ "conversations" ], "summary": "Delete Conversation Endpoint Handler", - "description": "Handle request to delete a conversation by ID.", + "description": "Handle request to delete a conversation by ID.\n\nValidates the conversation ID format and attempts to delete the\ncorresponding session from the Llama Stack backend. Raises HTTP\nerrors for invalid IDs, not found conversations, connection\nissues, or unexpected failures.\n\nReturns:\n ConversationDeleteResponse: Response indicating the result of the deletion operation.", "operationId": "delete_conversation_endpoint_handler_v1_conversations__conversation_id__delete", "parameters": [ { @@ -756,12 +756,24 @@ "module": { "type": "string", "title": "Module", - "default": "noop" + "description": "Authentication module to be used for REST API", + "default": "noop", + "examples": [ + "noop", + "noop-with-token", + "k8s", + "jwk-token" + ] }, "skip_tls_verification": { "type": "boolean", "title": "Skip Tls Verification", - "default": false + "description": "If set to true, the service skips TLS certificate verification", + "default": false, + "examples": [ + true, + false + ] }, "k8s_cluster_api": { "anyOf": [ @@ -774,7 +786,11 @@ "type": "null" } ], - "title": "K8S Cluster Api" + "title": "K8S Cluster Api", + "description": "The URL of the K8S/OCP API server where tokens are validated", + "examples": [ + "http://localhost:8080/api/validation/" + ] }, "k8s_ca_cert_path": { "anyOf": [ @@ -786,7 +802,11 @@ "type": "null" } ], - "title": "K8S Ca Cert Path" + "title": "K8S Ca Cert Path", + "description": "Path to a CA certificate for clusters with self-signed certificates", + "examples": [ + "/tmp/certs.crt" + ] }, "jwk_config": { "anyOf": [ @@ -796,7 +816,8 @@ { "type": "null" } - ] + ], + "description": "JWK configuration" } }, "type": "object", @@ -807,11 +828,20 @@ "properties": { "user_id": { "type": "string", - "title": "User Id" + "title": "User Id", + "description": "User ID, for example UUID", + "examples": [ + "c5260aec-4d82-4370-9fdf-05cf908b3f16" + ] }, "username": { "type": "string", - "title": "Username" + "title": "Username", + "description": "User name", + "examples": [ + "John Doe", + "Adam Smith" + ] } }, "type": "object", @@ -1140,33 +1170,6 @@ "title": "DatabaseConfiguration", "description": "Database configuration." }, - "DatabaseConfiguration": { - "properties": { - "sqlite": { - "anyOf": [ - { - "$ref": "#/components/schemas/SQLiteDatabaseConfiguration" - }, - { - "type": "null" - } - ] - }, - "postgres": { - "anyOf": [ - { - "$ref": "#/components/schemas/PostgreSQLDatabaseConfiguration" - }, - { - "type": "null" - } - ] - } - }, - "type": "object", - "title": "DatabaseConfiguration", - "description": "Database configuration." - }, "ErrorResponse": { "properties": { "detail": { @@ -2016,7 +2019,11 @@ "type": "null" } ], - "title": "Tls Certificate Path" + "title": "Tls Certificate Path", + "description": "Path to TLS certificate", + "examples": [ + "/etc/certs/certs.pem" + ] }, "tls_key_path": { "anyOf": [ @@ -2028,7 +2035,11 @@ "type": "null" } ], - "title": "Tls Key Path" + "title": "Tls Key Path", + "description": "Path to TLS certificate key", + "examples": [ + "/etc/certs/key.pem" + ] }, "tls_key_password": { "anyOf": [ @@ -2040,10 +2051,19 @@ "type": "null" } ], - "title": "Tls Key Password" + "title": "Tls Key Password", + "description": "Path to file containing TLS key passowrd", + "examples": [ + "/app-root/certs/password.txt" + ] } }, "type": "object", + "required": [ + "tls_certificate_path", + "tls_key_path", + "tls_key_password" + ], "title": "TLSConfiguration", "description": "TLS configuration." }, diff --git a/docs/openapi.md b/docs/openapi.md index 91449971..faee0b48 100644 --- a/docs/openapi.md +++ b/docs/openapi.md @@ -56,6 +56,16 @@ Returns: Handle requests to the /models endpoint. +Process GET requests to the /models endpoint, returning a list of available +models from the Llama Stack service. + +Raises: + HTTPException: If unable to connect to the Llama Stack server or if + model retrieval fails for any reason. + +Returns: + ModelsResponse: An object containing the list of available models. + @@ -138,6 +148,9 @@ Returns: Handle feedback requests. +Processes a user feedback submission, storing the feedback and +returning a confirmation response. + Args: feedback_request: The request containing feedback information. ensure_feedback_enabled: The feedback handler (FastAPI Depends) that @@ -148,6 +161,9 @@ Args: Returns: Response indicating the status of the feedback storage request. +Raises: + HTTPException: Returns HTTP 500 if feedback storage fails. + @@ -171,8 +187,11 @@ Returns: Handle feedback status requests. +Return the current enabled status of the feedback +functionality. + Returns: - Response indicating the status of the feedback. + StatusResponse: Indicates whether feedback collection is enabled. @@ -205,6 +224,20 @@ Handle request to retrieve all conversations for the authenticated user. Handle request to retrieve a conversation by ID. +Retrieve a conversation's chat history by its ID. Then fetches +the conversation session from the Llama Stack backend, +simplifies the session data to essential chat history, and +returns it in a structured response. Raises HTTP 400 for +invalid IDs, 404 if not found, 503 if the backend is +unavailable, and 500 for unexpected errors. + +Parameters: + conversation_id (str): Unique identifier of the conversation to retrieve. + +Returns: + ConversationResponse: Structured response containing the conversation + ID and simplified chat history. + ### 🔗 Parameters @@ -228,6 +261,14 @@ Handle request to retrieve a conversation by ID. Handle request to delete a conversation by ID. +Validates the conversation ID format and attempts to delete the +corresponding session from the Llama Stack backend. Raises HTTP +errors for invalid IDs, not found conversations, connection +issues, or unexpected failures. + +Returns: + ConversationDeleteResponse: Response indicating the result of the deletion operation. + ### 🔗 Parameters @@ -372,11 +413,11 @@ Authentication configuration. | Field | Type | Description | |-------|------|-------------| -| module | string | | -| skip_tls_verification | boolean | | -| k8s_cluster_api | | | -| k8s_ca_cert_path | | | -| jwk_config | | | +| module | string | Authentication module to be used for REST API | +| skip_tls_verification | boolean | If set to true, the service skips TLS certificate verification | +| k8s_cluster_api | | The URL of the K8S/OCP API server where tokens are validated | +| k8s_ca_cert_path | | Path to a CA certificate for clusters with self-signed certificates | +| jwk_config | | JWK configuration | ## AuthorizedResponse @@ -391,8 +432,8 @@ Attributes: | Field | Type | Description | |-------|------|-------------| -| user_id | string | | -| username | string | | +| user_id | string | User ID, for example UUID | +| username | string | User name | ## Configuration @@ -973,9 +1014,9 @@ TLS configuration. | Field | Type | Description | |-------|------|-------------| -| tls_certificate_path | | | -| tls_key_path | | | -| tls_key_password | | | +| tls_certificate_path | | Path to TLS certificate | +| tls_key_path | | Path to TLS certificate key | +| tls_key_password | | Path to file containing TLS key passowrd | ## UnauthorizedResponse diff --git a/docs/output.md b/docs/output.md index c21cbc90..72864609 100644 --- a/docs/output.md +++ b/docs/output.md @@ -56,6 +56,16 @@ Returns: Handle requests to the /models endpoint. +Process GET requests to the /models endpoint, returning a list of available +models from the Llama Stack service. + +Raises: + HTTPException: If unable to connect to the Llama Stack server or if + model retrieval fails for any reason. + +Returns: + ModelsResponse: An object containing the list of available models. + @@ -144,6 +154,9 @@ Returns: Handle feedback requests. +Processes a user feedback submission, storing the feedback and +returning a confirmation response. + Args: feedback_request: The request containing feedback information. ensure_feedback_enabled: The feedback handler (FastAPI Depends) that @@ -154,6 +167,9 @@ Args: Returns: Response indicating the status of the feedback storage request. +Raises: + HTTPException: Returns HTTP 500 if feedback storage fails. + @@ -182,8 +198,11 @@ Returns: Handle feedback status requests. +Return the current enabled status of the feedback +functionality. + Returns: - Response indicating the status of the feedback. + StatusResponse: Indicates whether feedback collection is enabled. @@ -218,6 +237,20 @@ Handle request to retrieve all conversations for the authenticated user. Handle request to retrieve a conversation by ID. +Retrieve a conversation's chat history by its ID. Then fetches +the conversation session from the Llama Stack backend, +simplifies the session data to essential chat history, and +returns it in a structured response. Raises HTTP 400 for +invalid IDs, 404 if not found, 503 if the backend is +unavailable, and 500 for unexpected errors. + +Parameters: + conversation_id (str): Unique identifier of the conversation to retrieve. + +Returns: + ConversationResponse: Structured response containing the conversation + ID and simplified chat history. + ### 🔗 Parameters @@ -243,6 +276,14 @@ Handle request to retrieve a conversation by ID. Handle request to delete a conversation by ID. +Validates the conversation ID format and attempts to delete the +corresponding session from the Llama Stack backend. Raises HTTP +errors for invalid IDs, not found conversations, connection +issues, or unexpected failures. + +Returns: + ConversationDeleteResponse: Response indicating the result of the deletion operation. + ### 🔗 Parameters @@ -396,11 +437,11 @@ Authentication configuration. | Field | Type | Description | |-------|------|-------------| -| module | string | | -| skip_tls_verification | boolean | | -| k8s_cluster_api | | | -| k8s_ca_cert_path | | | -| jwk_config | | | +| module | string | Authentication module to be used for REST API | +| skip_tls_verification | boolean | If set to true, the service skips TLS certificate verification | +| k8s_cluster_api | | The URL of the K8S/OCP API server where tokens are validated | +| k8s_ca_cert_path | | Path to a CA certificate for clusters with self-signed certificates | +| jwk_config | | JWK configuration | ## AuthorizedResponse @@ -415,8 +456,8 @@ Attributes: | Field | Type | Description | |-------|------|-------------| -| user_id | string | | -| username | string | | +| user_id | string | User ID, for example UUID | +| username | string | User name | ## Configuration @@ -580,7 +621,6 @@ Service customization. | system_prompt | | | - ## DatabaseConfiguration @@ -986,9 +1026,9 @@ TLS configuration. | Field | Type | Description | |-------|------|-------------| -| tls_certificate_path | | | -| tls_key_path | | | -| tls_key_password | | | +| tls_certificate_path | | Path to TLS certificate | +| tls_key_path | | Path to TLS certificate key | +| tls_key_password | | Path to file containing TLS key passowrd | ## UnauthorizedResponse diff --git a/src/models/config.py b/src/models/config.py index c03eec30..2d6b3d1e 100644 --- a/src/models/config.py +++ b/src/models/config.py @@ -3,7 +3,13 @@ from pathlib import Path from typing import Optional -from pydantic import BaseModel, model_validator, FilePath, AnyHttpUrl +from pydantic import ( + BaseModel, + model_validator, + FilePath, + AnyHttpUrl, + Field, +) from typing_extensions import Self, Literal import constants @@ -14,9 +20,20 @@ class TLSConfiguration(BaseModel): """TLS configuration.""" - tls_certificate_path: Optional[FilePath] = None - tls_key_path: Optional[FilePath] = None - tls_key_password: Optional[FilePath] = None + tls_certificate_path: Optional[FilePath] = Field( + description="Path to TLS certificate", + examples=["/etc/certs/certs.pem"], + ) + + tls_key_path: Optional[FilePath] = Field( + description="Path to TLS certificate key", + examples=["/etc/certs/key.pem"], + ) + + tls_key_password: Optional[FilePath] = Field( + description="Path to file containing TLS key passowrd", + examples=["/app-root/certs/password.txt"], + ) @model_validator(mode="after") def check_tls_configuration(self) -> Self: @@ -105,7 +122,11 @@ class ServiceConfiguration(BaseModel): workers: int = 1 color_log: bool = True access_log: bool = True - tls_config: TLSConfiguration = TLSConfiguration() + tls_config: TLSConfiguration = Field( + default=TLSConfiguration( + tls_certificate_path=None, tls_key_path=None, tls_key_password=None + ) + ) @model_validator(mode="after") def check_service_configuration(self) -> Self: @@ -210,11 +231,34 @@ class JwkConfiguration(BaseModel): class AuthenticationConfiguration(BaseModel): """Authentication configuration.""" - module: str = constants.DEFAULT_AUTHENTICATION_MODULE - skip_tls_verification: bool = False - k8s_cluster_api: Optional[AnyHttpUrl] = None - k8s_ca_cert_path: Optional[FilePath] = None - jwk_config: Optional[JwkConfiguration] = None + module: str = Field( + constants.DEFAULT_AUTHENTICATION_MODULE, + description="Authentication module to be used for REST API", + examples=["noop", "noop-with-token", "k8s", "jwk-token"], + ) + + skip_tls_verification: bool = Field( + False, + description="If set to true, the service skips TLS certificate verification", + examples=[True, False], + ) + + k8s_cluster_api: Optional[AnyHttpUrl] = Field( + None, + description="The URL of the K8S/OCP API server where tokens are validated", + examples=["http://localhost:8080/api/validation/"], + ) + + k8s_ca_cert_path: Optional[FilePath] = Field( + None, + description="Path to a CA certificate for clusters with self-signed certificates", + examples=["/tmp/certs.crt"], + ) + + jwk_config: Optional[JwkConfiguration] = Field( + None, + description="JWK configuration", + ) @model_validator(mode="after") def check_authentication_model(self) -> Self: @@ -292,8 +336,14 @@ class Configuration(BaseModel): user_data_collection: UserDataCollection database: DatabaseConfiguration = DatabaseConfiguration() mcp_servers: list[ModelContextProtocolServer] = [] - authentication: Optional[AuthenticationConfiguration] = ( - AuthenticationConfiguration() + authentication: Optional[AuthenticationConfiguration] = Field( + default=AuthenticationConfiguration( + module=constants.DEFAULT_AUTHENTICATION_MODULE, + skip_tls_verification=False, + k8s_cluster_api=None, + k8s_ca_cert_path=None, + jwk_config=None, + ), ) customization: Optional[Customization] = None inference: InferenceConfiguration = InferenceConfiguration() diff --git a/src/models/responses.py b/src/models/responses.py index c5a319d2..5d037a77 100644 --- a/src/models/responses.py +++ b/src/models/responses.py @@ -2,7 +2,7 @@ from typing import Any, Optional -from pydantic import BaseModel +from pydantic import BaseModel, Field class ModelsResponse(BaseModel): @@ -252,8 +252,16 @@ class AuthorizedResponse(BaseModel): username: The name of the logged in user. """ - user_id: str - username: str + user_id: str = Field( + ..., + description="User ID, for example UUID", + examples=["c5260aec-4d82-4370-9fdf-05cf908b3f16"], + ) + username: str = Field( + ..., + description="User name", + examples=["John Doe", "Adam Smith"], + ) # provides examples for /docs endpoint model_config = { diff --git a/tests/unit/models/test_config.py b/tests/unit/models/test_config.py index acdd9493..f8f16eee 100644 --- a/tests/unit/models/test_config.py +++ b/tests/unit/models/test_config.py @@ -42,7 +42,9 @@ def test_service_configuration_constructor() -> None: assert s.workers == 1 assert s.color_log is True assert s.access_log is True - assert s.tls_config == TLSConfiguration() + assert s.tls_config == TLSConfiguration( + tls_certificate_path=None, tls_key_path=None, tls_key_password=None + ) def test_service_configuration_port_value() -> None: @@ -227,6 +229,22 @@ def test_tls_configuration() -> None: assert cfg.tls_key_password == Path("tests/configuration/password") +def test_tls_configuration_in_service_configuration() -> None: + """Test the TLS configuration in service configuration.""" + cfg = ServiceConfiguration( + tls_config=TLSConfiguration( + tls_certificate_path=Path("tests/configuration/server.crt"), + tls_key_path=Path("tests/configuration/server.key"), + tls_key_password=Path("tests/configuration/password"), + ) + ) + assert cfg is not None + assert cfg.tls_config is not None + assert cfg.tls_config.tls_certificate_path == Path("tests/configuration/server.crt") + assert cfg.tls_config.tls_key_path == Path("tests/configuration/server.key") + assert cfg.tls_config.tls_key_password == Path("tests/configuration/password") + + def test_tls_configuration_wrong_certificate_path() -> None: """Test the TLS configuration loading when some path is broken.""" with pytest.raises(ValueError, match="Path does not point to a file"): @@ -416,7 +434,13 @@ def test_dump_configuration(tmp_path) -> None: """ cfg = Configuration( name="test_name", - service=ServiceConfiguration(), + service=ServiceConfiguration( + tls_config=TLSConfiguration( + tls_certificate_path=Path("tests/configuration/server.crt"), + tls_key_path=Path("tests/configuration/server.key"), + tls_key_password=Path("tests/configuration/password"), + ) + ), llama_stack=LlamaStackConfiguration( use_as_library_client=True, library_client_config_path="tests/configuration/run.yaml", @@ -462,9 +486,9 @@ def test_dump_configuration(tmp_path) -> None: "color_log": True, "access_log": True, "tls_config": { - "tls_certificate_path": None, - "tls_key_path": None, - "tls_key_password": None, + "tls_certificate_path": "tests/configuration/server.crt", + "tls_key_password": "tests/configuration/password", + "tls_key_path": "tests/configuration/server.key", }, }, "llama_stack": { diff --git a/tests/unit/runners/test_uvicorn_runner.py b/tests/unit/runners/test_uvicorn_runner.py index 1568fed7..4cf0881e 100644 --- a/tests/unit/runners/test_uvicorn_runner.py +++ b/tests/unit/runners/test_uvicorn_runner.py @@ -52,7 +52,9 @@ def test_start_uvicorn_different_host_port() -> None: def test_start_uvicorn_empty_tls_configuration() -> None: """Test the function to start Uvicorn server using empty TLS configuration.""" - tls_config = TLSConfiguration() + tls_config = TLSConfiguration( + tls_certificate_path=None, tls_key_path=None, tls_key_password=None + ) configuration = ServiceConfiguration( host="x.y.com", port=1234, workers=10, tls_config=tls_config )