dshbase

插件目录 / Developer / dsh-ringcentral

dsh-ringcentral

已验证 · 实测可装 ringclaw

✓ 持续维护 2 位贡献者 基于 9 个官方 DSH 包

查看 GitHub ↗ ← 返回插件目录

0Stars
0Forks
0未关闭 issue
—语言
2026-08-21最近推送
跨平台平台

功能简介

Plugin for integrating RingCentral with DeepSeek Harness (dsh)

✅
我们的评价
可用 — 实测通过,早期项目

Plugin for integrating RingCentral with DeepSeek Harness (dsh) 实测能干净安装、正常启动。早期项目,但功能可用。

「已验证」表示我们的自动化 CI 在干净 profile 里实际执行了 dsh plugin add 并启动成功——仅此而已。功能描述与版本兼容性均为作者声明。这不是安全审计,也不代表对第三方代码的背书。

README

dsh-ringcentral

RingCentral Team Messaging IM channel plugin for
deepseek-harness (dsh).
It turns a RingCentral Bot Add-in into a first-class frontend for a dsh agent:
inbound posts from RingCentral chats drive the agent loop, and assistant
replies flow back as threaded RingCentral posts.

English | 中文说明

Architecture

RingCentral user ──▶ WebSocket (PostAdded) ──▶ im-ringcentral ──▶ ctx.agents ──▶ dsh agent loop ──▶ LLM
                                                │                                     │
                                                └── admission / session / event ◀────┘
                                                     (assistant reply ──▶ RingCentral post, threaded)

The plugin is a pure Cordis plugin following the dsh "Plugins, not loop changes"
principle. It speaks the RingCentral Team Messaging v1 REST API + WebSocket
subscription stream directly (no external SDK) and reuses the host dsh services
for agents, sessions, models, compaction, and tool presentation.

Install

1. Via dsh plugin manager

# install into a profile
npx @deepseek-ai/dsh plugin --profile ringcentral add dsh-ringcentral

# start
export RC_BOT_TOKEN="your-bot-jwt"
export DEEPSEEK_API_KEY="your-deepseek-key"
npx @deepseek-ai/dsh --profile ringcentral

Or run the bundled installer: sh install.sh.

2. Local path

cd /path/to/dsh-ringcentral
pnpm install && pnpm build
npx @deepseek-ai/dsh plugin --profile ringcentral add /path/to/dsh-ringcentral
export RC_BOT_TOKEN="your-bot-jwt"
npx @deepseek-ai/dsh --profile ringcentral

3. --patch development mode

The --patch overlay loads the plugin from a local absolute path without
installing it into a profile. Generate the machine-local patch first, then
boot:

cd /path/to/dsh-ringcentral
pnpm install && pnpm build        # dist entry (npx dsh cannot resolve .js -> .ts)
node scripts/gen-dev-patch.mjs    # writes cordis.local.yml with the real path
export RC_BOT_TOKEN="your-bot-jwt"
npx @deepseek-ai/dsh web --patch ./cordis.local.yml

Use pnpm dev (tsc --watch) while iterating: the loader hot-reloads the
plugin whenever dist/ changes. Pointing the patch at src/index.ts only
works inside a deepseek-harness source tree (pnpm dsh), not with the
npx-installed package.

RingCentral bot setup

  1. Sign in at https://developers.ringcentral.com/.
  2. Create an app with the Bot platform type.
  3. Grant at least: TeamMessaging, ReadAccounts, WebSocketsSubscription.
  4. Install or publish the bot to your RingCentral account.
  5. Copy the bot JWT and use it as RC_BOT_TOKEN.

Optional owner credentials (JWT REST API app for your own account, with
TeamMessaging + WebSocketsSubscription + ReadMessages) give
ringcentral_get_recent_messages owner read fallback and outbound owner
fallback. The history tool always reads through the bot client
(RC_BOT_TOKEN) first; without owner credentials it uses only the bot
client (chats the bot is a member of).

Configuration

Config follows dsh practice: the cordis config tree is the single source
(profile cordis.patch.yml / cordis.yml), with Schema defaults applied
automatically. Secrets (RC_BOT_TOKEN, RC_USER_CLIENT_ID,
RC_USER_CLIENT_SECRET, RC_USER_JWT_TOKEN) resolve through the host
credentials domain — an explicit config value wins, then environment →
managed $DSH_HOME/.credentials.yaml → project/user .env, with the plain
process environment as the final fallback. RC_SERVER_URL works the other
way for operational overrides (e.g. sandbox): the environment value wins over
the configured/default server. Secrets are never persisted into profile YAML.
To drive any other setting from an environment variable, use the cordis
loader's !!js tag (double bang — a single !js is not evaluated), e.g.
access.groupMode: !!js process.env.RC_GROUP_MODE ?? 'open'.

