MemoryProxy Injection Pipeline: Understanding ContextContentProvider and InjectionHook Abstractions
The MemoryProxy injection pipeline in TencentDB-Agent-Memory uses the InjectionHook interface as its core abstraction, enabling protocol-agnostic context injection at specific InjectionPoint locations, while provider utilities in ContextContentProvider (via createInjectionHook) simplify the creation of cache-aware injectors that return ContextBlock arrays.
The TencentDB-Agent-Memory repository implements a sophisticated MemoryProxy injection pipeline that enriches LLM requests before they reach the model. This system relies on a strictly typed hierarchy of abstractions—centered on the InjectionHook contract and supporting provider utilities—to inject contextual blocks at precise conversation boundaries. The architecture supports priority-ordered execution, semantic anchoring, and cache-aware prewarming across different agent protocols.
The Core Data Model: ContextBlock and AgentContext
The pipeline operates on immutable data structures defined in MemoryProxy/src/injection/types.ts. Understanding these foundation types is essential before implementing custom hooks.
ContextBlock: The Atomic Content Unit
Every piece of injectable content is encapsulated as a ContextBlock. This union type supports text, tool calls, images, and custom payloads, making the pipeline protocol-agnostic.
export type ContextBlockType =
| "text" | "tool_use" | "tool_result" | "thinking" | "image" | "custom";
export interface ContextBlock {
type: ContextBlockType;
content: string;
metadata?: Record<string, unknown>;
}
AgentContext: The Pipeline Payload
The AgentContext interface (lines 128–146 in types.ts) represents the complete request state traversing the pipeline. It aggregates messages, available tools, request parameters, and metadata.
export interface AgentContext {
messages: ContextMessage[];
tools?: AgentTool[];
requestParams: Record<string, unknown>;
metadata: AgentContextMetadata;
}
The AgentContextMetadata sub-interface carries trace identifiers, user/session context, and protocol information required by injectors to make contextual decisions.
Injection Points and Semantic Anchoring
The MemoryProxy injection pipeline supports nine distinct InjectionPoint values (lines 148–164), defining exactly where content modification occurs:
- System message boundaries:
system.prefix,system.suffix,system.before_tools,system.after_tools - User message boundaries:
user.before,user.after,user.first_turn - Tool list modifications:
tools.append,tools.prepend
Portable Anchoring with SemanticSlot
For agents requiring precise structural placement, the AnchorTarget interface combines with SemanticSlot types to declare which conceptual region (e.g., "persona", "memory", "knowledge") receives the injection, independent of the underlying protocol representation.
export type SemanticSlot = "persona" | "tools" | "skills" | "memory" | "knowledge" | "rules" | "task_context" | (string & {});
export interface AnchorTarget {
slot?: SemanticSlot;
rawKey?: string;
relation: AnchorRelation;
}
The InjectionHook Interface: Core Abstraction
The InjectionHook interface (lines 122–162 in types.ts) is the primary contract that all context injectors must implement. This abstraction decouples content generation from application logic.
export interface InjectionHook {
id: string;
point: InjectionPoint;
anchor?: AnchorTarget;
priority: HookPriority;
description: string;
cacheStrategy?: CacheStrategy;
prewarm?(input: PrewarmInput): Promise<ContextBlock[]> | ContextBlock[];
execute(ctx: AgentContext): Promise<ContextBlock[]> | ContextBlock[];
}
Key properties include:
- point: The specific
InjectionPointwhere execution triggers - priority: Numeric execution order (lower values execute first)
- cacheStrategy: Controls precomputation via
"none","session_init", or"hybrid"modes - prewarm: Optional initialization function receiving
PrewarmInput(containingkeyId,userId,sessionInfo) - execute: The main method receiving
AgentContextand returningContextBlock[]arrays
Hook Priority and Registration
Execution Ordering with HookPriority
The pipeline respects explicit numerical priorities. The HOOK_PRIORITY constant (lines 332–353) provides sensible defaults:
export const HOOK_PRIORITY = {
SYSTEM: 0,
MEMORY: 100,
SKILL: 200,
WIKI: 300,
CUSTOM: 1000,
} as const;
The HookRegistry Contract
The HookRegistry interface (lines 64–78) manages hook lifecycle and retrieval. Implementations guarantee that getHooks(point) returns injectors sorted by priority for deterministic execution order.
export interface HookRegistry {
register(hook: InjectionHook): void;
unregister(hookId: string): void;
getHooks(point: InjectionPoint): InjectionHook[];
getAll(): InjectionHook[];
}
The concrete implementation resides in MemoryProxy/src/injection/registry.ts, while the factory function createInjectionHook in MemoryProxy/src/injection/provider.ts simplifies instantiation of compliant objects.
Cache-Aware Execution Strategies
The pipeline optimizes performance through the CacheStrategy union type ("none" | "session_init" | "hybrid"). When set to "session_init" or "hybrid", the prewarm method executes once during session establishment, allowing expensive data fetching (e.g., loading conversation history from TencentDB) to occur before the first turn.
The PrewarmInput interface supplies session context including keyId, agentSource, spaceId, and sessionInfo, enabling injectors to preload user-specific data.
Pipeline Orchestration
The InjectionPipeline implementation in MemoryProxy/src/injection/pipeline.ts coordinates the complete flow:
- Warm-up Phase: Invokes
prewarmon hooks with applicable cache strategies - Execution Phase: Collects
ContextBlockarrays from hooks at eachInjectionPointin priority order - Application Phase: Merges injected blocks into the
AgentContextaccording to semantic or positional rules - Observation Phase: Optional
InjectionObserverintegrations (defined inobserver.ts) emit telemetry to systems like Langfuse
Practical Implementation Example
Implementing a custom injector requires implementing the InjectionHook contract and registering via the provider utilities:
import { createInjectionHook } from "./injection/provider.js";
import { HOOK_PRIORITY, InjectionPoint } from "./injection/types.js";
const memoryInjector = createInjectionHook({
id: "mem-recent-conversation",
point: "user.before",
priority: HOOK_PRIORITY.MEMORY,
description: "Inject recent conversation snippets",
cacheStrategy: "hybrid",
async prewarm(input) {
// Called once per session during initialization
const recent = await fetchRecentMessages(input.keyId);
return recent.map(txt => ({ type: "text", content: txt }));
},
async execute(ctx) {
// Called per-turn for dynamic context
return [{ type: "text", content: "Remember to check the latest logs." }];
},
});
// Register with the global registry
registry.register(memoryInjector);
// Execute via the pipeline
const pipeline = getInjectionPipeline({});
const enrichedCtx = await pipeline.run(originalAgentContext);
This example demonstrates the ContextContentProvider pattern: the createInjectionHook factory transforms a configuration object into a fully compliant InjectionHook, handling interface conformance automatically.
Summary
- The MemoryProxy injection pipeline centers on the
InjectionHookinterface defined inMemoryProxy/src/injection/types.ts, which standardizes how contextual content enters the LLM request flow. - Nine distinct
InjectionPointvalues allow precise placement of injected content at system, user, or tool boundaries. - Priority-based execution (via
HookPriorityandHOOK_PRIORITYconstants) ensures system-level hooks execute before skill or memory hooks. - Cache strategies (
"session_init","hybrid") enable expensive data loading during session initialization via theprewarmlifecycle method. - The
createInjectionHookfactory inMemoryProxy/src/injection/provider.tsimplements the ContextContentProvider pattern, simplifying the creation of type-safe injectors. - The Pipeline orchestrator in
MemoryProxy/src/injection/pipeline.tscoordinates hook execution and block application across the conversation lifecycle.
Frequently Asked Questions
What is the difference between InjectionHook and ContextContentProvider?
InjectionHook is the strict TypeScript interface defining the contract for all injectors (id, point, priority, execute/prewarm methods), while ContextContentProvider refers to the factory utilities (particularly createInjectionHook in provider.ts) that instantiate these hooks. The provider abstracts boilerplate, allowing developers to supply only the configuration and logic functions while ensuring type safety.
How does hook priority affect injection order?
The priority property (typed as HookPriority, which is a number) determines execution sequence within each InjectionPoint. Lower numeric values execute first. The system provides predefined constants in HOOK_PRIORITY: SYSTEM (0), MEMORY (100), SKILL (200), WIKI (300), and CUSTOM (1000). The HookRegistry implementation automatically sorts hooks by priority when retrieved for a specific point.
What are the available cache strategies for injection hooks?
The CacheStrategy type supports three modes: "none" (execute execute() every turn), "session_init" (execute prewarm() once at session start and cache results), and "hybrid" (combine both—use prewarm for static data and execute for dynamic per-turn context). The PrewarmInput interface supplies session metadata including keyId, userId, and agentSource during the warm-up phase.
Where are the concrete implementations of the injection pipeline located?
The core type definitions reside in MemoryProxy/src/injection/types.ts. The pipeline orchestrator is implemented in MemoryProxy/src/injection/pipeline.ts, while hook registration logic lives in MemoryProxy/src/injection/registry.ts. Factory functions for creating hooks are found in MemoryProxy/src/injection/provider.ts, and real-world injector examples (such as tool injectors) are located in MemoryProxy/src/injection/injectors/.
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 →