Skip to content

Comments

Add FileArtifactService#131

Open
kalenkevich wants to merge 7 commits intomainfrom
feat/file_artifact_service
Open

Add FileArtifactService#131
kalenkevich wants to merge 7 commits intomainfrom
feat/file_artifact_service

Conversation

@kalenkevich
Copy link
Collaborator

@kalenkevich kalenkevich commented Feb 10, 2026

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:
The ADK TS lacked a local filesystem-backed artifact service (aligned with python file service), which is essential for local development and testing. Additionally, the existing GcsArtifactService and InMemoryArtifactService had inconsistent implementations and lacked a shared test suite to ensure parity and correctness across all artifact service implementations.

Solution:
This PR introduces FileArtifactService to support local artifact storage with versioning and metadata management. It also establishes a shared test suite (runArtifactServiceTests) in core/test/artifacts/artifact_service_test_utils.ts that enforces a consistent interface and behavior across all artifact services. GcsArtifactService and InMemoryArtifactService have been refactored and updated to pass this shared test suite, ensuring alignment and reliability.

Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.

Summary of passed npm test results:

  • core/test/artifacts/file_artifact_service_test.ts: Verifies FileArtifactService using the shared test suite.
  • core/test/artifacts/gcs_artifact_service_test.ts: Verifies GcsArtifactService improvements and alignment.
  • core/test/artifacts/in_memory_artifact_service_test.ts: Verifies InMemoryArtifactService functionality.
  • All core tests passed.

Manual End-to-End (E2E) Tests:

Checklist

  • I have read the CONTRIBUTING.md document.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have manually tested my changes end-to-end.
  • Any dependent changes have been merged and published in downstream modules.

Additional context

This aligns the TypeScript implementation of FileArtifactService with the Python ADK and ensures consistent behavior across artifact services.

return !sessionId || filename.startsWith(USER_NAMESPACE_PREFIX);
}

function getUserArtifactsDir(baseRoot: string): string {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/baseRoot/userRoot/g

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't look like this was done in these two methods

try {
await fs.access(artifactDir);
} catch {
return undefined;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this worth logging for debug purposes?

This goes for the rest of the "return undefined;" here, just not leaving a comment for each one. Some of them might point to bugs, like no version for a filename.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the rest were changed but not this one

@kalenkevich kalenkevich force-pushed the feat/file_artifact_service branch 7 times, most recently from 35a726b to 396f1b5 Compare February 18, 2026 05:42
@kalenkevich kalenkevich force-pushed the feat/file_artifact_service branch 3 times, most recently from 109eca2 to 2470ce8 Compare February 18, 2026 06:04
Copy link
Member

@ScottMansfield ScottMansfield left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this needs to be resolved in this PR but we should consider the similarities of a filesystem in GCS and a filesystem on disk. They're not too different and maybe the code could be largely shared.

let mimeType: string | undefined;
if (artifact.inlineData) {
const data = artifact.inlineData.data || '';
// We need to store binary data in base64 format.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This can still be more clear. GenAI SDK Part data is in Base64 format. See https://googleapis.github.io/js-genai/release_docs/interfaces/types.Part.html

try {
await fs.access(artifactDir);
} catch {
return undefined;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the rest were changed but not this one

return !sessionId || filename.startsWith(USER_NAMESPACE_PREFIX);
}

function getUserArtifactsDir(baseRoot: string): string {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't look like this was done in these two methods

const relative = file.name.substring(usernamePrefix.length);
const parts = relative.split('/');
if (parts.length >= 2) {
fileNames.add(`${parts.slice(0, -1).join('/')}`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unnecessary interpolation

Comment on lines 151 to 158
if (!file.name.startsWith(prefix)) continue;
const relative = file.name.substring(prefix.length);
const parts = relative.split('/');
// Expect at least name and version: name/version
// If name contains slashes: dir/name/version
if (parts.length < 2) continue;

const name = parts.slice(0, -1).join('/');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the third time this logic shows up in these few functions. I was going to ignore it for 2, but with a third this needs to be factored out into a function

@kalenkevich kalenkevich force-pushed the feat/file_artifact_service branch from 9462f0d to fd38679 Compare February 24, 2026 22:32
@kalenkevich kalenkevich force-pushed the feat/file_artifact_service branch from fd38679 to 6b710dd Compare February 24, 2026 23:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants