Repository navigation
fix(sessions): snapshot initial state in in-memory sessions - #7676
xxwtiancai wants to merge 2 commits into
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. |
Copy initial app, user, and session state before storing it so later changes to the input cannot silently alter existing sessions. Preserve the configured light-copy behavior and filter temporary values before copying.
6cb3fba to
110262a
Compare
BichengWang
left a comment
There was a problem hiding this comment.
Reviewed 110262ad33f2c82b6eaa47faca9d6931e0566782. No blocking findings in the initial-state snapshot change.
The copy happens after scope extraction and before any stored scope is updated, so discarded temp: values are not deep-copied. Both creation entry points use this path, and the existing helper preserves the opt-in light-copy behavior.
Validation on Python 3.13.16, offline:
pytest tests/unittests/sessions/test_session_service.py -q: 436 passed.- Replaced only
_create_session_implwith current upstream's implementation in an isolated test process: the two default-copy regression cases failed; both light-copy controls passed. - Ran a real Runner with a FunctionNode reading session, user, and app state after mutating the retained initial input: all three scopes kept their original values.
Checked the existing discussion and reviews before testing. The full repository suite and multi-version tox were not run for this review.
Link to Issue or Description of Change
No existing issue found; bug report included below as permitted by CONTRIBUTING.md.
Problem:
InMemorySessionService.create_session(state=...)stores nestedvalues from the input by reference, even with the default deep-copy setting.
Changing or reusing that input after creation silently changes the saved session
and the state its next Runner invocation reads, without an event or state delta.
This affects session,
user:, andapp:initial state, including the synchronouscreation entry point.
Reproduction / environment: On
mainatfacd7dd(ADK 2.12.0), macOS arm64,Python 3.11.14; no model, credentials, or network needed:
Expected:
{'items': ['coffee']}. Before this fix:{'items': ['coffee', 'tea']}.Reproduces every run.
Solution: Copy each extracted state scope using the existing
_copy_statehelper before storage. The opt-in
IN_MEMORY_SESSION_SERVICE_LIGHT_COPYmodekeeps its shallow-copy behavior. Temporary state is excluded before copying; the regression includes a discarded
temp:value that cannot be deep-copied.This concerns initial input ownership; #7105 already fixed the separate path
that copies scoped state into returned sessions. No public API changes.
Testing Plan
Unit tests and checks:
New regression on unmodified
main: 2 failed, 2 passed. Both default-modeentry points fail; the light-copy controls pass.
Full sessions suite after the fix: 657 passed.
Changed-file pre-commit hooks passed; source mypy passed.
Independent Astra xhigh review: no actionable findings; 12 focused tests
passed, plus public-interface probes for scoped propagation and temporary
values that cannot be deep-copied.
Required full
toxmatrix completed on macOS arm64. It is not fully green:Re-ran every failing node on pristine base
facd7ddand the patch withthe corresponding tox interpreter, installed dependencies and host permissions.
Both checkouts reproduced exactly the same failing nodes and counts for each
version. The failures are:
all 13 pass for both checkouts when run in the local sandbox, which does not
expose those system proxy settings.
the local Xcode setup. Selecting the already installed Command Line Tools
Git makes the full 66-test script module pass. The 3.14 run used that Git.
test_reading_directory_raises: the fake sandbox runs the host'sbase64,which returns success for directory input on this macOS installation.
The full matrix ran against the final production change. Afterwards the new
regression's discarded
temp:value was strengthened to a non-copyable lock;all four regression cases passed again on each Python version, and the
full sessions suite passed again (657 tests). The strengthened test still
produces exactly 2 failures / 2 passes against the original source.
No unrelated source or test behavior was changed to hide these failures.
Manual E2E: Ran a public
Runnerwith aFunctionNodethat returnscart,user:profile, andapp:configfrom context. After creating the session, changedthe retained input dictionary before invoking the Runner. No LLM was involved.
uv buildproduced the sdist and wheel. Installed the wheel into a cleanPython 3.11 environment and ran the same reproduction with
python -I; itreturned the original state.
Runner setup and executable reproduction
Save as
repro.py; runpython repro.pyin the checkout environment, orpython -I repro.pywith the installed wheel.AI assistance disclosure
OpenAI Codex assisted with investigation, implementation, tests, and this
description. A separate Astra xhigh agent reviewed the final diff.