Skip to content

extensions/memory: add Google Cloud Firestore session backend#2955

Closed
Kcstring wants to merge 1 commit intoopenai:mainfrom
Kcstring:feat/firestore-session
Closed

extensions/memory: add Google Cloud Firestore session backend#2955
Kcstring wants to merge 1 commit intoopenai:mainfrom
Kcstring:feat/firestore-session

Conversation

@Kcstring
Copy link
Copy Markdown

Summary

Add FirestoreSession — a production-grade session backend backed by Google Cloud Firestore — to agents.extensions.memory.

Motivation: The SDK already ships Redis, MongoDB, SQLAlchemy, Dapr, and SQLite session backends. Firestore is a natural addition for teams running on Google Cloud Platform: it is serverless, scales automatically, and is widely used in GCP-native applications. This PR follows the same pattern established by the recently merged MongoDB backend.

Design:

  • Conversation items are stored as documents in a messages sub-collection under each session document.
  • A monotonic _seq counter on the parent session document is incremented atomically via a Firestore transaction, guaranteeing strict insertion order across concurrent writers and processes.
  • from_project(session_id, *, project) is a convenience constructor that creates an AsyncClient from a GCP project ID using Application Default Credentials.
  • Injecting an existing AsyncClient is also supported for applications that manage the client lifecycle themselves.

Files changed:

  • src/agents/extensions/memory/firestore_session.py — new FirestoreSession class
  • src/agents/extensions/memory/__init__.py — export FirestoreSession with lazy import + helpful error message
  • pyproject.toml — add firestore = ["google-cloud-firestore>=2.19"] optional dependency group
  • tests/extensions/memory/test_firestore_session.py — 14 unit tests (no real Firestore server required; uses in-process fakes)

Test plan

All tests run without a real Firestore server by injecting lightweight in-memory fakes into sys.modules before the module under test is imported — the same approach used by the MongoDB test suite.

uv run pytest tests/extensions/memory/test_firestore_session.py -v
# 14 passed in 0.13s

Issue number

Checks

  • I've added new tests (if relevant)
  • I've added/updated the relevant documentation
  • I've run make lint and make format
  • I've made sure tests pass

Add FirestoreSession, a production-grade session backend backed by
Google Cloud Firestore.  Conversation items are stored as documents in
a messages sub-collection; a monotonic sequence counter on the parent
session document (updated via a Firestore transaction) guarantees
strict insertion order across concurrent writers.

Public API mirrors the existing MongoDB/Redis backends:
- FirestoreSession(session_id, *, client, ...)
- FirestoreSession.from_project(session_id, *, project, ...)
- get_items / add_items / pop_item / clear_session / close / ping

Also adds:
- firestore optional dependency group in pyproject.toml
- 14 unit tests (no real Firestore server required)
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4cfa66a775

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +231 to +232
@self._client.transaction() # type: ignore[arg-type]
async def _txn(transaction: Any) -> int:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use Firestore transaction wrapper API correctly

In add_items, _txn is decorated with @self._client.transaction(), but AsyncClient.transaction() returns an AsyncTransaction object rather than the transactional decorator API, so this pattern fails against the real Firestore client and prevents message inserts from succeeding. The official async usage is to create a transaction object and wrap the coroutine with async_transactional (then call it with the transaction), so this code path can raise before any write and make the new FirestoreSession unusable in production.

Useful? React with 👍 / 👎.

@seratch
Copy link
Copy Markdown
Member

seratch commented Apr 19, 2026

Thanks for sharing this. While we do not include this module in the core SDK, please feel free to publish the code as your own package or use it in your own projects.

@seratch seratch closed this Apr 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants