Skip to content

feat(chat): surface generated file artifacts in run-overview rail (#384)#447

Merged
mateaix merged 1 commit into
mateaix:devfrom
SuperCoderMan521:feature-generated-files-run-overview
Jun 28, 2026
Merged

feat(chat): surface generated file artifacts in run-overview rail (#384)#447
mateaix merged 1 commit into
mateaix:devfrom
SuperCoderMan521:feature-generated-files-run-overview

Conversation

@SuperCoderMan521

Copy link
Copy Markdown
Contributor
  • Backend: extract generated-file markdown links from tool results in StreamAccumulator and attach them to message metadata
  • Frontend: parse generated-file links in SSE tool_result handler, de-duplicate by URL, and expose via metadata.generatedFiles
  • RunOverviewPanel: new "Generated Files" section with file-type color-coded icons (docx/xlsx/pptx/pdf/image), clickable download links, and rail badge counter
  • Types: add GeneratedFile interface and generatedFiles to MessageMetadata
  • i18n: add en-US/zh-CN labels for generated files section

…teaix#384)

- Backend: extract generated-file markdown links from tool results in
  StreamAccumulator and attach them to message metadata
- Frontend: parse generated-file links in SSE tool_result handler,
  de-duplicate by URL, and expose via metadata.generatedFiles
- RunOverviewPanel: new "Generated Files" section with file-type
  color-coded icons (docx/xlsx/pptx/pdf/image), clickable download
  links, and rail badge counter
- Types: add GeneratedFile interface and generatedFiles to MessageMetadata
- i18n: add en-US/zh-CN labels for generated files section
@SuperCoderMan521

Copy link
Copy Markdown
Contributor Author

surface generated file artifacts in run-overview rail

@mateaix

mateaix commented Jun 28, 2026

Copy link
Copy Markdown
Owner

感谢贡献 🙏 后端持久化(写入 message metadata,刷新后历史也能展示)+ 前端 SSE 实时解析的双路设计、按 URL 去重、GeneratedFile 类型、双语 i18n、rel="noopener" 都到位。已合并到 dev

有两点 follow-up(其中一个是安全加固),我在下一条评论里详细说明,麻烦后续用一个小 PR 跟进 🙏

@mateaix mateaix merged commit 3c6c765 into mateaix:dev Jun 28, 2026
@mateaix

mateaix commented Jun 28, 2026

Copy link
Copy Markdown
Owner

已合并 ✅ 以下是 follow-up,麻烦用一个小 PR 跟进 🙏

1.(安全 + 复用)链接正则过于宽松,建议改用仓库已有的规范写法

当前两端用的是:

\[([^\]]+)\]\(([^)]*?/api/v1/files/generated/[a-zA-Z0-9-]+)\)

[^)]*? 前缀会接受任意非 ) 文本,一个不含括号的 javascript:…/api/v1/files/generated/x 也能被捕获,随后直接绑定到 <a :href="file.url">。Vue 不会:href 做过滤,因此若某个工具结果里带入了外部可控文本(web 搜索/抓取/MCP/浏览器类工具回显的内容),用户点击 rail 里的链接即在应用源下执行 JS(target="_blank" 不能拦 javascript:)。

仓库里同包的 SegmentSupersedeDetectorchannel.web)以及各 channel adapter 已经有规范、限定 scheme 的写法:

(?:https?://[^/\s)\]]+)?/api/v1/files/generated/[A-Za-z0-9-]+

只允许「可选的 https?://host」或相对路径。建议把 markdown 链接正则的 URL 部分换成它(两端都改),路径前缀可复用常量 GeneratedFileCache.DOWNLOAD_PATH_PREFIX。这样既堵住 scheme 注入,也避免重复造一套正则。

参考改法:

  • 后端 ChatController\[([^\]]+)\]\(((?:https?://[^/\s)\]]+)?/api/v1/files/generated/[A-Za-z0-9-]+)\)
  • 前端 useChat.ts/\[([^\]]+)\]\(((?:https?:\/\/[^/\s)\]]+)?\/api\/v1\/files\/generated\/[A-Za-z0-9-]+)\)/g

2.(规范)内联全限定名

ChatControllerjava.util.regex.Pattern / java.util.regex.Matcher 用了内联 FQN,按仓库规范改成顶部 import + 简单名(同包的 SegmentSupersedeDetector 已是 import 写法)。

3.(小)未使用的 i18n key

noFiles 在 en-US/zh-CN 都加了,但模板里没用到(noPlan/noSubagents 那几个分区都有 v-else 空状态)。建议给 Generated Files 分区补一个空状态用上它,或直接删掉该 key。

谢谢!其中第 1 条是安全项,建议优先。

mateaix pushed a commit that referenced this pull request Jun 28, 2026
Follow-up to #447. The generated-file link extraction accepted any
non-')' text before the path, so a paren-free javascript:/data: URL
embedding /api/v1/files/generated/<id> could be captured and bound to an
<a href>, enabling XSS on click. Adopt the scheme-restricted pattern
already used by SegmentSupersedeDetector and the channel adapters, on
both backend (ChatController) and frontend (useChat). Also replace the
inline fully-qualified Pattern/Matcher with imports and drop an unused
run-overview i18n key.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mateaix

mateaix commented Jun 28, 2026

Copy link
Copy Markdown
Owner

补充:上面 follow-up 里的第 1 条(安全加固)和第 2、3 条(内联 FQN、未使用 i18n key)我已经直接在 dev 上的后续提交 faf71329 里改好了 —— 两端正则都换成了限定 scheme 的写法((?:https?://[^/\s)\]]+)?/api/v1/files/generated/[A-Za-z0-9-]+),Pattern/Matcher 改为 import,并删掉了未使用的 chat.runOverview.noFiles。已用 javac/node 验证:http(s)/相对 URL 照常匹配,javascript:/data: 等 scheme 被拒绝。

你这边不用再重复改了,感谢贡献 🙏

mateaix added a commit that referenced this pull request Jun 28, 2026
Follow-up to #447. The generated-file link extraction accepted any
non-')' text before the path, so a paren-free javascript:/data: URL
embedding /api/v1/files/generated/<id> could be captured and bound to an
<a href>, enabling XSS on click. Adopt the scheme-restricted pattern
already used by SegmentSupersedeDetector and the channel adapters, on
both backend (ChatController) and frontend (useChat). Also replace the
inline fully-qualified Pattern/Matcher with imports and drop an unused
run-overview i18n key.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants