How MemoryCore Functions in TencentDB Agent Memory: Architecture and Implementation

MemoryCore in TencentDB-Agent-Memory is implemented by the TdaiCore class, which serves as a host-neutral façade that manages four hierarchical memory layers (L0-L3) through lifecycle orchestration, recall pre-processing, turn capture, and pipeline scheduling, while exposing agent-callable tools and optional Skill module integration.

The TencentDB-Agent-Memory repository provides a production-grade memory system for AI agent frameworks. At its architectural center lies the MemoryCore functionality, primarily realized through the TdaiCore class in MemoryCore/src/core/tdai-core.ts, which coordinates raw conversation persistence, structured memory extraction, and intelligent retrieval across multiple abstraction layers.

Core Lifecycle Management

The TdaiCore class manages the entire memory system lifecycle through two primary methods. The initialize() function creates necessary data directories, instantiates the vector store and embedding service, and initializes the MemoryPipelineManager while wiring L1, L2, and L3 runners. When the Skill module is enabled in configuration, initialize() also triggers ensureSkillModuleWired() to construct the SkillCore and optional SkillExtractor. Conversely, destroy() gracefully shuts down the scheduler, drains background tasks tracked in the bgTasks set, and closes both the vector store and embedding service connections.

Pre-Prompt Recall Processing

Before the LLM generates a response, the handleBeforeRecall(userText, sessionKey) method processes retrieval requests. This function is invoked by the OpenClaw before_prompt_build hook (or Hermes prefetch) and executes performAutoRecall to query the vector store. The system applies configured recall strategies and reports latency metrics via reportRecallMetrics, ensuring relevant context from structured L1 memories and raw L0 conversations surfaces in the prompt context.

Post-Turn Capture and Persistence

After an agent completes a turn, handleTurnCommitted(turn) handles the agent_end hook to persist interaction data. This method first calls ensureSchedulerStarted() to guarantee the pipeline is active, then executes performAutoCapture which performs three critical operations: writing the conversation to L0 JSONL storage, submitting the turn to the pipeline manager for L1/L2/L3 extraction, and scheduling background L0 embedding tasks tracked in bgTasks for asynchronous processing.

Pipeline Scheduling and Layer Extraction

The MemoryPipelineManager, created via createPipelineManager in MemoryCore/src/utils/pipeline-factory.ts, orchestrates hierarchical memory formation. This manager buffers incoming turns and triggers L1 extraction (structured fact extraction) immediately, schedules L2 scene extraction after a configurable delay to aggregate related facts, and runs L3 persona generation on a periodic schedule. The wirePipelineRunners() method connects these L1/L2/L3 runners to the manager during initialization, creating a cohesive extraction pipeline.

Agent Tool Registration

The plugin entry point at MemoryCore/index.ts registers two agent-callable tools through its register(api) function. The tdai_memory_search tool delegates to TdaiCore.searchMemories for querying structured L1 memories, while tdai_conversation_search utilizes TdaiCore.searchConversations to retrieve raw L0 conversation logs. These tools enable agents to perform explicit memory retrieval beyond automatic recall mechanisms.

Optional Skill Module Integration

When cfg.skill.enabled is true, the ensureSkillModuleWired() method constructs a SkillCore instance with optional SkillExtractor capabilities. This module shares the primary vector store while maintaining separate SQLite tables for skill assets. The Skill module supports two operational modes: a singleton LLM runner for stand-alone deployments or per-instance factories for service-mode architectures where multiple agent instances require isolated processing contexts.

Concurrency and Safety Mechanisms

TdaiCore implements three critical concurrency safeguards. The schedulerStartPromise acts as a gate that ensures concurrent initialization calls all await the same asynchronous start sequence, preventing race conditions during checkpoint loading. The skillWiringPromise coalesces concurrent attempts to construct the Skill subsystem, avoiding duplicate resource allocation. Finally, the bgTasks Set tracks fire-and-forget embedding operations, allowing destroy() to await their completion within configured timeouts during graceful shutdown.

Metrics and Observability

