---
title: Agents
description: Create AI agents and run them against conversations.
---
## List agents
```python
result = client.agents.list()
for agent in result: # ListResponse is iterable
print(agent.name)
result.meta # {"total": 3}
```
## Create an agent
```python
agent = client.agents.create(
name="Hotel Concierge",
system_prompt="You are a hotel operations agent...",
business_account_id="acc_01hx...",
)
agent.id # "agt_01hx..."
agent.name # "Hotel Concierge"
```
### With structured fields
Define `payload_schema` to enforce specific fields in the AI output payload:
```python
agent = client.agents.create(
name="Hotel Concierge",
system_prompt="Extract structured tasks from hotel guest messages.",
payload_schema=[
{"name": "room_number", "field_type": "text", "required": True},
{"name": "description", "field_type": "text", "required": True},
{"name": "due_at", "field_type": "datetime", "required": False},
{"name": "priority", "field_type": "text", "required": False},
],
)
```
Available field types: `text`, `number`, `boolean`, `date`, `time`, `datetime`. Max 10 fields.
### With allowed action types
By default, the AI can return any action type (free-form). Set `allowed_actions` to constrain it to a specific list — the AI **can only return values from this list**.
```python
agent = client.agents.create(
name="Support Agent",
system_prompt="Handle customer support requests.",
allowed_actions=[
"support.refund.process",
"support.ticket.create",
"support.escalation.request",
],
)
```
Format: `domain.resource.action` (snake_case, 3 segments). Max 10 action types.
When a run completes, every action's `type` is guaranteed to be in this list:
```python
run = agent.run(input={"last_message": "I want a refund for order #1234"})
for action in run.actions:
match action["type"]:
case "support.refund.process":
process_refund(action["payload"])
case "support.ticket.create":
create_ticket(action["payload"])
case "support.escalation.request":
notify_escalation(action["payload"])
```
Without `allowed_actions`, the AI invents action types freely — useful for prototyping but unpredictable in production. Add constraints once you know your action types.
`required` instructs the AI to always fill the field — it does not guarantee a value.
Always validate on your end before processing actions.
## Retrieve an agent
```python
agent = client.agents.retrieve("agt_01hx...")
agent.is_active # True
agent.is_auto_run # False
```
## Update an agent
```python
agent = client.agents.update("agt_01hx...", name="Updated Concierge")
```
## Delete an agent
```python
client.agents.delete("agt_01hx...") # True
```
## Run an agent
Creates a run and polls until complete (blocks). The run is processed asynchronously on the server.
```python
# String input (auto-wrapped as last_message)
run = agent.run(input="Clean room 204 tomorrow at 8")
# Dict input (full control)
run = agent.run(input={
"last_message": "Clean room 204 tomorrow at 8",
"recent_messages": ["Hi, I have a request"],
})
run.status # "completed"
run.intent # "task_extraction"
run.confidence # 0.95
run.actions # [{"type": "hospitality.room_service.request", "payload": {...}}]
run.suggested_reply # "I'll arrange cleaning for room 204 tomorrow at 8am."
run.context_summary # "Guest requested room 204 cleaning for tomorrow 8am."
```
### Async (non-blocking)
```python
run = agent.run_async(input="Clean room 204 tomorrow at 8")
run.status # "pending"
# ... do other things ...
run.wait(timeout=30) # blocks until completed
```
## List runs
```python
# From an agent object
runs = agent.runs().list()
# From the client
runs = client.agent_runs("agt_01hx...").list()
```
## Retrieve a run
```python
run = client.agent_runs("agt_01hx...").retrieve("run_01hx...")
```
## Dispatch actions with a registry
Use an `ActionRegistry` to route agent actions to your handlers:
```python
from whatsrb_cloud import ActionRegistry
registry = ActionRegistry()
registry.register("create_task", lambda payload: create_task(
description=payload["description"],
room_number=payload["room_number"],
priority=payload["priority"],
))
registry.register("create_ticket", lambda payload: create_ticket(
message=payload["message"],
))
# Dispatch all actions from a completed run
run = agent.run(input={"last_message": "Fix the AC in room 107"})
run.dispatch(registry)
```
See [Registries](/sdks/python/registries) for the full guide.
## Action confirmation
When an agent has `confirmation_mode="confirm"`, actions require human validation before dispatch.
```python
# Enable confirmation mode
agent = client.agents.update("agt_xxx",
confirmation_mode="confirm",
confirmation_timeout_minutes=30
)
# Run the agent
run = agent.run(input="I want a refund for order #1234")
# Review action_statuses
run.action_statuses # [{"status": "pending", ...}, ...]
# Confirm specific actions (by index)
run.confirm_actions([0, 2])
# Reject specific actions (by index)
run.reject_actions([1])
# Dispatch only executes confirmed actions
run.dispatch(registry)
```
See [Action Confirmation](/guides/action-confirmation) for the full guide.
## Agent attributes
| Attribute | Type | Description |
|-----------|------|-------------|
| `id` | str | Agent ID (`agt_...`) |
| `name` | str | Agent name |
| `description` | str | Agent description |
| `model` | str | Model used (`gpt-4o-mini`) |
| `temperature` | float | LLM temperature |
| `max_tokens` | int | Max output tokens |
| `active` | bool | Whether agent is active |
| `auto_run_inbound` | bool | Auto-process inbound messages |
| `debounce_seconds` | int | Batch window for rapid messages |
| `context_ttl_minutes` | int | Conversation context TTL (default 60) |
| `business_account_id` | str | Linked business account |
| `allowed_actions` | list | Allowed action types (empty = free-form) |
| `payload_schema` | list | Structured field definitions |
| `confirmation_mode` | str | `auto` or `confirm` |
| `confirmation_timeout_minutes` | int | Timeout for unconfirmed actions (default 30) |
| `is_active` | bool | Whether agent is active |
## AgentRun attributes
| Attribute | Type | Description |
|-----------|------|-------------|
| `id` | str | Run ID (`run_...`) |
| `agent_id` | str | Parent agent ID |
| `status` | str | `pending`, `running`, `completed`, `failed` |
| `triggered_by` | str | `api`, `auto_inbound` |
| `output` | dict | Full agent output |
| `error` | str | Error message if failed |
| `model_used` | str | LLM model used |
| `input_tokens` | int | Tokens consumed |
| `output_tokens` | int | Tokens generated |
| `latency_ms` | int | LLM response latency |
| `duration_ms` | int | Total run duration |
| `intent` | str | Shortcut for `output["intent"]` |
| `confidence` | float | Shortcut for `output["confidence"]` |
| `actions` | list | Shortcut for `output["actions"]` |
| `suggested_reply` | str | Suggested reply in customer's language |
| `context_summary` | str | Conversation state for continuity |
| `action_statuses` | list | Per-action confirmation statuses (null in auto mode) |
| `actions_decided_at` | str | Timestamp when all actions were decided |
| `is_pending` | bool | Status is pending |
| `is_completed` | bool | Status is completed |
| `is_failed` | bool | Status is failed |