@@ -1576,3 +1576,187 @@ def test_agent_with_session_and_conversation_manager():
1576
1576
assert agent .messages == agent_2 .messages
1577
1577
# Asser the conversation manager was initialized properly
1578
1578
assert agent .conversation_manager .removed_message_count == agent_2 .conversation_manager .removed_message_count
1579
+
1580
+
1581
+ def test_agent_tool_non_serializable_parameter_filtering (agent , mock_randint ):
1582
+ """Test that non-serializable objects in tool parameters are properly filtered during tool call recording."""
1583
+ mock_randint .return_value = 42
1584
+
1585
+ # Create a non-serializable object (Agent instance)
1586
+ another_agent = Agent ()
1587
+
1588
+ # This should not crash even though we're passing non-serializable objects
1589
+ result = agent .tool .tool_decorated (
1590
+ random_string = "test_value" ,
1591
+ non_serializable_agent = another_agent , # This would previously cause JSON serialization error
1592
+ user_message_override = "Testing non-serializable parameter filtering" ,
1593
+ )
1594
+
1595
+ # Verify the tool executed successfully
1596
+ expected_result = {
1597
+ "content" : [{"text" : "test_value" }],
1598
+ "status" : "success" ,
1599
+ "toolUseId" : "tooluse_tool_decorated_42" ,
1600
+ }
1601
+ assert result == expected_result
1602
+
1603
+ # The key test: this should not crash during execution
1604
+ # Check that we have messages recorded (exact count may vary)
1605
+ assert len (agent .messages ) > 0
1606
+
1607
+ # Check user message with filtered parameters - this is the main test for the bug fix
1608
+ user_message = agent .messages [0 ]
1609
+ assert user_message ["role" ] == "user"
1610
+ assert len (user_message ["content" ]) == 2
1611
+
1612
+ # Check override message
1613
+ assert user_message ["content" ][0 ]["text" ] == "Testing non-serializable parameter filtering\n "
1614
+
1615
+ # Check tool call description with filtered parameters - this is where JSON serialization would fail
1616
+ tool_call_text = user_message ["content" ][1 ]["text" ]
1617
+ assert "agent.tool.tool_decorated direct tool call." in tool_call_text
1618
+ assert '"random_string": "test_value"' in tool_call_text
1619
+ assert '"non_serializable_agent": "<<non-serializable: Agent>>"' in tool_call_text
1620
+
1621
+
1622
+ def test_agent_tool_multiple_non_serializable_types (agent , mock_randint ):
1623
+ """Test filtering of various non-serializable object types."""
1624
+ mock_randint .return_value = 123
1625
+
1626
+ # Create various non-serializable objects
1627
+ class CustomClass :
1628
+ def __init__ (self , value ):
1629
+ self .value = value
1630
+
1631
+ non_serializable_objects = {
1632
+ "agent" : Agent (),
1633
+ "custom_object" : CustomClass ("test" ),
1634
+ "function" : lambda x : x ,
1635
+ "set_object" : {1 , 2 , 3 },
1636
+ "complex_number" : 3 + 4j ,
1637
+ "serializable_string" : "this_should_remain" ,
1638
+ "serializable_number" : 42 ,
1639
+ "serializable_list" : [1 , 2 , 3 ],
1640
+ "serializable_dict" : {"key" : "value" },
1641
+ }
1642
+
1643
+ # This should not crash
1644
+ result = agent .tool .tool_decorated (random_string = "test_filtering" , ** non_serializable_objects )
1645
+
1646
+ # Verify tool executed successfully
1647
+ expected_result = {
1648
+ "content" : [{"text" : "test_filtering" }],
1649
+ "status" : "success" ,
1650
+ "toolUseId" : "tooluse_tool_decorated_123" ,
1651
+ }
1652
+ assert result == expected_result
1653
+
1654
+ # Check the recorded message for proper parameter filtering
1655
+ assert len (agent .messages ) > 0
1656
+ user_message = agent .messages [0 ]
1657
+ tool_call_text = user_message ["content" ][0 ]["text" ]
1658
+
1659
+ # Verify serializable objects remain unchanged
1660
+ assert '"serializable_string": "this_should_remain"' in tool_call_text
1661
+ assert '"serializable_number": 42' in tool_call_text
1662
+ assert '"serializable_list": [1, 2, 3]' in tool_call_text
1663
+ assert '"serializable_dict": {"key": "value"}' in tool_call_text
1664
+
1665
+ # Verify non-serializable objects are replaced with descriptive strings
1666
+ assert '"agent": "<<non-serializable: Agent>>"' in tool_call_text
1667
+ assert (
1668
+ '"custom_object": "<<non-serializable: test_agent_tool_multiple_non_serializable_types.<locals>.CustomClass>>"'
1669
+ in tool_call_text
1670
+ )
1671
+ assert '"function": "<<non-serializable: function>>"' in tool_call_text
1672
+ assert '"set_object": "<<non-serializable: set>>"' in tool_call_text
1673
+ assert '"complex_number": "<<non-serializable: complex>>"' in tool_call_text
1674
+
1675
+
1676
+ def test_agent_tool_serialization_edge_cases (agent , mock_randint ):
1677
+ """Test edge cases in parameter serialization filtering."""
1678
+ mock_randint .return_value = 999
1679
+
1680
+ # Test with None values, empty containers, and nested structures
1681
+ edge_case_params = {
1682
+ "none_value" : None ,
1683
+ "empty_list" : [],
1684
+ "empty_dict" : {},
1685
+ "nested_list_with_non_serializable" : [1 , 2 , Agent ()], # This should be filtered out
1686
+ "nested_dict_serializable" : {"nested" : {"key" : "value" }}, # This should remain
1687
+ }
1688
+
1689
+ result = agent .tool .tool_decorated (random_string = "edge_cases" , ** edge_case_params )
1690
+
1691
+ # Verify successful execution
1692
+ expected_result = {
1693
+ "content" : [{"text" : "edge_cases" }],
1694
+ "status" : "success" ,
1695
+ "toolUseId" : "tooluse_tool_decorated_999" ,
1696
+ }
1697
+ assert result == expected_result
1698
+
1699
+ # Check parameter filtering in recorded message
1700
+ assert len (agent .messages ) > 0
1701
+ user_message = agent .messages [0 ]
1702
+ tool_call_text = user_message ["content" ][0 ]["text" ]
1703
+
1704
+ # Verify serializable values remain
1705
+ assert '"none_value": null' in tool_call_text
1706
+ assert '"empty_list": []' in tool_call_text
1707
+ assert '"empty_dict": {}' in tool_call_text
1708
+ assert '"nested_dict_serializable": {"nested": {"key": "value"}}' in tool_call_text
1709
+
1710
+ # Verify non-serializable nested structure is replaced
1711
+ assert '"nested_list_with_non_serializable": [1, 2, "<<non-serializable: Agent>>"]' in tool_call_text
1712
+
1713
+
1714
+ def test_agent_tool_no_non_serializable_parameters (agent , mock_randint ):
1715
+ """Test that normal tool calls with only serializable parameters work unchanged."""
1716
+ mock_randint .return_value = 555
1717
+
1718
+ # Call with only serializable parameters
1719
+ result = agent .tool .tool_decorated (random_string = "normal_call" , user_message_override = "Normal tool call test" )
1720
+
1721
+ # Verify successful execution
1722
+ expected_result = {
1723
+ "content" : [{"text" : "normal_call" }],
1724
+ "status" : "success" ,
1725
+ "toolUseId" : "tooluse_tool_decorated_555" ,
1726
+ }
1727
+ assert result == expected_result
1728
+
1729
+ # Check message recording works normally
1730
+ assert len (agent .messages ) > 0
1731
+ user_message = agent .messages [0 ]
1732
+ tool_call_text = user_message ["content" ][1 ]["text" ]
1733
+
1734
+ # Verify normal parameter serialization (no filtering needed)
1735
+ assert "agent.tool.tool_decorated direct tool call." in tool_call_text
1736
+ assert '"random_string": "normal_call"' in tool_call_text
1737
+ # Should not contain any "<<non-serializable:" strings
1738
+ assert "<<non-serializable:" not in tool_call_text
1739
+
1740
+
1741
+ def test_agent_tool_record_direct_tool_call_disabled_with_non_serializable (agent , mock_randint ):
1742
+ """Test that when record_direct_tool_call is disabled, non-serializable parameters don't cause issues."""
1743
+ mock_randint .return_value = 777
1744
+
1745
+ # Disable tool call recording
1746
+ agent .record_direct_tool_call = False
1747
+
1748
+ # This should work fine even with non-serializable parameters since recording is disabled
1749
+ result = agent .tool .tool_decorated (
1750
+ random_string = "no_recording" , non_serializable_agent = Agent (), user_message_override = "This shouldn't be recorded"
1751
+ )
1752
+
1753
+ # Verify successful execution
1754
+ expected_result = {
1755
+ "content" : [{"text" : "no_recording" }],
1756
+ "status" : "success" ,
1757
+ "toolUseId" : "tooluse_tool_decorated_777" ,
1758
+ }
1759
+ assert result == expected_result
1760
+
1761
+ # Verify no messages were recorded
1762
+ assert len (agent .messages ) == 0
0 commit comments