Introduction

The philosophy of DSH is “Everything is a plugin,” and many capabilities on the WebUI are injected by plugins. When developing agents, you often encounter a need: to let several models discuss around the same context in turns—one proposing a solution, one critiquing, one summarizing. Without specialized tools, you usually have to manually shuttle context between multiple sessions, and you have to monitor the speaking order yourself.

The dsh-group-chat introduced below turns this into a group chat form: You act as the “Group Owner” in the DSH WebUI, managing a group of configurable AI roles, letting them speak in turns around a shared context. The plugin is maintained by Qx002, current version 0.1.0.

What is this

dsh-group-chat is a DSH native multi-AI group chat plugin with three core settings:

  1. The user is the “Group Owner” and AI roles are group members; they can configure role cards, models, speaking modes, and can mute members at any time;
  2. The group chat is a separate page, completely isolated from native workspace conversations—the plugin does not take over the native input box (it does not register agent/pre-step interceptors); the input box, model selection, and read/write permissions in the native conversation area continue to serve the original workflow;
  3. Pure Node.js / Cordis implementation, without using Tauri / Rust.

Core Features

Independent Group Chat Page

The plugin injects two entry points via WebUI slots:

  • conversation.input.left: The group chat switch at the left end of the input card toolbar; clicking it opens or closes the independent group chat page; the state is persisted to enabledSessions, and the global switch is automatically linked;
  • settings.section (id group-chat): The “Group Chat Settings” page in the settings panel.

The group chat page covers about 2/3 of the native conversation area and is centered. The top-right ✕ closes it, and the top-left ⚙ opens settings. The chat view has a WeChat-style layout: AI member messages on the left, user on the right. The independent input box supports Enter to send, Shift+Enter for new lines, and can send images (PNG/JPEG/WebP/GIF, which are persisted via the DSH attachment service, enter the model request as an image block, and display within the bubble). The message view is polled while the page is open.

AI Role Management

First, add members on the settings page, then configure them one by one. Each AI role can be configured with:

  • Role card System Prompt and initial context;
  • Provider / Model, selected via the ModelPicker cascading selector: clicking it first lists DSH-connected providers (ctx.llm.listProviders()), then lists the models advertised by that provider (listModels(provider)); the data is completely consistent with the DSH model catalog; manual input of provider/model is also possible if no catalog is available;
  • Speaking mode (Passive Reply / Active Speaking) and active speaking strategy;
  • @ alias and trigger words;
  • Mute/Enable permissions, and the member list supports quick muting.

Speaker Selection and Group Owner Rules

Who speaks in each round is determined by a fixed priority:

mentioned (@name/alias)  triggered (trigger words)  active (active speaking members)  default (fallback)

The candidate pool first filters out muted or removed members; the number of speakers per turn is truncated by maxAgentsPerTurn; when muteAll is enabled, no replies are generated, but user messages are still saved to disk; if no one triggers, the first available member acts as the fallback.

Group Owner rules are centralized on the settings page: mute all, global active speaking switch, maximum replies per turn, maximum speakers per turn, parallel generation, timeout, and @ syntax.

Shared Context

All speakers see the same transcript. The plugin projects the unified Session Log into lines of “[AI Name]: “, using the “User Name Display” from settings (default “Group Owner”) for user lines, and truncates by the scroll window maxMessages; the transcript template is configurable, and there is a separate switch for role card injection. In sequential mode, later speakers can see the latest reply of the speaker before them in the current round—transcripts are re-derived at every step.

Active Speaking

Passive members wait for @ or trigger words, while members in active mode speak on their own. Each active member sets a one-time timer with a random interval within [minIntervalMs, maxIntervalMs]. Before triggering, it checks a set of conditions: group chat is enabled, global active speaking switch is on, not muted globally, the member is not muted, there are no ongoing turns in the session, and the interval since the last activity is met. If conditions are temporarily unmet, it retries after 30 seconds. Configuration changes immediately reset all active timers, and strategy changes take effect immediately.

Turn Events and Stream Output

The event sequence of a group chat turn is isomorphic to the official agent-loop:

turn/start → user/message → each speaker: step/start → assistant/chunk* → assistant/message → step/end → turn/end

To avoid conflict with native turn numbering, group chat turn numbers use an offset space starting from GROUP_TURN_BASE = 1_000_000; logging is scanned to continue numbering when restoring a session. Regarding streaming, each chunk is first written to disk as assistant/chunk, assembled by the official BlockAssembler, and then written as assistant/message. The message carries source: {provider, model} trace information and usage.

The failure semantics are relatively restrained: a single speaker failure only records itself and does not affect others from continuing to speak; only when all fail does it end with turn/end(error); cancellation midway is marked as aborted.

Configuration Persistence

