How Skill Extraction Works and What Triggers Automatic Skill Creation in TencentDB-Agent-Memory
Skill extraction triggers automatically when a conversation round ends with a final answer, buffering normalized messages until a threshold is met and then archiving them for the extraction pipeline.
The TencentCloud/TencentDB-Agent-Memory repository implements an intelligent skill extraction system that observes human-to-assistant conversations and automatically generates skills when sufficient context accumulates. Unlike naive turn-level logging, this system uses a round-level lifecycle to capture complete problem-solving exchanges while minimizing unnecessary RPC traffic. Understanding the specific triggers and extraction pipeline requires examining the proxy-to-core flow that begins in MemoryProxy and culminates in the SkillExtractor.
The Round-Level Trigger Architecture
Skill extraction operates on conversation rounds rather than individual HTTP turns to avoid fragmenting tool-use loops into separate archives.
Detecting Final Answers
The extraction trigger depends on identifying a final answer—an assistant message that concludes the current round without pending tool calls. In MemoryProxy/src/skill/handler-glue.ts, the triggerSkillExtractIfReady function inspects each assistant message using isFinalAnswer, which checks for the absence of tool_use or tool_calls blocks. Only messages meeting this criteria initiate the extraction sequence, ensuring that incomplete tool chains do not prematurely flush the buffer.
Round Slicing Strategy
Once a final answer is confirmed, the system slices the conversation to isolate the current round. The findLastFinalAssistant utility (lines 11-13 of the handler glue) locates the previous final message in the full history. The slice begins immediately after this marker, capturing only the new user-assistant exchange. If no prior final message exists—indicating the first round—the entire conversation is sent instead. This approach guarantees one archive per human-to-assistant exchange rather than one per HTTP request, dramatically reducing buffer pressure during multi-turn tool loops.
The Automatic Skill Creation Pipeline
After slicing, the normalized conversation flows through a three-stage pipeline that culminates in automatic skill generation.
Entry Point and Capability Checks
The triggerSkillExtractIfReady function serves as the central gatekeeper. Before processing, it validates that:
- The user has skill capability enabled via
assetCapabilities: { skill: true } - The session and Core-Skill endpoint are available
- The current assistant reply is definitively a final answer
If any check fails, the pipeline aborts silently to prevent disrupting the primary response path.
Protocol Normalization
The normalizeConversation function in MemoryProxy/src/skill/normalize-conversation.ts transforms protocol-specific message formats into a unified 5-role schema: user, assistant, tool_call, tool_result, and system. This normalization handles Anthropic's block-based content structures and OpenAI's separate tool_calls fields, ensuring the core service receives consistent data regardless of the inbound protocol (anthropic, openai, or responses).
Core Buffering and Archiving
The normalized messages are transmitted to the core Skill service via SkillClient.addConversation (defined in sdk/memory-core/typescript/src/v3/skill-client.ts), which POSTs to /v3/skill/conversation/add. The core buffers these messages per-space according to an internal threshold. When the buffer-size limit is reached, the system automatically archives the conversation and invokes the SkillExtractor (implemented in MemoryCore/src/core/skill/skill-extractor.ts) to generate skill candidates. The gateway handlers in MemoryCore/src/gateway/skill-handlers.ts manage this buffering logic and return status: "archived" when extraction begins.
Implementation Examples
The following examples demonstrate how to manually invoke the extraction flow and normalize conversation data.
Triggering Extraction Manually
import { triggerSkillExtractIfReady } from
"./MemoryProxy/src/skill/handler-glue.js";
await triggerSkillExtractIfReady({
config: proxyConfig,
sessionKey: "sess-123",
sessionInfo: {
user_id: "u1",
team_id: "t1",
agent_id: "a1",
space_id: "s1",
},
inputMessages: [{ role: "user", content: "How to list tables?" }],
assistantMessage: {
role: "assistant",
content: "Here is the answer…", // no tool_use → final answer
},
protocol: "openai",
agentSource: "gpt-4",
assetCapabilities: { skill: true },
});
Normalizing Protocol-Specific Messages
import { normalizeConversation } from
"./MemoryProxy/src/skill/normalize-conversation.js";
const raw = [
{ role: "user", content: "Write a function." },
{ role: "assistant", tool_calls: [{ /* … */ }] },
{ role: "assistant", content: "Here is the result." },
];
const norm = normalizeConversation(raw, "anthropic", null, "claude-code");
// → [{role:"user",content:"Write a function."},
// {role:"assistant",content:"Here is the result."}]
Summary
- Round-level extraction: The system waits for complete human-to-assistant exchanges rather than logging every HTTP turn, preventing premature buffer saturation during tool loops.
- Final answer trigger: Only assistant messages without pending
tool_useortool_callsinitiate the extraction sequence viatriggerSkillExtractIfReady. - Automatic skill creation: The core service buffers normalized conversations and automatically archives them when thresholds are met, triggering the
SkillExtractorpipeline without manual intervention. - Protocol agnostic: The
normalizeConversationutility standardizes Anthropic, OpenAI, and response formats into a unified 5-role schema before transmission.
Frequently Asked Questions
What is the difference between round-level and turn-level skill extraction?
Round-level extraction captures the complete user-assistant exchange from question to final answer, whereas turn-level extraction would log every individual HTTP request. In TencentDB-Agent-Memory, round-level processing prevents fragmented archives during multi-turn tool-use loops, ensuring that a single human query generates exactly one archive entry regardless of how many internal tool calls occurred.
How does the system know when to trigger automatic skill creation?
Automatic skill creation triggers when the core service's internal buffer reaches a predefined threshold. The SkillClient.addConversation method sends normalized round slices to /v3/skill/conversation/add, where the gateway accumulates messages per-space. Once the buffer size limit is met, the conversation is automatically archived and passed to SkillExtractor for skill generation, returning status: "archived" to the proxy.
What file handles the protocol normalization for different LLM providers?
The normalizeConversation function in MemoryProxy/src/skill/normalize-conversation.ts handles normalization. It converts provider-specific formats—such as Anthropic's content blocks or OpenAI's tool_calls arrays—into a standardized 5-role schema (user, assistant, tool_call, tool_result, system) that the core Skill service can process uniformly regardless of the source protocol.
Why does the extraction only trigger on final answers?
Restricting extraction to final answers (messages without pending tool calls) ensures that the archived conversation represents a complete, meaningful exchange rather than an incomplete intermediate state. This design prevents the core buffer from filling with partial tool-use fragments, which would trigger premature archiving and result in malformed skill candidates that lack resolution context.
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 →