Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions mesa_llm/llm_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
Observation,
Reasoning,
)
from mesa_llm.tools.inbuilt_tools import INBUILT_TOOL_NAMES
from mesa_llm.tools.tool_manager import ToolManager


Expand All @@ -38,6 +39,10 @@ class LLMAgent(Agent):
the agent each step.
api_base (str | None): Optional custom LiteLLM-compatible base URL for
self-hosted or remote inference endpoints.
include_default_tools (bool): Whether to include the built-in tools
(``move_one_step``, ``teleport_to_location``, ``speak_to``) in
this agent's tool manager. Set to ``False`` when the agent should
only have access to domain-specific tools. Defaults to ``True``.

Attributes:
llm (ModuleLLM): The internal LLM interface used by the agent.
Expand All @@ -55,6 +60,7 @@ def __init__(
internal_state: list[str] | str | None = None,
step_prompt: str | None = None,
api_base: str | None = None,
include_default_tools: bool = True,
):
super().__init__(model=model)

Expand All @@ -73,6 +79,9 @@ def __init__(
)

self.tool_manager = ToolManager()
if not include_default_tools:
for name in INBUILT_TOOL_NAMES:
self.tool_manager.tools.pop(name, None)
self.vision = vision
self.reasoning = reasoning(agent=self)
self.system_prompt = system_prompt
Expand Down
4 changes: 4 additions & 0 deletions mesa_llm/tools/inbuilt_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@

logger = logging.getLogger(__name__)

INBUILT_TOOL_NAMES: frozenset[str] = frozenset(
{"move_one_step", "teleport_to_location", "speak_to"}
)

# Mapping directions to (dx, dy) for Cartesian-style spaces.
direction_map_xy = {
"North": (0, 1),
Expand Down
51 changes: 51 additions & 0 deletions tests/test_llm_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from mesa_llm.llm_agent import LLMAgent
from mesa_llm.memory.st_memory import ShortTermMemory
from mesa_llm.reasoning.react import ReActReasoning
from mesa_llm.tools.inbuilt_tools import INBUILT_TOOL_NAMES


def test_apply_plan_adds_to_memory(monkeypatch):
Expand Down Expand Up @@ -957,3 +958,53 @@ async def noop(*a, **kw):
assert data["sender"] == 10
assert data["message"] == "hello"
assert "recipients" not in data


def test_include_default_tools_true_by_default(monkeypatch):
"""Default behavior: inbuilt tools are present in the tool manager."""
monkeypatch.setenv("GEMINI_API_KEY", "dummy")
model = Model(rng=42)
agent = LLMAgent(model=model, reasoning=ReActReasoning)

for name in INBUILT_TOOL_NAMES:
assert agent.tool_manager.has_tool(name), f"{name} should be registered"


def test_include_default_tools_false_removes_inbuilt(monkeypatch):
"""When include_default_tools=False, inbuilt tools are removed."""
monkeypatch.setenv("GEMINI_API_KEY", "dummy")
model = Model(rng=42)
agent = LLMAgent(model=model, reasoning=ReActReasoning, include_default_tools=False)

for name in INBUILT_TOOL_NAMES:
assert not agent.tool_manager.has_tool(name), f"{name} should NOT be registered"


def test_include_default_tools_false_keeps_user_tools(monkeypatch):
"""User-defined global tools survive when include_default_tools=False."""
monkeypatch.setenv("GEMINI_API_KEY", "dummy")
from mesa_llm.tools.tool_decorator import _GLOBAL_TOOL_REGISTRY, tool

@tool
def custom_domain_tool(agent, value: int) -> str:
"""A user-defined domain tool.

Args:
value: The input value.

Returns:
Confirmation string.
"""
return f"done {value}"

try:
model = Model(rng=42)
agent = LLMAgent(
model=model, reasoning=ReActReasoning, include_default_tools=False
)

assert agent.tool_manager.has_tool("custom_domain_tool")
for name in INBUILT_TOOL_NAMES:
assert not agent.tool_manager.has_tool(name)
finally:
_GLOBAL_TOOL_REGISTRY.pop("custom_domain_tool", None)