Skip to content

Commit 315e4f0

Browse files
committed
test: strengthen callback-manager filtering tests and document name fallback
- assert the inferred schema explicitly excludes run_manager/callbacks - add a test case covering the async CallbackManagerForToolRun variant so both sync and async callback-manager types are exercised separately - document why the run_manager/callbacks name fallback exists: this module uses from __future__ import annotations, so annotations arrive as strings and get_type_hints can fail to resolve them, leaving string annotations that the issubclass check cannot match Signed-off-by: godququ5-code <godququ5@gmail.com>
1 parent c1b1fc2 commit 315e4f0

2 files changed

Lines changed: 48 additions & 0 deletions

File tree

python/packages/autogen-ext/src/autogen_ext/tools/langchain/_langchain_adapter.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,13 @@ def __init__(self, langchain_tool: LangChainTool):
219219
# * ``callbacks`` (a ``Callbacks`` sequence of handlers) —
220220
# ``_is_callback_manager_annotation`` does not match it, so
221221
# it must be filtered by name.
222+
# ``get_type_hints`` resolves annotations to real types when it
223+
# can, but this module uses ``from __future__ import annotations``,
224+
# so annotations arrive as strings and ``get_type_hints`` can fail
225+
# (e.g. for a locally-defined tool), leaving a string annotation
226+
# that ``_is_callback_manager_annotation``'s ``issubclass`` check
227+
# cannot match. The ``run_manager``/``callbacks`` name check is a
228+
# deliberate fallback for exactly that case.
222229
annotation = type_hints.get(k, v.annotation)
223230
if _is_callback_manager_annotation(annotation) or k in ("run_manager", "callbacks"):
224231
continue

python/packages/autogen-ext/tests/tools/test_langchain_tools.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ async def test_langchain_tool_adapter_skips_run_manager() -> None:
133133
assert "parameters" in schema
134134
assert "properties" in schema["parameters"]
135135
props = schema["parameters"]["properties"]
136+
assert "run_manager" not in props
136137
assert set(props.keys()) == {"a", "b"}
137138
assert "required" in schema["parameters"]
138139
assert set(schema["parameters"]["required"]) == {"a", "b"}
@@ -167,6 +168,46 @@ async def test_langchain_tool_adapter_skips_callbacks() -> None:
167168
assert "parameters" in schema
168169
assert "properties" in schema["parameters"]
169170
props = schema["parameters"]["properties"]
171+
assert "callbacks" not in props
172+
assert set(props.keys()) == {"a", "b"}
173+
assert "required" in schema["parameters"]
174+
assert set(schema["parameters"]["required"]) == {"a", "b"}
175+
176+
result = await adapter.run_json({"a": 2, "b": 3}, CancellationToken())
177+
assert result == 5
178+
179+
180+
class NoSchemaAsyncManagerTool(LangChainTool):
181+
name: str = "NoSchemaAsyncManager"
182+
description: str = "a tool whose sync _run is annotated with the async callback manager type"
183+
184+
def _run(
185+
self, a: int, b: int, run_manager: Optional[AsyncCallbackManagerForToolRun] = None
186+
) -> int:
187+
return a + b
188+
189+
async def _arun(
190+
self, a: int, b: int, run_manager: Optional[AsyncCallbackManagerForToolRun] = None
191+
) -> int:
192+
return a + b
193+
194+
195+
@pytest.mark.asyncio
196+
async def test_langchain_tool_adapter_skips_async_run_manager() -> None:
197+
# The detection must cover the *async* callback-manager type
198+
# (``AsyncCallbackManagerForToolRun``), not only the sync
199+
# ``CallbackManagerForToolRun``. ``_is_callback_manager_annotation`` unwraps
200+
# ``Optional[...]`` and matches both via ``issubclass``, so a tool that
201+
# annotates its signature with the async variant is still filtered out.
202+
tool = NoSchemaAsyncManagerTool()
203+
adapter = LangChainToolAdapter(tool) # type: ignore
204+
205+
schema = adapter.schema
206+
assert schema["name"] == "NoSchemaAsyncManager"
207+
assert "parameters" in schema
208+
assert "properties" in schema["parameters"]
209+
props = schema["parameters"]["properties"]
210+
assert "run_manager" not in props
170211
assert set(props.keys()) == {"a", "b"}
171212
assert "required" in schema["parameters"]
172213
assert set(schema["parameters"]["required"]) == {"a", "b"}

0 commit comments

Comments
 (0)