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
跑
真实代码对照
| 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
进阶练习
- 加 @plan_mode / @todo_reminders:6 大类中的其他 4 类
- 加 session_memory:从 sessionStorage 取上文
- 加 stream 模式:不等所有,收到一个就 yield 一个
- 加 cache:同一文件多次引用只读一次
- 加 priority:system prompt 附件 > user 附件
- 加 size limit:单个附件 > 100KB 截断
相关阅读