From ac8d5aee027f7c1bd4f14a082213181fd6f1b1ab Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 10 Apr 2026 15:07:05 +0000 Subject: [PATCH] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- studio/backend/models/inference.py | 8 +++++ studio/backend/routes/inference.py | 40 +++++++++++++++------- studio/backend/tests/test_responses_api.py | 22 ++++++++---- 3 files changed, 51 insertions(+), 19 deletions(-) diff --git a/studio/backend/models/inference.py b/studio/backend/models/inference.py index 983b674453..6fcbe0cdbc 100644 --- a/studio/backend/models/inference.py +++ b/studio/backend/models/inference.py @@ -456,12 +456,14 @@ class ChatCompletion(BaseModel): class ResponsesInputTextPart(BaseModel): """Text content part in a Responses API message (type=input_text).""" + type: Literal["input_text"] text: str class ResponsesInputImagePart(BaseModel): """Image content part in a Responses API message (type=input_image).""" + type: Literal["input_image"] image_url: str = Field(..., description = "data:image/png;base64,... or https://...") detail: Optional[Literal["auto", "low", "high"]] = "auto" @@ -472,12 +474,14 @@ ResponsesContentPart = Union[ResponsesInputTextPart, ResponsesInputImagePart] class ResponsesInputMessage(BaseModel): """A single message in the Responses API input array.""" + role: Literal["system", "user", "assistant", "developer"] content: Union[str, list[ResponsesContentPart]] class ResponsesRequest(BaseModel): """OpenAI Responses API request.""" + model: str = Field("default", description = "Model identifier") input: Union[str, list[ResponsesInputMessage]] = Field( default = [], @@ -510,6 +514,7 @@ class ResponsesRequest(BaseModel): class ResponsesOutputTextContent(BaseModel): """A text content block inside an output message.""" + type: Literal["output_text"] = "output_text" text: str annotations: list = Field(default_factory = list) @@ -517,6 +522,7 @@ class ResponsesOutputTextContent(BaseModel): class ResponsesOutputMessage(BaseModel): """An output message in the Responses API response.""" + type: Literal["message"] = "message" id: str = Field(default_factory = lambda: f"msg_{uuid.uuid4().hex[:12]}") status: Literal["completed", "in_progress"] = "completed" @@ -526,6 +532,7 @@ class ResponsesOutputMessage(BaseModel): class ResponsesUsage(BaseModel): """Token usage for a Responses API response (input_tokens, not prompt_tokens).""" + input_tokens: int = 0 output_tokens: int = 0 total_tokens: int = 0 @@ -533,6 +540,7 @@ class ResponsesUsage(BaseModel): class ResponsesResponse(BaseModel): """Top-level Responses API response object.""" + id: str = Field(default_factory = lambda: f"resp_{uuid.uuid4().hex[:12]}") object: Literal["response"] = "response" created_at: int = Field(default_factory = lambda: int(time.time())) diff --git a/studio/backend/routes/inference.py b/studio/backend/routes/inference.py index 393c9d8289..b5d52bd50a 100644 --- a/studio/backend/routes/inference.py +++ b/studio/backend/routes/inference.py @@ -1953,16 +1953,20 @@ def _normalise_responses_input(payload: ResponsesRequest) -> list[ChatMessage]: if isinstance(part, ResponsesInputTextPart): parts.append(TextContentPart(type = "text", text = part.text)) elif isinstance(part, ResponsesInputImagePart): - parts.append(ImageContentPart( - type = "image_url", - image_url = ImageUrl(url = part.image_url, detail = part.detail), - )) + parts.append( + ImageContentPart( + type = "image_url", + image_url = ImageUrl(url = part.image_url, detail = part.detail), + ) + ) messages.append(ChatMessage(role = role, content = parts if parts else "")) return messages -def _build_chat_request(payload: ResponsesRequest, messages: list[ChatMessage], stream: bool) -> ChatCompletionRequest: +def _build_chat_request( + payload: ResponsesRequest, messages: list[ChatMessage], stream: bool +) -> ChatCompletionRequest: """Build a ChatCompletionRequest from a ResponsesRequest.""" chat_kwargs = dict( model = payload.model, @@ -2097,7 +2101,9 @@ async def _responses_stream( usage = chunk_data.get("usage") if usage: input_tokens = usage.get("prompt_tokens", input_tokens) - output_tokens = usage.get("completion_tokens", output_tokens) + output_tokens = usage.get( + "completion_tokens", output_tokens + ) continue delta = choices[0].get("delta", {}) @@ -2139,13 +2145,21 @@ async def _responses_stream( "created_at": created_at, "status": "completed", "model": payload.model, - "output": [{ - "type": "message", - "id": msg_id, - "status": "completed", - "role": "assistant", - "content": [{"type": "output_text", "text": full_text, "annotations": []}], - }], + "output": [ + { + "type": "message", + "id": msg_id, + "status": "completed", + "role": "assistant", + "content": [ + { + "type": "output_text", + "text": full_text, + "annotations": [], + } + ], + } + ], "usage": { "input_tokens": input_tokens, "output_tokens": output_tokens, diff --git a/studio/backend/tests/test_responses_api.py b/studio/backend/tests/test_responses_api.py index 1905e58de2..5b55f87259 100644 --- a/studio/backend/tests/test_responses_api.py +++ b/studio/backend/tests/test_responses_api.py @@ -38,6 +38,7 @@ from models.inference import ( # pulls in heavy dependencies (structlog/twisted/torch). This is a # direct copy of the function for testing purposes. + def _normalise_responses_input(payload: ResponsesRequest) -> list: """Convert a ResponsesRequest into a list of ChatMessage for the completions backend.""" messages = [] @@ -65,10 +66,12 @@ def _normalise_responses_input(payload: ResponsesRequest) -> list: if isinstance(part, ResponsesInputTextPart): parts.append(TextContentPart(type = "text", text = part.text)) elif isinstance(part, ResponsesInputImagePart): - parts.append(ImageContentPart( - type = "image_url", - image_url = ImageUrl(url = part.image_url, detail = part.detail), - )) + parts.append( + ImageContentPart( + type = "image_url", + image_url = ImageUrl(url = part.image_url, detail = part.detail), + ) + ) messages.append(ChatMessage(role = role, content = parts if parts else "")) return messages @@ -106,7 +109,10 @@ class TestResponsesRequest: "role": "user", "content": [ {"type": "input_text", "text": "What is in this image?"}, - {"type": "input_image", "image_url": "https://example.com/img.png"}, + { + "type": "input_image", + "image_url": "https://example.com/img.png", + }, ], }, ], @@ -270,7 +276,10 @@ class TestNormaliseResponsesInput: "role": "user", "content": [ {"type": "input_text", "text": "Describe this:"}, - {"type": "input_image", "image_url": "data:image/png;base64,abc"}, + { + "type": "input_image", + "image_url": "data:image/png;base64,abc", + }, ], }, ], @@ -315,4 +324,5 @@ class TestNormaliseResponsesInput: if __name__ == "__main__": import pytest + pytest.main([__file__, "-v"])