zettelkasten-memory-server
Version:
基于 Zettelkasten 记忆片段盒方法的 MCP 记忆服务器 v1.6.X
108 lines • 5.99 kB
JavaScript
import { extractLinkedCardNames, isEmptyPlaceholder, canAccessMemory, incrementMemoryAccessCounter, hasLatestContent, markLatestContentFetched } from './utils.js';
/**
* 获取记忆片段内容处理器
*/
function createGetMemoryHandler(manager) {
return async (args) => {
try {
const { fragmentName, expandDepth = 0, withLineNumber = false, conversationId } = args;
if (!fragmentName || typeof fragmentName !== 'string') {
throw new Error('fragmentName is required and must be a string');
}
// 验证 conversationId 参数
if (!conversationId || typeof conversationId !== 'string') {
throw new Error('conversationId is required and must be a string');
}
let content;
let rawContent;
let notFound = false;
let shouldReturnCached = false;
// 检查是否允许读取(基于重复读取限制)
if (!canAccessMemory(fragmentName, conversationId)) {
return {
content: [{
type: "text",
text: `⚠️ 记忆片段 "${fragmentName}" 已经存在于上下文中并且是最新版本的,可以直接使用。如需重新获取,请等待内容更新或使用其他操作重置计数器。`
}]
};
}
// 如果已经获取过最新内容,直接返回缓存提示
if (hasLatestContent(fragmentName, conversationId)) {
shouldReturnCached = true;
}
// 尝试获取文件内容,如果获取失败,则还是需要获取最新内容
try {
content = await manager.getMemory(fragmentName, expandDepth, withLineNumber);
rawContent = await manager.getMemory(fragmentName, 0, withLineNumber);
}
catch (e) {
if (e && e.message && e.message.includes('Card not found')) {
notFound = true;
// 文件不存在时,标记为已获取(因为不存在内容)
shouldReturnCached = false;
}
throw e;
}
// 检查是否为 EMPTY_PLACEHOLDER
const isPlaceholder = isEmptyPlaceholder(manager, rawContent);
// 如果文件为 EMPTY_PLACEHOLDER,标记为已获取
if (isPlaceholder) {
shouldReturnCached = false;
}
// 对于已经展开了的内容也要标记为已获取最新内容
if (expandDepth > 0) {
const tempContent = await manager.getMemory(fragmentName, expandDepth - 1, withLineNumber);
// 这样就不包括 未展开的内容了
if (tempContent && tempContent.length > 0) {
const expandedFragmentNames = extractLinkedCardNames(tempContent);
// 将展开的内容也标记为已获取最新内容
expandedFragmentNames.forEach(name => markLatestContentFetched(name, conversationId));
}
}
// 检查是否应该返回缓存提示
// 当 withLineNumber 为 true 时,忽略是否获取过,永远输出带行号的文件内容
if (shouldReturnCached && !withLineNumber) {
return {
content: [{
type: "text",
text: `✅ 记忆片段 "${fragmentName}" 的最新内容已在上下文中,无需重复获取。`
}]
};
}
let truncated = false;
const MAX_LENGTH = 1024 * 24; // 24KB 限制
if (content.length > MAX_LENGTH) {
content = content.slice(0, MAX_LENGTH) + '\n...\n[内容过长已截断,请减少展开层次或手动获取细节内容]';
truncated = true;
}
// 只有未被截断的内容才标记为已获取最新内容
if (!truncated) {
markLatestContentFetched(fragmentName, conversationId);
// 增加读取计数
incrementMemoryAccessCounter(fragmentName, conversationId);
}
const expansionInfo = expandDepth > 0 ? ` (展开深度: ${expandDepth})` : '';
const optimizationHint = content.length > 1000 && !truncated ?
'\n\n💡 **提示**:内容较长,可使用 extractMemory 工具(支持精确范围定位)拆分为更小的记忆片段。' : '';
const blankFill = "<!-- 这是一个自动创建的占位记忆片段 -->";
const suggestFillBlank = rawContent.includes(blankFill) ? `\n\n💡 **提示**:当前记忆片段是其他地方创建链接后的占位记忆片段,你可以通过 getBacklinks 工具查看所有指向该记忆片段的链接,然后使用 setMemory 工具填充内容。` : '';
const tooLongHint = truncated ? '\n\n⚠️ **警告**:内容已被截断,建议减少展开层次或手动获取细节内容。' : '';
return {
content: [{
type: "text",
text: `📄 **记忆片段: ${fragmentName}**${expansionInfo}\n\n${content}${optimizationHint}${suggestFillBlank}${tooLongHint}`
}]
};
}
catch (error) {
return {
content: [{
type: "text",
text: `❌ 获取记忆片段内容失败: ${error && error.message ? error.message : String(error)}\n\n💡 **提示**:如需探索记忆片段结构,可以使用 getMemoryHints 工具获取相关提示。`
}]
};
}
};
}
export default createGetMemoryHandler;
//# sourceMappingURL=createGetMemoryHandler.js.map