From 99ce5bd07ec7f29a296b81cde44ed8d31b939d33 Mon Sep 17 00:00:00 2001 From: suhasagg Date: Tue, 6 Oct 2026 18:48:51 +0530 Subject: [PATCH 1/2] fix: recognize flat function mappings by name --- .../packages/core/agent_framework/_tools.py | 13 +++- .../core/tests/core/test_middleware.py | 78 +++++++++++++++++++ 2 files changed, 88 insertions(+), 3 deletions(-) diff --git a/python/packages/core/agent_framework/_tools.py b/python/packages/core/agent_framework/_tools.py index 7fa5155b951..a9b88543c54 100644 --- a/python/packages/core/agent_framework/_tools.py +++ b/python/packages/core/agent_framework/_tools.py @@ -304,11 +304,18 @@ def __repr__(self) -> str: def _get_tool_name(tool: Any) -> str | None: """Extract a tool name from a tool object or dict tool definition.""" if isinstance(tool, Mapping): - func = tool.get("function", None) # type: ignore - if func and isinstance(func, Mapping): - name = func.get("name") # type: ignore + if tool.get("type") == "function": + name = tool.get("name") + if isinstance(name, str): + return name + + func = tool.get("function") + if isinstance(func, Mapping): + name = func.get("name") return name if isinstance(name, str) else None + return None + name = getattr(tool, "name", None) return name if isinstance(name, str) else None diff --git a/python/packages/core/tests/core/test_middleware.py b/python/packages/core/tests/core/test_middleware.py index 314860811ca..b5309fc2b5d 100644 --- a/python/packages/core/tests/core/test_middleware.py +++ b/python/packages/core/tests/core/test_middleware.py @@ -111,6 +111,84 @@ def test_init_with_custom_metadata(self, mock_function: FunctionTool) -> None: assert context.metadata == metadata +def test_remove_flat_function_mapping_by_name() -> None: + """Flat Responses-style function mappings can be removed by name.""" + lookup = { + "type": "function", + "name": "lookup", + "parameters": {"type": "object"}, + } + tools = [lookup] + + context = FunctionInvocationContext( + function=FunctionTool( + name="loader", + description="Load tools", + func=lambda: None, + ), + arguments={}, + tools=tools, + ) + + context.remove_tools("lookup") + + assert tools == [] + + +def test_add_rejects_duplicate_flat_function_mapping() -> None: + """Flat function mappings participate in duplicate-name checks.""" + lookup = { + "type": "function", + "name": "lookup", + "parameters": {"type": "object"}, + } + duplicate = { + "type": "function", + "name": "lookup", + "parameters": { + "type": "object", + "properties": {"query": {"type": "string"}}, + }, + } + tools = [lookup] + + context = FunctionInvocationContext( + function=FunctionTool( + name="loader", + description="Load tools", + func=lambda: None, + ), + arguments={}, + tools=tools, + ) + + with pytest.raises(ValueError, match="lookup"): + context.add_tools(duplicate) + + +def test_remove_name_preserves_non_function_builtin_mapping() -> None: + """A named non-function built-in mapping is not treated as a function.""" + builtin_tool = { + "type": "web_search_preview", + "name": "lookup", + } + tools = [builtin_tool] + + context = FunctionInvocationContext( + function=FunctionTool( + name="loader", + description="Load tools", + func=lambda: None, + ), + arguments={}, + tools=tools, + ) + + context.remove_tools("lookup") + + assert tools == [builtin_tool] + + class TestChatContext: """Test cases for ChatContext.""" From fbbfca8efdce253cf9d613f8f057ca68a3acb592 Mon Sep 17 00:00:00 2001 From: suhasagg Date: Wed, 7 Oct 2026 13:56:35 +0530 Subject: [PATCH 2/2] fix: satisfy typing checks for flat tool mappings --- python/packages/core/agent_framework/_tools.py | 10 +++++----- python/packages/core/tests/core/test_middleware.py | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/python/packages/core/agent_framework/_tools.py b/python/packages/core/agent_framework/_tools.py index a9b88543c54..9676d6d3788 100644 --- a/python/packages/core/agent_framework/_tools.py +++ b/python/packages/core/agent_framework/_tools.py @@ -304,14 +304,14 @@ def __repr__(self) -> str: def _get_tool_name(tool: Any) -> str | None: """Extract a tool name from a tool object or dict tool definition.""" if isinstance(tool, Mapping): - if tool.get("type") == "function": - name = tool.get("name") + if tool.get("type") == "function": # type: ignore + name = tool.get("name") # type: ignore if isinstance(name, str): return name - func = tool.get("function") - if isinstance(func, Mapping): - name = func.get("name") + func = tool.get("function", None) # type: ignore + if func and isinstance(func, Mapping): + name = func.get("name") # type: ignore return name if isinstance(name, str) else None return None diff --git a/python/packages/core/tests/core/test_middleware.py b/python/packages/core/tests/core/test_middleware.py index b5309fc2b5d..ab473306b5f 100644 --- a/python/packages/core/tests/core/test_middleware.py +++ b/python/packages/core/tests/core/test_middleware.py @@ -30,7 +30,7 @@ MiddlewareTermination, categorize_middleware, ) -from agent_framework._tools import FunctionTool +from agent_framework._tools import FunctionTool, ToolTypes class TestAgentContext: @@ -118,7 +118,7 @@ def test_remove_flat_function_mapping_by_name() -> None: "name": "lookup", "parameters": {"type": "object"}, } - tools = [lookup] + tools: list[ToolTypes] = [lookup] context = FunctionInvocationContext( function=FunctionTool( @@ -150,7 +150,7 @@ def test_add_rejects_duplicate_flat_function_mapping() -> None: "properties": {"query": {"type": "string"}}, }, } - tools = [lookup] + tools: list[ToolTypes] = [lookup] context = FunctionInvocationContext( function=FunctionTool( @@ -172,7 +172,7 @@ def test_remove_name_preserves_non_function_builtin_mapping() -> None: "type": "web_search_preview", "name": "lookup", } - tools = [builtin_tool] + tools: list[ToolTypes] = [builtin_tool] context = FunctionInvocationContext( function=FunctionTool(