Skip to content

fix(artifacts): preserve file artifact creation timestamps - #7113

Closed
baba9811 wants to merge 1 commit into
google:mainfrom
baba9811:fix/file-artifact-create-time
Closed

baba9811 wants to merge 1 commit into
google:mainfrom
baba9811:fix/file-artifact-create-time

Conversation

@baba9811

@baba9811 baba9811 commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Description of Change

FileArtifactService saves the correct createTime to disk, but
_build_artifact_version() omits it when constructing the returned metadata.
The ArtifactVersion default then assigns the current time on every read,
so the same saved version appears newly created each time it is fetched.

This change forwards the persisted timestamp in the helper shared by
get_artifact_version() and list_artifact_versions(). It preserves the
existing fallback for unavailable metadata, canonical URI validation, and
custom metadata copying.

Reproduction

On main at 460715b6c62c8e9ab00931c502381ee0364e39b6, save an artifact,
reopen the service, and read the same version repeatedly:

import asyncio
from tempfile import TemporaryDirectory

from google.adk.artifacts.file_artifact_service import FileArtifactService
from google.genai import types


async def main():
    with TemporaryDirectory() as root:
        service = FileArtifactService(root_dir=root)
        scope = dict(app_name="app", user_id="user", session_id="session",
                     filename="report.txt")
        await service.save_artifact(**scope, artifact=types.Part(text="report"))
        service = FileArtifactService(root_dir=root)
        first = await service.get_artifact_version(**scope, version=0)
        second = await service.get_artifact_version(**scope, version=0)
        versions = await service.list_artifact_versions(**scope)
        times = [first.create_time, second.create_time, versions[0].create_time]
        print(times)
        assert len(set(times)) == 1


asyncio.run(main())

Expected: each read returns the persisted creation time. Before the fix, the
timestamps differ and the assertion fails. With the fix, it passes.

Reproduced on macOS 26.6.2 arm64, Python 3.12.10, ADK 2.9.0,
google-genai 2.23.0 and Pydantic 2.13.5. No model or LiteLLM is involved.

Testing Plan

Regression and affected callers: the new regression fails before the fix
and passes afterward. It covers distinct save/read times, a zero timestamp,
reopening, multiple versions, session/user scopes, and text/binary payloads.
The artifact, Context, forwarding service, local storage, FastAPI, and
save-files plugin tests report 1,142 passed, 5 skipped, 1 xfailed.

Full unit suite via tox:

Python Passed Failed Skipped Xfailed Xpassed
3.10 14632 0 87 27 2
3.11 14639 0 86 27 2
3.12 14630 2 (also fail on main) 87 27 2
3.13 14632 0 87 27 2
3.14 14632 0 87 27 2

The two Python 3.12 failures are the agent/runner import-allowlist tests
detecting Homebrew's preloaded sitecustomize; both fail identically on
unchanged main with the same interpreter. Overall tox exits with code 1.
The test process excludes gcloud from PATH to prevent interactive login;
an unrelated CLI test's interactive option flow remains unverified.

Formatting and types: full pre-commit passed. The optional addlicense
binary was unavailable, so that check was skipped. Mypy reports the same
847 errors before and after the change, with no new diagnostics.

End-to-end: built the wheel, installed it in a clean environment, and
verified the public API and actual adk web HTTP routes using file artifact
storage and in-memory sessions/memory. Save/get/get/list all return HTTP 200.
The returned timestamps now match the persisted value:

Before: saved 1789339027.512842
Returned: [1789339027.515331, 1789339027.517152,
           1789339027.5185258, 1789339027.5201972]
After: saved 1789339026.686486
Returned: [1789339026.686486, 1789339026.686486,
           1789339026.686486, 1789339026.686486]

Missing, malformed, legacy missing-time, and invalid-time metadata retain
their previous fallback behavior. These checks pass before and after the fix.

Forward the persisted creation time when returning file artifact version
metadata so repeated get and list calls do not assign a new creation time.
Keep the existing fallback when metadata is unavailable.
copybara-service Bot pushed a commit that referenced this pull request Sep 15, 2026
Merge #7113

PiperOrigin-RevId: 982032909
@adk-bot

adk-bot commented Sep 15, 2026

Copy link
Copy Markdown
Collaborator

Thank you @baba9811 for your contribution! 🎉

Your changes have been successfully imported and merged via Copybara in commit e93ff5b.

Closing this PR as the changes are now in the main branch.

@adk-bot adk-bot added the merged [Status] This PR is merged label Sep 15, 2026
@adk-bot adk-bot closed this Sep 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merged [Status] This PR is merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants