test_tool_argument_normalization.py 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. from __future__ import annotations
  2. import pytest
  3. from agent import ToolRegistry
  4. from script_build_host.tools.registry import (
  5. _structured_object,
  6. _structured_object_list,
  7. )
  8. def test_structured_arguments_accept_native_and_provider_encoded_json() -> None:
  9. assert _structured_object({"name": "native"}, "payload") == {"name": "native"}
  10. assert _structured_object('{"name":"encoded"}', "payload") == {"name": "encoded"}
  11. assert _structured_object_list('[{"index":1},{"index":2}]', "items") == [
  12. {"index": 1},
  13. {"index": 2},
  14. ]
  15. assert _structured_object_list(['{"index":1}'], "items") == [{"index": 1}]
  16. @pytest.mark.parametrize("value", ["not-json", "123", '{"not":"an-array"}'])
  17. def test_structured_object_list_rejects_non_object_arrays(value: str) -> None:
  18. with pytest.raises(ValueError):
  19. _structured_object_list(value, "items")
  20. def test_structured_arguments_enforce_item_and_byte_limits() -> None:
  21. with pytest.raises(ValueError, match="item limit"):
  22. _structured_object_list([{}, {}], "items", max_items=1)
  23. with pytest.raises(ValueError, match="byte limit"):
  24. _structured_object({"value": "x" * (2 * 1024 * 1024)}, "payload")
  25. def test_planner_schema_exposes_only_semantic_inputs_and_decision_ids() -> None:
  26. from script_build_host.tools.registry import register_script_tools
  27. registry = ToolRegistry()
  28. register_script_tools(registry, object()) # type: ignore[arg-type]
  29. schema = registry.get_schemas(["plan_script_tasks"])[0]
  30. intents = schema["function"]["parameters"]["properties"]["intents"]
  31. intent = intents["items"]
  32. assert intents["type"] == "array"
  33. assert "schema_version" not in intent["properties"]
  34. assert "objective" in intent["required"]
  35. for derived in (
  36. "parent_task_id",
  37. "scope_ref",
  38. "intent_class",
  39. "input_decision_refs",
  40. "base_artifact_ref",
  41. "write_scope",
  42. "output_schema",
  43. "budget",
  44. "candidate_closure_decision_refs",
  45. "compose_order",
  46. ):
  47. assert derived not in intent["properties"]
  48. assert intent["properties"]["task_kind"]["enum"] == [
  49. "direction",
  50. "structure",
  51. "paragraph",
  52. "element-set",
  53. "compare",
  54. "compose",
  55. "candidate-portfolio",
  56. ]
  57. assert intent["additionalProperties"] is False
  58. def test_physical_retrieval_tools_are_not_registered() -> None:
  59. from script_build_host.tools.registry import register_script_tools
  60. registry = ToolRegistry()
  61. register_script_tools(registry, object()) # type: ignore[arg-type]
  62. assert {
  63. "search_knowledge",
  64. "external_search_case",
  65. "query_pattern_qa",
  66. "search_script_decode_case",
  67. }.isdisjoint(registry._tools)