You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
InMemoryArtifactService ignores the "user:" namespace convention — user-scoped artifacts are wrongly session-scoped #1460
InMemoryArtifactService does not implement the user:-prefixed filename convention that the rest of the artifact-service contract relies on: a filename starting with user: is meant to be stored once per (appName, userId) and be visible from every session for that user, not just the session that saved it.
Both other implementations in this repo already do this correctly:
GcsArtifactService.getBlobPrefix() stores user:-prefixed filenames under appName/userId/user/filename/..., independent of sessionId.
adk-python's InMemoryArtifactService._artifact_path() does the same ({app_name}/{user_id}/user/{filename}), and list_artifact_keys unions the session-scoped and user-namespaced prefixes.
InMemoryArtifactService.java, however, keys everything by (appName, userId, sessionId, filename) unconditionally:
InMemoryArtifactServiceservice = newInMemoryArtifactService();
service.saveArtifact("app", "user1", "session-a", "user:profile.txt", artifact).blockingGet();
// Same user, different session — should see the same user-namespaced artifact.Optional<Part> result = service.loadArtifact("app", "user1", "session-b", "user:profile.txt")
.map(Optional::of).defaultIfEmpty(Optional.empty()).blockingGet();
// Actual: result is empty. Expected: result contains the artifact saved from session-a.
The same gap applies to listArtifactKeys (a user:-namespaced artifact saved elsewhere never appears) and deleteArtifact/listVersions (they silently no-op / return empty against the wrong session-scoped key instead of touching the real user-scoped entry).
Impact
Any application relying on InMemoryArtifactService (the default in tests, samples, and quick local runs) for cross-session, per-user artifacts (e.g. a user profile or preference file meant to persist across conversations) silently loses that data the moment a new session starts — with no error, since the tool call still succeeds, it just operates on an empty/wrong scope.
Fix
I have a fix + regression tests ready (keys the in-memory map the same way GcsArtifactService keys GCS blobs, and unions the session/user prefixes in listArtifactKeys) and will open a PR shortly.
Hi @Ashfaqbs,Thank you for flagging this issue and putting together a PR to address it. I am able to reproduce this issue from my end and currently this Issue and PR are under review by our team. We will reach out if we need any more information. Thank you.
Thanks @Ashfaqbs — real bug, and #1460 nails the diagnosis.
This issue was recently addressed and merged via #1449, which had been open since Aug 23. Both solutions are slightly different: yours mirrors adk-python's flat _artifact_path() → {app}/{user}/user/{filename}, while #1449 mirrors adk-go's sessionID = userScopedArtifactKey substitution (artifact/inmemory.go:54). Both are defensible ports, and we appreciate the effort you put into this.
Since the fix has landed, I am going to close this issue. Could you pull main and check that the merged fix actually covers your cases? You found this, so you're the right person to confirm it's genuinely resolved. If it doesn't cover your case, please let me know or reopen the issue and we will investigate further.
Activity
hemasekhar-p commentedon Aug 27, 2026
Hi @Ashfaqbs,Thank you for flagging this issue and putting together a PR to address it. I am able to reproduce this issue from my end and currently this Issue and PR are under review by our team. We will reach out if we need any more information. Thank you.
sherryfox commentedon Aug 27, 2026
Thanks @Ashfaqbs — real bug, and #1460 nails the diagnosis.
This issue was recently addressed and merged via #1449, which had been open since Aug 23. Both solutions are slightly different: yours mirrors adk-python's flat _artifact_path() →
{app}/{user}/user/{filename}, while #1449 mirrors adk-go'ssessionID = userScopedArtifactKeysubstitution (artifact/inmemory.go:54). Both are defensible ports, and we appreciate the effort you put into this.Since the fix has landed, I am going to close this issue. Could you pull main and check that the merged fix actually covers your cases? You found this, so you're the right person to confirm it's genuinely resolved. If it doesn't cover your case, please let me know or reopen the issue and we will investigate further.