from __future__ import annotations import os from importlib import import_module from typing import Optional, Type from tools import Tool TOOL_REGISTRY = { "look": { "module": "tools", "class": "LookTool", "kwargs": {}, "description": "Sends the 'schau' look command to refresh the room description.", }, "simple": { "module": "tools", "class": "LookTool", "kwargs": {}, "description": "Alias of 'look'. Sends the 'schau' look command to refresh the room description.", }, "move": { "module": "movement_tool", "class": "MovementTool", "kwargs": {}, "description": "Looks around and moves in one available direction, chosen randomly among unvisited exits.", }, "movement": { "module": "movement_tool", "class": "MovementTool", "kwargs": {}, "description": "Alias of 'move'. Looks around and moves in one available direction, chosen randomly among unvisited exits.", }, "explore": { "module": "tools", "class": "ExploreTool", "kwargs": {}, "description": "Sends 'schau' once, then 'untersuche ' for each noun found in the room description.", }, "communication": { "module": "tools", "class": "CommunicationTool", "kwargs": {}, "description": "Responds to private tells with a friendly greeting via 'teile mit ...'.", }, "intelligent": { "module": "intelligent_tool", "class": "IntelligentCommunicationTool", "kwargs": { "model": os.environ.get("MISTLE_LLM_MODEL", "mistral/mistral-small") }, "description": "Uses an LLM to craft a polite reply to private tells.", }, "intelligentcommunication": { "module": "intelligent_tool", "class": "IntelligentCommunicationTool", "kwargs": { "model": os.environ.get("MISTLE_LLM_MODEL", "mistral/mistral-small") }, "description": "Alias of 'intelligent'. Uses an LLM to craft a polite reply to private tells.", }, } TOOL_DESCRIPTIONS = { name: meta["description"] for name, meta in TOOL_REGISTRY.items() } def build_tool(spec: str) -> Tool: """Instantiate a tool based on configuration.""" normalized = spec.strip() or "look" key = normalized.lower() if key in TOOL_REGISTRY: meta = TOOL_REGISTRY[key] module_name = meta["module"] class_name = meta["class"] kwargs = meta.get("kwargs", {}) try: module = import_module(module_name) tool_cls = getattr(module, class_name) except AttributeError as exc: # pragma: no cover - optional dependency raise RuntimeError(f"{class_name} is not available in tools module") from exc tool = _instantiate_tool(tool_cls, normalized, kwargs) model_name = kwargs.get("model") if kwargs else None if model_name: print(f"[Tool] Using LLM model: {model_name}") return tool if ":" in normalized: module_name, class_name = normalized.split(":", 1) if not module_name or not class_name: raise RuntimeError("MISTLE_TOOL must be in 'module:ClassName' format") module = import_module(module_name) tool_cls = getattr(module, class_name) return _instantiate_tool(tool_cls, normalized) raise RuntimeError(f"Unknown tool spec '{spec}'.") def _instantiate_tool( tool_cls: Type[Tool], tool_spec: str, kwargs: Optional[dict] = None ) -> Tool: if not issubclass(tool_cls, Tool): raise RuntimeError(f"{tool_spec} is not a Tool subclass") try: kwargs = kwargs or {} return tool_cls(**kwargs) except TypeError as exc: raise RuntimeError(f"Failed to instantiate {tool_spec}: {exc}") from exc