Skip to main content

Writing a custom provider

The provider interface is deliberately small. If you want to back the SDK with something other than atomicmemory-core or Mem0 — an internal memory service, a Pinecone-fronted store, a SQLite-over-disk prototype — you write a MemoryProvider and register it. Application code keeps calling the same SDK methods.

Minimum implementation

Extend BaseMemoryProvider — it provides the scope-validation scaffolding and a default getExtension that checks your declared capabilities.

import {
BaseMemoryProvider,
type Capabilities,
type IngestInput,
type IngestResult,
type SearchRequest,
type SearchResultPage,
type ListRequest,
type ListResultPage,
type MemoryRef,
type Memory,
} from '@atomicmemory/atomicmemory-sdk';

export class MyProvider extends BaseMemoryProvider {
readonly name = 'my-provider';

constructor(private readonly config: { endpoint: string }) {
super();
}

capabilities(): Capabilities {
return {
ingestModes: ['text', 'message', 'memory'],
requiredScope: {
user: true,
agent: false,
namespace: false,
thread: false,
},
extensions: {
package: false,
temporal: false,
versioning: false,
updater: false,
graph: false,
forgetter: false,
profiler: false,
reflector: false,
batchOps: false,
health: true,
},
customExtensions: {},
};
}

async ingest(input: IngestInput): Promise<IngestResult> {
const res = await fetch(`${this.config.endpoint}/ingest`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(input),
});
if (!res.ok) throw new Error(`ingest failed: ${res.status}`);
return res.json();
}

async search(request: SearchRequest): Promise<SearchResultPage> { /* ... */ }
async get(ref: MemoryRef): Promise<Memory | null> { /* ... */ }
async delete(ref: MemoryRef): Promise<void> { /* ... */ }
async list(request: ListRequest): Promise<ListResultPage> { /* ... */ }
}

That's it. The six core methods plus capabilities() and the provider name. Everything else is opt-in.

Register the provider

Providers are created by factories in the registry. The simplest path is to construct your provider and pass it in via a factory-style registration. See src/memory/providers/registry.ts for the shipped registry and the pattern for adding to it.

At SDK construction time, reference your provider by name in context.providers:

const sdk = new AtomicMemorySDK({
userAccounts: { /* ... */ },
context: {
providers: {
default: 'my-provider',
'my-provider': { endpoint: 'https://memory.internal.example.com' },
},
},
});

Declaring capabilities accurately

Two rules:

  1. Don't lie. If capabilities().extensions.package is true, your getExtension('package') must return a real Packager. The default BaseMemoryProvider.getExtension returns this when the capability is true and relies on the subclass implementing the extension methods on itself.
  2. Declare requiredScope honestly. If your backend needs namespace to partition correctly, set requiredScope.namespace: true. BaseMemoryProvider.validateScope will reject requests missing required fields before they reach your network code.

Implementing an extension

If you want to support context packaging:

import type { Packager, PackageRequest, ContextPackage } from '@atomicmemory/atomicmemory-sdk';

export class MyProvider extends BaseMemoryProvider implements Packager {
// ... core methods, capabilities ...

async package(request: PackageRequest): Promise<ContextPackage> {
const page = await this.search(request);
const text = formatInjection(page.results, request.tokenBudget ?? 2000);
return { text, results: page.results, tokens: approxTokens(text) };
}
}

Set capabilities().extensions.package = true. Done — sdk.package() now works.

Testing

The SDK's own test suite uses a fixture provider (src/memory/__tests__/memory-service.test.ts). The pattern works for any custom provider: construct the SDK with your provider as default, exercise the public SDK methods, assert on observable behaviour rather than internal state.

Next

  • Provider model — the full extension menu you can opt into
  • Capabilities — the contract apps rely on when they call your provider