dsh-model-palette
Global provider-aware model command palette for DeepSeek Harness Web
Alt+M · Fuzzy search · Provider filter · Model config · OpenRouter media
dsh-model-palette is a plugin for DeepSeek Harness that replaces the native model selector with a powerful, global command palette. Press Alt+M from anywhere in the Web UI — or click the composer trigger — and instantly search, filter, favorite, and switch models across all your providers.
Project site: jensen-yao.github.io/dsh-model-palette
Current release: v0.5.4
✨ Features
🎯 Global Command Palette
|
🏷️ Provider Filter Rail
|
⭐ Favorites & Recents
|
🧠 Reasoning Effort Selector
|
⚙️ Provider & Model ConfigurationAdd, edit, or remove provider profiles directly from the UI:
|
📦 Model Presets
|
🖼️ OpenRouter Media Tools (Optional)
|
🔒 Safety & Privacy
|
Skin Center v2 compatibility
The package remains a standard DSH client plugin. Skin Center v2 owns skin.json, skin.css, patches.css, and hooks.mjs; dsh-model-palette does not pretend to be a skin and does not add a second skin manifest. When a v2 skin is active, the palette stays usable through the native slot, document-level portal, and keyboard shortcut.
The client exposes data-dsh-plugin="dsh-model-palette" on its launcher and dialog roots so v2 skins can target the plugin without generated class names. The normal DSH client loader discovers and mounts the bundle through dsh.client; the v2 bridge is installed at plugin activation and remains usable even when the composer mounts later. A v2 skin can open the model, media, or config view through this stable browser event:
window.dispatchEvent(new CustomEvent('dsh-model-palette:open', { detail: { view: 'media' } }))
view accepts models, media, or config; omitted or unknown values open the model view. Hooks that need direct view switching can also use the page bridge:
window.__DSH_MODEL_PALETTE__?.open('config')
If a skin can activate before this plugin, use the dsh-model-palette:ready handshake instead of making one optional-chaining call:
function openModelPaletteWhenReady(view = 'models') {
const retry = () => window.__DSH_MODEL_PALETTE__?.open(view)
window.addEventListener('dsh-model-palette:ready', retry, { once: true })
if (retry() === true) window.removeEventListener('dsh-model-palette:ready', retry)
}
openModelPaletteWhenReady('media')
The ready event fires after the plugin component mounts; when the bridge exists but the component does not, open() queues the request. The event and page bridge stay local to the current browser page and carry no credentials or conversation content. The launcher deliberately avoids a class name containing seat, because workbook skins may hide native composer seat carriers with [class*="seat"]. skinManifestVersion: 2 remains a skin.json concern; this project remains a normal DSH dsh.client plugin and does not pretend to be a skin.
🚀 Quick Start
Install
dsh plugin --profile web add github:Jensen-Yao/dsh-model-palette#v0.5.4
Restart dsh web, then press Alt+M or click the model trigger in the composer area.
Enable OpenRouter Media Tools (Optional)
Add a profile patch to enable the optional image/video generation tools:
# cordis.patch.yml or your profile patch file
- id: dsh-model-palette
config:
openrouterMedia:
enabled: true
credentialRef: OPENROUTER_API_KEY
outputDir: 'D:\AI\openrouter\outputs'
allowPaidImages: false
allowPaidVideos: false
preferredImageModels: []
preferredVideoModels: []
This registers five agent tools:
| Tool | Description |
|---|---|
openrouter_media_models |
Browse live OpenRouter image/video models and pricing |
openrouter_generate_image |
Generate images via OpenRouter |
openrouter_generate_video |
Submit asynchronous video generation |
openrouter_video_status |
Poll a video job's status |
openrouter_download_video |
Download a completed video to the configured output directory |
🎮 Using the Palette
Basic Usage
| Action | How |
|---|---|
| Open palette | Press Alt+M or click the ⌘ model trigger |
| Close palette | Press Esc or click outside the dialog |
| Search | Type into the search field — matches model name, model ID, provider name, provider ID, and description |
| Navigate | ↑ / ↓ arrow keys |
| Select | Enter on the highlighted row |
| Filter by provider | Click a provider in the left rail |
| Show favorites only | Click Favorites only in the left rail |
| Show recent models | Click Recent models in the left rail |
| Toggle favorite | Click the ★ star on any model row |
| Switch reasoning effort | Use the dropdown in the footer (visible when the active model supports it) |
Configuration Panel
Press Alt+M and select Model config in the left rail to:
- Select or create a provider — choose from the dropdown or click "Add provider"
- Duplicate a provider when useful — start from a working route without reusing its credential reference
- Configure the endpoint — set base URL, protocol, and credential reference
- Manage API keys — enter a new key or load the stored one (loopback only)
- Test the connection — click "Check connection" to discover models
- Validate the API key — prefer an authenticated
/modelsrequest and fall back to a minimal request with the selected model when necessary - Test the live protocol — send one minimal request to
/chat/completionsand/responsesand show which actually works - Configure models — filter long lists, copy parameters, and set context window, max output, and input types
- Apply presets — auto-fill from the registry or select manually
- Repair known dialect compatibility — use Repair and apply when a DeepSeek-compatible route lacks historical
reasoning_contentreplay fields; normal model selection also runs the preflight automatically - Save safely — duplicate IDs are rejected, and unsaved edits are clearly marked before switching or reloading
- Delete a provider — remove its settings profile after confirmation; its credential is intentionally kept
API key validation reports whether the credential is usable, invalid, blocked by a provider or gateway, unavailable because of quota/rate limits, or inconclusive because the endpoint/model does not support the check. The key stays on the plugin backend. If /models is unavailable, the fallback model request may incur a small charge.
Live protocol probing sends real minimal API requests and may incur a small charge. The plugin never changes protocol based solely on reasoning capability.
Media Tools Panel
Press Alt+M and select Media tools in the left rail:
- The panel loads the live OpenRouter image/video catalog
- Models reported as free run without restrictions
- Models not reported as free require a one-time charge acknowledgement for each request
- Image generation runs synchronously and saves to the output directory
- Video generation submits an async job — check status and download when complete
🛠️ Development
# Clone the repository
git clone https://github.com/Jensen-Yao/dsh-model-palette.git
cd dsh-model-palette
# Install dependencies
pnpm install
# Run type check, tests, and build
pnpm check
# Build only
pnpm build
# Run tests
pnpm test
Prebuilt lib/ files are committed to the repository so GitHub-based installs do not need build scripts.
Project Structure
dsh-model-palette/
├── src/
│ ├── client/ # Frontend React components
│ │ ├── index.tsx # Client entry point & slot registration
│ │ ├── ModelPalette.tsx # Main palette component
│ │ ├── ConfigPanel.tsx # Provider & model config UI
│ │ ├── MediaPanel.tsx # OpenRouter media tools UI
│ │ ├── model.ts # Search, ranking, favorites logic
│ │ ├── model-config.ts # Configuration data utilities
│ │ ├── selection-compatibility.ts # DeepSeek compatibility preflight before selection
│ │ ├── model-presets.ts # Preset registry management
│ │ ├── config-api.ts # Config API client
│ │ ├── media-api.ts # Media API client
│ │ ├── skin-v2.ts # Skin Center v2 page bridge
│ │ ├── locales.ts # i18n (en & zh)
│ │ ├── types.ts # TypeScript types
│ │ └── style.css # Component styles
│ ├── index.js # Plugin entry point (server-side)
│ ├── openrouter-media.js # OpenRouter media backend
│ ├── model-config-api.js # Model config API backend
│ └── media-protocol.ts # Shared protocol constants
├── assets/
│ ├── icon.svg # Plugin icon
│ └── model-presets.json # Bundled model presets
├── docs/
│ └── openrouter-media.zh-CN.md # Media tools documentation (zh)
├── tests/
│ ├── model.test.ts
│ ├── model-config.test.ts
│ ├── model-presets.test.ts
│ ├── media-api.test.ts
│ ├── model-config-api.test.js
│ └── openrouter-media.test.js
├── lib/ # Prebuilt output
├── package.json
├── tsconfig.json
├── tsdown.config.ts
└── cordis.patch.yml
📋 Requirements
- Node.js >= 22.19
- DeepSeek Harness >= 4.0.1
- pnpm >= 11.21 (for development)
📄 License
MIT © Jensen Yao
No comments yet. Be the first to write one.