news 2026/9/10 21:13:05

qwen-code 终端内联图片渲染:display_image 工具、Kitty/chafa 三级降级与 E2E 验证指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
qwen-code 终端内联图片渲染:display_image 工具、Kitty/chafa 三级降级与 E2E 验证指南

qwen-code 终端内联图片渲染:display_image 工具、Kitty/chafa 三级降级与 E2E 验证指南

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

本文以仓库 .qwen/e2e-tests/terminal-inline-images.md 的 E2E 测试计划为主体,系统讲解 qwen-code 在交互式终端中显示图片的完整方案:display_image工具的文件路径渲染、AI 回复与工具结果中的内联inlineData图片渲染、Kitty/Ghostty 原生协议与 chafa ANSI 回退的降级链路,以及占位符、无障碍模式与流生命周期下的验证要点。读完本文,你将掌握这套终端图片渲染的架构边界、安全约束与可执行的回归验证步骤。

背景:为什么要做终端内联图片

qwen-code 是一款运行在终端中的开源 AI 编码 Agent(见 README.md)。终端本身没有浏览器那样的 DOM 可以承载图片,要在 CLI 里让用户看到模型输出的图片、或让模型调用工具展示工作区里的 PNG,就必须依赖终端协议能力。仓库的方案由两条输入通道组成:

  • 文件路径通道:模型调用display_image工具,传入工作区内 PNG 的绝对路径,由终端渲染器读取文件并显示(已有能力,见 display-image.ts)。
  • 内联数据通道:模型回复或工具结果的parts中直接携带inlineData(base64 编码的image/png),CLI 需要把图片从"模型事件流"提取出来,按顺序渲染进转录(transcript),这是 .qwen/e2e-tests/terminal-inline-images.md 重点验证的新入口点。

E2E 计划的开篇 "Baseline" 明确了当前基线:在main分支上,助手回复中text -> inlineData(image/png) -> text的图片会被省略,工具functionResponse.parts中的 PNG 会被降级为文本;而 #8217 引入的display_image渲染器已能显示工作区 PNG。因此验证的核心就是:复用display_image的渲染器,补齐内联数据入口与转录生命周期,确保两条通道行为一致。

渲染架构:一个共享渲染器,两条数据入口

渲染器分层(三级降级)

终端图片渲染的统一实现位于 packages/cli/src/ui/utils/terminal-image-renderer.ts,按能力降级为三级:

  1. Kitty 图像协议(原生):当满足supportsKittyImageProtocol()的条件时(标准输出为 TTY、无TMUX/SSH_TTY/SSH_CLIENT环境变量、TERMkittyTERM_PROGRAMghostty,且非 Warp 终端),渲染器把 PNG 编码为 Kitty 虚拟图像序列encodeKittyVirtualImage,并在屏幕上布局对应行数的 Unicode 占位符buildKittyPlaceholder。终端负责从占位符单元格重绘图像,因此同一图像只需传输一次 base64 载荷——这正是 E2E 计划中"remounting a history row does not retransmit an already-written payload"的实现基础(源码见wasKittyImageWritten/markKittyImageWrittenTRANSMITTED_KEY_LIMIT = 256的会话级已写集合,见 terminal-image-renderer.ts)。
  2. chafa ANSI 回退:在不支持 Kitty 协议的环境中,若findExecutable('chafa')能在 PATH 中找到 chafa,则调用chafa --animate=off --colors=256 --format=symbols --symbols=block --size=WxH生成 ANSI 符号行。图片数据通过 stdin(input)传入,文件路径仅用于--size之外的显式参数,模型可控值绝不允许作为命令参数拼接,且通过CMD_SHELL_METACHARACTERS正则与shouldRunThroughShell防御 Windows.cmd/.batshim 的命令注入(见 terminal-image-renderer.ts 与 renderWithChafa)。chafa 渲染有 8 秒超时、2 MiB 输出上限。
  3. 纯文本占位符:两者都不可用时(或无障碍模式开启时),输出确定性的占位符文本[image: <width>x<height> png]

文件路径通道:display_image 工具

display_image工具定义在 packages/core/src/tools/display-image.ts,它是一个只读声明式工具,完整校验链为:

  • file_path必须是绝对路径、经过unescapePath清洗、非空;
  • 路径必须位于当前工作区内(isPathWithinWorkspace校验);
  • 执行时校验:文件存在、是普通文件而非目录、大小不超过MAX_TERMINAL_IMAGE_BYTES(即 8 MiB,常量定义见 packages/core/src/tools/tools.ts);
  • 读取 24 字节 PNG 头,校验89504e470d0a1a0a签名,截断或非 PNG 文件直接报错;
  • 只能由主 Agent 执行isInForkExecution()时返回EXECUTION_DENIED
  • 渲染支持探测通过后返回TerminalImageDisplaytype: 'terminal_image'),CLI 侧的FileTerminalImage组件渲染它。

