From 66be1630faa2335803969abea89b6c1ffc74fa40 Mon Sep 17 00:00:00 2001 From: Sameer6305 Date: Thu, 30 Jul 2026 20:43:26 +0530 Subject: [PATCH] fix(agno): fail fast on toolkit registration failures - #780 --- integrations/agno/decision_kit.py | 8 +++--- integrations/agno/kg_toolkit.py | 8 +++--- tests/integrations/agno/test_decision_kit.py | 28 ++++++++++++++++++-- tests/integrations/agno/test_kg_toolkit.py | 26 +++++++++++++++++- 4 files changed, 57 insertions(+), 13 deletions(-) diff --git a/integrations/agno/decision_kit.py b/integrations/agno/decision_kit.py index bcb4e66e..cc64e9c6 100644 --- a/integrations/agno/decision_kit.py +++ b/integrations/agno/decision_kit.py @@ -123,12 +123,10 @@ class AgnoDecisionKit(_ToolkitBase): # type: ignore[misc] tools_to_register.append(self.check_policy) for fn in tools_to_register: - self._tools.append(fn) if AGNO_AVAILABLE: - try: - self.register(fn) - except Exception: - pass + self.register(fn) + if fn not in self._tools: + self._tools.append(fn) logger.info("AgnoDecisionKit initialised") diff --git a/integrations/agno/kg_toolkit.py b/integrations/agno/kg_toolkit.py index 75ee26ed..c36ea63f 100644 --- a/integrations/agno/kg_toolkit.py +++ b/integrations/agno/kg_toolkit.py @@ -122,12 +122,10 @@ class AgnoKGToolkit(_ToolkitBase): # type: ignore[misc] self.export_subgraph, ] for fn in tools_to_register: - self._tools.append(fn) if AGNO_AVAILABLE: - try: - self.register(fn) - except Exception: - pass + self.register(fn) + if fn not in self._tools: + self._tools.append(fn) logger.info("AgnoKGToolkit initialised (backend=%s)", graph_store_backend) diff --git a/tests/integrations/agno/test_decision_kit.py b/tests/integrations/agno/test_decision_kit.py index 8efd4830..3f13b6c0 100644 --- a/tests/integrations/agno/test_decision_kit.py +++ b/tests/integrations/agno/test_decision_kit.py @@ -8,7 +8,7 @@ import json import sys import types import unittest -from unittest.mock import MagicMock +from unittest.mock import MagicMock, patch # --------------------------------------------------------------------------- @@ -75,7 +75,31 @@ class TestAgnoDecisionKitInit(unittest.TestCase): def test_tools_registered(self): kit = AgnoDecisionKit(context=_make_context()) # Tools should be registered (Toolkit.register was called) - self.assertTrue(len(kit._tools) >= 5) + self.assertEqual(len(kit._tools), 6) + self.assertEqual(len(kit._tools), len(set(kit._tools))) + + def test_registration_invoked(self): + with patch.object(AgnoDecisionKit, "register") as mock_register: + AgnoDecisionKit(context=_make_context()) + self.assertEqual(mock_register.call_count, 6) + + def test_registration_failure_propagates(self): + with patch.object(AgnoDecisionKit, "register", side_effect=RuntimeError("Registration failed")): + with self.assertRaises(RuntimeError): + AgnoDecisionKit(context=_make_context()) + + def test_graceful_degradation_when_agno_unavailable(self): + with patch("integrations.agno.decision_kit.AGNO_AVAILABLE", False): + with patch.object(AgnoDecisionKit, "register") as mock_register: + kit = AgnoDecisionKit(context=_make_context()) + mock_register.assert_not_called() + self.assertEqual(len(kit._tools), 6) + self.assertEqual(len(kit._tools), len(set(kit._tools))) + + def test_no_duplicate_tools(self): + kit = AgnoDecisionKit(context=_make_context()) + self.assertEqual(len(kit._tools), len(set(kit._tools))) + self.assertEqual(len(kit._tools), 6) def test_policy_tool_can_be_disabled(self): kit = AgnoDecisionKit(context=_make_context(), enable_policy_check=False) diff --git a/tests/integrations/agno/test_kg_toolkit.py b/tests/integrations/agno/test_kg_toolkit.py index 8ddd25a9..d9dcdbfc 100644 --- a/tests/integrations/agno/test_kg_toolkit.py +++ b/tests/integrations/agno/test_kg_toolkit.py @@ -129,7 +129,31 @@ class TestAgnoKGToolkitInit(unittest.TestCase): def test_tools_registered(self): kit = AgnoKGToolkit() - self.assertTrue(len(kit._tools) >= 7) + self.assertEqual(len(kit._tools), 7) + self.assertEqual(len(kit._tools), len(set(kit._tools))) + + def test_registration_invoked(self): + with patch.object(AgnoKGToolkit, "register") as mock_register: + AgnoKGToolkit() + self.assertEqual(mock_register.call_count, 7) + + def test_registration_failure_propagates(self): + with patch.object(AgnoKGToolkit, "register", side_effect=RuntimeError("Registration failed")): + with self.assertRaises(RuntimeError): + AgnoKGToolkit() + + def test_graceful_degradation_when_agno_unavailable(self): + with patch("integrations.agno.kg_toolkit.AGNO_AVAILABLE", False): + with patch.object(AgnoKGToolkit, "register") as mock_register: + kit = AgnoKGToolkit() + mock_register.assert_not_called() + self.assertEqual(len(kit._tools), 7) + self.assertEqual(len(kit._tools), len(set(kit._tools))) + + def test_no_duplicate_tools(self): + kit = AgnoKGToolkit() + self.assertEqual(len(kit._tools), len(set(kit._tools))) + self.assertEqual(len(kit._tools), 7) def test_context_graph_attached(self): ctx = MagicMock()