From 379733f140eefc51024361b5d3f76ea6ee8472fd Mon Sep 17 00:00:00 2001 From: YuvaKunaal Date: Mon, 3 Aug 2026 17:15:10 +0530 Subject: [PATCH 1/3] test(sdk): fix two builtin-tool tests that don't exercise what they claim MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit test_a_bare_tool_name_string_is_ignored_too passed coerce_tool_configs's pydantic ToolConfigParseResult straight into resolve(), which iterates it as (field, value) tuples instead of the coerced BuiltinToolConfig — the empty tool_specs result was true for the wrong reason. It now asserts on .tool_configs directly before resolving. test_no_json_example_writes_a_builtin_tool_entry used a raw substring check that any whitespace variant like "type":"builtin" slips past. It now json.loads each fenced block and recursively walks it for any type == "builtin" entry, failing loudly on invalid JSON too. Closes #5662 --- .../test_agenta_builtins_reference_files.py | 19 ++++++++++++++++++- .../pytest/unit/agents/tools/test_resolver.py | 5 ++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/sdks/python/oss/tests/pytest/unit/agents/test_agenta_builtins_reference_files.py b/sdks/python/oss/tests/pytest/unit/agents/test_agenta_builtins_reference_files.py index b0aca3fbd3..ef77243de8 100644 --- a/sdks/python/oss/tests/pytest/unit/agents/test_agenta_builtins_reference_files.py +++ b/sdks/python/oss/tests/pytest/unit/agents/test_agenta_builtins_reference_files.py @@ -10,6 +10,7 @@ from __future__ import annotations +import json import re from pathlib import Path from typing import get_args @@ -165,13 +166,29 @@ def test_config_schema_names_every_tool_type_discriminator(): assert not missing, f"config-schema.md does not document tool type(s): {missing}" +def _contains_builtin_tool_entry(value: object) -> bool: + if isinstance(value, dict): + if value.get("type") == "builtin": + return True + return any(_contains_builtin_tool_entry(v) for v in value.values()) + if isinstance(value, list): + return any(_contains_builtin_tool_entry(item) for item in value) + return False + + def test_no_json_example_writes_a_builtin_tool_entry(): # The `builtin` arm survives only as legacy dual-read. The authoring agent copies these # examples verbatim, so an example that still writes one would keep producing configs the # resolver has to ignore. content = _file("references/config-schema.md").content for block in re.findall(r"```json\n(.*?)```", content, flags=re.DOTALL): - assert '"type": "builtin"' not in block, ( + try: + parsed = json.loads(block) + except json.JSONDecodeError as exc: + raise AssertionError( + f"config-schema.md has a json fence that is not valid JSON: {exc}" + ) from exc + assert not _contains_builtin_tool_entry(parsed), ( "a JSON example in config-schema.md still writes a builtin tool entry" ) diff --git a/sdks/python/oss/tests/pytest/unit/agents/tools/test_resolver.py b/sdks/python/oss/tests/pytest/unit/agents/tools/test_resolver.py index 2d4afd5d0a..139fa60315 100644 --- a/sdks/python/oss/tests/pytest/unit/agents/tools/test_resolver.py +++ b/sdks/python/oss/tests/pytest/unit/agents/tools/test_resolver.py @@ -296,7 +296,10 @@ async def resolve(self, tools): async def test_a_bare_tool_name_string_is_ignored_too(): # `coerce_tool_config` turns a bare string into a BuiltinToolConfig. - resolved = await ToolResolver().resolve(coerce_tool_configs(["read"])) + parsed = coerce_tool_configs(["read"]) + assert parsed.tool_configs == [BuiltinToolConfig(name="read")] + + resolved = await ToolResolver().resolve(parsed.tool_configs) assert resolved.tool_specs == [] From 343c013983b10c11a5ee51b24a2694ba7a9ced86 Mon Sep 17 00:00:00 2001 From: Boggavarapu Yuva Satya Kunaal <126342173+Yuvakunaal@users.noreply.github.com> Date: Mon, 3 Aug 2026 17:28:05 +0530 Subject: [PATCH 2/3] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- sdks/python/oss/tests/pytest/unit/agents/tools/test_resolver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdks/python/oss/tests/pytest/unit/agents/tools/test_resolver.py b/sdks/python/oss/tests/pytest/unit/agents/tools/test_resolver.py index 139fa60315..b1c6f4a3a5 100644 --- a/sdks/python/oss/tests/pytest/unit/agents/tools/test_resolver.py +++ b/sdks/python/oss/tests/pytest/unit/agents/tools/test_resolver.py @@ -295,7 +295,7 @@ async def resolve(self, tools): async def test_a_bare_tool_name_string_is_ignored_too(): - # `coerce_tool_config` turns a bare string into a BuiltinToolConfig. + # `coerce_tool_configs` turns a bare string into a BuiltinToolConfig. parsed = coerce_tool_configs(["read"]) assert parsed.tool_configs == [BuiltinToolConfig(name="read")] From 773f26e14108dd5fac735258411d5a347051a88c Mon Sep 17 00:00:00 2001 From: YuvaKunaal Date: Mon, 3 Aug 2026 17:46:37 +0530 Subject: [PATCH 3/3] test(sdk): guard against an empty JSON-example match in the builtins test CodeRabbit caught it: re.findall could return an empty list, and the loop would then silently validate nothing while still passing. Assert at least one block is found before iterating. --- .../unit/agents/test_agenta_builtins_reference_files.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sdks/python/oss/tests/pytest/unit/agents/test_agenta_builtins_reference_files.py b/sdks/python/oss/tests/pytest/unit/agents/test_agenta_builtins_reference_files.py index ef77243de8..fa11ebdfcd 100644 --- a/sdks/python/oss/tests/pytest/unit/agents/test_agenta_builtins_reference_files.py +++ b/sdks/python/oss/tests/pytest/unit/agents/test_agenta_builtins_reference_files.py @@ -181,7 +181,9 @@ def test_no_json_example_writes_a_builtin_tool_entry(): # examples verbatim, so an example that still writes one would keep producing configs the # resolver has to ignore. content = _file("references/config-schema.md").content - for block in re.findall(r"```json\n(.*?)```", content, flags=re.DOTALL): + blocks = re.findall(r"```json\n(.*?)```", content, flags=re.DOTALL) + assert blocks, "config-schema.md must contain at least one JSON example" + for block in blocks: try: parsed = json.loads(block) except json.JSONDecodeError as exc: