Capabilities
Not every memory backend supports every operation. atomicmemory-core ships context packaging and temporal search; Mem0 does not. A custom provider you write might support neither. The SDK's design is to make these differences runtime-queryable rather than baked into types, so the same application code can target any configured backend.
The Capabilities object
Every provider returns a Capabilities object from its capabilities() method, declaring what it supports:
const caps = sdk.capabilities();
// {
// ingestModes: ['text', 'message', 'memory'],
// requiredScope: { user: true, agent: false, namespace: false, thread: false },
// extensions: { package: true, temporal: true, versioning: true, health: true, ... },
// customExtensions: { ... },
// }
Three fields matter in practice:
ingestModes— which shapes of input the provider accepts. Most providers accept all three; some specialize.requiredScope— which scope fields must be present in a request. For example, a workspace-only provider might requirenamespace; a personal-memory provider might only needuser.extensions— a record of capability keys to booleans.package,temporal,versioning,updater,graph,forgetter,profiler,reflector,batchOps,health. Ifextensions.packageistrue, the provider supportssdk.package(). Iffalse, callingsdk.package()raisesUnsupportedOperationError.
The extension probe
The public way to get at an extension is provider.getExtension<T>(name):
import type { Packager } from '@atomicmemory/atomicmemory-sdk';
const packager = provider.getExtension<Packager>('package');
if (packager) {
const pkg = await packager.package(request);
// use pkg.text directly as injected context
}
The extension key matches the capability key ('package', not 'packager') — this is the contract, and it matches the implementation (src/memory/memory-service.ts:188).
Why apps must check
An app that calls sdk.package() without first confirming the capability is declaring a dependency on a specific backend. That's fine if you know you're always talking to atomicmemory-core, but it defeats the purpose of the SDK's backend-agnostic design.
The recommended pattern for portable code:
const { extensions } = sdk.capabilities();
if (extensions.package) {
const pkg = await sdk.package(request, site);
return pkg.text;
} else {
// Graceful degradation: fall back to search + local formatting
const page = await sdk.search(request, site);
return formatResults(page.results);
}
Capabilities are read once
capabilities() is not a runtime guard — it is a declaration. Providers do not change their capabilities after initialization, so reading the object once at startup is fine. Cache it if you check frequently.
Next
- Provider model — the interface the capabilities describe
- Swapping backends — the operational story when capabilities differ across providers