| name | cuga-build-agent |
| description | Use when the user wants to write Python code that creates or invokes a CugaAgent or CugaSupervisor, e.g. "build an agent with cuga", "how do I call agent.invoke", "set up a multi-agent supervisor". |
Building with the CugaAgent SDK
Single agent
from cuga import CugaAgent
from langchain_core.tools import tool
import asyncio
@tool
def add_numbers(a: int, b: int) -> int:
"""Add two numbers together"""
return a + b
agent = CugaAgent(tools=[add_numbers])
async def main():
result = await agent.invoke("What is 5 + 3?")
print(result.answer)
asyncio.run(main())
Key points:
- Tools are plain LangChain
@tool-decorated functions (or an OpenAPI/MCP provider — see cuga-build-tool).
await agent.invoke(message, thread_id=...) — thread_id isolates conversation state per user/session; omit it for a one-off call.
agent.stream() gives real-time execution events instead of a single final result.
agent.policies is the entry point for attaching Intent Guard / Playbook / Tool Approval / Tool Guide / Output Formatter policies programmatically — see cuga-author-policy.
- Knowledge/RAG is on by default (
enable_knowledge=True) — see cuga-knowledge-rag; pass enable_knowledge=False to turn it off.
- The underlying LangGraph graph is reachable for advanced use cases (custom nodes, inspecting state) if the simple API isn't enough.
Multi-agent (CugaSupervisor)
from cuga import CugaAgent, CugaSupervisor
from langchain_core.tools import tool
import asyncio
@tool
def get_customers(limit: int = 10) -> str:
"""Fetch top customers from CRM."""
return "Alice ($250k); Bob ($180k)"
@tool
def send_email(to: str, body: str) -> str:
"""Send an email."""
return f"Email sent to {to}"
async def main():
crm_agent = CugaAgent(tools=[get_customers])
crm_agent.description = "CRM and customer data"
email_agent = CugaAgent(tools=[send_email])
email_agent.description = "Sending emails and notifications"
supervisor = CugaSupervisor(agents={"crm": crm_agent, "email": email_agent})
result = await supervisor.invoke("Get our top customer and email them a thank-you")
print(result.answer)
asyncio.run(main())
- Each sub-agent needs a
.description — the supervisor uses it to decide who handles what.
- Mix local
CugaAgents with remote agents via A2A: pass an "agent_name": {"type": "external", "description": "...", "config": {"a2a_protocol": {...}}} entry in agents=.
- Pass data between sub-agents with
variables=["var_name"].
CugaSupervisor.from_yaml("path/to/config.yaml") loads agents from a config file instead of constructing them in code.
- Try it live first:
uv run cuga start demo_supervisor (see cuga-install-and-launch).
Reference
Full SDK docs: https://docs.cuga.dev/docs/sdk/cuga_agent/ and https://docs.cuga.dev/docs/sdk/cuga_supervisor