Repository navigation
Conversation
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
|
Hi @galleonli, thank you very much for taking the time to investigate this and for putting together such a thorough PR and test suite! After reviewing the end-to-end session lifecycle across all ADK session backends, we realized that the inline comment added in
We sincerely apologize that the existing comment in |
Link to Issue or Description of Change
Problem: When two callers hold copies of the same in-memory session, broadcasting the same event to both updates only the first caller.
append_eventfinds the event in canonical storage and returns before updating the second caller's state and history. A running agent can therefore continue with stale state even though the append succeeded.This is a follow-up to the event deduplication introduced for #5723. The existing tests cover repeated delivery to one reference; this change covers delivery to separate references.
Steps to reproduce:
counter=0and retrieve a second copy before appending any event.state_delta={"counter": 1}to the first copy.Expected: both callers see
counter=1and the event remains stored once. Observed: the second caller still hascounter=0and an empty event list. The new Runner regression reproduces the same behavior with two concurrent invocations and no model calls.Environment: Reproduced with google-adk 2.11.0 and the source at
ea656b03d3f3c6dd041ba8e3f65d612017592c42, Python 3.12.3, macOS arm64. Model/LiteLLM: N/A. Reproducible without credentials or network services.Solution: If storage already contains the event but the caller does not, refresh the caller from a copied storage snapshot with merged app/user state. Refreshing the snapshot, rather than replaying the old delta, preserves newer values and event order. Update the caller's containers in place to preserve existing references and local temporary state. An event already present in both references remains a no-op, and canonical storage is unchanged.
Testing Plan
Unit Tests: Added six parameterized session cases covering both copy modes, same-object/equal-copy delivery, scoped state, temporary state, copy isolation, idempotence, and late delivery after a newer update. All six fail on the original implementation and pass with the patch.
End-to-End Runner Validation:
test_concurrent_invocations_receive_a_shared_state_eventuses anasyncio.Barrierto ensure both invocations have loaded their session before a customBaseAgentyields the shared event. It exercises the actual Runner append path without mocking the session service or calling an LLM.The Runner regression is included in the Runner suite count above. The full repository suite, GPU execution, and performance benchmarks were not run.
Changed-file pre-commit hooks passed.
mypy --follow-imports=silent src/google/adk/sessions/in_memory_session_service.pyandgit diff --checkpassed.Compatibility recheck (2026-10-08): The results above were recorded for the initial fix,
cddc380c. After upstream changed the shared session and Runner tests, mergedmainat7d56ef84into this branch ased94ef16. The session-service implementation is unchanged. On the merged source, the combined session and Runner suites passed:Changed-file pre-commit hooks, the single-file mypy check, and the diff check passed again. This was a Python 3.12.3 CPU run in the existing environment; the full multi-version
toxsuite was not run.Checklist
No new public API or dependency changes.