fix(dingtalk): support dingtalk-stream 0.24+ SDK (async process, CallbackMessage, oapi webhooks, TextContent)#11471
Merged
Merged
Conversation
…hape
The cherry-picked SDK compat fix (previous commit) wired process() to
parse CallbackMessage.data into a ChatbotMessage, but _extract_text()
was still written against the pre-0.20 payload shape:
* message.text changed from dict {content: ...} → TextContent object.
The old code's str(text) fallback produced 'TextContent(content=...)'
as the agent's input, so every received message came in mangled.
* rich_text moved from message.rich_text (list) to
message.rich_text_content.rich_text_list.
This preserves legacy fallbacks (dict-shaped text, bare rich_text list)
while handling the current SDK layout via hasattr(text, 'content').
Adds regression tests covering:
* webhook domain allowlist (api.*, oapi.*, and hostile lookalikes)
* _IncomingHandler.process is a coroutine function
* _extract_text against TextContent object, dict, rich_text_content,
legacy rich_text, and empty-message cases
Also adds kevinskysunny to scripts/release.py AUTHOR_MAP (release CI
blocks unmapped emails).
This was referenced Apr 17, 2026
This was referenced Apr 17, 2026
This was referenced Apr 17, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Salvages #11257 (kevinskysunny — authorship preserved) plus a follow-up fix discovered during E2E testing against the real
dingtalk-stream0.24.3 SDK.What's broken on
mainOur
gateway/platforms/dingtalk.pywas written against pre-0.20dingtalk-stream. Four incompatibilities break DingTalk in production:ChatbotHandler.process()is nowasync— ours was sync and usedrun_coroutine_threadsafe, so it never fires on the new SDK.process()now receives aCallbackMessageenvelope with a.datadict — ours expected aChatbotMessagedirectly.DingTalkStreamClient.start()is now a coroutine —asyncio.to_thread(self._stream_client.start)never awaits it.oapi.dingtalk.com— our regex only allowedapi.dingtalk.com, so every reply was silently rejected by the origin allowlist.Items 1-4 close out a pile of duplicate PRs reporting the same root cause: #5038, #8477, #8954, #9131, #9764, #9828, #10153, #10369, #10820, #11257, plus issues #5037, #6986, #8811, #8816, #9149, #9752.
What kevinskysunny's commit fixes (cherry-picked as-is)
_DINGTALK_WEBHOOK_RE→^https://(?:api|oapi)\.dingtalk\.com/_run_streamawaitsself._stream_client.start()directly_IncomingHandler.processbecomesasyncand parsescallback_message.dataviaChatbotMessage.from_dictFollow-up fix added on top (825b0fe)
E2E testing against real
dingtalk-stream==0.24.3revealed_extract_text()was also broken by the SDK change:message.textdictwithcontentkeyTextContentdataclassstr(text)returned'TextContent(content=hello)'literallymessage.rich_text(list)message.rich_text_content.rich_text_listEvery text message received by the agent was coming in as the string
TextContent(content=...)instead of the actual user message. Fix handles both shapes viahasattr(text, 'content')and falls back through legacy paths.Tests
process(), and_extract_text()against the current SDK, the legacy SDK, and edge cases.tests/gateway/test_dingtalk.py: 29 passed.tests/gateway/: 3042 passed, 6 pre-existing failures in signal/telegram (unrelated to this PR).E2E verification
Ran the adapter end-to-end against real
dingtalk-stream==0.24.3:Authorship
Original commit preserved with
kevinskysunny@gmail.comauthorship — will merge with--rebaseto keep attribution.Supersedes / closes
Once merged, the following can be closed with credit: