dsh-expert-ai
No description
- Stars
- 0
- Language
- TypeScript
- Created
- Aug 19, 2026
- Updated
- Oct 20, 2026
Introduction
dsh-expert-ai
English | 中文
dsh-expert-ai keeps a library of expert identities (persona, avatar, source disclosure) for DeepSeek Harness and serves it to other plugins through the expertIdentity Cordis service. It is the identity layer meant to run together with the dsh-bot runtime, and it adds exactly one other thing: a conversation with a single expert.
Features
The plugin does two things:
- Identity layer: persists records in the
expert-aisettings namespace and each identity in$DSH_HOME/expert-ai/<id>/agents/<id>.md; provides theexpertIdentityCordis service so another plugin, such as a Bot runtime, can read the enabled identities: persona, avatar, source disclosure and revision. - Single-expert conversation: pick an expert in the sidebar Chat Panel, or type
@in the composer and pick one, to open a conversation bound to that expert's persona. It has no Workspace, is forced to the read-only file sandbox, and gets its opening message from the plugin. - Expert mention and consultation:
@<id>in the composer still saves the mention as model-visible text, and the primary agent can ask one expert through theconsult_experttool, whose answer comes back through a persona subagent.
It also adds a Harness-styled settings section for creating, editing, enabling, and deleting records, including imports from agent Markdown files (YAML frontmatter is ignored, the body is the persona).
It does not add an Agent preset selector, online expert-package import, or group chats (the dsh-bot runtime owns those).
Working with dsh-bot
This plugin only supplies identities; the dsh-bot runtime runs the single and group chats. Install both into the same Profile.
dsh-botasks for theexpertIdentityservice withctx.inject(['expertIdentity'], …). Without this plugin it behaves like a plain ds-bot, and this plugin needs nothing fromdsh-bot.- Identities are created and edited only here, under Settings → 专家.
dsh-botis designed to take a bound Bot's persona and source disclosure from the service and to followexpert-identity/changed. - This plugin registers no session tools and binds no persona to Harness's own Sessions, so a Bot Session carries one identity.
- A linked checkout is served from
lib/, which is not committed: runpnpm run buildafter changing the Host half.
The split of responsibilities and the service contract are in docs/expert-bot-phase1.md.
Demo
| Chat Panel | Settings | Create expert |
|---|---|---|
![]() | ![]() | ![]() |
Record fields
Each record has an id, name, description, primary-domain category, composable tags[], agent, persona, and enabled flag. agent is the only runtime identity source. When no Agent file is supplied, saving a record writes persona to the managed <id>/agents/<id>.md file and stores that relative path in agent; when an Agent file is supplied, its Markdown body is authoritative and persona is ignored. Relative agent paths are read from $DSH_HOME/expert-ai/ first and then from the plugin package, so bundled experts/ files work in a fresh Profile; a same-named file under $DSH_HOME/expert-ai/ overrides the bundled copy. New records using the custom category should set customCategory; older records without it fall back to the display name. The Host validates the settings document; leftover features, teams, and maxBatchSize from older settings are ignored. toolFilter and model are optional: they pick the tools and the model a consultation runs on.
Presentation fields are optional, so records saved before they existed stay valid:
title(at most 40 characters after trimming) is shown after the name and defaults to “思考助手”.avataris{ mime, data }with animage/png,image/jpegorimage/webpmime and base64 data; the whole data URL must fit in 160,000 characters. The editor crops a picked image to a centered 160 px square and re-encodes it.sourceis{ kind, note? }withkindone ofpublic,organizationorauthorized;noteholds at most 200 characters. A record withoutsourcecounts aspublic, and the kind selects the disclosure the identity carries.
expertIdentity service
Another plugin reads identities with ctx.inject(['expertIdentity'], ctx => …):
list()returns the enabled identities whose persona can be read.get(id)returns one with itspersonaanddisclosure, orundefinedfor an unknown, disabled or unreadable id.revisionis the sha256 of the persona. A change of title, avatar or source does not alter it; it arrives through the changed event and a freshget.disclosureis a Chinese paragraph chosen bysource.kind, for the consumer to put into its prompt as is.expert-identity/changedcarries{ ids, withdrawn? }.idsare the sorted ids that appeared, disappeared or changed.withdrawn(sorted, absent when empty) lists those whose record the user disabled or deleted, andidsstill contains them; an identity whose persona merely cannot be read is not withdrawn. Listeners are not awaited, and nothing is emitted at startup.- The types
ExpertIdentity,ExpertIdentitySummary,ExpertIdentityServiceandExpertIdentityChangeare exported.
Install from GitHub
dsh-expert-ai is installed into a DeepSeek Harness Web Profile. The commands below are run from the Harness checkout, not from the plugin repository.
Prerequisites
- A working DeepSeek Harness checkout
- Node.js and pnpm versions supported by that Harness checkout
- A GitHub URL for this repository
Install
cd /path/to/deepseek-harness
pnpm dsh plugin --profile web add https://github.com/elonnzhang/dsh-expert-ai.git
The command installs the plugin into $DSH_HOME/profiles/web, adds its bundle to the Web Profile, and applies its Host and Client halves on the next boot.
Start the Web Profile:
pnpm dsh web --port 3080
Open http://127.0.0.1:3080, then go to Settings → 专家.
GitHub installs run the package's
preparescript and buildlib/from source. For a reproducible release, run the checks locally before pushing:cd /path/to/dsh-expert-ai pnpm install pnpm run check git add .gitignore .npmrc src scripts docs package.json pnpm-lock.yaml tsconfig.json tsconfig.types.json tsdown.config.ts tsdown.client.ts cordis.patch.yml README.md README.zh.md git commit -m "build: update plugin contract" git push
With pnpm 10+, a GitHub install may require an explicit
allowBuildsentry in the target Profile; see docs/publish.md.
Update or uninstall
From the Harness checkout:
# Update the installed GitHub dependency
pnpm dsh plugin --profile web update dsh-expert-ai
# Remove it from the Web Profile
pnpm dsh plugin --profile web remove dsh-expert-ai
Restart pnpm dsh web after installing, updating, or removing the plugin.
Upgrading from a release that offered run modes
The features run-mode switch is gone: the identity layer, the Chat Panel and the @ expert
source are always on, and the expert-ai-mode Agent preset, online expert-package import
(expert/catalog, expert/import) and the category/review/team features before them have been
removed. No data migration is needed. Stop the Profile and drop the fields that are no longer read
from the plugin's patch row:
- id: expert-ai
name: dsh-expert-ai
config:
stateDir: … # keep
provider: spawn # keep: the subagent provider for consult_expert
records: […] # keep
# no longer read; safe to delete
features: [identity, conversation]
teams: […]
maxBatchSize: 3
The data directory is still $DSH_HOME/expert-ai. Its .expert-packages/ directory holds packages
imported online by an older release; projects/ and sessions/ keep working. History you no longer
need can be deleted:
rm -rf "${DSH_HOME:-$HOME/.dsh}/expert-ai/.expert-packages"
rm -rf "${DSH_HOME:-$HOME/.dsh}/expert-ai/.expert-reviews"
Local development
Link the checkout into the profile once, then iterate against the running server:
cd /path/to/dsh-expert-ai
pnpm install
pnpm run check
cd /path/to/deepseek-harness
pnpm dsh plugin --profile web add /path/to/dsh-expert-ai
pnpm dsh web --port 3080
Build
pnpm run build runs tsdown over both halves and then refreshes the declaration compatibility tree:
| Artifact | Entry | Consumer |
|---|---|---|
lib/index.js | src/index.ts | the Host, applied by cordis |
lib/index.d.ts | Host declarations | TypeScript consumers |
lib/invariant.js | src/invariant.ts | exports["./invariant"] |
lib/client.js | src/client/index.ts | the browser loader, which requests the dsh-expert-ai/client.js bundle through the versioned combo URL in the boot manifest |
lib/types/client/index.d.ts | Client declarations | TypeScript consumers of ./client |
lib/index.d.ts and lib/invariant.d.ts are generated by tsdown. build:types additionally emits
the per-file lib/types/** declarations required by the dual-face Client export. The Client runtime
entry itself remains a loader-registration artifact rather than a normal importable browser library.
The client artifact is not an ordinary browser bundle. The web shell's module loader requires it to
register itself by calling window.__ModuleLoader__.load({ id, factory }); one that loads without
registering fails plugin boot with bundle … loaded without registering "dsh-expert-ai".
tsdown.client.ts produces that wrapper (CJS output inside a factory banner and footer), keeps the
shell's module-table specifiers external so they survive as require() calls the loader can answer,
and compiles every stylesheet into a style-injection module with hashed class names. Replacing it with
a plain browser-bundle config breaks plugin boot rather than just the styling.
Hot reload
A running dsh web stat-polls every client bundle it serves, so rewriting lib/client.js is the entire trigger — no server restart and no page refresh:
cd /path/to/dsh-expert-ai
pnpm run dev
On a content change the Host broadcasts a rebuilt frame over its GET /plugins/events channel and the browser half swaps the cordis fiber in place: it drops the stale factory, refetches the bundle, drains the old fiber's disposers, removes the <style data-plugin="dsh-expert-ai"> tags, and re-applies. Component state inside the swapped subtree is lost; the rest of the page keeps running.
Two kinds of change stay outside that chain and need dsh web restarted: the Host half, because node-side plugin reloading is not mounted in the Web Profile, and cordis.patch.yml, because composition is read at boot.
Do not reach for the Harness's own pnpm run dev:web here. It is the watch build for packages inside the Harness checkout, it must not run concurrently with pnpm run build there, and it rebuilds nothing for an out-of-tree package.
For the package contract, local overlays, and distribution choices, see
docs/build.md, docs/load-into-dsh.md, and
docs/publish.md.
Usage
1. Configure experts
Open Settings → 专家 after the Web Profile starts. Add or edit a record with:
The plugin UI follows the Harness locale and provides complete English and Simplified Chinese dictionaries. Switching the application language updates Settings and the Chat Panel without translating user-authored names, descriptions, or Persona content.
- ID: lowercase letters, numbers, and hyphens, for example
zjh - Name: the display name, for example
张剑辉 - Description: a short responsibility summary
- Category:
business,science,culture, orcustom - Custom category: recommended when
Categoryiscustom - Tags: searchable capabilities such as
储能系统,工程化 - Persona: the initial identity and response rules; converted to a managed Agent file when Agent is empty
- Enabled: only enabled records reach the
expertIdentityservice and the Chat Panel
You can also import an Agent Markdown file. Its YAML frontmatter is ignored and its Markdown body is the identity. A file selected through the browser is imported into the managed file because the browser does not expose a path that the Host can reopen. When no external path is entered, the Persona is written to:
$DSH_HOME/expert-ai/<id>/agents/<id>.md
An external Agent file remains the sole source of identity and is not copied or overwritten by the plugin.
The settings document is the Profile's Cordis patch, not $DSH_HOME/settings.yaml:
$DSH_HOME/profiles/<profile>/cordis.patch.yml
Saving on the settings page rewrites the expert-ai row of that file.
2. Chat with an expert
Type @ in the composer and pick an expert, or open Chat Panel in the sidebar and choose one; either way the plugin starts a new conversation with that expert. The plugin creates an isolated project under $DSH_HOME/expert-ai/projects/<datetime>, then creates a Session and binds the expert's persona on the Host:
- The Session receives a record-specific system prompt through Host binding; the opening message is written by the plugin and does not repeat the full persona.
- The Session is forced to the read-only file sandbox: files can be read, not changed.
- The binding is saved under
$DSH_HOME/expert-ai/sessions/, so reopening the Session after a Host restart keeps its persona.
3. Consult one expert from a conversation
With @<id> in the composer, the mention stays model-visible text and the primary agent decides whether a consultation helps. consult_expert(id, question) starts a persona subagent for that expert and returns its answer; the subagent provider is the 子代理 Provider setting (default spawn). The expert answers once, without follow-up questions.
4. Update the plugin
After publishing a new GitHub revision, build the plugin before pushing. Then update it from the Harness checkout:
pnpm dsh plugin --profile web update dsh-expert-ai
pnpm dsh web --port 3080
If the profile still uses an old linked installation, remove and add it again:
pnpm dsh plugin --profile web remove dsh-expert-ai
pnpm dsh plugin --profile web add https://github.com/elonnzhang/dsh-expert-ai.git
Model Experience
An expert conversation receives a record-specific system prompt and is set to the read-only file sandbox. The role instruction is carried by the system prompt and remains durable and model-visible in that Session.
consult_expert adds its schema to the primary agent's model request. A consultation starts one subagent, installs the expert's persona as the subagent persona, and returns the answer text.
Known Limitations
- Expert conversations start in a new Session each time, either from the
@menu or from the Chat Panel; the current Session keeps only the@<id>mention text. - The Chat Panel lives in the sidebar footer action Slot: the current public sidebar has no additive Slot above the workspace browser.
- Expert conversations use the deployment's default Agent preset; the plugin no longer installs one of its own.


