build-small-hackathon/hackathon-advisor
16
1import pytest2 3from hackathon_advisor.tool_contracts import (4 ToolCall,5 ToolContractError,6 parse_xml_tool_call,7 resolve_tool_call,8 tool_schemas,9 validate_tool_call,10)11 12 13def test_tool_schemas_are_model_ready() -> None:14 schemas = tool_schemas()15 16 assert len(schemas) >= 817 assert schemas[0]["type"] == "function"18 assert {schema["function"]["name"] for schema in schemas} >= {19 "search_projects",20 "find_whitespace",21 "save_idea",22 "score_idea",23 "make_plan",24 "set_goals",25 }26 schema_text = str(schemas)27 assert "set_target" not in schema_text28 assert "side_quests" not in schema_text29 assert "prize" not in schema_text.lower()30 assert "badge" not in schema_text.lower()31 assert "Build Small" not in schema_text32 assert "hackathon" not in schema_text.lower()33 34 35def test_parse_and_validate_minicpm_xml_tool_call() -> None:36 call = parse_xml_tool_call('<function name="search_projects">{"query":"lullaby audio"}</function>')37 38 assert validate_tool_call(call) == ToolCall("search_projects", {"query": "lullaby audio"})39 40 41def test_validate_rejects_unknown_tool() -> None:42 with pytest.raises(ToolContractError, match="unknown tool"):43 validate_tool_call(ToolCall("invent_project", {}))44 45 46def test_validate_rejects_bad_argument_type() -> None:47 with pytest.raises(ToolContractError, match="search_projects.query must be string"):48 validate_tool_call(ToolCall("search_projects", {"query": 47}))49 50 51def test_validate_rejects_extra_arguments() -> None:52 with pytest.raises(ToolContractError, match="unexpected arguments"):53 validate_tool_call(ToolCall("find_whitespace", {"query": "unused"}))54 55 56def test_resolve_defaults_to_search_when_output_is_broken() -> None:57 resolution = resolve_tool_call("<function", fallback_query="offline archive")58 59 assert resolution.status == "defaulted"60 assert resolution.call == ToolCall("search_projects", {"query": "offline archive"})61 assert resolution.errors62 63 64def test_resolve_defaults_to_whitespace_without_query() -> None:65 resolution = resolve_tool_call("no function here")66 67 assert resolution.status == "defaulted"68 assert resolution.call == ToolCall("find_whitespace", {})69 