deepseek-ui-agent-sky
No description
- Stars
- 0
- Language
- TypeScript
- Created
- Aug 23, 2026
- Updated
- Aug 23, 2026
Introduction
🌌 ui-agent-sky · DeepSeek Harness 星野进度插件
AI 干活时,抬头看天——思考是星云聚拢,输出是流星划过,任务完成,满屏烟花。
一个给 DeepSeek Harness(DeepSeek 开源的 agent 运行框架)写的纯前端可视化插件:在会话头部右侧(紧贴 Session log 按钮)挂一块宽宽的「夜空」,agent 的每一个工作阶段都对应一种天象——思考时紫色星云从四周向中心聚拢,输出时金色流光自左向右掠过,跑工具时青色粒子绕轨道环旋转,等你批准时琥珀色光点脉动。任务完成的一刻,全屏升起五发烟花;出错时,则是一阵暗红色的余烬缓缓落下。
而彩蛋还在:当你在输入框里发出包含「快一点」「继续」「怎么了」「卡了」这类催促词的消息时,一道闪电会劈过整个屏幕——哪怕这条消息是在落地页发出的、挂件还没挂载——同时挂件里的粒子被冲击波吹得四散,右上角还会记下这页里你催了几次「雷」。鞭子没有消失,它化作了一道闪电。
特性一览
- 🪐 相位即天象:直接从会话快照推导 7 种相位,每种相位一套独立粒子行为,纯 canvas 实现
- 🎆 完成即烟花:运行结束且成功 → 全屏五连发烟花(重力、拖尾、渐隐一应俱全);出错 → 余烬坠落
- ⚡ 隐藏闪电:UI 上没有任何按钮,催促语随消息发出即触发一次全页雷击 + 粒子冲击波
- 🔭 零后端改动:只读订阅
ConversationSnapshot,加一个 200ms 的输入框轮询,不碰任何宿主逻辑 - 🌍 中英双语文案:接入 harness 的 locale 体系,声明式合并命名空间
它是怎么工作的(30 秒版)
DeepSeek Harness 的一切皆插件,底座是 vendored 的 Cordis 运行时。本插件是一个「两半」插件:
- Host 半(Node 侧):空的
apply(),只为了出现在 cordis.yml 的加载清单里; - Browser 半(浏览器侧):通过
package.json的dsh.client声明被发现,打包成独立 client bundle,在浏览器里注册到 UI 的插槽(slot)conversation.session.header.utilities上——那是头部右侧的工具区,与 Session log 按钮同一排;挂件以order: -5排在它左边。
浏览器侧用多个 useSyncExternalStore 选择器从会话快照投影出原始值信号:running(是否在跑)、partial.blocks 的末块类型(区分思考/输出/工具调用)、runningCalls[0].name(正在跑的工具名)、pending(是否等待批准)、lastAgentError(本轮是否出错)、turnTimings.size(跑过几轮)。这些信号喂给一个 200ms 的状态机,状态机驱动相位切换;相位再驱动粒子发射器。烟花/闪电/余烬三种全屏特效通过 createPortal 挂到 document.body,不受头部裁剪影响。闪电的触发是独立的模块级 watcher,从 apply() 起就以 200ms 轮询输入框草稿:草稿从「含催促词」变为「空」(即消息已发出)时,劈一道雷。因为 watcher 不依赖挂件挂载,落地页发出的第一条催促消息同样会召来闪电。
相位与天象
| 相位 | 何时出现 | 挂件里的天象 | 文案示例 |
|---|---|---|---|
idle | 没有运行中的任务 | 静谧夜空,稀疏星点闪烁 | 夜空静谧,等活儿干 |
think | 模型在产出推理内容 | 紫色星云从四边向中心螺旋聚拢,附秒数计时 | 模型正在思考… |
write | 模型在输出正文 | 金色流星自左向右掠过 | 正在输出… |
tool | agent 在调用工具 | 青色粒子绕轨道环旋转,右下角亮出工具名 | 正在执行 Bash |
await | 等待你批准操作 | 琥珀色光点在中心脉动 | 等你批准… |
done | 任务成功结束 | 金色光尘上浮 + 全屏烟花 ×5 | 任务完成,放烟花! |
failed | 本轮出错 | 灰色光尘下沉 + 全屏余烬坠落 | 这一轮出错了 |
安装与运行
前提
- 已克隆 deepseek-harness 并完成
pnpm install(Node^22.19 || >=24,pnpm 11) - 想让天象真的「动」起来,需要配置
DEEPSEEK_API_KEY(放进 harness 仓库根目录的.env,不要提交);不配 key 也能看 UI,但 agent 跑不起来
第 1 步:拷贝插件包
把本仓库的插件包整体拷进 harness monorepo:
cp -r <本仓库>/packages/client/ui-agent-sky <deepseek-harness>/packages/client/
第 2 步:登记 TypeScript 工程引用
在 harness 根目录 tsconfig.client.json 的 references 数组里加一行:
{ "path": "./packages/client/ui-agent-sky" },
第 3 步:让 web-app 依赖它
在 packages/bundle/web-app/package.json 的 dependencies 里加一行:
"@deepseek-ai/dsh-client-ui-agent-sky": "workspace:^",
第 4 步:安装并构建
cd <deepseek-harness>
pnpm install
pnpm run build:lib
第 5 步:patch 启动
mkdir -p scratch/agent-sky
cp <本仓库>/patch/agent-sky.cordis.yml scratch/agent-sky/cordis.yml
pnpm dsh web --patch ./scratch/agent-sky/cordis.yml
打开 http://127.0.0.1:3080,会话头部右侧就是那块夜空。发一条消息让 agent 干活,星云就开始聚拢了。
玩法
触发闪电(隐藏机制)
发送的消息文本里包含下列任意一个词,就会劈下一道闪电:
快一点 · 快点 · 继续 · 怎么了 · 卡了 · 卡住
界面上没有任何提示——它就是个彩蛋。闪电有两段效果:全屏雷击(约 1.4s 的折线闪电 + 视口闪光),以及挂件内粒子的一次冲击波散射。右上角的徽标记录这一页里召来的「雷」数;两次雷击之间至少有 1.2s 冷却。
仓库结构
├── packages/client/ui-agent-sky/ # 插件本体(整体拷入 harness monorepo)
│ ├── package.json # dsh.client 声明 + exports["./client"]
│ ├── tsconfig.json # extends harness 的 client 基础配置
│ ├── tsdown.config.ts # client bundle 打包入口
│ └── src/
│ ├── index.ts # host 半:空 apply,仅为出现在加载清单
│ ├── invariant.ts # 包级 invariant companion
│ ├── css-modules.d.ts # CSS Modules 类型垫片
│ └── client/ # browser 半
│ ├── index.ts # 注册 locale + 挂载 header slot + 启动 watcher
│ ├── whip.ts # 模块级输入框轮询:催促词随消息发出即召雷
│ ├── SkyPhaseAction.tsx # 相位状态机、粒子引擎、烟花/闪电/余烬特效
│ ├── SkyPhaseAction.module.css
│ └── locales.ts # zh / en 文案,zh 为键集真源
└── patch/
└── agent-sky.cordis.yml # 启动用的 cordis.yml 覆盖层
开发备忘
- 改完必须重启服务:client bundle 的 URL 带
?rev=<sha>修订号,启动时计算;重新构建后要重启dsh web浏览器才能拿到新包。 - CSS 时长会被压缩:lightningcss 把
2800ms压成2.8s。在产物里 grep 动画时长时记得搜压缩后的形式。 - 严格 TS:
strict: true+noUncheckedIndexedAccess。数组索引结果是T | undefined,CSS Modules 索引结果是string | undefined,拼类名用clsx(harness 的既有依赖)。 - uSES 选择器必须投影为原始值:
useSession是裸的useSyncExternalStore,Object.is比较;选择器里直接返回布尔/数字/字符串,不要返回对象。 - lint:oxlint。注意
@stylistic(arrow-parens)(块体要括号、表达式体不要)和typescript(no-unnecessary-condition)(不要给非空类型写?? fallback)。 - 端口冲突时用
--port换一个,例如pnpm dsh web --patch ... --port 3123 --no-open。
致谢与许可
基于 deepseek-ai/deepseek-harness(MIT)开发,插件架构遵循其 packages/client/* 的既有约定。
MIT © tangguoan