External Memory Plugin
Develop external memory adapters against the current Nexent contract and prove them without live-service CI dependencies.
Establish scope
- Read the repository
AGENTS.mdand invoke its SPEC workflow for production behavior changes. - Inspect, rather than assume, these current contracts:
sdk/nexent/memory/providers/base.pysdk/nexent/memory/models.pybackend/services/memory_provider_plugin_loader.pybackend/services/memory_external_provider_service.py
- Read references/plugin-contract.md before creating or reviewing a manifest or provider.
- Read references/mem0-example.md when implementing HTTP transport, error mapping, or tests.
- Preserve tenant, user, Agent, and conversation scope. Never print or persist credentials.
Implement the adapter
- Create
<plugin-dir>/<name>/plugin.yamlandprovider.py. - Declare only implemented capabilities in
implements. - Make protocol methods asynchronous and return the exact Nexent models.
- Honor provider-level
timeout_secondsand result limits. - Map remote failures to
ProviderErrorand the retry exception matching recovery semantics. - Keep OTel attributes low-cardinality and free of queries, memory content, user identifiers, tenant identifiers, and secrets. Rely on the orchestration service's standard instrumentation unless provider-specific spans add actionable detail.
- Treat the deployment search/ingest switches as kill switches and the provider
enabledfield as the instance switch; do not bypass them in normal runtime paths.
Test without external dependencies
- Test manifest discovery and protocol validation with a temporary plugin directory.
- Mock the network at the HTTP client transport boundary; for
httpx, useMockTransport. - Cover successful, empty, partial, malformed, unauthorized, forbidden, rate-limited, timeout, connection, and server-error responses as applicable.
- Assert request scope and authentication shape without using real credentials.
- Assert every ingest unit receives a result and retry classification is correct.
- Run the narrow plugin and loader suites first, then affected service and integration suites.
- Reach at least 90% coverage for each new or modified module.
Do not let a test silently reach the internet. Real-provider tests require explicit authorization and must remain separate from CI unit tests.
Verify installation and runtime
- Keep partner code outside the Nexent Git worktree and image. Locate the deployment's
nexent-dataroot, then copy the plugin to itsmemory-provider-plugins/<plugin-name>child. - For Docker, resolve
ROOT_DIRfrom the deployment argument ordeploy/env/.env(default$HOME/nexent-data). For Kubernetes local storage, readglobal.sharedStorage.memoryPlugins.localPath; for other storage classes, inspect thenexent-memory-pluginsPVC. Do not redefine the established in-container path/mnt/nexent-data/memory-provider-plugins. - Restart both services, then confirm discovery through
GET /memory/provider-pluginsor the Memory Management UI. - Create a disabled provider configuration and run test search and ingest.
- Enable the provider and the required deployment kill switch only after connectivity succeeds.
- Use unique internal and external memory markers in an Agent conversation.
- Inspect
nexent.memory.external_providerspans and standard metrics for operation, provider, outcome, error code, latency, and result/unit counts. - Record sanitized evidence. Do not call the feature complete when real-runtime or required telemetry evidence is unavailable; mark that verification blocked.
Review checklist
- Manifest fields and class name match the files.
config_schemamarks secrets and required fields correctly.- Search results set
sourceandis_external=True. - Ingest handles idempotency and partial acceptance.
- Error types match retry behavior.
- Logs, exceptions, metrics, and spans contain no sensitive payloads.
- Unit tests are deterministic and network-isolated.
- Deployment and user documentation name both switch levels.