Kilo VS Code 插件聊天输入框文件附件机制解析:图片粘贴、拖放与 @file 路径引用
2026/9/13 8:42:19 网站建设 项目流程

Kilo VS Code 插件聊天输入框文件附件机制解析:图片粘贴、拖放与 @file 路径引用

【免费下载链接】kilocodeKilo is the all-in-one agentic engineering platform. Build, ship, and iterate faster with the most popular open source coding agent.项目地址: https://gitcode.com/GitHub_Trending/ki/kilocode

导读

本篇文章围绕 Kilo 开源仓库中 file-attachments.md 这份功能设计文档展开,深入剖析 VS Code 插件聊天输入框当前的附件能力:包括图片附件的粘贴与拖放、@file路径提及的拖拽引用,以及尚未实现的非图片文件内容附件路线图。读完本文,你将掌握 Kilo 聊天输入框附件的支持范围、底层实现(MIME 白名单校验、DataTransfer 事件处理、URI 路径解析)以及后续待办功能的具体设计方向,可直接对照源码与测试用例继续深入。

现状概览:附件能力的"两部分已就绪,一部分缺失"

该文档(标记优先级为P2,对应 Issue#6078)开门见山地界定了聊天输入框附件能力的当前状态:

  • 图片附件:支持粘贴与拖放;
  • @file路径提及:支持通过@语法或拖拽将文件路径带入对话;
  • 非图片文件的"内容"附件:尚缺失——即把文本类文件的内容直接作为消息的一部分发送给模型。

因此,当前的附件体系实际上是"路径引用"与"图片二进制内容"两种形态的混合:图片走真实文件数据(Data URL),其他文件走路径引用(@mention),而"读取文件内容并入消息"的能力仍在规划中。这也解释了为什么仓库中同时存在两套独立的 Hook:useImageAttachments.ts 负责图片附件,useFileMention.ts 负责@提及与路径追踪。

支持的图片类型:MIME 白名单

文档明确列出四种受支持的图片格式,用于粘贴与拖放场景:

格式MIME 类型
PNGimage/png
JPEGimage/jpeg
GIFimage/gif
WebPimage/webp

这一白名单在源码中有直接且一致的体现。在 image-attachments-utils.ts 中定义了常量:

export const ACCEPTED_IMAGE_TYPES = ["image/png", "image/jpeg", "image/gif", "image/webp"] /** Returns true if the given MIME type is an accepted image type. */ export function isAcceptedImageType(mimeType: string): boolean { return ACCEPTED_IMAGE_TYPES.includes(mimeType) }

配套的单测 image-attachments-utils.test.ts 对白名单做了边界验证:image/png等四种类型返回trueapplication/pdftext/plainvideo/mp4、空字符串返回false;尤其值得注意的是image/svg+xmlimage/bmp虽然同为图片格式,但因不在白名单内同样被拒绝。这说明附件校验是严格基于 MIME 精确匹配的枚举白名单,而非宽泛的image/*前缀匹配——如需扩展格式支持,只需同步修改该常量与测试用例。

图片粘贴:剪贴板事件中的文件项过滤

图片粘贴由 useImageAttachments.ts 中的handlePaste处理:

const handlePaste = (event: ClipboardEvent) => { const items = Array.from(event.clipboardData?.items ?? []) const imageItems = items.filter((item) => item.kind === "file" && ACCEPTED_IMAGE_TYPES.includes(item.type)) if (imageItems.length === 0) return event.preventDefault() for (const item of imageItems) { const file = item.getAsFile() if (file) add(file) } }

处理逻辑要点:

  1. 遍历剪贴板中的DataTransferItem,仅当item.kind === "file"且 MIME 命中白名单时才视为图片附件;
  2. 若剪贴板中没有任何受支持的图片,直接return,不拦截剪贴板事件,保证普通文本粘贴不受影响;
  3. 命中后调用event.preventDefault()阻止默认行为,再逐个取出File交给add

add内部使用FileReader.readAsDataURL将图片读取为 Data URL,并封装成统一的ImageAttachment结构:

export interface ImageAttachment { id: string filename: string mime: string dataUrl: string }

每条附件拥有独立idcrypto.randomUUID()生成),便于后续按id删除(remove)与整体清空(clear)。pending信号用于追踪 FileReader 的异步读取进度,读取期间界面可据此展示"正在处理中"的状态。

拖放图片:为何必须按住 Shift?

文档特别强调了一个容易踩坑的交互细节:拖放图片到聊天输入框时,需要按住 Shift 键。原因在于:

VS Code 在拖拽操作期间会禁用 webview 的 pointer-events,以便自身处理编辑器区域内的拖放;按住 Shift 拖拽会重新启用 webview 接收 drop 事件(要求 VS Code 1.91+,源自 microsoft/vscode 的相关 issue)。

也就是说,这是 VS Code 宿主环境对 webview 施加的全局限制,而非 Kilo 自身的行为缺陷。若不按 Shift,webview 内根本收不到拖拽事件,图片自然无法落入输入框。

在 PromptInput.tsx 的容器元素上,可以看到拖放事件的完整接线:

<div class="prompt-input-container" classList={{ "prompt-input-container--dragging": imageAttach.dragging() }} onDragOver={imageAttach.handleDragOver} onDragLeave={imageAttach.handleDragLeave} onDrop={(event) => { if (readonly()) { event.preventDefault() return } imageAttach.handleDrop(event) }} >

值得注意的几点:

  • 只读态防护:当会话处于只读状态时,drop事件只做preventDefault()拦截,不产生任何附件;
  • 拖拽视觉反馈dragging信号驱动prompt-input-container--dragging样式类,输入框在拖拽悬停时会有明显的视觉提示(对应样式见 prompt-input.css);
  • 拖离判定handleDragLeave借助isDragLeavingComponent判断拖拽是否真正离开了组件边界(relatedTarget为空或不在容器内),避免鼠标在输入框内部子元素间移动时闪烁拖拽状态。

handleDragOver对可接受的拖拽数据类型做了白名单判断,只接受三种:

const acceptable = types.includes("Files") || types.includes("application/vnd.code.uri-list") || types.includes(KILO_FILE_PATH_MIME)

刻意拒绝纯text/plain——否则普通的文本拖拽会被误拦截为文件拖放,破坏常规编辑体验。这三类数据的含义分别是:真实文件拖入(Files)、VS Code 资源管理器/编辑器标签页拖出(application/vnd.code.uri-list)、Kilo 内部的文件路径拖拽(自定义 MIME)。

文件路径拖放与 @file 提及:DataTransfer 的多级解析

handleDrop的核心是优先解析文件路径,其次才兜底到图片文件

const handleDrop = (event: DragEvent) => { setDragging(false) event.preventDefault() const dt = event.dataTransfer if (!dt) return // First: check for text/URI file path drops (VS Code explorer, editor tabs) const paths = extractDropPaths(dt) if (paths && paths.length > 0 && onFilePaths) { onFilePaths(paths) return } // Second: fall through to image file drops const files = dt.files if (!files) return for (const file of Array.from(files)) add(file) }

路径解析实现在 path-mentions.ts 的extractDropPaths中,按优先级依次检查三类数据源:

  1. Kilo 内部相对路径拖拽(自定义 MIMEapplication/x-kilo-file-path):用于 diff 面板文件头等内部场景,内容是可直接用作@提及的工作区相对路径;
  2. VS Code URI 列表application/vnd.code.uri-list):来自资源管理器、编辑器标签页的拖出,内容是file://vscode-remote://形式的 URI;
  3. text/plain兜底:仅当每一行都满足isFilePathfile:///vscode-remote://前缀、Unix 绝对路径、Windows 盘符路径如C:\)时才会被当作路径处理,否则保持普通文本拖拽语义。

路径拿到后还需经过convertToMentionPath归一化:剥离file://vscode-remote://协议前缀、decodeURIComponent解码、规范化反斜杠,并在文件位于工作区内时转换为相对路径(如src/index.ts);对workspace/appworkspace/app2这类前缀歧义还做了边界字符检查。最后insertPathMentions会给每个路径加上@前缀拼入输入框文本:

const inserted = paths.map((path) => `@${path}`).join(" ") + " "

这正好对应了文档"@filepath mentions work"的结论:拖一个文件进输入框,等价于手打一条@路径引用,模型侧会通过上下文机制读取对应文件内容,而无需把文件内容整体塞进消息体。

附件生命周期的另一面:消息恢复时的回填

附件并不只存在于输入框这一个瞬时状态。在消息被"恢复"(例如 revert 到某条历史消息)时,附件需要被精确回填。相关协议定义在 extension-messages.ts 的SetChatBoxMessage中:

export interface RestoredImage { dataUrl: string mime: string filename?: string } export interface SetChatBoxMessage { type: "setChatBoxMessage" text: string /** 被恢复消息携带的文件附件精确相对路径(若有),如 revert 到带 @mention 的消息 */ paths?: string[] /** 被恢复消息引用的历史会话,与 paths 同样方式回填 */ sessions?: SessionSearchItem[] /** 被恢复消息附带的图片;存在即视为权威值,PromptInput 用其替换当前附件 */ images?: RestoredImage[] }

