Tools & Capabilities
dsh-plugin-ai-bridge
SwainGao/dsh-plugin-ai-bridge · ★ 1
Lets DeepSeek Harness collaborate seamlessly with external AI models — second-opinion review, adversarial review, task delegation, and non-blocking background scheduling.
Manifest details
安装
dsh plugin --profile web add github:SwainGao/dsh-plugin-ai-bridgeGitHub 源码安装:首次需按提示配置 allowBuilds 构建授权后重试
For install and environment setup, plus plugin development tutorials, see DSH community docs ↗
README
Table of contents
- dsh-plugin-ai-bridge
- Bridge DeepSeek Harness to external AI models — second-opinion review · adversarial review · task delegation · non-blocking background scheduling
- ✨ Features
- ⚡ Install
- 🔧 Config
- 🔌 Relay gateways (cc-switch)
- 🔑 Environment fallbacks
- 🎛️ Commands
- 🔍 /bridge review [--fast|--deep|--auto] [--model <m>] <file|code>
- ⚔️ /bridge adversarial-review [--fast|--deep|--auto] <file|code>
- 🛟 /bridge rescue [--full] <task>
- ⏳ Job management
- 🧰 Model-facing tools
- 🏗️ Architecture
- 🎬 Demo
- 🧪 Tests
- 🛡️ Security & data boundaries
- ⚖️ License & compliance
- 📄 License
dsh-plugin-ai-bridge
Bridge DeepSeek Harness to external AI models — second-opinion review · adversarial review · task delegation · non-blocking background scheduling
✨ Features · ⚡ Install · 🔧 Config · 🎛️ Commands · 🧰 Tools · 🏗️ Architecture · 🎬 Demo · 🧪 Tests · 🛡️ Security · ⚖️ License
✨ Features
DeepSeek Harness currently lacks cross-model collaboration. This plugin builds a "bridge" for it — delegate code review or complex tasks to an external model from inside a session, then bring its judgment back into the current session.
🔍 Read-only second-opinion review — style, logic, potential bugs, security; never mutates session state
⚔️ Adversarial review — challenge design decisions, architecture assumptions, boundary conditions and error handling with 5–10 "soul-searching" questions
🛟 Task delegation / rescue — bundle conversation history + task, inject the result back as plugin context
⏳ Non-blocking background jobs — status / result / cancel on top of ctx.jobs
🧩 Model-facing tools — ai_bridge_review / ai_bridge_delegate so the agent can ask for help on its own
| Capability | Trigger | Description |
|---|---|---|
| Second-opinion review | /bridge review <file|code> |
Read-only review, runs as a non-blocking background job |
| Adversarial review | /bridge adversarial-review <file|code> |
5–10 challenging questions |
| Task delegation / rescue | /bridge rescue <task> |
History + task → external model → injected result |
| Job status | /bridge status |
List bridge background jobs |
| Read result | /bridge result <job-id> |
Read a finished job's output |
| Cancel job | /bridge cancel <job-id> |
Cancel a running job |
⚡ Install
# One command installs and auto-mounts the plugin (via dsh.bundle.patch).
dsh plugin --profile <profile-name> add dsh-plugin-ai-bridge
# Restart the profile, then type:
/bridge help
Then override the config in the profile's cordis.patch.yml (see "Config" below):
- id: ai-bridge
config:
provider: generic
baseUrl: https://your-relay.example.com/v1
defaultModel: gpt-5.4
apiKey: sk-...
No manual
insertis needed — the plugin mounts itself throughdsh.bundle.patch. You can also use only env vars (BRIDGE_API_KEY/BRIDGE_BASE_URL/BRIDGE_MODEL).If you previously mounted it with a manual
insert, remove that block to avoid double-mounting. To install from source:npm run build, then linklib/into the profile'snode_modules/dsh-plugin-ai-bridge.
🔧 Config
Plugin config lives in the profile's cordis.patch.yml (environment variables act as fallbacks).
| Key | Default | Description |
|---|---|---|
apiKey |
'' |
External-model API key |
baseUrl |
per provider | Endpoint base URL (OpenAI-compatible URLs include /v1; Anthropic URLs do not) |
provider |
openai |
openai (GPT, Chat Completions) · codex (Responses API) · anthropic (Claude) · generic (any OpenAI-compatible relay) |
defaultModel |
gpt-5-codex |
Default model id (the "deep" model) |
fastModel |
same as defaultModel |
Cheap/fast model for --fast and auto escalation. Empty falls back to the deep model (single-model installs keep working) |
deepModel |
same as defaultModel |
Authoritative/deep model. Empty falls back to defaultModel → BRIDGE_MODEL → provider default |
timeoutMs |
120000 |
Per-request timeout (milliseconds) |
maxOutputTokens |
4000 |
Maximum output tokens per call |
cacheTtlMs |
600000 |
Dedup cache TTL (ms): identical requests reuse the previous answer within this window. 0 disables |
threadCompressAfter |
8 |
Summarize earlier rescue-thread turns with fastModel once the thread exceeds this many messages. 0 disables |
injectRescueResult |
false |
Auto-inject rescue results back into the session (marked untrusted); when false, read them via /bridge result |
reviewGate |
false |
Enable the opt-in review gate that reviews the agent response before a turn stops (can loop and consume quota) |
threadsDir |
~/.dsh-plugin-ai-bridge |
Directory that persists rescue threads |
# $DSH_HOME/profiles/<profile-name>/cordis.patch.yml
- insert:
- id: ai-bridge
name: dsh-plugin-ai-bridge
config:
provider: openai
defaultModel: gpt-5-codex
baseUrl: https://api.openai.com/v1
apiKey: sk-...
- insert:
- id: ai-bridge
name: dsh-plugin-ai-bridge
config:
provider: codex
defaultModel: gpt-5-codex
baseUrl: https://api.openai.com/v1
apiKey: sk-...
- insert:
- id: ai-bridge
name: dsh-plugin-ai-bridge
config:
provider: anthropic
defaultModel: claude-sonnet-4-5
baseUrl: https://api.anthropic.com
apiKey: sk-ant-...
- insert:
- id: ai-bridge
name: dsh-plugin-ai-bridge
config:
provider: generic
baseUrl: https://your-gateway.example.com/v1
defaultModel: your-model-id
apiKey: ...
🔌 Relay gateways (cc-switch)
The plugin supports any relay gateway through baseUrl. If you use cc-switch to route Claude / Codex through a relay, fill in the same "relay URL + token + model name":
| Scenario | provider |
baseUrl |
defaultModel |
|---|---|---|---|
| Codex (Chat Completions relay) | generic |
https://<relay>/v1 |
the model name your relay expects |
| Codex (Responses API relay) | codex |
https://<relay>/v1 |
the model name your relay expects |
| Claude (Anthropic relay) | anthropic |
https://<relay> |
the model name your relay expects |
⚠️ cc-switch writes to Claude Code / Codex CLI config files, which do not automatically flow into the DSH process. Either repeat the same relay credentials in the config above, or export cc-switch-style environment variables (below) — the plugin reads them as fallbacks.
🔑 Environment fallbacks
When cordis.patch.yml omits a value, it is read from the environment in this priority order:
- API key:
BRIDGE_API_KEY→ANTHROPIC_AUTH_TOKEN(anthropic only) →ANTHROPIC_API_KEY(anthropic only) →OPENAI_API_KEY - baseUrl:
BRIDGE_BASE_URL→ANTHROPIC_BASE_URL(anthropic only) /OPENAI_BASE_URL(others) - model:
BRIDGE_MODEL
So if your shell already exports the cc-switch-style
ANTHROPIC_BASE_URL/ANTHROPIC_AUTH_TOKEN/OPENAI_BASE_URL/OPENAI_API_KEY, this plugin reuses them directly.
🎛️ Commands
DSH command names only allow
[a-z][a-z0-9_-]*(no:). The six operations are therefore implemented as subcommands of a single/bridgecommand:
| Requested command | Actual trigger |
|---|---|
/bridge:review [file path or code snippet] |
/bridge review [--fast|--deep|--auto] [--model <m>] <file|code> |
/bridge:adversarial-review [...] |
/bridge adversarial-review [--fast|--deep|--auto] <file|code> |
/bridge:rescue [task description] |
/bridge rescue [--full] <task> |
/bridge:status |
/bridge status |
/bridge:result [job-id] |
/bridge result <job-id> |
/bridge:cancel [job-id] |
/bridge cancel <job-id> |
🔍 /bridge review [--fast|--deep|--auto] [--model <m>] <file|code>
Read-only review. file may be an absolute path or one relative to the current session's working directory; otherwise the input is treated as a code snippet.
Model tier (the cost-efficiency switch):
--deep(default) → review withdeepModel(best quality);--fast→ review withfastModel(cheapest);--auto→ review withfastModelfirst, and escalate todeepModelonly when it outputsCONFIDENCE: low(or a missing/ambiguous marker). A single-model install collapses all three to one call.
/bridge review src/index.ts
/bridge review function add(a, b) { return a - b }
/bridge review --fast src/a.ts
/bridge review --auto src/a.ts
review and adversarial-review run as background jobs (non-blocking), returning an ai-bridge-N job id immediately; read the result with /bridge result <id>.
⚔️ /bridge adversarial-review [--fast|--deep|--auto] <file|code>
Adversarial review, producing 5–10 "soul-searching" questions. Supports the same review targets and model tiers as review.
🛟 /bridge rescue [--full] <task>
Bundles the task + current conversation history (last 200 messages, up to 60k chars) and delegates them to the external model. By default only user/assistant text is sent, with common secret shapes redacted; add --full to also include tool calls/results and reasoning (may contain secrets). By default (injectRescueResult: false) the result is not auto-injected — read it via /bridge result <id>; when injection is enabled, it is marked [bridge rescue result — UNTRUSTED EXTERNAL OUTPUT].
Long threads are compressed: once a thread exceeds threadCompressAfter messages, earlier turns are summarized with fastModel and only the summary plus the most recent turns are sent verbatim to the deep model (skipped automatically on single-model installs).
⏳ Job management
/bridge status # list bridge background jobs
/bridge result <job-id> # read a finished result; running jobs prompt you to wait
/bridge cancel <job-id> # cancel a running job
🧰 Model-facing tools
The plugin also registers two tools so the DeepSeek Harness agent can use them proactively without human input:
| Tool | Parameters | Description |
|---|---|---|
ai_bridge_review |
code (required) · adversarial? · mode? (fast/deep/auto) |
Send code (or a file path) to an external model for a read-only review; mode selects the model tier |
ai_bridge_delegate |
task (required) · include_history? |
Delegate a task (optionally with conversation history) and return its continuation |
🏗️ Architecture
Dependency injection: inject = ['commands', 'jobs', 'tools']; apply() attaches the background-job controller via ctx.jobs.attachController('ai-bridge').
| File | Responsibility |
|---|---|
src/index.ts |
Plugin entry: name / inject / Config / apply |
src/client.ts |
External-model HTTP client (OpenAI-compatible + Anthropic, streaming/non-streaming, dedup cache) |
src/cache.ts |
Request-hash de-duplication cache (TTL + LRU eviction) |
src/router.ts |
Model-tier routing (fast/deep/auto) + thread-history compression |
src/prompts.ts |
review / adversarial / rescue / confidence / summary system prompts |
src/context.ts |
File reading and conversation-history serialization |
src/jobs.ts |
ctx.jobs background-job wrapper + JobKindMap extension (ai-bridge) |
src/commands.ts |
/bridge command registration and subcommand dispatch |
src/tools.ts |
Model-facing tool registration |
src/
├── index.ts # entry: name / inject / Config / apply
├── client.ts # external-model client (OpenAI-compatible + Anthropic)
├── cache.ts # request de-duplication cache
├── router.ts # model-tier routing + thread compression
├── prompts.ts # system prompts
├── context.ts # file reading + history serialization
├── jobs.ts # ctx.jobs background jobs + JobKind extension
├── commands.ts # /bridge command dispatch
└── tools.ts # ai_bridge_review / ai_bridge_delegate
🎬 Demo
User ❯ /bridge review src/index.ts
Bridge ❯ Started review as background job ai-bridge-1.
Check progress: /bridge status
Get result: /bridge result ai-bridge-1
User ❯ /bridge status
Bridge ❯ ai-bridge-1 [ai-bridge] running — bridge review src/index.ts
User ❯ /bridge result ai-bridge-1
Bridge ❯ [style] Naming is clear, but the magic number at index.ts:42 should be a constant
[logic] parseArgs does not short-circuit on empty input — possible null dereference
[security] User input is concatenated into a template string; escape it
...
User ❯ /bridge rescue fix the failing test
Bridge ❯ Delegated rescue task as background job ai-bridge-2.
The result will be injected back into this session when ready.
Bridge ❯ [bridge rescue result]
Found the root cause: ... apply the following fixes in order ...
Record as
demo.gifwithterminalizerorasciinema.
🧪 Tests
npm install # install dependencies
npm run typecheck # type check
npm run build # compile to lib/
npm test # build and run the tests
| Test file | Coverage |
|---|---|
test/client.test.mjs |
API client against a local mock server (OpenAI/Anthropic, streaming/non-streaming, error handling) |
test/context.test.mjs |
File reading and history serialization |
test/commands.test.mjs |
End-to-end behavior of the six subcommands (background jobs, rescue injection) |
test/integration.test.mjs |
Loads the plugin with the real CommandRuntime and executes /bridge |
test/smoke.test.mjs |
Plugin object shape and registration |
🛡️ Security & data boundaries
This plugin sends content to the configured baseUrl (an external model or relay). Know these boundaries:
- File paths: only workspace-relative paths are allowed; absolute paths,
../traversal, and symlinks pointing outside the workspace are rejected. Files are size-checked (300 KB cap) before being read. - Code review:
/bridge review/ai_bridge_reviewsend only the file or inline code you specify. - Task delegation:
/bridge rescueandai_bridge_delegatesend only user/assistant text by default, with common secret shapes redacted; reasoning and tool results are sent only with--full(orinclude_tool_results). - External output: rescue results are marked "untrusted external output" for reference only; do not execute commands or instructions from them. By default (
injectRescueResult: false) results are not auto-injected — read them via/bridge result.
⚖️ License & compliance
This plugin is inspired by OpenAI's
codex-plugin-ccand is an independent implementation, not affiliated with OpenAI.
codex-plugin-cc(Copyright OpenAI and its contributors) is licensed under Apache-2.0. This plugin only draws on its design ideas as an independent implementation; it contains, copies, or derives no source code from it, and has no affiliation with, endorsement by, or sponsorship from OpenAI.See
NOTICEin the repository root.
📄 License
Apache-2.0 · third-party notices in NOTICE.
Made with 🧡 for the DeepSeek Harness community · Inspired by OpenAI codex-plugin-cc (independent implementation)