Repository navigation
fix(artifacts): load artifacts removed by a rewind as None in file and GCS services - #7483
Open
spandankeche wants to merge 1 commit into
Open
spandankeche wants to merge 1 commit into
spandankeche wants to merge 1 commit into
Conversation
Runner.rewind_async removes an artifact that did not exist at the rewind point by saving an empty application/octet-stream part as a new version. Only InMemoryArtifactService loaded that part as None. FileArtifactService, the default store for adk web and adk api_server, and GcsArtifactService returned it as a 0-byte artifact, so the artifact endpoint answered 200 instead of 404 and load_artifacts told the model the artifact existed and was empty. Define the marker once in artifact_util, save it through that helper in the rewind code, and have the file and GCS services load it as None like the in-memory service. The marker itself is unchanged, so sessions rewound by earlier releases are read correctly. Fixes google#7482
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.
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:
Runner.rewind_asyncremoves an artifact that did not exist at the rewind point by saving an emptyapplication/octet-streampart as a new version. OnlyInMemoryArtifactServiceloaded that part asNone.FileArtifactService, the default store foradk webandadk api_server, andGcsArtifactServicereturned the empty part, so after a rewindload_artifactreturned a 0-byte artifact, the artifact endpoint answered 200 instead of 404, andload_artifactstold the model the artifact existed and was empty.Solution:
artifact_util(_new_rewind_tombstone,_is_rewind_tombstone, both private)._rewind_utilssaves it through the helper, andInMemoryArtifactServicerecognizes it through the helper, with no change in behavior.FileArtifactServiceandGcsArtifactServiceload a version holding the marker asNone, the same asInMemoryArtifactService.Not changed, to keep this to one concern: all three services still list the removed artifact in
list_artifact_keysafter a rewind (noted in #7482).Testing Plan
Unit Tests:
New tests:
test_artifact_service.py::test_artifact_removed_by_rewind_loads_as_none: on all three services, a version holding the marker loads asNone, by latest and by explicit version.test_artifact_service.py::test_version_before_rewind_tombstone_still_loads: on all three services, the version saved before the marker still loads its content.test_runner_rewind.py::test_rewind_removes_artifact_created_after_rewind_point: aRunner.rewind_asyncround trip on the in-memory and file services.The tests catch the bug: with only the file and GCS change reverted, the 4 file and GCS cases of the first test and the file case of the runner test fail; with only the in-memory check removed, its 3 in-memory cases fail.
versionargument).pytest tests/unittests, installed the way the CI unit-test job does (uv sync --extra test,UV_EXCLUDE_NEWERone hour back), onmainat3d11f9fe7plus this change: 18,367 / 18,355 / 18,357 / 18,356 passed on Python 3.11 / 3.12 / 3.13 / 3.14. The 4 to 7 failures per version are unrelated to this change; each was rerun three times on this branch and three times on untouchedmain(see Additional context).pre-commit run --all-files: 14/14 hooks passed.mypy ., base vs. this change,comm -13) on Python 3.11, 3.12 and 3.13: 831 errors on both sides, 0 new.Manual End-to-End (E2E) Tests:
Setup: wheel built from this branch with
uv buildand installed into a fresh virtualenv (ADK imported fromsite-packages), Python 3.11. The script is the one from #7482: aRunneronInMemorySessionService, a session whereinv2first savesreport.txt, thenrewind_async(rewind_before_invocation_id="inv2")andload_artifact("report.txt").Before (google-adk 2.11.0):
After (wheel from this branch):
The same steps with
GcsArtifactService(on the test suite'sMockClient) also printNone. With anLlmAgentthat saves the artifact from a tool and later callsload_artifacts(scripted model), the model previously receivedArtifact report.txt is:followed by an empty text part on the file service and onadk web's per-agent file storage; with this change it receives no artifact content, the same as with the in-memory service.Checklist
Additional context
docs/guides/covers rewind.main(3d11f9fe7):TestParseToolCallArgumentslog tests inmodels/test_litellm.pyfail only inside the full run and pass in every rerun on both branches.test_import_loading.py::test_entry_point_loads_only_allowlisted_packages[agent]and[runner]fail on Python 3.12 on both branches with identical messages: Ubuntu's system Python 3.12 provides asitecustomizemodule that the check reports.test_telemetry_schemacases intelemetry/test_functional.pyfail intermittently on both branches (1 of 9 reruns here, 2 of 9 onmain).test_bigquery_agent_analytics_plugin.py::TestSafetyLifecycleHardening::test_completed_constructor_close_dispatched_off_loopfailed once on 3.14 under full-suite load and passed in all six reruns.