dsh-pet
PC2005-cloud/dsh-petDSH Web UI 桌面宠物,Windows / macOS / Linux 三端可用:浏览器浮层或透明置顶桌面窗口,106 个透明动画、带挤压与粒子的甩抛反弹物理、随会话事件实时联动的工作状态气泡、碎碎念与带持久记忆的对话、余额展示、表情包配图、多开同屏,并支持直接放入的自定义动画与宠物种类(pet pack)。
English · 中文
Tucked into the DSH tab bar is a tiny auto-chess table: take the blue side yourself and play a match against the AI, or lean back in the audience seat and watch two AIs, each on a model of its own choosing, slug it out on the board. No move here is free: every round's decision is a real model request. Crank the thinking level up to High or Max, open the reasoning log, and watch the AI work through who to buy, who to sell, which traits to chase, and whether that gold belongs in a level-up or a reroll. The result lands on the board; the reasoning stays in the log.
Game state lives in a module-level store in the browser: switching tabs or sessions never resets the match or interrupts an in-flight AI decision.
[row, col] (row 0-3, col 0-6), mirrored into a 4×14 battlefield for combat.DSH's standard plugin mechanism is bundle → profile: the package declares dsh.bundle in package.json and ships a patch file (cordis.patch.yml); use dsh plugin to install it into any profile:
# Install from a local checkout (run inside the plugin directory; build lib/ first)
pnpm run build
dsh plugin --profile web add /Users/yejiming/Desktop/OpenSource/dsh-auto-chess
After installing, verify the config layer, then start (or restart) the Web UI:
dsh --profile web --dump-config # the output should contain the auto-chess layer
dsh web # the 自走棋 tab appears in the session tab bar after the restart
The plugin is installed into the local
webprofile (~/.dsh/profiles/web, with@deepseek-ai/dsh-auto-chessin the bundle list as a link dependency). The Web process must restart to scan new client bundles and inject the client tab.
Remove: dsh plugin --profile web remove @deepseek-ai/dsh-auto-chess removes both the dependency and its layer.
The game itself (state, economy, traits, battle simulation) lives in the browser UI; the server only arbitrates the AI's prep-phase decisions, so illegal replies are rejected server-side and can never corrupt the browser's game. The game engine (src/game/engine.ts) is pure TypeScript, dependency-free and deterministically shared: the server clones the full board state from each AI request, validates and applies the model's action batch with the exact same engine the browser uses, and returns the all-valid action list plus the reasoning text; the browser then applies the accepted actions to its own authoritative state with the same engine. The two sides can never drift.
Every AI decision is a standalone auxiliary request to the selected provider/model route. The system prompt is either the user-edited text or the package default (full rules, a strict JSON-array return format, a correct example, common mistakes, and basic strategy); the single user message carries the side's complete board state (HP, gold, exp/level, board cap, bench JSON, board layout JSON, active traits, shop JSON, last round's battle result, and the known enemy composition: fielded count, star distribution, race/class counts and rough power), plus, on retry, the previous illegal reply and its rejection reason. A decision request can also carry a thinking level (off/high/max): the server forwards it as the request's reasoning effort only when the selected model advertises support; unsupported levels fall back to the model's own default. Optional per-request actionTimeoutMs and maxActionOutputTokens overrides replace the config defaults for that request only. The reply's reasoning block is returned to the browser as the reasoning field alongside the action results.
The model returns a JSON array (at most 4 actions): {"action":"buy","name":"..."}, {"action":"sell","chess_id":N}, {"action":"move","chess_id":N,"pos":[r,c]}, {"action":"upgrade"}, {"action":"refresh"}, {"action":"end_prep"}. The server validates the whole batch (gold, bench cap, board cap, coordinates in range, occupied cells, id existence, etc.); any illegal action rejects the entire batch and retries with corrective feedback (default max 3 attempts); the final failure returns error with lastText/lastReason, and the browser shows the error plus a retry button.
The auxiliary request spends tokens on constructing the state (roughly 1-2 KB of board text + system prompt + maxActionOutputTokens, default 32000). Thinking levels above off add reasoning tokens that count against the same output budget: reasoning models may spend most of the budget thinking, so a truncated reply still parses as long as the JSON array is complete; only lost JSON triggers a retry. The request is fully independent of any agent conversation and is never written to the session log.
Auxiliary requests are standalone model requests; their prompts change with every board position, so there is no stable shared prefix with agent traffic. Editing the system prompt replaces the text wholesale, defeating provider-side cross-game prefix reuse; the default prompt stays stable only while unedited.
All fields have loader defaults; there are no library-level defaults.
| Key | Description |
|---|---|
actionTimeoutMs | End-to-end deadline for one AI decision attempt (default 300000 ms, i.e. 5 minutes); the UI no longer offers an edit entry. |
maxActionOutputTokens | Output-token cap for one AI decision reply. Default 32000 (generous, because reasoning models count thinking against the output budget); truncated replies still parse while the JSON is complete, and only lost JSON triggers a retry. No longer editable in the UI. |
maxActionAttempts | Total AI attempts per decision request; the last attempt carries corrective feedback (default 3). |
pnpm run build # tsdown builds the node half + the browser bundle and emits type declarations
pnpm run typecheck # tsc --noEmit
pnpm test # vitest: engine (economy/merge/battle/settlement), reply parsing, request validation, prompt assembly
node tests/e2e/gui-round.spec.mjs # end-to-end: run one full round against a separate dsh web test instance (--port 3095; the plugin must be installed with a working model configured)
Local dependencies point at the Harness SDK checkout through symlinks (packages/* and vendor/* under ~/.dsh/source/current), the same approach as dsh-gomoku.