该工具是纯展示性的:llmContent明确告知模型"此工具不向模型提供图片内容,需要理解图片请用 read_file"。CLI 组件还会二次校验路径仍在工作区内,越界直接拒绝显示。

内联数据通道:parts 提取与顺序保持

内联图片的提取逻辑位于 packages/cli/src/ui/utils/inline-image-parts.ts:

  • getInlineImageData(part):仅接受mimeTypeimage/开头、data为字符串且长度不超过MAX_INLINE_IMAGE_ENCODED_LENGTH的 part(编码上限由 8 MiB 原始字节按 base64 膨胀 4/3 换算并向上取整);
  • collectInlineImages(parts):遍历顶层 part 与functionResponse.parts中的嵌套 part,每个条目最多渲染 4 张图片MAX_INLINE_IMAGES_PER_ITEM = 4),超出部分计入omittedImageCount
  • extractInlineContentRuns(parts):把 parts 流折叠为text -> image -> text交替的 run 序列,thoughtpart 被跳过,保证转录顺序为text -> image -> text,溢出图片在末尾折叠为[+N more images](对应计划中"six images render four and the row ends with[+2 more images]")。

CLI 侧 TerminalImage.tsx 根据 props 是否含image字段自动分派到InlineTerminalImageFileTerminalImage,两者共用RenderedTerminalImage:Kitty 序列通过writeRaw写入、chafa 行进入MaxSizedBox、不可用时显示占位符。渲染结果还有两层缓存:40 条/32 MiB 的渲染结果 LRU 与 4 条的内联解码缓存,避免 resize 与历史行重挂时重复读盘、重复派生 chafa。

内联图片的完整性校验与占位符语义

内联数据来自模型输出,属于不可信输入,必须在渲染前做完整性校验。getDecodedInlinePngreadValidatedInlinePngSize实现了以下检查(见 terminal-image-renderer.ts):

  • base64 语法校验:去除空白后非空、长度% 4 != 1、字符集合法、解码后重新编码必须与原文一致(防"宽松解码"歧义);
  • 解码后字节数不得超过 8 MiB;
  • PNG 结构校验:至少 24 字节、IHDR 块长度必须为 13、块类型必须为IHDR
  • 尺寸合理性:宽高为正整数、单边不超过MAX_INLINE_IMAGE_DIMENSION(1,000,000)、像素总数不超过MAX_INLINE_IMAGE_PIXELS(64,000,000);
  • 长度或编码上限超限的载荷在进入 UI 历史前就被丢弃(返回null,不产生渲染结果);而通过校验但畸形的数据(如伪造 IHDR)与超出 8 MiB 的载荷则走确定性占位符路径。

这套语义正是 E2E 计划 "Placeholders and accessibility" 一节要回归验证的内容:malformed base64、超过 8 MiB 的载荷、非法 IHDR 尺寸、非 PNG MIME 类型四种负例,必须"不写任何原始图像序列"。

无障碍模式与流生命周期

无障碍模式

开启无障碍模式后,内联图片只输出占位符。开启方式有两种等价途径:

  • CLI 启动参数:--screen-reader
  • 配置文件:ui.accessibility.screenReader: true(对应配置项定义见 packages/cli/src/config/config.test.ts 的 screenReader 配置测试)。

实现上,InlineTerminalImage通过useIsScreenReaderEnabled()感知该模式,并将其作为disabled传入prepareInlineTerminalImage——渲染结果直接置空,仅保留[image: WxH png]占位文本,避免原始图像序列对读屏器产生噪音。

流生命周期边界

模型输出是流式的,因此 E2E 计划 "Stream lifecycle" 一节要求覆盖六类边界:全新重试(fresh retry)、续传重试(continuation retry)、模型回退(fallback)、取消、流边界(stream boundary)与工具调用边界(tool call boundary)。需要验证的三条核心不变量:

  1. 全新尝试丢弃一切:失败尝试中暂存的图片/文本 run 全部作废,不残留到 UI;
  2. 续传保留部分输出:continuation 场景必须保留已提交的部分输出;
  3. 边界先提交再继续:每个正常边界,先提交之前的 run,再渲染后续状态行或工具行,确保text -> image -> text顺序在历史中稳定。

会话恢复(/resume)语义

计划明确了两类持久化差异:

  • 成功工具行的图片:从持久化的functionResponse.parts中重建,顺序保持;
  • 助手内联图片:当前 Core 的 recorder不持久化助手的内联图片,恢复会话时助手输出以持久化的文本继续。

这意味着 E2E 验证/resume(或--continue)后,工具图片必须完整还原,而助手图片按"文本续接"预期处理即可。

按环境分组的回归验证步骤

共享渲染器回归(display_image 既有能力不被破坏)

  1. 让模型对工作区内 PNG 调用display_image
  2. 在直接运行的 Kitty 或 Ghostty 中,确认原生预览仍能渲染;
  3. 在安装了 chafa 的非原生终端中,确认 ANSI 预览仍能渲染;
  4. 确认文件路径工具仍保留工作区、文件大小与 PNG 校验行为(对应 display-image.ts 的完整校验链)。

