masquerator-coder/dsh-im-gateway ↗★ 1
dsh-im-gateway
DeepSeek Harness (DSH) IM gateway plugin: foolproof multi-channel (5G消息 / email / feishu / wechat / qq / http) -> per-chat persistent Agent -> reply routing. 适合需要将5G消息、微信、飞书等通道接入DSH智能体的用户。
같은 패키지 이름의 다른 저장소
설치
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:masquerator-coder/dsh-im-gatewayConfiguration (via cordis.yml)
| Key | Default | Meaning |
|---|---|---|
host | 127.0.0.1 | Inbound listen address |
port | 8799 | Inbound listen port |
inboundPath | /im | Webhook URL path |
secret | '' | Optional shared secret; requests must send it in header x-im-secret. Empty = no auth. |
chatIdField | chat_id | Webhook JSON body field identifying the chat |
textField | text | Webhook JSON body field carrying the message text |
senderField | sender_id | Optional body field for the sender id (used by allowlist + source injection) |
allowlist | [] | Sender allowlist (access control). Non-empty ⇒ only these senderIds may drive the agent; others / sender-less are denied up front |
callbackUrl | (required) | URL the reply is POSTed to |
callbackChatHeader | x-im-chat-id | Header holding the chat id on the callback |
callbackSecretHeader | x-im-secret | Header holding the secret on the callback |
provider | '' | Model provider route override (empty = runtime default model) |
model | '' | Model id override (empty = runtime default model) |
maxTokens | 0 | Positive output cap, or 0 for default |
agentPreset | '' | Optional agent preset applied on creation |
cwd | '' | Optional working directory for the Agent session (a real Harness workspace) |
disposeAfterReply | false | Dispose the Agent after each reply (frees resources, drops context) |
⚠️ Only
host/port/inboundPath/chatIdField/textField/senderField/allowlist/callbackChatHeader/callbackSecretHeaderand the checkbox-like fields are non-sensitive wiring.secretandcallbackUrlare deployment secrets — never commit real values. Keep yourcordis.ymlsecret in.env/local overrides and out of the repository.
Usage
The plugin ships in two interchangeable forms:
- a bundle (recommended for deployment) — installed by package name, loads the built
lib/index.js; - a local source overlay (development) —
--patchagainstsrc/for fast iteration.
Install as a bundle
Add the bundle to a profile. The built lib/ is committed, and the package has
no prepare/postinstall script, so nothing runs on install:
dsh plugin --profile demo add github:you/dsh-im-gateway
No
allowBuildsentry is needed — on this machine or on any sharee's. pnpm ≥ 10 refuses to run an unapproved dependency build script and exits non-zero, whichdsh pluginreports as a failed install ("add the exact key pnpm printed above under allowBuilds in …"), so one straypostinstallanywhere in the runtime dependency closure would break the one-command install for every user. This package therefore guarantees that closure is empty of them: the Feishu SDK — whose hard dependencyprotobufjsships a purely cosmeticpostinstall— is vendored intolib/vendor/lark-sdk.cjsinstead of being installed, andpnpm buildrunsscripts/check-install-scripts.mjs, which fails the build the moment any runtime dependency (transitively) gains apreinstall/install/postinstallscript. Verified by installing this package on a clean profile with noallowBuildssection at all:pnpmexits 0. Contributor rule: becauselib/is committed, everysrc/change must ship with its rebuiltlib/(pnpm buildthen commit) — otherwise the distributed version runs a stale bundle. For a single-file artifact instead of a Git install, runpnpm packanddsh plugin --profile demo add ./dsh-im-gateway-.tgz.
Upgrading from a version that needed
allowBuilds? If an earlier install failure already wrote aprotobufjs:placeholder into your profile'spnpm-workspace.yaml(C:\Users\\.dsh\profiles\ \pnpm-workspace.yaml), delete that line —protobufjsis no longer part of the dependency tree — and re-run theaddcommand.
The bundle's layer is cordis.patch.yml, which inserts the im-gateway row with
sensible defaults. Override any key from your profile's own cordis.patch.yml
(a later layer wins per row and replaces the whole config, so restate every key).
Load the local source overlay (development)
From the DSH repository root (after the run-from-source path), start the Web UI with this overlay:
pnpm dsh web --patch /path/to/dsh-im-gateway/cordis.yml
cordis.yml example:
- insert:
- id: im-gateway
name: './src/index.ts'
config:
inboundPath: '/im'
secret: 'change-me'
chatIdField: 'chat_id'
textField: 'text'
senderField: 'sender_id'
allowlist: ['user-7']
callbackUrl: 'https://your-im-bridge.example/reply'
provider: 'deepseek'
model: 'deepseek-chat'
External IM → gateway (legacy HTTP webhook)
The settings UI is the primary way to attach channels (see above). The legacy single HTTP webhook path below is retained for back-compat / headless setups.
POST messages to http://: /im:
{ "chat_id": "group-42|user-7", "sender_id": "user-7", "text": "你好" }
Send header
x-im-secret:whensecretis set. The gateway responds202 { ok: true }immediately once the message is accepted — it does not wait for the model turn. The agent reply always arrives later over the callback (see below). Whenallowlistis set andsender_idis not in it (or missing), the message is denied up front (a202is still returned) — no agent turn, no reply.
Gateway → external IM (outbound callback)
The collected reply is POSTed to callbackUrl (with up to 2 delivery attempts; a give-up is logged reply NOT delivered):
POST
x-im-chat-id: group-42|user-7
x-im-secret: change-me
{ "chat_id": "group-42|user-7", "text": "", "ts": 1710000000000 }