context and yields events. Cycls
wraps it in a web application, a streaming protocol, per-user storage and a
managed model loop.
agent.py
The decorator
What the managed loop does
llm.run(context=context) is the default loop. Yielding its events through your
body is all a normal agent needs.
Model calls and streaming
Text, reasoning and tool-call deltas from Anthropic natively and from any
OpenAI-compatible endpoint.
Tool execution
Built-in tools and your handlers, run in parallel where the provider sends a
batch, with results fed back to the model.
Retries and recovery
Transient provider failures are retried with backoff. Context overflow
triggers one compaction and a replay.
Compaction
When the window fills, older turns are summarized behind an append-only
marker so the conversation continues.
Persistence
The user’s turn is written to disk before the model is called, so a dropped
connection never loses it.
Cost accounting
Every turn logs tokens and cost when
.price() is set, queryable with
cycls cost and cycls sql.A turn, end to end
Yielding your own events
The body is ordinary Python, so you can emit anything before, during or after the loop. Events are plain dicts, and strings are markdown text.Watching the loop
Events are dicts, so a plain check is enough to react without changing behavior.cycls.to_ui(ev) still appears in older examples. It is now an identity function
kept for backwards compatibility, so yield ev and yield cycls.to_ui(ev) do
the same thing.Adding HTTP routes
An agent is also a web service. Use.server for webhooks, health checks and
OAuth callbacks, and Depends(my_agent.auth) to protect a route with the same
identity the chat endpoint uses.
Next steps
Models
Providers, reasoning, budgets and pricing.
Tools
Built-in tools and your own handlers.
Context
Messages, users, workspaces and per-request switches.
Custom loops
Replace the default loop while keeping the kit.