zeekayandHanzo Dev d5ce906725 ci: restore the image build under .hanzo/workflows
Every workflow in this repo was deleted and nothing replaced them, so the sole
producer of ghcr.io/hanzoai/agent no longer existed anywhere and there was no CI
at all. That is silent staleness: no failing run, just an artifact that quietly
stops being rebuilt.

.github/workflows now holds sync.yml and nothing else, copied verbatim from
universe infra/ci/sync.yml. It replaces a mirror-nudge file that POSTed
/api/v1/repos/.../mirror-sync and described git.hanzo.ai as a downstream pull
mirror; the forge is canonical and refs are pushed to it. Without it a
.hanzo/workflows file has nothing to trigger it.

deploy.yml restores docker-publish.yml. Two things could not come across as-is:

- Its body was one `uses: hanzoai/.github/.github/workflows/docker-build.yml@main`.
  A private cross-repo reusable workflow does not resolve on the forge, so the
  amd64 build/push is vendored inline, as hanzoai/bot already does.
- It built `context: control-plane`, and no control-plane directory exists on
  main; the orchestrator was hoisted to the root module in v0.1.1 and the
  directory survives only on the unmerged consolidate/held-work branch.
  Restoring that context restores a build that cannot run. It builds
  Dockerfile.sdk — the one Dockerfile on main whose context exists, previously
  referenced by nothing despite sdk-* tags being live on the image — and tags it
  sdk-* so the two Dockerfiles cannot collide in one tag namespace.

The tag rule is shell rather than docker/metadata-action, so it is two readable
lines with no action semantics to guess at, and it was tested standalone:
v* -> :sdk-X.Y.Z + :sdk-latest, main -> :sdk-sha-<sha7> + :sdk-latest.

ci.yml replaces tests.yml and test.yml, which checked the same things twice, the
second with `|| true` on most steps so it could not fail. It gates what is
verifiable on main today — gofmt/build/vet/test for the Go module, and the
locked install plus `import agents` for Python, which is what Dockerfile.sdk's
builder stage and HEALTHCHECK do. It deliberately does not run ruff, mypy or
pytest: `make sync` cannot resolve (requires-python >=3.9, a transitive numpy
needs >=3.10), ruff reports 2337 errors, and pytest INTERNALERRORs at collection
because a test module sys.exit(1)s at import. tests.yml ran `make sync` first in
all five jobs, so none of them could have gone green. Those four are written down
in LLM.md as work rather than shipped as a permanently red check, which gets read
as broken CI instead of broken code.

gofmt over eight files so that gate is real instead of omitted; build, vet and
test re-run green afterwards. Alignment whitespace only.

