From 3cdaea720a08747fbabfaf20c53a37c104e5045c Mon Sep 17 00:00:00 2001 From: yenkins-admin <5391010+yenkins-admin@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:47:09 +0000 Subject: [PATCH] feat(gooddata-sdk): [AUTO] Add ToolCallEventResult schema and toolCallEvents to chat response --- .../gooddata-sdk/src/gooddata_sdk/__init__.py | 1 + .../src/gooddata_sdk/compute/model/chat.py | 32 +++++++++ .../tests/compute/test_chat_models.py | 70 +++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 packages/gooddata-sdk/src/gooddata_sdk/compute/model/chat.py create mode 100644 packages/gooddata-sdk/tests/compute/test_chat_models.py diff --git a/packages/gooddata-sdk/src/gooddata_sdk/__init__.py b/packages/gooddata-sdk/src/gooddata_sdk/__init__.py index 77397b92d..7a53d540e 100644 --- a/packages/gooddata-sdk/src/gooddata_sdk/__init__.py +++ b/packages/gooddata-sdk/src/gooddata_sdk/__init__.py @@ -274,6 +274,7 @@ from gooddata_sdk.compute.compute_to_sdk_converter import ComputeToSdkConverter from gooddata_sdk.compute.model.attribute import Attribute from gooddata_sdk.compute.model.base import ExecModelEntity, ObjId +from gooddata_sdk.compute.model.chat import ToolCallEventResult from gooddata_sdk.compute.model.execution import ( BareExecutionResponse, Execution, diff --git a/packages/gooddata-sdk/src/gooddata_sdk/compute/model/chat.py b/packages/gooddata-sdk/src/gooddata_sdk/compute/model/chat.py new file mode 100644 index 000000000..461504be5 --- /dev/null +++ b/packages/gooddata-sdk/src/gooddata_sdk/compute/model/chat.py @@ -0,0 +1,32 @@ +# (C) 2026 GoodData Corporation +from __future__ import annotations + +import attrs +from gooddata_api_client.model.tool_call_event_result import ( + ToolCallEventResult as ApiToolCallEventResult, +) + +from gooddata_sdk.catalog.base import Base + + +@attrs.define(kw_only=True) +class ToolCallEventResult(Base): + """Represents a tool call event emitted during the agentic loop. + + Only present in :class:`~gooddata_api_client.model.chat_result.ChatResult` + when the ``GEN_AI_YIELD_TOOL_CALL_EVENTS`` feature flag is enabled on the + GoodData backend. + """ + + function_arguments: str + """JSON-encoded arguments passed to the tool function.""" + + function_name: str + """Name of the tool function that was called.""" + + result: str + """Result returned by the tool function.""" + + @staticmethod + def client_class() -> type[ApiToolCallEventResult]: + return ApiToolCallEventResult diff --git a/packages/gooddata-sdk/tests/compute/test_chat_models.py b/packages/gooddata-sdk/tests/compute/test_chat_models.py new file mode 100644 index 000000000..3b6abf22f --- /dev/null +++ b/packages/gooddata-sdk/tests/compute/test_chat_models.py @@ -0,0 +1,70 @@ +# (C) 2026 GoodData Corporation +from __future__ import annotations + +import pytest +from gooddata_sdk.compute.model.chat import ToolCallEventResult + + +@pytest.mark.parametrize( + "scenario, input_data, expected_snake", + [ + ( + "basic", + { + "functionArguments": '{"x": 1}', + "functionName": "get_revenue", + "result": "42", + }, + { + "function_arguments": '{"x": 1}', + "function_name": "get_revenue", + "result": "42", + }, + ), + ( + "empty_strings", + { + "functionArguments": "", + "functionName": "noop", + "result": "", + }, + { + "function_arguments": "", + "function_name": "noop", + "result": "", + }, + ), + ], +) +def test_tool_call_event_result_from_dict(scenario, input_data, expected_snake): + """Verify ToolCallEventResult round-trips through from_dict / to_dict.""" + model = ToolCallEventResult.from_dict(input_data) + + assert model.function_arguments == expected_snake["function_arguments"] + assert model.function_name == expected_snake["function_name"] + assert model.result == expected_snake["result"] + + # Round-trip back to camelCase dict + as_dict = model.to_dict(camel_case=True) + assert as_dict["functionArguments"] == expected_snake["function_arguments"] + assert as_dict["functionName"] == expected_snake["function_name"] + assert as_dict["result"] == expected_snake["result"] + + +def test_tool_call_event_result_construction(): + """Verify direct construction and attribute access.""" + evt = ToolCallEventResult( + function_arguments='{"threshold": 0.5}', + function_name="filter_results", + result="filtered", + ) + assert evt.function_arguments == '{"threshold": 0.5}' + assert evt.function_name == "filter_results" + assert evt.result == "filtered" + + +def test_tool_call_event_result_client_class(): + """Verify client_class() returns the generated API model class.""" + from gooddata_api_client.model.tool_call_event_result import ToolCallEventResult as ApiToolCallEventResult + + assert ToolCallEventResult.client_class() is ApiToolCallEventResult