230 lines
6.9 KiB
Python
230 lines
6.9 KiB
Python
"""
|
|
Agent module tests
|
|
"""
|
|
|
|
import os
|
|
import tempfile
|
|
import unittest
|
|
|
|
from unittest.mock import patch
|
|
|
|
from datetime import datetime
|
|
|
|
from smolagents import CodeAgent, PythonInterpreterTool
|
|
|
|
from txtai.agent import Agent
|
|
from txtai.embeddings import Embeddings
|
|
|
|
# agents.md content
|
|
AGENTS = """
|
|
Basic instructions here
|
|
"""
|
|
|
|
# Sample skill.md content
|
|
SKILL = """---
|
|
name: hello
|
|
description: says hello world
|
|
---
|
|
|
|
Says hello world
|
|
"""
|
|
|
|
|
|
class TestAgent(unittest.TestCase):
|
|
"""
|
|
Agent tests.
|
|
"""
|
|
|
|
def testExecute(self):
|
|
"""
|
|
Test executing main agent loop
|
|
"""
|
|
|
|
agent = Agent(llm="hf-internal-testing/tiny-random-LlamaForCausalLM", max_steps=1)
|
|
|
|
# Patch LLM to generate answer
|
|
agent.process.model.llm = lambda *args, **kwargs: 'Action:\n{"name": "final_answer", "arguments": "Hi"}'
|
|
|
|
self.assertEqual(agent("Hello"), "Hi")
|
|
|
|
def testInstructions(self):
|
|
"""
|
|
Test loading an agents.md file
|
|
"""
|
|
|
|
# Test loading instructions from file
|
|
agents = os.path.join(tempfile.gettempdir(), "agents.md")
|
|
with open(agents, "w", encoding="utf-8") as output:
|
|
output.write(AGENTS)
|
|
|
|
agent = Agent(instructions=agents, llm="hf-internal-testing/tiny-random-LlamaForCausalLM", max_iterations=1)
|
|
agent.process.model.llm = lambda *args, **kwargs: 'Action:\n{"name": "final_answer", "arguments": "Hi"}'
|
|
self.assertEqual(agent("Hello"), "Hi")
|
|
|
|
# Test loading from memory
|
|
agent = Agent(instructions=AGENTS, llm="hf-internal-testing/tiny-random-LlamaForCausalLM", max_iterations=1)
|
|
agent.process.model.llm = lambda *args, **kwargs: 'Action:\n{"name": "final_answer", "arguments": "Hi"}'
|
|
self.assertEqual(agent("Hello"), "Hi")
|
|
|
|
def testMemory(self):
|
|
"""
|
|
Test agent memory
|
|
"""
|
|
|
|
agent = Agent(llm="hf-internal-testing/tiny-random-LlamaForCausalLM", max_steps=1, memory=5)
|
|
|
|
# Patch LLM to generate answer
|
|
agent.process.model.llm = lambda *args, **kwargs: 'Action:\n{"name": "final_answer", "arguments": "Hi"}'
|
|
|
|
self.assertEqual(agent("Hello"), "Hi")
|
|
self.assertEqual(agent("Hello"), "Hi")
|
|
|
|
# Test that results are stored in shared memory
|
|
self.assertEqual(len(agent.memory.get(None)), 2)
|
|
|
|
# Test resetting shared memory
|
|
self.assertEqual(agent("Hello", reset=True), "Hi")
|
|
self.assertEqual(len(agent.memory.get(None)), 1)
|
|
|
|
# Test session memory
|
|
self.assertEqual(agent("Hello", session="session-0"), "Hi")
|
|
self.assertEqual(len(agent.memory.get("session-0")), 1)
|
|
|
|
# Test resetting session memory
|
|
self.assertEqual(agent("Hello", session="session-0", reset=True), "Hi")
|
|
self.assertEqual(len(agent.memory.get("session-0")), 1)
|
|
self.assertEqual(len(agent.memory.get(None)), 1)
|
|
|
|
def testMethod(self):
|
|
"""
|
|
Test agent process methods
|
|
"""
|
|
|
|
agent = Agent(method="code", llm="hf-internal-testing/tiny-random-LlamaForCausalLM", max_iterations=1)
|
|
self.assertIsInstance(agent.process, CodeAgent)
|
|
|
|
def testSkill(self):
|
|
"""
|
|
Test running a skill from a skill.md file
|
|
"""
|
|
|
|
skill = os.path.join(tempfile.gettempdir(), "skill.md")
|
|
with open(skill, "w", encoding="utf-8") as output:
|
|
output.write(SKILL)
|
|
|
|
agent = Agent(tools=[skill], llm="hf-internal-testing/tiny-random-LlamaForCausalLM", max_iterations=1)
|
|
|
|
self.assertIsInstance(agent.tools["hello"]("say hello"), str)
|
|
|
|
def testToolsBasic(self):
|
|
"""
|
|
Test adding basic function tools
|
|
"""
|
|
|
|
class DateTime:
|
|
"""
|
|
Date time instance
|
|
"""
|
|
|
|
def __call__(self, iso):
|
|
"""
|
|
Gets the current date and time
|
|
|
|
Args:
|
|
iso: date will be converted to iso format if True
|
|
|
|
Returns:
|
|
current date and time
|
|
"""
|
|
|
|
return datetime.today().isoformat() if iso else datetime.today()
|
|
|
|
today = {"name": "today", "description": "Gets the current date and time", "target": DateTime()}
|
|
|
|
def current(iso: str) -> str:
|
|
"""
|
|
Gets the current date and time
|
|
|
|
Args:
|
|
iso: date will be converted to iso format if True
|
|
|
|
Returns:
|
|
current date and time
|
|
"""
|
|
|
|
return datetime.today().isoformat() if iso else datetime.today()
|
|
|
|
agent = Agent(tools=[today, current, "websearch"], llm="hf-internal-testing/tiny-random-LlamaForCausalLM", max_steps=1)
|
|
|
|
self.assertIsNotNone(agent)
|
|
self.assertIsInstance(agent.tools["today"](True), str)
|
|
self.assertIsInstance(agent.tools["current"](True), str)
|
|
|
|
def testToolsDefaults(self):
|
|
"""
|
|
Test default toolkit tools
|
|
"""
|
|
|
|
agent = Agent(tools=["defaults"], llm="hf-internal-testing/tiny-random-LlamaForCausalLM", max_steps=1)
|
|
|
|
# Working directory
|
|
work = tempfile.gettempdir()
|
|
|
|
# Test file
|
|
path = os.path.join(work, "agent_tools.txt")
|
|
agent.tools["write"](path, "hello world")
|
|
|
|
# Test default tools
|
|
self.assertIsNotNone(agent.tools["bash"](["ls", work]))
|
|
self.assertGreater(len(agent.tools["glob"](work)), 0)
|
|
self.assertGreater(len(agent.tools["grep"]("world", "*")), 0)
|
|
self.assertEqual(agent.tools["todowrite"]("plan"), "plan")
|
|
|
|
agent.tools["edit"](path, "hello", "goodbye")
|
|
self.assertEqual(agent.tools["read"](path), "goodbye world".strip())
|
|
|
|
def testToolsEmbeddings(self):
|
|
"""
|
|
Test adding Embeddings as a tool
|
|
"""
|
|
|
|
embeddings = Embeddings()
|
|
embeddings.index(["test"])
|
|
|
|
# Generate temp file path and save
|
|
index = os.path.join(tempfile.gettempdir(), "embeddings.agent")
|
|
embeddings.save(index)
|
|
|
|
embeddings1 = {
|
|
"name": "embeddings1",
|
|
"description": "Searches a test database",
|
|
"target": embeddings,
|
|
}
|
|
|
|
embeddings2 = {"name": "embeddings2", "description": "Searches a test database", "path": index}
|
|
|
|
agent = Agent(tools=[embeddings1, embeddings2], llm="hf-internal-testing/tiny-random-LlamaForCausalLM", max_steps=1)
|
|
|
|
self.assertIsNotNone(agent)
|
|
self.assertIsInstance(agent.tools["embeddings1"]("test"), list)
|
|
|
|
# pylint: disable=C0115,C0116
|
|
@patch("mcpadapt.core.MCPAdapt")
|
|
def testToolsMCP(self, mcp):
|
|
"""
|
|
Test adding a MCP tool collection
|
|
"""
|
|
|
|
class MCPAdapt:
|
|
def __init__(self, *args):
|
|
self.args = args
|
|
|
|
def tools(self):
|
|
return [PythonInterpreterTool()]
|
|
|
|
# Patch MCP adapter for testing
|
|
mcp.side_effect = MCPAdapt
|
|
|
|
agent = Agent(tools=["http://localhost:8000/mcp"], llm="hf-internal-testing/tiny-random-LlamaForCausalLM", max_steps=1)
|
|
self.assertEqual(len(agent.tools), 2)
|