Introduction¶
When running long tasks in the DSH Web interface, the interface is silent: you don’t know if the model is currently thinking, if a command is executing, or if it has already errored out; you can only stare at the logs to repeatedly confirm. The dsh-pet-sayaka plugin does something very direct—it listens to the DSH session state and translates it into expressions, short lines, and voiceovers using a desktop pet (Kamishiro Sayaka) in the bottom right corner of the interface. Running code makes it draw its sword, reporting an error makes it sad, success makes it happy, making the execution status visible at a glance.
It is maintained by KOGGUA-EDIT, open source, and under the MIT license. Below is an introduction following the order of “What is this—How states are mapped—How voiceovers are triggered—How to install—How to use”.
What is it¶
One-sentence positioning: Adds a desktop pet to the DeepSeek Harness Web UI, maps session runtime states to twelve standing illustrations, and pairs them with dialogue bubbles and audio. The maintainer is KOGGUA-EDIT, the source code is in the dsh-pet-sayaka repository on GitHub, and the labeled category is “Fun Cosplay”.
It doesn’t solve a functional problem, but a feedback problem. How long will the command take, did this round actually succeed, or is it stuck right now—you can tell without reading the logs.
The plugin targets the Web端, injecting frontend resources via the DSH plugin system’s bundle mechanism, not going through the function call route.
State Mapping¶
The plugin maps DSH session states to twelve standing illustrations (assets/pet/<state>.png, 784x720 transparent background), switching is a direct replacement with no fade in/out. The mapping provided by the README is as follows:
| Session State | Corresponding Expression | Illustration Name |
|---|---|---|
| Idle | Sleeping | sayaka-睡觉 (Permanent, occasionally wipes sword when idle) |
| Thinking | Thinking | sayaka-思考 |
| Running Code (bash / pwsh etc. command-line tools) | Drawing Sword | sayaka-拔刀 |
| Run Failed (non-zero exit, isError, timeout, killed, whole round error) | Sad for 5 seconds | sayaka-伤心 |
| Run Success | Happy for 5 seconds | sayaka-高兴 |
| Round finished, and no other sessions are running | Collapsed for 5 seconds | sayaka-累倒 |
| First minute after first run | Calm → 1 min → Sleeping | sayaka-平常心 |
| During Sleeping / Calm / Thinking, every 14~30 seconds | Wiping Sword for 3.5 seconds | sayaka-擦剑 |
| First two pokes | Ignoring | — |
| Three pokes in 10 seconds | Shy for 1 second | sayaka-害羞 |
| Five pokes in 10 seconds | Angry for 3 seconds | sayaka-生气 |
| Ten pokes in 10 seconds | Exploded for 6 seconds | sayaka-生气2 (Highest priority) |
| Holding and dragging | Dragged away | sayaka-拖拽 |
In implementation, the illustrations are cached and switched directly at runtime. The first eight are versions cut, background removed, and compressed from the original large image (one is 75-95 KB); the last four were added later, quantized to 256 colors, one is 64-79 KB. The 1 MB original images are not included in the repository.
Dialogue Bubbles and Voiceovers¶
When a state first switches, a monologue bubble pops up: a large rounded rectangle with a white background, dark gray stroke, and 20px border radius, displaying for only 1 second. Long states like Sleeping or Calm won’t keep the text hanging; it only appears during that one second of switching. Bubble width follows the number of words (widest up to 1.7 times the pet’s width), font size scales with the pet’s size.
For example, Thinking displays emmmmm, Drawing Sword displays 武装保卫见泷原!, Happy displays 耶✌️, and Exploded displays 你再戳一下试试!. See the README for the full list of lines.
Lines aren’t just fixed sentences during state switching; they also change responses based on accumulated counts. When the same state is encountered for the Nth time, it switches to a line that sounds more like a response, and the expression and audio are changed if necessary. The rules are written in the QUIPS table in lib/client.js. Adding a line is adding a row, the at field indicates how many times this state has accumulated in the current round:
| State | Nth Time | Line | Audio | Bonus |
|---|---|---|---|---|
| Sad | 2 | 又出问题了 | quip-sad-2.wav |
— |
| Sad | 5 | 气死我了!!! | angry.wav |
Expression switches to Angry for 3 seconds |
| Sad | 9 | 这点小事才不会让我认输! | quip-sad-9.wav |
Then resets counter |
| Happy | 2 | 嘿嘿,成了 | quip-happy-2.wav |
— |
| Happy | 5 | 今天日子真不错 | quip-happy-5.wav |
Then resets counter |
| Drawing Sword | 5 | 我可不是跑腿的! | quip-sword-5.wav |
Then resets counter |
| Thinking | 3 | 想不出来… | quip-thinking-3.wav |
Then resets counter |
| 5 pokes in 10 seconds | — | 别戳了!!! | quip-poke.wav |
Angry for 3 seconds |
| 10 pokes in 10 seconds | — | 你再戳一下试试,我绝对不放过你! | quip-poke2.wav |
Exploded for 6 seconds |
It resets when reaching the last tier, so it’s “get angry every five errors,” and the next five errors will get angry again, not just the first time.
Regarding audio, each state has a recording (assets/pet/<state>.wav) that plays with the state; situational lines have dedicated recordings (assets/pet/quip-*.wav). State recordings aren’t played every time; each state tracks a separate counter: +1 every time you enter the state, play once after accumulating 5-8 times, reset, and then roll a new random interval of 5-8. The casual morning.wav says the first sentence after every startup, not replaying on page refresh; if the browser blocks autoplay, it will catch up on the first click/key press. Shy speaks every time it is poked, not accumulating counts; dragging and consecutive pokes have their own dedicated recordings. Only one plays at a time; if the previous one isn’t finished when the next starts, it is cut short directly; two lines won’t overlap.
If you don’t want this interval, there is a “Speak on every change” switch in the “sayaka” section of the settings page: turning it on stops counting, and Drawing Sword / Happy / Sad / Thinking / Sleeping / Calm will play a segment directly on every change (Shy, Angry, Dragged already have their own dedicated lines, so they won’t repeat). The “Audio” switch in the same section can turn off all sounds with one click, while the expressions move normally.
Installation and Usage¶
Install from npm (recommended):
dsh plugin --profile web add dsh-pet-sayaka
Or install directly from GitHub:
dsh plugin --profile web add github:KOGGUA-EDIT/dsh-pet-sayaka
After installation, the Web service needs to be restarted once to take effect: DSH title bar “⋯” → “Restart Web Service”, then refresh the page, and you can see the desktop pet in the bottom right. The reason is that the manifest of browser plugins (which plugins have frontend bundles) is scanned when the Web service starts, and the list is fetched from the server when the page loads.
When developing locally, the README also introduces a non-packaging wiring method: source code is placed in a fixed directory, and a tools/install.mjs script is used to write the plugin into the profile’s dependencies, add to dsh.profile.bundles, and create a link (or junction) in node_modules pointing to the source directory. The script has --status / --uninstall parameters, is idempotent, and running it repeatedly is fine. When using source code for development, changes or preference changes require restarting the Web service to take effect; the same applies to installation and uninstallation.
Uninstall via CLI:
NODE="$LOCALAPPDATA/Deepseek Harness EAC/dsh-desktop/vendor/node/node.exe"
BIN="$LOCALAPPDATA/Deepseek Harness EAC/dsh-desktop/node_modules/@deepseek-ai/dsh/lib/bin.js"
"$NODE" --use-system-ca "$BIN" plugin --profile web-desktop remove dsh-pet-sayaka
It is worth noting that this uninstall command is copied from the author’s Windows local path in the README; when changing machines, adjust according to your own DSH_HOME and profile name. Every version has a tag and a packaged tgz attached in the Releases page.
Scenarios and Notes¶
Suitable for DSH Web users who need to monitor long tasks for a long time and value runtime feedback, especially in scenarios like solo development where you don’t want logs taking up the whole view. It only reads session states for visual mapping and does not change command execution logic or affect the normal invocation of the plugin itself.
A few points to note:
- After being loaded by the plugin system, it runs with the permissions of the current dsh Web process and can access the sessions and tool events loaded by that profile. Before installing, you should open the source code to verify and confirm there is no extra request behavior or local data exfiltration.
- The license is MIT, author attribution is KOGGUA-EDIT; if you want to replicate the illustrations and audio, you need to confirm the copyright of the materials yourself; the repository only contains compressed images and wav files.
- It targets the Web interface, injecting via frontend bundle, so if you install it on a profile without a Web service, you won’t see anything.
- Both bubbles and voiceovers can interrupt attention; for those who need a quiet environment, it is recommended to turn off “Audio” in the settings page first, or only keep the state face switching.
Conclusion¶
The value of dsh-pet-sayaka is not in adding another feature, but in adding a perceptible visualization layer to the silent session: running commands makes it draw its sword, finishing makes it collapse, errors make it switch to sad, and repeated errors change the lines. For people staring at the Web UI to run tasks, it saves trouble compared to repeatedly checking logs. The directory page is https://www.skillhub.cn/plugins/KOGGUA-EDIT/dsh-pet-sayaka, and the source code is at https://github.com/KOGGUA-EDIT/dsh-pet-sayaka.