内联助手图片与工具图片

  1. 在两条助手文本 part 之间返回一张 1x1 PNG,确认转录顺序为text -> image -> text
  2. 在成功工具的顶层与嵌套functionResponse.parts中返回 PNG,确认成功工具行保留图片;
  3. /resume(或--continue)恢复会话,确认成功工具图片顺序从持久化 parts 重建;
  4. 一次输出六张图片(五张助手 + 一张工具),确认前四张渲染、行尾出现[+2 more images]

Kitty/Ghostty 原生协议

  1. 在未套 tmux、未走 SSH 的直接 Kitty/Ghostty 中启动 CLI;
  2. 重复助手与工具用例;
  3. 确认内联 PNG 与display_image使用相同的虚拟布局与 Unicode 占位符;
  4. 确认历史行重挂(remount)不会重传已写入的图像载荷(由transmittedKeys会话级集合保证)。

chafa 回退环境

  1. 在 Warp、iTerm2、tmux、SSH 或其他非原生环境(已安装 chafa)启动 CLI;
  2. 重复助手与工具用例;
  3. 确认 PNG 字节渲染为 ANSI 符号行且滚动时保持对齐;
  4. 确认图像数据通过 stdin 提供,任何模型可控值都不作为命令参数使用。

占位符与无障碍

  1. 在既非直接 Kitty/Ghostty、又未安装 chafa 的环境中重复用例;
  2. 确认有效 PNG 显示[image: <width>x<height> png]
  3. 分别用畸形 base64、超过 8 MiB 的载荷、非法 IHDR 尺寸、非 PNG MIME 类型验证:不写原始图像序列;超限载荷在进入 UI 历史前被丢弃;可解析的畸形/非 PNG 数据输出确定性占位符;
  4. --screen-reader(或ui.accessibility.screenReader: true)重复,确认只输出占位符。

流生命周期用例

依次演练全新重试、续传重试、模型回退、取消、流边界、工具调用边界与 goal-state 事件展示,按前述三条不变量核对输出。

自动化证据清单

E2E 计划的 "Automated Evidence" 要求完成并记录以下检查项,作为人工终端验证之外的机器证据:

  • 聚焦测试:CLI 渲染器(如 TerminalImage.test.tsx)、组件、流、工具、resume 与压缩(compaction)相关测试;
  • Core 测试Turndisplay_image(见 display-image.test.ts)、配置、调度器与工具测试;
  • 工程门禁npm run lint:cinpm run typechecknpm run buildnpm run check:serve-fast-path-bundle

关于真实终端验证:当本地环境没有 Kitty/Ghostty 会话时,真实终端输出属于评审者的硬件步骤。由于本方案复用 #8217 的渲染器,其既有的 Kitty、Ghostty、cmux、Warp 手动证据已覆盖终端协议层;本计划把新的手动验证聚焦于内联数据入口与转录生命周期即可,无需重复整套协议验证。

关键源码索引

  • E2E 计划原文:.qwen/e2e-tests/terminal-inline-images.md
  • 渲染器核心实现:packages/cli/src/ui/utils/terminal-image-renderer.ts
  • 内联 parts 提取:packages/cli/src/ui/utils/inline-image-parts.ts
  • 共享 UI 组件:packages/cli/src/ui/components/TerminalImage.tsx
  • display_image工具:packages/core/src/tools/display-image.ts 及其测试 packages/core/src/tools/display-image.test.ts
  • 8 MiB 上限常量:packages/core/src/tools/tools.ts
  • 无障碍配置测试:packages/cli/src/config/config.test.ts

【免费下载链接】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 21:07:16

昇腾CANN/GE算子属性获取API

aclmdlGetOpAttr 【免费下载链接】ge GE&#xff08;Graph Engine&#xff09;是面向昇腾的图编译器和执行器&#xff0c;提供了计算图优化、多流并行、内存复用和模型下沉等技术手段&#xff0c;加速模型执行效率&#xff0c;减少模型内存占用。 GE 提供对 PyTorch、TensorFlo…

作者头像 李华
网站建设 2026/9/10 21:04:46

金刚石激光烧蚀多物理场仿真与COMSOL优化实践

1. 金刚石激光烧蚀的物理背景与工程挑战 金刚石作为自然界已知最硬的材料&#xff0c;在精密加工领域一直存在加工效率低、工具损耗大的痛点。传统机械加工方法在应对金刚石超硬特性时往往力不从心&#xff0c;而激光烧蚀技术通过将高能量激光聚焦于微小区域&#xff0c;能在极…

作者头像 李华
网站建设 2026/9/10 21:03:51

怀化短视频公司盘点:AI短视频服务商推荐

来源&#xff1a;唐sirAI&#xff08;www.tangsir.cc&#xff09; | 电话&#xff1a;18874530691━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━随着AI技术的飞速发展&#xff0c;怀化短视频公司已经成为怀化本地企业数字化营销的重要趋势…

作者头像 李华