diff --git a/tests/test_cloud.py b/tests/test_cloud.py index 47fbdaff..52f13ea6 100644 --- a/tests/test_cloud.py +++ b/tests/test_cloud.py @@ -115,9 +115,12 @@ async def test_cloud(): mock_vefaas_client = Mock() mock_vefaas_in_app.return_value = mock_vefaas_client mock_vefaas_client.delete.return_value = None - - cloud_app.delete_self() - mock_vefaas_client.delete.assert_called_with("app-123") + with patch.object( + cloud_app, "_get_vefaas_application_id_by_name" + ) as mock_get_id_by_name: + mock_get_id_by_name.return_value = None + cloud_app.delete_self() + mock_vefaas_client.delete.assert_called_with("app-123") # Verify all mocks were called as expected mock_vefaas_service.deploy.assert_called_once() diff --git a/veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py b/veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py index 379c033a..87d87920 100644 --- a/veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py +++ b/veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py @@ -18,6 +18,7 @@ ExtractorResponse, LLMAttributesParams, ) +from veadk.utils.misc import safe_json_serialize def llm_gen_ai_request_model(params: LLMAttributesParams) -> ExtractorResponse: @@ -133,7 +134,7 @@ def llm_gen_ai_prompt(params: LLMAttributesParams) -> ExtractorResponse: else "" ) message[f"gen_ai.prompt.{idx}.tool_calls.0.function.arguments"] = ( - json.dumps(part.function_call.args) + safe_json_serialize(part.function_call.args) if part.function_call.args else json.dumps({}) ) @@ -168,7 +169,7 @@ def llm_gen_ai_completion(params: LLMAttributesParams) -> ExtractorResponse: else "" ) message[f"gen_ai.completion.{idx}.tool_calls.0.function.arguments"] = ( - json.dumps(part.function_call.args) + safe_json_serialize(part.function_call.args) if part.function_call.args else json.dumps({}) ) @@ -289,7 +290,7 @@ def llm_gen_ai_assistant_message(params: LLMAttributesParams) -> ExtractorRespon else "" ) message_part["tool_calls.0.function.arguments"] = ( - json.dumps(part.function_call.args) + safe_json_serialize(part.function_call.args) if part.function_call.args else json.dumps({}) ) @@ -326,7 +327,7 @@ def llm_gen_ai_choice(params: LLMAttributesParams) -> ExtractorResponse: else "" ) message["message.tool_calls.0.function.arguments"] = ( - json.dumps(part.function_call.args) + safe_json_serialize(part.function_call.args) if part.function_call.args else json.dumps({}) ) @@ -351,7 +352,7 @@ def llm_gen_ai_choice(params: LLMAttributesParams) -> ExtractorResponse: else "" ) message["message.tool_calls.0.function.arguments"] = ( - json.dumps(part.function_call.args) + safe_json_serialize(part.function_call.args) if part.function_call.args else json.dumps({}) ) diff --git a/veadk/tracing/telemetry/attributes/extractors/tool_attributes_extractors.py b/veadk/tracing/telemetry/attributes/extractors/tool_attributes_extractors.py index 3a87a895..20e07717 100644 --- a/veadk/tracing/telemetry/attributes/extractors/tool_attributes_extractors.py +++ b/veadk/tracing/telemetry/attributes/extractors/tool_attributes_extractors.py @@ -12,12 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -import json - from veadk.tracing.telemetry.attributes.extractors.types import ( ExtractorResponse, ToolAttributesParams, ) +from veadk.utils.misc import safe_json_serialize def tool_gen_ai_operation_name(params: ToolAttributesParams) -> ExtractorResponse: @@ -27,7 +26,7 @@ def tool_gen_ai_operation_name(params: ToolAttributesParams) -> ExtractorRespons def tool_gen_ai_tool_message(params: ToolAttributesParams) -> ExtractorResponse: tool_input = { "role": "tool", - "content": json.dumps( + "content": safe_json_serialize( { "name": params.tool.name, "description": params.tool.description, @@ -45,7 +44,7 @@ def tool_gen_ai_tool_input(params: ToolAttributesParams) -> ExtractorResponse: "parameters": params.args, } return ExtractorResponse( - content=json.dumps(tool_input, ensure_ascii=False) or "" + content=safe_json_serialize(tool_input) or "" ) @@ -63,7 +62,7 @@ def tool_gen_ai_tool_output(params: ToolAttributesParams) -> ExtractorResponse: "response": function_response["response"], } return ExtractorResponse( - content=json.dumps(tool_output, ensure_ascii=False) or "" + content=safe_json_serialize(tool_output) or "" ) diff --git a/veadk/utils/misc.py b/veadk/utils/misc.py index 750ed1a5..f6e35648 100644 --- a/veadk/utils/misc.py +++ b/veadk/utils/misc.py @@ -13,6 +13,7 @@ # limitations under the License. import importlib.util +import json import sys import time import types @@ -81,3 +82,21 @@ def flatten_dict( else: items.append((new_key, v)) return dict(items) + + +def safe_json_serialize(obj) -> str: + """Convert any Python object to a JSON-serializable type or string. + + Args: + obj: The object to serialize. + + Returns: + The JSON-serialized object string or if the object cannot be serialized. + """ + + try: + return json.dumps( + obj, ensure_ascii=False, default=lambda o: "" + ) + except (TypeError, OverflowError): + return ""