Not restored, with reasons in LLM.md: docs.yml (mkdocs gh-deploy is GitHub Pages,
never published anything, and Pages is not how we serve sites), publish.yml
(pointed at the PyPI package hanzoai/python-sdk owns; deliberately removed
earlier), issues.yml (upstream's stale-issue bot).

LLM.md documents the chain, records the four broken Python checks, and states
the open question this repo actually has: nothing in hanzoai/universe references
ghcr.io/hanzoai/agent, so the image has no consumer and no App CR.

.gitignore ignored .hanzo/ under an "# IDE" heading, which silently dropped
both new workflows from the commit — the same silent-staleness shape this is
meant to remove, one level down. Narrowed to .hanzo/* with .hanzo/workflows/
re-included.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-27 09:01:00 -07:00
2025-03-11 09:42:28 -07:00
2026-07-26 20:47:06 -07:00
2026-07-26 20:47:06 -07:00

agent

Hanzo Agent SDK

A powerful Python framework for building AI agents and multi-agent systems with built-in orchestration.

✨ Features

  • 🤖 Multi-Agent Networks: Build systems where multiple specialized agents collaborate
  • 🧠 Intelligent Routing: Semantic, rule-based, and load-balanced routing strategies
  • 🛠️ Powerful Tools: Enhanced tool system with MCP (Model Context Protocol) support
  • 📊 Shared State: Agents can share information through network state
  • 🔄 Orchestration: Define complex workflows with parallel, conditional, and loop steps
  • 💾 Memory System: Long-term memory with vector search and reflection capabilities
  • ⚡ UI Streaming: Real-time updates for building responsive interfaces
  • 🔍 Observability: Built-in tracing and monitoring via Hanzo Cloud dashboard
  • 🌐 Backend Flexibility: Use with Hanzo Router for 100+ LLM providers

Optional Extensions:

  • 💎 Web3 Integration ([web3]): Wallet management, transactions, on-chain identity
  • 🔒 TEE Support ([tee]): Intel SGX, AMD SEV, NVIDIA H100 attestation and confidential computing
  • 🛒 Marketplace ([marketplace]): Decentralized agent service discovery and economics
  • 💻 CLI ([cli]): Command-line interface integration

Core concepts:

  1. Agents: LLMs configured with instructions, tools, and memory
  2. Networks: Multi-agent systems with intelligent routing
  3. Workflows: Orchestrate complex multi-step processes
  4. State & Memory: Shared state and long-term memory
  5. Tools: Enhanced tool system with MCP support
  6. Tracing: Built-in tracking and observability

Explore the examples directory to see the SDK in action, and read our documentation for more details.

Notably, our SDK is compatible with any model providers that support the Open AI Chat Completions API format.

Get started

  1. Set up your Python environment
python -m venv env
source env/bin/activate
  1. Install Hanzo Agent SDK
# Basic installation
pip install hanzo-agent

# With Web3 support
pip install "hanzo-agent[web3]"

# With TEE support
pip install "hanzo-agent[tee]"

# With Marketplace support
pip install "hanzo-agent[marketplace]"

# With CLI support
pip install "hanzo-agent[cli]"

# Full installation (all extensions)
pip install "hanzo-agent[full]"

Quick Examples

Simple Agent

from agents import Agent, Runner

agent = Agent(name="Assistant", instructions="You are a helpful assistant")

result = Runner.run_sync(agent, "Write a haiku about recursion in programming.")
print(result.final_output)

# Code within the code,
# Functions calling themselves,
# Infinite loop's dance.

Multi-Agent Network

from agents import Agent
from agents.network import create_network, SemanticRouter

# Create specialized agents
researcher = Agent(
    name="Researcher",
    instructions="You find and analyze information.",
    tools=[search_tool, analyze_tool],
)

writer = Agent(
    name="Writer",
    instructions="You create content based on research.",
    tools=[format_tool],
)

# Create a network
network = create_network(
    agents=[researcher, writer],
    router=SemanticRouter(),
    default_model="gpt-4",
)

# Run the network
result = await network.run("Research and write about quantum computing")

Orchestrated Workflow

from agents import Agent
from agents.orchestration import Orchestrator, OrchestrationConfig

# Define agents (omitted: see Multi-Agent Network above)
researcher = Agent(name="researcher", instructions="...")
writer     = Agent(name="writer",     instructions="...")
reviewer   = Agent(name="reviewer",   instructions="...")

# Orchestrator owns the agent registry and workflow execution
orchestrator = Orchestrator(
    config=OrchestrationConfig(name="Content Pipeline"),
)
orchestrator.register_agent(researcher, capabilities=["research"])
orchestrator.register_agent(writer,     capabilities=["writing"])
orchestrator.register_agent(reviewer,   capabilities=["review"])

# Build a workflow from registered agents and execute it
workflow = orchestrator.create_workflow_from_agents(
    name="Article Workflow",
    agents=["researcher", "writer", "reviewer"],
)
orchestrator.register_workflow(workflow)

result = await orchestrator.execute_workflow(
    workflow_id=workflow.id,
    input="Research and write about AI safety.",
)
print(result.success, result.output)

For lower-level control — composing parallel, conditional, and loop steps directly — see agents.orchestration.Workflow plus the Step helpers (Step.agent, Step.parallel, Step.conditional, Step.loop).

(Configure backend with HANZO_ROUTER_URL and HANZO_API_KEY environment variables)

Handoffs example

from agents import Agent, Runner
import asyncio

spanish_agent = Agent(
    name="Spanish agent",
    instructions="You only speak Spanish.",
)

english_agent = Agent(
    name="English agent",
    instructions="You only speak English",
)

triage_agent = Agent(
    name="Triage agent",
    instructions="Handoff to the appropriate agent based on the language of the request.",
    handoffs=[spanish_agent, english_agent],
)


async def main():
    result = await Runner.run(triage_agent, input="Hola, ¿cómo estás?")
    print(result.final_output)
    # ¡Hola! Estoy bien, gracias por preguntar. ¿Y tú, cómo estás?


if __name__ == "__main__":
    asyncio.run(main())

Functions example

import asyncio

from agents import Agent, Runner, function_tool


@function_tool
def get_weather(city: str) -> str:
    return f"The weather in {city} is sunny."


agent = Agent(
    name="Hello world",
    instructions="You are a helpful agent.",
    tools=[get_weather],
)


async def main():
    result = await Runner.run(agent, input="What's the weather in Tokyo?")
    print(result.final_output)
    # The weather in Tokyo is sunny.


if __name__ == "__main__":
    asyncio.run(main())

The agent loop

When you call Runner.run(), we run a loop until we get a final output.

  1. We call the LLM, using the model and settings on the agent, and the message history.
  2. The LLM returns a response, which may include tool calls.
  3. If the response has a final output (see below for more on this), we return it and end the loop.
  4. If the response has a handoff, we set the agent to the new agent and go back to step 1.
  5. We process the tool calls (if any) and append the tool responses messages. Then we go to step 1.

There is a max_turns parameter that you can use to limit the number of times the loop executes.

Final output

Final output is the last thing the agent produces in the loop.

  1. If you set an output_type on the agent, the final output is when the LLM returns something of that type. We use structured outputs for this.
  2. If there's no output_type (i.e. plain text responses), then the first LLM response without any tool calls or handoffs is considered as the final output.

As a result, the mental model for the agent loop is:

  1. If the current agent has an output_type, the loop runs until the agent produces structured output matching that type.
  2. If the current agent does not have an output_type, the loop runs until the current agent produces a message without any tool calls/handoffs.

Common agent patterns

The Agent SDK is designed to be highly flexible, allowing you to model a wide range of LLM workflows including deterministic flows, iterative loops, and more. See examples in examples/agent_patterns.

Tracing

The Agent SDK automatically traces your agent runs, making it easy to track and debug the behavior of your agents. Tracing is extensible by design, supporting custom spans and a wide variety of external destinations, including Logfire, AgentOps, Braintrust, Scorecard, and Keywords AI. For more details about how to customize or disable tracing, see Tracing.

Development (only needed if you need to edit the SDK/examples)

  1. Ensure you have uv installed.
uv --version
  1. Install dependencies
make sync
  1. (After making changes) lint/test
make tests  # run tests
make mypy   # run typechecker
make lint   # run linter

Acknowledgements

We'd like to acknowledge the excellent work of the open-source community, especially:

We're committed to continuing to build the Agent SDK as an open source framework so others in the community can expand on our approach.

Extension Examples

Web3 Agent

from agents import Agent, Runner
from agents.extensions.web3 import Web3Agent, AgentWallet

# Create wallet for agent
wallet = AgentWallet.from_mnemonic("your mnemonic here")

# Create Web3-enabled agent
trader = Web3Agent(
    name="Crypto Trader",
    instructions="You are a cryptocurrency trading agent",
    wallet=wallet
)

# Agent can now use wallet tools
result = await Runner.run(trader, "Check my ETH balance")

TEE (Confidential) Agent

from agents import Agent, Runner
from agents.extensions.tee import ConfidentialAgent, TEEProvider

# Create agent that runs in TEE
confidential_agent = ConfidentialAgent(
    name="Secure Agent",
    instructions="You handle sensitive data",
    tee_provider=TEEProvider.INTEL_SGX
)

# Generate attestation
attestation = await confidential_agent.generate_attestation()
print(f"Attestation: {attestation.quote}")

Marketplace Agent

from agents import Agent
from agents.extensions.marketplace import AgentMarketplace, ServiceOffer, ServiceType

# Create agent that offers services
service_agent = Agent(
    name="Research Agent",
    instructions="You conduct research"
)

# Create service offer
offer = ServiceOffer(
    id="research-1",
    agent_address="0x...",
    agent_name="Research Agent",
    service_type=ServiceType.RESEARCH,
    price_eth=0.01,
    description="Comprehensive research services"
)

# Register on marketplace
marketplace = AgentMarketplace()
await marketplace.register_offer(offer)
S
Description
No description provided
Readme MIT
19 MiB
Languages
Python 80.1%
Go 11.2%
TypeScript 7.3%
Shell 0.9%
PowerShell 0.4%