Skip to content

[Bug]: 钉钉卡片宽屏配置 card_auto_layout 失效——config 被放在 cardData 而非 cardParamMap(#1952 在 #2226 中回归) #2361

Description

@SingularityKChen

运行环境

v4.10.6(镜像 rockchin/langbot@sha256:459ab3d8…,source commit cb6c8d1e)、Linux x64 容器(podman)、Python 3.12、中国大陆

部署版本

社区版

异常情况

钉钉适配器开启「卡片宽屏自动布局」(card_auto_layout = true),并按 #1924 评论里的做法在卡片模板中声明了对象变量 config(含布尔子属性 autoLayout),钉钉 PC 端 AI 流式卡片仍然以窄栏渲染,同会话里的普通 markdown 消息则是正常宽度。

根因是投放请求体中 config 的层级放错了:它被放在 cardData 下、与 cardParamMap 平级,而钉钉模板变量只从 cardData.cardParamMap 取值,所以模板里的 config 变量始终没有被赋值,卡片回落到默认布局。

实际发出的请求体(v4.10.6 日志,已脱敏):

{
  "cardTemplateId": "<template>.schema",
  "outTrackId": "",
  "cardData": {
    "cardParamMap": { "content": "", "query": "" },
    "config": "{\"autoLayout\": true}"
  },
  "callbackType": "STREAM",
  "openSpaceId": "dtv1.card//IM_ROBOT.<staffId>",
  "imGroupOpenSpaceModel": { "supportForward": true },
  "imRobotOpenSpaceModel": { "supportForward": true },
  "imRobotOpenDeliverModel": { "spaceType": "IM_ROBOT" }
}

应为:

"cardData": {
  "cardParamMap": { "content": "", "query": "", "config": "{\"autoLayout\": true}" }
}

代码定位(master 与 v4.10.6 一致):

  • src/langbot/libs/dingtalk_api/api.py:631-633
cardData: dict = {'cardParamMap': _stringify_card_param_map(card_param_map)}
if card_data_config is not None:
    cardData['config'] = json.dumps(card_data_config)

这是一处回归。 #1952 最初的实现是正确的:

card_data['config'] = json.dumps({'autoLayout': card_auto_layout})
card_data['content'] = ''

彼时 card_data 会被 dingtalk_stream.AICardReplier 整体作为 cardParamMap 提交(见官方 SDK dingtalk_stream/card_replier.py,四处投放/更新接口一律是 "cardData": {"cardParamMap": card_data})。#2226(commit 0755beeb,"feat: add supports for dify hitl")把 AICardReplier 替换为自建的 create_and_deliver_card 时,把 config 从 cardParamMap 提到了 cardData 顶层,宽屏配置自此失效。

复现步骤

  1. 在钉钉卡片平台的 AI 卡片模板中新增对象变量 config,添加布尔子属性 autoLayout(即 [Feature]: 钉钉AI卡片请支持PC端宽屏配置 #1924 评论中的截图做法),发布模板;
  2. 钉钉适配器填入该模板 ID,开启「启用钉钉卡片流式回复模式」与「卡片宽屏自动布局」;
  3. 在 PC 端钉钉单聊里向机器人提问,让它输出一段较长的回复;
  4. 观察卡片宽度:仍为窄栏,未启用宽屏;
  5. 对照日志中 DingTalk createAndDeliver request body,可见 configcardParamMap 平级。

建议修复

config 并入 cardParamMap_stringify_card_param_map() 已经会把 dict 正确编码成 JSON 字符串,因此不需要额外的 json.dumps

merged_param_map = dict(card_param_map or {})
if card_data_config is not None:
    merged_param_map['config'] = card_data_config
cardData: dict = {'cardParamMap': _stringify_card_param_map(merged_param_map)}

src/langbot/pkg/platform/sources/dingtalk.py:1131(human input 卡片路径)复用同一个 card_data_config 参数,一并生效。

需要注意的是,宽屏生效仍要求用户在卡片模板中声明 config 变量(#1924@o1298098 已确认:只在卡片上静态配置不会触发,必须在投放时传入变量值),这一点值得在配置项说明里补一句。

启用的插件

两个自研插件(命令入口 + KnowledgeEngine),均不参与卡片投放;问题位于适配器层,上述请求体日志可直接佐证。

Metadata

Metadata

Assignees

Labels

bug?Bug或Bug修复相关 / maybe a bug

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions