Skip to main content

deepseek-harness-desktop/packages/dsh-mode-switcher

156Stars5Forks6Issues0Watchers

Add an agent mode switch dropdown at the top of DSH Web chat sessions. Blank sessions switch in place. Sessions with history open a new session in the same workspace before switching, so the original conversation remains uninterrupted.

Evidence5/5methodologySourceInstallMaintenanceDSH versionSecurity scan
Machine-auditedInstall commandRepo verifieddsh-plugin topicLicenseREADMEAI wiki

ⓘ This plugin is a sub-package of the ningbainb/deepseek-harness-desktop monorepo — stars and activity count the whole repository.

Language
TypeScript
License
BSD-3-Clause
Branch
main
ai-agentai-coding-assistantcodexdeepseekdeepseek-harnessdesktop-appdshdsh-plugin

Install

cmdweb profile
$ dsh plugin --profile web add --allow-build=@linxin666/dsh-client-ui-mode-switcher github:ningbainb/deepseek-harness-desktop#path:packages/dsh-mode-switcher

Run the command above in your terminal to install this plugin via the dsh CLI. You can switch Profile in the top-right corner. New to dsh? Read the beginner tutorial

Install via your agent

Install the DeepSeek Harness plugin ningbainb/deepseek-harness-desktop/packages/dsh-mode-switcher for me: review the repository at https://github.com/ningbainb/deepseek-harness-desktop first, then run the install command and verify the plugin loads successfully.

Paste this instruction to the DSH Web GUI assistant — it will install and verify for you.

One-Line Description

Adds an intelligent agent mode switcher dropdown at the top of DSH Web chat sessions; switching takes effect in-place on blank sessions, while for existing conversations it first creates a new session in the same workspace before applying the new mode, avoiding disruption to the current chat context.

Core Features

  • Top dropdown switch: Injects a capsule-style <select> at the session header, listing all available agent modes provided by the DSH runtime (Plan / Code / etc.). On selection, it calls api.agentPresets.select to replace the current session's mode with the target preset.
  • Automatic filtering of broken presets: Skips presets with broken !== undefined during list loading, only displaying usable modes to avoid selecting half-broken presets.
  • In-place switch for blank sessions: When session.blank === true, directly calls the host switch interface without modifying the session view.
  • Safe switch for sessions with history: When session.blank === false, first clears the client's current session, then calls workspaces.startSession to create a new blank session in the same workspace path, and applies the selected mode to that new session. The original conversation history remains in the host's real session list; the client simply switches to the new session.
  • Smart hiding: When fewer than two runtime-available presets exist, the dropdown is not rendered (modes.length < 2 returns null), avoiding a dead control with only one item in the list.
  • Disable during switching: The dropdown becomes disabled and the cursor changes to wait during switching. If switching fails (new session not received within 10 seconds, or host returns an error), the error message is written to the title tooltip and cleared on the next switch attempt.

Technical Implementation

  • Language: TypeScript (ESM; "type": "module"), host/client dual-half compilation (tsc -b + tsdown), React 18 for browser rendering.
  • Key Dependencies: @deepseek-ai/dsh-client-runtime (injects client services), @deepseek-ai/dsh-client-ui-slots (slot injection target conversation.session.header.actions), @deepseek-ai/dsh-client-ui-conversation (session component context), react ^18.2.0; the host half only declares cordis interfaces without any runtime dependencies.
  • Architecture Pattern: Cordis dual-half plugin, but client-only: src/index.ts is an empty host entry (apply is a no-op), all functionality is concentrated in src/client/; apply(ctx) obtains the RPC handle from ctx.get('connection').api.agentPresets, gets session/workspace snapshots from ctx.sessions / ctx.workspaces, then mounts the ModeSwitcher component to the conversation.session.header.actions slot (order = -9, packages/dsh-mode-switcher/src/client/index.ts:10-26); activation goes through cordis.patch.yml to inject the ui-mode-switcher row into the web profile.
  • Entry Files: packages/dsh-mode-switcher/src/client/index.ts (browser half entry) + packages/dsh-mode-switcher/src/client/mode-controller.ts (core switching logic) + packages/dsh-mode-switcher/src/client/ModeSwitcher.tsx (React view).

Use Cases

You frequently need to switch between different working modes like Plan / Code / etc. within the same session, but don't want to manually edit configuration files or close the current conversation and start a new one; the plugin will proactively open a new blank session with your selected mode in an already half-way conversation, leaving the old conversation untouched on the host side. Also suitable for users who only want to use the few presets exposed by the DSH official runtime and think "not being able to switch modes in sessions" is a missing feature.

Prerequisites & Compatibility

DependencyMinimum VersionDescription
DeepSeek Harness (web profile)^0.1.0-rc.7peerDependencies all locked to this version (packages/dsh-mode-switcher/package.json:34-40); cordis.patch.yml:1-3 injects ui-mode-switcher row into web profile registry
Node.js^22.19.0 || >=24.0.0No separate engines declared in package; consistent with root package.json#engines across the entire repository
PlatformCross-platform (macOS / Windows / Linux)Web GUI injection only (platform: "web", packages/dsh-mode-switcher/package.json:24), no node-gyp / native bindings
React^18.2.0peer dependency (packages/dsh-mode-switcher/package.json:41)

Installation

dsh plugin --profile web add github:ningbainb/deepseek-harness-desktop/packages/dsh-mode-switcher

After installation, restart dsh web, open any session, and you will see a capsule-style mode switch dropdown at the top of the chat area.

Configuration Options

