Files
odysseus/tests/test_model_tool_modes.py
T

145 lines
4.6 KiB
Python

from types import SimpleNamespace
from routes import model_routes
from src import agent_loop, llm_core
from src.tool_schemas import FUNCTION_TOOL_SCHEMAS
from src.model_profiles import (
GENERIC_TOOL_SCHEMA_PROFILE,
ODYSSEUS_COMPACT_TOOL_SCHEMA_PROFILE,
tool_schema_profile,
)
def test_model_tool_modes_filters_to_supported_values():
ep = SimpleNamespace(
model_tool_modes='{"small": "compact", "legacy": "none", "big": "full", "bad": "verbose"}'
)
assert model_routes._model_tool_modes(ep) == {
"small": "compact",
"legacy": "none",
"big": "full",
}
def test_agent_model_tool_modes_parser_matches_route_parser():
raw = {"small": "compact", "legacy": "none", "big": "full", "bad": "verbose"}
assert agent_loop._parse_model_tool_modes(raw) == {
"small": "compact",
"legacy": "none",
"big": "full",
}
def test_apply_compact_tool_surface_strips_schema_descriptions():
schema = {
"type": "function",
"function": {
"name": "read_file",
"description": "Read a file from disk",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string", "description": "File path"},
},
},
},
}
compact = agent_loop._apply_tool_surface_to_schemas([schema], "compact")
assert compact[0]["function"]["name"] == "read_file"
assert "description" not in compact[0]["function"]
assert "description" not in compact[0]["function"]["parameters"]["properties"]["path"]
def test_apply_none_tool_surface_removes_schemas():
assert agent_loop._apply_tool_surface_to_schemas([{"type": "function"}], "none") == []
def test_qwen35_policy_route_honors_explicit_thinking_control(monkeypatch):
monkeypatch.setenv("ODYSSEUS_QWEN_ROUTE_THINKING", "off")
assert agent_loop._thinking_mode_for_route(
model="qwen35-9b-policy-run",
tool_surface="",
domains={"files"},
) == "off"
assert agent_loop._thinking_mode_for_route(
model="llama-3.1-8b",
tool_surface="",
domains={"files"},
) is None
def test_preheretic_tools_model_forces_thinking_off():
assert agent_loop._thinking_mode_for_route(
model="odysseus-qwen3.5-tools-pre-heretic",
tool_surface="compact",
domains={"web"},
) == "off"
def test_ajax_c375_defaults_to_compact_and_forces_thinking_off(monkeypatch):
class BrokenSession:
def __init__(self):
raise RuntimeError("endpoint metadata unavailable")
import core.database
monkeypatch.setattr(core.database, "SessionLocal", BrokenSession)
assert agent_loop._configured_model_tool_surface(
"http://100.67.207.85:19187/v1", "ajax_c375"
) == "compact"
assert agent_loop._thinking_mode_for_route(
model="ajax_c375",
tool_surface="compact",
domains=set(),
) == "off"
payload = {}
monkeypatch.setattr(llm_core, "is_local_endpoint", lambda _url: True)
llm_core._apply_local_qwen_thinking_mode(
payload,
"http://ajax.invalid/v1",
"ajax_c375",
"off",
)
assert payload["chat_template_kwargs"] == {"enable_thinking": False}
def test_named_schema_profile_aliases_are_accepted_by_settings_api():
assert model_routes._normalize_model_tool_mode("regular") == "full"
assert model_routes._normalize_model_tool_mode("odysseus_compact") == "compact"
def test_odysseus_ajax_names_force_native_tool_transport():
assert agent_loop._agent_route_tool_mode(
"http://model.invalid/v1", "Odysseus-experiment"
) == (True, False, False)
assert agent_loop._agent_route_tool_mode(
"http://model.invalid/v1", "provider/Ajax_trial_99"
) == (True, False, False)
def test_builtin_function_schemas_are_accepted_by_openai_top_level_contract():
forbidden = {"oneOf", "anyOf", "allOf", "enum", "const", "not"}
for schema in FUNCTION_TOOL_SCHEMAS:
parameters = schema.get("function", {}).get("parameters", {})
assert parameters.get("type") == "object"
assert forbidden.isdisjoint(parameters)
def test_models_select_one_of_two_tool_schema_profiles():
assert tool_schema_profile("gpt-5.5") == GENERIC_TOOL_SCHEMA_PROFILE
assert tool_schema_profile("claude-sonnet-5") == GENERIC_TOOL_SCHEMA_PROFILE
assert (
tool_schema_profile("lab/Odysseus-trial55")
== ODYSSEUS_COMPACT_TOOL_SCHEMA_PROFILE
)
assert (
tool_schema_profile("provider/Ajax_c375")
== ODYSSEUS_COMPACT_TOOL_SCHEMA_PROFILE
)