Configuration is stored in the group-chat user settings namespace: the plugin registers the same schema via installSettingsSection; the resolution priority is schema default values → entry base → ~/.dsh/settings.yaml user layer. If the settings service is not available in the environment, a GroupChatError (code NO_SETTINGS) is thrown for the write path, and reading falls back to entry configuration. Every configuration submission broadcasts a group-chat/config-updated event, and the orchestrator resets the active speaking timers based on this.

Installation and Build

The official installation command is not provided in the reviewed materials (README, package.json), so we will not splice one together here. Please refer to the repository README for installation methods (the repository homepage field in the README is currently a TODO placeholder, please refer to the GitHub repository page):

https://github.com/Qx002/dsh-group-chat

When building from source, the plugin’s declared peer dependencies are:

@deepseek-ai/cordis          ^4.0.1
@deepseek-ai/dsh-attachment  ^0.1.0-rc.6
@deepseek-ai/dsh-llm         ^0.1.0-rc.6
@deepseek-ai/dsh-session     ^0.1.0-rc.6
@deepseek-ai/dsh-settings    ^0.1.0-rc.6
@deepseek-ai/schemastery     ^3.18.1
react                        ^18.2.0

The build command is npm run build, equivalent to tsc compiling the host-side lib, plus tsdown to bundle the browser-side client.js.

Typical Usage

Starting from the UI, the flow is roughly:

  1. Click the group chat switch next to the input box to open the independent group chat page;
  2. Click ⚙ in the top-left to enter group chat settings, add AI members, and configure role cards, models, and speaking modes;
  3. Return to the chat page to input messages, @ a specific member, or wait for active speaking members to speak on their own;
  4. To stop, click the top-right ✕ to close the page (the switch syncs back to “off,” and active speaking timers stop), or call cancelSession in code.

If you are used to writing code, you can also use the Service API directly:

// Persistently enable group chat for a session
await ctx.groupChat.enableSession(sessionId);

// Add an AI role
const agent = await ctx.groupChat.addAgent(input);

// Manage member state
await ctx.groupChat.setMuted(agent.id, true);
await ctx.groupChat.setMode(agent.id, "active");

// Group Owner control
await ctx.groupChat.setMuteAll(true);
await ctx.groupChat.setActiveSpeakEnabled(false);

// Submit a user message and run a round of group chat (images can be attached)
// Requires group chat to be enabled and the session to be in enabledSessions
await ctx.groupChat.submitMessage(sessionId, text, images);

// Abort an ongoing group chat turn
await ctx.groupChat.cancelSession(sessionId);

The complete interface also includes getConfig / getAgent / listAgents / getStatus / watch, updateAgent / removeAgent / setEnabled, updateHostRules / updateSharedContext, setGroupEnabled / setGroupName, isSessionEnabled / listEnabledSessions, getEngine / listModelCatalog.

Developer Interface

Besides the UI, the plugin provides three types of access points for other plugins or scripts:

  • WebUI API routes /api/group-chat/*: state, config, models, messages, attachment, toggle, submit, cancel, agents, host. Includes same-origin POST protection, errors are uniformly {ok:false, code, message}.
  • Cordis events: group-chat/config-updated, agent-added/updated/removed, turn-start, agent-speaking, agent-spoken, turn-end, orchestrator-attached/detached, which can be subscribed to as needed.
  • Client bundle purity gate: The client only allows referencing platform modules (react, cordis, ui-slots, etc.) and the inline security layer; any other @deepseek-ai value imports will be rejected during the build phase. To collaborate with it, you must use the Cordis service instead of directly importing.

Applicable Scenarios and Notes

Who is it for:

  • DSH users who want multiple models to discuss, evaluate, and brainstorm around the same context;
  • People who want to compare the performance of different models under the same role settings—each member is configured with an independent Provider/Model;
  • Plugin developers: The turn events are isomorphic to the official agent-loop, allowing secondary development based on Cordis events or ctx.groupChat.

Points to note:

  1. The plugin runs with the current DSH process permissions; it is recommended to read the source code before installing;
  2. The files in package.json includes the LICENSE file, but the materials do not specify the specific license type; please confirm on the repository before use;
  3. The group chat is completely isolated from native workspace conversations; group chat content will not mix into workspace conversations;
  4. The version is 0.1.0; the README indicates that the infrastructure, orchestrator engine, and WebUI three stages are all completed, but the overall project is still in the early stages.

Conclusion

dsh-group-chat puts multi-model collaboration into the DSH native interface: the Group Owner controls the scene, members speak in turns according to rules, and they share a context, while also providing developers with a complete Service API and event subscription. If you have a need for multiple AI roles collaborating in DSH, you can try it out following the steps above.

  • Plugin Directory Page: https://www.skillhub.cn/plugins/Qx002/dsh-group-chat
  • GitHub Repository: https://github.com/Qx002/dsh-group-chat