设计上有两个细节值得注意:

  • paths采用精确路径回填而非从文本正则反推——注释中明确指出,当真实路径包含空格时,正则无法区分完整提及与截断前缀,因此必须携带权威路径列表;
  • images字段"存在即权威":PromptInput会用该列表整体替换当前附件(空数组即清空);字段缺失则保持现状不动。这避免了恢复动作与用户正在编辑的附件状态互相覆盖。

这从协议层面印证了文档所言"image attachments … work":图片附件的存取、回填链路已经完整闭环。

剩余工作路线图:非图片文件内容附件

文档以 "Remaining Work" 小节完整列出了下一步规划,这是附件能力从"路径引用"走向"内容附件"的关键设计清单:

  1. 输入框工具栏新增附件按钮(回形针或类似图标);
  2. 支持非图片文件拖放到聊天输入区域;
  3. 通过按钮唤起文件选择对话框
  4. 文本类文件:读取内容,作为消息中的文本部分(text part)随消息发送;
  5. 二进制文件:展示"不支持"提示;
  6. 附件展示:在输入框上方以 chips/标签形式列出已附加文件,并带移除按钮;
  7. 大小限制:限制附件体积,超出时给出明确错误提示。

对照现有源码结构,可以推断出该路线图的落点:第 1~3 项会扩展PromptInput工具栏与useImageAttachmentssetFilePathDropHandler机制(后者已预留了"文件路径拖放回调"的注册口子);第 4~5 项需要新增按 MIME 判断"文本类 vs 二进制"的分派逻辑——现有的ACCEPTED_IMAGE_TYPES白名单模式可以天然扩展为一张包含text/*application/json等的多级类型表;第 6 项可复用图片附件已实现的id-remove-clear删除链路;第 7 项则与pending信号、FileReader 读取链路天然衔接。可以说,路线图的每一项都能在当前架构中找到对应的挂载点。

总结

Kilo 聊天输入框的附件能力目前呈"双轨"形态:图片以真实数据(Data URL)附加其他文件以@路径引用。本文从设计文档出发,结合 useImageAttachments.ts、path-mentions.ts、PromptInput.tsx 及其配套测试,完整还原了 MIME 白名单校验、粘贴/拖放事件处理、VS Code Shift 拖拽限制、URI 路径归一化与消息恢复回填的实现细节。对于希望参与该 P2 功能开发的读者,可从文档的 Remaining Work 清单入手,以图片附件链路为模板,向"文本内容附件 + chips 展示 + 大小限制"方向扩展即可。

【免费下载链接】kilocodeKilo is the all-in-one agentic engineering platform. Build, ship, and iterate faster with the most popular open source coding agent.项目地址: https://gitcode.com/GitHub_Trending/ki/kilocode

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询