How Data Isolation Works in TencentDB Agent Memory: Architecture and Implementation
TencentDB Agent Memory enforces strict multi‑tenant data isolation through a mandatory four‑field tuple (team_id, agent_id, user_id, session_id) validated at the API layer and embedded into storage keys.
The TencentDB-Agent-Memory repository implements a layered isolation strategy that spans from incoming HTTP requests down to the underlying Redis and SQLite storage backends. This design ensures that teams, agents, and users can never access data outside their authorized scope, even when multiple tenants share the same infrastructure.
The Isolation Tuple: Core Identity Fields
All v3 API endpoints—representing the "strict isolation version" of the data plane—require four identity fields that together form a composite isolation key. The Zod schema isolationFieldsSchema in MemoryCore/src/gateway/v2-schemas.ts defines these mandatory fields:
export const isolationFieldsSchema = z.object({
team_id: z.string().nonempty(),
agent_id: z.string().nonempty(),
user_id: z.string().nonempty(),
session_id: z.string().nonempty(),
});
Source: MemoryCore/src/gateway/v2-schemas.ts#L300-L305
An optional fifth field, task_id, can be appended for finer-grained task-level scoping but is not enforced by the base isolation schema.
API Layer Enforcement
v3 Router Validation
The gateway router explicitly designates /v3 as the strict isolation path that shares handlers with /v2 but applies separate validation:
// /v3 is L0–L3 data-plane strict isolation version
// - shares handler with /v2 but uses separate isolation validation
// /v3 paths require team_id, agent_id, user_id, session_id
Source: MemoryCore/src/gateway/v2-router.ts#L102-L105
When a request hits any /v3 endpoint, the router parses incoming headers or body fields against isolationFieldsSchema. Missing values trigger an immediate 422 error before any data layer access occurs.
Header and Body Extraction
Isolation fields can be supplied via x-tdai-* headers or JSON payload fields. The parsing utilities in the gateway normalize these sources into a consistent internal structure used by downstream handlers.
Source: MemoryCore/src/gateway/v2-router.ts#L80-L150
SDK-Level Contract Enforcement
TypeScript SDK
The MemoryClient constructor for v3 demands a V3IsolationContext object. Omitting this parameter throws a ParamError at instantiation:
export interface V3IsolationContext {
/** Team ID. Required by v3 strict isolation. */
team_id: string;
/** Agent ID. Required by v3 strict isolation. */
agent_id: string;
/** User ID. Required by v3 strict isolation. */
user_id: string;
/** Session ID. Required by v3 strict isolation. */
session_id: string;
/** Optional task ID carried in isolation fields. */
task_id?: string;
}
constructor(transport: Transport, isolation: V3IsolationContext) {
if (!isolation) throw new ParamError("v3 MemoryClient transport constructor requires isolation context");
this.isolation = {
team_id: isolation.team_id,
agent_id: isolation.agent_id,
user_id: isolation.user_id,
session_id: isolation.session_id,
task_id: isolation.task_id,
};
}
Sources:
- Type definition:
sdk/memory-core/typescript/src/v3/types.ts#L1-L11 - Constructor enforcement:
sdk/memory-core/typescript/src/v3/client.ts#L140-L149
Python SDK
The Python v3 client mirrors this behavior, rejecting any construction attempt without the isolation dictionary:
client = MemoryClient(
transport,
isolation={
"team_id": "team-123",
"agent_id": "agent-beta",
"user_id": "user-99",
"session_id": "sess-20230902-002",
},
)
Source: sdk/memory-core/python/tencentdb_agent_memory/v3/client.py#L155-L162
Storage Layer Isolation
Redis Key Prefixing
The memory proxy service embeds isolation fields directly into Redis key names, ensuring physical separation at the caching layer:
${serviceId}:session:${sessionKey}:${teamId}:${agentId}
This pattern guarantees that even with shared Redis infrastructure, keys from different teams or agents remain namespace-separated and cannot collide or be accessed through key enumeration.
Source: MemoryProxy/src/redis-session-store.ts#L1-L3
SQLite Scoped Stores
For persistent knowledge storage, SQLite-backed stores are initialized per serviceId with isolation enforced through table-level separation or database file organization, preventing cross-tenant data leakage at the filesystem and query levels.
Source: MemoryKnowledge/src/store/sqlite-store.ts#L6-L7
Environment Configuration
The gateway's environment configuration documents that v3 endpoints reject requests lacking isolation fields, serving as a runtime contract enforcement mechanism:
Source: MemoryCore/src/utils/env-config.ts#L153-L155
Practical Usage Examples
TypeScript Client with Strict Isolation
import { MemoryClient } from '@tencentdb-agent-memory/memory-sdk-ts/v3';
const transport = new HttpTransport({ baseUrl: 'https://memory.api.tencentcloud.com' });
const isolation = {
team_id: 'team-123',
agent_id: 'agent-alpha',
user_id: 'user-42',
session_id: 'sess-20230902-001',
};
// Constructor throws ParamError if any isolation field is missing
const client = new MemoryClient(transport, isolation);
// All operations automatically scoped to the isolation tuple
await client.conversationAdd({
messages: [{ role: 'user', content: 'Hello' }],
});
Direct REST API Call
POST /v3/conversation/add HTTP/1.1
Host: memory.api.tencentcloud.com
Content-Type: application/json
x-tdai-team-id: team-456
x-tdai-agent-id: agent-gamma
x-tdai-user-id: user-77
x-tdai-session-id: sess-20230902-003
{
"messages": [{"role": "user", "content": "How does isolation work?"}]
}
Missing any header results in a 422 response from the gateway validator.
Isolation Level Matrix
| Layer | Mechanism | Enforcement Point |
|---|---|---|
| API Gateway | Schema validation (isolationFieldsSchema) |
v2-router.ts for all /v3/* paths |
| SDK Constructor | Mandatory V3IsolationContext parameter |
client.ts in TypeScript and Python SDKs |
| HTTP Transport | Header injection from context | SDK request interceptors |
| Redis Cache | Key prefix with serviceId:teamId:agentId |
redis-session-store.ts |
| SQLite Persistence | Per-service database scoping | sqlite-store.ts in Knowledge service |
Summary
- TencentDB Agent Memory data isolation relies on a mandatory four-field tuple:
team_id,agent_id,user_id,session_id - API layer validates this tuple via
isolationFieldsSchemainv2-schemas.tsat the/v3router level - SDK constructors require
V3IsolationContextand throwParamErrorif fields are absent, preventing accidental unscoped calls - Storage backends embed isolation fields into Redis key prefixes and SQLite database scoping for physical separation
- Multi-layer defense: Gateway validation, SDK enforcement, and storage naming conventions work together to guarantee tenant isolation
Frequently Asked Questions
What happens if I omit an isolation field in a v3 API request?
The gateway returns a 422 Unprocessable Entity error. The isolationFieldsSchema in v2-schemas.ts requires all four fields (team_id, agent_id, user_id, session_id) to be non-empty strings, and the v3 router applies this validation before any handler execution.
Can I use the same MemoryClient for multiple users or sessions?
No—the V3IsolationContext is immutable after client construction. Each distinct (team, agent, user, session) combination requires a separate MemoryClient instance. The SDK design intentionally prevents sharing clients across isolation boundaries to eliminate accidental data leakage.
How does the storage layer prevent key collisions between teams?
Redis keys follow a structured prefix pattern: ${serviceId}:session:${sessionKey}:${teamId}:${agentId}. This ensures that identical session keys from different teams occupy distinct Redis namespaces. SQLite stores similarly scope tables or databases by serviceId first, then apply query-level filtering by isolation fields.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →