mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-09-13 03:32:21 +02:00
79 lines
3.2 KiB
Python
79 lines
3.2 KiB
Python
"""Regression: api_call reaches the model for API-integration intent (#3794).
|
|
|
|
The repro prompt — "Use the api_call tool to call Home Assistant GET
|
|
/api/states" — matched no domain in ``_classify_agent_request``, so it was
|
|
treated as low-signal. The agent loop then skipped retrieval and the function
|
|
schema filter sent only the always-available tools (manage_memory / ask_user /
|
|
update_plan); ``api_call`` was never advertised to the model even though the
|
|
ToolIndex description existed. Adding the registry description alone did not fix
|
|
runtime selection.
|
|
|
|
These tests drive the real path the agent uses — classifier -> domain tool map
|
|
(relevant tools) -> FUNCTION_TOOL_SCHEMAS filter — using the actual functions and
|
|
constants, so they would fail on the pre-fix code (empty domains -> low-signal ->
|
|
no api_call). They skip locally when the agent's heavy deps (httpx/embeddings)
|
|
are absent, and run in CI where they are installed.
|
|
"""
|
|
import pytest
|
|
|
|
agent_loop = pytest.importorskip("src.agent_loop")
|
|
|
|
REPRO = "Use the api_call tool to call Home Assistant GET /api/states"
|
|
|
|
|
|
def _selected_tools(domains):
|
|
"""Mirror agent_loop's deterministic domain seeding (see the loop over
|
|
`_intent['domains']` that updates `_relevant_tools` from `_DOMAIN_TOOL_MAP`)."""
|
|
tools = set()
|
|
for domain in domains:
|
|
tools |= agent_loop._DOMAIN_TOOL_MAP.get(domain, set())
|
|
return tools
|
|
|
|
|
|
def _schema_names_sent(tools):
|
|
"""Mirror the api-model schema filter that keeps only selected tools."""
|
|
return {
|
|
s.get("function", {}).get("name")
|
|
for s in agent_loop.FUNCTION_TOOL_SCHEMAS
|
|
if s.get("function", {}).get("name") in tools
|
|
}
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"prompt",
|
|
[
|
|
REPRO,
|
|
"check my home assistant lights",
|
|
"fetch the latest unread from miniflux via the api_call tool",
|
|
"call my gitea integration to list repos",
|
|
],
|
|
)
|
|
def test_integration_prompts_are_not_low_signal(prompt):
|
|
intent = agent_loop._classify_agent_request([], prompt)
|
|
assert intent["low_signal"] is False, intent
|
|
assert "integrations" in intent["domains"], intent
|
|
|
|
|
|
def test_repro_selects_and_sends_api_call_schema():
|
|
intent = agent_loop._classify_agent_request([], REPRO)
|
|
selected = _selected_tools(intent["domains"])
|
|
assert "api_call" in selected, selected
|
|
# The schema filter must actually advertise api_call to the model.
|
|
assert "api_call" in _schema_names_sent(selected), "api_call schema must reach the model"
|
|
|
|
|
|
def test_integrations_domain_has_a_rule_pack():
|
|
# _domain_rules_for_tools indexes _DOMAIN_RULES[domain] directly, so a domain
|
|
# present in _DOMAIN_TOOL_MAP without a _DOMAIN_RULES entry would KeyError the
|
|
# moment api_call is selected.
|
|
rules = agent_loop._domain_rules_for_tools({"api_call"})
|
|
assert any("api_call" in r for r in rules), rules
|
|
|
|
|
|
def test_plain_greeting_does_not_pull_api_call():
|
|
# Guard against over-matching: an unrelated message stays low-signal and must
|
|
# not drag the integration tool into context.
|
|
intent = agent_loop._classify_agent_request([], "hey there, how are you")
|
|
assert "integrations" not in intent["domains"], intent
|
|
assert "api_call" not in _selected_tools(intent["domains"])
|