from __future__ import annotations import pytest from agent import ToolRegistry from script_build_host.tools.registry import ( _structured_object, _structured_object_list, ) def test_structured_arguments_accept_native_and_provider_encoded_json() -> None: assert _structured_object({"name": "native"}, "payload") == {"name": "native"} assert _structured_object('{"name":"encoded"}', "payload") == {"name": "encoded"} assert _structured_object_list('[{"index":1},{"index":2}]', "items") == [ {"index": 1}, {"index": 2}, ] assert _structured_object_list(['{"index":1}'], "items") == [{"index": 1}] @pytest.mark.parametrize("value", ["not-json", "123", '{"not":"an-array"}']) def test_structured_object_list_rejects_non_object_arrays(value: str) -> None: with pytest.raises(ValueError): _structured_object_list(value, "items") def test_structured_arguments_enforce_item_and_byte_limits() -> None: with pytest.raises(ValueError, match="item limit"): _structured_object_list([{}, {}], "items", max_items=1) with pytest.raises(ValueError, match="byte limit"): _structured_object({"value": "x" * (2 * 1024 * 1024)}, "payload") def test_planner_schema_exposes_only_semantic_inputs_and_decision_ids() -> None: from script_build_host.tools.registry import register_script_tools registry = ToolRegistry() register_script_tools(registry, object()) # type: ignore[arg-type] schema = registry.get_schemas(["plan_script_tasks"])[0] intents = schema["function"]["parameters"]["properties"]["intents"] intent = intents["items"] assert intents["type"] == "array" assert "schema_version" not in intent["properties"] assert "objective" in intent["required"] for derived in ( "parent_task_id", "scope_ref", "intent_class", "input_decision_refs", "base_artifact_ref", "write_scope", "output_schema", "budget", "candidate_closure_decision_refs", "compose_order", ): assert derived not in intent["properties"] assert intent["properties"]["task_kind"]["enum"] == [ "direction", "structure", "paragraph", "element-set", "compare", "compose", "candidate-portfolio", ] assert intent["additionalProperties"] is False def test_physical_retrieval_tools_are_not_registered() -> None: from script_build_host.tools.registry import register_script_tools registry = ToolRegistry() register_script_tools(registry, object()) # type: ignore[arg-type] assert { "search_knowledge", "external_search_case", "query_pattern_qa", "search_script_decode_case", }.isdisjoint(registry._tools)