Storage batteries
These batteries persist artifact bytes only — not conversation state
The storage batteries implement the spool reader/writer pattern for SpooledArtifact persistence. They are NOT a replacement for the 25 TurnRunnerConfig storage callbacks. They do not persist Messages, Memories, or ToolCalls. Session state still requires all 25 callbacks. See Bring Your Own Storage.
They store artifact bytes. Nothing else.
When a tool handler returns a string or Uint8Array, the bundled OpenAI/WebLLM adapters currently spool it to in-memory storage. To use these storage batteries instead, build or wire your own executor path using these stores.
If you are running in production, bytes must survive across requests, server restarts, or browser sessions. The storage batteries provide the persistence layer for these artifact bytes.
They do not persist Message records, Memory records, ToolCall metadata, or any of the other primitives in the 25-callback surface. Those are yours to implement. See Bring Your Own Storage.
import { InMemorySpoolStore } from '@nhtio/adk/batteries/storage/in_memory'
const store = new InMemorySpoolStore()import { Disk } from 'flydrive'
import { FSDriver } from 'flydrive/drivers/fs'
import { FlydriveSpoolStore } from '@nhtio/adk/batteries/storage/flydrive'
const disk = new Disk(new FSDriver({ location: '/var/app/artifacts', visibility: 'public' }))
const store = new FlydriveSpoolStore(disk)import { OpfsSpoolStore, type OpfsDirectoryHandle } from '@nhtio/adk/batteries/storage/opfs'
const store = new OpfsSpoolStore({
directory: async () => {
const root = await navigator.storage.getDirectory()
return (await root.getDirectoryHandle('agent-artifacts', { create: true })) as OpfsDirectoryHandle
},
keyPrefix: 'agent-runs-'
})In-Memory (@nhtio/adk/batteries/storage/in_memory)
Environment-neutral. Works in Node, browsers, edge runtimes, and workers. Backed by a Map<string, string>.
Binary Data Corrupts Here
InMemorySpoolStore is strictly text-oriented. It forces a UTF-8 decode on whatever you feed it. If you attempt to store arbitrary binary data, it will corrupt. If your tools return binary payloads, use the Flydrive or OPFS batteries.
import { InMemorySpoolStore } from '@nhtio/adk/batteries/storage/in_memory'
const store = new InMemorySpoolStore()
// Write artifact bytes and get a reader
const reader = store.write(callId, artifactBytes)
// Read previously written bytes
const existingReader = store.read(callId) // returns InMemorySpoolReader | undefinedwrite() stores the bytes (converting Uint8Array to a UTF-8 string) and returns an InMemorySpoolReader bound to the stored content. read() returns a reader for a previously stored call ID, or undefined if not found.
Each call to write() or read() returns a fresh reader instance.
Use this for:
- Unit and integration tests
- Prototypes and quick CLI spikes
- Ephemeral environments where artifact loss on process exit is irrelevant
Do not use this for:
- Production deployments requiring binary data integrity
- Production deployments where artifacts must survive restarts or scale across multiple server instances
Flydrive (@nhtio/adk/batteries/storage/flydrive)
Node/server runtime; not browser. Requires flydrive as a peer dependency. Backed by a flydrive Disk — which can point at the local filesystem or remote object storage backends (S3, GCS, etc.) via any supported flydrive driver.
Install the peer dependency first:
npm install flydriveimport { Disk } from 'flydrive'
import { FSDriver } from 'flydrive/drivers/fs'
import { FlydriveSpoolStore } from '@nhtio/adk/batteries/storage/flydrive'
const disk = new Disk(new FSDriver({ location: '/var/app/artifacts', visibility: 'public' }))
const store = new FlydriveSpoolStore(disk)
// Write artifact bytes to the backing store
const reader = await store.write(callId, artifactBytes)
// Read previously written bytes
const existingReader = await store.read(callId) // FlydriveSpoolReader | undefinedFlydriveSpoolStore is stateless — it owns no in-memory cache. Multiple store instances sharing the same Disk are safe.
FlydriveSpoolReader supports line access, byte-length reporting, line counts, and full decoded string reads. Large artifacts use streaming mode for line/index access, but readAll()/asString() loads the full decoded string into memory.
Use this for:
- Server-side production deployments
- Multi-process setups where artifacts need to be shared via a cloud storage driver
OPFS (@nhtio/adk/batteries/storage/opfs)
Browser only. Uses the Origin Private File System — a sandboxed filesystem API available in modern browsers. No network required. Data persists in the browser's origin-private storage.
import { OpfsSpoolStore, type OpfsDirectoryHandle } from '@nhtio/adk/batteries/storage/opfs'
const store = new OpfsSpoolStore({
directory: async () => {
const root = await navigator.storage.getDirectory()
return (await root.getDirectoryHandle('agent-artifacts', { create: true })) as OpfsDirectoryHandle
},
keyPrefix: 'agent-runs-'
})
// Write artifact bytes
const reader = await store.write(callId, artifactBytes)
// Read previously written bytes
const existingReader = await store.read(callId) // OpfsSpoolReader | undefinedCorrect API Usage
The constructor accepts the directory callback options configuration. Passing a directory handle to write() or read() is not supported; those methods do not accept it.
OpfsSpoolStore works on the main thread and in Web Worker threads, using different internal code paths for each context. The public API is identical in both.
Use this for:
- Browser-embedded agents that need artifact persistence across page reloads
- Progressive web apps or browser extension-based agents
Choosing the Right Battery
These recommendations apply only for spool-byte persistence in production. For the 25-callback storage adapter, go to Bring Your Own Storage.
| Environment | Battery |
|---|---|
| Tests and prototypes | InMemorySpoolStore |
| Node server (development) | InMemorySpoolStore |
| Node server (production) | FlydriveSpoolStore |
| Browser | OpfsSpoolStore |
| Edge / serverless | InMemorySpoolStore (if artifact loss is acceptable) |
If your production setup needs artifact bytes to survive across requests or processes, use FlydriveSpoolStore. If your agent runs in the browser, use OpfsSpoolStore. If bytes are ephemeral and you are okay losing them on restart, InMemorySpoolStore is valid for production too — but only if you are not processing binary data.