mirror of
https://github.com/hanzoai/agents.git
synced 2026-10-30 18:48:36 +00:00
- A rebrand wrote "Hanzo Agents" into identifiers, so the conftest did not
parse and no test ran.
- The client built {url}/api/v1; the control plane serves /v1. Notes append
/ui to the base instead of rewriting its first /v1.
- BaseMemory stands where MemoryClient stands; pass it to Agent as `store`. It
binds to the running execution, so scope ids resolve as the control plane
resolves them, and a read without a scope walks workflow, session, actor and
global.
- The web3 extension declares eth-account as an extra, and stops exporting two
modules that import packages this SDK does not have.
- A heartbeat test waits for the state it asserts instead of sleeping.
Co-authored-by: Hanzo Dev <[email protected]>
148 lines
4.0 KiB
Python
148 lines
4.0 KiB
Python
import asyncio
|
|
import sys
|
|
from types import SimpleNamespace
|
|
|
|
import pytest
|
|
|
|
from hanzo_agents.agent import Agent
|
|
from hanzo_agents.agent_registry import get_current_agent_instance
|
|
from hanzo_agents.execution_context import (
|
|
ExecutionContext,
|
|
set_execution_context,
|
|
reset_execution_context,
|
|
)
|
|
|
|
|
|
def make_agent_stub():
|
|
agent = object.__new__(Agent)
|
|
agent.node_id = "node"
|
|
agent.hanzo_agents_server = "http://hanzo_agents"
|
|
agent.dev_mode = False
|
|
agent.async_config = SimpleNamespace(
|
|
enable_async_execution=True, fallback_to_sync=True
|
|
)
|
|
agent._async_execution_manager = None
|
|
agent._current_execution_context = None
|
|
agent.client = SimpleNamespace(api_base="http://hanzo_agents/v1")
|
|
return agent
|
|
|
|
|
|
def test_get_current_execution_context_creates_and_reuses():
|
|
agent = make_agent_stub()
|
|
ctx1 = agent._get_current_execution_context()
|
|
assert isinstance(ctx1, ExecutionContext)
|
|
assert agent._current_execution_context is ctx1
|
|
|
|
# Thread-local context should override agent-level
|
|
token = set_execution_context(ctx1)
|
|
try:
|
|
ctx2 = agent._get_current_execution_context()
|
|
assert ctx2 is ctx1
|
|
finally:
|
|
reset_execution_context(token)
|
|
|
|
# Clearing agent-level should create new context
|
|
agent._current_execution_context = None
|
|
ctx3 = agent._get_current_execution_context()
|
|
assert ctx3 is not ctx1
|
|
|
|
|
|
def test_set_as_current_updates_agent_registry():
|
|
agent = make_agent_stub()
|
|
|
|
agent._clear_current()
|
|
assert get_current_agent_instance() is None
|
|
|
|
agent._set_as_current()
|
|
assert get_current_agent_instance() is agent
|
|
|
|
agent._clear_current()
|
|
assert get_current_agent_instance() is None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cleanup_async_resources(monkeypatch):
|
|
agent = make_agent_stub()
|
|
|
|
class DummyManager:
|
|
def __init__(self):
|
|
self.stopped = False
|
|
|
|
async def stop(self):
|
|
self.stopped = True
|
|
|
|
manager = DummyManager()
|
|
agent._async_execution_manager = manager
|
|
await agent._cleanup_async_resources()
|
|
assert manager.stopped is True
|
|
assert agent._async_execution_manager is None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_note_sends_async_request(monkeypatch):
|
|
agent = make_agent_stub()
|
|
|
|
called = {}
|
|
|
|
class DummyTimeout:
|
|
def __init__(self, total):
|
|
self.total = total
|
|
|
|
class DummySession:
|
|
def __init__(self, timeout):
|
|
self.timeout = timeout
|
|
|
|
async def __aenter__(self):
|
|
return self
|
|
|
|
async def __aexit__(self, exc_type, exc, tb):
|
|
return False
|
|
|
|
def post(self, url, json=None, headers=None):
|
|
called["url"] = url
|
|
called["json"] = json
|
|
called["headers"] = headers
|
|
|
|
class DummyResponse:
|
|
status = 200
|
|
|
|
async def __aenter__(self_inner):
|
|
return self_inner
|
|
|
|
async def __aexit__(self_inner, exc_type, exc, tb):
|
|
return False
|
|
|
|
async def text(self_inner):
|
|
return "ok"
|
|
|
|
return DummyResponse()
|
|
|
|
stub_aiohttp = SimpleNamespace(
|
|
ClientTimeout=DummyTimeout, ClientSession=DummySession
|
|
)
|
|
monkeypatch.setitem(sys.modules, "aiohttp", stub_aiohttp)
|
|
monkeypatch.setattr("hanzo_agents.agent.aiohttp", stub_aiohttp)
|
|
|
|
context = SimpleNamespace(to_headers=lambda: {"X-Workflow-ID": "wf"})
|
|
monkeypatch.setattr(agent, "_get_current_execution_context", lambda: context)
|
|
|
|
tasks = []
|
|
|
|
class DummyLoop:
|
|
def is_running(self):
|
|
return True
|
|
|
|
def create_task(self, coro):
|
|
task = asyncio.ensure_future(coro)
|
|
tasks.append(task)
|
|
return task
|
|
|
|
monkeypatch.setattr("asyncio.get_event_loop", lambda: DummyLoop())
|
|
|
|
agent.note("hello", tags=["debug"])
|
|
await asyncio.gather(*tasks)
|
|
|
|
assert called["url"].startswith("http://hanzo_agents/v1/ui")
|
|
assert called["json"]["message"] == "hello"
|
|
assert called["json"]["tags"] == ["debug"]
|