How TencentDB Agent Memory Architecture Decouples Storage, Routing, and Team Management
TencentDB Agent Memory decouples storage, routing, and team management through three orthogonal layers: the IStorageBackend interface for pluggable persistence, the ProxyConfig object for data-driven request routing, and the handleSessionInit state machine for protocol-agnostic session binding.
The TencentCloud/TencentDB-Agent-Memory repository implements a modular AI memory system where each architectural layer depends only on well-defined interfaces rather than concrete implementations. This separation allows developers to swap storage backends, adjust routing strategies, or onboard new agent teams without modifying unrelated codebase components.
The Three-Layer Architectural Model
TencentDB Agent Memory organizes functionality into distinct concerns that communicate through narrow contracts:
- Storage Layer – Handles persistence for scene files, persona markdown, and L0/L1 records via the
IStorageBackendabstraction - Routing Layer – Directs traffic to appropriate LLM endpoints while applying cost-guard and request-splitting rules through configuration objects
- Team Management Layer – Binds user sessions to specific teams/agents and manages asset injection through the session initialization state machine
Each layer imports interfaces from lower layers but never concrete implementations, ensuring changes remain isolated.
Storage Decoupling via the IStorageBackend Interface
All persistence operations in TencentDB Agent Memory flow through a single abstraction defined in MemoryCore/src/core/storage/types.ts. Upper-layer modules like MemoryCore, MemoryKnowledge, and MemoryProxy import only this interface, never touching the COS SDK or Node.js fs module directly.
Core Storage Contract
The IStorageBackend interface standardizes operations across local filesystem and cloud object storage:
// MemoryCore/src/core/storage/types.ts
export interface IStorageBackend {
readonly type: "local" | "cos";
putObject(key: string, content: string|Buffer, opts?: PutObjectOptions): Promise<void>;
appendObject(key: string, content: string|Buffer): Promise<void>;
getObject(key: string): Promise<StorageObject | null>;
exists(key: string): Promise<boolean>;
listObjects(prefix: string, opts?: ListObjectsOptions): Promise<ListResult>;
deleteObject(key: string): Promise<void>;
deleteByPrefix(prefix: string): Promise<number>;
}
Concrete implementations reside in local-backend.ts and cos-backend.ts, selected at runtime via the StorageBackendConfig type. Adding Amazon S3 or MinIO support requires only implementing these seven methods and updating the configuration parser—no changes needed to memory management or routing logic.
Storage Usage Example
import { createStorageBackend } from "./core/storage/factory.js";
// Configure COS backend
const cfg = { type: "cos", credentialProvider: myProvider };
const storage = await createStorageBackend(cfg);
// Persist a markdown scene block
await storage.putObject(
"scenes/my-scene.md",
"# My Scene\nHello world",
{ contentType: "text/markdown" }
);
Routing Decoupling via ProxyConfig
Request routing decisions in TencentDB Agent Memory derive entirely from the ProxyConfig interface defined in MemoryProxy/src/types.ts. The proxy never hard-codes upstream URLs; instead, it constructs targets from configuration objects enabling dynamic routing without code redeployment.
Centralized Routing Configuration
The ProxyConfig interface encapsulates all routing concerns:
// MemoryProxy/src/types.ts
export interface ProxyConfig {
server: { host: string; port: number; forwardTimeoutMs?: number };
upstream: {
url: string; // Global upstream endpoint
apiKey: string;
agents: Record<string, AgentUpstreamEntry>;
};
costGuard: CostGuardConfig;
ccRequestRouting: CcRequestRoutingConfig;
workbuddyRequestRouting: WorkbuddyRequestRoutingConfig;
}
Per-agent routing allows specific teams to target dedicated infrastructure:
export interface AgentUpstreamEntry {
url: string;
apiKey?: string; // Falls back to global key if omitted
}
The forwardToUpstream function extracts these entries at runtime. For example, workbuddy requests resolve through config.upstream.agents.workbuddy while default traffic routes through the global URL.
Cost-Guard and Request Splitting
The architecture treats cost-guard and CC-request splitting as pure functions within the routing layer. CostGuardConfig toggles private forwarding extensions, while CcRequestRoutingConfig enables three-way traffic segmentation (main/fork/side-query) based on cache_control markers. These decisions return routing plans without mutating request bodies, preserving separation between routing logic and business logic.
Dynamic Routing Configuration
import { loadConfig } from "./config/loader.js";
const cfg = await loadConfig("./proxy.yaml");
// Enable cost-guard for specific models only
cfg.costGuard.enabled = true;
cfg.costGuard.agentProfile = "gemini";
// Route workbuddy traffic to isolated endpoint
cfg.upstream.agents.workbuddy = {
url: "https://workbuddy.api.example.com/v1",
apiKey: "wb-secret-key"
};
Team and Agent Management Decoupling
Team management operates through a protocol-agnostic session initialization layer that binds user contexts to specific agents without coupling to HTTP transport details.
Session Initialization State Machine
The handleSessionInit function exported from MemoryProxy/src/session/index.ts drives the entire onboarding flow. It accepts minimal input—primarily a messages[] array—and returns SessionInitResult containing:
sessionInfo– Bound team/agent/task identifiersbypassed– User opt-out status for "Plan" modejustRegistered– Session creation flag for pre-warming
All client types (codex, anthropic, workbuddy) reuse this single state machine, ensuring consistent team binding logic across protocols.
Workbuddy-Specific Session Handling
While sharing the core state machine, workbuddy requests maintain isolated session state through the WorkbuddySessionState interface defined in MemoryProxy/src/workbuddyHandler.ts:
export interface WorkbuddySessionState {
status: "initialized" | "pending";
bypassed?: boolean;
sessionInfo?: Record<string, unknown> | null;
}
After successful binding, the injectWorkbuddyAssets function constructs injection blocks containing skills and knowledge assets. This function shallow-copies request bodies to ensure other agents' pipelines remain unaffected by workbuddy-specific asset injection.
Team Binding Workflow
- Initial Request –
handleSessionInitdetects missingsessionInfoand returns a form response viabuildCodexFormResponse - User Selection – Client submits team, agent, and optional task selections
- Persistence –
MemoryProxy/src/session/store.tspersists the binding under a session key - Asset Injection – Subsequent requests retrieve bindings and trigger
injectWorkbuddyAssetsfor the first message only
Programmatic Team Assignment
import { getSessionStore } from "./session/store.js";
const store = getSessionStore();
const key = "workbuddy:abcd1234";
// Bind session to specific team and agent
await store.bind(key, {
userId: "user-5678",
agentSource: "workbuddy",
sessionId: "abcd1234",
spaceId: "team-42",
team_id: "team-42",
agent_id: "code-assistant"
});
// Retrieve binding for asset injection
const state = await store.get(key);
console.log(state.sessionInfo?.team_id); // "team-42"
Summary
TencentDB Agent Memory achieves architectural decoupling through three key design patterns:
- Storage abstraction via
IStorageBackendenables swapping between local filesystem, Tencent COS, or future backends without touching memory or routing code - Configuration-driven routing through
ProxyConfigconsolidates upstream selection, cost-guard logic, and request splitting into data structures rather than conditional code - Protocol-agnostic session management using
handleSessionInitand the session store separates team binding logic from transport-specific handlers likeworkbuddyHandler.ts
This separation allows independent scaling and modification of storage infrastructure, routing policies, and team onboarding flows while maintaining system stability.
Frequently Asked Questions
How does the storage layer handle backend selection at runtime?
The system uses a factory pattern in MemoryCore/src/core/storage/factory.js that instantiates either LocalBackend or CosBackend based on the type property in StorageBackendConfig. Both classes implement the identical IStorageBackend contract, allowing the factory to return the appropriate implementation without upstream modules knowing which persistence mechanism is active.
Can routing rules be changed without restarting the proxy?
Yes. Since ProxyConfig is loaded from YAML and referenced throughout the request lifecycle, updating the configuration file and triggering a hot-reload (or restarting the process) immediately applies new routing rules. All routing decisions—including per-agent upstream selection and cost-guard toggles—are pure data transformations from the config object.
What prevents team management logic from leaking into the routing layer?
The session initialization state machine in handleSessionInit operates solely on session metadata and returns results through the SessionStore interface. The routing layer (workbuddyHandler.ts) checks for existing sessionInfo but never contains logic for team selection forms or asset injection—that responsibility remains in the dedicated session management module, accessed only after routing decisions are complete.
How does the architecture support adding new agent types?
New agents require only three integration points: implementing an AgentUpstreamEntry in ProxyConfig for routing, potentially extending SessionStore bindings for team association, and optionally creating agent-specific injection functions like injectWorkbuddyAssets. The storage layer (IStorageBackend) and core session state machine require no modifications to support additional agent types.
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 →