The memory system exposes detailed telemetry through the MetricTrackingRunnerFactory wrapper. LLM-run credit consumption and recall latency metrics flow through reportRecallMetrics, while turn-level agent_turn metrics emit after each capture event. These reports contain complete prompt context, recalled memories, L0 record references, and operation durations, enabling comprehensive performance monitoring and debugging.

Code Examples

Initializing the Core System

import { OpenClawHostAdapter } from "./adapters/openclaw/host-adapter.js";
import { TdaiCore } from "./src/core/tdai-core.js";

const hostAdapter = new OpenClawHostAdapter({ 
  api, 
  pluginDataDir, 
  openclawConfig 
});

const core = new TdaiCore({
  hostAdapter,
  config: parsedConfig,                 // MemoryTdaiConfig from src/config.js
  sessionFilter: new SessionFilter([]), // optional exclusion patterns
});

await core.initialize();

// Pre-prompt recall
const recall = await core.handleBeforeRecall(
  "What did the user order last week?", 
  "sess‑123"
);

// Post-turn capture
await core.handleTurnCommitted({
  messages: turnMessages,
  sessionKey: "sess‑123",
  sessionId: "session‑abc",
  userText: "I want a pizza",
  originalUserMessageCount: 5,
  startedAt: Date.now(),
});

Registering Memory Search Tools

api.registerTool(
  {
    name: "tdai_memory_search",
    description: "Search L1 structured memories.",
    parameters: {
      type: "object",
      properties: {
        query: { 
          type: "string", 
          description: "What to recall?" 
        },
        limit: { 
          type: "number", 
          description: "Maximum results." 
        },
      },
      required: ["query"],
    },
    async execute(_, params) {
      const { query, limit } = params;
      const result = await core.searchMemories({ query, limit });
      return { 
        content: [{ type: "text", text: result.text }] 
      };
    },
  },
  { name: "tdai_memory_search" }
);

Summary

  • TdaiCore in MemoryCore/src/core/tdai-core.ts serves as the host-neutral MemoryCore implementation, managing initialization, recall, capture, and shutdown lifecycles.
  • The system implements four memory layers: L0 (raw JSONL conversations), L1 (structured facts), L2 (scene blocks), and L3 (persona synthesis), orchestrated by the MemoryPipelineManager.
  • Pre-prompt recall operates via handleBeforeRecall and performAutoRecall, while post-turn capture uses handleTurnCommitted and performAutoCapture to persist data and trigger extraction.
  • Two agent-callable tools—tdai_memory_search and tdai_conversation_search—expose explicit memory retrieval capabilities from MemoryCore/index.ts.
  • Concurrency guards including schedulerStartPromise, skillWiringPromise, and bgTasks ensure thread-safe initialization and graceful shutdown.
  • Optional Skill module integration supports both singleton and factory-mode architectures for asset extraction when enabled.

Frequently Asked Questions

What triggers the automatic recall mechanism in MemoryCore?

The handleBeforeRecall(userText, sessionKey) method triggers automatically when the OpenClaw framework executes the before_prompt_build hook (or Hermes prefetch). This method calls performAutoRecall to query the vector store using the configured recall strategy, ensuring relevant historical context surfaces before the LLM generates a response.

How does MemoryCore handle concurrent initialization requests?

MemoryCore uses a schedulerStartPromise gate that ensures all concurrent calls to initialization logic await the same asynchronous start sequence. This pattern prevents race conditions when loading checkpoints or starting the pipeline, guaranteeing that ensureSchedulerStarted() returns a consistent, initialized state across multiple concurrent invocations.

What is the difference between L0 and L1 memory layers?

L0 represents raw conversation storage written as JSONL files immediately during performAutoCapture, preserving the complete unprocessed turn history. L1 contains structured, semantically extracted facts generated by the pipeline manager's L1 runner, which processes raw L0 data to create queryable, vectorized memory entries stored in the shared vector store.

How does the Skill module integrate with the core memory system?

When enabled via cfg.skill.enabled, the ensureSkillModuleWired() method constructs a SkillCore instance that shares the primary vector store and embedding service while maintaining separate SQLite tables for skill-specific assets. The module can operate in stand-alone mode using a singleton LLM runner or service mode using per-instance factories, depending on deployment requirements.

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 →