news 2026/9/10 13:41:27

qwen-code Web Shell @ 提及图标芯片(mention icon chips)机制解析与验证指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
qwen-code Web Shell @ 提及图标芯片(mention icon chips)机制解析与验证指南

qwen-code Web Shell @ 提及图标芯片(mention icon chips)机制解析与验证指南

【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code

本篇文章围绕 qwen-code 仓库中 .qwen/e2e-tests/webshell-mention-icon-chips.md 这份验证文档展开,系统讲解 Web Shell 输入框内@提及(mention)功能如何把插入的引用文本渲染为带内置图标的 inline chip 标签、如何通过composerTagIcons注册自定义图标,以及相关的安全回归约束与可复现的验证方法。读完本文,你将掌握内置/自定义提及 chip 的渲染链路、图标解析与 CSS 转义的安全边界,并能在本地直接运行文档所列的测试与构建命令进行验证。

一、验证文档要解决的问题

在 Web Shell 的 composer 输入框中输入@会唤起提及(at-mention)菜单,用于引用扩展(extension)、文件(file)、MCP 资源(MCP resources)以及 skill 等对象。选择某个候选项后,输入框里不应出现一段生硬的纯文本(例如@ext:...@mcp:...或文件引用路径),而应当插入一个内联 composer 标签(inline composer tag):一个带有图标、标签、值与可删除按钮的视觉芯片。该验证文档围绕三个测试组展开:

  • Built-in mention chips(内置提及芯片):接受扩展、文件或 MCP 的@提及后,编辑器插入原始序列化文本,并附着内联 composer 标签;可见结果是一个带内置图标的内联 chip,而不是@ext:...@mcp:...或文件引用纯文本。
  • Custom mention chips(自定义提及芯片):注册一个atProvider,其候选项提供composerTag.kind = 'table',并向WebShell传入composerTagIcons={{ table: '<icon-url>' }};接受该候选项后应插入 provider 提供的insertText,并使用注册的 table 图标渲染内联 chip。
  • Regression coverage(回归覆盖):自定义图标查找必须忽略继承的对象属性;未注册自定义图标时内置图标仍能正常解析;图标 URL 在写入 CSS 自定义属性前必须经过转义。

最后一部分还记录了 2026-07-16 的一次内置 SVG data URI 回归(基线版本0.18.5-preview.0),用于验证四个内置图标(extension、file、MCP、skill)在内联 composer 标签、顶部 composer 标签和已提交用户消息标签三种表面上的掩码节点渲染是否正常,以及任意 SVG data URI 和javascript:自定义图标 URL 是否仍被排除在 DOM 之外。

二、从「纯文本」到「图标 chip」:内联标签渲染链路

2.1@提及解析与菜单状态机

