From dcd31f5862ed8f1f5eb22be772d47fc26d6eb8bc Mon Sep 17 00:00:00 2001 From: twentyOne2x Date: Thu, 16 Jul 2026 08:53:53 +0200 Subject: [PATCH] Use provider-compatible Leo read schema --- scripts/leo_oos_readonly_guard.py | 28 +++++++++++++--------------- tests/test_leo_oos_readonly_guard.py | 15 +++++++-------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/scripts/leo_oos_readonly_guard.py b/scripts/leo_oos_readonly_guard.py index 3569f34..2d51ada 100644 --- a/scripts/leo_oos_readonly_guard.py +++ b/scripts/leo_oos_readonly_guard.py @@ -72,20 +72,6 @@ _ACTION_SPECS = { READ_ONLY_BRIDGE_COMMANDS = frozenset(_ACTION_SPECS) -def _action_schema(action: str) -> dict[str, Any]: - spec = _ACTION_SPECS[action] - fields = (*spec["required"], *spec["optional"]) - return { - "type": "object", - "properties": { - "action": {"type": "string", "enum": [action]}, - **{field: _FIELD_SCHEMAS[field] for field in fields}, - }, - "required": ["action", *spec["required"]], - "additionalProperties": False, - } - - STRUCTURED_READ_TOOL_SCHEMA = { "name": STRUCTURED_READ_TOOL_NAME, "description": ( @@ -94,7 +80,19 @@ STRUCTURED_READ_TOOL_SCHEMA = { ), "parameters": { "type": "object", - "oneOf": [_action_schema(action) for action in sorted(_ACTION_SPECS)], + "properties": { + "action": { + "type": "string", + "enum": sorted(_ACTION_SPECS), + "description": ( + "Read operation. query is required for search, context, and search-proposals; claim_id is " + "required for show, evidence, and edges; proposal_id is required for show-proposal." + ), + }, + **_FIELD_SCHEMAS, + }, + "required": ["action"], + "additionalProperties": False, }, } diff --git a/tests/test_leo_oos_readonly_guard.py b/tests/test_leo_oos_readonly_guard.py index e7e7a4b..bb7657d 100644 --- a/tests/test_leo_oos_readonly_guard.py +++ b/tests/test_leo_oos_readonly_guard.py @@ -78,15 +78,14 @@ def test_structured_read_rejects_writes_bad_types_irrelevant_fields_and_unbounde guard.structured_read_argv(tool_args) -def test_schema_encodes_action_specific_required_fields() -> None: - branches = guard.STRUCTURED_READ_TOOL_SCHEMA["parameters"]["oneOf"] - by_action = {branch["properties"]["action"]["enum"][0]: branch for branch in branches} +def test_schema_is_provider_compatible_while_handler_enforces_action_contracts() -> None: + parameters = guard.STRUCTURED_READ_TOOL_SCHEMA["parameters"] - assert by_action["context"]["required"] == ["action", "query"] - assert set(by_action["context"]["properties"]) == {"action", "query", "limit", "context_limit", "format"} - assert by_action["context"]["additionalProperties"] is False - assert by_action["show"]["required"] == ["action", "claim_id"] - assert by_action["status"]["required"] == ["action"] + assert parameters["required"] == ["action"] + assert parameters["additionalProperties"] is False + assert not ({"oneOf", "anyOf", "allOf"} & set(parameters)) + assert set(parameters["properties"]["action"]["enum"]) == set(guard.READ_ONLY_BRIDGE_COMMANDS) + assert "query is required" in parameters["properties"]["action"]["description"] class FakeProcess: