Quickstart#
Wire SQLSpec stores into your ADK agent to persist sessions, events, and memory across restarts.
How It Works#
Create a SQLSpec database config with ADK extension settings.
Initialize the appropriate stores (session and memory).
Pass the service wrappers to your ADK agent.
Session Service#
The session service persists agent state and events between conversations. When a user returns, the agent can resume from where it left off.
from sqlspec.adapters.asyncpg import AsyncpgConfig
from sqlspec.adapters.asyncpg.adk import AsyncpgADKStore
from sqlspec.extensions.adk import SQLSpecSessionService
config = AsyncpgConfig(
connection_config={"dsn": "postgresql://localhost/mydb"},
extension_config={
"adk": {
"session_table": "adk_session",
"events_table": "adk_event",
}
},
)
store = AsyncpgADKStore(config)
await store.ensure_tables()
session_service = SQLSpecSessionService(store)
# Create a session with scoped state
session = await session_service.create_session(
app_name="my_agent",
user_id="user_123",
state={
"app:model": "gemini-2.0", # shared across all sessions
"user:name": "Alice", # shared across user's sessions
"conversation_turn": 0, # session-local
"temp:scratch": "...", # runtime-only, never persisted
},
)
Events are persisted automatically when you use the session service with an
ADK runner. Each call to append_event() atomically stores the event and
updates the session's durable state via append_event_and_update_state().
Listing Sessions#
SQLSpecSessionService.list_sessions() accepts optional ordering and paging
arguments in addition to Google ADK's app_name and user_id. They are a
SQLSpec extension to ADK's narrower base signature, and the ordering and page
bounds are applied in SQL rather than by trimming a fully materialized result.
# Most recently updated sessions for one user, 20 at a time
page = await session_service.list_sessions(
app_name="my_agent",
user_id="user_123",
limit=20,
offset=0,
)
# Oldest conversations first
oldest = await session_service.list_sessions(
app_name="my_agent",
user_id="user_123",
order_by="create_time",
descending=False,
limit=20,
)
The contract is deliberately narrow:
The default is unchanged:
update_timedescending, with no page bounds.order_byaccepts onlycreate_timeorupdate_time. No other value and no raw SQL expression reaches a query.idis applied as a secondary sort key in the same direction, so pages stay deterministic when two sessions share a timestamp.limitandoffsetaccept non-negative integers.limit=0returns an empty response without touching the database, and a positiveoffsetrequires a finitelimit.The response is Google ADK's
ListSessionsResponse. It carries no total count and no cursor token, so paginate by advancingoffsetyourself.
Scoped State#
State keys use prefixes to control their scope and persistence:
app:-- shared across all sessions for the same application.user:-- shared across all sessions for the same user.temp:-- runtime-only, stripped before every write to storage.(no prefix) -- private to the current session.
See Scoped State Semantics for full details.
Memory Service#
The memory service retains context that the agent can reference later. This enables long-term memory across sessions with full-text search.
from sqlspec.adapters.asyncpg.adk import AsyncpgADKMemoryStore
from sqlspec.extensions.adk import SQLSpecMemoryService
memory_store = AsyncpgADKMemoryStore(config)
await memory_store.ensure_tables()
memory_service = SQLSpecMemoryService(memory_store)
Enable full-text search by setting memory_use_fts: True in the ADK config.
This creates database-native FTS indexes (tsvector, FTS5, InnoDB FT) for
efficient memory retrieval.
Artifact Service#
The artifact service contracts live in sqlspec.extensions.adk.artifact and
separate SQL metadata from object-storage content. Use them when your
deployment provides a concrete artifact metadata store; adapter adk
packages currently export session/event and memory stores only.
Schema Setup#
You can programmatically create ADK tables ahead of first use with
ensure_tables():
await session_store.ensure_tables()
await memory_store.ensure_tables()
Alternatively, configure SQLSpec migrations for your database and run the migration CLI as part of deployment:
sqlspec upgrade