跳转至

Mini Attachment Resolver

从 3997 行的 src/utils/attachments.ts 提炼到 ~150 行 的 @-prefix 解析 + maybe() 失败隔离 + 1s 总超时。 5 测试场景:4 种前缀 / 失败隔离 / 超时 / 纯 tokenize / 空文本。

文件

mini-attachment-resolver/
├── src/
│   ├── resolver.ts  parseAtTokens + 4 resolver + maybe() + 1s 超时(~150 行)
│   └── cli.ts       5 测试场景
└── README.md

npm install && npm start

真实代码对照

Demo 真实代码 简化
parseAtTokens attachments.ts:50 parseAttachment (~100 行) 8 行 regex
resolveFile attachments.ts:200 readFile
resolveMcp attachments.ts:500 mcpCall mock
resolveAgent attachments.ts:800 agentLookup mock
resolveSkill attachments.ts:1100 skillLoad mock
maybe() 失败隔离 attachments.ts:500 getAttachments 24+ maybe() Promise.allSettled
1s 总超时 attachments.ts:1500 AbortController

核心 4 件套

1️⃣ @-prefix 4 种类型

前缀 格式 例子
@file: 文件路径 @file:/etc/hosts
@mcp: server.tool[:args] @mcp:github.get_user:{"name":"x"}
@agent: agent 名字 @agent:researcher
@skill: skill 名字 @skill:web_search

2️⃣ maybe() = 失败隔离

async function maybe<T>(promise: Promise<T>) {
  try { return { ok: true, value: await promise }; }
  catch (err) { return { ok: false, error: err as Error }; }
}
核心思想:单个附件失败不影响其他。CC 真实代码 24+ 个 maybe() 调,确保 1 个挂了整个还能继续。

3️⃣ Promise.allSettled = 并行

const results = await Promise.allSettled(promises);
for (const r of results) {
  if (r.status === "fulfilled") attachments.push(r.value);
  // rejected 已经 try/catch 在 resolver 内处理
}
N 个附件同时解析(不等上一个)。总耗时 = max(单个) 而非 sum

4️⃣ 1s 总超时 = AbortController

const ac = new AbortController();
setTimeout(() => ac.abort(), 1000).unref();
const content = await fs.readFile(path, { signal: ac.signal });
关键设计:整个 batch 共用 1 个超时。任何一个附件 触发 abort,所有进行中的都会 reject(如果有 signal 监听)。

5 场景输出

📌 Test 1: parse 4 @-prefix types
  resolved: 2, failed: 1 (file 不存在)
  - file: ERROR / mcp: mock-result / agent: mock

📌 Test 2: failure isolation
  resolved: 1, failed: 2 (3 个 file,1 个 OK,2 个 ENOENT)
  /etc/hosts 读出真实内容 ✅

📌 Test 3: 1s timeout
  elapsed: 0ms, timedOut: false (read /dev/null 太快)

📌 Test 4: parseAtTokens
  4 tokens: file, mcp, agent, skill

📌 Test 5: empty text
  0 attachments

进阶练习

  1. 加 @plan_mode / @todo_reminders:6 大类中的其他 4 类
  2. 加 session_memory:从 sessionStorage 取上文
  3. 加 stream 模式:不等所有,收到一个就 yield 一个
  4. 加 cache:同一文件多次引用只读一次
  5. 加 priority:system prompt 附件 > user 附件
  6. 加 size limit:单个附件 > 100KB 截断

相关阅读