fix(dingtalk): preserve richText formatting and set HTTP client timeout
richText messages only kept rich_text_list items whose type was "text", so bold/italic/inlineCode/pre segments were silently dropped; a message made entirely of formatted segments produced empty content and fell through to the "unsupported message type: richText" warning. Now any item carrying text is kept (matching the SDK's own get_text_list, which keys off the "text" field) and its type is mapped to Markdown so the formatting survives into the agent's context. Text and downloadCode within a rich-text item are handled independently (the SDK treats them as separate via get_text_list / get_image_list), so an item carrying both a caption and an attachment no longer drops the file. The shared httpx.AsyncClient was created without a timeout, so all requests (including large file/image downloads) used httpx's 5s default and hit ConnectTimeout/ReadTimeout on uploads. Set an explicit httpx.Timeout (connect=10s, read/write=30s). Adds regression tests for formatted-segment preservation, the all-formatted no-drop case, the text+downloadCode item, and the client timeout configuration. Closes #4497
This commit is contained in:
@@ -94,11 +94,23 @@ class NanobotDingTalkHandler(CallbackHandler):
|
||||
for item in rich_list:
|
||||
if not isinstance(item, dict):
|
||||
continue
|
||||
if item.get("type") == "text":
|
||||
t = item.get("text", "").strip()
|
||||
if t:
|
||||
content = (content + " " + t).strip() if content else t
|
||||
elif item.get("downloadCode"):
|
||||
# A rich-text item may carry text and/or a downloadCode; the
|
||||
# DingTalk SDK treats them independently, so handle both.
|
||||
t = item.get("text", "").strip()
|
||||
if t:
|
||||
fmt = item.get("type", "")
|
||||
if fmt == "bold":
|
||||
formatted = f"**{t}**"
|
||||
elif fmt == "italic":
|
||||
formatted = f"*{t}*"
|
||||
elif fmt == "inlineCode":
|
||||
formatted = f"`{t}`"
|
||||
elif fmt == "pre":
|
||||
formatted = f"```\n{t}\n```"
|
||||
else:
|
||||
formatted = t
|
||||
content = (content + " " + formatted).strip() if content else formatted
|
||||
if item.get("downloadCode"):
|
||||
dc = item["downloadCode"]
|
||||
fname = item.get("fileName") or "file"
|
||||
sender_uid = chatbot_msg.sender_staff_id or chatbot_msg.sender_id or "unknown"
|
||||
@@ -214,7 +226,9 @@ class DingTalkChannel(BaseChannel):
|
||||
return
|
||||
|
||||
self._running = True
|
||||
self._http = httpx.AsyncClient()
|
||||
self._http = httpx.AsyncClient(
|
||||
timeout=httpx.Timeout(10.0, connect=10.0, read=30.0, write=30.0, pool=10.0)
|
||||
)
|
||||
|
||||
self.logger.info(
|
||||
"Initializing Stream Client with Client ID: {}...",
|
||||
|
||||
Reference in New Issue
Block a user