用户键入@后,useAtMentionMenuHook 负责解析当前光标处的提及查询并管理菜单状态。其核心入口是parseAtMention,正则AT_PATTERN = /@((?:[\p{L}\p{N}_./:-]|\\.)*)$/u负责匹配光标前最后一个@开始的片段,并校验前一个字符必须是空白或[\s([{'"]之一,避免误触(例如邮箱地址中的@`)。详见 useAtMentionMenu.ts。

菜单状态机包含categoriesitems两级:

  • categories层展示所有可用 provider(内置的 files / extensions / mcp-resources,以及宿主注册的自定义 provider);
  • items层展示当前 provider 的候选项,支持 150ms 防抖(SEARCH_DEBOUNCE_MS = 150)、AbortController 取消过期请求以及内置 provider 的结果缓存。

内置 provider 通过createFileProvidercreateExtensionProvidercreateMcpResourcesProvider构造,并可用WebShellBuiltinAtProvidersConfig控制启用/禁用(支持布尔值、ID 数组或{ enabled, include, exclude }三种形态),见 useAtMentionMenu.ts 与 customization.tsx。

2.2 候选项到 composer tag 的转换

每个@候选项的类型是WebShellAtItem,其中composerTag?: WebShellComposerTag字段携带了选中后要创建的标签数据。WebShellComposerTag的核心结构为(见 customization.tsx):

export interface WebShellComposerTag { id: string; label?: string; // chip 中带主题色的标签文本 value?: string; // chip 中的主文本(如文件路径) removable?: boolean; // 是否允许删除(默认可删除) kind?: WebShellComposerTagKind; // 用于图标解析:extension | file | mcp | skill | 自定义字符串 icon?: WebShellIconSource; metadata?: unknown; serialized?: string; // 提交时真正写回文本流的序列化内容 }

其中WebShellComposerTagKind'extension' | 'file' | 'mcp' | 'skill' | (string & {}),即内置四类之外还允许任意自定义字符串(见 customization.tsx),这正是文档中composerTag.kind = 'table'自定义场景的类型基础。

选中候选项后,useAtMentionMenu会调用createComposerTagForItem生成标签,并把原始插入文本(insertText)写入编辑器,同时通过createInlineTagEffect效果(StateEffect)通知 composer 在该文本对应的文档区间上挂载内联标签装饰。相关实现见 useComposerCore.ts 中的addInlineTagEffect/removeInlineTagEffect/clearInlineTagsEffect

2.3 CodeMirror 装饰层与 chip 的 DOM 结构

Web Shell 的 composer 基于 CodeMirror 6 构建。内联 chip 是通过StateField+Decoration.replace实现的:inlineComposerTagField维护一个DecorationSetaddInlineTagEffectComposerTagWidget作为替换装饰挂到对应区间上,并同时注册为EditorView.atomicRanges,保证光标移动与编辑不会“穿过” chip 内部(见 useComposerCore.ts)。

ComposerTagWidget.toDOM负责把标签渲染成 chip DOM,关键渲染步骤包括:

  1. 解析图标:const iconUrl = this.tag.iconUrl ?? getComposerTagIconUrl(this.tag.kind)
  2. 安全校验:仅当isBuiltinComposerTagIconUrl(iconUrl) || isSafeImageSrc(iconUrl)时才使用该 URL,否则不渲染图标(safeIconUrlundefined);
  3. 构造图标节点:一个 12×12 的<span>,使用background: currentColor配合mask: var(--composer-tag-icon-url) center / contain no-repeat(含-webkit-mask)渲染,图标 URL 通过cssUrlValue(safeIconUrl)写入--composer-tag-icon-url自定义属性;
  4. 附加默认内容(label + value,超出max-width:32ch省略)、tooltip(可选)与删除按钮×removable !== false时)。

上述逻辑见 useComposerCore.ts。也正是“mask 节点(icon mask node)”一词的来源:图标本质上是把 SVG 当作 CSS mask 画在 chip 内部的节点上。

2.4 提交时:inline chip 如何还原成文本

发送消息时,buildComposerPromptWithInlineTagPlacements会把文档中的内联标签区间替换回序列化文本(replaceInlineTagPlacements按区间排序后逐段重组文本),再与顶部标签一起拼装 prompt(见 useComposerCore.ts)。也就是说:chip 只是编辑时的视觉投影,提交时仍还原为serialized文本(默认回退顺序为serialized -> value -> label -> id,见 composerTag.ts)。同时createInputAnnotationsFromComposerTags会为每个标签生成DaemonInputAnnotation(类型为reference,携带idkindlabelvaluemetadataserializedremovable),供会话记录层在用户消息中继续渲染 chip(见 composerTag.ts)。

三、自定义图标:composerTagIconsatProvider的配合

3.1 定制入口与类型定义

宿主(host)可以在WebShellCustomization中声明composerTagIcons?: WebShellComposerTagIconMap,类型为Readonly<Record<string, string>>,即「标签 kind → 图标 URL」的映射(见 customization.tsx 与 customization.tsx)。文档给出的用法是:

composerTagIcons={{ table: '<icon-url>' }}

同时注册一个自定义atProvider,其候选项的composerTag.kind设为'table'

{ id: 'my-tables', label: 'Tables', search: async ({ query, signal }) => [ { id: 'table:orders', label: 'orders', insertText: '@table:orders ', composerTag: { id: 'table:orders', kind: 'table', value: 'orders' }, }, ], }

接受该候选项后,composer 会插入insertText(即@table:orders),并把标签解析为 inline chip——此时kind === 'table'在内置图标表中不存在,于是回退到composerTagIcons['table']注册的图标。

3.2 图标解析顺序与安全边界

图标解析集中在 composerTag.ts:

  • getOwnIconUrl(iconUrls, kind)使用Object.prototype.hasOwnProperty.call(iconUrls, kind)严格检查自身属性,这正是文档回归项中「自定义图标查找忽略继承的对象属性」的实现保证——即使某个 kind 名称恰好与Object.prototype上的属性同名(如constructortoString),也不会被错误命中;
  • getComposerTagIconUrl(kind, customIconUrls)的解析顺序为:自定义图标映射优先,其次内置图标映射builtinTagIconUrls内部包含 extension/file/mcp/skill 四个 SVG 资源);
  • isBuiltinComposerTagIconUrl通过内置图标 URL 的 Set 集合做白名单校验,只有「内置图标」或「通过isSafeImageSrc校验的 URL」才会被写入 DOM 的 mask 节点。

3.3 图标 URL 的 CSS 转义

文档明确要求「icon URLs are escaped before being written into CSS custom properties」。由于图标 URL 最终会被写入 CSS 自定义属性--composer-tag-icon-url并作为url(...)使用,URL 中若含引号、反斜杠、换行等字符可能破坏 CSS 语法甚至注入样式。cssUrlVar.ts中的cssUrlValue负责转义:

export function cssUrlValue(url: string): string { const escaped = url.replace(/["\\\n\r\f]/g, (char) => { switch (char) { case '"': case '\\': return `\\${char}`; case '\n': return '\\A '; case '\r': return '\\D '; case '\f': return '\\C '; default: return ''; } }); return `url("${escaped}")`; }

其测试用例(cssUrlVar.test.ts)验证了'https://x.test/a"\\\nb.svg'被转义为url("https://x.test/a\"\\\A b.svg"),以及cssUrlVar('--icon-url', '/icons/table.svg')生成{ '--icon-url': 'url("/icons/table.svg")' }。正是这一层转义,配合isBuiltinComposerTagIconUrl || isSafeImageSrc的双重校验,使文档中「任意 SVG data URI 和javascript:自定义图标 URL 不进入 DOM」的回归结论成立。

四、内置 SVG data URI 回归验证(2026-07-16)

4.1 基线问题

全局qwen --version基线为0.18.5-preview.0。修复前的 DOM 矩阵显示:虽然四个内置图标都能解析为data:image/svg+xmlURL,但在内联 composer 标签、顶部 composer 标签和已提交用户消息标签三种表面上,渲染出的icon mask 节点数量为零——即图标 URL 已解析但未实际渲染成可见图标。

4.2 验证结论

修复后的验证结果如下:

  • @菜单接受一个扩展项,仍能在编辑器中插入kind: 'extension'的内联标签;
  • 内联 composer 标签、顶部 composer 标签、已提交用户消息标签三种表面,均渲染出 extension、file、MCP、skill 四个图标 mask 节点;
  • 任意 SVG data URI 与javascript:自定义图标 URL 在三种表面上均不出现于 DOM;
  • 聚焦 WebShell 场景下 5 个文件共 128 个测试通过(包含扩展@接受路径);
  • 按现有 lockfile 声明的依赖集安装后,全仓库构建通过,全仓库 typecheck 通过。

这条回归与第一节提到的两个修复效果截图相互印证:修复前内联 chip 上「Icon mask node: Missing」,修复后变为「Icon mask node: Detected ✓」。

五、本地验证方法:命令与预期结果

5.1 单元测试

packages/web-shell下运行提及菜单、composer 核心、图标解析与 CSS 转义四组测试:

cd packages/web-shell && npx vitest run \ client/hooks/useComposerCore.test.ts \ client/hooks/useAtMentionMenu.test.tsx \ client/components/composerTagIcons.test.ts \ client/utils/cssUrlVar.test.ts

预期结果:通过,涉及 4 个文件、80 个测试。需要说明的是,当前仓库源码中图标解析逻辑位于 utils/composerTag.ts,对应的测试文件为 composerTag.test.ts;验证文档中记录的composerTagIcons.test.ts是编写验证时的既有文件清单,useComposerCore.test.tsuseAtMentionMenu.test.tsxcssUrlVar.test.ts均存在且可直接运行。

5.2 ESLint 静态检查

npx eslint \ packages/web-shell/client/customization.tsx \ packages/web-shell/client/components/composerTagIcons.ts \ packages/web-shell/client/components/composerTagIcons.test.ts \ packages/web-shell/client/components/ChatEditor.tsx \ packages/web-shell/client/hooks/useAtMentionMenu.ts \ packages/web-shell/client/hooks/useAtMentionMenu.test.tsx \ packages/web-shell/client/hooks/useComposerCore.ts \ packages/web-shell/client/hooks/useComposerCore.test.ts \ packages/web-shell/client/index.ts \ packages/web-shell/client/App.tsx \ packages/web-shell/client/utils/cssUrlVar.ts \ packages/web-shell/client/utils/cssUrlVar.test.ts

预期结果:全部通过。

5.3 构建验证

npm run build --workspace=packages/web-shell

预期结果:构建通过(存在已有的 Vite large chunk 警告,不影响结果)。验证文档同时注明:当前环境未进行人工浏览器截图,行为覆盖停留在 hook 与渲染辅助函数边界,包构建用于校验 web-shell bundle 本身。

5.4 聚焦与全量验证(回归场景)

针对 2026-07-16 回归,聚焦 WebShell 结果为5 个文件、128 个测试通过(包含扩展@接受路径);随后按现有 lockfile 声明的依赖集完成安装后,全仓库构建与全仓库 typecheck 均通过。整个验证链路与文档中「Built-in SVG data URI regression」一节完全对应,可作为该功能后续任何图标相关改动的回归基线。

六、关键实现文件索引

以下是本文引用的核心实现与测试文件,便于深入阅读:

  • packages/web-shell/client/hooks/useAtMentionMenu.ts:@提及菜单状态机、provider 注册与候选项加载;
  • packages/web-shell/client/hooks/useComposerCore.ts:CodeMirror 编辑器装配、内联标签装饰与 chip DOM 渲染、提交时文本还原;
  • packages/web-shell/client/utils/composerTag.ts:标签序列化/反序列化、图标解析(自定义优先、内置兜底)、内置图标白名单;
  • packages/web-shell/client/utils/composerTag.test.ts:标签解析与图标解析的单元测试;
  • packages/web-shell/client/utils/cssUrlVar.ts:CSSurl(...)转义与自定义属性生成;
  • packages/web-shell/client/utils/cssUrlVar.test.ts:CSS 转义与cssUrlVar的单元测试;
  • packages/web-shell/client/customization.tsx:WebShellCustomizationWebShellComposerTagWebShellComposerTagIconMapWebShellAtProvider等公共类型定义;
  • .qwen/e2e-tests/webshell-mention-icon-chips.md:本文依据的验证文档本体。

七、小结

Web Shell 的@提及图标芯片功能,本质上是「序列化文本 + 编辑期视觉投影」这一设计思想在 CodeMirror 装饰层上的落地:选中候选项时写入原始文本并挂上替换装饰,编辑期呈现为带图标/标签/删除按钮的 chip,提交时再无损还原为文本,同时以 input annotation 形式把标签语义传给会话记录层。自定义图标通过composerTagIcons按 kind 注册、优先于内置图标解析,并受到「自身属性检查 + 内置白名单/安全图片源校验 + CSS 转义」三重防护。验证文档及其背后 80/128 个测试用例,为这一交互与安全边界提供了可复现的回归基线。

【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 13:41:02

光伏板积灰检测数据集:VOC转YOLO、去重与YOLOv8训练

简介&#xff1a;面向太阳能光伏板积灰与灰尘检测场景的目标检测数据集&#xff0c;包含1463张JPEG图像及对应的VOC格式XML与YOLO格式TXT标注文件&#xff0c;标注类别为Dirt单一类&#xff0c;共6822个矩形框。压缩包约75.98MB&#xff0c;共2000个文件&#xff0c;以XML与TXT…

作者头像 李华
网站建设 2026/9/10 13:41:02

AD8602ARMZ-REEL,8MHz双通道轨到轨输入输出单电源精密CMOS运算放大器

AD8602ARMZ-REEL是ADI亚德诺DigiTrim工艺双通道CMOS运算放大器&#xff0c;专为电池供电便携设备、高阻抗传感器信号调理、单电源ADC缓冲、音频前置放大场景设计。支持2.7V~5.5V单电源供电&#xff0c;具备8MHz增益带宽积、80μV低输入失调、极低输入偏置电流、轨到轨输入输出&…

作者头像 李华
网站建设 2026/9/10 13:38:49

UI设计中的空间与层次构建技巧解析

1. 项目概述&#xff1a;UI设计中的空间与层次概念解析 在数字产品设计领域&#xff0c;视觉层次的构建能力直接决定了用户体验的质量。最近为一个金融类APP做设计改版时&#xff0c;我通过重构空间层次使关键业务转化率提升了37%。这个案例让我深刻认识到&#xff1a;优秀的UI…

作者头像 李华
网站建设 2026/9/10 13:38:38

STM32+ESP8266对接阿里云飞燕平台实战指南

简介&#xff1a;本资源是一套面向嵌入式物联网开发者的完整实战项目代码&#xff0c;聚焦STM32F103与ESP8266协同接入阿里云飞燕平台的端到端实现&#xff0c;适用于具备C语言基础与Keil开发经验的中级工程师及高校电子/物联网专业学生。项目涵盖设备联网、数据主动上报、云端…

作者头像 李华