# Client

> AgentClient is the async HTTP client for a served agent.

Source: https://docs.pyrula.io/agents/serving/client/

`AgentClient` submits, streams and cancels turns through the server's [HTTP routes](https://docs.pyrula.io/agents/serving/http.md).

```python
from pyrula.agents import AgentClient

client = AgentClient(
    "https://agents.example.com",
    headers={"Authorization": "Bearer ..."},   # sent on every call
    prefix="/agents",                           # default
    timeout=30.0,                               # per request, default; streams have no total cap
)

handle = await client.submit("support", message="where is my order?", metadata={"source": "web"})
async for event in client.stream("support", handle.turn_id):
    print(event.kind, event.payload)

events = await client.run("support", message="where is my order?")   # submit, drain to the end

info = await client.status("support", handle.turn_id)
await client.cancel("support", handle.turn_id, reason="user left")      # stops at next step boundary
await client.terminate("support", handle.turn_id)                       # ends now; no worker needed
```

`run` follows `continue_as_new` chains and returns every event. Keyword arguments to `submit` / `run` other than `metadata`, `idempotency_key` and `headers` are the agent's parameters.

`idempotency_key` on `submit` and `run` makes a retried submission return the existing turn.

## Reconnect

Pass `last_event_id` and the server resumes after it. If that id has fallen out of the live window the stream emits `stream:overflow`; `stream_with_replay_fallback` switches to `replay` (the full stored event list) for you:

```python
async for event in client.stream_with_replay_fallback("support", turn_id, last_event_id=seen):
    ...
```

`stream(..., idle_timeout_seconds=...)` gives up on a stream that goes silent.
