How MemoryProxy Injects Team Memory and Skills into LLM Requests
TLDR: MemoryProxy injects team memory and skills into LLM requests by rendering static curl-based tool specification blocks into the system prompt via two dedicated injectors — TdaiMemoryToolsInjector and SkillToolsInjector — which embed session identity as HTTP headers so the LLM can call team-wide resources without ever seeing or forging secrets.
In the TencentCloud/TencentDB-Agent-Memory repository, MemoryProxy acts as a secure gateway between an LLM and shared team assets. Every LLM turn is enriched with tool definitions that let the model search memory and manage skills, while identity is handled automatically through HTTP headers. This article breaks down the exact injection mechanism, the source files that implement it, and how the whole pipeline protects your data.
The Two Injection Hooks
MemoryProxy uses two dedicated injection hooks to enrich every LLM turn with static, session-stable tool specifications. Both operate at the system prompt level, keeping the model's visible context clean and free of any sensitive identity information.
| Hook | What it injects | Where it is inserted | How identity is added |
|---|---|---|---|
TdaiMemoryToolsInjector |
A <tdai_memory_tools> block describing read-only TDAI memory endpoints (search, query, conversation-search) |
system.suffix (the very end of the system prompt) |
Calls getTdaiIdentity(ctx.metadata.custom) to obtain the current team_id, user_id, agent_id, and session_id, then adds x-tdai-service-id and x-conversation-id headers to every curl recipe |
SkillToolsInjector |
A <skill_tools> block describing cloud-skill CRUD and read-only operations (search, view, files-read, extract) |
system.before_tools (just before the <available_skills> block) |
Uses the same session metadata to build the x-tdai-service-id and x-conversation-id headers, guaranteeing the LLM's curl calls are signed with the correct team/user/agent context |
Both injectors are static — the block content depends only on the proxy base URL and the session's identity. They are rendered once at session_init (via cacheStrategy: "session_init"), then cached for the whole session, which makes them cheap and cache-friendly.
How the Injection Works Internally
The injection pipeline flows through five steps, each orchestrated by the memory proxy core:
-
Session metadata is attached to every request by the core gateway. The metadata contains a
customobject holding the current session'steam_id,user_id,agent_id,session_id, and the tenant'sspace_id. -
Pre-warm step: When a new session is created, the proxy runs the
prewarm(input)method of each injector. TheTdaiMemoryToolsInjector.prewarmreceivessessionInfo.session_idandsessionInfo.space_idand callsrenderTdaiMemoryToolsBlockto produce the full text block. TheSkillToolsInjector.prewarmdoes the same for the skill block, optionally toggling write capabilities viaallowLlmWrite. -
Caching: The rendered block is wrapped in a
ContextBlockwith a stablecacheKey— eithertdai-memory-tools-injector:toolsorskill-tools-injector:catalog:ro/rw. -
Attachment: The injection engine (registered in
src/injection/index.ts) attaches the block to the appropriate point in the system prompt. Because the block lives inside the system prompt, the LLM never sees the raw identity headers — it only sees the curl recipes. -
Request interception: When the LLM issues a curl command that hits a memory or skill endpoint, MemoryProxy intercepts the request, reads the
x-tdai-service-idandx-conversation-idheaders that are baked into the curl recipe, and injects the real team-wide IdFields (team_id,user_id,agent_id) into the upstream core request. This guarantees that the LLM cannot forge identities and that the token never appears in the prompt.
Configuring the Proxy Base URL
The first step is configuring where MemoryProxy points when forwarding requests to the core gateway. The configuration is done in memory-proxy/config.example.yaml:
proxyBaseUrl: "http://127.0.0.1:8096"
allowLlmWrite: false # optional, controls skill write tools
The allowLlmWrite flag determines whether the SkillToolsInjector renders write-capable curl recipes (like skill_create) or only read-only ones (like skill_search).
Rendering the Memory Tools Block
The TdaiMemoryToolsInjector calls renderTdaiMemoryToolsBlock to generate the memory specification. In TypeScript, you can see the full process:
import { renderTdaiMemoryToolsBlock } from "./injection/injectors/tdai-tools-injector";
const block = renderTdaiMemoryToolsBlock(
"http://127.0.0.1:8096", // proxyBaseUrl
"conv-12345", // sessionId (x-conversation-id)
"space-abc" // spaceId (x-tdai-service-id)
);
console.log(block);
The resulting block looks something like this:
<tdai_memory_tools>
**这些是你可以主动调用的记忆能力**(不是文档),通过 Bash + curl 使用。
...
<tool name="tdai_memory_search">
curl: http://127.0.0.1:8096/memory-bridge/v3/atomic/search
body: {"query": "<text>", "limit": 5}
use: 搜索 L1 原子记忆…
</tool>
…
</tdai_memory_tools>
Because each tool recipe includes the curl command and expected body format, the LLM can immediately execute searches against the team memory without knowing anything about the underlying authentication mechanism.
Rendering the Skill Tools Block
The SkillToolsInjector uses renderSkillToolsBlock to build the skill catalog. This block is more complex because it conditionally includes write operations based on the allowLlmWrite flag:
import { renderSkillToolsBlock } from "./injection/injectors/skill-tools-injector";
const block = renderSkillToolsBlock(
"http://127.0.0.1:8096",
true, // allowLlmWrite – inject write tools
"conv-12345",
"space-abc"
);
console.log(block);
When write mode is enabled, the output includes CRUD recipes like:
<skill_tools>
...
<tool name="skill_search">
path: http://127.0.0.1:8096/skill-bridge/v3/skill/search
body: {"query": "…"}
...
<tool name="skill_create">
path: http://127.0.0.1:8096/skill-bridge/v3/skill/create
body: {"name":"…","content":"…"}
...
</skill_tools>
The search tool is always present. The create/update/delete tools only appear when allowLlmWrite: true.
Example: LLM Calling a Memory Endpoint
Once the system prompt contains the injected blocks, the workflow looks like this. Inside its reasoning, the LLM emits a curl command to call the memory bridge:
curl -sfk -X POST http://127.0.0.1:8096/memory-bridge/v3/atomic/search \
-H 'Content-Type: application/json' \
-H 'x-tdai-service-id: space-abc' \
-H 'x-conversation-id: conv-12345' \
-d '{"query":"用户偏好的编程语言","limit":5}'
MemoryProxy receives this request, validates the injected headers, and forwards it to the core gateway. The upstream service automatically inserts the team_id, user_id, and agent_id that belong to the conversation. The LLM never sees those values — it only sees the curl command with the two headers that act as opaque identifiers. This design ensures authentication and authorization happen at coordinates where the protocol does not force the LLM to handle secrets.
Key Source Files
| File (GitHub link) | Role |
|---|---|
MemoryProxy/src/injection/injectors/tdai-tools-injector.ts |
Implements the <tdai_memory_tools> injector that adds team-wide memory curl recipes |
MemoryProxy/src/injection/injectors/skill-tools-injector.ts |
Implements the <skill_tools> injector that adds skill-related curl recipes |
MemoryProxy/src/injection/index.ts |
Registers the injectors and wires them to the correct system-prompt insertion points (system.suffix and system.before_tools) |
MemoryProxy/src/types.ts |
Defines AgentContext, CacheStrategy, HookPriority and the getTdaiIdentity helper used by the injectors |
MemoryProxy/src/tdai/identity.ts |
Extracts team_id, user_id, agent_id, and session_id from the session metadata |
MemoryProxy/src/workbuddyHandler.ts |
The main request handler that receives the LLM's curl calls, validates the injected headers, and forwards the request to core services |
Summary
-
MemoryProxy uses a static injection model: both the memory and skill tool blocks are rendered once per session and cached, so the per-query overhead is close to zero.
-
Identity is transmitted via headers, not the prompt: curl recipes contain
x-tdai-service-idandx-conversation-id, and a dedicated code path back-fills the realteam_id,user_id, andagent_idupstream. -
Write access is optional: the
allowLlmWriteconfig flag controls whether the skill catalog exposes mutating operations, giving you granular control over what the LLM may change. -
All wiring is centralized in
src/injection/index.ts, respecting theAgentContexttypes that define the interface between the gateway and the injection engine.
Frequently Asked Questions
What exactly does the TdaiMemoryToolsInjector inject?
The TdaiMemoryToolsInjector injects a <tdai_memory_tools> block at the end of the system prompt (system.suffix). The block contains curl recipes for read-only memory endpoints like tdai_memory_search, letting the LLM query team-wide atomistic memory during conversation. Each recipe includes the required HTTP headers for identity, so the model simply executes the curl command.
Does the LLM ever see the real team or user credentials?
No. The system prompt only contains curl recipes with the session identifier headers (x-tdai-service-id and x-conversation-id). Actual authentication tokens and the full team_id/user_id/agent_id triple are injected downstream by MemoryProxy in workbuddyHandler.ts, only after the LLM emits a curl call.
How does the SkillToolsInjector decide whether to include write operations?
The renderSkillToolsBlock function receives an allowLlmWrite boolean. When true, it injects CRUD operations like skill_create, skill_update, and skill_delete. When false, it only emits read-only tools such as skill_search and skill_files_read. This flag is controlled via the allowLlmWrite setting in the config file.
Why are the injected blocks cached at session_init?
Because the block content depends only on the proxy base URL and session identity — which are stable for the entire session. Rendering once and caching with a stable cacheKey avoids repeated string-building overhead on every LLM call, keeping the proxy efficient even under heavy load.
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 →