- Session runs are stored one row per run in a dedicated runs table.
user_idscoping extends to metrics, schedules, evals, knowledge and vector databases.background=Trueon AgentOS is backed by a durable job queue that survives crashes and deploys.- Database migrations run through the built-in
MigrationManager, with schema versions tracked on every adapter.
Storage
Denormalized session storage
Denormalized session storage
- Runs are no longer stored as a JSON blob in the sessions table. Each run is
a row in the runs table (
agno_runsby default) withrun_id,session_id,run_type,run_index,user_id,statusandrun_data. - Saving a run writes one row instead of rewriting the whole session history. This removes the quadratic write amplification and unbounded row growth of the blob design.
session.runsis still populated on read: sessions merge the runs table with any legacy blob, so un-migrated sessions keep working.- New direct accessors:
db.get_run(run_id)anddb.get_runs(session_id=..., user_id=..., status=..., limit=...). - The v2 -> v3 migration preserves the legacy
runscolumn as a backup. Reclaim it withdb.cleanup_legacy_runs_column(force=True)(SQL) ordb.cleanup_legacy_runs_field(force=True)(document/KV adapters) after verifying the migration — the migration keeps every legacy blob as a backup, so the unforced call refuses by design.
SQLite runs in WAL journal mode
SQLite runs in WAL journal mode
SqliteDbandAsyncSqliteDbissuePRAGMA journal_mode=WALon connect, replacing SQLite’s default DELETE journal (a journal create, double fsync and delete on every commit).- WAL is persistent on the database file and produces
-waland-shmsidecar files next to it. Copy or back up all three together.
Built-in migrations and schema versioning
Built-in migrations and schema versioning
MigrationManager(db).up()walks all registered migrations for every table and stamps the resulting schema version.- Schema versions are tracked on every adapter, including the document and key-value stores (MongoDB, Redis, Valkey, Firestore, DynamoDB, SurrealDB, JSON, GCS JSON, in-memory). An unstamped database is treated as pre-v3 and migrated.
- Migrations are idempotent and non-destructive. Failures raise and abort before any version stamp is written.
Knowledge
Insert API replaces add_content
Insert API replaces add_content
Knowledge.add_content->insert()Knowledge.add_content_async->ainsert()Knowledge.add_contents_async->ainsert_many()
Vector database changes
Vector database changes
LanceDb:use_tantivyis removed; passing it now raises aTypeError.- On schema-based stores, searching a pre-v3 vector table with a
user_idraises aValueErrordirecting you to the vector database migration, instead of silently returning empty results. Schemaless stores (Qdrant, Pinecone, Upstash, Chroma, MongoDB, OpenSearch, SurrealDB) treat pre-v3 documents as shared.
User Isolation
Per-user scoping across the platform
Per-user scoping across the platform
user_idcolumns added to the schedules, schedule-runs and evals tables. All user-facing read and write methods acceptuser_id.- Metrics aggregate per user. The unique key changed from
(date, aggregation_period)to(user_id, date, aggregation_period). Sessions without auser_idaggregate into a shared bucket thatget_metricsmaps back toNone. - Knowledge and vector database contents are scoped per user when isolation
is enabled. On schema-based stores, searching a pre-v3 vector table with a
user_idraises aValueErrordirecting you to the vector database migration; schemaless stores treat pre-v3 documents as shared. - Schedule polling (
claim_due_schedule/release_schedule) stays unscoped so background execution fires across all users; each schedule run records the owner denormalized from its parent schedule.
AgentOS
MCP server configuration
MCP server configuration
AgentOS(enable_mcp_server=..., mcp_config=...)is replaced by a singlemcp_server=parameter, which takes a bool or anMCPServerConfig.
Pagination is validated
Pagination is validated
- Passing
pagewithoutlimit, or apagebelow 1, now raises aValueErrorinstead of being silently ignored. Pages are 1-indexed.
Durable background execution
Durable background execution
- Accepted
background=Truerequests are committed job rows that survive crashes, restarts and deploys. Any replica’s worker can claim and execute them. - Concurrency is bounded. Excess submissions wait in
pendingstatus instead of overloading the process. - Runs can be tailed (
stream=true), 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.
- Background execution requires a
dbon the component and returns a 400 without one. - External framework agents (LangGraph, Claude, DSPy, etc.) stream inline
when
background=trueis requested; their runs are not resumable.
JWT middleware
JWT middleware
secret_keyremoved fromJWTMiddlewareandauthorization_config. Useverification_keys, which takes a list of keys.
Metadata route consolidation
Metadata route consolidation
GET /modelsremoved. Model data moved intoGET /configunderavailable_models.GET /returns a minimal landing response linking to/docs,/infoand/health.GET /infois the single unauthenticated metadata endpoint.
Agents
Removed parameters
Removed parameters
enable_user_memories->update_memory_on_runsearch_session_history->search_past_sessionsnum_history_sessions->num_past_sessions_to_searchnum_past_session_runs->num_past_session_runs_in_searchreasoning=Trueremoved. Setreasoning_model=<native reasoning model>explicitly.continue_run/acontinue_run:updated_toolsremoved. Passrequirements(a list ofRunRequirementfrom the paused run output).
Culture feature removed
Culture feature removed
- The experimental culture feature is removed:
enable_agentic_culture,add_culture_to_context,CulturalKnowledge, the culture tools and theagno_culturetable. - Use Knowledge for shared cross-user information.
Teams & Workflows
Keyword-only Workflow constructor
Keyword-only Workflow constructor
- The
Workflowconstructor no longer accepts positional arguments:Workflow(name=..., steps=[...]). Teamstill acceptsTeam([agent_1, agent_2]); the keyword formTeam(members=[...])is preferred but not required.
HITL configuration unified into HumanReview
HITL configuration unified into HumanReview
- Flat HITL kwargs on
Step,Steps,Loop,ConditionandRouterare removed:requires_confirmation,confirmation_message,on_reject,requires_user_input,user_input_message,user_input_schema,requires_output_review,output_review_message,requires_iteration_review,iteration_review_message,on_error,hitl_max_retries,hitl_timeout,on_timeout. - Pass
human_review=HumanReview(...)instead (import fromagno.workflow.types). Field names are unchanged excepthitl_max_retries->max_retriesandhitl_timeout->timeout.
Tools
Toolkit updates
Toolkit updates
MCPToolbox:auth_tokensandauth_headersremoved. Useauth_token_getters.- Toolkits have an
id, used by AgentOS to reference tools stably.
Workspace refuses credential files by default
Workspace refuses credential files by default
-
Workspacenow excludes env files (.env*,*.env) and conventional credential files — private keys and keystores (*.pem,*.key,id_rsa*), credential directories (.ssh,.aws,.kube), registry and host tokens (.npmrc,.netrc,.git-credentials), credential data files (credentials.json,secrets.yaml,service_account*.json) and Terraform inputs (*.tfvars). -
An agent that reads one of these today starts getting a refusal. Re-allow a
specific path explicitly:
-
Committed templates go the other way and become readable
(
.env.example,.env.sample,.env.template,.env.dist). -
credentials.*andsecrets.*are deliberately absent from the list: they would also refuse ordinary source such ascredentials.py. - Known limit: a hard link to an excluded file bypasses the boundary. Symlinks are caught.
Removed and renamed toolkits
Removed and renamed toolkits
MultiMCPToolsis removed, along with itsallow_partial_failureparameter. Use oneMCPToolsper server.- The flat Google tool modules are removed:
agno.tools.gmail,agno.tools.googlesheets,agno.tools.googlecalendar,agno.tools.google_maps,agno.tools.google_driveandagno.tools.google_bigquery. Import fromagno.tools.google.*instead. - Google toolkits:
creds_path->credentials_path,auth_port->oauth_port. SeltzTools:max_documents->max_results. OlderseltzSDKs still work through a fallback;seltz>=1.2.0is needed for thescope, domain and date filters.BrandfetchTools: theasync_toolsparameter is removed.StudioTool->StudioTools.GDriveContextProvider->GoogleDriveContextProvider.
Removed toolkit methods
Removed toolkit methods
DuckDuckGoTools.duckduckgo_search->web_search, andDuckDuckGoTools.duckduckgo_news->search_news. The toolkit now builds onWebSearchTools, which supplies both methods.FileTools.check_escape->Toolkit._check_path.LocalFileSystemToolskeeps its owncheck_escape, which is unaffected.BrightDataTools.get_screenshot: the unusedoutput_pathparameter is removed.PgVector.enable_prefix_matchingis removed. It was a dead helper with no effect on search.
Scheduler
Schedule provenance columns
Schedule provenance columns
- The schedules table gains eight nullable columns recording where a schedule
came from and who last touched it:
managed_by,target_type,target_id,created_by_run_id,created_by_session_id,updated_by_run_id,updated_by_session_idanddisabled_reason.managed_byandtarget_idare indexed. - The v3.0.0 migration adds the columns and indexes on SQLite and PostgreSQL
(sync and async). Existing rows are left as-is with
NULLprovenance; no data is rewritten. MongoDB needs no schema change.
Schedule names are unique per user
Schedule names are unique per user
- The schedules unique key becomes
(user_id, name). - If duplicate schedule names already exist, the v3.0.0 migration aborts rather than stamping itself as done. Resolve the duplicates and re-run.
update_schedule column allow-list
update_schedule column allow-list
update_schedulecan only writename,description,method,endpoint,payload,cron_expr,timezone,timeout_seconds,max_retries,retry_delay_seconds,enabled,next_run_atanddisabled_reason. Any other key raises aValueErrornaming the rejected columns.- Ownership, provenance and lock state are no longer writable through the generic update path, so a name-keyed upsert cannot repoint who a schedule belongs to or what it targets.
Evals
Result file placeholder renamed
Result file placeholder renamed
store_result_in_file: theeval_idparameter is renamed torun_id.{eval_id}is no longer accepted infile_path_to_save_resultstemplates. Use{run_id}.POST /eval-runsnow returns the id the row was actually stored under (run_id), instead of the eval object’seval_id. Every eval run gets its ownrun_id.- The eval classes no longer carry
eval_id; results carry a per-runrun_id, so re-runs no longer overwrite each other’s stored results.
Models
Removed model APIs
Removed model APIs
- The
agno.models.metricsmodule and itsMetricsalias are removed. Useagno.metricsandRunMetrics. Model.classify_error->ModelProviderError.classify(error).
Mistral requires mistralai v2
Mistral requires mistralai v2
- The
mistralaiv1 compatibility layer is removed.agno[mistral]now requiresmistralai>=2.0.0. agno[mistral]is included in themodelsextra again.
Default model updates
Default model updates
CerebrasandCerebrasOpenAIdefault togpt-oss-120b, replacingllama-4-scout-17b-16e-instruct.- OpenAI
reasoning_effort,reasoning_summary,service_tierandverbosityaccept the full set of API values (includingnone,xhigh,max,scale,fast,ultrafast) and any future string. This widens the accepted types; no existing call breaks.
Learning
Entity memory is isolated per user
Entity memory is isolated per user
EntityMemoryStorewithnamespace="user"did not isolate users: the row key carried no user component, so two users recording the same entity name and type shared one row. One user’s facts overwrote the other’s and leaked into their prompt context.- Row keys under
namespace="user"now embed a digest of theuser_id. Global and custom namespaces are unchanged and do not re-key. - Pre-v3 rows are re-keyed by the v3.0.0 migration, not at runtime. Run it
with the rest of your migrations, or call
agno.learn.migrations.rekey_user_entity_learningsdirectly. The migration’sdown()refuses to reverse the re-key, since the old key collides users by design. EntityMemoryStore.delete/adeletetake a keyword-onlyuser_idand refusenamespace="user"deletes without it.get/agetnow require auser_idin that namespace instead of returning an arbitrary user’s row.
Removed learn aliases
Removed learn aliases
MemoriesConfig->UserMemoryConfigMemoriesStore->UserMemoryStoreDecision->DecisionLog
Packaging
Postgres extra installs a working driver
Postgres extra installs a working driver
agno[postgres]installedpsycopg-binaryonly, which ships the C accelerator but no importablepsycopgand no engine layer, soPostgresDbraisedModuleNotFoundError: No module named 'sqlalchemy'on a clean install. The extra now installspsycopg,psycopg-binaryandsqlalchemy.- If you worked around this by installing
psycopgorsqlalchemyyourself, you can drop those pins.
Errors
Clearer schema mismatch errors
Clearer schema mismatch errors
- SQL adapters raised
Table <name> has an invalid schemawith no next step. The error now names the likely cause (a database created by an older Agno version) and points at both fixes:asyncio.run(MigrationManager(db).up())orPOST /databases/all/migrateon AgentOS.