TypeScriptADK-TS
Artifacts

Service Implementations

Different artifact service backends and their configurations for various deployment scenarios

The artifact system is built around the BaseArtifactService interface, which allows you to choose different storage backends based on your requirements. Each implementation offers different trade-offs between performance, persistence, and scalability.

BaseArtifactService Interface

All artifact services implement the same core interface:

import type { Part } from '@google/genai';

interface BaseArtifactService {
  saveArtifact(args: {
    appName: string;
    userId: string;
    sessionId: string;
    filename: string;
    artifact: Part;
  }): Promise<number>;

  loadArtifact(args: {
    appName: string;
    userId: string;
    sessionId: string;
    filename: string;
    version?: number;
  }): Promise<Part | null>;

  listArtifactKeys(args: {
    appName: string;
    userId: string;
    sessionId: string;
  }): Promise<string[]>;

  deleteArtifact(args: {
    appName: string;
    userId: string;
    sessionId: string;
    filename: string;
  }): Promise<void>;

  listVersions(args: {
    appName: string;
    userId: string;
    sessionId: string;
    filename: string;
  }): Promise<number[]>;
}

This consistent interface allows you to switch between implementations without changing your agent code.

InMemoryArtifactService

Fast, temporary storage for development and testing scenarios.

Characteristics

  • Storage: Artifacts stored in memory only
  • Persistence: Data lost when process terminates
  • Performance: Fastest access, no network latency
  • Scalability: Limited by available RAM
  • Use Cases: Development, testing, prototyping

Setup and Configuration

import { InMemoryArtifactService, Runner } from '@iqai/adk';

// Create the service (no configuration needed)
const artifactService = new InMemoryArtifactService();

// Use with Runner
const runner = new Runner({
  appName: "my_app",
  agent: myAgent,
  sessionService: mySessionService,
  artifactService
});

Example Usage

import { InMemoryArtifactService } from '@iqai/adk';

const artifactService = new InMemoryArtifactService();

// Save an artifact
const textArtifact = {
  inlineData: {
    data: Buffer.from('Hello, World!').toString('base64'),
    mimeType: 'text/plain'
  }
};

const version = await artifactService.saveArtifact({
  appName: 'test_app',
  userId: 'user123',
  sessionId: 'session456',
  filename: 'greeting.txt',
  artifact: textArtifact
});

console.log(`Saved version: ${version}`); // 0

// Load the artifact
const loaded = await artifactService.loadArtifact({
  appName: 'test_app',
  userId: 'user123',
  sessionId: 'session456',
  filename: 'greeting.txt'
});

if (loaded) {
  const text = Buffer.from(loaded.inlineData.data, 'base64').toString();
  console.log(`Loaded: ${text}`); // "Hello, World!"
}

Internal Implementation

The InMemoryArtifactService uses a simple Map to store artifacts:

// Internal storage structure
private readonly artifacts: Map<string, Part[]> = new Map();

// Path generation handles scoping
private getArtifactPath(
  appName: string,
  userId: string,
  sessionId: string,
  filename: string
): string {
  if (filename.startsWith("user:")) {
    return `${appName}/${userId}/user/${filename}`;
  }
  return `${appName}/${userId}/${sessionId}/${filename}`;
}

Data stored in InMemoryArtifactService is lost when the process restarts. Use only for development and testing.

GcsArtifactService

Production-ready artifact storage using Google Cloud Storage.

Characteristics

  • Storage: Google Cloud Storage buckets
  • Persistence: Durable, replicated storage
  • Performance: Network-dependent, highly optimized
  • Scalability: Virtually unlimited
  • Use Cases: Production deployments, large-scale applications

Setup and Configuration

import { GcsArtifactService, Runner } from '@iqai/adk';

// Basic configuration
const artifactService = new GcsArtifactService('my-artifacts-bucket');

// Use with Runner
const runner = new Runner({
  appName: "production_app",
  agent: myAgent,
  sessionService: mySessionService,
  artifactService
});

Google Cloud Setup

Before using GcsArtifactService, ensure your Google Cloud environment is configured:

  1. Create a Storage Bucket:
gsutil mb gs://my-artifacts-bucket
  1. Set up Authentication:
# Using service account
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account.json"

# Or using gcloud CLI
gcloud auth application-default login
  1. Set Bucket Permissions:
