Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@

from __future__ import annotations

import json
import re
from pathlib import Path
from typing import get_args
from typing import Any, get_args

import pytest

Expand Down Expand Up @@ -165,13 +166,33 @@ 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_type(value: Any) -> bool:
"""Recursively detect any object with ``type == "builtin"`` (whitespace-safe)."""
if isinstance(value, dict):
if value.get("type") == "builtin":
return True
return any(_contains_builtin_type(item) for item in value.values())
if isinstance(value, list):
return any(_contains_builtin_type(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.
# Parse each fenced JSON block so whitespace variants like `"type":"builtin"` still fail.
# Match indented / spaced fences and require at least one block so the test cannot pass vacuously.
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, (
blocks = re.findall(
r"^[ \t]*```json[ \t]*\r?\n(.*?)^[ \t]*```",
content,
flags=re.DOTALL | re.IGNORECASE | re.MULTILINE,
)
assert blocks, "config-schema.md must contain a fenced JSON example"
for block in blocks:
data = json.loads(block)
assert not _contains_builtin_type(data), (
Comment thread
coderabbitai[bot] marked this conversation as resolved.
"a JSON example in config-schema.md still writes a builtin tool entry"
)

Expand Down
11 changes: 9 additions & 2 deletions sdks/python/oss/tests/pytest/unit/agents/tools/test_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,15 @@ 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"]))
# `coerce_tool_configs` turns a bare string into a BuiltinToolConfig.
# Pass `.tool_configs` — the parse result itself is not a sequence of configs
# (iterating the pydantic model yields field tuples, so resolve would not see
# the coerced BuiltinToolConfig and would pass for the wrong reason).
parsed = coerce_tool_configs(["read"])
assert len(parsed.tool_configs) == 1
assert isinstance(parsed.tool_configs[0], BuiltinToolConfig)

resolved = await ToolResolver().resolve(parsed.tool_configs)

assert resolved.tool_specs == []

Expand Down
Loading