Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/gooddata-sdk/src/gooddata_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
32 changes: 32 additions & 0 deletions packages/gooddata-sdk/src/gooddata_sdk/compute/model/chat.py
Original file line number Diff line number Diff line change
@@ -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
70 changes: 70 additions & 0 deletions packages/gooddata-sdk/tests/compute/test_chat_models.py
Original file line number Diff line number Diff line change
@@ -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
Loading