Gives the agent a mouth through the ai-ball floating orb: speak text that the orb types out character by character, set its mood colour, show or hide its monologue panel, read back what you typed into it, and check or start it. The orb is a separate Python 3.10+ overlay you install yourself, and the plugin only writes the files it watches.
Install
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:Hyfwdnmd666/dsh-ai-ball
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
This plugin publishes its README in Chinese only.
给 agent 一张嘴:让它通过 ai-ball 那颗悬浮球说话、做表情、听你打字。
ai-ball 是一个 Windows 悬浮球 —— 它把自己追加到 monologue.log 的文字逐字"说"出来、
按 status.json 里的 mood 变色、把你打进输入框的话追加到 input.log。
球本身是哑的,它只认文件。
所以这个插件很薄:它不去操作球的窗口,也不 spawn Python,它只写球已经在看的那些文件。 这也是为什么任何进程都能当球的"大脑"。
你需要什么
- ai-ball 本体(一个 Python 3.10+ 的目录,里面有
ball.py) - 把它跑起来(双击
start.bat,或python ball.py)
插件本身不包含球,也不会替你安装它。
安装
dsh plugin --profile web add link:/path/to/dsh-ai-ball
或者从市场里装。
配置
挂在 profile 的 cordis.patch.yml 里:
- id: dsh-ai-ball
name: dsh-ai-ball
config:
ballDir: C:\tools\ai-ball # 必填:放着 ball.py 的那个目录
startCommand: C:\tools\ai-ball\start.bat # 可选:ball_launch 用
cps: 50 # 可选:球的打字速度,用来估算 wait
heartbeatMs: 3000 # 可选:心跳间隔,必须小于球那边的 stale_s
followInput: true # 可选:你在球里打的字直接变成 agent 的消息
followMs: 700 # 可选:input.log 的轮询间隔
files: # 可选:和球自己的 config.json 对齐
monologue: monologue.log
input: input.log
status: status.json
也可以走环境变量 AIBALL_DIR / AIBALL_START。
ballDir 故意没有默认值。 猜别人把球解压到哪儿了,正是插件往错目录里写文件的方式 ——
所以它宁可报一个说清楚哪里不对的错。
听,才是"交互"
只写不读的球是个牵线木偶:agent 说话、你看着,然后没有下文。
而"我轮询一下看看你说没说话"也不算交互 —— agent 只有碰巧想起来调 ball_listen 才听得到你。
你没被听见的时候,你打进去的字就进了 input.log 这个黑洞。
所以默认开着 followInput:插件自己盯着 input.log,把每一行当成一条真正的用户消息
交给 agent(agent.followup(),它的契约原话是"排一个普通的后续回合并唤醒驱动器 ——
这条目自成其回合的唯一一条普通消息")。你在球里打字,等于你发了条消息。
三个细节:
- agent 是"学"来的。 插件层的上下文里没有 agent;
exec.agent只在工具调用时才出现。 所以插件在任何一个球工具第一次被调用时才知道该把话送给谁。在那之前的输入不会丢, 会等它认领。 - 投递失败会重试,不会吃掉你的话。 送不出去就把游标退回去,下一拍再送。
- 监听器和
ball_listen共用同一个读取游标。 两个游标会让同一句话被消费两次 (一次当消息、一次当工具结果)。所以开着followInput时ball_listen通常返回空 —— 那是成功,不是沉默,话已经以消息的形式到了。
⚠️
brain.py也读input.log。 两个读者 = 两个回复。想要球只当 DSH 的嘴, 就别跑brain.py(插件从加载起就接管心跳,球不会因此变灰)。想让它自己聊天, 就把followInput关掉。
六个工具
| 工具 | 作用 |
|---|---|
ball_say |
说话。追加到 monologue.log,球逐字念出来。clear=true 先清屏 |
ball_mood |
改球的脸:idle / thinking / nervous / smug / broken |
ball_panel |
显示 / 收起独白面板 |
ball_listen |
手动读 input.log。开着 followInput 时通常返回空(话已经作为消息送来了) |
ball_status |
报告接线情况:文件大小、最后说了什么、心跳多旧、有没有在心跳 |
ball_launch |
按配置的 startCommand 把球拉起来 |
两个会让你浪费一下午的坑
1. 心跳不是可选项 —— 插件会自己接管它
球把过期的心跳读成"大脑死了"并渲染成灰色,而那会盖掉 mood。
所以 ball_mood 不只是写一次 mood:它同时启动一个心跳,在插件加载期间一直刷。
这有两个后果:
- 第一次调
ball_mood之后,球就再也不会因为你没在做事而变灰了(这是对的: 插件活着 = harness 活着) - 插件被卸载/重载时心跳会停(挂在 cordis 的 dispose 上,不会泄漏定时器)
一个只写一次 mood、不管心跳的实现,看起来像成功了,然后 20 秒后静默失效。
2. 如果 brain.py 在跑,它每三秒会把你的 mood 踩回 idle
brain.py 每隔几秒重写整个 status.json(心跳是它的)。
两个写者抢同一个文件,后写的赢。
想自己拥有球的脸,在 brain.json 里设:
{ "write_mood": false }
那样它只刷心跳,文件里现有的 mood 原样保留 —— 两个写者就能共存了。
3. ball_panel 为什么带一个序号
status.json 里的 panel 不是"当前该是什么状态",是一条命令,panel_seq 是它的序号。
球只在序号变化时动一次。
不这么做的话,插件每几秒重写一次文件,就等于和你抢面板开关: 你收起面板,它下一拍又打开。
带序号之后:
- 你手动开关面板一直算数(插件没改变主意,序号没变)
- 插件改变主意时把序号加一,球再执行一次
- 每次调
ball_panel都是新请求(序号加一),所以"你关掉了,我要它再显示" 是有效的,不会变成空操作
(球那边没有 panel_seq 的 panel 一律不执行 —— 没有序号就无法区分"你刚关掉"和
"它一直这么说",照做就是抢开关。)
ball_listen 为什么不会切坏中文
读游标按字节记,而且只推进到最后一个换行。
写入方可能被撞见写到一半:游标如果按字符算、或者用替换字符解码尾部, 那半个 UTF-8 序列会变成 U+FFFD 并且永久留在游标后面 —— 内容就再也读不出来了。 停在最后一个换行,残缺的尾巴下次会重新读一遍,这是简单正确的做法。
(同一个 bug、同一个修法,ai-ball 的 Python 侧也有一份。)
它不做的事
- 不判断球在不在跑。
ball_status报的是文件状态,不是窗口状态 —— 严格来说,一个没在跑的球 和一个在跑但没人写的球,看起来是一样的。 - 不会只启动一颗球。
ball_launch是只写的,重复调用会得到两颗球。 - 不渲染 Markdown。 球是嘴,不是文档。
**强调**会原样显示出来。 - 不会替你记住要开面板。
ball_say不会自动显示面板 —— 面板收着的时候它照样写成功, 只是没人看得见。要保证被看到,先ball_panel(true)。
许可
Links
More in this category
PC2005-cloud/dsh-pet#dsh-pet★ 3496
Desktop pet for the DSH Web UI with 25 transparent animations, screen wandering, click reactions and drag, plus a reproducible asset-generation pipeline.
Nagi-ovo/dsh-ads★ 682
Parody ads in 2005-Chinese-web style: sidebar banners, in-chat feeds, corner popups, and a close button whose hit area is smaller than it looks. All fictional.
vlln/whale-girl★ 375
Desktop pet (QQ-pet style): floats in the corner, draggable, feedable, playable.
yyh-001/dsh-meme★ 295
Chat meme stickers: text-only send, mood auto-send, QQ/WeChat-style picker, auto-learn, custom packs.
a86582751/dsh-nexttavern★ 191
NextTavern is a long-form roleplay plugin for DeepSeek Harness 0.1.7-rc.2 Web, with character-card import and creation, worldlines, worldbooks, layered long-term memory, keyword/semantic/hybrid retrieval, character agents, and card or novel export. SillyTavern character-card import is supported; v0.2.9 fixes distribution and installation.
Sutera-Diffusus/dsh-whale-musume★ 156
A whale-girl companion for DeepSeek Harness with 45 achievements, daily quests and weekly check-ins, three mini-games, 92 artworks, 620 dialogue lines, a growth journal, weather and festival reactions, per-tool work poses, cross-device save export/import (JSON file or migration code), accessibility mode and an optional MiMo TTS bridge. Data stays in the host localStorage with no telemetry. Verified on DSH desktop 0.2.0-rc.2; compatible with 0.2.1-rc.1/rc.2 and legacy 0.1.x web.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.