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 IStorageBackend abstraction
  • 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 identifiers
  • bypassed – User opt-out status for "Plan" mode
  • justRegistered – 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

  1. Initial RequesthandleSessionInit detects missing sessionInfo and returns a form response via buildCodexFormResponse
  2. User Selection – Client submits team, agent, and optional task selections
  3. PersistenceMemoryProxy/src/session/store.ts persists the binding under a session key
  4. Asset Injection – Subsequent requests retrieve bindings and trigger injectWorkbuddyAssets for 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 IStorageBackend enables swapping between local filesystem, Tencent COS, or future backends without touching memory or routing code
  • Configuration-driven routing through ProxyConfig consolidates upstream selection, cost-guard logic, and request splitting into data structures rather than conditional code
  • Protocol-agnostic session management using handleSessionInit and the session store separates team binding logic from transport-specific handlers like workbuddyHandler.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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →