Skip to content

feat(agent-core): TUI @文件引用支持预读注入 #559

@fengshenx

Description

@fengshenx

背景

当前 TUI 中 @ 文件引用只提供自动补全功能(file-mention-provider.ts),用户提交消息后 @path/to/file 作为原始文本发给 LLM。LLM 要获取文件内容,仍需自行调用 Read tool,多一轮工具调用的开销。

提议

在 turn 启动时(applyUserPromptHook 之后、step loop 之前),解析用户输入中的 @ 文件引用,调用 ReadTool 预读文件内容,将合成的 assistant + tool result 消息注入 context。LLM 看到的效果等同于自己已经调用过 Read tool,可直接基于文件内容回答。

动机

  • 减少一轮 tool call 往返,加快首次响应
  • 用户显式 @ 了文件,说明意图明确——预读符合直觉
  • 与 Claude Code 等竞品的 @ 行为对齐(引用即注入)

设计要点

  1. 复用 ReadTool — 预读走 ReadTool.resolveExecution().execute(),继承二进制检测、NUL 字节校验、MAX_BYTES/MAX_LINES 限制、CRLF 处理等全部逻辑,无重复代码
  2. 路径过滤 — 只匹配看起来像文件路径的 token(含 / 或扩展名 .,加常见无扩展名文件 allowlist),避免误匹配 email、version pin、commit hash
  3. Workspace 对齐 — 使用 ToolManager 持有的 workspace(含 skill roots + additionalDirs),与 builtin Read tool 路径访问策略一致
  4. 事件发射 — 发射 tool.call.started / tool.result 事件,TUI 正常渲染 "Read xxx" 卡片
  5. 并行读取Promise.all 并行读取,接受 turn 的 AbortSignal,支持用户取消
  6. 上限 — 单条消息最多预读 5 个文件
  7. 时机 — 在 UserPromptSubmit hook 之后注入,hook block 时不会污染 history

开放问题

  • 是否需要对预读失败(文件不存在、超出 workspace)向用户显示提示?当前静默跳过。
  • pendingToolResultIds 同步:合成消息直接 appendMessage 不走 loop event 路径,是否需要额外处理以兼容 compaction?

参考实现

我在 fork 上有一份初步实现:feat/preread-file-mentions,涉及文件:

  • packages/agent-core/src/agent/turn/file-mention.ts(提取 + 读取)
  • packages/agent-core/src/agent/turn/index.ts(集成到 turn)
  • packages/agent-core/src/agent/tool/index.ts(暴露 workspace)
  • 23 个单元测试通过

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions