Skip to content

feat: Google ADK integration with first-class artifact storage #720

Description

@cofin

Summary

Add a advanced_alchemy.extensions.adk package providing a declarative, dual sync/async integration with Google ADK (≥ 2.0.0b1) — covering session, memory, and artifact services, with framework plugins for the existing AA extensions (Litestar, FastAPI, Flask, Sanic, Starlette).

Motivation

Google ADK ships only InMemorySessionService and DatabaseSessionService (raw SQL, single-backend) for sessions, and InMemoryArtifactService / GcsArtifactService for artifacts. Existing third-party SQL implementations (e.g. sqlspec) take a raw-SQL approach across many adapters, which sacrifices ORM ergonomics and type safety.

Advanced Alchemy already has every primitive needed:

  • JsonB ≈ ADK's DynamicJSON (PostgreSQL-native, Oracle-optimized fallback)
  • DateTimeUTC ≈ ADK's PreciseTimestamp (with a small fsp extension for MySQL parity)
  • StoredObject / FileObject + the existing session-tracker for transactional artifact storage across S3 / GCS / Azure / local / fsspec / obstore
  • Repository + Service patterns for sync/async parity via unasyncd
  • Mature framework integrations to plug services into apps

A first-party AA integration delivers idiomatic SQLAlchemy 2.0 models, transactional artifact storage that works across every supported file backend, and the same async/sync ergonomics AA already provides.

Scope

The integration ships in chapters so each piece can land and stabilize independently:

  1. Foundationextensions/adk/ package skeleton, [adk] optional dep with Python 3.10+ guard, schema-version routing module (mirrors ADK's _SchemaClasses pattern so future schema versions are drop-in), and DateTimeUTC(fsp=…) extension for MySQL DATETIME(6) parity.
  2. Models — the 5 v1 ADK tables (sessions, events, app_states, user_states, adk_internal_metadata) declared as Mapped 2.0 models with composite primary keys, FK cascades, and indexes matching ADK exactly.
  3. Session Service — repositories + ADKSessionService(BaseSessionService) with stale-session detection and temp-state filtering.
  4. Alembic template — pre-built migration scaffold (not autogenerate) so users can adopt the schema with one command.
  5. Litestar plugin — exemplar framework integration; provides DI for the session/artifact services.
  6. Artifact Service (headline feature)ADKArtifactService over StoredObject + FileObjectSessionTracker. Backend-agnostic, transactionally consistent. Path layout {app}/{user}/{session}/{filename}/v{N} matches GcsArtifactService for migration parity.
  7. Memory Service — SQL backend, with pgvector opt-in via [adk-vector] extra.
  8. Framework breadth — FastAPI, Flask, Sanic, Starlette plugins following the Litestar plugin shape.
  9. Test matrix — integration tests across the supported DB backends + perf benchmarks vs upstream ADK services.
  10. Docs & release — Sphinx docs, ADK compatibility matrix, examples.

Key design decisions

  • Target google-adk>=2.0.0b1. v2.0.0b1 ships zero schema changes from v1.31, and v2.0 GA is imminent.
  • Declarative ORM, not raw SQL. Lean into AA's existing strengths — Mapped[...] models, SQLAlchemyAsyncRepository, services. Lower boilerplate, automatic dialect handling.
  • Pluggable schema-version routing from MVP. Future schema versions are drop-in modules with no API breakage.
  • Inherit BaseSessionService, do not duplicate. Lazy-import google.adk inside the service module so any future abstract-method additions fail loudly at import time, not silently at user runtime.
  • Composite PKs declared explicitly. AA's primary-key mixins assume single-column PKs; ADK's sessions has 3 PK columns and events has 4.
  • String(128) for sessions.id, not GUID. Custom session IDs (ADK ≥ 1.28) are user-supplied strings up to 128 chars.
  • Decoupled runtime/migration flags. enable_sessions vs include_sessions_migration as independent booleans — users can mix AA runtime with external Alembic, AA migrations with AA runtime, or manual table management.
  • Auth check raises PermissionError. sqlspec returns None on app/user mismatch in get_session; AA raises a typed exception for better diagnostics and to match AA's exception philosophy.
  • Async-first; sync via unasyncd. The ADK BaseSessionService contract is async; the sync mirror is generated for AA's sync stack but isn't registered as a BaseSessionService.
  • Python 3.10+ only for the [adk] extra. ADK requires it. Core AA stays 3.9+. The extensions/adk/__init__.py runtime guard raises a clear error on 3.9.
  • Owner-id factory is a typed Mapped[...], not free-form DDL. Clean, type-safe, FK-aware multi-tenancy.
  • First framework integration: Litestar. Mirrors existing AA extension maturity; FastAPI / Flask / Sanic / Starlette follow the same shape in chapter 8.

Out of scope

  • Workflow / checkpoint persistence. ADK explicitly designs workflow state as in-memory; HITL resume reads from the existing events table by invocation_id. A separate checkpoint table would be wasted work and could conflict with future ADK additions.

Differentiators vs. existing options

ADK upstream sqlspec AA (this proposal)
Session backend In-memory or one raw-SQL impl Raw SQL across many adapters Declarative ORM, all SQLAlchemy dialects
Artifact backend In-memory or GCS-only n/a Any StoredObject backend (S3/GCS/Azure/local/fsspec/obstore), transactional
Sync + async Async only Both Both, single source of truth via unasyncd
Framework plugins None None Litestar / FastAPI / Flask / Sanic / Starlette
Schema versioning None None Pluggable routing from MVP

Tracking

I'll open follow-up issues for each chapter as it becomes ready to implement, blocking on this one.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions