Skip to content

Feat: Firestore support#5088

Open
ScottMansfield wants to merge 26 commits intogoogle:mainfrom
ScottMansfield:feat/firestore
Open

Feat: Firestore support#5088
ScottMansfield wants to merge 26 commits intogoogle:mainfrom
ScottMansfield:feat/firestore

Conversation

@ScottMansfield
Copy link
Copy Markdown
Member

@ScottMansfield ScottMansfield commented Mar 31, 2026

Adding support for Firestore for both session and memory storage.

This started by copying the Firestore support from the Java ADK into the Python ADK and also takes inspiration from @anmolg1997's PR google/adk-python-community#104. It does things differently from both.

Firestore contains a hierarchical set of data for sessions:

adk-session
  ↳ <user ID>
    ↳ sessions
      ↳ <session ID>
        ↳ events
          ↳ <event ID>
            ↳ Event document

The firestore memory service creates a top-level collection that hold indexed memories when sessions are added.

Link to Issue or Description of Change

This is from an existing customer request for firestore support.

Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.
$ pytest tests/unittests/integrations/firestore
======================================== test session starts ========================================
platform darwin -- Python 3.11.14, pytest-9.0.2, pluggy-1.6.0
rootdir: /Users/scottmansfield/projects/adk-python
configfile: pyproject.toml
plugins: mock-3.15.1, xdist-3.8.0, langsmith-0.7.23, asyncio-1.3.0, anyio-4.13.0
asyncio: mode=Mode.AUTO, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function
collected 28 items                                                                                  

tests/unittests/integrations/firestore/test_firestore_memory_service.py ...........           [ 39%]
tests/unittests/integrations/firestore/test_firestore_session_service.py .................    [100%]

========================================= warnings summary ==========================================
src/google/adk/features/_feature_decorator.py:72
  /Users/scottmansfield/projects/adk-python/src/google/adk/features/_feature_decorator.py:72: UserWarning: [EXPERIMENTAL] feature FeatureName.PLUGGABLE_AUTH is enabled.
    check_feature_enabled()

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=================================== 28 passed, 1 warning in 1.52s ===================================

Manual End-to-End (E2E) Tests:

I created a demo app locally to test the session and memory storage with a real firebase instance. It successfully records sessions and memories, verified by manually checking the cloud console.

Memory did require an index, which will be created by the user the first time the memory session is used. Firestore has a specific deep link that it will create to give the exact index needed. After that, memory worked fine.

Checklist

  • I have read the CONTRIBUTING.md document.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have manually tested my changes end-to-end.
  • Any dependent changes have been merged and published in downstream modules.

@adk-bot
Copy link
Copy Markdown
Collaborator

adk-bot commented Mar 31, 2026

Response from ADK Triaging Agent

Hello @ScottMansfield, thank you for creating this PR!

I see that this is a draft PR. When you are ready, please ensure you have read the contribution guide and filled out the PR template, including:

  • Link to an existing issue or a description of the change: This helps reviewers understand the context of your contribution.
  • Testing Plan: Please describe the tests you ran to verify your changes.

This information will help reviewers to review your PR more efficiently. Thanks!

@adk-bot adk-bot added the services [Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc label Mar 31, 2026
@rohityan rohityan self-assigned this Apr 1, 2026
@ScottMansfield
Copy link
Copy Markdown
Member Author

Looks like we have one open for the community repo: google/adk-python-community#104

@rohityan
Copy link
Copy Markdown
Collaborator

rohityan commented Apr 1, 2026

Hi @ScottMansfield , Thank you for your contribution! We appreciate you taking the time to submit this pull request.
Closing this PR here as it belongs to adk-python-community repo.
We highly recommend releasing the feature as a standalone package that we will then share through: https://google.github.io/adk-docs/integrations/

@rohityan rohityan closed this Apr 1, 2026
@rohityan rohityan added the community repo [Community] FRs/issues well suited for google/adk-python-community repository label Apr 1, 2026
@rohityan rohityan reopened this Apr 3, 2026
@rohityan rohityan removed the community repo [Community] FRs/issues well suited for google/adk-python-community repository label Apr 3, 2026
@rohityan
Copy link
Copy Markdown
Collaborator

rohityan commented Apr 3, 2026

Hi @ScottMansfield , is this PR still in draft? If not can you please fill in the details for the PR.

@ScottMansfield
Copy link
Copy Markdown
Member Author

I believe this is ready for review but I'm testing it with a real firestore instance


from __future__ import annotations

DEFAULT_STOP_WORDS = {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is this something specific to the firestore implementation? Should this be something we apply to all memory service?

"""Session service that uses Google Cloud Firestore as the backend.

It creates a hierarchy in Firestore to hold events by user and session:
adk-session
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

what about app?



@pytest.mark.asyncio
async def test_list_sessions_with_user_id(mock_firestore_client):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Add a test that there are multiple apps, and only specific app is fetched?

if event.partial:
return event

self._apply_temp_state(session, event)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Also a test covering this?

self._search_by_keyword(app_name, user_id, keyword)
for keyword in keywords
]
results = await asyncio.gather(*tasks)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Add a test to verify that failures in parallel tasks are handled

else:
session_updates[key] = value

if app_updates:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The current append_event implementation updates App, User, and Session states across multiple independent transactions and batches. This lacks atomicity; if the final batch.commit() fails after the state transactions have finished, the storage layers will become desynchronized. Please wrap all related state and event updates into a single Firestore transaction to ensure consistency.

has_updates = True

if has_updates:
await batch.commit()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This adds all session events to a single write batch without checking size. This will crash if a session exceeds Firestore's 500-operation limit. Please implement a batch-splitting mechanism similar to the 500-count logic already used in delete_session

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

services [Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants