Repository navigation
Conversation
FirestoreSessionService stored only an event's author, timestamp, and text, function call, function response and file data parts, and rebuilt events from those fields alone. Reloaded events lost their ID, invocation ID, branch, actions, thought flags and signatures, and function call and response IDs, and user events came back with the user ID as their author. Function call args were stored as they were, so a tool confirmation request, whose args hold a FunctionCall and a ToolConfirmation, could not be saved. - Events are also stored as JSON in `rawEvent` and read back from it. Events stored before this change still load from the other fields, which FirestoreMemoryService keeps reading. - Tool call args and results are stored as plain values.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Please ensure you have read the contribution guide before creating a pull request.
Link to Issue or Description of Change
1. Link to an existing issue (if applicable):
2. Or, if no issue exists, describe the change:
Problem:
FirestoreSessionServicestores only part of each event and rebuilds events from that part when a session is read back. Reloaded events lose theirid,invocationId,branch,actions, thought flags and signatures, and function call and response IDs, and user events come back with the user ID as their author. BecauseRunnerreads the session on every run, later requests quote earlier user messages as another agent's content and drop earlier tool results. The function call args are stored as they are, so a tool confirmation request, whose args hold aFunctionCalland aToolConfirmation, cannot be saved. #1640 has the details and a reproduction.Solution:
eventToMapalso stores the whole event as JSON (event.toJson()) in a newrawEventfield, andeventFromMapreads it back withEvent.fromJson(). As in fix: stop losing event fields on Vertex AI session reloads #1574 for the Vertex AI session service, the other fields remain the fallback whenrawEventis missing (events stored before this change) or unreadable.FirestoreMemoryServicesearches the same documents bykeywordsand readsauthor,timestampand the text parts from them.FunctionTooldoes for tool return values. Firestore cannot encode aFunctionCall, aToolConfirmationor anOptional.One deliberate difference from ADK Python, noted in the
RAW_EVENT_KEYJavadoc: ADK Python stores the event as a map (event_data), and this stores a JSON string, so Firestore's limits on maps (no arrays directly inside arrays, reserved field names, nesting depth) do not apply to this copy of the event. The tool args and results in the other fields are still subject to them, as before. The field is namedrawEventas in #1574; the Java and Python Firestore services use different collection paths, so neither reads the other's events.Testing Plan
Unit Tests:
./mvnw -pl contrib/firestore-session-service test: 56 run, 2 failures, both inFirestorePropertiesTest(shouldReturnHardcodedDefaultIfPropertyFileHasNoEntry,shouldLoadDevPropertiesWhenEnvIsSetToDev), which fail only on Windows, the same way onmain, and pass in the Ubuntu CI (local run: Microsoft Build of OpenJDK 17.0.19, Windows 11). The four new tests are inFirestoreSessionServiceTest:mainappendAndGet_returnsEventsAsAppended: a user message, a model event with a signed thought and a function call, and the function response, read back withgetSessionidandinvocationIdarenulland the user message's author istest-user-id, among other differencesappendEvent_withToolConfirmationRequest_storesArgsAsPlainValuesoriginalFunctionCallis stored as aFunctionCallappendEvent_withObjectsInToolResult_storesResultAsPlainValues:{"result": [a record with an Optional]}, which is whatFunctionToolreturns for a listgetSession_withUnreadableRawEvent_loadsEventFromOtherFieldsmainignoresrawEvent)Partial implementations fail them too: writing
rawEventwithout reading it fails the first test, converting only the args or only the results fails the third or the second, and catchingIllegalArgumentException(what #1574 catches aroundconvertValue) instead of theIllegalStateExceptionthatEvent.fromJsonthrows fails the fourth.appendAndGet_withAllPartTypes_serializesAndDeserializesCorrectlynow removesrawEventfrom the stored document before reading it back, so it keeps covering how events stored before this change are read.Manual End-to-End (E2E) Tests:
Not run against a real Firestore database or a model. Following the reproduction steps in #1640:
Contents, are the same as before the reload;appendEventstores for the tool confirmation request is accepted bybatch().set(...)of a realFirestoreclient that never commits. Onmainit throwsNo properties to serialize found on class com.google.genai.types.AutoValue_FunctionCall.Checklist
Additional context
rawEvent, so they still load from the other fields as before (the user ID as the author, no IDs). Only events appended after the change come back whole.FirestoreMemoryServiceand older versions of this service read, and inrawEvent. If you would rather keep only whatFirestoreMemoryServiceneeds in the current fields (the author, timestamp, text parts and keywords), I can change that, which would leave only the text stored twice.rawEventalso holds inline data and repeats the text, function calls and function responses, some events that were saved before can now exceed Firestore's 1 MiB document limit and fail to save: one with inline data such as an uploaded image, which used to be dropped, or one whose text or tool results take up more than about half of the limit. ADK Python keeps inline data inevent_datatoo. With an artifact service,RunConfig.saveInputBlobsAsArtifactssaves the inline data in user messages as artifacts instead.