Skip to content
reaatechREAATECH

@reaatech/a2a-reference-persistence

npm v0.1.0

Provides a standardized `TaskStore` interface for persisting A2A task state, offering implementations for in-memory, file-system, and Redis storage. It supports paginated listing, history management, and artifact tracking, with the Redis implementation requiring the `ioredis` package at runtime.

@reaatech/a2a-reference-persistence

npm version License: MIT CI

Status: Pre-1.0 — APIs may change in minor versions. Pin to a specific version in production.

Task store abstractions for persisting A2A task state. Provides a consistent TaskStore interface with three implementations: in-memory (zero-dependency), file-system (single JSON file), and Redis (via ioredis).

Installation

terminal
npm install @reaatech/a2a-reference-persistence
# or
pnpm add @reaatech/a2a-reference-persistence

For Redis support, install ioredis:

terminal
npm install ioredis

Feature Overview

  • Single abstractionTaskStore interface defines 8 methods shared by all implementations
  • In-memory store — fast, ephemeral, zero dependencies beyond @reaatech/a2a-reference-core
  • File-system store — persists to a single JSON file, write-through on every mutation
  • Redis store — distributed, persistent, suitable for multi-process deployments
  • History truncation — automatic enforcement of historyLength caps
  • Paginated listing — cursor-based pagination with contextId and status filtering

Quick Start

typescript
import {
  InMemoryTaskStore,
  FileSystemTaskStore,
  RedisTaskStore,
} from "@reaatech/a2a-reference-persistence";
import Redis from "ioredis";
 
// In-memory (ephemeral, no setup)
const memoryStore = new InMemoryTaskStore();
 
// File-system (persistent, single JSON file)
const fileStore = new FileSystemTaskStore({ path: "./tasks.json" });
await fileStore.load();
 
// Redis (distributed, production)
const redis = new Redis("redis://localhost:6379");
const redisStore = new RedisTaskStore({ redis });

API Reference

TaskStore Interface

The contract that all implementations fulfill:

typescript
interface TaskStore {
  create(task: Task): Promise<void>;
  get(id: string, options?: { historyLength?: number }): Promise<Task | undefined>;
  update(id: string, updates: Partial<Task> | ((task: Task) => Task)): Promise<Task | undefined>;
  list(options?: {
    contextId?: string;
    status?: TaskStatus;
    pageSize?: number;
    pageToken?: string;
    historyLength?: number;
  }): Promise<{ tasks: Task[]; nextPageToken: string; totalSize: number }>;
  cancel(id: string): Promise<Task | undefined>;
  addHistory(id: string, message: Message): Promise<void>;
  addArtifact(id: string, artifact: Artifact): Promise<void>;
  updateStatus(id: string, status: TaskStatus): Promise<void>;
}
MethodDescription
createPersist a new task
getRetrieve a task by ID with optional history truncation
updatePartial update or function-based update
listPaginated listing with optional filters
cancelCancel a task (no-op if already terminal)
addHistoryAppend a message to the task’s history
addArtifactAppend an artifact to the task
updateStatusReplace the task’s status object

InMemoryTaskStore

Ephemeral Map-backed store. Ideal for development and testing.

typescript
const store = new InMemoryTaskStore();
 
await store.create(task);
const t = await store.get("task-abc123");
const { tasks, nextPageToken, totalSize } = await store.list({ pageSize: 10 });
  • No constructor arguments
  • Data is lost on process exit
  • No cleanup or connection management required

FileSystemTaskStore

Persists tasks to a single JSON file with write-through on every mutation.

typescript
const store = new FileSystemTaskStore({ path: "./data/tasks.json" });
await store.load();           // Hydrate from disk (idempotent — creates file if missing)
// ... use the store ...
await store.close();          // Flush and stop periodic sync

FileSystemTaskStoreOptions

PropertyTypeDescription
pathstringFile path to the JSON store file

Key behaviors:

  • Write-through — every mutation immediately writes the full JSON file
  • Periodic flush — a 5-second interval ensures data is synced even if a write is missed
  • Error tolerance — missing files on load() initialize an empty store without error
  • Shutdown — call close() before process exit to flush pending writes

RedisTaskStore

Redis-backed store using ioredis. Suitable for distributed, multi-process deployments.

typescript
import Redis from "ioredis";
 
const redis = new Redis({
  host: "localhost",
  port: 6379,
  password: "optional",
});
 
const store = new RedisTaskStore({ redis, keyPrefix: "a2a" });
// ... use the store ...
await store.close(); // Calls redis.quit()

RedisTaskStoreOptions

PropertyTypeDefaultDescription
redisRedis(required)Pre-configured ioredis client instance
keyPrefixstringa2aPrefix for all Redis keys

Key schema:

  • <prefix>:task:<id> — JSON-serialized task objects
  • <prefix>:tasks — Redis set tracking all task IDs for enumeration

Integration with the Server

typescript
import { createA2AExpressApp } from "@reaatech/a2a-reference-server";
import { FileSystemTaskStore } from "@reaatech/a2a-reference-persistence";
 
const taskStore = new FileSystemTaskStore({ path: "./tasks.json" });
await taskStore.load();
 
const app = createA2AExpressApp({ agentCard, executor, taskStore });
 
// Graceful shutdown
process.on("SIGTERM", async () => {
  await app.shutdown();
  await taskStore.close();
  process.exit(0);
});
 
app.listen(3000);

Choosing a Store

StoreUse Case
InMemoryTaskStoreDevelopment, testing, single-process prototypes
FileSystemTaskStoreSingle-server deployments, simple persistence needs
RedisTaskStoreMulti-process deployments, horizontal scaling, production

All three implement the same interface — swap them without changing application code.

License

MIT