mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-19 19:25:27 -04:00
56ba144875
Moves chat_with_model, ask_teacher and list_models out of ai_interaction.py into src/agent_tools/model_interaction_tools.py (the do_ prefix dropped) and registers them in TOOL_HANDLERS, so dispatch flows through the registry instead of the dispatch_ai_tool elif in tool_execution.py. The implementations are relocated, not wrapped. ai_interaction.py keeps only the shared helpers they reuse (_resolve_model, AI_CHAT_TIMEOUT), still used by the not-yet-migrated session/pipeline tools. dispatch_ai_tool loses its three now-unused branches. Also removes the dead do_second_opinion: it was already off the live tool surface (no tag/schema/parsing/dispatch; tool_index.py notes it was removed), so the function and its stale frontend catalog entries (admin.js, assistant.js) are deleted. Tests: owner-scope test points at the new list_models location and drops the moved tools from the dispatch_ai_tool parametrize; a new test_model_interaction_registry covers registration, owner threading, and registry dispatch.
105 lines
3.6 KiB
Python
105 lines
3.6 KiB
Python
"""Tests for the model-interaction tools after their move to the agent_tools
|
|
registry (#3629): chat_with_model, ask_teacher, list_models.
|
|
|
|
The implementations now live in src/agent_tools/model_interaction_tools.py
|
|
(moved out of src/ai_interaction.py). These assert (1) the handlers are
|
|
registered in TOOL_HANDLERS, (2) each handler runs the moved logic and threads
|
|
session_id/owner from the ctx, and (3) tool_execution.py dispatches them
|
|
through the registry rather than the legacy dispatch_ai_tool elif.
|
|
"""
|
|
import asyncio
|
|
from pathlib import Path
|
|
|
|
import src.ai_interaction as ai_interaction
|
|
import src.llm_core as llm_core
|
|
import src.database as database
|
|
from src.agent_tools import TOOL_HANDLERS
|
|
from src.agent_tools import model_interaction_tools as mit
|
|
|
|
_MODEL_TOOLS = ("chat_with_model", "ask_teacher", "list_models")
|
|
|
|
|
|
def test_model_interaction_tools_registered():
|
|
for name in _MODEL_TOOLS:
|
|
assert name in TOOL_HANDLERS, f"{name} missing from TOOL_HANDLERS"
|
|
|
|
|
|
def test_chat_with_model_threads_owner_and_returns(monkeypatch):
|
|
seen = {}
|
|
|
|
def fake_resolve(spec, owner=None):
|
|
seen["spec"] = spec
|
|
seen["owner"] = owner
|
|
return ("http://x", "model-x", {})
|
|
|
|
async def fake_call(url, model, messages, headers=None, timeout=None):
|
|
seen["message"] = messages[-1]["content"]
|
|
return "hi back"
|
|
|
|
monkeypatch.setattr(ai_interaction, "_resolve_model", fake_resolve)
|
|
monkeypatch.setattr(llm_core, "llm_call_async", fake_call)
|
|
|
|
res = asyncio.run(mit.ChatWithModelTool().execute(
|
|
"model-x\nhello there", {"owner": "alice", "session_id": "s1"}))
|
|
|
|
assert res == {"model": "model-x", "response": "hi back"}
|
|
assert seen["owner"] == "alice"
|
|
assert seen["spec"] == "model-x"
|
|
assert seen["message"] == "hello there"
|
|
|
|
|
|
def test_ask_teacher_threads_owner_and_marks_teacher(monkeypatch):
|
|
seen = {}
|
|
|
|
def fake_resolve(spec, owner=None):
|
|
seen["owner"] = owner
|
|
return ("http://x", "teacher-x", {})
|
|
|
|
async def fake_call(url, model, messages, headers=None, timeout=None):
|
|
return "do this and that"
|
|
|
|
monkeypatch.setattr(ai_interaction, "_resolve_model", fake_resolve)
|
|
monkeypatch.setattr(llm_core, "llm_call_async", fake_call)
|
|
|
|
res = asyncio.run(mit.AskTeacherTool().execute(
|
|
"teacher-x\nI am stuck", {"owner": "bob"}))
|
|
|
|
assert res["teacher"] is True
|
|
assert res["response"] == "do this and that"
|
|
assert seen["owner"] == "bob"
|
|
|
|
|
|
def test_list_models_no_endpoints(monkeypatch):
|
|
class _Q:
|
|
def filter(self, *a, **k):
|
|
return self
|
|
|
|
def all(self):
|
|
return []
|
|
|
|
class _S:
|
|
def query(self, *a, **k):
|
|
return _Q()
|
|
|
|
def close(self):
|
|
pass
|
|
|
|
monkeypatch.setattr(database, "SessionLocal", lambda: _S())
|
|
|
|
res = asyncio.run(mit.ListModelsTool().execute("", {}))
|
|
assert res == {"results": "No enabled model endpoints configured."}
|
|
|
|
|
|
def test_dispatched_via_registry_not_dispatch_ai_tool():
|
|
"""The model tools route through the registry (_document_tool_dispatch), and
|
|
are no longer in the dispatch_ai_tool elif tuple."""
|
|
source = (Path(__file__).resolve().parent.parent / "src" / "tool_execution.py").read_text(encoding="utf-8")
|
|
assert 'elif tool in ("chat_with_model", "ask_teacher", "list_models"):' in source
|
|
|
|
marker = "from src.ai_interaction import dispatch_ai_tool"
|
|
idx = source.index(marker)
|
|
branch_head = source.rfind("elif tool in (", 0, idx)
|
|
legacy_tuple = source[branch_head:idx]
|
|
for name in _MODEL_TOOLS:
|
|
assert f'"{name}"' not in legacy_tuple, f"{name} still routed via dispatch_ai_tool"
|