Skip to content

feat(dingtalk): proactive messaging via Robot OpenAPI#17370

Open
spike2204 wants to merge 1 commit into
NousResearch:mainfrom
spike2204:feat/dingtalk-proactive-send
Open

feat(dingtalk): proactive messaging via Robot OpenAPI#17370
spike2204 wants to merge 1 commit into
NousResearch:mainfrom
spike2204:feat/dingtalk-proactive-send

Conversation

@spike2204

Copy link
Copy Markdown

Summary

When no session_webhook is available (e.g. agent-initiated messages, expired webhook, or scheduler-triggered sends), fall back to DingTalk Robot OpenAPI for message delivery — the same pattern Feishu uses for proactive im.v1.message.create calls.

Changes

Module-level additions:

  • _dingtalk_fetch_access_token() / _dingtalk_fetch_oapi_token() — dual token management (OAuth2 + legacy OAPI) with in-memory cache + expiry
  • _dingtalk_upload_media() — upload image/video/voice/file via /v1.0/robot/messageFiles/download with 20MB guard
  • _dingtalk_classify_chat_id() — route OTO vs group by sender_id format
  • _dingtalk_build_msg_param() — build sampleText/sampleMarkdown/sampleImageMsg/sampleFile payloads with auto-format detection
  • dingtalk_send_proactive() — orchestrate token → classify → build → POST
  • _looks_like_markdown() — heuristic for markdown auto-detection

Class-level changes:

  • Add self._robot_code to __init__
  • send() now falls back to dingtalk_send_proactive() when no webhook

Ported from dingtalk-openclaw-connector services/proactive-sender.ts.

Related

Part of the DingTalk adapter enhancement series — see #12769 for the umbrella PR.

When no session_webhook is available (e.g. agent-initiated messages,
expired webhook, or scheduler-triggered sends), fall back to DingTalk
Robot OpenAPI for message delivery — the same pattern Feishu uses for
proactive im.v1.message.create calls.

Module-level additions:
- _dingtalk_fetch_access_token() / _dingtalk_fetch_oapi_token() — dual
  token management (OAuth2 + legacy OAPI) with in-memory cache + expiry
- _dingtalk_upload_media() — upload image/video/voice/file via
  /v1.0/robot/messageFiles/download with 20MB guard
- _dingtalk_classify_chat_id() — route OTO vs group by sender_id format
- _dingtalk_build_msg_param() — build sampleText/sampleMarkdown/
  sampleImageMsg/sampleFile payloads with auto-format detection
- dingtalk_send_proactive() — orchestrate token → classify → build →
  POST /v1.0/robot/oToMessages/batchSend or /v1.0/robot/groupMessages/send
- _looks_like_markdown() — heuristic for markdown auto-detection

Class-level changes:
- Add self._robot_code to __init__
- send() now falls back to dingtalk_send_proactive() when no webhook

Ported from dingtalk-openclaw-connector services/proactive-sender.ts. to #
@alt-glitch alt-glitch added type/feature New feature or request P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery platform/dingtalk DingTalk adapter labels Apr 29, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #14336 — same DingTalk Robot OpenAPI proactive messaging implementation. Also overlaps with #12077. Part of umbrella #12769.

@spike2204

Copy link
Copy Markdown
Author

Hi @alt-glitch, thanks for the careful review! 🙏

Correct — this extracts the proactive messaging feature from the original stacked #14336, rebased cleanly against main.

Context: We're the DingTalk (钉钉) Open Platform team at Alibaba. @PeterGuy326 and @spike2204 are colleagues on the same team.

Regarding #12077: Our implementation is more comprehensive and follows the same architectural pattern Hermes already uses for Feishu's proactive im.v1.message.create calls:

  • Dual token management — OAuth2 (/v1.0/oauth2/accessToken) for new-style Robot OpenAPI + legacy OAPI (/gettoken) for media upload, both with in-memory cache and expiry tracking
  • Chat ID auto-routingcidXXXX== (openConversationId) → group send, plain staffId → OTO batch send, LWCP-encoded sender → fast-fail with actionable error
  • Media upload pipeline — image/video/voice/file upload via /v1.0/robot/messageFiles/download with 20MB guard and extension-based mediaType routing
  • Message format auto-detection_looks_like_markdown() heuristic + _dingtalk_build_msg_param() builds the correct msgKey (sampleText / sampleMarkdown / sampleImageMsg / sampleFile)
  • Graceful fallback in send() — when no session_webhook exists, transparently routes through Robot OpenAPI instead of returning an error

This has been running in our production deployment handling proactive notifications, scheduled digests, and cross-platform message forwarding. We're happy to help reconcile with #12077 — our implementation likely subsumes its scope.

Let us know if you'd like any changes! 🚀

@shuans

shuans commented May 5, 2026

Copy link
Copy Markdown

@alt-glitch, hope this PR can be merged soon. Currently dingtalk is missing these features, making it inconvenient to use. If my PR #12077 is not modular enough, feel free to merge this PR directly.

@shuans

shuans commented May 28, 2026

Copy link
Copy Markdown

Hi guys, I built a CLI tool that sends messages directly to DingTalk (individual or group), with a plugin system so more platforms can be added later.
npx msgcli send "hello world"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists platform/dingtalk DingTalk adapter type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants