Memory Import Processor

Memory Import Processor 允许你在 GEMINI.md 中使用 @file.md 语法,从其他文件导入内容,实现模块化管理。

概览

借助该功能,可以将大型 GEMINI.md 拆分为更小、更易维护的组件,并在不同上下文中复用。导入处理器同时支持相对路径与绝对路径,并内置安全机制以防循环导入并保障文件访问安全。

语法

使用 @ 加上要导入文件的路径:

# Main GEMINI.md file

This is the main content.

@./components/instructions.md

More content here.

@./shared/configuration.md

支持的路径格式

相对路径

  • @./file.md —— 从同级目录导入
  • @../file.md —— 从父目录导入
  • @./components/file.md —— 从子目录导入

绝对路径

  • @/absolute/path/to/file.md —— 使用绝对路径导入

示例

基本导入

# My GEMINI.md

Welcome to my project!

@./get-started.md

## Features

@./features/overview.md

嵌套导入

被导入的文件也可以继续包含导入,形成嵌套结构:

# main.md

@./header.md @./content.md @./footer.md
# header.md

# Project Header

@./shared/title.md

安全特性

循环导入检测

处理器会自动检测并阻止循环导入:

# file-a.md

@./file-b.md

# file-b.md

@./file-a.md <!-- This will be detected and prevented -->

文件访问安全

validateImportPath 函数确保仅允许从指定目录导入文件,防止访问超出安全范围的敏感资源。

最大导入深度

为避免无限递归,导入深度可配置,默认最多 5 层。

错误处理

文件缺失

若引用的文件不存在,导入会优雅失败,并在输出中写入错误注释。

文件访问错误

权限问题或其他文件系统错误会被捕获,并返回相应错误信息。

代码区域检测

处理器使用 marked 库分析代码块与行内代码,确保这些区域内的 @ 不会被误识别为导入语法,从而正确处理嵌套代码块与复杂 Markdown 结构。

导入树结构

处理器会返回导入树,展示文件层级关系,类似 Claude /memory 功能。这有助于调试 GEMINI.md,了解读取的文件及其依赖关系。

示例:

Memory Files
 L project: GEMINI.md
            L a.md
              L b.md
                L c.md
              L d.md
                L e.md
                  L f.md
            L included.md

导入树保留文件的导入顺序,并显示完整链路,方便排查问题。

与 Claude Code /memoryclaude.md)的比较

Claude Code 的 /memory 功能会将所有文件串联为平铺文档,并在文件边界标注注释与路径。它不会显式展示导入层级,但由于 LLM 能看到全部内容及路径,如有需要可以自行还原。

[!NOTE] 导入树主要用于开发阶段的可读性,对 LLM 的实际推理影响有限。

API 参考

processImports(content, basePath, debugMode?, importState?)

处理 GEMINI.md 内容中的导入语句。

参数:

  • content (string):待处理内容
  • basePath (string):当前文件所在目录
  • debugMode (boolean,可选):是否开启调试日志(默认 false)
  • importState (ImportState,可选):用于检测循环导入的状态对象

返回值: Promise<ProcessImportsResult>,包含处理后的内容与导入树。

ProcessImportsResult

interface ProcessImportsResult {
  content: string; // 解析后的内容
  importTree: MemoryFile; // 导入层级树
}

MemoryFile

interface MemoryFile {
  path: string; // 文件路径
  imports?: MemoryFile[]; // 直接导入的文件,按导入顺序排列
}

validateImportPath(importPath, basePath, allowedDirectories)

校验导入路径是否安全并位于允许的目录中。

参数:

  • importPath (string):待校验路径
  • basePath (string):解析相对路径时的基准目录
  • allowedDirectories (string[]):允许访问的目录列表

返回值: boolean,表示路径是否有效。

findProjectRoot(startDir)

自给定目录向上搜索 .git,以确定项目根目录。实现为 async 函数,使用非阻塞文件系统 API,避免阻塞 Node.js 事件循环。

参数:

  • startDir (string):起始目录

返回值: Promise<string>,返回项目根目录;若未找到 .git,则返回起始目录。

最佳实践

  1. 使用具描述性的文件名,便于识别导入内容。
  2. 保持导入层级浅,避免过深的导入链。
  3. 记录结构,维护清晰的文件层次。
  4. 验证导入,确保所有引用文件存在且可访问。
  5. 优先使用相对路径,增强跨环境可移植性。

故障排查

常见问题

  1. 导入失败:检查文件是否存在以及路径是否正确。
  2. 循环导入警告:检查导入结构,避免自引用。
  3. 权限错误:确认文件可读且位于允许的目录内。
  4. 路径解析问题:若相对路径解析失败,可尝试使用绝对路径。

调试模式

启用调试模式可查看导入过程的详细日志:

const result = await processImports(content, basePath, true);