Agents API
List, activate/suspend, message, and inspect agents. Agents themselves are provisioned by installing a competency/agent package via the catalog API — there is no POST /agents (create) or POST /agents/{id}/clone endpoint.
Endpoints
| Method | Path | Action | Description |
|---|---|---|---|
| GET | /agents | AgentList | List all agents |
| GET | /agents/{id} | AgentStatus | Get agent status + invocation metrics |
| PUT | /agents/{id} | AgentUpdate | Update agent properties |
| POST | /agents/{id}/activate | AgentStart | Activate a suspended agent |
| POST | /agents/{id}/suspend | AgentStop | Suspend a running agent |
| POST | /agents/{id}/send | AgentSendMessage | Send a free-text message, get a reply |
| POST | /agents/{id}/invoke | AgentInvoke | Invoke with structured InvocationContext |
| PUT | /agents/{id}/model | AgentUpdate | Change the agent's model |
| GET | /agents/{id}/tools | AgentStatus | Get agent tools |
| GET | /agents/{id}/skills | AgentStatus | Get agent skills |
| POST | /agents/{id}/session/reset | AgentUpdate | Reset conversation session (clears the canonical cross-channel session) |
| DELETE | /agents/{id}/history | AgentUpdate | Clear conversation history (clears all per-channel sessions + the canonical session) |
| GET | /agents/{id}/session | SessionRead | Get the agent's current session |
| GET | /agents/{id}/sessions | SessionRead | List sessions for the agent |
| GET | /sessions | SessionRead | List sessions across all agents |
There is no PUT /agents/{id}/tools or PUT /agents/{id}/skills — the competency install/upgrade path (ADR-044) is the only way to change what an agent can do. The GET variants remain for read/display.
Current-build note:
PUT /agents/{id}andPUT /agents/{id}/modelare wired at the HTTP layer but theirHozironPlatformimplementations are stubs today (crates/platform/hoziron-core/src/platform.rs): they validate the agent ID, return200, and otherwise no-op.get_agent_tools/get_agent_skillsalways return[](TODO: populate from the kernel tool registry).POST /agents/{id}/session/resetandDELETE /agents/{id}/historyare real (Issue #683) — see their sections below. Don't build a demo flow aroundPUT /agents/{id}orPUT /agents/{id}/modelactually changing agent behavior yet;/agents/{id}/send,/agents/{id}/invoke,/agents/{id}/activate,/agents/{id}/suspend, and the list/status/session-read/session-reset/history-clear endpoints are fully live.
GET /agents
List all registered agents.
curl -H "Api-Version: v1" -H "Authorization: Bearer hzn_sk_..." \
http://localhost:4200/agents
Response (200)
{
"agents": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "claims-agent",
"title": "Claims Intake Agent",
"state": "Running",
"equipped_competencies": ["claims-intake"]
}
]
}
state is one of Running / Suspended — there is no Created state; an agent exists in one of those two states from the moment its owning package activates it. equipped_competencies is an ordered list (an agent may have more than one), and is omitted entirely from the JSON when empty. title is the display title from the source template's MANIFEST.toml, resolved by matching name back to the installed template — null if no surviving template matches. There is no triggers field — agents do not declare accepted invocation sources — see invocation-model.md.
GET /agents/{id}
Get detailed agent status including invocation metrics.
curl -H "Api-Version: v1" -H "Authorization: Bearer hzn_sk_..." \
http://localhost:4200/agents/550e8400-e29b-41d4-a716-446655440000
Response (200)
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "claims-agent",
"state": "Running",
"equipped_competencies": ["claims-intake"],
"uptime": 51735000,
"tasks_received": 142,
"tasks_completed": 140,
"invocation_metrics": {
"total_count": 142,
"error_count": 2,
"avg_duration_ms": 2100,
"by_source": [["Api", 120, 1, 2050], ["Cron", 22, 1, 2400]]
}
}
uptime is milliseconds (not seconds). The agent-level trust_policy field is never serialized (ADR-049 — PII policy is carrier-owned via carrier-pii-policy.toml, not per-agent). See the PII Engine guide.
Error (404)
{"error": {"category": "NotFound", "message": "Agent not found: 550e8400-...", "details": {"agent_id": "550e8400-..."}}}
PUT /agents/{id}
Accepts an arbitrary JSON object of updates (serde_json::Value — no fixed request schema is validated at the HTTP layer today).
curl -X PUT -H "Api-Version: v1" -H "Authorization: Bearer hzn_sk_..." \
-H "Content-Type: application/json" \
-d '{"system_prompt": "You are an updated claims processor."}' \
http://localhost:4200/agents/550e8400-e29b-41d4-a716-446655440000
Response (200)
{"status": "updated"}
POST /agents/{id}/activate
Activate a suspended agent.
curl -X POST -H "Api-Version: v1" -H "Authorization: Bearer hzn_sk_..." \
http://localhost:4200/agents/550e8400-e29b-41d4-a716-446655440000/activate
Response (200)
Empty body (200 OK, no JSON payload).
POST /agents/{id}/suspend
Suspend a running agent.
curl -X POST -H "Api-Version: v1" -H "Authorization: Bearer hzn_sk_..." \
http://localhost:4200/agents/550e8400-e29b-41d4-a716-446655440000/suspend
Response (200)
Empty body.
POST /agents/{id}/send
Send a free-text message to an agent and receive its reply synchronously.
curl -X POST -H "Api-Version: v1" -H "Authorization: Bearer hzn_sk_..." \
-H "Content-Type: application/json" \
-d '{"message": "How many open claims are there today?"}' \
http://localhost:4200/agents/550e8400-e29b-41d4-a716-446655440000/send
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
message | string | Yes | Message text to send |
Response (200)
{
"content": "There are currently 23 open claims in the queue.",
"tool_calls": [],
"tokens_used": 342
}
Note: there is no latency_ms field in this response (AgentResponse — content, tool_calls, tokens_used only). tool_calls is a list of {"tool_name", "skill_id", "duration_ms", "success"} records when tools were invoked.
POST /agents/{id}/invoke
Invoke an agent with a structured InvocationContext — the programmatic-integration path (webhooks, cron, channel bridges all funnel through this same context shape).
curl -X POST -H "Api-Version: v1" -H "Authorization: Bearer hzn_sk_..." \
-H "Content-Type: application/json" \
-d '{
"source": "Api",
"message": "Process this claim",
"idempotency_key": "req-123",
"correlation_id": "corr-abc",
"workflow_type": "fnol"
}' \
http://localhost:4200/agents/550e8400-e29b-41d4-a716-446655440000/invoke
Request Body (InvocationContext)
| Field | Type | Required | Description |
|---|---|---|---|
source | string/object | Yes | "Api", or an object for Channel/Cron sources |
message | string | Yes | The payload to deliver to the agent |
idempotency_key | string | No | Dedup key — a repeat call returns the cached result with error.category = "DuplicateInvocation" and HTTP 200 |
correlation_id | string | Yes | Tracing correlation ID |
workflow_type | string | No | Workflow type for transaction-budget gating (e.g. "fnol", "endorsement") |
Response (200) — InvocationResult
{
"content": "Claim processed successfully. Claim number: CLM-2026-143",
"tokens_used": 512,
"duration_ms": 3200,
"correlation_id": "corr-abc",
"source": "Api"
}
PUT /agents/{id}/model
Change the model assigned to an agent. Stub today — accepts and validates the body, returns 200, but does not actually change routing (see the note above; ADR-053 also establishes that routing is provider/model-inventory driven from config.toml, not per-agent-mutable).
curl -X PUT -H "Api-Version: v1" -H "Authorization: Bearer hzn_sk_..." \
-H "Content-Type: application/json" \
-d '{"model_id": "llama3.2", "provider": "ollama"}' \
http://localhost:4200/agents/550e8400-e29b-41d4-a716-446655440000/model
Response (200)
{"status": "model_updated"}
GET /agents/{id}/tools
Returns {"tools": []} unconditionally (not yet wired to the kernel tool registry). There is no PUT /agents/{id}/tools — installing/upgrading the agent's competency is the only supported way to change its tools.
GET /agents/{id}/skills
Same stub behavior as tools: returns {"skills": []}. There is no PUT /agents/{id}/skills, for the same reason as PUT /agents/{id}/tools above.
POST /agents/{id}/session/reset
Clears the agent's canonical (cross-channel) session — the live conversation context injected into every future invocation. Mirrors the same clear the platform already performs internally after a model switch ("prevent memory poisoning from old model's responses"): a soft reset that starts the conversation fresh without deleting the per-channel session transcripts (GET /agents/{id}/sessions still lists them). Use DELETE /agents/{id}/history to erase those too. Returns 404 if no agent with the given ID exists.
curl -X POST -H "Api-Version: v1" -H "Authorization: Bearer hzn_sk_..." \
http://localhost:4200/agents/550e8400-e29b-41d4-a716-446655440000/session/reset
Response (200)
{"status": "reset"}
DELETE /agents/{id}/history
Hard-deletes every per-channel session transcript for the agent, plus the canonical session — mirroring the same cascade full agent teardown (kill_agent) performs. Returns 404 if no agent with the given ID exists.
Response (204)
No content.
GET /agents/{id}/session
curl -H "Api-Version: v1" -H "Authorization: Bearer hzn_sk_..." \
http://localhost:4200/agents/550e8400-e29b-41d4-a716-446655440000/session
Response (200)
{"agent_id": "550e8400-e29b-41d4-a716-446655440000", "state": "Running", "messages": []}
messages is currently always empty — session transcript retrieval is not yet implemented behind this endpoint.
GET /agents/{id}/sessions
{"sessions": [{"agent_id": "550e8400-...", "state": "Running"}]}
GET /sessions
Lists a session summary row per agent across the whole platform.
{
"sessions": [
{"agent_id": "550e8400-...", "agent_name": "claims-agent", "state": "Running"}
]
}
Related
- workflows.md — multi-agent pipelines that invoke agents as steps
- memory.md — per-agent KV store
- schedules.md — non-API invocation sources
- competencies.md — how an agent's capability set is composed