Skip to main content

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 require namespace; a personal-memory provider might only need user.
  • extensions — a record of capability keys to booleans. package, temporal, versioning, updater, graph, forgetter, profiler, reflector, batchOps, health. If extensions.package is true, the provider supports sdk.package(). If false, calling sdk.package() raises UnsupportedOperationError.

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