diff --git a/api/controllers/console/app/workflow_app_log.py b/api/controllers/console/app/workflow_app_log.py index 6b402898e8..c9bf48103b 100644 --- a/api/controllers/console/app/workflow_app_log.py +++ b/api/controllers/console/app/workflow_app_log.py @@ -104,10 +104,28 @@ class WorkflowRunForArchivedLogResponse(ResponseModel): return str(getattr(value, "value", value)) +class WorkflowAppLogEvaluationNodeInfoResponse(ResponseModel): + node_id: str + type: str + title: str + + +class WorkflowAppLogEvaluationItemResponse(ResponseModel): + name: str + value: Any = None + details: dict[str, Any] | None = None + node_info: WorkflowAppLogEvaluationNodeInfoResponse | None = Field( + default=None, + validation_alias="node_info", + serialization_alias="nodeInfo", + ) + + class WorkflowAppLogPartialResponse(ResponseModel): id: str workflow_run: WorkflowRunForLogResponse | None = None details: Any = None + evaluation: list[WorkflowAppLogEvaluationItemResponse] = Field(default_factory=list) created_from: str | None = None created_by_role: str | None = None created_by_account: SimpleAccount | None = None @@ -159,6 +177,8 @@ register_schema_models( WorkflowAppLogQuery, WorkflowRunForLogResponse, WorkflowRunForArchivedLogResponse, + WorkflowAppLogEvaluationNodeInfoResponse, + WorkflowAppLogEvaluationItemResponse, WorkflowAppLogPartialResponse, WorkflowArchivedLogPartialResponse, WorkflowAppLogPaginationResponse, diff --git a/api/controllers/service_api/app/workflow.py b/api/controllers/service_api/app/workflow.py index cc763fa89c..f489bb1f4a 100644 --- a/api/controllers/service_api/app/workflow.py +++ b/api/controllers/service_api/app/workflow.py @@ -1,7 +1,7 @@ import logging from collections.abc import Mapping from datetime import datetime -from typing import Literal +from typing import Any, Literal from dateutil.parser import isoparse from flask import request @@ -136,10 +136,28 @@ class WorkflowRunForLogResponse(ResponseModel): return _to_timestamp(value) +class WorkflowAppLogEvaluationNodeInfoResponse(ResponseModel): + node_id: str + type: str + title: str + + +class WorkflowAppLogEvaluationItemResponse(ResponseModel): + name: str + value: Any = None + details: dict[str, Any] | None = None + node_info: WorkflowAppLogEvaluationNodeInfoResponse | None = Field( + default=None, + validation_alias="node_info", + serialization_alias="nodeInfo", + ) + + class WorkflowAppLogPartialResponse(ResponseModel): id: str workflow_run: WorkflowRunForLogResponse | None = None details: dict | list | str | int | float | bool | None = None + evaluation: list[WorkflowAppLogEvaluationItemResponse] = Field(default_factory=list) created_from: str | None = None created_by_role: str | None = None created_by_account: SimpleAccount | None = None @@ -169,6 +187,8 @@ register_schema_models( service_api_ns, WorkflowRunResponse, WorkflowRunForLogResponse, + WorkflowAppLogEvaluationNodeInfoResponse, + WorkflowAppLogEvaluationItemResponse, WorkflowAppLogPartialResponse, WorkflowAppLogPaginationResponse, ) diff --git a/api/fields/workflow_app_log_fields.py b/api/fields/workflow_app_log_fields.py index 7d45bc977d..689e3c30c6 100644 --- a/api/fields/workflow_app_log_fields.py +++ b/api/fields/workflow_app_log_fields.py @@ -4,7 +4,7 @@ from datetime import datetime from typing import Any from flask_restx import Namespace, fields -from pydantic import field_validator +from pydantic import Field, field_validator from fields.base import ResponseModel from fields.end_user_fields import SimpleEndUser, simple_end_user_fields @@ -103,10 +103,28 @@ def _to_timestamp(value: datetime | int | None) -> int | None: return value +class WorkflowAppLogEvaluationNodeInfoResponse(ResponseModel): + node_id: str + type: str + title: str + + +class WorkflowAppLogEvaluationItemResponse(ResponseModel): + name: str + value: Any = None + details: dict[str, Any] | None = None + node_info: WorkflowAppLogEvaluationNodeInfoResponse | None = Field( + default=None, + validation_alias="node_info", + serialization_alias="nodeInfo", + ) + + class WorkflowAppLogPartialResponse(ResponseModel): id: str workflow_run: WorkflowRunForLogResponse | None = None details: Any = None + evaluation: list[WorkflowAppLogEvaluationItemResponse] = Field(default_factory=list) created_from: str | None = None created_by_role: str | None = None created_by_account: SimpleAccount | None = None diff --git a/api/tests/unit_tests/controllers/console/app/test_workflow_app_log_api.py b/api/tests/unit_tests/controllers/console/app/test_workflow_app_log_api.py index a9853f25b0..fa3830ada4 100644 --- a/api/tests/unit_tests/controllers/console/app/test_workflow_app_log_api.py +++ b/api/tests/unit_tests/controllers/console/app/test_workflow_app_log_api.py @@ -40,6 +40,17 @@ def test_workflow_app_log_pagination_response_normalizes_nested_fields(): "finished_at": created_at, }, "details": {"trigger_metadata": {}}, + "evaluation": [ + { + "name": "answer_correctness", + "value": 0.91, + "node_info": { + "node_id": "node-1", + "type": "llm", + "title": "Judge Node", + }, + } + ], "created_by_account": {"id": "acc-1", "name": "acc", "email": "acc@example.com"}, "created_at": created_at, } @@ -50,6 +61,8 @@ def test_workflow_app_log_pagination_response_normalizes_nested_fields(): assert response["data"][0]["workflow_run"]["status"] == "succeeded" assert response["data"][0]["workflow_run"]["created_at"] == int(created_at.timestamp()) assert response["data"][0]["created_at"] == int(created_at.timestamp()) + assert response["data"][0]["evaluation"][0]["name"] == "answer_correctness" + assert response["data"][0]["evaluation"][0]["nodeInfo"]["node_id"] == "node-1" def test_workflow_archived_log_pagination_response_normalizes_nested_fields():