Installing Agno v3
If you are already using Agno, you can upgrade to v3 by running:Migrating your Agno DB
The built-in migration makes two schema changes:- Session runs move to their own table. In v2, every session row held its
full run history as a single JSON blob in the
runscolumn. In v3, each run is its own row in a dedicated runs table (agno_runsby default), which removes the write amplification and unbounded row growth of the blob design. - A
user_idcolumn (with index) is added to the evals, components, knowledge, schedules, schedule-runs and metrics tables, for user isolation. The metrics unique key changes from(date, aggregation_period)to includeuser_id.
migrate_to_v3.py
libs/agno/migrations/v2_to_v3
(migrate_sql_vectordbs.py, migrate_field_vectordbs.py or
migrate_sentinel_vectordbs.py, depending on your vector store) to add
user_id scoping to existing collections. Un-migrated tables raise a
ValueError on user-scoped searches instead of returning empty results.
Notes:
- The migration is non-destructive and idempotent: the legacy
runscolumn is preserved as a backup, and re-running the migration never duplicates runs. - Reads keep working before, during and after the migration. Sessions merge the runs table with any legacy blob, so an un-migrated session still shows its history.
cleanup_legacy_runs_column()refuses to run while legacy data is present unless you passforce=True. Only passforce=Trueafter Step 2 passes. Cleanup permanently deletes the blob, which is the only copy of your history if the migration did not actually copy it.- Supported everywhere sessions are stored: Postgres, MySQL, SQLite, SingleStore (+ async variants), MongoDB, Redis, Valkey, Firestore, DynamoDB, SurrealDB, JSON, and GCS JSON.
Migrating your Agno code
Each section covers one breaking change, with before and after examples.1. Sessions and runs (denormalization)
Reading sessions is unchanged.session.runs is still populated, now from the
runs table:
v3_sessions.py
runs column of the sessions table directly (SQL, dashboards,
exports), point those queries at the runs table instead. After cleanup the
column no longer exists:
2. Workflow HITL: flat kwargs → HumanReview
Workflow primitives no longer accept flat HITL kwargs. All human-in-the-loop
configuration lives in one HumanReview object.
This is how it looked in v2:
v2_hitl.py
v3_hitl.py
HumanReview, except
hitl_max_retries → max_retries and hitl_timeout → timeout. This applies
to Step, Steps, Loop, Condition and Router.
3. Removed and renamed parameters
These deprecated parameters have been removed. Update them to their v3 names:Agent and Team constructors:
v3_agent_params.py
continue_run / acontinue_run: the updated_tools parameter is removed.
Pass requirements (a list of RunRequirement, available on the paused run
output) instead of a modified ToolExecution list:
v3_continue_run.py
authorization_config: secret_key is removed. Use
verification_keys, which takes a list:
v3_jwt.py
MCPToolbox: auth_tokens and auth_headers are removed. Use
auth_token_getters (same shape: a mapping of auth source names to token
callables).
4. Reasoning requires an explicit model
Thereasoning=True shortcut has been removed. Pass a native reasoning model
explicitly:
v2_reasoning.py
v3_reasoning.py
5. Team and Workflow constructors are keyword-only
Positional arguments are no longer accepted:
v2_team.py
v3_team.py
6. User isolation: user_id across the platform
With user_isolation enabled on AgentOS, data is now scoped per user across
memories, knowledge, evals, metrics, schedules and vector databases, in
addition to sessions. What this means for your code and data:
user_idcolumns were added to the schedules, schedule-runs and evals tables; the built-in migration handles this.- Metrics aggregate per user: the unique key changed from
(date, aggregation_period)to(user_id, date, aggregation_period). Deployments without isolation see the same single-row-per-date shape as before; sessions without auser_idaggregate into a shared bucket. - Vector database collections created before v3 have no per-user scoping. When
isolation is on, searching them with a
user_idraises aValueErrortelling you to run the vector database migration. This is deliberate: an un-migrated table fails loudly instead of silently returning empty results.
7. Background execution and durable queues
background=True on AgentOS is rebuilt around a durable job queue. In v2 it
spawned an unbounded asyncio.create_task, and a process death silently lost
every waiting and in-flight run. In v3:
- Accepted requests are committed rows that survive crashes, restarts and deploys; any replica’s worker can execute them.
- Runs are bounded by a concurrency cap; excess submissions wait in the
queue in
pendingstatus instead of overloading the process. - Every run can be watched (
stream=truetails), resumed after a disconnect (/resume) and cancelled from any replica. Idempotency-Keyheaders deduplicate resubmissions.- Redis is optional coordination (live event streams, cross-replica cancellation), never truth. A Redis fault degrades the live view; it cannot lose or corrupt a run.
db on the agent
(enforced with a 400), run status now transitions pending → running → completed (poll GET /agents/{id}/runs/{run_id} for the terminal state), and
external framework agents (LangGraph, Claude, etc.) stream inline, so their
runs are not resumable.
8. Culture feature removed
The experimental culture feature (enable_agentic_culture,
add_culture_to_context, CulturalKnowledge, the agno_culture table) has
been removed. Remove any references; if you need shared knowledge across users,
use Knowledge instead.
9. Smaller changes
- Async tools run in sync runs: v2’s
agent.run()raised when the agent had async tools, forcingarun(). v3 executes them automatically; the guard and its error are gone. - Toolkit parameters:
enable_*prefixes are dropped (e.g.SlackTools(enable_send_message=True)→SlackTools(send_message=True)). v2 names still work with a deprecation warning. - AgentOS metadata routes:
GET /modelswas removed (its data moved intoGET /configunderavailable_models), andGET /is now a minimal landing response.GET /infois the single unauthenticated metadata endpoint. - Toolkits have an
id, used by AgentOS to reference tools stably.
Migrate with a Coding Agent
Paste the prompt below into Claude, Cursor, or any coding agent with access to your repository. It applies the mechanical changes and flags everything that needs your judgment.Copy this prompt