diff --git a/api/controllers/openapi/_models.py b/api/controllers/openapi/_models.py index 7304c83044..fb9ad080f0 100644 --- a/api/controllers/openapi/_models.py +++ b/api/controllers/openapi/_models.py @@ -4,7 +4,7 @@ from __future__ import annotations from typing import Any -from pydantic import BaseModel +from pydantic import BaseModel, Field # Server-side cap on `limit` query param for any /openapi/v1/* list endpoint. # Sibling endpoints (`/apps`, `/account/sessions`, future routes) all clamp to @@ -67,3 +67,46 @@ class AppDescribeResponse(BaseModel): info: AppDescribeInfo | None = None parameters: dict[str, Any] | None = None input_schema: dict[str, Any] | None = None + + +class ChatMessageResponse(BaseModel): + event: str + task_id: str + id: str + message_id: str + conversation_id: str + mode: str + answer: str + metadata: MessageMetadata = Field(default_factory=MessageMetadata) + created_at: int + + +class CompletionMessageResponse(BaseModel): + event: str + task_id: str + id: str + message_id: str + mode: str + answer: str + metadata: MessageMetadata = Field(default_factory=MessageMetadata) + created_at: int + + +class WorkflowRunData(BaseModel): + id: str + workflow_id: str + status: str + outputs: dict[str, Any] = {} + error: str | None = None + elapsed_time: float | None = None + total_tokens: int | None = None + total_steps: int | None = None + created_at: int | None = None + finished_at: int | None = None + + +class WorkflowRunResponse(BaseModel): + workflow_run_id: str + task_id: str + mode: str = "workflow" # echoed for CLI per-mode rendering — see endpoints.md L154 + data: WorkflowRunData diff --git a/api/tests/unit_tests/controllers/openapi/test_pagination_envelope.py b/api/tests/unit_tests/controllers/openapi/test_pagination_envelope.py index a765e86241..f75d0f39bd 100644 --- a/api/tests/unit_tests/controllers/openapi/test_pagination_envelope.py +++ b/api/tests/unit_tests/controllers/openapi/test_pagination_envelope.py @@ -100,3 +100,19 @@ def test_app_describe_response_nests_info_and_parameters(): dumped = obj.model_dump(mode="json") assert dumped["info"]["service_api_enabled"] is True assert dumped["parameters"]["opening_statement"] is None + + +def test_response_models_dump_per_mode(): + from controllers.openapi._models import ( + ChatMessageResponse, CompletionMessageResponse, WorkflowRunResponse, WorkflowRunData, + ) + chat = ChatMessageResponse( + event="message", task_id="t1", id="m1", message_id="m1", + conversation_id="c1", mode="chat", answer="hi", created_at=0, + ) + assert chat.model_dump(mode="json")["mode"] == "chat" + wf = WorkflowRunResponse( + workflow_run_id="r1", task_id="t1", + data=WorkflowRunData(id="r1", workflow_id="w1", status="succeeded"), + ) + assert wf.model_dump(mode="json")["data"]["status"] == "succeeded"