The access-control block mirrors @tencent-connect/dsh-qqbot exactly
(QQ's c2c surface is dm here). RingCentral's three non-DM chat types
(Team / Everyone / Group) are all governed by the group surface.

Config Type Default Description
botToken string required Bot static JWT (env: RC_BOT_TOKEN)
ownerCredentials.clientId / clientSecret / jwt string - Owner JWT (env: RC_USER_*)
server string https://platform.ringcentral.com API server (env: RC_SERVER_URL)
access.dmMode enum open DM handling: disabled, allowlist, open
access.dmAllow string[] [] Person ids allowed in DMs; empty or ["*"] = allow all
access.groupMode enum open Group handling: disabled, allowlist, open
access.groupAllow string[] [] Chat ids allowed in groups; empty or ["*"] = allow all
requireMention boolean true Require @-mention in group chats
groupPrompt string - Extra system prompt for group chats
directPrompt string - Extra system prompt for DMs
processingPlaceholder.enabled boolean false Post 👀 → ⏳ while the agent works (texts/delay are fixed)
historyMessageLimit number 250 Default record count for the history tool
homeChannel string - Fallback target for the history tool
textChunkLimit number 4000 Max chars per outgoing post
provider / model string host default LLM route (fallback chain: per-peer prefs → config → host agentDefaultModel)
preset string - Agent preset id
cwd string process.cwd() Agent working directory
sessionIdleTimeout number 1800000 Idle session eviction (ms)
showToolResults boolean false Show successful tool results (errors always show)
debug boolean false Debug logging (includes inbound message logs)

Every row except the secret entries is editable from the Web GUI card
described below.

Web GUI configuration

Installed into a web profile (dsh plugin --profile web add dsh-ringcentral),
the plugin registers a settings namespace and a configuration card under
Settings → Plugins → Plugin configuration. The card:

  • edits every non-secret entry of the table above; saves apply to the next
    inbound IM message
    (no restart), and a per-field Reset returns a value
    to the composed profile layer;
  • renders the four secrets (RC_BOT_TOKEN, RC_USER_*) as write-only
    controls: it reports only whether each is configured and writes through the
    settings domain (fallback to the host credentials domain where reachable);
    secret values are never sent back to the page. Credential changes apply
    live: within ~1s the plugin rebuilds its REST clients and reconnects the
    websocket with the new token — no restart, and the per-peer session context
    survives rotation (the account key derives from the stable bot identity).

Without a settings service (a bare custom cordis.yml), the card simply does
not mount and the plugin behaves exactly as before.

Commands

Command Description
/new (/reset, /clear) Start a new session (clear context)
/compact Compress session history (summary replaces old records)
/model Show or switch the model
/stop Abort the current generation
/rc-ping Connectivity test
/rc-version Plugin version
/rc-status Current session status
/rc-help List all commands

Session routing

sessionKey: ringcentral:<accountScopeKey>:<scope>:<peerId> where scope is
direct (peer = person id), group (peer = Group DM chat id), or
channel (peer = Team/Everyone chat id), and accountScopeKey is a
SHA-256 fingerprint of server + bot token. The SessionId is derived
deterministically (SHA-256), so the same user/chat always routes to the same
session and survives restarts. Resolution order: in-process reuse → persisted
resume → fresh create.

Agent questions (ask_user)

When the agent calls ask_user_question, the plugin renders the question
into the chat (thread-anchored) and waits for the user to reply in the same
session:

  • Reply with an option number or label to select a choice (multi_select
    accepts "1, 3"), or type a free-text answer.
  • Multi-question asks are answered one question at a time.
  • Answers resolve the pending question and are not appended to session
    history (same semantics as the web GUI).
  • Waiting times out after 10 minutes (the ask is cancelled with a notice).

Note: the provider registers on the userQuestions service seam. In a web
profile the GUI provider takes precedence — questions then appear in the web
UI, not in RingCentral. Use a dedicated profile for IM-only operation.

Design principles

  • Pure Cordis plugin — follows dsh "Plugins, not loop changes".
  • Declarative deps — inject = ['agents']; tools/compaction/presets are optional seams.
  • Session isolation — one agent per RingCentral peer.
  • Mini-Markdown outbound — replies are converted to RingCentral Mini-Markdown and chunked.
  • Threading — replies always anchor on the triggering post (threadId preferred), with owner fallback and unthreaded retry.
  • Idle eviction — inactive agents are disposed automatically.
  • Defensive degradation — missing tools/presets/owner credentials never crash the plugin.

Not in v1 (planned follow-ups)

  • Adaptive Card / note / calendar / task artifact tools
  • Cron and out-of-process notification sender
  • Multi-account support
  • Native streaming (RingCentral has no stream API; the processing placeholder is the typing affordance)

Local development

pnpm install
pnpm build          # or: pnpm dev (watch)
pnpm test
pnpm typecheck

# run against the npx-installed dsh
export RC_BOT_TOKEN="xxx"
node scripts/gen-dev-patch.mjs
npx @deepseek-ai/dsh web --patch ./cordis.local.yml

scripts/gen-dev-patch.mjs emits the gitignored cordis.local.yml directly,
with the entry resolved to an absolute path on the machine (default
dist/index.js; pass src/index.ts to point at the TypeScript entry).

Test coverage map

pnpm test runs 143 cases across 17 files. No network is touched — clients,
websockets, and harness services are stubbed.

File Covers
tests/accounts.test.ts Secret resolution precedence, schema-default fallbacks, legacy __FROM_ENV__ compat, numeric clamping
tests/account-scope-key.test.ts Stable-identity account key: rotation keeps session keys; token-fingerprint fallback
tests/credentials.test.ts resolveSecret chain (service → env → managed file), inject handle, file parser, file watcher
tests/settings-merge.test.ts Live config merge into runtime/account copies, secret-field exemption, server/placeholder branches
tests/settings-redact.test.ts role('secret') wire redaction and its sidecar
tests/monitor.test.ts WS frame extraction, post filtering (own echoes, answer markers), websocket URL building
tests/rotation-scheduler.test.ts Debounce coalescing, single-flight, dispose (extracted module, fake timers)
tests/gateway-rotation.test.ts Fake-harness integration: rotate() rebuilds clients, re-registers the history tool, reconnects the websocket; no-op on same token; fail-safe on missing token
tests/session-manager.test.ts Deterministic session ids, per-scope isolation, setAccountKey re-derivation
tests/inbound.test.ts Admission (dm/group allowlists), mention gating, prompt injection, command routing
tests/outbound.test.ts Reply chunking, showToolResults gating, placeholder lifecycle
tests/history-tool.test.ts Reader precedence (bot → owner), record clamping, target resolution
tests/threading.test.ts Thread-participation tracking and follow-up classification
tests/targets.test.ts Reply-target resolution and thread anchoring
tests/markdown.test.ts Mini-Markdown conversion
tests/user-questions.test.ts IM answer surface for agent questions
tests/debug-log.test.ts On-disk debug log format and gating

Troubleshooting

Symptom Likely cause Fix
Plugin not starting RC_BOT_TOKEN missing Set RC_BOT_TOKEN (env or $DSH_HOME/.credentials.yaml) or botToken in config
Debug log shows [cred] … service=absent In desktop-style deployments, bundle-row plugins cannot read host services via ctx.get (isolate scoping) Not an error: 0.3.15+ ships a file fallback and 0.3.17 an inject-based path — see docs/credentials-service-unreachable.md
Bot never replies in a group chat access.groupMode: disabled, not allowlisted, or no mention Check access.groupMode / access.groupAllow and @-mention the bot
DM ignored access.dmMode: disabled or sender not in access.dmAllow Check access.dmMode / access.dmAllow
History tool returns nothing Chat not visible to bot or owner Reads try the bot first, then the owner; pass a bare chat id or channel:<chatId> and make sure one client is a member
Agent question not answered from RingCentral Web GUI provider registered (web profile) Questions go to the web UI; use a dedicated profile or answer in the web UI

License

MIT

安装

🧩 让 Agent 自动装(推荐)

装一次目录插件,之后本站所有插件都能让 DeepSeek Harness 自动找、自动装:

dsh plugin add dshbase-catalog

然后对 agent 说「帮我装 dsh-ringcentral」,它会在目录里找到并自动安装。文档:dshbase-catalog · 已验证场景包。

该插件是 GitHub 源码(未发 npm)——直接从仓库装:

Web profile:

dsh plugin --profile web add github:ringclaw/dsh-ringcentral

Headless(CLI)profile:

dsh plugin --profile headless add github:ringclaw/dsh-ringcentral

实测报告

验证通过:从 GitHub 源码完成 L1 安装 + L2 加载 + L3 运行(dsh 0.1.0-rc.6)。

安全:尚未扫描——我们的每日静态扫描将很快覆盖它。

分享徽章

Developer 里更多

浏览全部 7819 个插件 →