Preface¶
DSH’s ask_user_question suffers from two common interaction gaps: option text is often limited to a single sentence, and users who wish to add constraints can only enter them into the custom input box. Furthermore, during the card session, the model does not answer follow-up questions like “what exactly does this option mean,” requiring users to exit the current process and start a new round to verify information. The plugin described below addresses these two issues without altering the original selection protocol.
This is tlewa/dsh-better-choice on the community directory page, maintained by TLEWA. It is classified as a client plugin, has 1 GitHub star (as of 2026-11-06), the latest npm version is 1.0.4, and the license is MIT. In a nutshell, it fills the gap for DSH’s generic question cards by adding a “supplementary input per option” and “inline side-asking model,” while preserving all official behaviors such as left-click selection, skipping, pagination, and countdown.
Plugin Overview¶
Check the scope before installation. It only intercepts generic multiple-choice cards on the DSH client; non-generic question cards such as plan-review or approval still use the official components. The host requires the DSH 0.2.0-rc family (engines.dsh: >=0.2.0-rc.1 <0.3.0-0, client built-in package ^0.2.0-rc.1) and Node.js 20+. The author has verified it on DSH 0.2.2-rc.1.
It consists of two parts:
- Client: Mounted on the browser side, registered to the
conversation.composerchain slot withpriority: -10(official default 0), queried before the official components; - Host: A custom command
bc-askused to run the side-asking sub-agent; - Styles: Derived from the official question card CSS and prefixed with
bc_to avoid polluting other plugins.
When a generic PendingQuestion carrier is not detected, the enhanced card returns null, automatically falling back to the official component.
Core Capabilities¶
Right-click to Add Supplementary Notes to Options¶
Right-click any option to select it (if not already selected) and expand a supplementary input box below that option. The filled content does not replace the option but serves as a note for that option, which is submitted to the model along with the selected option:
{
"answers": [
{
"id": "question-id",
"selected": ["方案 B"],
"custom": "方案 B: 先灰度 5%,观察一小时再全量"
}
]
}
When no notes are filled, the request is identical to the official one, and no additional custom is generated. For both single and multiple choice, supplementary content is saved per option, and switching options does not mix up the drafts. When submitting multiple choices, one note per line:
方案 A: 需要保留旧接口
方案 C: 下个迭代再删
When notes are written for unselected options in multiple choice, the submitted text will be marked as (Unselected), making it easier for the model to distinguish the tone.
Inline Side-asking¶
The bottom of the question card has a “Ask First” input area used to answer user queries based on the current session context, for example, “What is the difference between these two options in production?” or “Which files need to be changed if B is selected?” How side-asking works:
- Uses a fork sub-agent to reuse the current session’s completed context, model, and tool declarations, with
delivery: 'caller'attaching it to the current command invocation without queuing for the parent turn; - Side-asking content is only displayed in the card, not submitted, does not pollute the main dialogue, and does not make a choice on behalf of the user;
- During execution, the sub-agent hooks
tools.guard, rejecting all tool calls, preventing file changes and continuation of the original task; output limit is 32000 tokens (not exceeding the parent session limit).
Interaction details: Placing the cursor in the side-asking box pauses the card showing “Paused,” the countdown stops, and it automatically resumes on blur; after clicking “Ask,” the card enters a waiting state and will not timeout waiting for a response; threads are saved separately by question, so switching questions and returning still shows the original Q&A; during the answer, clicking “Cancel Side-asking” can abort it, with a maximum of 20 rounds retained per thread. Side-asking answers currently appear as complete paragraphs after completion, not as a character-by-character stream.
Installation and Enablement¶
The following commands are from the README. The author recommends installing from npm.
Install from npm (Recommended):
- Open the sidebar plugins page → Install plugin;
- Enter the package name and confirm:
dsh-better-choice
- After installation, hard refresh (
Ctrl+Shift+R); if the host side is not effective, restart the desktop app.
Pin a version:
dsh-better-choice@1.0.1
Command line equivalent:
dsh plugin --profile desktop add dsh-better-choice@1.0.1
The repository’s lib/ is the directly runnable artifact; installing from GitHub does not require local building:
https://github.com/TLEWA/dsh-better-choice
Pin to a tag:
https://github.com/TLEWA/dsh-better-choice#v1.0.3
Or install the Release attachment directly:
https://github.com/TLEWA/dsh-better-choice/releases/latest/download/dsh-better-choice.tgz
Command line equivalent:
dsh plugin --profile desktop add github:TLEWA/dsh-better-choice#v1.0.3
Install from source:
git clone https://github.com/TLEWA/dsh-better-choice.git
cd dsh-better-choice
npm install
npm run build
npm test
dsh plugin --profile desktop add .
Hard refresh the page after installation or upgrade. When the host command bc-ask is not registered, the side-asking box will indicate failure, and restarting the desktop app will resolve it.
Typical Usage¶
- Wait for the model to initiate a generic multiple-choice question;
- To add constraints: Right-click an option, write it, and submit normally;
- To verify information first: Ask in the bottom side-asking box, read the answer, then select;
- Both can be used simultaneously; side-asking content will not enter the final answer.
Right-clicking on a trackpad is typically a two-finger tap; devices without a right-click button can still answer normally with left-click, but the supplementary box cannot be used.
Implementation Highlights¶
Side-asking is completed via this plugin’s own command bc-ask. The client serializes the question, all question cards, written notes, and previous side-asking in this thread, then hands it to the host. The mechanism on the host side:
- Uses
ctx.subagents.startActivation({ provider: 'fork', delivery: 'caller' })to start the fork sub-agent. The seed is the completed turns before the lastturn/endin the parent session; the current unfinished tool-call turn does not enter the seed; - Only appends a single trailing user message (side-asking mode + question card + previous side-asking + current question), without modifying system, tool declarations, or rewriting history;
- The sub-agent inherits the parent session’s provider / model / reasoningEffort, with
maxTokensset tomin(32000, parent.maxTokens); - The parent call’s signal is passed through along with the 30-minute watchdog;
- The sub-agent does not write the Q&A back to the parent session. The parent session only records
command/run,subagent/catalog, andcommand/done, withrecordInput: falseso the question body is not recorded.
Since the fork sub-agent reuses the prefix of the parent session’s completed turns, the provider can hit existing prompt cache. The author tested that both the main request and the subsequent fork sub-request report a non-zero cacheReadTokens, growing with the parent session’s completed turns (the local DeepSeek routing uses automatic prefix caching).
Applicable Scenarios and Notes¶
This plugin is suitable for projects using ask_user_question in production decision-making scenarios: those needing to add constraints per option, or wanting to clarify option meanings within the current session context before answering. It solves an information density problem, not the selection itself.
Several limitations from the README:
- Only intercepts generic multiple-choice questions; cards like plan-review and approval remain with official implementation;
- Side-asking is fixed to the model of the current session and does not provide an entry point to select a separate model or reasoning effort;
- Side-asking is read-only; questions requiring reading files or running commands to answer should be asked directly in the dialogue;
- The fork seed only contains the last completed turn of the parent session; the round currently waiting for an answer does not enter the seed;
- Side-asking answers appear as complete paragraphs after completion, not as a character-by-character stream, and very long answers are constrained by the 32K output limit;
- Devices without a right-click input cannot use the supplementary box, but left-click answering is completely unaffected.
Pay attention to permission boundaries: The plugin runs with the permissions of the current DSH process. Before installing, check the source code and license; this plugin is MIT, and NOTICE.md lists the specific scope of reuse (the question card component structure and style are derived from dsh-question-note, and the side-asking interaction references the design of dsh-btw). If a DSH upgrade changes the internal structure of the question card, the enhanced card will not take over upon recognition failure, and the official question card remains usable; errors will be reported if the side-asking interface changes, but normal answering is not affected.
Directory and Source¶
Directory page: https://www.skillhub.cn/plugins/TLEWA/dsh-better-choice
GitHub: https://github.com/TLEWA/dsh-better-choice
npm: https://www.npmjs.com/package/dsh-better-choice
To summarize: it handles two small things: “option notes” and “inline side-asking.” The entry points are all on the official composer chain; if a generic question card is not detected, it automatically falls back to the official component, making the change to the existing selection flow very small. If you are using DSH’s ask_user_question for decision gathering, you can first install the npm package, hard refresh to test it, and then decide if you need to pin a version.