This plugin requires no additional configuration. At runtime it does not read ctx.config, expose cordis Schema, or read environment variables; adjustable parameters (timeoutMs, controlling the timeout for waiting for new sessions) are only passed through the ModeSwitcherController constructor, not through plugin configuration.

ConfigTypeDescriptionDefault
(No user-level config items)—All adjustable parameters in the source code are injected during development construction, not exposed through the plugin config panel at runtime—

FAQ

Q: What can be seen after installation?

A: At the top of any session opened in dsh web, a capsule-style dropdown appears, listing all available agent modes exposed by the current DSH runtime (such as Plan / Code / etc.). Selecting one will immediately switch the current session's working mode. When fewer than two runtime-available presets exist, this dropdown automatically hides to avoid meaningless controls (packages/dsh-mode-switcher/src/client/ModeSwitcher.tsx:26, README.md:14).

Q: Will switching modes clear the current conversation history?

A: It depends. For blank sessions (no messages yet), it switches in-place on the original session. As long as the current session already has messages, the plugin first clears the client's session view, then calls the workspace service to create a brand new blank session under the same path, and applies the selected mode to the new session (packages/dsh-mode-switcher/src/client/mode-controller.ts:53-70, tests/mode-controller.spec.ts:41-49). Historical data remains in the host process's real session list and won't be deleted—the current chat view just switches to the new session.

Q: Which modes will be listed?

A: The list comes from the DSH official runtime (packages/dsh-mode-switcher/src/client/mode-controller.ts:39-51 calls api.agentPresets.list). Any preset with a broken field is filtered out; if a preset has no name, it falls back to using its id as the display text (packages/dsh-mode-switcher/src/client/mode-controller.ts:44-50).

Q: How are switching failures reported?

A: Errors don't block the UI but are displayed in the dropdown's tooltip (title attribute); the message is cleared on the next switch attempt (packages/dsh-mode-switcher/src/client/ModeSwitcher.tsx:30-40). Meanwhile, the dropdown is disabled during switching and the cursor changes to wait to prevent repeated clicks.

Q: What if waiting for a new session times out?

A: The controller has an internal default 10-second timeout (timeoutMs default value, packages/dsh-mode-switcher/src/client/mode-controller.ts:73). After timeout, it throws "timed out while starting the new mode session" and the same error handling logic writes it to the tooltip; users can retry or refresh the page.

Q: Does it conflict with official DSH mode management?

A: No conflict. This plugin is a pure browser-side slot injector that attaches the "mode switch" action to the conversation.session.header.actions slot (packages/dsh-mode-switcher/src/client/index.ts:20-25), without modifying the official session data model or runtime. After uninstallation, the dropdown will no longer appear on the next dsh web launch.

Q: Can this plugin only be used on DSH Web? What about Headless / CLI mode?

A: Yes, DSH Web GUI only (profile=web). package.json#dsh.client.platform declares web, and cordis.patch.yml inserts the plugin row into the web profile registry. The host half is an empty no-op (packages/dsh-mode-switcher/src/index.ts:5-6), and all behavior is in the browser half, so this dropdown won't be injected in CLI/headless mode.

Getting Started Difficulty

Beginner — one installation command, restart dsh web and it takes effect; no configuration needed; users only need to select a mode from the dropdown at the session header. All behaviors like "in-place switch vs. new session," "filter broken presets," "10-second timeout" are built into the plugin; no editor involvement required.

Known Issues & Limitations

  • Errors can only be passively viewed: Runtime errors are exposed via the dropdown's title tooltip—no toast or log entry (packages/dsh-mode-switcher/src/client/ModeSwitcher.tsx:30-40). If failures are frequent and tooltip content is hard to see, you need to open DevTools to see the raw error text.
  • Web profile only: package.json#dsh.client.platform locks to web; in headless / CLI mode, the entire client injection (apply) won't be called, and the host half is a no-op (packages/dsh-mode-switcher/src/index.ts:5-6), so this dropdown won't be visible in desktop non-Web entries.
  • Switching timeout hardcoded to 10 seconds: mode-controller.ts:73's timeoutMs ?? 10_000 cannot be configured by users on the DSH side; if your workspace has very slow initialization (extremely cold cache), you may need to refresh and retry.
  • New session ID parsing depends on state.byId[id].blank === true check (packages/dsh-mode-switcher/src/client/mode-controller.ts:87). If the host-side session state doesn't have the correct blank flag, waiting will time out and fail.
  • Dropdown only displays when DSH runtime preset count ≥ 2: If the runtime exposes only one or zero available presets, the dropdown is completely hidden—no UI indication of "no presets available" (packages/dsh-mode-switcher/src/client/ModeSwitcher.tsx:26).
  • Preset display text fallback: When presets lack a name field, they fall back to displaying the id, which may not be user-friendly (packages/dsh-mode-switcher/src/client/mode-controller.ts:48).
  • Does not enter model visible surface: This plugin is pure UI behavior—switching doesn't write to systemPrompt or appear in the agent's context. If you want the agent to know which mode is currently in use, a separate extension is needed.

Read the usage guide →

Install steps, key points, FAQ and compatibility for this plugin — auto-derived from indexed fields.

Listing badge

Listed on deepseek-plugin.org
[![Listed on deepseek-plugin.org](https://img.shields.io/badge/listed_on-deepseek--plugin.org-007EC6)](https://deepseek-plugin.org/plugins/ningbainb/deepseek-harness-desktop/packages/dsh-mode-switcher)

Paste this markdown into your GitHub README to link back to this listing. The badge only states the listing — not a security endorsement.

← Back to plugin directory