# Grant your service account storage access
gsutil iam ch serviceAccount:my-service@project.iam.gserviceaccount.com:roles/storage.objectAdmin gs://my-artifacts-bucket

Storage Structure

The GCS implementation organizes artifacts using a hierarchical structure:

my-artifacts-bucket/
├── app1/
│   ├── user123/
│   │   ├── session456/
│   │   │   ├── temp_file.txt/
│   │   │   │   ├── 0  (version 0)
│   │   │   │   └── 1  (version 1)
│   │   │   └── analysis.json/
│   │   │       └── 0
│   │   └── user/
│   │       └── user:profile.png/
│   │           ├── 0
│   │           └── 1
│   └── user456/
│       └── ...
└── app2/
    └── ...

Example Usage

import { GcsArtifactService } from '@iqai/adk';

const artifactService = new GcsArtifactService('my-artifacts-bucket');

// Save a large binary file
const imageData = Buffer.from(/* your image data */);
const imageArtifact = {
  inlineData: {
    data: imageData.toString('base64'),
    mimeType: 'image/png'
  }
};

try {
  const version = await artifactService.saveArtifact({
    appName: 'photo_app',
    userId: 'user789',
    sessionId: 'session123',
    filename: 'user:profile_picture.png',
    artifact: imageArtifact
  });

  console.log(`Image saved as version ${version}`);

  // List all artifact filenames for this user/session
  const artifactKeys = await artifactService.listArtifactKeys({
    appName: 'photo_app',
    userId: 'user789',
    sessionId: 'session123'
  });

  console.log('Available artifacts:', artifactKeys);
  // ['user:profile_picture.png', ...]

} catch (error) {
  console.error('GCS operation failed:', error);
}

Performance Considerations

Optimization Strategies:

// Batch operations when possible
const operations = [
  artifactService.saveArtifact({ /* args1 */ }),
  artifactService.saveArtifact({ /* args2 */ }),
  artifactService.saveArtifact({ /* args3 */ })
];

const versions = await Promise.all(operations);
console.log('All artifacts saved:', versions);

// Use streaming for large files
const loadLargeArtifact = async (filename: string) => {
  try {
    const artifact = await artifactService.loadArtifact({
      appName: 'my_app',
      userId: 'user123',
      sessionId: 'session456',
      filename
    });

    if (artifact && artifact.inlineData.data.length > 10 * 1024 * 1024) {
      console.log('Large artifact detected, consider streaming');
    }

    return artifact;
  } catch (error) {
    console.error('Failed to load large artifact:', error);
    return null;
  }
};

Error Handling

const robustGcsOperations = async () => {
  const artifactService = new GcsArtifactService('my-bucket');

  try {
    const artifact = await artifactService.loadArtifact({
      appName: 'my_app',
      userId: 'user123',
      sessionId: 'session456',
      filename: 'config.json'
    });

    if (!artifact) {
      console.log('Artifact not found, creating default');
      // Create and save default artifact
    }

  } catch (error) {
    if (error.code === 404) {
      console.log('Bucket or file not found');
    } else if (error.code === 403) {
      console.error('Permission denied - check IAM settings');
    } else {
      console.error('Unexpected GCS error:', error);
    }

    // Implement fallback behavior
    return getDefaultConfig();
  }
};

The GCS service automatically handles retries for transient errors and provides built-in redundancy and durability.

Custom Service Implementation

You can implement your own artifact service by extending the BaseArtifactService interface for specific requirements like database storage or caching layers.

Service Selection Guide

Choose the appropriate artifact service based on your requirements:

Development and Testing

  • Use: InMemoryArtifactService
  • Reasons: Fast, simple setup, no external dependencies
  • Limitations: Data lost on restart

Production Applications

  • Use: GcsArtifactService or custom database service
  • Reasons: Durable storage, scalability, backup/recovery
  • Considerations: Network latency, cost, compliance requirements

Hybrid Scenarios

  • Use: Combination approach with caching
  • Implementation: Database/GCS for persistence + Redis for caching
  • Benefits: Fast access with durability

Performance Comparison

Service TypeRead SpeedWrite SpeedDurabilityScalabilitySetup Complexity
InMemoryFastestFastestNoneRAM-limitedMinimal
GCSFastFastHighUnlimitedModerate
DatabaseModerateModerateHighHighHigh
RedisVery FastVery FastModerateHighModerate

Choose based on your specific requirements for performance, durability, and operational complexity.