diff --git a/docs/openapi.json b/docs/openapi.json index 09bd0771..dc7dfbb6 100644 --- a/docs/openapi.json +++ b/docs/openapi.json @@ -50,7 +50,7 @@ "info" ], "summary": "Info Endpoint Handler", - "description": "Handle request to the /info endpoint.\n\nProcess GET requests to the /info endpoint, returning the\nservice name and version.\n\nReturns:\n InfoResponse: An object containing the service's name and version.", + "description": "Handle request to the /info endpoint.\n\nProcess GET requests to the /info endpoint, returning the\nservice name, version and Llama-stack version.\n\nReturns:\n InfoResponse: An object containing the service's name and version.", "operationId": "info_endpoint_handler_v1_info_get", "responses": { "200": { @@ -117,7 +117,7 @@ } ] }, - "503": { + "500": { "description": "Connection to Llama Stack is broken" } } @@ -174,8 +174,8 @@ } } }, - "503": { - "description": "Service Unavailable", + "500": { + "description": "Internal Server Error", "detail": { "response": "Unable to connect to Llama Stack", "cause": "Connection error." @@ -214,13 +214,56 @@ }, "responses": { "200": { - "description": "Successful Response", + "description": "Streaming response with Server-Sent Events", "content": { "application/json": { "schema": {} + }, + "text/event-stream": { + "schema": { + "type": "string", + "example": "data: {\"event\": \"start\", \"data\": {\"conversation_id\": \"123e4567-e89b-12d3-a456-426614174000\"}}\n\ndata: {\"event\": \"token\", \"data\": {\"id\": 0, \"role\": \"inference\", \"token\": \"Hello\"}}\n\ndata: {\"event\": \"end\", \"data\": {\"referenced_documents\": [], \"truncated\": null, \"input_tokens\": 0, \"output_tokens\": 0}, \"available_quotas\": {}}\n\n" + } + } + } + }, + "400": { + "description": "Missing or invalid credentials provided by client", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedResponse" + } + } + } + }, + "401": { + "description": "Unauthorized: Invalid or missing Bearer token for k8s auth", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedResponse" + } + } + } + }, + "403": { + "description": "User is not authorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ForbiddenResponse" + } } } }, + "500": { + "description": "Internal Server Error", + "detail": { + "response": "Unable to connect to Llama Stack", + "cause": "Connection error." + } + }, "422": { "description": "Validation Error", "content": { @@ -473,6 +516,26 @@ } ] }, + "400": { + "description": "Missing or invalid credentials provided by client", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedResponse" + } + } + } + }, + "401": { + "description": "Unauthorized: Invalid or missing Bearer token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedResponse" + } + } + } + }, "503": { "description": "Service Unavailable", "detail": { @@ -530,6 +593,26 @@ } ] }, + "400": { + "description": "Missing or invalid credentials provided by client", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedResponse" + } + } + } + }, + "401": { + "description": "Unauthorized: Invalid or missing Bearer token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedResponse" + } + } + } + }, "404": { "detail": { "response": "Conversation not found", @@ -588,6 +671,26 @@ "success": true, "message": "Conversation deleted successfully" }, + "400": { + "description": "Missing or invalid credentials provided by client", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedResponse" + } + } + } + }, + "401": { + "description": "Unauthorized: Invalid or missing Bearer token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedResponse" + } + } + } + }, "404": { "detail": { "response": "Conversation not found", diff --git a/docs/openapi.md b/docs/openapi.md index 12295667..6ef13f8d 100644 --- a/docs/openapi.md +++ b/docs/openapi.md @@ -34,7 +34,7 @@ Handle request to the / endpoint. Handle request to the /info endpoint. Process GET requests to the /info endpoint, returning the -service name and version. +service name, version and Llama-stack version. Returns: InfoResponse: An object containing the service's name and version. @@ -74,7 +74,7 @@ Returns: | Status Code | Description | Component | |-------------|-------------|-----------| | 200 | Successful Response | [ModelsResponse](#modelsresponse) | -| 503 | Connection to Llama Stack is broken | | +| 500 | Connection to Llama Stack is broken | | ## POST `/v1/query` > **Query Endpoint Handler** @@ -108,7 +108,7 @@ Returns: | 200 | Successful Response | [QueryResponse](#queryresponse) | | 400 | Missing or invalid credentials provided by client | [UnauthorizedResponse](#unauthorizedresponse) | | 403 | User is not authorized | [ForbiddenResponse](#forbiddenresponse) | -| 503 | Service Unavailable | | +| 500 | Internal Server Error | | | 422 | Validation Error | [HTTPValidationError](#httpvalidationerror) | ## POST `/v1/streaming_query` @@ -143,7 +143,11 @@ Raises: | Status Code | Description | Component | |-------------|-------------|-----------| -| 200 | Successful Response | ... | +| 200 | Streaming response with Server-Sent Events | ...string | +| 400 | Missing or invalid credentials provided by client | [UnauthorizedResponse](#unauthorizedresponse) | +| 401 | Unauthorized: Invalid or missing Bearer token for k8s auth | [UnauthorizedResponse](#unauthorizedresponse) | +| 403 | User is not authorized | [ForbiddenResponse](#forbiddenresponse) | +| 500 | Internal Server Error | | | 422 | Validation Error | [HTTPValidationError](#httpvalidationerror) | ## GET `/v1/config` @@ -269,6 +273,8 @@ Handle request to retrieve all conversations for the authenticated user. | Status Code | Description | Component | |-------------|-------------|-----------| | 200 | Successful Response | [ConversationsListResponse](#conversationslistresponse) | +| 400 | Missing or invalid credentials provided by client | [UnauthorizedResponse](#unauthorizedresponse) | +| 401 | Unauthorized: Invalid or missing Bearer token | [UnauthorizedResponse](#unauthorizedresponse) | | 503 | Service Unavailable | | ## GET `/v1/conversations/{conversation_id}` @@ -304,6 +310,8 @@ Returns: | Status Code | Description | Component | |-------------|-------------|-----------| | 200 | Successful Response | [ConversationResponse](#conversationresponse) | +| 400 | Missing or invalid credentials provided by client | [UnauthorizedResponse](#unauthorizedresponse) | +| 401 | Unauthorized: Invalid or missing Bearer token | [UnauthorizedResponse](#unauthorizedresponse) | | 404 | Not Found | | | 503 | Service Unavailable | | | 422 | Validation Error | [HTTPValidationError](#httpvalidationerror) | @@ -335,6 +343,8 @@ Returns: | Status Code | Description | Component | |-------------|-------------|-----------| | 200 | Successful Response | [ConversationDeleteResponse](#conversationdeleteresponse) | +| 400 | Missing or invalid credentials provided by client | [UnauthorizedResponse](#unauthorizedresponse) | +| 401 | Unauthorized: Invalid or missing Bearer token | [UnauthorizedResponse](#unauthorizedresponse) | | 404 | Not Found | | | 503 | Service Unavailable | | | 422 | Validation Error | [HTTPValidationError](#httpvalidationerror) | @@ -769,15 +779,6 @@ Example: user_question="what are you doing?", user_feedback="This response is not helpful", llm_response="I don't know", - sentiment=1 - ) - - # Feedback with categories - feedback_request = FeedbackRequest( - conversation_id="12345678-abcd-0000-0123-456789abcdef", - user_question="How do I deploy a web app?", - llm_response="You need to use Docker and Kubernetes for everything.", - user_feedback="This response is too general and doesn't provide specific steps.", sentiment=-1, categories=[FeedbackCategory.INCORRECT, FeedbackCategory.INCOMPLETE] ) diff --git a/docs/output.md b/docs/output.md index 7ae0d544..6ef13f8d 100644 --- a/docs/output.md +++ b/docs/output.md @@ -34,7 +34,7 @@ Handle request to the / endpoint. Handle request to the /info endpoint. Process GET requests to the /info endpoint, returning the -service name and version. +service name, version and Llama-stack version. Returns: InfoResponse: An object containing the service's name and version. @@ -74,7 +74,7 @@ Returns: | Status Code | Description | Component | |-------------|-------------|-----------| | 200 | Successful Response | [ModelsResponse](#modelsresponse) | -| 503 | Connection to Llama Stack is broken | | +| 500 | Connection to Llama Stack is broken | | ## POST `/v1/query` > **Query Endpoint Handler** @@ -108,7 +108,7 @@ Returns: | 200 | Successful Response | [QueryResponse](#queryresponse) | | 400 | Missing or invalid credentials provided by client | [UnauthorizedResponse](#unauthorizedresponse) | | 403 | User is not authorized | [ForbiddenResponse](#forbiddenresponse) | -| 503 | Service Unavailable | | +| 500 | Internal Server Error | | | 422 | Validation Error | [HTTPValidationError](#httpvalidationerror) | ## POST `/v1/streaming_query` @@ -143,7 +143,11 @@ Raises: | Status Code | Description | Component | |-------------|-------------|-----------| -| 200 | Successful Response | ... | +| 200 | Streaming response with Server-Sent Events | ...string | +| 400 | Missing or invalid credentials provided by client | [UnauthorizedResponse](#unauthorizedresponse) | +| 401 | Unauthorized: Invalid or missing Bearer token for k8s auth | [UnauthorizedResponse](#unauthorizedresponse) | +| 403 | User is not authorized | [ForbiddenResponse](#forbiddenresponse) | +| 500 | Internal Server Error | | | 422 | Validation Error | [HTTPValidationError](#httpvalidationerror) | ## GET `/v1/config` @@ -269,6 +273,8 @@ Handle request to retrieve all conversations for the authenticated user. | Status Code | Description | Component | |-------------|-------------|-----------| | 200 | Successful Response | [ConversationsListResponse](#conversationslistresponse) | +| 400 | Missing or invalid credentials provided by client | [UnauthorizedResponse](#unauthorizedresponse) | +| 401 | Unauthorized: Invalid or missing Bearer token | [UnauthorizedResponse](#unauthorizedresponse) | | 503 | Service Unavailable | | ## GET `/v1/conversations/{conversation_id}` @@ -304,6 +310,8 @@ Returns: | Status Code | Description | Component | |-------------|-------------|-----------| | 200 | Successful Response | [ConversationResponse](#conversationresponse) | +| 400 | Missing or invalid credentials provided by client | [UnauthorizedResponse](#unauthorizedresponse) | +| 401 | Unauthorized: Invalid or missing Bearer token | [UnauthorizedResponse](#unauthorizedresponse) | | 404 | Not Found | | | 503 | Service Unavailable | | | 422 | Validation Error | [HTTPValidationError](#httpvalidationerror) | @@ -335,6 +343,8 @@ Returns: | Status Code | Description | Component | |-------------|-------------|-----------| | 200 | Successful Response | [ConversationDeleteResponse](#conversationdeleteresponse) | +| 400 | Missing or invalid credentials provided by client | [UnauthorizedResponse](#unauthorizedresponse) | +| 401 | Unauthorized: Invalid or missing Bearer token | [UnauthorizedResponse](#unauthorizedresponse) | | 404 | Not Found | | | 503 | Service Unavailable | | | 422 | Validation Error | [HTTPValidationError](#httpvalidationerror) | diff --git a/src/app/endpoints/conversations.py b/src/app/endpoints/conversations.py index 68f3e485..bfb95129 100644 --- a/src/app/endpoints/conversations.py +++ b/src/app/endpoints/conversations.py @@ -19,6 +19,7 @@ ConversationDeleteResponse, ConversationsListResponse, ConversationDetails, + UnauthorizedResponse, ) from utils.endpoints import ( check_configuration_loaded, @@ -45,6 +46,14 @@ } ], }, + 400: { + "description": "Missing or invalid credentials provided by client", + "model": UnauthorizedResponse, + }, + 401: { + "description": "Unauthorized: Invalid or missing Bearer token", + "model": UnauthorizedResponse, + }, 404: { "detail": { "response": "Conversation not found", @@ -65,6 +74,14 @@ "success": True, "message": "Conversation deleted successfully", }, + 400: { + "description": "Missing or invalid credentials provided by client", + "model": UnauthorizedResponse, + }, + 401: { + "description": "Unauthorized: Invalid or missing Bearer token", + "model": UnauthorizedResponse, + }, 404: { "detail": { "response": "Conversation not found", @@ -100,6 +117,14 @@ }, ] }, + 400: { + "description": "Missing or invalid credentials provided by client", + "model": UnauthorizedResponse, + }, + 401: { + "description": "Unauthorized: Invalid or missing Bearer token", + "model": UnauthorizedResponse, + }, 503: { "detail": { "response": "Unable to connect to Llama Stack", diff --git a/src/app/endpoints/info.py b/src/app/endpoints/info.py index 18e7107a..dfcb6202 100644 --- a/src/app/endpoints/info.py +++ b/src/app/endpoints/info.py @@ -47,7 +47,7 @@ async def info_endpoint_handler( Handle request to the /info endpoint. Process GET requests to the /info endpoint, returning the - service name and version. + service name, version and Llama-stack version. Returns: InfoResponse: An object containing the service's name and version. diff --git a/src/app/endpoints/models.py b/src/app/endpoints/models.py index e6059745..afecf343 100644 --- a/src/app/endpoints/models.py +++ b/src/app/endpoints/models.py @@ -46,7 +46,7 @@ }, ] }, - 503: {"description": "Connection to Llama Stack is broken"}, + 500: {"description": "Connection to Llama Stack is broken"}, } diff --git a/src/app/endpoints/query.py b/src/app/endpoints/query.py index 43c3eb60..bbf14591 100644 --- a/src/app/endpoints/query.py +++ b/src/app/endpoints/query.py @@ -59,7 +59,7 @@ "description": "User is not authorized", "model": ForbiddenResponse, }, - 503: { + 500: { "detail": { "response": "Unable to connect to Llama Stack", "cause": "Connection error.", diff --git a/src/app/endpoints/streaming_query.py b/src/app/endpoints/streaming_query.py index 60d9d4d6..3775995a 100644 --- a/src/app/endpoints/streaming_query.py +++ b/src/app/endpoints/streaming_query.py @@ -29,6 +29,7 @@ from metrics.utils import update_llm_token_count_from_turn from models.config import Action from models.requests import QueryRequest +from models.responses import UnauthorizedResponse, ForbiddenResponse from models.database.conversations import UserConversation from utils.endpoints import check_configuration_loaded, get_agent, get_system_prompt from utils.mcp_headers import mcp_headers_dependency, handle_mcp_headers_with_toolgroups @@ -52,6 +53,46 @@ router = APIRouter(tags=["streaming_query"]) auth_dependency = get_auth_dependency() +streaming_query_responses: dict[int | str, dict[str, Any]] = { + 200: { + "description": "Streaming response with Server-Sent Events", + "content": { + "text/event-stream": { + "schema": { + "type": "string", + "example": ( + 'data: {"event": "start", ' + '"data": {"conversation_id": "123e4567-e89b-12d3-a456-426614174000"}}\n\n' + 'data: {"event": "token", "data": {"id": 0, "role": "inference", ' + '"token": "Hello"}}\n\n' + 'data: {"event": "end", "data": {"referenced_documents": [], ' + '"truncated": null, "input_tokens": 0, "output_tokens": 0}, ' + '"available_quotas": {}}\n\n' + ), + } + } + }, + }, + 400: { + "description": "Missing or invalid credentials provided by client", + "model": UnauthorizedResponse, + }, + 401: { + "description": "Unauthorized: Invalid or missing Bearer token for k8s auth", + "model": UnauthorizedResponse, + }, + 403: { + "description": "User is not authorized", + "model": ForbiddenResponse, + }, + 500: { + "detail": { + "response": "Unable to connect to Llama Stack", + "cause": "Connection error.", + } + }, +} + METADATA_PATTERN = re.compile(r"\nMetadata: (\{.+})\n") @@ -519,7 +560,7 @@ def _handle_heartbeat_event(chunk_id: int) -> Iterator[str]: ) -@router.post("/streaming_query") +@router.post("/streaming_query", responses=streaming_query_responses) @authorize(Action.STREAMING_QUERY) async def streaming_query_endpoint_handler( # pylint: disable=too-many-locals request: Request, diff --git a/tests/integration/test_openapi_json.py b/tests/integration/test_openapi_json.py index 15e7d87c..1b5c6932 100644 --- a/tests/integration/test_openapi_json.py +++ b/tests/integration/test_openapi_json.py @@ -59,16 +59,24 @@ def test_servers_section_present(spec: dict): [ ("/", "get", {"200"}), ("/v1/info", "get", {"200", "500"}), - ("/v1/models", "get", {"200", "503"}), - ("/v1/query", "post", {"200", "400", "403", "503", "422"}), + ("/v1/models", "get", {"200", "500"}), + ("/v1/query", "post", {"200", "400", "403", "500", "422"}), ("/v1/streaming_query", "post", {"200", "422"}), ("/v1/config", "get", {"200", "503"}), ("/v1/feedback", "post", {"200", "401", "403", "500", "422"}), ("/v1/feedback/status", "get", {"200"}), ("/v1/feedback/status", "put", {"200", "422"}), - ("/v1/conversations", "get", {"200", "503"}), - ("/v1/conversations/{conversation_id}", "get", {"200", "404", "503", "422"}), - ("/v1/conversations/{conversation_id}", "delete", {"200", "404", "503", "422"}), + ("/v1/conversations", "get", {"200", "400", "401", "503"}), + ( + "/v1/conversations/{conversation_id}", + "get", + {"200", "400", "401", "404", "503", "422"}, + ), + ( + "/v1/conversations/{conversation_id}", + "delete", + {"200", "400", "401", "404", "503", "422"}, + ), ("/readiness", "get", {"200", "503"}), ("/liveness", "get", {"200"}), ("/authorized", "post", {"200", "400", "401", "403"}),