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]>
90 lines
2.5 KiB
Python
90 lines
2.5 KiB
Python
import asyncio
|
|
import httpx
|
|
import pytest
|
|
|
|
from hanzo_agents.agent import Agent
|
|
from hanzo_agents.client import HanzoAgentsClient
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_reasoner_async_mode_sends_status(monkeypatch):
|
|
agent = Agent(
|
|
node_id="test-agent", hanzo_agents_server="http://control", auto_register=False
|
|
)
|
|
|
|
@agent.reasoner()
|
|
async def echo(value: int) -> dict:
|
|
await asyncio.sleep(0)
|
|
return {"value": value}
|
|
|
|
recorded = []
|
|
|
|
class DummyResponse:
|
|
def __init__(self, status_code: int = 200):
|
|
self.status_code = status_code
|
|
|
|
def json(self):
|
|
return {}
|
|
|
|
async def fake_request(self, method, url, **kwargs):
|
|
recorded.append({"method": method, "url": url, "json": kwargs.get("json")})
|
|
return DummyResponse(200)
|
|
|
|
monkeypatch.setattr(HanzoAgentsClient, "_async_request", fake_request)
|
|
|
|
async with httpx.AsyncClient(
|
|
transport=httpx.ASGITransport(app=agent), base_url="http://agent"
|
|
) as client:
|
|
response = await client.post(
|
|
"/reasoners/echo",
|
|
json={"value": 7},
|
|
headers={"X-Execution-ID": "exec-123"},
|
|
)
|
|
|
|
assert response.status_code == 202
|
|
await asyncio.sleep(0.1)
|
|
|
|
status_calls = [entry for entry in recorded if "/executions/" in entry["url"]]
|
|
assert status_calls, "expected async status callback"
|
|
payload = status_calls[-1]["json"]
|
|
assert payload["status"] == "succeeded"
|
|
assert payload["result"]["value"] == 7
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_post_execution_status_retries(monkeypatch):
|
|
agent = Agent(
|
|
node_id="test-agent", hanzo_agents_server="http://control", auto_register=False
|
|
)
|
|
|
|
attempts = {"count": 0}
|
|
|
|
class DummyResponse:
|
|
def __init__(self, status_code: int):
|
|
self.status_code = status_code
|
|
|
|
async def fake_request(self, method, url, **kwargs):
|
|
attempts["count"] += 1
|
|
if attempts["count"] < 3:
|
|
raise RuntimeError("transient error")
|
|
return DummyResponse(200)
|
|
|
|
monkeypatch.setattr(HanzoAgentsClient, "_async_request", fake_request)
|
|
|
|
sleeps = []
|
|
|
|
async def fake_sleep(delay):
|
|
sleeps.append(delay)
|
|
|
|
monkeypatch.setattr(asyncio, "sleep", fake_sleep)
|
|
|
|
await agent._post_execution_status(
|
|
"http://control/v1/executions/exec-1/status",
|
|
{"status": "running"},
|
|
"exec-1",
|
|
max_retries=5,
|
|
)
|
|
|
|
assert attempts["count"] == 3
|
|
assert sleeps == [1, 2]
|