@soimy/dingtalk 3.6.1 → 3.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/dist/index.d.ts +14 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +14603 -0
  4. package/dist/index.js.map +7 -0
  5. package/dist/src/access-control.d.ts +43 -0
  6. package/dist/src/access-control.d.ts.map +1 -0
  7. package/dist/src/ack-reaction/dynamic-ack-reaction-controller.d.ts +22 -0
  8. package/dist/src/ack-reaction/dynamic-ack-reaction-controller.d.ts.map +1 -0
  9. package/dist/src/ack-reaction/dynamic-ack-reaction-events.d.ts +36 -0
  10. package/dist/src/ack-reaction/dynamic-ack-reaction-events.d.ts.map +1 -0
  11. package/dist/src/ack-reaction/dynamic-ack-reaction-progress.d.ts +7 -0
  12. package/dist/src/ack-reaction/dynamic-ack-reaction-progress.d.ts.map +1 -0
  13. package/dist/src/ack-reaction-classifier.d.ts +8 -0
  14. package/dist/src/ack-reaction-classifier.d.ts.map +1 -0
  15. package/dist/src/ack-reaction-service.d.ts +15 -0
  16. package/dist/src/ack-reaction-service.d.ts.map +1 -0
  17. package/dist/src/auth.d.ts +7 -0
  18. package/dist/src/auth.d.ts.map +1 -0
  19. package/dist/src/card/card-action-handler.d.ts +14 -0
  20. package/dist/src/card/card-action-handler.d.ts.map +1 -0
  21. package/dist/src/card/card-markdown-image-reroute.d.ts +16 -0
  22. package/dist/src/card/card-markdown-image-reroute.d.ts.map +1 -0
  23. package/dist/src/card/card-run-registry.d.ts +60 -0
  24. package/dist/src/card/card-run-registry.d.ts.map +1 -0
  25. package/dist/src/card/card-stop-handler.d.ts +18 -0
  26. package/dist/src/card/card-stop-handler.d.ts.map +1 -0
  27. package/dist/src/card/card-streaming-mode.d.ts +8 -0
  28. package/dist/src/card/card-streaming-mode.d.ts.map +1 -0
  29. package/dist/src/card/card-template.d.ts +21 -0
  30. package/dist/src/card/card-template.d.ts.map +1 -0
  31. package/dist/src/card/reasoning-answer-split.d.ts +6 -0
  32. package/dist/src/card/reasoning-answer-split.d.ts.map +1 -0
  33. package/dist/src/card/reasoning-block-assembler.d.ts +7 -0
  34. package/dist/src/card/reasoning-block-assembler.d.ts.map +1 -0
  35. package/dist/src/card/statusline-renderer.d.ts +24 -0
  36. package/dist/src/card/statusline-renderer.d.ts.map +1 -0
  37. package/dist/src/card-callback-service.d.ts +23 -0
  38. package/dist/src/card-callback-service.d.ts.map +1 -0
  39. package/dist/src/card-draft-controller.d.ts +75 -0
  40. package/dist/src/card-draft-controller.d.ts.map +1 -0
  41. package/dist/src/card-service.d.ts +99 -0
  42. package/dist/src/card-service.d.ts.map +1 -0
  43. package/dist/src/channel.d.ts +10 -0
  44. package/dist/src/channel.d.ts.map +1 -0
  45. package/dist/src/command/card-stop-command.d.ts +30 -0
  46. package/dist/src/command/card-stop-command.d.ts.map +1 -0
  47. package/dist/src/command/inbound-command-dispatch-service.d.ts +40 -0
  48. package/dist/src/command/inbound-command-dispatch-service.d.ts.map +1 -0
  49. package/dist/src/config-schema.d.ts +8 -0
  50. package/dist/src/config-schema.d.ts.map +1 -0
  51. package/dist/src/config.d.ts +60 -0
  52. package/dist/src/config.d.ts.map +1 -0
  53. package/dist/src/connection-manager.d.ts +148 -0
  54. package/dist/src/connection-manager.d.ts.map +1 -0
  55. package/dist/src/dedup.d.ts +4 -0
  56. package/dist/src/dedup.d.ts.map +1 -0
  57. package/dist/src/device-registration.d.ts +16 -0
  58. package/dist/src/device-registration.d.ts.map +1 -0
  59. package/dist/src/docs-service.d.ts +12 -0
  60. package/dist/src/docs-service.d.ts.map +1 -0
  61. package/dist/src/draft-stream-loop.d.ts +28 -0
  62. package/dist/src/draft-stream-loop.d.ts.map +1 -0
  63. package/dist/src/feedback-learning-service.d.ts +123 -0
  64. package/dist/src/feedback-learning-service.d.ts.map +1 -0
  65. package/dist/src/feedback-learning-store.d.ts +181 -0
  66. package/dist/src/feedback-learning-store.d.ts.map +1 -0
  67. package/dist/src/gateway/channel-gateway.d.ts +4 -0
  68. package/dist/src/gateway/channel-gateway.d.ts.map +1 -0
  69. package/dist/src/http-client.d.ts +9 -0
  70. package/dist/src/http-client.d.ts.map +1 -0
  71. package/dist/src/inbound-handler.d.ts +9 -0
  72. package/dist/src/inbound-handler.d.ts.map +1 -0
  73. package/dist/src/learning-command-service.d.ts +64 -0
  74. package/dist/src/learning-command-service.d.ts.map +1 -0
  75. package/dist/src/logger-context.d.ts +10 -0
  76. package/dist/src/logger-context.d.ts.map +1 -0
  77. package/dist/src/media-utils.d.ts +63 -0
  78. package/dist/src/media-utils.d.ts.map +1 -0
  79. package/dist/src/message-context-store.d.ts +126 -0
  80. package/dist/src/message-context-store.d.ts.map +1 -0
  81. package/dist/src/message-utils.d.ts +12 -0
  82. package/dist/src/message-utils.d.ts.map +1 -0
  83. package/dist/src/messaging/attachment-text-extractor.d.ts +13 -0
  84. package/dist/src/messaging/attachment-text-extractor.d.ts.map +1 -0
  85. package/dist/src/messaging/btw-deliver.d.ts +42 -0
  86. package/dist/src/messaging/btw-deliver.d.ts.map +1 -0
  87. package/dist/src/messaging/channel-actions.d.ts +3 -0
  88. package/dist/src/messaging/channel-actions.d.ts.map +1 -0
  89. package/dist/src/messaging/channel-outbound.d.ts +3 -0
  90. package/dist/src/messaging/channel-outbound.d.ts.map +1 -0
  91. package/dist/src/messaging/quoted-context.d.ts +36 -0
  92. package/dist/src/messaging/quoted-context.d.ts.map +1 -0
  93. package/dist/src/messaging/quoted-file-service.d.ts +25 -0
  94. package/dist/src/messaging/quoted-file-service.d.ts.map +1 -0
  95. package/dist/src/messaging/quoted-ref.d.ts +12 -0
  96. package/dist/src/messaging/quoted-ref.d.ts.map +1 -0
  97. package/dist/src/onboarding.d.ts +4 -0
  98. package/dist/src/onboarding.d.ts.map +1 -0
  99. package/dist/src/path-utils.d.ts +3 -0
  100. package/dist/src/path-utils.d.ts.map +1 -0
  101. package/dist/src/peer-id-registry.d.ts +35 -0
  102. package/dist/src/peer-id-registry.d.ts.map +1 -0
  103. package/dist/src/persistence-store.d.ts +27 -0
  104. package/dist/src/persistence-store.d.ts.map +1 -0
  105. package/dist/src/platform/channel-status.d.ts +3 -0
  106. package/dist/src/platform/channel-status.d.ts.map +1 -0
  107. package/dist/src/plugin-sdk-channel-actions-augment.d.ts +7 -0
  108. package/dist/src/plugin-sdk-channel-actions-augment.d.ts.map +1 -0
  109. package/dist/src/proactive-risk-registry.d.ts +22 -0
  110. package/dist/src/proactive-risk-registry.d.ts.map +1 -0
  111. package/dist/src/reply-strategy-card.d.ts +14 -0
  112. package/dist/src/reply-strategy-card.d.ts.map +1 -0
  113. package/dist/src/reply-strategy-markdown.d.ts +10 -0
  114. package/dist/src/reply-strategy-markdown.d.ts.map +1 -0
  115. package/dist/src/reply-strategy-types.d.ts +85 -0
  116. package/dist/src/reply-strategy-types.d.ts.map +1 -0
  117. package/dist/src/reply-strategy-with-reaction.d.ts +47 -0
  118. package/dist/src/reply-strategy-with-reaction.d.ts.map +1 -0
  119. package/dist/src/reply-strategy.d.ts +14 -0
  120. package/dist/src/reply-strategy.d.ts.map +1 -0
  121. package/dist/src/run-usage-store.d.ts +15 -0
  122. package/dist/src/run-usage-store.d.ts.map +1 -0
  123. package/dist/src/runtime.d.ts +4 -0
  124. package/dist/src/runtime.d.ts.map +1 -0
  125. package/dist/src/secret-input.d.ts +42 -0
  126. package/dist/src/secret-input.d.ts.map +1 -0
  127. package/dist/src/send-service.d.ts +46 -0
  128. package/dist/src/send-service.d.ts.map +1 -0
  129. package/dist/src/session-command-service.d.ts +35 -0
  130. package/dist/src/session-command-service.d.ts.map +1 -0
  131. package/dist/src/session-lock.d.ts +11 -0
  132. package/dist/src/session-lock.d.ts.map +1 -0
  133. package/dist/src/session-peer-store.d.ts +21 -0
  134. package/dist/src/session-peer-store.d.ts.map +1 -0
  135. package/dist/src/session-routing.d.ts +14 -0
  136. package/dist/src/session-routing.d.ts.map +1 -0
  137. package/dist/src/session-state.d.ts +13 -0
  138. package/dist/src/session-state.d.ts.map +1 -0
  139. package/dist/src/signature.d.ts +6 -0
  140. package/dist/src/signature.d.ts.map +1 -0
  141. package/dist/src/targeting/agent-name-matcher.d.ts +63 -0
  142. package/dist/src/targeting/agent-name-matcher.d.ts.map +1 -0
  143. package/dist/src/targeting/agent-routing.d.ts +72 -0
  144. package/dist/src/targeting/agent-routing.d.ts.map +1 -0
  145. package/dist/src/targeting/group-members-store.d.ts +3 -0
  146. package/dist/src/targeting/group-members-store.d.ts.map +1 -0
  147. package/dist/src/targeting/target-directory-adapter.d.ts +13 -0
  148. package/dist/src/targeting/target-directory-adapter.d.ts.map +1 -0
  149. package/dist/src/targeting/target-directory-store.d.ts +45 -0
  150. package/dist/src/targeting/target-directory-store.d.ts.map +1 -0
  151. package/dist/src/targeting/target-input.d.ts +3 -0
  152. package/dist/src/targeting/target-input.d.ts.map +1 -0
  153. package/dist/src/types.d.ts +730 -0
  154. package/dist/src/types.d.ts.map +1 -0
  155. package/dist/src/utils.d.ts +54 -0
  156. package/dist/src/utils.d.ts.map +1 -0
  157. package/index.ts +234 -16
  158. package/openclaw.plugin.json +5 -5
  159. package/package.json +26 -5
  160. package/src/device-registration.ts +0 -32
  161. package/src/gateway/channel-gateway.ts +1 -1
  162. package/src/onboarding.ts +3 -7
  163. package/src/secret-input.ts +13 -47
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../index.ts", "../src/secret-input.ts", "../src/path-utils.ts", "../src/config.ts", "../src/http-client.ts", "../src/utils.ts", "../src/auth.ts", "../src/channel.ts", "../src/config-schema.ts", "../src/persistence-store.ts", "../src/message-context-store.ts", "../src/gateway/channel-gateway.ts", "../src/card-callback-service.ts", "../src/card/card-run-registry.ts", "../src/card-service.ts", "../src/card/card-template.ts", "../src/peer-id-registry.ts", "../src/logger-context.ts", "../src/types.ts", "../src/command/card-stop-command.ts", "../src/runtime.ts", "../src/card/card-stop-handler.ts", "../src/card/card-action-handler.ts", "../src/connection-manager.ts", "../src/dedup.ts", "../src/feedback-learning-service.ts", "../src/feedback-learning-store.ts", "../src/inbound-handler.ts", "../src/access-control.ts", "../src/ack-reaction-classifier.ts", "../src/ack-reaction-service.ts", "../src/ack-reaction/dynamic-ack-reaction-events.ts", "../src/ack-reaction/dynamic-ack-reaction-progress.ts", "../src/ack-reaction/dynamic-ack-reaction-controller.ts", "../src/card/statusline-renderer.ts", "../src/learning-command-service.ts", "../src/session-command-service.ts", "../src/command/inbound-command-dispatch-service.ts", "../src/media-utils.ts", "../src/message-utils.ts", "../src/messaging/attachment-text-extractor.ts", "../src/send-service.ts", "../src/proactive-risk-registry.ts", "../src/messaging/btw-deliver.ts", "../src/messaging/quoted-ref.ts", "../src/messaging/quoted-context.ts", "../src/messaging/quoted-file-service.ts", "../src/card/reasoning-answer-split.ts", "../src/card/reasoning-block-assembler.ts", "../src/card/card-streaming-mode.ts", "../src/card/card-markdown-image-reroute.ts", "../src/draft-stream-loop.ts", "../src/card-draft-controller.ts", "../src/session-state.ts", "../src/run-usage-store.ts", "../src/reply-strategy-card.ts", "../src/reply-strategy-markdown.ts", "../src/reply-strategy.ts", "../src/session-lock.ts", "../src/session-peer-store.ts", "../src/session-routing.ts", "../src/targeting/agent-name-matcher.ts", "../src/targeting/agent-routing.ts", "../src/targeting/group-members-store.ts", "../src/targeting/target-directory-store.ts", "../src/onboarding.ts", "../src/device-registration.ts", "../src/messaging/channel-actions.ts", "../src/messaging/channel-outbound.ts", "../src/targeting/target-directory-adapter.ts", "../src/platform/channel-status.ts", "../src/targeting/target-input.ts", "../src/docs-service.ts"],
4
+ "sourcesContent": ["import { defineChannelPluginEntry, type OpenClawPluginApi } from \"openclaw/plugin-sdk/core\";\nimport { readStringParam } from \"openclaw/plugin-sdk/param-readers\";\nimport { getAccessToken } from \"./src/auth\";\nimport { dingtalkPlugin } from \"./src/channel\";\nimport { getConfig, listDingTalkAccountIds, resolveDingTalkAccount } from \"./src/config\";\nimport {\n appendToDoc,\n createDoc,\n DocCreateAppendError,\n listDocs,\n searchDocs,\n} from \"./src/docs-service\";\nimport { accumulateUsage } from \"./src/run-usage-store\";\nimport { setDingTalkRuntime } from \"./src/runtime\";\nimport { sendMessage } from \"./src/send-service\";\n\ntype GatewayMethodContext = Pick<\n Parameters<Parameters<OpenClawPluginApi[\"registerGatewayMethod\"]>[1]>[0],\n \"context\" | \"params\" | \"respond\"\n>;\n\n/**\n * Register the canonical OpenClaw DingTalk docs RPC namespace.\n *\n * The `dingtalk-connector.docs.*` names below are compatibility aliases for\n * existing connector-style Gateway callers that already use the\n * `dingtalk-connector` prefix. They intentionally share the same handlers as\n * `dingtalk.docs.*`; this plugin does not vendor or mirror a separate\n * third-party connector implementation. New OpenClaw callers should prefer the\n * canonical `dingtalk.docs.*` namespace.\n */\nfunction registerDingTalkDocsGatewayMethods(api: OpenClawPluginApi): void {\n const createHandler = async ({ respond, params }: GatewayMethodContext) => {\n const accountId = readStringParam(params, \"accountId\");\n const spaceId = readStringParam(params, \"spaceId\", { required: true });\n const title = readStringParam(params, \"title\", { required: true });\n const content = readStringParam(params, \"content\", { allowEmpty: true });\n const parentId = readStringParam(params, \"parentId\");\n const config = getConfig(api.config, accountId ?? undefined);\n try {\n const doc = await createDoc(\n config,\n spaceId,\n title,\n content ?? undefined,\n api.logger,\n parentId ?? undefined,\n );\n return respond(true, doc);\n } catch (error) {\n if (error instanceof DocCreateAppendError) {\n return respond(true, {\n partialSuccess: true,\n initContentAppended: false,\n docId: error.doc.docId,\n doc: error.doc,\n appendError: error.message,\n });\n }\n throw error;\n }\n };\n\n const appendHandler = async ({ respond, params }: GatewayMethodContext) => {\n const accountId = readStringParam(params, \"accountId\");\n const docId = readStringParam(params, \"docId\", { required: true });\n const content = readStringParam(params, \"content\", { required: true, allowEmpty: false });\n const config = getConfig(api.config, accountId ?? undefined);\n const result = await appendToDoc(config, docId, content, api.logger);\n return respond(true, result);\n };\n\n const searchHandler = async ({ respond, params }: GatewayMethodContext) => {\n const accountId = readStringParam(params, \"accountId\");\n const keyword = readStringParam(params, \"keyword\", { required: true });\n const spaceId = readStringParam(params, \"spaceId\");\n const config = getConfig(api.config, accountId ?? undefined);\n const docs = await searchDocs(config, keyword, spaceId, api.logger);\n return respond(true, { docs });\n };\n\n const listHandler = async ({ respond, params }: GatewayMethodContext) => {\n const accountId = readStringParam(params, \"accountId\");\n const spaceId = readStringParam(params, \"spaceId\", { required: true });\n const parentId = readStringParam(params, \"parentId\");\n const config = getConfig(api.config, accountId ?? undefined);\n const docs = await listDocs(config, spaceId, parentId, api.logger);\n return respond(true, { docs });\n };\n\n api.registerGatewayMethod(\"dingtalk.docs.create\", createHandler);\n api.registerGatewayMethod(\"dingtalk.docs.append\", appendHandler);\n api.registerGatewayMethod(\"dingtalk.docs.search\", searchHandler);\n api.registerGatewayMethod(\"dingtalk.docs.list\", listHandler);\n api.registerGatewayMethod(\"dingtalk-connector.docs.create\", createHandler);\n api.registerGatewayMethod(\"dingtalk-connector.docs.append\", appendHandler);\n api.registerGatewayMethod(\"dingtalk-connector.docs.search\", searchHandler);\n api.registerGatewayMethod(\"dingtalk-connector.docs.list\", listHandler);\n}\n\nfunction getContentParam(params: Record<string, unknown>): string | undefined {\n return readStringParam(params, \"content\") ?? readStringParam(params, \"message\");\n}\n\nfunction getErrorMessage(error: unknown, fallback: string): string {\n return error instanceof Error ? error.message : fallback;\n}\n\nfunction maskClientId(clientId: string | undefined): string | null {\n if (!clientId) {\n return null;\n }\n return clientId.length <= 4 ? \"****\" : `****${clientId.slice(-4)}`;\n}\n\nfunction isConnectorSendTarget(target: string): boolean {\n return /^(user|group):\\S+$/.test(target);\n}\n\nasync function sendGatewayMessage(params: {\n api: OpenClawPluginApi;\n respond: GatewayMethodContext[\"respond\"];\n accountId?: string;\n target: string;\n content: string;\n storePath?: string;\n useAICard?: unknown;\n}) {\n const config = getConfig(params.api.config, params.accountId);\n const accountId = params.accountId ?? \"default\";\n if (!config.clientId || !config.clientSecret) {\n return params.respond(false, { error: \"DingTalk not configured\" });\n }\n let result: Awaited<ReturnType<typeof sendMessage>>;\n try {\n result = await sendMessage(config, params.target, params.content, {\n log: params.api.logger,\n accountId,\n conversationId: params.target,\n storePath: params.storePath,\n forceMarkdown: params.useAICard === false,\n });\n } catch (error: unknown) {\n const message = getErrorMessage(error, \"send failed\");\n params.api.logger?.warn?.(`[DingTalk][GatewayRPC] send failed: ${message}`);\n return params.respond(false, { error: message });\n }\n return params.respond(\n result.ok,\n result.ok\n ? {\n ok: true,\n target: params.target,\n messageId: result.messageId ?? null,\n tracking: result.tracking ?? null,\n }\n : { error: result.error || \"send failed\" },\n );\n}\n\n/**\n * Register compatibility Gateway RPCs for connector-style DingTalk callers.\n *\n * Compatibility target: callers that address DingTalk through the historical\n * `dingtalk-connector.*` Gateway namespace. The maintenance boundary is only\n * this thin parameter/response adapter; canonical plugin behavior, auth, docs,\n * sending, and persistence remain implemented by this repository's existing\n * `dingtalk.*` services. Do not add connector-only behavior here unless it is\n * also documented as part of this compatibility surface.\n */\nfunction registerDingTalkConnectorCompatibilityGatewayMethods(api: OpenClawPluginApi): void {\n api.registerGatewayMethod(\n \"dingtalk-connector.sendToUser\",\n async ({ context, respond, params }: GatewayMethodContext) => {\n const accountId = readStringParam(params, \"accountId\");\n const userId = readStringParam(params, \"userId\", { required: true });\n const content = getContentParam(params);\n if (!content) {\n return respond(false, { error: \"content or message is required\" });\n }\n return sendGatewayMessage({\n api,\n respond,\n accountId: accountId ?? undefined,\n target: `user:${userId}`,\n content,\n storePath: context?.cronStorePath,\n useAICard: params.useAICard,\n });\n },\n );\n\n api.registerGatewayMethod(\n \"dingtalk-connector.sendToGroup\",\n async ({ context, respond, params }: GatewayMethodContext) => {\n const accountId = readStringParam(params, \"accountId\");\n const openConversationId = readStringParam(params, \"openConversationId\", { required: true });\n const content = getContentParam(params);\n if (!content) {\n return respond(false, { error: \"content or message is required\" });\n }\n return sendGatewayMessage({\n api,\n respond,\n accountId: accountId ?? undefined,\n target: `group:${openConversationId}`,\n content,\n storePath: context?.cronStorePath,\n useAICard: params.useAICard,\n });\n },\n );\n\n api.registerGatewayMethod(\n \"dingtalk-connector.send\",\n async ({ context, respond, params }: GatewayMethodContext) => {\n const accountId = readStringParam(params, \"accountId\");\n const target = readStringParam(params, \"target\", { required: true });\n const content = getContentParam(params);\n if (!content) {\n return respond(false, { error: \"content or message is required\" });\n }\n if (!isConnectorSendTarget(target)) {\n return respond(false, { error: \"target must start with user: or group:\" });\n }\n return sendGatewayMessage({\n api,\n respond,\n accountId: accountId ?? undefined,\n target,\n content,\n storePath: context?.cronStorePath,\n useAICard: params.useAICard,\n });\n },\n );\n\n api.registerGatewayMethod(\n \"dingtalk-connector.status\",\n async ({ respond }: GatewayMethodContext) => {\n const accountIds = listDingTalkAccountIds(api.config);\n const accounts = accountIds.length > 0 ? accountIds : [\"default\"];\n return respond(true, {\n channel: \"dingtalk\",\n accounts: accounts.map((accountId) => {\n const account = resolveDingTalkAccount(api.config, accountId);\n return {\n accountId,\n configured: account.configured,\n enabled: account.enabled !== false,\n name: account.name ?? null,\n clientId: maskClientId(account.clientId),\n };\n }),\n });\n },\n );\n\n api.registerGatewayMethod(\n \"dingtalk-connector.probe\",\n async ({ respond, params }: GatewayMethodContext) => {\n const accountId = readStringParam(params, \"accountId\");\n const config = getConfig(api.config, accountId ?? undefined);\n if (!config.clientId || !config.clientSecret) {\n return respond(false, { error: \"DingTalk not configured\" });\n }\n try {\n await getAccessToken(config, api.logger);\n return respond(true, { ok: true, clientId: maskClientId(config.clientId) });\n } catch (error: unknown) {\n const message = getErrorMessage(error, \"probe failed\");\n api.logger?.warn?.(`[DingTalk][GatewayRPC] probe failed: ${message}`);\n return respond(false, { error: message });\n }\n },\n );\n}\n\nexport { dingtalkPlugin } from \"./src/channel\";\nexport { setDingTalkRuntime } from \"./src/runtime\";\n\nexport default defineChannelPluginEntry({\n id: \"dingtalk\",\n name: \"DingTalk Channel\",\n description: \"DingTalk (\u9489\u9489) messaging channel via Stream mode\",\n plugin: dingtalkPlugin,\n setRuntime: setDingTalkRuntime,\n registerFull(api) {\n registerDingTalkDocsGatewayMethods(api);\n registerDingTalkConnectorCompatibilityGatewayMethods(api);\n\n api.on(\n \"llm_output\",\n (event: {\n runId: string;\n usage?: {\n input?: number;\n output?: number;\n cacheRead?: number;\n cacheWrite?: number;\n total?: number;\n };\n }) => {\n if (event.usage) {\n accumulateUsage(event.runId, event.usage);\n }\n },\n );\n },\n});\n", "import { readFile } from \"node:fs/promises\";\nimport { z } from \"zod\";\nimport { resolveRelativePath } from \"./path-utils\";\n\nexport type SecretInputRef = {\n source: \"env\" | \"file\";\n provider: string;\n id: string;\n};\n\nexport type SecretInput = string | SecretInputRef;\n\nexport type SecretInputResolutionFailure = {\n source: SecretInputRef[\"source\"];\n provider: string;\n id: string;\n reason: string;\n};\n\ntype SecretInputLog = {\n warn?: (message: string, data?: unknown) => void;\n};\n\nconst SECRET_INPUT_PROVIDER_PATTERN = /^[^:>]+$/;\nconst SECRET_INPUT_ID_PATTERN = /^[^>]+$/;\n\nfunction buildSecretInputFailure(\n value: SecretInputRef,\n reason: string,\n): SecretInputResolutionFailure {\n return {\n source: value.source,\n provider: value.provider,\n id: value.id,\n reason,\n };\n}\n\nexport function formatSecretInputResolutionFailure(failure: SecretInputResolutionFailure): string {\n return `${failure.source}:${failure.provider}:${failure.id} - ${failure.reason}`;\n}\n\nexport function buildSecretInputSchema() {\n return z.union([\n z.string(),\n z.object({\n source: z.enum([\"env\", \"file\"]),\n provider: z.string().min(1).max(1024).regex(SECRET_INPUT_PROVIDER_PATTERN),\n id: z.string().min(1).max(1024).regex(SECRET_INPUT_ID_PATTERN),\n }),\n ]);\n}\n\nexport function isSecretInputRef(value: unknown): value is SecretInputRef {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const ref = value as SecretInputRef;\n return (\n (ref.source === \"env\" || ref.source === \"file\") &&\n typeof ref.provider === \"string\" &&\n ref.provider.trim().length > 0 &&\n SECRET_INPUT_PROVIDER_PATTERN.test(ref.provider) &&\n typeof ref.id === \"string\" &&\n ref.id.trim().length > 0 &&\n SECRET_INPUT_ID_PATTERN.test(ref.id)\n );\n}\n\nexport function hasConfiguredSecretInput(value: unknown): boolean {\n if (typeof value === \"string\") {\n return value.trim().length > 0;\n }\n if (!isSecretInputRef(value)) {\n return false;\n }\n if (value.source === \"env\") {\n return Boolean(process.env[value.id]?.trim());\n }\n // File references are considered configured when the reference shape is\n // present. The actual filesystem lookup happens at runtime so status checks\n // can stay side-effect free.\n return true;\n}\n\nexport function normalizeSecretInputString(value: unknown): string | undefined {\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n return trimmed || undefined;\n }\n if (!isSecretInputRef(value)) {\n return undefined;\n }\n return `<${value.source}:${value.provider}:${value.id}>`;\n}\n\nexport function parseSecretInputString(value: unknown): SecretInput | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n if (!trimmed) {\n return undefined;\n }\n const match = trimmed.match(/^<(env|file):([^:>]+):([^>]+)>$/);\n if (!match) {\n return trimmed;\n }\n return {\n source: match[1] as SecretInputRef[\"source\"],\n provider: match[2],\n id: match[3],\n };\n}\n\nexport async function resolveSecretInputString(\n value: unknown,\n log?: SecretInputLog,\n): Promise<string | undefined> {\n return (await resolveSecretInputStringWithFailure(value, log)).value;\n}\n\nexport async function resolveSecretInputStringWithFailure(\n value: unknown,\n log?: SecretInputLog,\n): Promise<{ value?: string; failure?: SecretInputResolutionFailure }> {\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n return { value: trimmed || undefined };\n }\n if (!isSecretInputRef(value)) {\n return {};\n }\n if (value.source === \"env\") {\n const envValue = process.env[value.id]?.trim();\n if (envValue) {\n return { value: envValue };\n }\n const failure = buildSecretInputFailure(value, \"environment variable is not set or is empty\");\n log?.warn?.(\"[DingTalk][SecretInput] Failed to resolve env secret\", {\n provider: value.provider,\n id: value.id,\n error: failure.reason,\n });\n return { failure };\n }\n try {\n // Trust boundary: file SecretInput reads the configured local path. Use it\n // only with trusted plugin configuration.\n const filePath = resolveRelativePath(value.id);\n const secret = (await readFile(filePath, \"utf8\")).trim();\n if (secret) {\n return { value: secret };\n }\n return { failure: buildSecretInputFailure(value, \"file secret is empty\") };\n } catch (error) {\n const failure = buildSecretInputFailure(\n value,\n error instanceof Error ? error.message : String(error),\n );\n log?.warn?.(\"[DingTalk][SecretInput] Failed to read file secret\", {\n provider: value.provider,\n id: value.id,\n error: failure.reason,\n });\n return { failure };\n }\n}\n\nexport async function resolveDingTalkSecretConfig<T extends { clientSecret?: unknown }>(\n config: T,\n log?: SecretInputLog,\n): Promise<\n T & { clientSecret?: string; clientSecretResolutionFailure?: SecretInputResolutionFailure }\n> {\n const resolvedSecret = await resolveSecretInputStringWithFailure(config.clientSecret, log);\n return {\n ...config,\n clientSecret: resolvedSecret.value,\n clientSecretResolutionFailure: resolvedSecret.failure,\n };\n}\n", "import * as os from \"node:os\";\nimport * as path from \"node:path\";\n\nconst WINDOWS_ROOT_DIRECTORIES = new Set([\n \"Users\",\n \"Program Files\",\n \"Program Files (x86)\",\n \"ProgramData\",\n \"Windows\",\n \"Documents and Settings\",\n]);\n\nexport function resolveRelativePath(input: string): string {\n const trimmed = input.trim();\n if (!trimmed) {\n return trimmed;\n }\n\n const segments = (value: string): string[] => value.split(/[\\\\/]+/).filter(Boolean);\n const pathSegments = segments(trimmed);\n const firstSegment = pathSegments[0];\n\n if (trimmed === \"~\") {\n return path.resolve(os.homedir());\n }\n if (trimmed.startsWith(\"~/\") || trimmed.startsWith(\"~\\\\\")) {\n return path.resolve(os.homedir(), ...segments(trimmed.slice(2)));\n }\n\n if (process.platform === \"win32\") {\n if (/^[a-zA-Z]:[\\\\/]/.test(trimmed)) {\n return path.win32.normalize(trimmed);\n }\n if (firstSegment && /^[a-zA-Z]:$/.test(firstSegment)) {\n return path.win32.resolve(`${firstSegment}\\\\`, ...pathSegments.slice(1));\n }\n if (firstSegment && WINDOWS_ROOT_DIRECTORIES.has(firstSegment)) {\n return path.win32.resolve(\"\\\\\", ...pathSegments);\n }\n }\n\n if (/^[\\\\/]/.test(trimmed)) {\n return path.resolve(path.sep, ...pathSegments);\n }\n\n return path.resolve(process.cwd(), ...pathSegments);\n}\n\nexport const resolveUserPath = resolveRelativePath;\n", "import type { OpenClawConfig } from \"openclaw/plugin-sdk/core\";\nimport {\n formatSecretInputResolutionFailure,\n hasConfiguredSecretInput,\n resolveDingTalkSecretConfig,\n} from \"./secret-input\";\nimport type { DingTalkChannelConfig, DingTalkConfig } from \"./types\";\nexport { resolveRelativePath, resolveUserPath } from \"./path-utils\";\nconst DEFAULT_LEARNING_NOTE_TTL_MS = 6 * 60 * 60 * 1000;\nexport type RuntimeDingTalkConfig = Omit<DingTalkConfig, \"clientSecret\"> & { clientSecret: string };\n\nfunction normalizeLearningConfig(\n config: DingTalkConfig,\n options: { applyDefaults: boolean },\n): DingTalkConfig {\n return {\n ...config,\n learningEnabled: options.applyDefaults ? config.learningEnabled ?? false : config.learningEnabled,\n learningAutoApply: options.applyDefaults\n ? config.learningAutoApply ?? false\n : config.learningAutoApply,\n learningNoteTtlMs: options.applyDefaults\n ? config.learningNoteTtlMs ?? DEFAULT_LEARNING_NOTE_TTL_MS\n : config.learningNoteTtlMs,\n cardStreamingMode: options.applyDefaults\n ? (config.cardStreamingMode ?? (config.cardRealTimeStream === true ? \"all\" : \"off\"))\n : config.cardStreamingMode,\n };\n}\n\nfunction stripRemovedLegacyFields(config: DingTalkConfig): DingTalkConfig {\n const {\n verboseRealtimeStream: _verboseRealtimeStream,\n cardStreamReasoning: _cardStreamReasoning,\n accounts,\n ...rest\n } = config as DingTalkConfig & {\n verboseRealtimeStream?: unknown;\n cardStreamReasoning?: unknown;\n accounts?: Record<string, DingTalkConfig | undefined>;\n };\n const sanitizedAccounts = accounts\n ? Object.fromEntries(\n Object.entries(accounts).map(([accountId, accountConfig]) => [\n accountId,\n accountConfig ? stripRemovedLegacyFields(accountConfig) : accountConfig,\n ]),\n )\n : undefined;\n if (sanitizedAccounts) {\n return { ...rest, accounts: sanitizedAccounts } as DingTalkConfig;\n }\n return rest as DingTalkConfig;\n}\n\n/**\n * Merge channel-level defaults into an account-specific config.\n * Account-level values take precedence; `accounts` key is excluded to avoid recursion.\n */\nexport function mergeAccountWithDefaults(\n channelCfg: DingTalkConfig,\n accountCfg: DingTalkConfig,\n): DingTalkConfig {\n const { accounts: _accounts, ...defaultCandidate } =\n channelCfg as DingTalkConfig & { accounts?: unknown; verboseRealtimeStream?: unknown };\n const defaults = stripRemovedLegacyFields(defaultCandidate as DingTalkConfig);\n const normalizedAccountCfg = stripRemovedLegacyFields(\n normalizeLearningConfig(accountCfg, { applyDefaults: false }),\n );\n const overrides: Partial<DingTalkConfig> = {};\n for (const [key, value] of Object.entries(normalizedAccountCfg)) {\n if (value !== undefined) {\n Object.assign(overrides, { [key]: value });\n }\n }\n return normalizeLearningConfig(\n {\n ...defaults,\n ...overrides,\n },\n { applyDefaults: true },\n );\n}\n\n/**\n * Resolve DingTalk config for an account.\n * Named accounts inherit channel-level defaults with account-level overrides.\n * Falls back to top-level config for single-account setups.\n */\nexport function getConfig(cfg: OpenClawConfig, accountId?: string): DingTalkConfig {\n const dingtalkCfg = cfg?.channels?.dingtalk as DingTalkConfig | undefined;\n if (!dingtalkCfg) {\n return {} as DingTalkConfig;\n }\n\n if (accountId && dingtalkCfg.accounts?.[accountId]) {\n return mergeAccountWithDefaults(dingtalkCfg, dingtalkCfg.accounts[accountId]);\n }\n\n if (accountId) {\n return stripRemovedLegacyFields(normalizeLearningConfig(dingtalkCfg, { applyDefaults: true }));\n }\n\n if (dingtalkCfg.accounts && Object.keys(dingtalkCfg.accounts).length > 0) {\n return stripRemovedLegacyFields(dingtalkCfg);\n }\n\n return stripRemovedLegacyFields(normalizeLearningConfig(dingtalkCfg, { applyDefaults: true }));\n}\n\nexport function isConfigured(cfg: OpenClawConfig, accountId?: string): boolean {\n const config = getConfig(cfg, accountId);\n return Boolean(config.clientId && hasConfiguredSecretInput(config.clientSecret));\n}\n\nexport async function resolveRuntimeConfig(\n config: DingTalkConfig,\n log?: { warn?: (message: string, data?: unknown) => void },\n): Promise<RuntimeDingTalkConfig> {\n const resolved = await resolveDingTalkSecretConfig(config, log);\n if (!resolved.clientId || !resolved.clientSecret) {\n const secretFailure = resolved.clientSecretResolutionFailure\n ? `: clientSecret resolution failed for ${formatSecretInputResolutionFailure(resolved.clientSecretResolutionFailure)}`\n : \"\";\n throw new Error(`DingTalk clientId and resolved clientSecret are required${secretFailure}`);\n }\n return {\n ...resolved,\n clientSecret: resolved.clientSecret,\n };\n}\n\n/**\n * Resolve the robot code used by DingTalk APIs.\n * DingTalk robotCode is always equal to clientId; this helper trims whitespace.\n */\nexport function resolveRobotCode(config: Pick<DingTalkConfig, \"clientId\">): string {\n return (config.clientId || \"\").trim();\n}\n\nexport function resolveGroupConfig(\n cfg: DingTalkConfig,\n groupId: string,\n): { systemPrompt?: string; requireMention?: boolean; groupAllowFrom?: string[] } | undefined {\n // Group config supports exact match first, then wildcard fallback.\n const groups = cfg.groups;\n if (!groups) {\n return undefined;\n }\n return groups[groupId] || groups[\"*\"] || undefined;\n}\n\nfunction hasOwn(obj: unknown, key: string): boolean {\n return typeof obj === \"object\" && obj !== null && Object.prototype.hasOwnProperty.call(obj, key);\n}\n\nfunction resolveAgentIdentityEmoji(cfg: OpenClawConfig, agentId?: string | null): string | undefined {\n const targetAgentId = String(agentId || \"\").trim();\n if (!targetAgentId) {\n return undefined;\n }\n const agents = Array.isArray((cfg as any)?.agents?.list) ? (cfg as any).agents.list : [];\n const agent = agents.find((entry: any) => String(entry?.id || \"\").trim() === targetAgentId);\n const emoji = typeof agent?.identity?.emoji === \"string\" ? agent.identity.emoji.trim() : \"\";\n return emoji || undefined;\n}\n\nfunction normalizeAckReactionValue(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n if (!trimmed) {\n return \"\";\n }\n const normalized = trimmed.toLowerCase();\n if (normalized === \"off\") {\n return \"off\";\n }\n if (normalized === \"emoji\") {\n return \"emoji\";\n }\n if (normalized === \"kaomoji\") {\n return \"kaomoji\";\n }\n if (trimmed === \"\uD83E\uDD14\u601D\u8003\u4E2D\") {\n return \"emoji\";\n }\n return trimmed;\n}\n\nexport function resolveAckReactionSetting(params: {\n cfg: OpenClawConfig;\n accountId?: string | null;\n agentId?: string | null;\n}): string | undefined {\n const dingtalk = (params.cfg?.channels as any)?.dingtalk;\n const accountId = String(params.accountId || \"\").trim();\n const accountConfig =\n accountId && dingtalk?.accounts && typeof dingtalk.accounts === \"object\"\n ? dingtalk.accounts[accountId]\n : undefined;\n\n if (hasOwn(accountConfig, \"ackReaction\")) {\n return normalizeAckReactionValue(accountConfig.ackReaction);\n }\n if (hasOwn(dingtalk, \"ackReaction\")) {\n return normalizeAckReactionValue(dingtalk.ackReaction);\n }\n\n const messages = (params.cfg as any)?.messages;\n if (hasOwn(messages, \"ackReaction\")) {\n return normalizeAckReactionValue(messages.ackReaction);\n }\n\n return resolveAgentIdentityEmoji(params.cfg, params.agentId) || \"\uD83D\uDC40\";\n}\n\n/**\n * Strip group/user prefixes used by CLI targeting.\n * Returns raw DingTalk target ID and whether caller explicitly requested a user target.\n */\nexport function stripTargetPrefix(target: string): { targetId: string; isExplicitUser: boolean } {\n if (target.startsWith(\"group:\")) {\n return { targetId: target.slice(6), isExplicitUser: false };\n }\n if (target.startsWith(\"user:\")) {\n return { targetId: target.slice(5), isExplicitUser: true };\n }\n return { targetId: target, isExplicitUser: false };\n}\n\n// ============ Onboarding Helper Functions ============\n\nconst DEFAULT_ACCOUNT_ID = \"default\";\n\n\n/**\n * List all DingTalk account IDs from config\n */\nexport function listDingTalkAccountIds(cfg: OpenClawConfig): string[] {\n const dingtalk = cfg.channels?.dingtalk as DingTalkChannelConfig | undefined;\n if (!dingtalk) {\n return [];\n }\n\n const accountIds: string[] = [];\n\n if (dingtalk.clientId || dingtalk.clientSecret) {\n accountIds.push(DEFAULT_ACCOUNT_ID);\n }\n\n if (dingtalk.accounts) {\n accountIds.push(...Object.keys(dingtalk.accounts));\n }\n\n return accountIds;\n}\n\n/**\n * Resolved DingTalk account with configuration status\n */\nexport interface ResolvedDingTalkAccount extends DingTalkConfig {\n accountId: string;\n configured: boolean;\n}\n\n/**\n * Resolve a specific DingTalk account configuration\n */\nexport function resolveDingTalkAccount(\n cfg: OpenClawConfig,\n accountId?: string | null,\n): ResolvedDingTalkAccount {\n const id = accountId || DEFAULT_ACCOUNT_ID;\n const dingtalk = cfg.channels?.dingtalk as DingTalkChannelConfig | undefined;\n\n if (id === DEFAULT_ACCOUNT_ID) {\n const rawConfig: DingTalkConfig = {\n clientId: dingtalk?.clientId ?? \"\",\n clientSecret: dingtalk?.clientSecret ?? \"\",\n name: dingtalk?.name,\n enabled: dingtalk?.enabled,\n dmPolicy: dingtalk?.dmPolicy,\n groupPolicy: dingtalk?.groupPolicy,\n allowFrom: dingtalk?.allowFrom,\n groupAllowFrom: dingtalk?.groupAllowFrom,\n displayNameResolution: dingtalk?.displayNameResolution,\n contextVisibility: dingtalk?.contextVisibility,\n journalTTLDays: dingtalk?.journalTTLDays,\n ackReaction: dingtalk?.ackReaction,\n debug: dingtalk?.debug,\n messageType: dingtalk?.messageType,\n cardTemplateId: dingtalk?.cardTemplateId,\n cardTemplateKey: dingtalk?.cardTemplateKey,\n groups: dingtalk?.groups,\n accounts: dingtalk?.accounts,\n maxConnectionAttempts: dingtalk?.maxConnectionAttempts,\n initialReconnectDelay: dingtalk?.initialReconnectDelay,\n maxReconnectDelay: dingtalk?.maxReconnectDelay,\n reconnectJitter: dingtalk?.reconnectJitter,\n maxReconnectCycles: dingtalk?.maxReconnectCycles,\n reconnectDeadlineMs: dingtalk?.reconnectDeadlineMs,\n useConnectionManager: dingtalk?.useConnectionManager,\n mediaMaxMb: dingtalk?.mediaMaxMb,\n keepAlive: dingtalk?.keepAlive,\n bypassProxyForSend: dingtalk?.bypassProxyForSend,\n proactivePermissionHint: dingtalk?.proactivePermissionHint,\n cardStreamingMode: dingtalk?.cardStreamingMode,\n cardRealTimeStream: dingtalk?.cardRealTimeStream,\n cardStreamInterval: dingtalk?.cardStreamInterval,\n aicardDegradeMs: dingtalk?.aicardDegradeMs,\n learningEnabled: dingtalk?.learningEnabled,\n learningAutoApply: dingtalk?.learningAutoApply,\n learningNoteTtlMs: dingtalk?.learningNoteTtlMs,\n convertMarkdownTables: dingtalk?.convertMarkdownTables,\n cardAtSender: dingtalk?.cardAtSender,\n };\n const config = stripRemovedLegacyFields(rawConfig);\n return {\n ...config,\n accountId: id,\n configured: Boolean(config.clientId && hasConfiguredSecretInput(config.clientSecret)),\n };\n }\n\n const accountConfig = dingtalk?.accounts?.[id];\n if (accountConfig) {\n const merged = mergeAccountWithDefaults(\n dingtalk as DingTalkConfig,\n accountConfig,\n );\n const publicMerged = stripRemovedLegacyFields(merged);\n return {\n ...publicMerged,\n accountId: id,\n configured: Boolean(merged.clientId && hasConfiguredSecretInput(merged.clientSecret)),\n };\n }\n\n return {\n clientId: \"\",\n clientSecret: \"\",\n accountId: id,\n configured: false,\n };\n}\n", "import axios from \"axios\";\nimport type { AxiosInstance } from \"axios\";\n\nexport const DEFAULT_HTTP_TIMEOUT_MS = 10_000;\n\ntype AxiosInstanceWithGuards = AxiosInstance & {\n isAxiosError: typeof axios.isAxiosError;\n};\n\n// Centralize repo-level axios policy without mutating the global axios singleton\n// that third-party dependencies may also share.\nconst httpClient = (\n typeof axios?.create === \"function\"\n ? axios.create({ timeout: DEFAULT_HTTP_TIMEOUT_MS })\n : axios\n) as AxiosInstanceWithGuards;\n\nhttpClient.isAxiosError = axios.isAxiosError;\n\nexport default httpClient;\n", "import * as dns from \"node:dns\";\nimport * as fs from \"node:fs\";\nimport * as net from \"node:net\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { Logger, RetryOptions } from \"./types\";\n\ntype PluginDebugLogParams = {\n accountId: string;\n storePath?: string;\n debug?: boolean;\n baseLog?: Logger;\n now?: () => Date;\n fsImpl?: Pick<typeof fs, \"appendFileSync\" | \"mkdirSync\">;\n};\n\ntype PluginDebugWriter = {\n filePath: string;\n warned: boolean;\n directoryReady: boolean;\n};\n\nconst pluginDebugWriters = new Map<string, PluginDebugWriter>();\nconst closedPluginDebugScopes = new Set<string>();\n\nfunction padNumber(value: number, width = 2): string {\n return String(value).padStart(width, \"0\");\n}\n\nfunction formatTimezoneOffset(date: Date): string {\n const offsetMinutes = -date.getTimezoneOffset();\n const sign = offsetMinutes >= 0 ? \"+\" : \"-\";\n const absoluteMinutes = Math.abs(offsetMinutes);\n const hours = Math.floor(absoluteMinutes / 60);\n const minutes = absoluteMinutes % 60;\n return `${sign}${padNumber(hours)}:${padNumber(minutes)}`;\n}\n\nfunction formatPluginDebugTimestamp(date: Date): string {\n return `${date.getFullYear()}-${padNumber(date.getMonth() + 1)}-${padNumber(date.getDate())} ${padNumber(date.getHours())}:${padNumber(date.getMinutes())}:${padNumber(date.getSeconds())}.${padNumber(date.getMilliseconds(), 3)}${formatTimezoneOffset(date)}`;\n}\n\nfunction formatPluginDebugDate(date: Date): string {\n return `${date.getFullYear()}-${padNumber(date.getMonth() + 1)}-${padNumber(date.getDate())}`;\n}\n\nfunction resolvePluginDebugLogFilePath(params: { storePath: string; accountId: string; date: Date }): string {\n return path.join(\n path.dirname(params.storePath),\n \"logs\",\n \"dingtalk\",\n params.accountId,\n `debug-${formatPluginDebugDate(params.date)}.log`,\n );\n}\n\nfunction formatPluginDebugLine(params: { accountId: string; date: Date; message: string }): string {\n return `[${formatPluginDebugTimestamp(params.date)}] [debug] [dingtalk] [account:${params.accountId}] ${params.message}`;\n}\n\nfunction buildPluginDebugWriterKey(params: { storePath: string; accountId: string; date: Date }): string {\n return JSON.stringify([params.storePath, params.accountId, formatPluginDebugDate(params.date)]);\n}\n\nfunction buildPluginDebugScopeKey(params: { storePath: string; accountId: string }): string {\n return JSON.stringify([params.storePath, params.accountId]);\n}\n\nfunction resolvePluginDebugWriter(params: {\n storePath: string;\n accountId: string;\n date: Date;\n}): PluginDebugWriter {\n const key = buildPluginDebugWriterKey(params);\n const existing = pluginDebugWriters.get(key);\n if (existing) {\n return existing;\n }\n\n const created = {\n filePath: resolvePluginDebugLogFilePath(params),\n warned: false,\n directoryReady: false,\n };\n pluginDebugWriters.set(key, created);\n return created;\n}\n\nexport function resolvePluginDebugLog(params: PluginDebugLogParams): Logger {\n const baseLog = params.baseLog;\n const fsImpl = params.fsImpl ?? fs;\n const scopeKey = params.storePath\n ? buildPluginDebugScopeKey({ storePath: params.storePath, accountId: params.accountId })\n : undefined;\n\n if (scopeKey) {\n closedPluginDebugScopes.delete(scopeKey);\n }\n\n return {\n debug: (message: string) => {\n if (!params.debug) {\n baseLog?.debug?.(message);\n return;\n }\n\n const date = params.now ? params.now() : new Date();\n const line = formatPluginDebugLine({\n accountId: params.accountId,\n date,\n message,\n });\n\n try {\n process.stdout.write(`${line}\\n`);\n } catch {\n // Ignore stdout failures so plugin debug logging never breaks message handling.\n }\n\n if (params.storePath && scopeKey && !closedPluginDebugScopes.has(scopeKey)) {\n const writer = resolvePluginDebugWriter({\n storePath: params.storePath,\n accountId: params.accountId,\n date,\n });\n try {\n if (!writer.directoryReady) {\n fsImpl.mkdirSync(path.dirname(writer.filePath), { recursive: true });\n writer.directoryReady = true;\n }\n fsImpl.appendFileSync(writer.filePath, `${line}\\n`, \"utf8\");\n } catch (err) {\n if (!writer.warned) {\n writer.warned = true;\n baseLog?.warn?.(\n `[DingTalk] Plugin debug log file unavailable: accountId=${params.accountId} path=${writer.filePath} error=${getErrorMessage(err)}`,\n );\n }\n }\n }\n\n try {\n baseLog?.debug?.(message);\n } catch {\n // Ignore upstream debug failures so plugin-owned debug remains best-effort.\n }\n },\n info: (message: string) => baseLog?.info?.(message),\n warn: (message: string) => baseLog?.warn?.(message),\n error: (message: string) => baseLog?.error?.(message),\n };\n}\n\nexport function closePluginDebugLog(params: { accountId: string; storePath?: string }): void {\n if (!params.storePath) {\n return;\n }\n\n const scopeKey = buildPluginDebugScopeKey({\n storePath: params.storePath,\n accountId: params.accountId,\n });\n closedPluginDebugScopes.add(scopeKey);\n\n for (const key of pluginDebugWriters.keys()) {\n const [writerStorePath, writerAccountId] = JSON.parse(key) as [string, string, string];\n if (writerStorePath === params.storePath && writerAccountId === params.accountId) {\n pluginDebugWriters.delete(key);\n }\n }\n}\n\n/**\n * Mask sensitive fields in data for safe logging\n * Prevents PII leakage in debug logs\n */\nexport function maskSensitiveData(data: unknown): any {\n if (data === null || data === undefined) {\n return data;\n }\n\n if (typeof data !== \"object\") {\n return data as string | number;\n }\n\n const masked = JSON.parse(JSON.stringify(data)) as Record<string, unknown>;\n const sensitiveFields = new Set([\"token\", \"accessToken\"]);\n\n function maskObj(obj: Record<string, unknown>): void {\n for (const key in obj) {\n if (sensitiveFields.has(key)) {\n const val = obj[key];\n if (typeof val === \"string\" && val.length > 6) {\n obj[key] = val.slice(0, 3) + \"*\".repeat(val.length - 6) + val.slice(-3);\n } else if (typeof val === \"string\") {\n obj[key] = \"*\".repeat(val.length);\n }\n } else if (typeof obj[key] === \"object\" && obj[key] !== null && !Array.isArray(obj[key])) {\n maskObj(obj[key] as Record<string, unknown>);\n }\n }\n }\n\n maskObj(masked);\n return masked;\n}\n\nexport function stringifyUnknown(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n if (\n typeof value === \"number\" ||\n typeof value === \"boolean\" ||\n typeof value === \"bigint\"\n ) {\n return String(value);\n }\n try {\n const serialized = JSON.stringify(value);\n return serialized ?? String(value);\n } catch {\n return \"[unserializable]\";\n }\n}\n\nexport function parseBooleanLike(value: unknown): boolean | undefined {\n if (typeof value === \"boolean\") {\n return value;\n }\n if (typeof value === \"number\") {\n if (value === 1) {\n return true;\n }\n if (value === 0) {\n return false;\n }\n return undefined;\n }\n if (typeof value === \"string\") {\n const normalized = value.trim().toLowerCase();\n if ([\"1\", \"true\", \"yes\", \"y\", \"on\"].includes(normalized)) {\n return true;\n }\n if ([\"0\", \"false\", \"no\", \"n\", \"off\"].includes(normalized)) {\n return false;\n }\n }\n return undefined;\n}\n\nexport function getErrorMessage(err: unknown): string {\n if (err instanceof Error && err.message) {\n return err.message;\n }\n if (err && typeof err === \"object\") {\n const record = err as Record<string, unknown>;\n if (typeof record.message === \"string\" && record.message.trim()) {\n return record.message;\n }\n }\n return stringifyUnknown(err);\n}\n\nexport function getErrorResponseData(err: unknown): unknown {\n if (!err || typeof err !== \"object\") {\n return undefined;\n }\n return (err as { response?: { data?: unknown } }).response?.data;\n}\n\nexport function formatDingTalkErrorPayload(payload: unknown): string {\n if (payload === null || payload === undefined) {\n return \"payload=unknown\";\n }\n\n let code: string | undefined;\n let message: string | undefined;\n if (typeof payload === \"object\" && !Array.isArray(payload)) {\n const obj = payload as Record<string, unknown>;\n if (typeof obj.code === \"string\" || typeof obj.code === \"number\") {\n code = String(obj.code);\n }\n if (typeof obj.message === \"string\") {\n message = obj.message;\n }\n }\n\n let serialized: string;\n try {\n serialized = JSON.stringify(maskSensitiveData(payload));\n } catch {\n if (typeof payload === \"string\") {\n serialized = payload;\n } else if (typeof payload === \"number\" || typeof payload === \"boolean\" || typeof payload === \"bigint\") {\n serialized = `${payload}`;\n } else {\n serialized = \"[unserializable-payload]\";\n }\n }\n\n const parts: string[] = [];\n if (code) {\n parts.push(`code=${code}`);\n }\n if (message) {\n parts.push(`message=${message}`);\n }\n parts.push(`payload=${serialized}`);\n return parts.join(\" \");\n}\n\nexport function formatDingTalkErrorPayloadLog(\n scope: string,\n payload: unknown,\n prefix: \"[DingTalk]\" | \"[DingTalk][AICard]\" = \"[DingTalk]\",\n): string {\n return `${prefix}[ErrorPayload][${scope}] ${formatDingTalkErrorPayload(payload)}`;\n}\n\nexport function getProxyBypassOption(config?: { bypassProxyForSend?: boolean }): { proxy: false } | Record<string, never> {\n return config?.bypassProxyForSend ? { proxy: false } : {};\n}\n\ntype LookupCallback = (\n err: NodeJS.ErrnoException | null,\n address: string | dns.LookupAddress[],\n family?: number,\n) => void;\n\ntype LookupOptions = dns.LookupOneOptions | dns.LookupAllOptions;\n\nexport function createResolve4FallbackLookup(log?: Logger, accountId?: string) {\n return createResolve4FallbackLookupWithDeps(log, accountId, dns, net);\n}\n\nexport function createResolve4FallbackLookupWithDeps(\n log: Logger | undefined,\n accountId: string | undefined,\n dnsImpl: Pick<typeof dns, \"lookup\" | \"resolve4\">,\n netImpl: Pick<typeof net, \"isIP\">,\n) {\n let fallbackLogged = false;\n\n return (hostname: string, options: LookupOptions, callback: LookupCallback): void => {\n const ipFamily = netImpl.isIP(hostname);\n if (ipFamily !== 0) {\n if (options.all) {\n callback(null, [{ address: hostname, family: ipFamily }], ipFamily);\n return;\n }\n\n callback(null, hostname, ipFamily);\n return;\n }\n\n dnsImpl.lookup(hostname, options, (lookupErr, address, family) => {\n if (!lookupErr) {\n callback(null, address, family);\n return;\n }\n\n if (lookupErr.code !== \"ENOTFOUND\") {\n callback(lookupErr, address, family);\n return;\n }\n\n dnsImpl.resolve4(hostname, (resolveErr, addresses) => {\n if (resolveErr || !addresses || addresses.length === 0) {\n callback(lookupErr, address, family);\n return;\n }\n\n if (!fallbackLogged) {\n fallbackLogged = true;\n log?.warn?.(\n `[${accountId ?? \"default\"}] System DNS lookup failed for ${hostname} (ENOTFOUND); using resolve4 fallback ${addresses[0]}`,\n );\n }\n\n if (options.all) {\n callback(\n null,\n addresses.map((item) => ({ address: item, family: 4 })),\n 4,\n );\n return;\n }\n\n callback(null, addresses[0], 4);\n });\n });\n };\n}\n\nfunction getHeaderCaseInsensitive(headers: unknown, key: string): string | undefined {\n if (!headers || typeof headers !== \"object\" || Array.isArray(headers)) {\n return undefined;\n }\n\n const entries = Object.entries(headers as Record<string, unknown>);\n const matched = entries.find(([name]) => name.toLowerCase() === key.toLowerCase());\n if (!matched) {\n return undefined;\n }\n\n const value = matched[1];\n if (Array.isArray(value)) {\n return value.length > 0 ? String(value[0]) : undefined;\n }\n if (value === null || value === undefined) {\n return undefined;\n }\n if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\" ||\n typeof value === \"bigint\"\n ) {\n return String(value);\n }\n try {\n return JSON.stringify(value);\n } catch {\n return undefined;\n }\n}\n\nexport function formatDingTalkConnectionErrorLog(\n scope: string,\n err: unknown,\n baseMessage: string,\n): string | null {\n if (!err || typeof err !== \"object\") {\n return null;\n }\n\n const errRecord = err as Record<string, unknown>;\n const stage =\n typeof errRecord.dingtalkConnectionStage === \"string\"\n ? errRecord.dingtalkConnectionStage\n : scope;\n const endpoint =\n typeof errRecord.dingtalkConnectionEndpoint === \"string\"\n ? errRecord.dingtalkConnectionEndpoint\n : undefined;\n\n const hasResponse = \"response\" in errRecord && errRecord.response !== null && errRecord.response !== undefined;\n if (!hasResponse && !endpoint && stage === scope) {\n return null;\n }\n\n const parts: string[] = [`${baseMessage} [DingTalk][ConnectionError][${stage}]`];\n if (endpoint) {\n parts.push(`endpoint=${endpoint}`);\n }\n\n const response = (err as { response?: { status?: unknown; data?: unknown; headers?: unknown } }).response;\n if (response) {\n if (response.status !== undefined && response.status !== null) {\n const statusText =\n typeof response.status === \"string\" ||\n typeof response.status === \"number\" ||\n typeof response.status === \"boolean\" ||\n typeof response.status === \"bigint\"\n ? String(response.status)\n : JSON.stringify(response.status);\n parts.push(`status=${statusText}`);\n }\n\n let requestId = getHeaderCaseInsensitive(response.headers, \"x-acs-dingtalk-request-id\");\n if (!requestId && response.data && typeof response.data === \"object\" && !Array.isArray(response.data)) {\n const data = response.data as Record<string, unknown>;\n if (typeof data.requestId === \"string\") {\n requestId = data.requestId;\n } else if (typeof data.requestid === \"string\") {\n requestId = data.requestid;\n }\n }\n if (requestId) {\n parts.push(`requestId=${requestId}`);\n }\n\n if (response.data !== undefined) {\n parts.push(formatDingTalkErrorPayload(response.data));\n }\n }\n\n if (stage === \"connect.websocket\") {\n parts.push(\"Likely websocket/proxy/WSS issue after connections/open succeeded\");\n }\n\n parts.push(\"See docs/connection-troubleshooting.md or run scripts/dingtalk-connection-check.*\");\n\n return parts.join(\" \");\n}\n\n/**\n * Cleanup orphaned temp files from dingtalk media\n * Run at startup to clean up files from crashed processes\n */\nexport function cleanupOrphanedTempFiles(log?: Logger): number {\n const tempDir = os.tmpdir();\n const dingtalkPattern = /^dingtalk_\\d+\\..+$/;\n let cleaned = 0;\n\n try {\n const files = fs.readdirSync(tempDir);\n const now = Date.now();\n const maxAge = 24 * 60 * 60 * 1000;\n\n for (const file of files) {\n if (!dingtalkPattern.test(file)) {\n continue;\n }\n\n const filePath = path.join(tempDir, file);\n try {\n const stats = fs.statSync(filePath);\n if (now - stats.mtime.getTime() > maxAge) {\n fs.unlinkSync(filePath);\n cleaned++;\n log?.debug?.(`[DingTalk] Cleaned up orphaned temp file: ${file}`);\n }\n } catch (err: unknown) {\n log?.debug?.(`[DingTalk] Failed to cleanup temp file ${file}: ${getErrorMessage(err)}`);\n }\n }\n\n if (cleaned > 0) {\n log?.info?.(`[DingTalk] Cleaned up ${cleaned} orphaned temp files`);\n }\n } catch (err: unknown) {\n log?.debug?.(`[DingTalk] Failed to cleanup temp directory: ${getErrorMessage(err)}`);\n }\n\n return cleaned;\n}\n\n/**\n * Retry logic for API calls with exponential backoff\n * Handles transient failures like 401 token expiry\n */\nexport async function retryWithBackoff<T>(\n fn: () => Promise<T>,\n options: RetryOptions = {},\n): Promise<T> {\n const { maxRetries = 3, baseDelayMs = 100, log } = options;\n\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n try {\n return await fn();\n } catch (err: unknown) {\n const statusCode = (err as { response?: { status?: number } }).response?.status;\n const isRetryable =\n statusCode === 401 || statusCode === 429 || (statusCode && statusCode >= 500);\n\n const responseData = getErrorResponseData(err);\n if (responseData !== undefined) {\n log?.debug?.(formatDingTalkErrorPayloadLog(\"retry.beforeDecision\", responseData));\n }\n\n if (!isRetryable || attempt === maxRetries) {\n throw err;\n }\n\n const delayMs = baseDelayMs * Math.pow(2, attempt - 1);\n log?.debug?.(`[DingTalk] Retry attempt ${attempt}/${maxRetries} after ${delayMs}ms`);\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n }\n }\n\n throw new Error(\"Retry exhausted without returning\");\n}\n\n/**\n * Get current timestamp in ISO-compatible epoch milliseconds for status tracking.\n */\nexport function getCurrentTimestamp(): number {\n return Date.now();\n}\n", "import { resolveRuntimeConfig } from \"./config\";\nimport axios from \"./http-client\";\nimport type { DingTalkConfig, Logger, TokenInfo } from \"./types\";\nimport { retryWithBackoff } from \"./utils\";\n\ninterface TokenCache {\n accessToken: string;\n expiry: number;\n}\n\n// Access Token cache - keyed by clientId for multi-account support.\nconst accessTokenCache = new Map<string, TokenCache>();\n\n/**\n * Get DingTalk access token with clientId-scoped cache + retry.\n * Refreshes token one minute before expiry to avoid near-expiry failures.\n */\nexport async function getAccessToken(config: DingTalkConfig, log?: Logger): Promise<string> {\n const cacheKey = config.clientId;\n const now = Date.now();\n const cached = accessTokenCache.get(cacheKey);\n\n if (cached && cached.expiry > now + 60000) {\n return cached.accessToken;\n }\n\n const runtimeConfig = await resolveRuntimeConfig(config, log);\n\n const token = await retryWithBackoff(\n async () => {\n const response = await axios.post<TokenInfo>(\n \"https://api.dingtalk.com/v1.0/oauth2/accessToken\",\n {\n appKey: runtimeConfig.clientId,\n appSecret: runtimeConfig.clientSecret,\n },\n );\n\n accessTokenCache.set(cacheKey, {\n accessToken: response.data.accessToken,\n expiry: now + response.data.expireIn * 1000,\n });\n\n return response.data.accessToken;\n },\n { maxRetries: 3, log },\n );\n\n return token;\n}\n", "import { buildChannelConfigSchema, type OpenClawConfig } from \"openclaw/plugin-sdk/core\";\nimport { getConfig, isConfigured, mergeAccountWithDefaults, resolveGroupConfig } from \"./config\";\nimport { DingTalkConfigSchema } from \"./config-schema.js\";\nimport {\n CHANNEL_INFLIGHT_NAMESPACE_POLICY,\n createDingTalkGateway,\n} from \"./gateway/channel-gateway\";\nimport { dingtalkSetupAdapter, dingtalkSetupWizard } from \"./onboarding.js\";\nimport { createDingTalkMessageActions } from \"./messaging/channel-actions\";\nimport { createDingTalkOutbound } from \"./messaging/channel-outbound\";\nimport { createDingTalkStatus } from \"./platform/channel-status\";\nimport { hasConfiguredSecretInput } from \"./secret-input\";\nimport {\n listDingTalkDirectoryGroups,\n listDingTalkDirectoryUsers,\n} from \"./targeting/target-directory-adapter\";\nimport { looksLikeDingTalkTargetId, normalizeDingTalkTarget } from \"./targeting/target-input\";\nimport type { DingTalkChannelPlugin, ResolvedAccount } from \"./types\";\n\n// DingTalk Channel Definition (assembly layer).\n// Heavy logic is delegated to service modules for maintainability.\nexport const dingtalkPlugin: DingTalkChannelPlugin = {\n id: \"dingtalk\",\n meta: {\n id: \"dingtalk\",\n label: \"DingTalk\",\n selectionLabel: \"DingTalk (\u9489\u9489)\",\n docsPath: \"https://github.com/soimy/openclaw-channel-dingtalk\",\n blurb: \"\u9489\u9489\u4F01\u4E1A\u5185\u90E8\u673A\u5668\u4EBA\uFF0C\u4F7F\u7528 Stream \u6A21\u5F0F\uFF0C\u65E0\u9700\u516C\u7F51 IP\u3002\",\n aliases: [\"dd\", \"ding\"],\n },\n configSchema: buildChannelConfigSchema(DingTalkConfigSchema),\n setup: dingtalkSetupAdapter,\n setupWizard: dingtalkSetupWizard,\n capabilities: {\n chatTypes: [\"direct\", \"group\"] as Array<\"direct\" | \"group\">,\n reactions: false,\n threads: false,\n media: true,\n nativeCommands: false,\n blockStreaming: false,\n },\n reload: { configPrefixes: [\"channels.dingtalk\"] },\n config: {\n listAccountIds: (cfg: OpenClawConfig): string[] => {\n const config = getConfig(cfg);\n return config.accounts && Object.keys(config.accounts).length > 0\n ? Object.keys(config.accounts)\n : isConfigured(cfg)\n ? [\"default\"]\n : [];\n },\n resolveAccount: (cfg: OpenClawConfig, accountId?: string | null) => {\n const config = getConfig(cfg);\n const id = accountId || \"default\";\n const account = config.accounts?.[id];\n const resolvedConfig = account ? mergeAccountWithDefaults(config, account) : config;\n const configured = Boolean(\n resolvedConfig.clientId && hasConfiguredSecretInput(resolvedConfig.clientSecret),\n );\n return {\n accountId: id,\n config: resolvedConfig,\n enabled: resolvedConfig.enabled !== false,\n configured,\n name: resolvedConfig.name || null,\n };\n },\n defaultAccountId: (): string => \"default\",\n isConfigured: (account: ResolvedAccount): boolean =>\n Boolean(account.config?.clientId && hasConfiguredSecretInput(account.config?.clientSecret)),\n describeAccount: (account: ResolvedAccount) => ({\n accountId: account.accountId,\n name: account.config?.name || \"DingTalk\",\n enabled: account.enabled,\n configured: Boolean(account.config?.clientId),\n }),\n },\n security: {\n resolveDmPolicy: ({ account }: any) => ({\n policy: account.config?.dmPolicy || \"open\",\n allowFrom: account.config?.allowFrom || [],\n policyPath: \"channels.dingtalk.dmPolicy\",\n allowFromPath: \"channels.dingtalk.allowFrom\",\n approveHint: \"\u4F7F\u7528 /allow dingtalk:<userId> \u6279\u51C6\u7528\u6237\",\n normalizeEntry: (raw: string) => raw.replace(/^(dingtalk|dd|ding):/i, \"\"),\n }),\n },\n groups: {\n resolveRequireMention: ({ cfg, groupId }: any): boolean => {\n const config = getConfig(cfg);\n if (groupId) {\n const groupCfg = resolveGroupConfig(config, groupId);\n if (groupCfg?.requireMention !== undefined) {\n return groupCfg.requireMention;\n }\n }\n return config.groupPolicy !== \"open\";\n },\n resolveGroupIntroHint: ({ groupId, groupChannel }: any): string | undefined => {\n const parts = [`conversationId=${groupId}`];\n if (groupChannel) {\n parts.push(`sessionKey=${groupChannel}`);\n }\n return `DingTalk IDs: ${parts.join(\", \")}.`;\n },\n },\n messaging: {\n normalizeTarget: (raw: string) => (raw ? normalizeDingTalkTarget(raw) : undefined),\n targetResolver: {\n looksLikeId: (raw: string, normalized?: string): boolean =>\n looksLikeDingTalkTargetId(raw, normalized),\n hint: \"<displayName|conversationId|user:staffId|user:+861...>\",\n },\n },\n directory: {\n self: async () => null,\n listGroups: async (params) => listDingTalkDirectoryGroups(params),\n listGroupsLive: async (params) => listDingTalkDirectoryGroups(params),\n listPeers: async (params) => listDingTalkDirectoryUsers(params),\n listPeersLive: async (params) => listDingTalkDirectoryUsers(params),\n },\n actions: createDingTalkMessageActions(),\n outbound: createDingTalkOutbound(),\n gateway: createDingTalkGateway(),\n status: createDingTalkStatus(),\n};\n\nexport { CHANNEL_INFLIGHT_NAMESPACE_POLICY };\nexport { getAccessToken } from \"./auth\";\nexport { createAICard, finishAICard, streamAICard } from \"./card-service\";\nexport { detectMediaTypeFromExtension } from \"./media-utils\";\nexport { getLogger } from \"./logger-context\";\nexport {\n sendBySession,\n sendMessage,\n sendProactiveMedia,\n uploadMedia,\n} from \"./send-service\";\n", "import { z } from \"zod\";\nimport { DEFAULT_MESSAGE_CONTEXT_TTL_DAYS } from \"./message-context-store\";\nimport { buildSecretInputSchema } from \"./secret-input\";\n\nconst AckReactionSchema = z.union([\n z.literal(\"\"),\n z.enum([\"off\", \"emoji\", \"kaomoji\"]),\n z.string().min(1),\n]);\n\nconst CardStreamingModeSchema = z.enum([\"off\", \"answer\", \"all\"]);\nconst ContextVisibilitySchema = z.enum([\"all\", \"allowlist\", \"allowlist_quote\"]);\n\n/**\n * Runtime-parsed DingTalk account config.\n *\n * Compatibility note:\n * - `agentId`, `corpId`, `showThinkingStream`, and `asyncMode` are intentionally\n * not parsed here. They remain only in manifest metadata for legacy host/UI\n * compatibility and are ignored by the current runtime.\n */\nconst DingTalkAccountConfigShape = {\n /** Account name (optional display name) */\n name: z.string().optional(),\n\n /** Enable or disable this DingTalk channel/account without deleting saved credentials. */\n enabled: z.boolean().optional().default(true),\n\n /** DingTalk App Key (Client ID) used to authenticate API and Stream connections. */\n clientId: z.string().optional(),\n\n /** DingTalk App Secret (Client Secret) used to obtain DingTalk access tokens. */\n clientSecret: buildSecretInputSchema().optional(),\n\n /** Direct-message access policy: open, pairing, or allowlist. */\n dmPolicy: z.enum([\"open\", \"pairing\", \"allowlist\"]).optional().default(\"open\"),\n\n /** Group-message access policy: open, allowlist, or disabled. */\n groupPolicy: z.enum([\"open\", \"allowlist\", \"disabled\"]).optional().default(\"open\"),\n\n /** User IDs allowed when `dmPolicy` is `allowlist`. */\n allowFrom: z.array(z.string()).optional(),\n\n /** Sender IDs allowed when `groupPolicy` is `allowlist`. */\n groupAllowFrom: z.array(z.string()).optional(),\n\n /** Default disabled. Enabling `all` allows learned displayName lookup but may misroute on stale or duplicate names and is available to all callers until upstream exposes requester authz context. */\n displayNameResolution: z.enum([\"disabled\", \"all\"]).optional().default(\"disabled\"),\n\n /** Controls how much supplemental host context remains visible to the reply runtime. `allowlist_quote` is the safest advanced mode when only explicit quotes or replies should remain visible. */\n contextVisibility: ContextVisibilitySchema.optional(),\n\n /** Allowed remote media download hosts, IPs, or CIDRs for media fetches. */\n mediaUrlAllowlist: z.array(z.string()).optional(),\n\n /** Native acknowledgement reaction mode: off, emoji, kaomoji, or a custom compatibility string. */\n ackReaction: AckReactionSchema.optional(),\n\n /** Retention window in days for short-lived message context used by quoting and media recovery. */\n journalTTLDays: z.number().int().min(1).optional().default(DEFAULT_MESSAGE_CONTEXT_TTL_DAYS),\n /** Enable verbose DingTalk channel debug logging. */\n debug: z.boolean().optional().default(false),\n\n /** Default reply delivery mode: markdown or card. */\n messageType: z.enum([\"markdown\", \"card\"]).optional().default(\"markdown\"),\n\n /** Deprecated and ignored. AI card replies now always use the built-in DingTalk template contract. Keep only for backward-compatible config parsing. */\n cardTemplateId: z.string().optional(),\n\n /** Deprecated and ignored. The built-in AI card contract owns the streaming field mapping. Keep only for backward-compatible config parsing. */\n cardTemplateKey: z.string().optional().default(\"content\"),\n\n /** Per-group overrides keyed by conversationId. Supports `*` as a wildcard fallback. */\n groups: z\n .record(\n z.string(),\n z.object({\n /** Additional system prompt appended for this group. */\n systemPrompt: z.string().optional(),\n /** Require an explicit @mention before the bot answers in this group. */\n requireMention: z.boolean().optional(),\n /** Optional per-group sender allowlist for tighter access control than the channel default. */\n groupAllowFrom: z.array(z.string()).optional(),\n }),\n )\n .optional(),\n\n /** Connection robustness configuration */\n\n /** Maximum connection attempts in a single reconnect cycle before backing off or giving up. */\n maxConnectionAttempts: z.number().int().min(1).optional().default(10),\n\n /** Initial reconnect backoff delay in milliseconds. */\n initialReconnectDelay: z.number().int().min(100).optional().default(1000),\n\n /** Upper bound for reconnect backoff delay in milliseconds. */\n maxReconnectDelay: z.number().int().min(1000).optional().default(60000),\n\n /** Randomization factor added to reconnect backoff to avoid synchronized reconnect storms. */\n reconnectJitter: z.number().min(0).max(1).optional().default(0.3),\n\n /** Maximum reconnect cycles before the channel stops retrying and waits for the next lifecycle restart. */\n maxReconnectCycles: z.number().int().min(1).optional().default(10),\n\n /** Time limit in milliseconds for one reconnect cycle before starting a fresh cycle. */\n reconnectDeadlineMs: z.number().int().min(5000).optional().default(50000),\n\n /** Enable the plugin connection manager. Disable only when you intentionally rely on DWClient native keepAlive plus autoReconnect behavior. */\n useConnectionManager: z.boolean().optional().default(true),\n\n /** Maximum inbound media size in MB accepted by the plugin. When omitted, the runtime default is used. */\n mediaMaxMb: z.number().int().min(1).optional(),\n\n /** Enable the underlying Stream client heartbeat. When omitted, runtime derives a default from `useConnectionManager`. */\n keepAlive: z.boolean().optional(),\n /** Bypass global or system HTTP(S) proxy settings for DingTalk send, upload, and card APIs. */\n bypassProxyForSend: z.boolean().optional().default(false),\n /** Controls the proactive-send permission reminder shown when a conversation has not granted send rights yet. */\n proactivePermissionHint: z\n .object({\n /** Show the proactive-send permission hint when the runtime detects missing DingTalk proactive permission. */\n enabled: z.boolean().optional().default(true),\n /** Minimum cooldown in hours before the same proactive permission hint can be shown again. */\n cooldownHours: z.number().int().min(1).max(24 * 30).optional().default(24),\n })\n .optional()\n .default({ enabled: true, cooldownHours: 24 }),\n\n /** Deprecated compatibility flag. When true and `cardStreamingMode` is unset, runtime resolves to `cardStreamingMode: \"all\"`. Do not use in new configs. */\n cardRealTimeStream: z.boolean().optional(),\n\n /** Card streaming mode:\n * - off: disable incremental streaming\n * - answer: stream answer text\n * - all: stream answer + reasoning or thinking text */\n cardStreamingMode: CardStreamingModeSchema.optional(),\n\n /** Throttle interval in milliseconds between AI card streaming updates. */\n cardStreamInterval: z.number().int().min(200).optional().default(1000),\n\n /** Cooldown window in milliseconds after AI card trigger errors. Replies fall back to non-card delivery during this period. */\n aicardDegradeMs: z.number().int().min(60_000).optional().default(30 * 60 * 1000),\n\n /** Enable the local feedback-learning loop for notes, reflections, and command-assisted learning. */\n learningEnabled: z.boolean().optional(),\n\n /** Automatically apply generated learning output into session notes or global rules when available. */\n learningAutoApply: z.boolean().optional(),\n\n /** Retention window in milliseconds for temporary learning notes. */\n learningNoteTtlMs: z.number().int().min(60_000).optional(),\n\n /** Convert markdown tables to plain text before sending when you want more consistent DingTalk rendering. */\n convertMarkdownTables: z.boolean().optional().default(true),\n\n /** @mention the sender after card finalization in group chats.\n * Set to a non-empty string (e.g. \"\u2705 \u56DE\u590D\u5B8C\u6210\") to enable \u2014 the value is used as the message text.\n * Leave empty or omit to disable. */\n cardAtSender: z.string().optional(),\n\n /** Status line visibility toggles for the AI card footer. */\n cardStatusLine: z\n .object({\n /** Show model name. */\n model: z.boolean().optional().default(true),\n /** Show thinking effort level. */\n effort: z.boolean().optional().default(true),\n /** Show agent display name. */\n agent: z.boolean().optional().default(true),\n /** Show task elapsed time. */\n taskTime: z.boolean().optional().default(false),\n /** Show token usage summary (input/output/cache). */\n tokens: z.boolean().optional().default(false),\n /** Show DingTalk API call count. */\n dapiUsage: z.boolean().optional().default(false),\n })\n .optional()\n .default({ model: true, effort: true, agent: true, taskTime: false, tokens: false, dapiUsage: false }),\n} as const;\n\nconst DingTalkAccountConfigSchema = z.object(DingTalkAccountConfigShape);\n\n/**\n * DingTalk configuration schema using Zod\n * Mirrors the structure needed for proper control-ui rendering\n */\nexport const DingTalkConfigSchema: z.ZodTypeAny = DingTalkAccountConfigSchema.extend({\n /** Multi-account configuration */\n accounts: z.record(z.string(), DingTalkAccountConfigSchema.optional()).optional(),\n});\n\nexport type DingTalkConfig = z.infer<typeof DingTalkConfigSchema>;\n", "import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { Logger } from \"./types\";\n\ntype NamespaceFormat = \"json\";\n\nexport interface PersistenceScope {\n accountId?: string;\n agentId?: string;\n conversationId?: string;\n groupId?: string;\n targetId?: string;\n}\n\nexport interface ResolveNamespacePathOptions {\n storePath: string;\n scope?: PersistenceScope;\n format?: NamespaceFormat;\n}\n\nexport interface ReadNamespaceJsonOptions<T> extends ResolveNamespacePathOptions {\n fallback: T;\n log?: Logger;\n}\n\nexport interface WriteNamespaceJsonOptions<T> extends ResolveNamespacePathOptions {\n data: T;\n log?: Logger;\n}\n\nconst NAMESPACE_ROOT_DIR = \"dingtalk-state\";\n\nfunction toErrorMessage(err: unknown): string {\n if (err instanceof Error) {\n return err.message;\n }\n try {\n return JSON.stringify(err);\n } catch {\n return String(err);\n }\n}\n\nfunction sanitizeSegment(value: string): string {\n return value.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n}\n\nfunction encodeScopeValue(value: string): string {\n return Buffer.from(value, \"utf8\").toString(\"base64url\");\n}\n\nfunction buildScopeSuffix(scope?: PersistenceScope): string {\n if (!scope) {\n return \"\";\n }\n const ordered: Array<[keyof PersistenceScope, string | undefined]> = [\n [\"accountId\", scope.accountId],\n [\"agentId\", scope.agentId],\n [\"conversationId\", scope.conversationId],\n [\"groupId\", scope.groupId],\n [\"targetId\", scope.targetId],\n ];\n\n const segments = ordered\n .filter(([, value]) => Boolean(value && value.trim()))\n .map(([key, value]) => `${key.replace(/Id$/, \"\")}-${encodeScopeValue((value || \"\").trim())}`);\n\n if (segments.length === 0) {\n return \"\";\n }\n return `.${segments.join(\".\")}`;\n}\n\nexport function resolveNamespacePath(namespace: string, options: ResolveNamespacePathOptions): string {\n const format = options.format || \"json\";\n const baseDir = path.join(path.dirname(options.storePath), NAMESPACE_ROOT_DIR);\n const safeNamespace = sanitizeSegment(namespace.trim());\n const suffix = buildScopeSuffix(options.scope);\n return path.join(baseDir, `${safeNamespace}${suffix}.${format}`);\n}\n\nexport function readNamespaceJson<T>(\n namespace: string,\n options: ReadNamespaceJsonOptions<T>,\n): T {\n const filePath = resolveNamespacePath(namespace, options);\n try {\n if (!fs.existsSync(filePath)) {\n return options.fallback;\n }\n const raw = fs.readFileSync(filePath, \"utf-8\");\n if (!raw.trim()) {\n return options.fallback;\n }\n return JSON.parse(raw) as T;\n } catch (err: unknown) {\n options.log?.warn?.(\n `[DingTalk][Persistence] Failed to read namespace=${namespace} path=${filePath}: ${toErrorMessage(err)}`,\n );\n return options.fallback;\n }\n}\n\nexport function writeNamespaceJsonAtomic<T>(\n namespace: string,\n options: WriteNamespaceJsonOptions<T>,\n): void {\n const filePath = resolveNamespacePath(namespace, options);\n const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;\n try {\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n fs.writeFileSync(tempPath, JSON.stringify(options.data, null, 2));\n try {\n fs.renameSync(tempPath, filePath);\n } catch (err: unknown) {\n if (fs.existsSync(filePath)) {\n fs.rmSync(filePath, { force: true });\n fs.renameSync(tempPath, filePath);\n } else {\n throw err;\n }\n }\n } catch (err: unknown) {\n options.log?.warn?.(\n `[DingTalk][Persistence] Failed to write namespace=${namespace} path=${filePath}: ${toErrorMessage(err)}`,\n );\n if (fs.existsSync(tempPath)) {\n fs.rmSync(tempPath, { force: true });\n }\n }\n}\n", "import { randomUUID } from \"node:crypto\";\nimport { readNamespaceJson, writeNamespaceJsonAtomic } from \"./persistence-store\";\nimport type { AttachmentTextSource, Logger, QuotedRef } from \"./types\";\n\nconst MESSAGE_CONTEXT_NAMESPACE = \"messages.context\";\nconst MESSAGE_CONTEXT_VERSION = 1;\nexport const DEFAULT_MESSAGE_CONTEXT_TTL_DAYS = 7;\nexport const DEFAULT_CARD_CONTENT_TTL_MS = 24 * 60 * 60 * 1000;\nexport const DEFAULT_MEDIA_CONTEXT_TTL_MS = 24 * 60 * 60 * 1000;\nexport const DEFAULT_CREATED_AT_MATCH_WINDOW_MS = 2000;\nconst MAX_RECORDS_PER_SCOPE = 1000;\n\nexport type MessageContextDirection = \"inbound\" | \"outbound\";\nexport type MessageAliasKind =\n | \"inboundMsgId\"\n | \"messageId\"\n | \"processQueryKey\"\n | \"outTrackId\"\n | \"cardInstanceId\";\nexport type MessageDeliveryKind =\n | \"session\"\n | \"proactive-text\"\n | \"proactive-card\"\n | \"proactive-media\";\nexport const DEFAULT_OUTBOUND_SENDER = {\n senderId: \"bot\",\n senderName: \"OpenClaw\",\n} as const;\n\n/** DingTalk conversation ids usually start with \"cid\" for group chats; treat this as a heuristic. */\nexport function inferConversationChatType(conversationId: string): \"direct\" | \"group\" {\n return conversationId.startsWith(\"cid\") ? \"group\" : \"direct\";\n}\n\nexport interface MessageRecord {\n msgId: string;\n direction: MessageContextDirection;\n topic: string | null;\n accountId: string;\n conversationId: string | null;\n createdAt: number;\n updatedAt: number;\n expiresAt?: number;\n messageType?: string;\n text?: string;\n attachmentText?: string;\n attachmentTextSource?: AttachmentTextSource;\n attachmentTextTruncated?: boolean;\n attachmentFileName?: string;\n quotedRef?: QuotedRef;\n senderId?: string;\n senderName?: string;\n mentions?: string[];\n chatType?: \"direct\" | \"group\";\n /** Flat quoted target for summary/history lookups; quotedRef remains the authoritative structured link. */\n quotedMessageId?: string;\n media?: {\n downloadCode?: string;\n downloadCodes?: string[];\n spaceId?: string;\n fileId?: string;\n };\n delivery?: {\n messageId?: string;\n processQueryKey?: string;\n outTrackId?: string;\n cardInstanceId?: string;\n kind?: MessageDeliveryKind;\n };\n}\n\ninterface MessageContextState {\n version: number;\n updatedAt: number;\n records: Record<string, MessageRecord>;\n byAlias: Record<string, string>;\n recentByCreatedAt: string[];\n}\n\ninterface PersistedMessageContextState {\n version: number;\n updatedAt: number;\n records: Record<string, MessageRecord>;\n}\n\ninterface BaseUpsertParams {\n storePath?: string;\n accountId: string;\n conversationId: string | null;\n createdAt: number;\n updatedAt?: number;\n ttlMs?: number;\n ttlReferenceMs?: number;\n topic?: string | null;\n messageType?: string;\n text?: string;\n attachmentText?: string;\n attachmentTextSource?: AttachmentTextSource;\n attachmentTextTruncated?: boolean;\n attachmentFileName?: string;\n quotedRef?: QuotedRef;\n senderId?: string;\n senderName?: string;\n mentions?: string[];\n chatType?: \"direct\" | \"group\";\n quotedMessageId?: string;\n media?: {\n downloadCode?: string;\n downloadCodes?: string[];\n spaceId?: string;\n fileId?: string;\n };\n}\n\nexport interface UpsertInboundMessageContextParams extends BaseUpsertParams {\n msgId: string;\n cleanupCreatedAtTtlDays?: number;\n}\n\nexport interface UpsertOutboundMessageContextParams extends BaseUpsertParams {\n msgId?: string;\n delivery?: MessageRecord[\"delivery\"];\n}\n\ninterface ScopeParams {\n storePath?: string;\n accountId: string;\n conversationId: string | null;\n}\n\nconst stateCache = new Map<string, MessageContextState>();\n\nfunction getScopeKey(params: ScopeParams): string {\n return JSON.stringify([\n params.storePath || \"__memory__\",\n params.accountId,\n params.conversationId || null,\n ]);\n}\n\nfunction fallbackState(): MessageContextState {\n return {\n version: MESSAGE_CONTEXT_VERSION,\n updatedAt: Date.now(),\n records: {},\n byAlias: {},\n recentByCreatedAt: [],\n };\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return null;\n }\n return value as Record<string, unknown>;\n}\n\nfunction normalizeMedia(value: unknown): MessageRecord[\"media\"] | undefined {\n const candidate = asRecord(value);\n if (!candidate) {\n return undefined;\n }\n const downloadCode =\n typeof candidate.downloadCode === \"string\" && candidate.downloadCode.trim()\n ? candidate.downloadCode.trim()\n : undefined;\n const downloadCodes =\n Array.isArray(candidate.downloadCodes) && candidate.downloadCodes.length > 0\n ? candidate.downloadCodes.filter((c: unknown) => typeof c === \"string\" && c.trim())\n : undefined;\n const spaceId =\n typeof candidate.spaceId === \"string\" && candidate.spaceId.trim()\n ? candidate.spaceId.trim()\n : undefined;\n const fileId =\n typeof candidate.fileId === \"string\" && candidate.fileId.trim()\n ? candidate.fileId.trim()\n : undefined;\n if (!downloadCode && (!downloadCodes || downloadCodes.length === 0) && !spaceId && !fileId) {\n return undefined;\n }\n return { downloadCode, downloadCodes, spaceId, fileId };\n}\n\nfunction normalizeQuotedRef(value: unknown): QuotedRef | undefined {\n const candidate = asRecord(value);\n if (!candidate) {\n return undefined;\n }\n const targetDirection =\n candidate.targetDirection === \"outbound\"\n ? \"outbound\"\n : candidate.targetDirection === \"inbound\"\n ? \"inbound\"\n : undefined;\n const key =\n candidate.key === \"msgId\" ||\n candidate.key === \"messageId\" ||\n candidate.key === \"processQueryKey\" ||\n candidate.key === \"outTrackId\" ||\n candidate.key === \"cardInstanceId\"\n ? candidate.key\n : undefined;\n const valueString =\n typeof candidate.value === \"string\" && candidate.value.trim()\n ? candidate.value.trim()\n : undefined;\n const fallbackCreatedAt =\n typeof candidate.fallbackCreatedAt === \"number\" && Number.isFinite(candidate.fallbackCreatedAt)\n ? candidate.fallbackCreatedAt\n : undefined;\n if (!targetDirection) {\n return undefined;\n }\n if (!key && !fallbackCreatedAt) {\n return undefined;\n }\n if (key && !valueString) {\n return undefined;\n }\n return {\n targetDirection,\n key,\n value: valueString,\n fallbackCreatedAt,\n };\n}\n\nfunction normalizeAttachmentTextSource(value: unknown): AttachmentTextSource | undefined {\n return value === \"text\" || value === \"html\" || value === \"pdf\" || value === \"docx\"\n ? value\n : undefined;\n}\n\nfunction normalizeDelivery(value: unknown): MessageRecord[\"delivery\"] | undefined {\n const candidate = asRecord(value);\n if (!candidate) {\n return undefined;\n }\n const messageId =\n typeof candidate.messageId === \"string\" && candidate.messageId.trim()\n ? candidate.messageId.trim()\n : undefined;\n const processQueryKey =\n typeof candidate.processQueryKey === \"string\" && candidate.processQueryKey.trim()\n ? candidate.processQueryKey.trim()\n : undefined;\n const outTrackId =\n typeof candidate.outTrackId === \"string\" && candidate.outTrackId.trim()\n ? candidate.outTrackId.trim()\n : undefined;\n const cardInstanceId =\n typeof candidate.cardInstanceId === \"string\" && candidate.cardInstanceId.trim()\n ? candidate.cardInstanceId.trim()\n : undefined;\n const kind =\n typeof candidate.kind === \"string\" && candidate.kind.trim()\n ? (candidate.kind.trim() as MessageDeliveryKind)\n : undefined;\n if (!messageId && !processQueryKey && !outTrackId && !cardInstanceId && !kind) {\n return undefined;\n }\n return { messageId, processQueryKey, outTrackId, cardInstanceId, kind };\n}\n\nfunction normalizeMentions(value: unknown): string[] | undefined {\n if (!Array.isArray(value)) {\n return undefined;\n }\n // Preserve the original mention token casing because DingTalk ids may be case-sensitive.\n const normalized = [...new Set(value.map((item) => String(item || \"\").trim()).filter(Boolean))];\n return normalized.length > 0 ? normalized : undefined;\n}\n\nfunction normalizeMessageRecord(value: unknown): MessageRecord | null {\n const candidate = asRecord(value);\n if (!candidate) {\n return null;\n }\n const msgId =\n typeof candidate.msgId === \"string\" && candidate.msgId.trim() ? candidate.msgId.trim() : \"\";\n const direction =\n candidate.direction === \"outbound\"\n ? \"outbound\"\n : candidate.direction === \"inbound\"\n ? \"inbound\"\n : null;\n const accountId =\n typeof candidate.accountId === \"string\" && candidate.accountId.trim()\n ? candidate.accountId.trim()\n : \"\";\n const conversationId =\n typeof candidate.conversationId === \"string\" && candidate.conversationId.trim()\n ? candidate.conversationId.trim()\n : null;\n const createdAt =\n typeof candidate.createdAt === \"number\" && Number.isFinite(candidate.createdAt)\n ? candidate.createdAt\n : NaN;\n const updatedAt =\n typeof candidate.updatedAt === \"number\" && Number.isFinite(candidate.updatedAt)\n ? candidate.updatedAt\n : Date.now();\n if (!msgId || !direction || !accountId || !Number.isFinite(createdAt)) {\n return null;\n }\n const expiresAt =\n typeof candidate.expiresAt === \"number\" && Number.isFinite(candidate.expiresAt)\n ? candidate.expiresAt\n : undefined;\n return {\n msgId,\n direction,\n topic:\n candidate.topic === null\n ? null\n : typeof candidate.topic === \"string\"\n ? candidate.topic\n : null,\n accountId,\n conversationId,\n createdAt,\n updatedAt,\n expiresAt,\n messageType: typeof candidate.messageType === \"string\" ? candidate.messageType : undefined,\n text: typeof candidate.text === \"string\" ? candidate.text : undefined,\n attachmentText:\n typeof candidate.attachmentText === \"string\" ? candidate.attachmentText : undefined,\n attachmentTextSource: normalizeAttachmentTextSource(candidate.attachmentTextSource),\n attachmentTextTruncated: candidate.attachmentTextTruncated === true ? true : undefined,\n attachmentFileName:\n typeof candidate.attachmentFileName === \"string\" ? candidate.attachmentFileName : undefined,\n quotedRef: normalizeQuotedRef(candidate.quotedRef),\n senderId:\n typeof candidate.senderId === \"string\" && candidate.senderId.trim()\n ? candidate.senderId.trim()\n : undefined,\n senderName:\n typeof candidate.senderName === \"string\" && candidate.senderName.trim()\n ? candidate.senderName.trim()\n : undefined,\n mentions: normalizeMentions(candidate.mentions),\n chatType:\n candidate.chatType === \"direct\" || candidate.chatType === \"group\"\n ? candidate.chatType\n : undefined,\n quotedMessageId:\n typeof candidate.quotedMessageId === \"string\" && candidate.quotedMessageId.trim()\n ? candidate.quotedMessageId.trim()\n : undefined,\n media: normalizeMedia(candidate.media),\n delivery: normalizeDelivery(candidate.delivery),\n };\n}\n\nfunction buildAliasKey(kind: MessageAliasKind, value: string): string {\n return `${kind}:${value.trim()}`;\n}\n\nfunction buildAliasEntries(record: MessageRecord): Array<[string, string]> {\n const aliases: Array<[string, string]> = [];\n if (record.direction === \"inbound\" && record.msgId.trim()) {\n aliases.push([buildAliasKey(\"inboundMsgId\", record.msgId), record.msgId]);\n }\n const delivery = record.delivery;\n if (!delivery) {\n return aliases;\n }\n if (delivery.messageId) {\n aliases.push([buildAliasKey(\"messageId\", delivery.messageId), record.msgId]);\n }\n if (delivery.processQueryKey) {\n aliases.push([buildAliasKey(\"processQueryKey\", delivery.processQueryKey), record.msgId]);\n }\n if (delivery.outTrackId) {\n aliases.push([buildAliasKey(\"outTrackId\", delivery.outTrackId), record.msgId]);\n }\n if (delivery.cardInstanceId) {\n aliases.push([buildAliasKey(\"cardInstanceId\", delivery.cardInstanceId), record.msgId]);\n }\n return aliases;\n}\n\nfunction isRecordExpired(record: MessageRecord, nowMs: number): boolean {\n return (\n typeof record.expiresAt === \"number\" &&\n Number.isFinite(record.expiresAt) &&\n nowMs >= record.expiresAt\n );\n}\n\nfunction normalizeState(\n state: MessageContextState,\n nowMs: number,\n): { state: MessageContextState; removed: number } {\n const normalizedRecords: Record<string, MessageRecord> = {};\n const sortedRecords = Object.values(state.records)\n .map((record) => normalizeMessageRecord(record))\n .filter((record): record is MessageRecord => record !== null)\n .filter((record) => !isRecordExpired(record, nowMs))\n .toSorted((left, right) => left.createdAt - right.createdAt);\n const keptRecords = sortedRecords.slice(-MAX_RECORDS_PER_SCOPE);\n for (const record of keptRecords) {\n normalizedRecords[record.msgId] = record;\n }\n const byAlias: Record<string, string> = {};\n for (const record of keptRecords) {\n for (const [key, value] of buildAliasEntries(record)) {\n byAlias[key] = value;\n }\n }\n return {\n removed: Object.keys(state.records).length - Object.keys(normalizedRecords).length,\n state: {\n version: MESSAGE_CONTEXT_VERSION,\n updatedAt: state.updatedAt,\n records: normalizedRecords,\n byAlias,\n recentByCreatedAt: keptRecords.map((record) => record.msgId),\n },\n };\n}\n\nfunction hydrateState(params: ScopeParams, nowMs: number): MessageContextState {\n if (!params.storePath) {\n return fallbackState();\n }\n const persisted = readNamespaceJson<Partial<PersistedMessageContextState>>(\n MESSAGE_CONTEXT_NAMESPACE,\n {\n storePath: params.storePath,\n scope: { accountId: params.accountId, conversationId: params.conversationId || undefined },\n format: \"json\",\n fallback: { version: MESSAGE_CONTEXT_VERSION, updatedAt: Date.now(), records: {} },\n },\n );\n const parsedRecords = asRecord(persisted.records) || {};\n const hydrated = fallbackState();\n hydrated.updatedAt = typeof persisted.updatedAt === \"number\" ? persisted.updatedAt : Date.now();\n for (const [key, value] of Object.entries(parsedRecords)) {\n const normalized = normalizeMessageRecord(value);\n if (normalized) {\n hydrated.records[key] = normalized;\n }\n }\n return normalizeState(hydrated, nowMs).state;\n}\n\nfunction loadState(params: ScopeParams, nowMs: number = Date.now()): MessageContextState {\n const scopeKey = getScopeKey(params);\n const cached = stateCache.get(scopeKey);\n if (cached) {\n return cached;\n }\n const hydrated = params.storePath ? hydrateState(params, nowMs) : fallbackState();\n stateCache.set(scopeKey, hydrated);\n return hydrated;\n}\n\nfunction writeState(params: ScopeParams, state: MessageContextState): void {\n stateCache.set(getScopeKey(params), state);\n if (!params.storePath) {\n return;\n }\n writeNamespaceJsonAtomic(MESSAGE_CONTEXT_NAMESPACE, {\n storePath: params.storePath,\n scope: { accountId: params.accountId, conversationId: params.conversationId || undefined },\n format: \"json\",\n data: {\n version: MESSAGE_CONTEXT_VERSION,\n updatedAt: state.updatedAt,\n records: state.records,\n } satisfies PersistedMessageContextState,\n });\n}\n\nfunction cloneStateForMutation(state: MessageContextState): MessageContextState {\n return {\n version: state.version,\n updatedAt: state.updatedAt,\n records: { ...state.records },\n byAlias: state.byAlias,\n recentByCreatedAt: state.recentByCreatedAt,\n };\n}\n\nfunction mergeText(existing: string | undefined, next: string | undefined): string | undefined {\n if (typeof next !== \"string\") {\n return existing;\n }\n return next;\n}\n\nfunction mergeAttachmentText(\n existing: string | undefined,\n next: string | undefined,\n): string | undefined {\n if (typeof next !== \"string\") {\n return existing;\n }\n return next;\n}\n\nfunction mergeQuotedRef(\n existing: QuotedRef | undefined,\n next: QuotedRef | undefined,\n): QuotedRef | undefined {\n if (!existing) {\n return next;\n }\n if (!next) {\n return existing;\n }\n return {\n targetDirection: next.targetDirection,\n key: next.key || existing.key,\n value: next.value || existing.value,\n fallbackCreatedAt: next.fallbackCreatedAt ?? existing.fallbackCreatedAt,\n };\n}\n\nfunction mergeStringField(\n existing: string | undefined,\n next: string | undefined,\n): string | undefined {\n if (typeof next !== \"string\" || !next.trim()) {\n return existing;\n }\n return next.trim();\n}\n\nfunction mergeMentions(\n existing: string[] | undefined,\n next: string[] | undefined,\n): string[] | undefined {\n if (!next) {\n return existing;\n }\n return normalizeMentions(next) || existing;\n}\n\nfunction mergeMedia(\n existing: MessageRecord[\"media\"] | undefined,\n next: MessageRecord[\"media\"] | undefined,\n): MessageRecord[\"media\"] | undefined {\n if (!existing) {\n return next;\n }\n if (!next) {\n return existing;\n }\n return {\n downloadCode: next.downloadCode || existing.downloadCode,\n downloadCodes: next.downloadCodes || existing.downloadCodes,\n spaceId: next.spaceId || existing.spaceId,\n fileId: next.fileId || existing.fileId,\n };\n}\n\nfunction mergeDelivery(\n existing: MessageRecord[\"delivery\"] | undefined,\n next: MessageRecord[\"delivery\"] | undefined,\n): MessageRecord[\"delivery\"] | undefined {\n if (!existing) {\n return next;\n }\n if (!next) {\n return existing;\n }\n return {\n messageId: next.messageId || existing.messageId,\n processQueryKey: next.processQueryKey || existing.processQueryKey,\n outTrackId: next.outTrackId || existing.outTrackId,\n cardInstanceId: next.cardInstanceId || existing.cardInstanceId,\n kind: next.kind || existing.kind,\n };\n}\n\nfunction mergeAttachmentTextSource(\n existing: AttachmentTextSource | undefined,\n next: AttachmentTextSource | undefined,\n): AttachmentTextSource | undefined {\n return next ?? existing;\n}\n\nfunction mergeAttachmentTextTruncated(\n existing: boolean | undefined,\n next: boolean | undefined,\n): boolean | undefined {\n return next === undefined ? existing : next;\n}\n\nfunction mergeAttachmentFileName(\n existing: string | undefined,\n next: string | undefined,\n): string | undefined {\n if (typeof next !== \"string\") {\n return existing;\n }\n return next;\n}\n\nfunction resolveExistingMsgId(\n state: MessageContextState,\n params: {\n direction: MessageContextDirection;\n msgId?: string;\n delivery?: MessageRecord[\"delivery\"];\n },\n nowMs: number,\n): string | undefined {\n if (params.direction === \"inbound\" && params.msgId) {\n const direct = state.records[params.msgId];\n if (direct && !isRecordExpired(direct, nowMs)) {\n return params.msgId;\n }\n }\n const delivery = params.delivery;\n if (!delivery) {\n return undefined;\n }\n const candidates: Array<[MessageAliasKind, string | undefined]> = [\n [\"messageId\", delivery.messageId],\n [\"processQueryKey\", delivery.processQueryKey],\n [\"outTrackId\", delivery.outTrackId],\n [\"cardInstanceId\", delivery.cardInstanceId],\n ];\n for (const [kind, value] of candidates) {\n if (!value) {\n continue;\n }\n const aliasHit = state.byAlias[buildAliasKey(kind, value)];\n if (!aliasHit) {\n continue;\n }\n const record = state.records[aliasHit];\n if (record && !isRecordExpired(record, nowMs)) {\n return aliasHit;\n }\n }\n return undefined;\n}\n\nfunction computeExpiresAt(\n nowMs: number,\n ttlMs?: number,\n ttlReferenceMs?: number,\n): number | undefined {\n if (typeof ttlMs !== \"number\" || !Number.isFinite(ttlMs) || ttlMs <= 0) {\n return undefined;\n }\n return (\n (typeof ttlReferenceMs === \"number\" && Number.isFinite(ttlReferenceMs)\n ? ttlReferenceMs\n : nowMs) + ttlMs\n );\n}\n\nfunction pruneStateByCreatedAt(\n state: MessageContextState,\n ttlDays: number,\n nowMs: number,\n): { state: MessageContextState; removed: number } {\n if (!ttlDays || ttlDays <= 0) {\n return { state, removed: 0 };\n }\n const cutoff = nowMs - ttlDays * 24 * 60 * 60 * 1000;\n const nextRecords: Record<string, MessageRecord> = {};\n for (const [msgId, record] of Object.entries(state.records)) {\n if (record.createdAt >= cutoff) {\n nextRecords[msgId] = record;\n }\n }\n const removed = Object.keys(state.records).length - Object.keys(nextRecords).length;\n if (removed === 0) {\n return { state, removed: 0 };\n }\n return {\n removed,\n state: {\n ...state,\n records: nextRecords,\n },\n };\n}\n\nfunction upsertRecord(\n params: ScopeParams & {\n direction: MessageContextDirection;\n msgId?: string;\n createdAt: number;\n updatedAt?: number;\n topic?: string | null;\n ttlMs?: number;\n ttlReferenceMs?: number;\n messageType?: string;\n text?: string;\n attachmentText?: string;\n attachmentTextSource?: AttachmentTextSource;\n attachmentTextTruncated?: boolean;\n attachmentFileName?: string;\n quotedRef?: QuotedRef;\n senderId?: string;\n senderName?: string;\n mentions?: string[];\n chatType?: \"direct\" | \"group\";\n quotedMessageId?: string;\n media?: MessageRecord[\"media\"];\n delivery?: MessageRecord[\"delivery\"];\n cleanupCreatedAtTtlDays?: number;\n },\n): string | undefined {\n const nowMs = params.updatedAt ?? Date.now();\n let state = cloneStateForMutation(loadState(params, nowMs));\n if (params.cleanupCreatedAtTtlDays && params.cleanupCreatedAtTtlDays > 0) {\n state = pruneStateByCreatedAt(state, params.cleanupCreatedAtTtlDays, nowMs).state;\n }\n const existingMsgId = resolveExistingMsgId(\n state,\n {\n direction: params.direction,\n msgId: params.msgId,\n delivery: params.delivery,\n },\n nowMs,\n );\n const canonicalMsgId =\n existingMsgId ||\n params.msgId ||\n params.delivery?.messageId ||\n params.delivery?.processQueryKey ||\n params.delivery?.outTrackId;\n if (!canonicalMsgId || !canonicalMsgId.trim()) {\n return undefined;\n }\n const existing = state.records[canonicalMsgId];\n const expiresAt = computeExpiresAt(nowMs, params.ttlMs, params.ttlReferenceMs);\n const normalizedQuotedRef = normalizeQuotedRef(params.quotedRef);\n state.records[canonicalMsgId] = {\n msgId: canonicalMsgId,\n direction: params.direction,\n topic: params.topic ?? existing?.topic ?? null,\n accountId: params.accountId,\n conversationId: params.conversationId,\n createdAt: existing?.createdAt ?? params.createdAt,\n updatedAt: nowMs,\n expiresAt:\n expiresAt === undefined ? existing?.expiresAt : Math.max(expiresAt, existing?.expiresAt ?? 0),\n messageType: params.messageType || existing?.messageType,\n text: mergeText(existing?.text, params.text),\n attachmentText: mergeAttachmentText(existing?.attachmentText, params.attachmentText),\n attachmentTextSource: mergeAttachmentTextSource(\n existing?.attachmentTextSource,\n params.attachmentTextSource,\n ),\n attachmentTextTruncated: mergeAttachmentTextTruncated(\n existing?.attachmentTextTruncated,\n params.attachmentTextTruncated,\n ),\n attachmentFileName: mergeAttachmentFileName(\n existing?.attachmentFileName,\n params.attachmentFileName,\n ),\n quotedRef: mergeQuotedRef(existing?.quotedRef, normalizedQuotedRef),\n senderId: mergeStringField(existing?.senderId, params.senderId),\n senderName: mergeStringField(existing?.senderName, params.senderName),\n mentions: mergeMentions(existing?.mentions, params.mentions),\n chatType: params.chatType || existing?.chatType,\n quotedMessageId: mergeStringField(existing?.quotedMessageId, params.quotedMessageId),\n media: mergeMedia(existing?.media, params.media),\n delivery: mergeDelivery(existing?.delivery, params.delivery),\n };\n state.updatedAt = nowMs;\n writeState(params, normalizeState(state, nowMs).state);\n return canonicalMsgId;\n}\n\nexport function upsertInboundMessageContext(params: UpsertInboundMessageContextParams): string {\n return (\n upsertRecord({\n ...params,\n direction: \"inbound\",\n topic: params.topic ?? null,\n msgId: params.msgId,\n cleanupCreatedAtTtlDays: params.cleanupCreatedAtTtlDays,\n }) || params.msgId\n );\n}\n\nexport function upsertOutboundMessageContext(\n params: UpsertOutboundMessageContextParams,\n): string | undefined {\n return upsertRecord({\n ...params,\n direction: \"outbound\",\n topic: params.topic ?? null,\n });\n}\n\nexport function createSyntheticOutboundMsgId(createdAt: number): string {\n return `createdAt:${createdAt}:${randomUUID()}`;\n}\n\nexport function resolveByMsgId(\n params: ScopeParams & { msgId: string; nowMs?: number },\n): MessageRecord | null {\n const nowMs = params.nowMs ?? Date.now();\n const state = loadState(params, nowMs);\n const direct = state.records[params.msgId];\n if (direct && !isRecordExpired(direct, nowMs)) {\n return direct;\n }\n const aliasTarget = state.byAlias[buildAliasKey(\"inboundMsgId\", params.msgId)];\n if (!aliasTarget) {\n return null;\n }\n const record = state.records[aliasTarget];\n return record && !isRecordExpired(record, nowMs) ? record : null;\n}\n\nexport function resolveByAlias(\n params: ScopeParams & { kind: MessageAliasKind; value: string; nowMs?: number },\n): MessageRecord | null {\n const nowMs = params.nowMs ?? Date.now();\n const state = loadState(params, nowMs);\n const msgId = state.byAlias[buildAliasKey(params.kind, params.value)];\n if (!msgId) {\n return null;\n }\n const record = state.records[msgId];\n return record && !isRecordExpired(record, nowMs) ? record : null;\n}\n\nexport function resolveByQuotedRef(\n params: ScopeParams & { quotedRef: QuotedRef; nowMs?: number; log?: Logger },\n): MessageRecord | null {\n const nowMs = params.nowMs ?? Date.now();\n const quotedRef = normalizeQuotedRef(params.quotedRef);\n const log = params.log;\n if (!quotedRef) {\n log?.debug?.(\n `[DingTalk][QuotedRef] Resolve skipped: invalid quotedRef accountId=${params.accountId} conversationId=${params.conversationId || \"(none)\"}`,\n );\n return null;\n }\n if (quotedRef.targetDirection === \"inbound\") {\n if (quotedRef.key !== \"msgId\" || !quotedRef.value) {\n log?.debug?.(\n `[DingTalk][QuotedRef] Resolve skipped: inbound quotedRef missing msgId accountId=${params.accountId} conversationId=${params.conversationId || \"(none)\"}`,\n );\n return null;\n }\n const record = resolveByMsgId({\n ...params,\n msgId: quotedRef.value,\n nowMs,\n });\n log?.debug?.(\n `[DingTalk][QuotedRef] Resolve inbound by msgId=${quotedRef.value} hit=${record ? \"yes\" : \"no\"} accountId=${params.accountId} conversationId=${params.conversationId || \"(none)\"}`,\n );\n return record;\n }\n if (quotedRef.key && quotedRef.value && quotedRef.key !== \"msgId\") {\n const aliasRecord = resolveByAlias({\n ...params,\n kind: quotedRef.key,\n value: quotedRef.value,\n nowMs,\n });\n if (aliasRecord) {\n log?.debug?.(\n `[DingTalk][QuotedRef] Resolve outbound by ${quotedRef.key}=${quotedRef.value} hit=yes accountId=${params.accountId} conversationId=${params.conversationId || \"(none)\"}`,\n );\n return aliasRecord;\n }\n log?.debug?.(\n `[DingTalk][QuotedRef] Resolve outbound by ${quotedRef.key}=${quotedRef.value} hit=no accountId=${params.accountId} conversationId=${params.conversationId || \"(none)\"}`,\n );\n }\n if (\n typeof quotedRef.fallbackCreatedAt === \"number\" &&\n Number.isFinite(quotedRef.fallbackCreatedAt)\n ) {\n const record = resolveByCreatedAtWindow({\n ...params,\n createdAt: quotedRef.fallbackCreatedAt,\n direction: \"outbound\",\n nowMs,\n });\n log?.debug?.(\n `[DingTalk][QuotedRef] Resolve outbound by createdAt=${quotedRef.fallbackCreatedAt} hit=${record ? \"yes\" : \"no\"} accountId=${params.accountId} conversationId=${params.conversationId || \"(none)\"}`,\n );\n return record;\n }\n log?.debug?.(\n `[DingTalk][QuotedRef] Resolve outbound missed without createdAt fallback accountId=${params.accountId} conversationId=${params.conversationId || \"(none)\"}`,\n );\n return null;\n}\n\nexport function resolveByCreatedAtWindow(\n params: ScopeParams & {\n createdAt: number;\n windowMs?: number;\n direction?: MessageContextDirection;\n nowMs?: number;\n },\n): MessageRecord | null {\n const nowMs = params.nowMs ?? Date.now();\n const windowMs = params.windowMs ?? DEFAULT_CREATED_AT_MATCH_WINDOW_MS;\n const state = loadState(params, nowMs);\n let bestRecord: MessageRecord | null = null;\n let bestDelta = Infinity;\n for (const msgId of state.recentByCreatedAt) {\n const record = state.records[msgId];\n if (!record || isRecordExpired(record, nowMs)) {\n continue;\n }\n if (params.direction && record.direction !== params.direction) {\n continue;\n }\n const delta = Math.abs(record.createdAt - params.createdAt);\n if (delta <= windowMs && delta < bestDelta) {\n bestDelta = delta;\n bestRecord = record;\n }\n }\n return bestRecord;\n}\n\nexport function cleanupExpiredMessageContexts(params: ScopeParams & { nowMs?: number }): number {\n const nowMs = params.nowMs ?? Date.now();\n const state = loadState(params, nowMs);\n const beforeCount = Object.keys(state.records).length;\n const normalized = normalizeState(state, nowMs).state;\n const removed = beforeCount - Object.keys(normalized.records).length;\n if (removed > 0) {\n normalized.updatedAt = nowMs;\n writeState(params, normalized);\n }\n return removed;\n}\n\nexport function clearMessageContextCacheForTest(): void {\n stateCache.clear();\n}\n\n/**\n * Lists non-expired message-context records for one account/conversation scope in createdAt ascending order.\n */\nexport function listMessageContexts(params: ScopeParams & { nowMs?: number }): MessageRecord[] {\n const nowMs = params.nowMs ?? Date.now();\n const state = loadState(params, nowMs);\n return state.recentByCreatedAt\n .map((msgId) => state.records[msgId])\n .filter(\n (record): record is MessageRecord => Boolean(record) && !isRecordExpired(record, nowMs),\n );\n}\n", "import { DWClient, TOPIC_CARD, TOPIC_ROBOT } from \"dingtalk-stream\";\nimport { analyzeCardCallback } from \"../card-callback-service\";\nimport { handleCardAction } from \"../card/card-action-handler\";\nimport {\n finalizeActiveCardsForAccount,\n recoverPendingCardsForAccount,\n} from \"../card-service\";\nimport { resolveRobotCode, resolveRuntimeConfig } from \"../config\";\nimport { ConnectionManager } from \"../connection-manager\";\nimport { isMessageProcessed, markMessageProcessed } from \"../dedup\";\nimport {\n isLearningAutoApplyEnabled,\n isLearningEnabled,\n recordExplicitFeedbackLearning,\n} from \"../feedback-learning-service\";\nimport { handleDingTalkMessage } from \"../inbound-handler\";\nimport { setCurrentLogger } from \"../logger-context\";\nimport { preloadPeerIdsFromSessions } from \"../peer-id-registry\";\nimport { getDingTalkRuntime } from \"../runtime\";\nimport { sendProactiveTextOrMarkdown } from \"../send-service\";\nimport type {\n ConnectionManagerConfig,\n DingTalkChannelPlugin,\n DingTalkInboundMessage,\n GatewayStartContext,\n GatewayStopResult,\n StreamClientFactory,\n} from \"../types\";\nimport { ConnectionState } from \"../types\";\nimport {\n closePluginDebugLog,\n cleanupOrphanedTempFiles,\n createResolve4FallbackLookup,\n formatDingTalkConnectionErrorLog,\n getCurrentTimestamp,\n resolvePluginDebugLog,\n} from \"../utils\";\n\ntype InstrumentedDWClient = {\n getEndpoint?: () => Promise<unknown>;\n _connect?: () => Promise<unknown>;\n config?: Record<string, unknown> & { endpoint?: { endpoint?: string } | string };\n dw_url?: string;\n};\n\nfunction attachConnectionErrorContext(\n err: unknown,\n stage: \"connect.open\" | \"connect.websocket\",\n endpoint?: string,\n): void {\n if (!err || typeof err !== \"object\") {\n return;\n }\n const target = err as Record<string, unknown>;\n if (typeof target.dingtalkConnectionStage !== \"string\") {\n target.dingtalkConnectionStage = stage;\n }\n if (endpoint && typeof target.dingtalkConnectionEndpoint !== \"string\") {\n target.dingtalkConnectionEndpoint = endpoint;\n }\n}\n\nfunction getInstrumentedEndpoint(client: InstrumentedDWClient): string | undefined {\n if (typeof client.dw_url === \"string\" && client.dw_url.length > 0) {\n return client.dw_url;\n }\n\n const endpointConfig = client.config?.endpoint;\n if (typeof endpointConfig === \"string\") {\n return endpointConfig;\n }\n if (\n endpointConfig &&\n typeof endpointConfig === \"object\" &&\n typeof endpointConfig.endpoint === \"string\"\n ) {\n return endpointConfig.endpoint;\n }\n return undefined;\n}\n\nfunction instrumentConnectionStages(client: DWClient): void {\n const instrumented = client as unknown as InstrumentedDWClient;\n if (\n typeof instrumented.getEndpoint !== \"function\" ||\n typeof instrumented._connect !== \"function\"\n ) {\n return;\n }\n\n const originalGetEndpoint = instrumented.getEndpoint.bind(instrumented);\n const originalSocketConnect = instrumented._connect.bind(instrumented);\n\n instrumented.getEndpoint = async () => {\n try {\n return await originalGetEndpoint();\n } catch (err) {\n attachConnectionErrorContext(err, \"connect.open\");\n throw err;\n }\n };\n\n instrumented._connect = async () => {\n try {\n return await originalSocketConnect();\n } catch (err) {\n attachConnectionErrorContext(err, \"connect.websocket\", getInstrumentedEndpoint(instrumented));\n throw err;\n }\n };\n}\n\nconst INFLIGHT_TTL_MS = 5 * 60 * 1000;\nconst processingDedupKeys = new Map<string, number>();\nexport const CHANNEL_INFLIGHT_NAMESPACE_POLICY = \"memory-only\" as const;\nconst inboundCountersByAccount = new Map<\n string,\n {\n received: number;\n acked: number;\n dedupSkipped: number;\n inflightSkipped: number;\n processed: number;\n failed: number;\n noMessageId: number;\n }\n>();\nconst INBOUND_COUNTER_LOG_EVERY = 10;\n\nfunction getInboundCounters(accountId: string) {\n const existing = inboundCountersByAccount.get(accountId);\n if (existing) {\n return existing;\n }\n const created = {\n received: 0,\n acked: 0,\n dedupSkipped: 0,\n inflightSkipped: 0,\n processed: 0,\n failed: 0,\n noMessageId: 0,\n };\n inboundCountersByAccount.set(accountId, created);\n return created;\n}\n\nfunction logInboundCounters(log: any, accountId: string, reason: string): void {\n const stats = getInboundCounters(accountId);\n log?.info?.(\n `[${accountId}] Inbound counters (${reason}): received=${stats.received}, acked=${stats.acked}, processed=${stats.processed}, dedupSkipped=${stats.dedupSkipped}, inflightSkipped=${stats.inflightSkipped}, failed=${stats.failed}, noMessageId=${stats.noMessageId}`,\n );\n}\n\nexport function createDingTalkGateway(): NonNullable<DingTalkChannelPlugin[\"gateway\"]> {\n return {\n startAccount: async (ctx: GatewayStartContext): Promise<GatewayStopResult> => {\n const { account, cfg, abortSignal } = ctx;\n const config = account.config;\n let accountStorePath: string | undefined;\n try {\n const runtime = getDingTalkRuntime();\n accountStorePath = runtime.channel.session.resolveStorePath(cfg.session?.store, {\n agentId: account.accountId,\n });\n } catch {\n accountStorePath = undefined;\n }\n\n const pluginLog = resolvePluginDebugLog({\n accountId: account.accountId,\n storePath: accountStorePath,\n debug: config.debug,\n baseLog: ctx.log,\n });\n // Stream credentials are resolved once per account start. If a file\n // SecretInput rotates, restart the gateway/account so reconnects use the\n // new secret.\n const runtimeConfig = await resolveRuntimeConfig(config, pluginLog);\n setCurrentLogger(pluginLog, account.accountId);\n\n pluginLog?.info?.(`[${account.accountId}] Initializing DingTalk Stream client...`);\n\n preloadPeerIdsFromSessions();\n pluginLog?.debug?.(`[${account.accountId}] Peer ID registry preloaded from sessions`);\n\n cleanupOrphanedTempFiles(pluginLog);\n try {\n const recovered = await recoverPendingCardsForAccount(\n config,\n account.accountId,\n accountStorePath,\n pluginLog,\n );\n if (recovered > 0) {\n pluginLog?.info?.(\n `[${account.accountId}] Recovered and finalized ${recovered} unfinished card(s) from previous runtime`,\n );\n }\n } catch (err: any) {\n pluginLog?.warn?.(\n `[${account.accountId}] Failed to recover unfinished cards: ${err.message}`,\n );\n }\n\n const useConnectionManager = config.useConnectionManager ?? true;\n const applyStatusPatch = (patch: Record<string, unknown>) => {\n ctx.setStatus({\n ...ctx.getStatus(),\n ...patch,\n });\n };\n\n const createStreamClient: StreamClientFactory = () => {\n const client = new DWClient({\n clientId: runtimeConfig.clientId,\n clientSecret: runtimeConfig.clientSecret,\n debug: runtimeConfig.debug || false,\n keepAlive: runtimeConfig.keepAlive ?? !useConnectionManager,\n });\n (client as any).sslopts = {\n ...(client as any).sslopts,\n lookup: createResolve4FallbackLookup(pluginLog, account.accountId),\n };\n\n instrumentConnectionStages(client);\n\n (client as any).config.autoReconnect = !useConnectionManager;\n\n client.registerCallbackListener(TOPIC_ROBOT, async (res: any) => {\n const messageId = res.headers?.messageId;\n const stats = getInboundCounters(account.accountId);\n stats.received += 1;\n const acknowledge = () => {\n if (!messageId) {\n return;\n }\n try {\n client.socketCallBackResponse(messageId, { success: true });\n stats.acked += 1;\n } catch (ackError: any) {\n pluginLog?.warn?.(\n `[${account.accountId}] Failed to acknowledge callback ${messageId}: ${ackError.message}`,\n );\n }\n };\n try {\n const data = JSON.parse(res.data) as DingTalkInboundMessage;\n applyStatusPatch({\n connected: true,\n lastInboundAt: getCurrentTimestamp(),\n lastEventAt: getCurrentTimestamp(),\n });\n\n const robotKey = resolveRobotCode(config) || account.accountId;\n const msgId = data.msgId || messageId;\n const dedupKey = msgId ? `${robotKey}:${msgId}` : undefined;\n\n if (!dedupKey) {\n ctx.log?.warn?.(`[${account.accountId}] No message ID available for deduplication`);\n stats.noMessageId += 1;\n acknowledge();\n await handleDingTalkMessage({\n cfg,\n accountId: account.accountId,\n data,\n sessionWebhook: data.sessionWebhook,\n log: pluginLog,\n dingtalkConfig: config,\n });\n stats.processed += 1;\n if (stats.received % INBOUND_COUNTER_LOG_EVERY === 0) {\n logInboundCounters(pluginLog, account.accountId, \"periodic\");\n }\n return;\n }\n\n if (isMessageProcessed(dedupKey)) {\n pluginLog?.debug?.(`[${account.accountId}] Skipping duplicate message: ${dedupKey}`);\n stats.dedupSkipped += 1;\n acknowledge();\n logInboundCounters(pluginLog, account.accountId, \"dedup-skipped\");\n return;\n }\n\n const inflightSince = processingDedupKeys.get(dedupKey);\n if (inflightSince !== undefined) {\n if (Date.now() - inflightSince > INFLIGHT_TTL_MS) {\n pluginLog?.warn?.(\n `[${account.accountId}] Releasing stale in-flight lock for ${dedupKey} (held ${Date.now() - inflightSince}ms > TTL ${INFLIGHT_TTL_MS}ms)`,\n );\n processingDedupKeys.delete(dedupKey);\n } else {\n pluginLog?.debug?.(\n `[${account.accountId}] Skipping in-flight duplicate message: ${dedupKey}`,\n );\n stats.inflightSkipped += 1;\n acknowledge();\n logInboundCounters(pluginLog, account.accountId, \"inflight-skipped\");\n return;\n }\n }\n\n acknowledge();\n processingDedupKeys.set(dedupKey, Date.now());\n try {\n await handleDingTalkMessage({\n cfg,\n accountId: account.accountId,\n data,\n sessionWebhook: data.sessionWebhook,\n log: pluginLog,\n dingtalkConfig: config,\n });\n stats.processed += 1;\n markMessageProcessed(dedupKey);\n if (stats.received % INBOUND_COUNTER_LOG_EVERY === 0) {\n logInboundCounters(pluginLog, account.accountId, \"periodic\");\n }\n } finally {\n processingDedupKeys.delete(dedupKey);\n }\n } catch (error: any) {\n stats.failed += 1;\n logInboundCounters(pluginLog, account.accountId, \"failed\");\n pluginLog?.error?.(`[${account.accountId}] Error processing message: ${error.message}`);\n }\n });\n\n client.registerCallbackListener(TOPIC_CARD, async (res: any) => {\n const messageId = res.headers?.messageId;\n const acknowledge = () => {\n if (!messageId) {\n return;\n }\n try {\n client.socketCallBackResponse(messageId, { success: true });\n } catch (ackError: any) {\n pluginLog?.warn?.(\n `[${account.accountId}] Failed to acknowledge card callback ${messageId}: ${ackError.message}`,\n );\n }\n };\n\n try {\n const payload = JSON.parse(res.data);\n const analysis = analyzeCardCallback(payload);\n pluginLog?.info?.(\n `[${account.accountId}] [DingTalk][CardCallback] action=${analysis.summary} raw=${JSON.stringify(payload)}`,\n );\n\n if (analysis.feedbackTarget && analysis.feedbackAckText) {\n recordExplicitFeedbackLearning({\n enabled: isLearningEnabled(config),\n autoApply: isLearningAutoApplyEnabled(config),\n storePath: accountStorePath,\n accountId: account.accountId,\n targetId: analysis.feedbackTarget,\n feedbackType: analysis.actionId === \"feedback_up\" ? \"feedback_up\" : \"feedback_down\",\n userId: analysis.userId,\n processQueryKey: analysis.processQueryKey,\n noteTtlMs: config.learningNoteTtlMs,\n });\n try {\n await sendProactiveTextOrMarkdown(\n config,\n analysis.feedbackTarget,\n analysis.feedbackAckText,\n {\n accountId: account.accountId,\n log: pluginLog,\n },\n );\n pluginLog?.info?.(\n `[${account.accountId}] [DingTalk][CardCallback] feedback ack sent to ${analysis.feedbackTarget}`,\n );\n } catch (sendErr: any) {\n pluginLog?.warn?.(\n `[${account.accountId}] [DingTalk][CardCallback] Failed to send feedback ack: ${sendErr?.message || String(sendErr)}`,\n );\n }\n }\n const actionResult = await handleCardAction({\n analysis,\n cfg,\n accountId: account.accountId,\n config,\n log: pluginLog,\n });\n if (\n !actionResult.handled &&\n analysis.actionId &&\n analysis.actionId !== \"feedback_up\" &&\n analysis.actionId !== \"feedback_down\"\n ) {\n pluginLog?.debug?.(\n `[${account.accountId}] [DingTalk][CardCallback] Unhandled actionId=${analysis.actionId}`,\n );\n }\n } catch (error: any) {\n pluginLog?.error?.(\n `[${account.accountId}] [DingTalk][CardCallback] Failed to parse callback: ${error.message}`,\n );\n } finally {\n acknowledge();\n }\n });\n\n return client;\n };\n\n const client = createStreamClient();\n\n let stopped = false;\n let nativeStopResolve: (() => void) | undefined;\n const nativeStopPromise = new Promise<void>((resolve) => {\n nativeStopResolve = resolve;\n });\n let connectionManager: ConnectionManager | undefined;\n\n const stopClient = () => {\n if (stopped) {\n return;\n }\n stopped = true;\n pluginLog?.info?.(`[${account.accountId}] Stopping DingTalk Stream client...`);\n void finalizeActiveCardsForAccount(\n config,\n account.accountId,\n \"\u26A0\uFE0F \u670D\u52A1\u6B63\u5728\u91CD\u542F\uFF0C\u5F53\u524D\u56DE\u590D\u5DF2\u4E2D\u65AD\u3002\u8BF7\u91CD\u65B0\u53D1\u9001\u4F60\u7684\u95EE\u9898\u3002\",\n accountStorePath,\n pluginLog,\n ).catch((err: any) => {\n pluginLog?.debug?.(\n `[${account.accountId}] Failed to finalize active cards during stop: ${err.message}`,\n );\n });\n if (useConnectionManager) {\n connectionManager?.stop();\n } else {\n try {\n client.disconnect();\n } catch (err: any) {\n pluginLog?.warn?.(`[${account.accountId}] Error during disconnect: ${err.message}`);\n }\n nativeStopResolve?.();\n }\n\n applyStatusPatch({\n running: false,\n connected: false,\n lastEventAt: getCurrentTimestamp(),\n lastStopAt: getCurrentTimestamp(),\n });\n\n pluginLog?.info?.(`[${account.accountId}] DingTalk Stream client stopped`);\n closePluginDebugLog({\n accountId: account.accountId,\n storePath: accountStorePath,\n });\n };\n\n if (abortSignal) {\n if (abortSignal.aborted) {\n pluginLog?.warn?.(\n `[${account.accountId}] Abort signal already active, skipping connection`,\n );\n\n applyStatusPatch({\n running: false,\n connected: false,\n lastEventAt: getCurrentTimestamp(),\n lastStopAt: getCurrentTimestamp(),\n lastError: \"Connection aborted before start\",\n });\n\n throw new Error(\"Connection aborted before start\");\n }\n\n abortSignal.addEventListener(\"abort\", () => {\n if (stopped) {\n return;\n }\n pluginLog?.info?.(\n `[${account.accountId}] Abort signal received, stopping DingTalk Stream client...`,\n );\n stopClient();\n });\n }\n\n if (!useConnectionManager) {\n try {\n await client.connect();\n if (!stopped) {\n applyStatusPatch({\n running: true,\n connected: true,\n lastConnectedAt: getCurrentTimestamp(),\n lastEventAt: getCurrentTimestamp(),\n lastStartAt: getCurrentTimestamp(),\n lastError: null,\n });\n pluginLog?.info?.(`[${account.accountId}] DingTalk Stream client connected successfully`);\n await nativeStopPromise;\n }\n } catch (err: any) {\n pluginLog?.error?.(\n formatDingTalkConnectionErrorLog(\n \"connect.open\",\n err,\n `[${account.accountId}] Failed to establish connection: ${err.message}`,\n ) ?? `[${account.accountId}] Failed to establish connection: ${err.message}`,\n );\n applyStatusPatch({\n running: false,\n connected: false,\n lastEventAt: getCurrentTimestamp(),\n lastError: err.message || \"Connection failed\",\n });\n throw err;\n }\n\n return {\n stop: () => {\n stopClient();\n },\n };\n }\n\n const connectionConfig: ConnectionManagerConfig = {\n maxAttempts: config.maxConnectionAttempts ?? 10,\n initialDelay: config.initialReconnectDelay ?? 1000,\n maxDelay: config.maxReconnectDelay ?? 60000,\n jitter: config.reconnectJitter ?? 0.3,\n maxReconnectCycles: config.maxReconnectCycles,\n reconnectDeadlineMs: config.reconnectDeadlineMs,\n onStateChange: (state: ConnectionState, error?: string) => {\n if (stopped) {\n return;\n }\n pluginLog?.debug?.(\n `[${account.accountId}] Connection state changed to: ${state}${error ? ` (${error})` : \"\"}`,\n );\n if (state === ConnectionState.CONNECTED) {\n applyStatusPatch({\n running: true,\n connected: true,\n lastConnectedAt: getCurrentTimestamp(),\n lastEventAt: getCurrentTimestamp(),\n lastStartAt: getCurrentTimestamp(),\n lastError: null,\n });\n } else if (state === ConnectionState.FAILED || state === ConnectionState.DISCONNECTED) {\n const robotKey = resolveRobotCode(config) || account.accountId;\n let cleared = 0;\n for (const key of processingDedupKeys.keys()) {\n if (key.startsWith(`${robotKey}:`)) {\n processingDedupKeys.delete(key);\n cleared++;\n }\n }\n if (cleared > 0) {\n pluginLog?.info?.(\n `[${account.accountId}] Cleared ${cleared} stale in-flight lock(s) on disconnect`,\n );\n }\n applyStatusPatch({\n running: false,\n connected: false,\n lastEventAt: getCurrentTimestamp(),\n lastError: error || `Connection ${state.toLowerCase()}`,\n });\n }\n },\n };\n\n pluginLog?.debug?.(\n `[${account.accountId}] Connection config: maxAttempts=${connectionConfig.maxAttempts}, ` +\n `initialDelay=${connectionConfig.initialDelay}ms, maxDelay=${connectionConfig.maxDelay}ms, ` +\n `jitter=${connectionConfig.jitter}`,\n );\n\n connectionManager = new ConnectionManager(\n client,\n account.accountId,\n connectionConfig,\n pluginLog,\n createStreamClient,\n );\n\n try {\n await connectionManager.connect();\n\n if (!stopped && connectionManager.isConnected()) {\n applyStatusPatch({\n running: true,\n connected: true,\n lastConnectedAt: getCurrentTimestamp(),\n lastEventAt: getCurrentTimestamp(),\n lastStartAt: getCurrentTimestamp(),\n lastError: null,\n });\n pluginLog?.info?.(`[${account.accountId}] DingTalk Stream client connected successfully`);\n\n await connectionManager.waitForStop();\n } else {\n pluginLog?.info?.(\n `[${account.accountId}] DingTalk Stream client connect() completed but channel is ` +\n `not running (stopped=${stopped}, connected=${connectionManager.isConnected()})`,\n );\n }\n } catch (err: any) {\n pluginLog?.error?.(\n formatDingTalkConnectionErrorLog(\n \"connect.open\",\n err,\n `[${account.accountId}] Failed to establish connection: ${err.message}`,\n ) ?? `[${account.accountId}] Failed to establish connection: ${err.message}`,\n );\n\n applyStatusPatch({\n running: false,\n connected: false,\n lastEventAt: getCurrentTimestamp(),\n lastError: err.message || \"Connection failed\",\n });\n throw err;\n }\n\n return {\n stop: () => {\n stopClient();\n },\n };\n },\n };\n}\n", "import axios from \"./http-client\";\nimport { getProxyBypassOption } from \"./utils\";\n\nconst DINGTALK_API = \"https://api.dingtalk.com\";\n\nexport interface CardCallbackAnalysis {\n summary: string;\n actionId?: string;\n feedbackTarget?: string;\n feedbackAckText?: string;\n userId?: string;\n spaceId?: string;\n processQueryKey?: string;\n outTrackId?: string;\n cardInstanceId?: string;\n}\n\nfunction stringifyCandidate(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n try {\n return JSON.stringify(value);\n } catch {\n return \"[unserializable]\";\n }\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return undefined;\n }\n return value as Record<string, unknown>;\n}\n\nfunction parseEmbeddedJson(value: unknown): unknown {\n if (typeof value !== \"string\") {\n return value;\n }\n try {\n return JSON.parse(value);\n } catch {\n return value;\n }\n}\n\nexport function extractCardActionSummary(data: unknown): string {\n const record = asRecord(data);\n const candidates = [\n record?.action,\n record?.actionType,\n record?.actionValue,\n record?.value,\n record?.eventType,\n record?.operate,\n record?.callbackType,\n record?.cardPrivateData,\n record?.privateData,\n ].filter((value) => value !== undefined && value !== null);\n\n if (candidates.length === 0) {\n return \"(no action field found)\";\n }\n\n return candidates.map(stringifyCandidate).join(\" | \");\n}\n\nexport function extractCardActionId(data: unknown): string | undefined {\n const record = asRecord(data);\n const embeddedValue = parseEmbeddedJson(record?.value);\n const embeddedContent = parseEmbeddedJson(record?.content);\n\n for (const source of [embeddedValue, embeddedContent, record].filter(Boolean)) {\n const sourceRecord = asRecord(source);\n const cardPrivateData = asRecord(sourceRecord?.cardPrivateData);\n const actionIds = cardPrivateData?.actionIds;\n if (Array.isArray(actionIds) && actionIds.length > 0 && typeof actionIds[0] === \"string\") {\n return actionIds[0];\n }\n if (typeof sourceRecord?.actionValue === \"string\" && sourceRecord.actionValue.trim()) {\n return sourceRecord.actionValue.trim();\n }\n if (typeof sourceRecord?.eventKey === \"string\" && sourceRecord.eventKey.trim()) {\n return sourceRecord.eventKey.trim();\n }\n if (typeof sourceRecord?.value === \"string\" && sourceRecord.value.trim()) {\n return sourceRecord.value.trim();\n }\n }\n\n return undefined;\n}\n\nexport function analyzeCardCallback(data: unknown): CardCallbackAnalysis {\n const record = asRecord(data);\n const summary = extractCardActionSummary(data);\n const actionId = extractCardActionId(data);\n const embeddedValue = asRecord(parseEmbeddedJson(record?.value));\n const embeddedContent = asRecord(parseEmbeddedJson(record?.content));\n const embeddedCardPrivateData = asRecord(parseEmbeddedJson(record?.cardPrivateData));\n const embeddedValuePrivateData = asRecord(parseEmbeddedJson(embeddedValue?.cardPrivateData));\n const embeddedContentPrivateData = asRecord(parseEmbeddedJson(embeddedContent?.cardPrivateData));\n const candidateRecords = [\n record,\n embeddedValue,\n embeddedContent,\n embeddedCardPrivateData,\n embeddedValuePrivateData,\n embeddedContentPrivateData,\n ].filter(Boolean) as Array<Record<string, unknown>>;\n const pickString = (...keys: string[]): string | undefined => {\n for (const source of candidateRecords) {\n for (const key of keys) {\n const value = source[key];\n if (typeof value === \"string\" && value.trim()) {\n return value.trim();\n }\n }\n }\n return undefined;\n };\n const processQueryKey =\n pickString(\"processQueryKey\");\n const outTrackId = pickString(\"outTrackId\");\n const cardInstanceId = pickString(\"cardInstanceId\");\n // For non-feedback paths, pickString is fine for spaceId/userId (broad search).\n // For feedback paths, use precise extraction from record to avoid picking a\n // same-named but different-valued spaceId from nested embedded objects.\n const spaceId = pickString(\"spaceId\");\n const userId = pickString(\"userId\");\n\n if (actionId !== \"feedback_up\" && actionId !== \"feedback_down\") {\n return {\n summary,\n actionId,\n userId,\n spaceId,\n processQueryKey,\n outTrackId,\n cardInstanceId,\n };\n }\n\n // Feedback path: use precise extraction for spaceId/userId to avoid misrouting\n // feedbackTarget when nested objects contain same-named fields with different values.\n const preciseSpaceId =\n (typeof record?.spaceId === \"string\" && record.spaceId.trim()) || spaceId;\n const preciseUserId =\n (typeof record?.userId === \"string\" && record.userId.trim()) || userId;\n const spaceType = typeof record?.spaceType === \"string\" ? record.spaceType.trim().toLowerCase() : \"\";\n const feedbackTarget = spaceType === \"im\" ? preciseUserId : preciseSpaceId;\n const feedbackAckText =\n actionId === \"feedback_up\"\n ? \"\u2705 \u5DF2\u6536\u5230\u4F60\u7684\u70B9\u8D5E\uFF08\u53CD\u9988\u5DF2\u8BB0\u5F55\uFF09\"\n : \"\u26A0\uFE0F \u5DF2\u6536\u5230\u4F60\u7684\u70B9\u8E29\uFF08\u53CD\u9988\u5DF2\u8BB0\u5F55\uFF0C\u6211\u4F1A\u6539\u8FDB\uFF09\";\n\n return {\n summary,\n actionId,\n feedbackTarget: feedbackTarget || undefined,\n feedbackAckText,\n userId: userId || undefined,\n spaceId: spaceId || undefined,\n processQueryKey,\n outTrackId,\n cardInstanceId,\n };\n}\n\n/**\n * Update card variables via PUT /v1.0/card/instances.\n * Echoes params back into cardParamMap so the template can use conditional\n * rendering (e.g. hiding buttons when a param is set).\n */\nexport async function updateCardVariables(\n outTrackId: string,\n params: Record<string, unknown>,\n token: string,\n config?: { bypassProxyForSend?: boolean },\n): Promise<number> {\n const stringMap: Record<string, string> = {};\n for (const [k, v] of Object.entries(params)) {\n stringMap[k] = typeof v === \"string\" ? v : JSON.stringify(v);\n }\n const resp = await axios.put(\n `${DINGTALK_API}/v1.0/card/instances`,\n {\n outTrackId,\n cardData: { cardParamMap: stringMap },\n cardUpdateOptions: { updateCardDataByKey: true, updatePrivateDataByKey: true },\n },\n {\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-acs-dingtalk-access-token\": token,\n },\n ...getProxyBypassOption(config),\n },\n );\n return resp.status;\n}\n", "/**\n * In-process card run registry for tracking active AI card runs.\n *\n * DEPLOYMENT CONSTRAINT: This registry uses a process-local Map. In multi-process\n * deployments (cluster/PM2), stop callbacks may route to a different worker than\n * the one that created the card run, causing resolveCardRun to return null and\n * the stop button to silently fail. Ensure single-process deployment or sticky\n * routing per card callback when using the stop button feature.\n */\nimport type { CardDraftController } from \"../card-draft-controller\";\nimport type { AICardInstance } from \"../types\";\n\nexport interface CardRunRecord {\n outTrackId: string;\n accountId: string;\n sessionKey: string;\n /** OpenClaw agent ID resolved from the inbound route. */\n agentId: string;\n /** DingTalk userId of the user who initiated this card run. */\n ownerUserId?: string;\n card?: AICardInstance;\n controller?: CardDraftController;\n stopRequestedAt?: number;\n registeredAt: number;\n}\n\nconst CARD_RUN_TTL_MS = 30 * 60 * 1000;\nconst SWEEP_INTERVAL_MS = 5 * 60 * 1000;\n\nconst records = new Map<string, CardRunRecord>();\n\nlet sweepTimer: ReturnType<typeof setInterval> | null = null;\n\nfunction ensureSweepTimer(): void {\n if (sweepTimer) {\n return;\n }\n sweepTimer = setInterval(() => {\n const now = Date.now();\n for (const [key, record] of records) {\n if (now - record.registeredAt > CARD_RUN_TTL_MS) {\n records.delete(key);\n }\n }\n if (records.size === 0 && sweepTimer) {\n clearInterval(sweepTimer);\n sweepTimer = null;\n }\n }, SWEEP_INTERVAL_MS);\n // Allow the process to exit without waiting for this timer.\n if (typeof sweepTimer === \"object\" && \"unref\" in sweepTimer) {\n sweepTimer.unref();\n }\n}\n\nexport function registerCardRun(\n outTrackId: string,\n params: {\n accountId: string;\n sessionKey: string;\n agentId: string;\n ownerUserId?: string;\n card?: AICardInstance;\n /** Override registeredAt timestamp (useful for tests). */\n registeredAt?: number;\n },\n): void {\n const trimmed = outTrackId.trim();\n if (!trimmed) {\n return;\n }\n records.set(trimmed, {\n outTrackId: trimmed,\n accountId: params.accountId,\n sessionKey: params.sessionKey,\n agentId: params.agentId,\n ownerUserId: params.ownerUserId,\n card: params.card,\n registeredAt: params.registeredAt ?? Date.now(),\n });\n ensureSweepTimer();\n}\n\nexport function attachCardRunController(outTrackId: string, controller: CardDraftController): void {\n const record = records.get(outTrackId.trim());\n if (record) {\n record.controller = controller;\n }\n}\n\nexport function resolveCardRun(outTrackId: string): CardRunRecord | null {\n return records.get(outTrackId.trim()) ?? null;\n}\n\n/**\n * Find the most recently registered card run for a given account + conversation.\n * Uses case-insensitive match of the conversationId within sessionKey.\n *\n * @param accountId - The DingTalk account ID\n * @param conversationId - The target conversation ID (matches within sessionKey)\n * @param options - Optional filtering criteria\n * @param options.ownerUserId - If provided, only return runs owned by this user\n */\nexport function resolveCardRunByConversation(\n accountId: string,\n conversationId: string,\n options?: { ownerUserId?: string },\n): CardRunRecord | null {\n const lowerCid = conversationId.toLowerCase();\n const targetOwner = options?.ownerUserId;\n let latest: CardRunRecord | null = null;\n for (const record of records.values()) {\n if (record.accountId !== accountId) { continue; }\n if (!record.sessionKey.toLowerCase().includes(lowerCid)) { continue; }\n // If ownerUserId filter is specified, only match runs owned by that user\n if (targetOwner !== undefined && record.ownerUserId !== targetOwner) { continue; }\n if (!latest || record.registeredAt > latest.registeredAt) {\n latest = record;\n }\n }\n return latest;\n}\n\n/**\n * Find the most recently registered card run for a given account + owner.\n * This is a fallback query when conversationId is unavailable (e.g., sessionKey=-).\n *\n * @param accountId - The DingTalk account ID\n * @param ownerUserId - The DingTalk userId of the card owner\n */\nexport function resolveCardRunByOwner(\n accountId: string,\n ownerUserId: string,\n): CardRunRecord | null {\n let latest: CardRunRecord | null = null;\n for (const record of records.values()) {\n if (record.accountId !== accountId) { continue; }\n if (record.ownerUserId !== ownerUserId) { continue; }\n if (!latest || record.registeredAt > latest.registeredAt) {\n latest = record;\n }\n }\n return latest;\n}\n\nexport function markCardRunStopRequested(outTrackId: string): void {\n const record = records.get(outTrackId.trim());\n if (record && !record.stopRequestedAt) {\n record.stopRequestedAt = Date.now();\n }\n}\n\nexport function isCardRunStopRequested(outTrackId: string): boolean {\n return Boolean(records.get(outTrackId.trim())?.stopRequestedAt);\n}\n\nexport function removeCardRun(outTrackId: string): void {\n records.delete(outTrackId.trim());\n if (records.size === 0 && sweepTimer) {\n clearInterval(sweepTimer);\n sweepTimer = null;\n }\n}\n\nexport function clearCardRunRegistryForTest(): void {\n records.clear();\n if (sweepTimer) {\n clearInterval(sweepTimer);\n sweepTimer = null;\n }\n}\n", "import { randomUUID } from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport axios from \"./http-client\";\nimport { getAccessToken } from \"./auth\";\nimport { updateCardVariables } from \"./card-callback-service\";\nimport { DINGTALK_CARD_TEMPLATE, STOP_ACTION_VISIBLE, STOP_ACTION_HIDDEN } from \"./card/card-template\";\nimport { resolveRobotCode, stripTargetPrefix } from \"./config\";\nimport { resolveOriginalPeerId } from \"./peer-id-registry\";\nimport {\n createSyntheticOutboundMsgId,\n clearMessageContextCacheForTest,\n DEFAULT_CARD_CONTENT_TTL_MS,\n DEFAULT_CREATED_AT_MATCH_WINDOW_MS,\n DEFAULT_OUTBOUND_SENDER,\n inferConversationChatType,\n resolveByCreatedAtWindow,\n upsertOutboundMessageContext,\n} from \"./message-context-store\";\nimport {\n readNamespaceJson,\n resolveNamespacePath,\n writeNamespaceJsonAtomic,\n} from \"./persistence-store\";\nimport type {\n AICardInstance,\n AICardStreamingRequest,\n CardBlock,\n DingTalkConfig,\n DingTalkTrackingMetadata,\n Logger,\n QuotedRef,\n} from \"./types\";\nimport { AICardStatus } from \"./types\";\nimport { formatDingTalkErrorPayloadLog, getProxyBypassOption } from \"./utils\";\n\nconst DINGTALK_API = \"https://api.dingtalk.com\";\n// Thinking/tool stream snippets are truncated to keep card updates compact.\nconst CARD_STATE_FILE_VERSION = 1;\nconst CARD_PENDING_NAMESPACE = \"cards.active.pending\";\nconst RECOVERY_FINALIZE_MESSAGE = \"\u26A0\uFE0F \u4E0A\u4E00\u6B21\u56DE\u590D\u5904\u7406\u4E2D\u65AD\uFF0C\u5DF2\u81EA\u52A8\u7ED3\u675F\u3002\u8BF7\u91CD\u65B0\u53D1\u9001\u4F60\u7684\u95EE\u9898\u3002\";\nconst AICARD_DEGRADE_DEFAULT_MS = 30 * 60 * 1000;\nconst CARD_CACHE_MAX_PER_CONVERSATION = 20;\nconst CARD_CACHE_MAX_CONVERSATIONS = 500;\nconst DYNAMIC_SUMMARY_EXTENSION = { dynamicSummary: \"true\" } as const;\n\nconst aicardDegradeByAccount = new Map<string, { untilMs: number; reason: string }>();\n\nexport async function hideCardStopButton(\n outTrackId: string,\n token: string,\n config?: { bypassProxyForSend?: boolean },\n retries = 2,\n): Promise<void> {\n for (let attempt = 0; ; attempt++) {\n try {\n await updateCardVariables(\n outTrackId,\n { hasAction: String(STOP_ACTION_HIDDEN), stop_action: String(STOP_ACTION_HIDDEN) },\n token,\n config,\n );\n return;\n } catch (err) {\n if (attempt >= retries) {\n throw err;\n }\n await new Promise((r) => setTimeout(r, 500 * (attempt + 1)));\n }\n }\n}\n\nconst inMemoryCardContentStore = new Map<\n string,\n {\n entries: Array<{ content: string; createdAt: number; expiresAt: number }>;\n lastActiveAt: number;\n }\n>();\n\nfunction pruneInMemoryCardContentEntries(\n entries: Array<{ content: string; createdAt: number; expiresAt: number }>,\n nowMs: number,\n): Array<{ content: string; createdAt: number; expiresAt: number }> {\n return entries.filter((entry) => nowMs < entry.expiresAt).slice(-CARD_CACHE_MAX_PER_CONVERSATION);\n}\n\nfunction touchInMemoryCardContentBucket(scopeKey: string, nowMs: number): {\n entries: Array<{ content: string; createdAt: number; expiresAt: number }>;\n lastActiveAt: number;\n} {\n const existing = inMemoryCardContentStore.get(scopeKey);\n const bucket = existing\n ? {\n entries: pruneInMemoryCardContentEntries(existing.entries, nowMs),\n lastActiveAt: nowMs,\n }\n : { entries: [], lastActiveAt: nowMs };\n inMemoryCardContentStore.set(scopeKey, bucket);\n if (inMemoryCardContentStore.size > CARD_CACHE_MAX_CONVERSATIONS) {\n let oldestKey: string | undefined;\n let oldestTime = Infinity;\n for (const [key, candidate] of inMemoryCardContentStore) {\n if (candidate.lastActiveAt < oldestTime) {\n oldestTime = candidate.lastActiveAt;\n oldestKey = key;\n }\n }\n if (oldestKey) {\n inMemoryCardContentStore.delete(oldestKey);\n }\n }\n return bucket;\n}\n\nfunction getAICardDegradeMs(config?: DingTalkConfig): number {\n const raw = config?.aicardDegradeMs;\n if (typeof raw === \"number\" && Number.isFinite(raw) && raw >= 60_000) {\n return raw;\n }\n return AICARD_DEGRADE_DEFAULT_MS;\n}\n\nfunction normalizeDegradeErrorMessage(value: string): string {\n return value.toLowerCase().replace(/[^a-z0-9]+/g, \"\");\n}\n\nfunction shouldTriggerAICardDegrade(err: unknown): boolean {\n const maybeErr = err as {\n response?: { status?: number; data?: { message?: string } };\n message?: string;\n };\n const status = maybeErr.response?.status;\n const msg = normalizeDegradeErrorMessage(\n String(maybeErr.response?.data?.message || maybeErr.message || \"\"),\n );\n if (status === 403 || status === 429) {\n return true;\n }\n if (typeof status === \"number\" && status >= 500 && status < 600) {\n return true;\n }\n return [\n \"ipnotinwhitelist\",\n \"forbiddenaccessdenied\",\n \"timeout\",\n \"etimedout\",\n \"econnreset\",\n \"eaiagain\",\n \"sockethangup\",\n \"badgateway\",\n ].some((keyword) => msg.includes(keyword));\n}\n\nexport function isAICardDegraded(accountId: string): boolean {\n const state = aicardDegradeByAccount.get(accountId);\n if (!state) {\n return false;\n }\n if (Date.now() >= state.untilMs) {\n aicardDegradeByAccount.delete(accountId);\n return false;\n }\n return true;\n}\n\nexport function getAICardDegradeState(\n accountId: string,\n): { remainingMs: number; reason: string } | null {\n const state = aicardDegradeByAccount.get(accountId);\n if (!state) {\n return null;\n }\n const remainingMs = state.untilMs - Date.now();\n if (remainingMs <= 0) {\n aicardDegradeByAccount.delete(accountId);\n return null;\n }\n return { remainingMs, reason: state.reason };\n}\n\nexport function activateAICardDegrade(\n accountId: string,\n reason: string,\n config?: DingTalkConfig,\n log?: Logger,\n): void {\n const durationMs = getAICardDegradeMs(config);\n const untilMs = Date.now() + durationMs;\n const existed = isAICardDegraded(accountId);\n aicardDegradeByAccount.set(accountId, { untilMs, reason });\n const minutes = Math.round(durationMs / 60000);\n if (existed) {\n log?.warn?.(\n `[DingTalk][AICard][Degrade] Extended for account=${accountId}, minutes=${minutes}, reason=${reason}`,\n );\n } else {\n log?.warn?.(\n `[DingTalk][AICard][Degrade] Activated for account=${accountId}, minutes=${minutes}, reason=${reason}`,\n );\n }\n}\n\nexport function clearAICardDegrade(accountId: string, log?: Logger): void {\n if (!aicardDegradeByAccount.has(accountId)) {\n return;\n }\n const reason = aicardDegradeByAccount.get(accountId)?.reason || \"\";\n aicardDegradeByAccount.delete(accountId);\n log?.info?.(`[DingTalk][AICard][Degrade] Cleared for account=${accountId}, lastReason=${reason}`);\n}\n\nexport function incrementCardDapiCount(card: AICardInstance): number {\n const next = (card.dapiUsage || 0) + 1;\n card.dapiUsage = next;\n return next;\n}\n\nfunction markStreamingLifecycleAcknowledged(card: AICardInstance, finished: boolean): void {\n card.streamLifecycleOpened = !finished;\n}\n\nfunction extractCardProcessQueryKey(payload: unknown): string | undefined {\n if (!payload || typeof payload !== \"object\") {\n return undefined;\n }\n const data = payload as Record<string, any>;\n const deliverResults = data.result?.deliverResults;\n if (Array.isArray(deliverResults)) {\n for (const item of deliverResults) {\n if (typeof item?.carrierId === \"string\" && item.carrierId.trim()) {\n return item.carrierId.trim();\n }\n }\n }\n return undefined;\n}\n\nasync function putAICardStreamingField(\n card: AICardInstance,\n key: string,\n content: string,\n finished: boolean,\n log?: Logger,\n options: { suppressDegrade?: boolean } = {},\n): Promise<void> {\n const tokenAge = Date.now() - card.createdAt;\n const tokenRefreshThreshold = 90 * 60 * 1000;\n let tokenAlreadyRefreshed = false;\n\n if (tokenAge > tokenRefreshThreshold && card.config) {\n log?.debug?.(\"[DingTalk][AICard] Token age exceeds threshold, refreshing...\");\n try {\n card.accessToken = await getAccessToken(card.config, log);\n tokenAlreadyRefreshed = true;\n log?.debug?.(\"[DingTalk][AICard] Token refreshed successfully\");\n } catch (err: any) {\n log?.warn?.(`[DingTalk][AICard] Failed to refresh token: ${err.message}`);\n }\n }\n\n const streamBody: AICardStreamingRequest = {\n outTrackId: card.outTrackId || card.cardInstanceId,\n guid: randomUUID(),\n key,\n content,\n isFull: true,\n isFinalize: finished,\n isError: false,\n };\n\n log?.debug?.(\n `[DingTalk][AICard] PUT /v1.0/card/streaming key=${key} contentLen=${content.length} isFull=true isFinalize=${finished} guid=${streamBody.guid} payload=${JSON.stringify(streamBody)}`,\n );\n\n const requestConfig = {\n headers: {\n \"x-acs-dingtalk-access-token\": card.accessToken,\n \"Content-Type\": \"application/json\",\n },\n ...(card.config ? getProxyBypassOption(card.config) : {}),\n };\n\n try {\n const streamResp = await axios.put(`${DINGTALK_API}/v1.0/card/streaming`, streamBody, requestConfig);\n log?.debug?.(\n `[DingTalk][AICard] Streaming response: status=${streamResp.status}, data=${JSON.stringify(streamResp.data)}`,\n );\n card.lastUpdated = Date.now();\n incrementCardDapiCount(card);\n markStreamingLifecycleAcknowledged(card, finished);\n } catch (err: any) {\n if (err.response?.status === 401 && card.config && !tokenAlreadyRefreshed) {\n log?.warn?.(\"[DingTalk][AICard] Received 401 error, attempting token refresh and retry...\");\n try {\n card.accessToken = await getAccessToken(card.config, log);\n const retryResp = await axios.put(`${DINGTALK_API}/v1.0/card/streaming`, streamBody, {\n ...requestConfig,\n headers: {\n ...requestConfig.headers,\n \"x-acs-dingtalk-access-token\": card.accessToken,\n },\n });\n log?.debug?.(\n `[DingTalk][AICard] Retry after token refresh succeeded: status=${retryResp.status}`,\n );\n card.lastUpdated = Date.now();\n incrementCardDapiCount(card);\n markStreamingLifecycleAcknowledged(card, finished);\n return;\n } catch (retryErr: any) {\n log?.error?.(`[DingTalk][AICard] Retry after token refresh failed: ${retryErr.message}`);\n if (retryErr.response?.data !== undefined) {\n log?.error?.(\n formatDingTalkErrorPayloadLog(\n \"card.stream.retryAfterRefresh\",\n retryErr.response.data,\n \"[DingTalk][AICard]\",\n ),\n );\n }\n }\n }\n\n if (!options.suppressDegrade && card.accountId && shouldTriggerAICardDegrade(err)) {\n activateAICardDegrade(\n card.accountId,\n `card.stream:${err?.response?.status || \"unknown\"}`,\n card.config,\n log,\n );\n }\n log?.error?.(`[DingTalk][AICard] Streaming update failed: key=${key} ${err.message}`);\n if (err.response?.data !== undefined) {\n log?.error?.(\n formatDingTalkErrorPayloadLog(\"card.stream\", err.response.data, \"[DingTalk][AICard]\"),\n );\n }\n throw err;\n }\n}\n\ninterface CreateAICardOptions {\n accountId?: string;\n storePath?: string;\n persistPending?: boolean;\n contextConversationId?: string;\n /** Quote content to display in card header (shown when non-empty) */\n quoteContent?: string;\n /** Initial statusLine string to show on the first createAndDeliver render. */\n statusLine?: string;\n}\n\ninterface PendingCardRecord {\n accountId: string;\n cardInstanceId: string;\n outTrackId?: string;\n conversationId: string;\n contextConversationId?: string;\n createdAt: number;\n lastUpdated: number;\n state: string;\n lastContent?: string;\n lastBlockListJson?: string;\n streamLifecycleOpened?: boolean;\n}\n\ninterface PendingCardStateFile {\n version: number;\n updatedAt: number;\n pendingCards: PendingCardRecord[];\n}\n\nfunction getCardStateFilePath(storePath?: string): string | null {\n if (!storePath) {\n return null;\n }\n return resolveNamespacePath(CARD_PENDING_NAMESPACE, {\n storePath,\n format: \"json\",\n });\n}\n\nfunction getLegacyCardStateFilePath(storePath?: string): string | null {\n if (!storePath) {\n return null;\n }\n return path.join(path.dirname(storePath), \"dingtalk-active-cards.json\");\n}\n\nfunction normalizePendingState(parsed: Partial<PendingCardStateFile>): PendingCardStateFile {\n const records = Array.isArray(parsed.pendingCards) ? parsed.pendingCards : [];\n return {\n version: typeof parsed.version === \"number\" ? parsed.version : CARD_STATE_FILE_VERSION,\n updatedAt: typeof parsed.updatedAt === \"number\" ? parsed.updatedAt : Date.now(),\n pendingCards: records.filter((entry): entry is PendingCardRecord =>\n Boolean(\n entry &&\n typeof entry.accountId === \"string\" &&\n typeof entry.cardInstanceId === \"string\" &&\n (entry.outTrackId === undefined || typeof entry.outTrackId === \"string\") &&\n typeof entry.conversationId === \"string\" &&\n (entry.lastContent === undefined || typeof entry.lastContent === \"string\") &&\n (entry.lastBlockListJson === undefined || typeof entry.lastBlockListJson === \"string\") &&\n (entry.streamLifecycleOpened === undefined || typeof entry.streamLifecycleOpened === \"boolean\"),\n ),\n ),\n };\n}\n\nfunction readPendingCardState(storePath?: string, log?: Logger): PendingCardStateFile {\n if (!storePath) {\n return { version: CARD_STATE_FILE_VERSION, updatedAt: Date.now(), pendingCards: [] };\n }\n\n const filePath = getCardStateFilePath(storePath);\n const legacyPath = getLegacyCardStateFilePath(storePath);\n\n if (filePath && fs.existsSync(filePath)) {\n const parsed = readNamespaceJson<Partial<PendingCardStateFile>>(CARD_PENDING_NAMESPACE, {\n storePath,\n format: \"json\",\n fallback: {},\n log,\n });\n return normalizePendingState(parsed);\n }\n\n try {\n if (!legacyPath || !fs.existsSync(legacyPath)) {\n return { version: CARD_STATE_FILE_VERSION, updatedAt: Date.now(), pendingCards: [] };\n }\n const raw = fs.readFileSync(legacyPath, \"utf-8\");\n if (!raw.trim()) {\n return { version: CARD_STATE_FILE_VERSION, updatedAt: Date.now(), pendingCards: [] };\n }\n const normalized = normalizePendingState(JSON.parse(raw) as Partial<PendingCardStateFile>);\n writePendingCardState(normalized, storePath, log);\n return normalized;\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n log?.warn?.(`[DingTalk][AICard] Failed to read pending card state: ${message}`);\n return { version: CARD_STATE_FILE_VERSION, updatedAt: Date.now(), pendingCards: [] };\n }\n}\n\nfunction writePendingCardState(\n state: PendingCardStateFile,\n storePath?: string,\n log?: Logger,\n): void {\n if (!storePath) {\n return;\n }\n writeNamespaceJsonAtomic(CARD_PENDING_NAMESPACE, {\n storePath,\n format: \"json\",\n data: state,\n log,\n });\n}\n\nfunction upsertPendingCard(card: AICardInstance, storePath?: string, log?: Logger): void {\n if (!card.accountId || !storePath) {\n return;\n }\n const state = readPendingCardState(storePath, log);\n const next: PendingCardRecord = {\n accountId: card.accountId,\n cardInstanceId: card.cardInstanceId,\n outTrackId: card.outTrackId,\n conversationId: card.conversationId,\n contextConversationId: card.contextConversationId,\n createdAt: card.createdAt,\n lastUpdated: card.lastUpdated,\n state: card.state,\n lastContent: card.lastStreamedContent,\n lastBlockListJson: card.lastBlockListJson,\n streamLifecycleOpened: card.streamLifecycleOpened,\n };\n const index = state.pendingCards.findIndex((item) => item.cardInstanceId === card.cardInstanceId);\n if (index >= 0) {\n state.pendingCards[index] = next;\n } else {\n state.pendingCards.push(next);\n }\n state.updatedAt = Date.now();\n writePendingCardState(state, storePath, log);\n}\n\nfunction parseStoredBlockList(blockListJson?: string): CardBlock[] {\n if (!blockListJson?.trim()) {\n return [];\n }\n try {\n const parsed = JSON.parse(blockListJson) as unknown;\n return Array.isArray(parsed) ? (parsed as CardBlock[]) : [];\n } catch {\n return [];\n }\n}\n\nfunction buildStoppedCardFinalizePayload(params: {\n reason: string;\n previousContent?: string;\n previousBlockListJson?: string;\n}): { blockListJson: string; content: string } {\n const markerText = params.reason.trim();\n const baseContent = params.previousContent?.trim() || \"\";\n const blocks = parseStoredBlockList(params.previousBlockListJson);\n blocks.push({ type: 0, markdown: markerText });\n const content = baseContent\n ? `${baseContent}\\n\\n---\\n*${markerText}*`\n : markerText;\n return {\n blockListJson: JSON.stringify(blocks),\n content,\n };\n}\n\nfunction removePendingCard(card: AICardInstance, log?: Logger): void {\n if (!card.accountId || !card.storePath) {\n return;\n }\n removePendingCardById(card.cardInstanceId, card.storePath, log);\n}\n\nfunction removePendingCardById(cardInstanceId: string, storePath?: string, log?: Logger): void {\n if (!storePath) {\n return;\n }\n const state = readPendingCardState(storePath, log);\n const remaining = state.pendingCards.filter((item) => item.cardInstanceId !== cardInstanceId);\n if (remaining.length === state.pendingCards.length) {\n return;\n }\n state.pendingCards = remaining;\n state.updatedAt = Date.now();\n writePendingCardState(state, storePath, log);\n}\n\nfunction listPendingCardsByAccount(\n accountId: string,\n storePath?: string,\n log?: Logger,\n): PendingCardRecord[] {\n const state = readPendingCardState(storePath, log);\n return state.pendingCards.filter((item) => item.accountId === accountId);\n}\n\nfunction normalizeRecoveredState(state: string): AICardInstance[\"state\"] {\n if (state === AICardStatus.PROCESSING || state === AICardStatus.INPUTING) {\n return state;\n }\n return AICardStatus.PROCESSING;\n}\n\n// Helper to identify card terminal states.\nexport function isCardInTerminalState(state: string): boolean {\n return (\n state === AICardStatus.FINISHED\n || state === AICardStatus.STOPPED\n || state === AICardStatus.FAILED\n );\n}\n\n/**\n * Ensure card access token is fresh (refresh if >90min old).\n * Mutates card.accessToken in place if refreshed.\n */\nasync function ensureFreshToken(card: AICardInstance, log?: Logger): Promise<void> {\n const tokenAge = Date.now() - card.createdAt;\n const tokenRefreshThreshold = 90 * 60 * 1000;\n\n if (tokenAge > tokenRefreshThreshold && card.config) {\n log?.debug?.(\"[DingTalk][AICard] Token age exceeds threshold, refreshing...\");\n try {\n card.accessToken = await getAccessToken(card.config, log);\n log?.debug?.(\"[DingTalk][AICard] Token refreshed successfully\");\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n log?.warn?.(`[DingTalk][AICard] Failed to refresh token: ${msg}`);\n }\n }\n}\n\nexport function formatContentForCard(content: string | undefined, type: \"thinking\" | \"tool\"): string {\n if (!content) {\n return \"\";\n }\n\n const emoji = type === \"thinking\" ? \"\uD83E\uDD14\" : \"\uD83D\uDEE0\uFE0F\";\n const label = type === \"thinking\" ? \"\u601D\u8003\u4E2D\" : \"\u5DE5\u5177\u6267\u884C\";\n\n const escaped = content\n .split(\"\\n\")\n .map((line) => line.replace(/^_(?=[^ ])/, \"*\").replace(/(?<=[^ ])_(?=$)/, \"*\"))\n .join(\"\\n\");\n\n return `${emoji} **${label}**\\n\\n${escaped}`;\n}\n\nasync function sendTemplateMismatchNotification(\n card: AICardInstance,\n text: string,\n log?: Logger,\n): Promise<void> {\n const config = card.config;\n if (!config) {\n return;\n }\n try {\n const token = await getAccessToken(config, log);\n const { targetId, isExplicitUser } = stripTargetPrefix(card.conversationId);\n const resolvedTarget = resolveOriginalPeerId(targetId);\n const isGroup = !isExplicitUser && resolvedTarget.startsWith(\"cid\");\n const url = isGroup\n ? \"https://api.dingtalk.com/v1.0/robot/groupMessages/send\"\n : \"https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend\";\n\n // Direct markdown fallback notification to user/group, without re-entering sendMessage card flow.\n const payload: Record<string, unknown> = {\n robotCode: resolveRobotCode(config),\n msgKey: \"sampleMarkdown\",\n msgParam: JSON.stringify({ title: \"OpenClaw \u63D0\u9192\", text }),\n };\n\n if (isGroup) {\n payload.openConversationId = resolvedTarget;\n } else {\n payload.userIds = [resolvedTarget];\n }\n\n await axios({\n url,\n method: \"POST\",\n data: payload,\n headers: { \"x-acs-dingtalk-access-token\": token, \"Content-Type\": \"application/json\" },\n });\n } catch (sendErr: any) {\n log?.warn?.(`[DingTalk][AICard] Failed to send error notification to user: ${sendErr.message}`);\n }\n}\n\n/**\n * Send a proactive text message via card API (createAndDeliver + immediate finalize).\n * Used in card mode to replace oToMessages/batchSend for single-chat users.\n */\nexport async function sendProactiveCardText(\n config: DingTalkConfig,\n conversationId: string,\n content: string,\n log?: Logger,\n): Promise<{ ok: boolean; error?: string } & DingTalkTrackingMetadata> {\n try {\n const card = await createAICard(config, conversationId, log, { persistPending: false });\n if (!card) {\n return { ok: false, error: \"Failed to create AI card\" };\n }\n const blockListJson = JSON.stringify([{ type: 0, markdown: content } satisfies CardBlock]);\n await commitAICardBlocks(card, {\n blockListJson,\n content,\n }, log);\n return {\n ok: true,\n processQueryKey: card.processQueryKey,\n outTrackId: card.outTrackId,\n cardInstanceId: card.cardInstanceId,\n };\n } catch (err: any) {\n log?.error?.(`[DingTalk][AICard] Proactive card send failed: ${err.message}`);\n return { ok: false, error: err.message };\n }\n}\n\nexport async function recoverPendingCardsForAccount(\n config: DingTalkConfig,\n accountId: string,\n storePath?: string,\n log?: Logger,\n): Promise<number> {\n return finalizePendingCardsByAccount(\n config,\n accountId,\n RECOVERY_FINALIZE_MESSAGE,\n storePath,\n \"recover\",\n log,\n );\n}\n\nexport async function finalizeActiveCardsForAccount(\n config: DingTalkConfig,\n accountId: string,\n reason: string,\n storePath?: string,\n log?: Logger,\n): Promise<number> {\n return finalizePendingCardsByAccount(config, accountId, reason, storePath, \"finalize\", log);\n}\n\nasync function finalizePendingCardsByAccount(\n config: DingTalkConfig,\n accountId: string,\n reason: string,\n storePath: string | undefined,\n mode: \"recover\" | \"finalize\",\n log?: Logger,\n): Promise<number> {\n if (!storePath) {\n return 0;\n }\n\n const pendingCards = listPendingCardsByAccount(accountId, storePath, log).filter(\n (item) => !isCardInTerminalState(item.state),\n );\n if (pendingCards.length === 0) {\n return 0;\n }\n\n let token = \"\";\n try {\n token = await getAccessToken(config, log);\n } catch (err: any) {\n const tokenFailureScope =\n mode === \"recover\" ? \"pending card recovery\" : \"finalizing active cards\";\n log?.warn?.(\n `[DingTalk][AICard] Failed to fetch token for ${tokenFailureScope}: ${err.message}`,\n );\n return 0;\n }\n\n let finalizedCount = 0;\n for (const entry of pendingCards) {\n const card: AICardInstance = {\n cardInstanceId: entry.cardInstanceId,\n accessToken: token,\n conversationId: entry.conversationId,\n contextConversationId: entry.contextConversationId,\n accountId: entry.accountId,\n storePath,\n outTrackId: entry.outTrackId,\n createdAt: entry.createdAt || Date.now(),\n lastUpdated: entry.lastUpdated || Date.now(),\n state: normalizeRecoveredState(entry.state),\n config,\n lastStreamedContent: entry.lastContent,\n lastBlockListJson: entry.lastBlockListJson,\n streamLifecycleOpened: entry.streamLifecycleOpened,\n };\n try {\n await finalizeStoppedAICard(card, {\n reason,\n previousContent: entry.lastContent,\n previousBlockListJson: entry.lastBlockListJson,\n }, log);\n finalizedCount += 1;\n } catch (err: unknown) {\n const action = mode === \"recover\" ? \"recover\" : \"finalize\";\n const message = err instanceof Error ? err.message : String(err);\n log?.warn?.(\n `[DingTalk][AICard] Failed to ${action} active card ${entry.cardInstanceId}: ${message}`,\n );\n // Pending record intentionally kept for manual investigation\n }\n }\n return finalizedCount;\n}\n\nexport async function createAICard(\n config: DingTalkConfig,\n conversationId: string,\n log?: Logger,\n options: CreateAICardOptions = {},\n): Promise<AICardInstance | null> {\n const accountId = options.accountId ?? \"default\";\n if (isAICardDegraded(accountId)) {\n const state = getAICardDegradeState(accountId);\n log?.warn?.(\n `[DingTalk][AICard][Degrade] Skip create for account=${accountId}, remainingMs=${state?.remainingMs || 0}, reason=${state?.reason || \"unknown\"}`,\n );\n return null;\n }\n\n try {\n const shouldPersistPending =\n options.persistPending ?? Boolean(options.accountId && options.storePath);\n const token = await getAccessToken(config, log);\n const template = DINGTALK_CARD_TEMPLATE;\n // Use randomUUID to avoid collisions across workers/restarts.\n const cardInstanceId = `card_${randomUUID()}`;\n\n log?.info?.(`[DingTalk][AICard] Creating and delivering card outTrackId=${cardInstanceId}`);\n\n const isGroup = conversationId.startsWith(\"cid\");\n\n // DingTalk createAndDeliver API payload.\n // Note: do NOT include template.statusKey here \u2014 the createAndDeliver API may\n // reject unknown fields if the template variable is not yet provisioned.\n // flowStatus=2 (INPUTING) is set directly so the card shows \"\u8F93\u51FA\u4E2D\" immediately.\n const cardParamMap = {\n config: JSON.stringify({ autoLayout: true, enableForward: true }),\n [template.streamingKey]: \"\",\n quoteContent: options.quoteContent || \"\",\n ...(options.statusLine?.trim() ? { statusLine: options.statusLine } : {}),\n flowStatus: AICardStatus.INPUTING,\n // V2 template uses hasAction (string), V1 uses stop_action (string)\n // DingTalk cardParamMap requires all values to be strings\n hasAction: String(STOP_ACTION_VISIBLE),\n stop_action: String(STOP_ACTION_VISIBLE),\n };\n const createAndDeliverBody = {\n cardTemplateId: template.templateId,\n outTrackId: cardInstanceId,\n cardData: {\n cardParamMap,\n },\n callbackType: \"STREAM\",\n imGroupOpenSpaceModel: { supportForward: true },\n imRobotOpenSpaceModel: { supportForward: true },\n openSpaceId: isGroup\n ? `dtv1.card//IM_GROUP.${conversationId}`\n : `dtv1.card//IM_ROBOT.${conversationId}`,\n userIdType: 1,\n imGroupOpenDeliverModel: isGroup\n ? {\n robotCode: resolveRobotCode(config),\n extension: DYNAMIC_SUMMARY_EXTENSION,\n }\n : undefined,\n imRobotOpenDeliverModel: !isGroup\n ? {\n spaceType: \"IM_ROBOT\",\n robotCode: resolveRobotCode(config),\n extension: DYNAMIC_SUMMARY_EXTENSION,\n }\n : undefined,\n };\n\n log?.debug?.(\n `[DingTalk][AICard] POST /v1.0/card/instances/createAndDeliver body=${JSON.stringify(createAndDeliverBody)}`,\n );\n const resp = await axios.post(\n `${DINGTALK_API}/v1.0/card/instances/createAndDeliver`,\n createAndDeliverBody,\n {\n headers: { \"x-acs-dingtalk-access-token\": token, \"Content-Type\": \"application/json\" },\n ...getProxyBypassOption(config),\n },\n );\n log?.debug?.(\n `[DingTalk][AICard] CreateAndDeliver response: status=${resp.status} data=${JSON.stringify(resp.data)}`,\n );\n const responseData = resp.data as\n | {\n result?: DingTalkTrackingMetadata;\n processQueryKey?: unknown;\n outTrackId?: unknown;\n cardInstanceId?: unknown;\n }\n | undefined;\n const deliverResults = (responseData?.result as { deliverResults?: Array<{ success?: boolean; errorMsg?: string }> } | undefined)?.deliverResults;\n if (Array.isArray(deliverResults)) {\n const failedDelivery = deliverResults.find((item) => item?.success === false);\n if (failedDelivery) {\n throw new Error(failedDelivery.errorMsg?.trim() || \"DingTalk card delivery failed\");\n }\n }\n const responseTracking = responseData?.result;\n const processQueryKey =\n typeof responseTracking?.processQueryKey === \"string\" &&\n responseTracking.processQueryKey.trim()\n ? responseTracking.processQueryKey.trim()\n : typeof responseData?.processQueryKey === \"string\" && responseData.processQueryKey.trim()\n ? responseData.processQueryKey.trim()\n : undefined;\n const outTrackId =\n typeof responseTracking?.outTrackId === \"string\" && responseTracking.outTrackId.trim()\n ? responseTracking.outTrackId.trim()\n : typeof responseData?.outTrackId === \"string\" && responseData.outTrackId.trim()\n ? responseData.outTrackId.trim()\n : cardInstanceId;\n const resolvedCardInstanceId =\n typeof responseTracking?.cardInstanceId === \"string\" && responseTracking.cardInstanceId.trim()\n ? responseTracking.cardInstanceId.trim()\n : typeof responseData?.cardInstanceId === \"string\" && responseData.cardInstanceId.trim()\n ? responseData.cardInstanceId.trim()\n : cardInstanceId;\n\n // Return the AI card instance with config reference for token refresh/recovery.\n const aiCardInstance: AICardInstance = {\n cardInstanceId: resolvedCardInstanceId,\n accessToken: token,\n conversationId,\n contextConversationId: options.contextConversationId || conversationId,\n accountId,\n storePath: options.storePath,\n createdAt: Date.now(),\n lastUpdated: Date.now(),\n state: AICardStatus.PROCESSING,\n config,\n processQueryKey: processQueryKey || extractCardProcessQueryKey(resp.data),\n outTrackId,\n dapiUsage: 1,\n };\n if (shouldPersistPending) {\n upsertPendingCard(aiCardInstance, options.storePath, log);\n }\n\n clearAICardDegrade(accountId, log);\n\n return aiCardInstance;\n } catch (err: any) {\n log?.error?.(`[DingTalk][AICard] Create failed: ${err.message}`);\n if (err.response) {\n const status = err.response.status;\n const statusText = err.response.statusText;\n const statusLabel = status ? ` status=${status}${statusText ? ` ${statusText}` : \"\"}` : \"\";\n log?.error?.(`[DingTalk][AICard] Create error response${statusLabel}`);\n log?.error?.(\n formatDingTalkErrorPayloadLog(\"card.create\", err.response.data, \"[DingTalk][AICard]\"),\n );\n }\n if (shouldTriggerAICardDegrade(err)) {\n activateAICardDegrade(\n accountId,\n `card.create:${err?.response?.status || \"unknown\"}`,\n config,\n log,\n );\n }\n return null;\n }\n}\n\n/**\n * Update statusLine via PUT /v1.0/card/instances API.\n */\nexport async function updateAICardStatusLine(\n card: AICardInstance,\n statusLine: string,\n log?: Logger,\n): Promise<void> {\n if (isCardInTerminalState(card.state) || !statusLine.trim()) {\n return;\n }\n\n await ensureFreshToken(card, log);\n\n try {\n await updateCardVariables(\n card.outTrackId || card.cardInstanceId,\n { statusLine },\n card.accessToken,\n card.config,\n );\n incrementCardDapiCount(card);\n card.lastUpdated = Date.now();\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n log?.warn?.(`[DingTalk][AICard] StatusLine update failed: ${message}`);\n }\n}\n\nexport async function updateAICardBlockList(\n card: AICardInstance,\n blockListJson: string,\n log?: Logger,\n options?: { statusLine?: string },\n): Promise<void> {\n if (isCardInTerminalState(card.state)) {\n log?.debug?.(\n `[DingTalk][AICard] Skip blockList update because card already terminal: outTrackId=${card.cardInstanceId} state=${card.state}`,\n );\n return;\n }\n\n // Ensure token is fresh before API call\n await ensureFreshToken(card, log);\n\n const template = DINGTALK_CARD_TEMPLATE;\n const params: Record<string, unknown> = {\n [template.blockListKey]: blockListJson,\n };\n if (options?.statusLine?.trim()) {\n params.statusLine = options.statusLine;\n }\n\n try {\n await updateCardVariables(\n card.outTrackId || card.cardInstanceId,\n params,\n card.accessToken,\n card.config,\n );\n incrementCardDapiCount(card);\n card.lastBlockListJson = blockListJson;\n card.lastUpdated = Date.now();\n if (card.state === AICardStatus.PROCESSING) {\n card.state = AICardStatus.INPUTING;\n }\n upsertPendingCard(card, card.storePath, log);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n log?.error?.(`[DingTalk][AICard] BlockList update failed: ${message}`);\n throw err;\n }\n}\n\n/**\n * Stream answer text to content key for real-time display.\n * Only used when cardRealTimeStream=true.\n * Uses streaming API because content is a simple string type.\n */\nexport async function streamAICardContent(\n card: AICardInstance,\n text: string,\n log?: Logger,\n): Promise<void> {\n if (isCardInTerminalState(card.state)) {\n return;\n }\n const template = DINGTALK_CARD_TEMPLATE;\n await putAICardStreamingField(card, template.streamingKey, text, false, log);\n card.lastStreamedContent = text;\n upsertPendingCard(card, card.storePath, log);\n}\n\n/**\n * Clear the streaming content key.\n * Called when transitioning from streaming to blockList commit.\n */\nexport async function clearAICardStreamingContent(\n card: AICardInstance,\n log?: Logger,\n): Promise<void> {\n if (isCardInTerminalState(card.state)) {\n return;\n }\n const template = DINGTALK_CARD_TEMPLATE;\n try {\n await putAICardStreamingField(card, template.streamingKey, \"\", false, log);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n log?.debug?.(`[DingTalk][AICard] Non-critical: failed to clear streaming content: ${message}`);\n }\n}\n\nasync function finalizeAICardStreamingLifecycleIfNeeded(\n card: AICardInstance,\n content: string,\n log?: Logger,\n): Promise<void> {\n if (!card.streamLifecycleOpened) {\n return;\n }\n const template = DINGTALK_CARD_TEMPLATE;\n try {\n await putAICardStreamingField(card, template.streamingKey, content, true, log, {\n suppressDegrade: true,\n });\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n log?.warn?.(`[DingTalk][AICard] Streaming lifecycle finalize failed; continuing instances finalize: ${message}`);\n }\n}\n\n/**\n * Options for finalizing an AI Card via instances API.\n * All variables are written in a single API call for V2 template compatibility.\n */\nexport interface FinalizeCardOptions {\n /** CardBlock[] JSON string for blockList variable */\n blockListJson: string;\n /** Pure markdown answer text for copy action (content variable) */\n content: string;\n /** Optional quoted message preview text */\n quoteContent?: string;\n /** Optional statusLine string for card template */\n statusLine?: string;\n /** Optional quoted message reference for caching */\n quotedRef?: QuotedRef;\n}\n\n/**\n * Commit blocks and finalize card via single instances API call.\n * V2 template requires finalize through instances API (not streaming API).\n * Writes blockList, content, quoteContent, statusLine, and flowStatus in one call.\n */\nexport async function commitAICardBlocks(\n card: AICardInstance,\n options: FinalizeCardOptions,\n log?: Logger,\n): Promise<void> {\n if (isCardInTerminalState(card.state)) {\n log?.debug?.(\n `[DingTalk][AICard] Skip finalize because card already terminal: outTrackId=${card.cardInstanceId} state=${card.state}`,\n );\n return;\n }\n\n await ensureFreshToken(card, log);\n await finalizeAICardStreamingLifecycleIfNeeded(card, options.content, log);\n\n const template = DINGTALK_CARD_TEMPLATE;\n const updates: Record<string, unknown> = {\n [template.blockListKey]: options.blockListJson,\n [template.streamingKey]: options.content, // markdown content for display\n [template.copyContentKey]: options.content, // same markdown as String type for card copy action\n flowStatus: 3, // completed state - V2 template hides stop button automatically\n };\n\n // Optional fields\n if (options.quoteContent?.trim()) {\n updates.quoteContent = options.quoteContent;\n }\n if (options.statusLine?.trim()) {\n updates.statusLine = options.statusLine;\n }\n\n log?.debug?.(\n `[DingTalk][AICard] Finalizing via instances API: outTrackId=${card.outTrackId || card.cardInstanceId} ` +\n `blockListLen=${options.blockListJson.length} contentLen=${options.content.length} flowStatus=3` +\n (options.statusLine ? ` statusLine=\"${options.statusLine}\"` : \"\"),\n );\n\n try {\n await updateCardVariables(\n card.outTrackId || card.cardInstanceId,\n updates,\n card.accessToken,\n card.config,\n );\n incrementCardDapiCount(card);\n card.lastBlockListJson = options.blockListJson;\n card.lastStreamedContent = options.content;\n card.lastUpdated = Date.now();\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n log?.error?.(`[DingTalk][AICard] Finalize via instances API failed: ${message}`);\n throw err;\n }\n\n // Cache card content for quote recovery\n if (card.conversationId && options.content.trim() && card.accountId && card.processQueryKey) {\n const primaryConversationId = card.contextConversationId || card.conversationId;\n cacheCardContentByProcessQueryKey(\n card.accountId,\n primaryConversationId,\n card.processQueryKey,\n options.content,\n card.storePath,\n options.quotedRef,\n log,\n );\n }\n\n // Update local state\n card.state = AICardStatus.FINISHED;\n card.lastUpdated = Date.now();\n removePendingCard(card, log);\n log?.info?.(`[DingTalk][AICard] Card finalized: outTrackId=${card.outTrackId || card.cardInstanceId} state=FINISHED`);\n}\n\n\nexport async function streamAICard(\n card: AICardInstance,\n content: string,\n finished: boolean = false,\n log?: Logger,\n): Promise<void> {\n if (isCardInTerminalState(card.state)) {\n log?.debug?.(\n `[DingTalk][AICard] Skip stream update because card already terminal: outTrackId=${card.cardInstanceId} state=${card.state}`,\n );\n return;\n }\n const template = DINGTALK_CARD_TEMPLATE;\n\n try {\n await putAICardStreamingField(card, template.contentKey, content, finished, log);\n card.lastStreamedContent = content;\n if (finished) {\n card.state = AICardStatus.FINISHED;\n removePendingCard(card, log);\n } else if (card.state === AICardStatus.PROCESSING) {\n card.state = AICardStatus.INPUTING;\n upsertPendingCard(card, card.storePath, log);\n }\n } catch (err: any) {\n card.state = AICardStatus.FAILED;\n card.lastUpdated = Date.now();\n removePendingCard(card, log);\n if (err.response?.status === 500 && err.response?.data?.code === \"unknownError\") {\n const errorMsg =\n \"\u26A0\uFE0F **[DingTalk] AI Card \u4E32\u6D41\u66F4\u65B0\u5931\u8D25 (500 unknownError)**\\n\\n\"\n + \"\u8FD9\u901A\u5E38\u8868\u793A\u5F53\u524D\u5185\u7F6E\u6A21\u677F\u5951\u7EA6\u4E0E\u9489\u9489\u4FA7\u6A21\u677F\u5B57\u6BB5\u4E0D\u4E00\u81F4\uFF0C\u5F53\u524D\u53CA\u540E\u7EED\u6D88\u606F\u5C06\u81EA\u52A8\u56DE\u9000\u4E3A Markdown \u53D1\u9001\u3002\";\n await sendTemplateMismatchNotification(card, errorMsg, log);\n }\n throw err;\n }\n}\n\n/**\n * Finalize AI Card via streaming API.\n *\n * @deprecated For V2 template, use `commitAICardBlocks()` instead which finalizes\n * via instances API (single call writes blockList, content, flowStatus=3).\n * This function is kept for backward compatibility with V1 template and for\n * card-stop-handler which uses streaming API for immediate stop acknowledgment.\n */\nexport async function finishAICard(\n card: AICardInstance,\n content: string,\n log?: Logger,\n options: { quotedRef?: QuotedRef } = {},\n): Promise<void> {\n log?.debug?.(`[DingTalk][AICard] Starting finish, final content length=${content.length}`);\n await streamAICard(card, content, true, log);\n // Hide stop button on normal completion (symmetric with card-stop-handler).\n if (card.outTrackId && card.config) {\n try {\n const token = await getAccessToken(card.config, log);\n await hideCardStopButton(card.outTrackId, token, card.config);\n } catch (err: any) {\n log?.debug?.(`[DingTalk][AICard] Non-critical: failed to hide stop button on finish: ${err.message}`);\n }\n }\n if (card.conversationId && content.trim() && card.accountId && card.processQueryKey) {\n const primaryConversationId = card.contextConversationId || card.conversationId;\n cacheCardContentByProcessQueryKey(\n card.accountId,\n primaryConversationId,\n card.processQueryKey,\n content,\n card.storePath,\n options.quotedRef,\n log,\n );\n }\n}\n\nfunction getCardRecallTarget(card: AICardInstance): {\n isGroup: boolean;\n conversationId?: string;\n} {\n const { targetId, isExplicitUser } = stripTargetPrefix(card.conversationId);\n const resolvedTarget = resolveOriginalPeerId(targetId);\n const isGroup = !isExplicitUser && resolvedTarget.startsWith(\"cid\");\n return {\n isGroup,\n conversationId: resolvedTarget || undefined,\n };\n}\n\nfunction parseRecallFailureEntries(payload: unknown): Array<[string, string]> {\n if (!payload || typeof payload !== \"object\") {\n return [];\n }\n return Object.entries(payload as Record<string, unknown>)\n .map(([key, value]) => [String(key), String(value ?? \"\")] as [string, string]);\n}\n\nexport async function recallAICardMessage(\n card: AICardInstance,\n log?: Logger,\n): Promise<boolean> {\n const config = card.config;\n const processQueryKey = card.processQueryKey?.trim();\n const robotCode = config ? resolveRobotCode(config) : \"\";\n\n if (!config || !processQueryKey || !robotCode) {\n log?.warn?.(\n `[DingTalk][AICard] Skip recall because required metadata is missing: ` +\n `card=${card.cardInstanceId} hasConfig=${Boolean(config)} ` +\n `processQueryKey=${processQueryKey || \"(none)\"} robotCode=${robotCode || \"(none)\"}`,\n );\n return false;\n }\n\n const target = getCardRecallTarget(card);\n if (!target.conversationId) {\n log?.warn?.(\n `[DingTalk][AICard] Skip recall because conversationId is invalid: card=${card.cardInstanceId} conversationId=${card.conversationId}`,\n );\n return false;\n }\n\n const url = target.isGroup\n ? `${DINGTALK_API}/v1.0/robot/groupMessages/recall`\n : `${DINGTALK_API}/v1.0/robot/otoMessages/batchRecall`;\n const body: Record<string, unknown> = {\n robotCode,\n processQueryKeys: [processQueryKey],\n };\n if (target.isGroup) {\n body.openConversationId = target.conversationId;\n }\n\n try {\n const token = await getAccessToken(config, log);\n const response = await axios.post(url, body, {\n headers: {\n \"x-acs-dingtalk-access-token\": token,\n \"Content-Type\": \"application/json\",\n },\n ...getProxyBypassOption(config),\n });\n const successResults = Array.isArray((response.data as Record<string, unknown> | undefined)?.successResult)\n ? ((response.data as Record<string, unknown>).successResult as unknown[])\n .map((item) => String(item))\n : [];\n const failedEntries = parseRecallFailureEntries(\n (response.data as Record<string, unknown> | undefined)?.failedResult,\n );\n if (failedEntries.length > 0) {\n log?.warn?.(\n `[DingTalk][AICard] Recall reported failedResult: card=${card.cardInstanceId} ` +\n `processQueryKey=${processQueryKey} failed=${JSON.stringify(failedEntries)}`,\n );\n return false;\n }\n if (!successResults.includes(processQueryKey)) {\n log?.warn?.(\n `[DingTalk][AICard] Recall response missing successResult for processQueryKey=${processQueryKey} ` +\n `payload=${JSON.stringify(response.data)}`,\n );\n return false;\n }\n\n card.state = AICardStatus.FINISHED;\n card.lastUpdated = Date.now();\n removePendingCard(card, log);\n log?.info?.(\n `[DingTalk][AICard] Recalled empty card message: card=${card.cardInstanceId} ` +\n `conversationId=${target.conversationId} processQueryKey=${processQueryKey} mode=${target.isGroup ? \"group\" : \"direct\"}`,\n );\n return true;\n } catch (err: any) {\n log?.warn?.(`[DingTalk][AICard] Recall failed for card=${card.cardInstanceId}: ${err.message}`);\n if (err.response?.data !== undefined) {\n log?.warn?.(\n formatDingTalkErrorPayloadLog(\n target.isGroup ? \"card.groupRecall\" : \"card.directRecall\",\n err.response.data,\n \"[DingTalk][AICard]\",\n ),\n );\n }\n return false;\n }\n}\n\nexport async function finishStoppedAICard(\n card: AICardInstance,\n content: string,\n log?: Logger,\n): Promise<void> {\n if (isCardInTerminalState(card.state)) {\n log?.debug?.(\n `[DingTalk][AICard] finishStoppedAICard skipped \u2014 already terminal: ${card.state}`,\n );\n return;\n }\n const template = DINGTALK_CARD_TEMPLATE;\n try {\n await putAICardStreamingField(card, template.contentKey, content, true, log);\n } finally {\n // Ensure local state is consistent even when the streaming API call fails.\n // The card is logically stopped regardless of whether DingTalk acknowledged it.\n card.lastStreamedContent = content;\n card.state = AICardStatus.STOPPED;\n card.lastUpdated = Date.now();\n removePendingCard(card, log);\n }\n}\n\nexport async function finalizeStoppedAICard(\n card: AICardInstance,\n options: {\n reason: string;\n previousContent?: string;\n previousBlockListJson?: string;\n },\n log?: Logger,\n): Promise<void> {\n if (isCardInTerminalState(card.state)) {\n log?.debug?.(\n `[DingTalk][AICard] finalizeStoppedAICard skipped \u2014 already terminal: ${card.state}`,\n );\n return;\n }\n\n await ensureFreshToken(card, log);\n const template = DINGTALK_CARD_TEMPLATE;\n const payload = buildStoppedCardFinalizePayload(options);\n await finalizeAICardStreamingLifecycleIfNeeded(card, payload.content, log);\n try {\n await updateCardVariables(\n card.outTrackId || card.cardInstanceId,\n {\n [template.blockListKey]: payload.blockListJson,\n [template.streamingKey]: payload.content,\n [template.copyContentKey]: payload.content,\n flowStatus: 3,\n },\n card.accessToken,\n card.config,\n );\n incrementCardDapiCount(card);\n card.lastBlockListJson = payload.blockListJson;\n card.lastStreamedContent = payload.content;\n card.state = AICardStatus.STOPPED;\n card.lastUpdated = Date.now();\n removePendingCard(card, log);\n } catch (err: unknown) {\n card.lastBlockListJson = payload.blockListJson;\n card.lastStreamedContent = payload.content;\n card.state = AICardStatus.STOPPED;\n card.lastUpdated = Date.now();\n // Keep pending record for manual investigation on API failure\n throw err;\n }\n}\n\nfunction cacheCardContentByProcessQueryKey(\n accountId: string,\n conversationId: string,\n processQueryKey: string,\n content: string,\n storePath?: string,\n quotedRef?: QuotedRef,\n log?: Logger,\n): void {\n if (!processQueryKey.trim() || !content.trim() || !storePath) {\n return;\n }\n log?.debug?.(\n `[DingTalk][QuotedRef][Persist] direction=outbound scope=${conversationId} messageType=card ` +\n `processQueryKey=${processQueryKey} quotedRef=${quotedRef ? JSON.stringify(quotedRef) : \"(none)\"}`,\n );\n upsertOutboundMessageContext({\n storePath,\n accountId,\n conversationId,\n createdAt: Date.now(),\n text: content,\n messageType: \"card\",\n ...DEFAULT_OUTBOUND_SENDER,\n chatType: inferConversationChatType(conversationId),\n ttlMs: DEFAULT_CARD_CONTENT_TTL_MS,\n topic: null,\n quotedRef,\n delivery: {\n processQueryKey,\n kind: \"proactive-card\",\n },\n });\n}\n\nexport function cacheCardContent(\n accountId: string,\n conversationId: string,\n content: string,\n createdAt: number,\n storePath?: string,\n): void {\n if (!storePath) {\n // This fallback only serves short-lived, no-storePath sessions. It is kept\n // local to card-service instead of using the shared message context store\n // because there is no durable scope to share across modules or restarts.\n const scopeKey = `${accountId}:${conversationId}`;\n const nowMs = Date.now();\n const bucket = touchInMemoryCardContentBucket(scopeKey, nowMs);\n bucket.entries.push({ content, createdAt, expiresAt: nowMs + DEFAULT_CARD_CONTENT_TTL_MS });\n bucket.entries.sort((left, right) => left.createdAt - right.createdAt);\n bucket.entries = bucket.entries.slice(-CARD_CACHE_MAX_PER_CONVERSATION);\n return;\n }\n upsertOutboundMessageContext({\n storePath,\n accountId,\n conversationId,\n msgId: createSyntheticOutboundMsgId(createdAt),\n createdAt,\n text: content,\n messageType: \"card\",\n ...DEFAULT_OUTBOUND_SENDER,\n chatType: inferConversationChatType(conversationId),\n ttlMs: DEFAULT_CARD_CONTENT_TTL_MS,\n topic: null,\n });\n}\n\nexport function findCardContent(\n accountId: string,\n conversationId: string,\n repliedCreatedAt: number,\n storePath?: string,\n): string | null {\n if (!storePath) {\n const scopeKey = `${accountId}:${conversationId}`;\n const nowMs = Date.now();\n const bucket = inMemoryCardContentStore.get(scopeKey);\n if (!bucket) {\n return null;\n }\n bucket.entries = pruneInMemoryCardContentEntries(bucket.entries, nowMs);\n bucket.lastActiveAt = nowMs;\n if (bucket.entries.length === 0) {\n inMemoryCardContentStore.delete(scopeKey);\n return null;\n }\n let bestContent: string | null = null;\n let bestDelta = Infinity;\n for (const entry of bucket.entries) {\n const delta = Math.abs(entry.createdAt - repliedCreatedAt);\n if (delta <= DEFAULT_CREATED_AT_MATCH_WINDOW_MS && delta < bestDelta) {\n bestDelta = delta;\n bestContent = entry.content;\n }\n }\n return bestContent;\n }\n const record = resolveByCreatedAtWindow({\n storePath,\n accountId,\n conversationId,\n createdAt: repliedCreatedAt,\n windowMs: DEFAULT_CREATED_AT_MATCH_WINDOW_MS,\n direction: \"outbound\",\n });\n return record?.text || null;\n}\n\nexport function clearCardContentCacheForTest(): void {\n inMemoryCardContentStore.clear();\n clearMessageContextCacheForTest();\n}\n", "/** Card variable value that shows the stop button. */\nexport const STOP_ACTION_VISIBLE = true;\n/** Card variable value that hides the stop button. */\nexport const STOP_ACTION_HIDDEN = false;\n\nexport const BUILTIN_DINGTALK_CARD_TEMPLATE_ID =\n process.env.DINGTALK_CARD_TEMPLATE_ID || \"675cde2f-f526-40cb-b828-f5b2b57b8b77.schema\";\nexport const BUILTIN_DINGTALK_CARD_CONTENT_KEY = \"content\";\nexport const BUILTIN_DINGTALK_CARD_BLOCK_LIST_KEY = \"blockList\";\nexport const BUILTIN_DINGTALK_CARD_COPY_CONTENT_KEY = \"copy_content\";\n\nexport interface DingTalkCardTemplateContract {\n templateId: string;\n contentKey: string;\n /** V2: key for the streaming markdown field (same as contentKey). */\n streamingKey: string;\n /** V2: key for the block-list loopArray variable. */\n blockListKey: string;\n /** V2: key for the plain-text copy content variable (String type for card copy action). */\n copyContentKey: string;\n}\n\n/** Frozen singleton \u2014 no allocation on every call. */\nexport const DINGTALK_CARD_TEMPLATE: Readonly<DingTalkCardTemplateContract> = Object.freeze({\n templateId: BUILTIN_DINGTALK_CARD_TEMPLATE_ID,\n contentKey: BUILTIN_DINGTALK_CARD_CONTENT_KEY,\n streamingKey: BUILTIN_DINGTALK_CARD_CONTENT_KEY,\n blockListKey: BUILTIN_DINGTALK_CARD_BLOCK_LIST_KEY,\n copyContentKey: BUILTIN_DINGTALK_CARD_COPY_CONTENT_KEY,\n});\n\n", "/**\n * Peer ID Registry\n *\n * Maps lowercased peer/session keys back to their original case-sensitive\n * DingTalk conversationId values. DingTalk conversationIds are base64-encoded\n * and therefore case-sensitive, but the framework may lowercase session keys\n * internally. This registry preserves the original casing so outbound messages\n * can be delivered correctly.\n */\n\nimport { readFileSync, readdirSync } from \"fs\";\nimport * as os from \"os\";\nimport { join } from \"path\";\nimport { getLogger } from \"./logger-context\";\n\nconst peerIdMap = new Map<string, string>();\nlet preloaded = false;\n\n/**\n * Register an original peer ID, keyed by its lowercased form.\n */\nexport function registerPeerId(originalId: string): void {\n if (!originalId) {\n return;\n }\n peerIdMap.set(originalId.toLowerCase(), originalId);\n}\n\nfunction maybeRegisterDingTalkGroupPeerId(value: unknown): void {\n // DingTalk group openConversationId values are base64-like and consistently start with \"cid\".\n // User IDs in DM contexts do not follow this pattern and do not require case restoration.\n if (typeof value === \"string\" && value.startsWith(\"cid\")) {\n registerPeerId(value);\n }\n}\n\n/**\n * Resolve a possibly-lowercased peer ID back to its original casing.\n *\n * If registry is empty at first outbound call (for example, cron/delivery queue\n * fires before inbound callbacks), perform a one-time lazy preload from sessions.\n *\n * Returns the original if found, otherwise returns the input as-is.\n */\nexport function resolveOriginalPeerId(id: string): string {\n if (!id) {\n return id;\n }\n\n if (!preloaded) {\n preloadPeerIdsFromSessions();\n }\n\n return peerIdMap.get(id.toLowerCase()) || id;\n}\n\n/**\n * Clear the registry (for testing or shutdown).\n */\nexport function clearPeerIdRegistry(): void {\n peerIdMap.clear();\n preloaded = false;\n}\n\n/**\n * Preload known peer IDs from all agents' sessions.json files.\n *\n * Safe to call repeatedly:\n * - without explicit homeDir: runs once, then no-ops;\n * - with explicit homeDir: always runs (useful for tests).\n */\nexport function preloadPeerIdsFromSessions(homeDir?: string): void {\n if (!homeDir && preloaded) {\n return;\n }\n\n const home = homeDir || os.homedir();\n const agentsDir = join(home, \".openclaw\", \"agents\");\n const log = getLogger();\n let preloadCompleted = false;\n\n try {\n const agentDirs = readdirSync(agentsDir, { withFileTypes: true })\n .filter((entry) => entry.isDirectory())\n .map((entry) => entry.name);\n\n for (const agentName of agentDirs) {\n const sessionsPath = join(agentsDir, agentName, \"sessions\", \"sessions.json\");\n\n try {\n const raw = readFileSync(sessionsPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (!parsed || typeof parsed !== \"object\") {\n continue;\n }\n\n for (const session of Object.values(parsed as Record<string, unknown>)) {\n if (!session || typeof session !== \"object\") {\n continue;\n }\n\n const sessionRecord = session as Record<string, unknown>;\n maybeRegisterDingTalkGroupPeerId(sessionRecord.lastTo);\n\n const origin = sessionRecord.origin;\n if (!origin || typeof origin !== \"object\") {\n continue;\n }\n\n const originRecord = origin as Record<string, unknown>;\n maybeRegisterDingTalkGroupPeerId(originRecord.from);\n maybeRegisterDingTalkGroupPeerId(originRecord.to);\n }\n } catch (err) {\n // sessions.json may be missing or malformed for some agents; ignore per file.\n log?.debug?.(\n `[DingTalk][PeerIdRegistry] Failed to parse preload sessions file ${sessionsPath}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n }\n preloadCompleted = true;\n } catch (err) {\n const errorCode = (err as NodeJS.ErrnoException | undefined)?.code;\n if (errorCode === \"ENOENT\") {\n // agents directory may not exist yet; this is a stable no-op state.\n preloadCompleted = true;\n } else {\n log?.debug?.(\n `[DingTalk][PeerIdRegistry] Failed to scan preload directory ${agentsDir}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n }\n\n if (!homeDir && preloadCompleted) {\n preloaded = true;\n }\n}\n", "import type { Logger } from \"./types\";\n\nlet currentLogger: Logger | undefined;\nconst loggerByAccountId = new Map<string, Logger>();\n\n/**\n * Persist current request logger for shared services invoked outside handler scope.\n */\nexport function setCurrentLogger(log?: Logger, accountId?: string | null): void {\n currentLogger = log;\n const normalizedAccountId = typeof accountId === \"string\" ? accountId.trim() : \"\";\n if (!normalizedAccountId) {\n return;\n }\n if (log) {\n loggerByAccountId.set(normalizedAccountId, log);\n return;\n }\n loggerByAccountId.delete(normalizedAccountId);\n}\n\n/**\n * Read current logger bound by inbound handler.\n */\nexport function getLogger(accountId?: string | null): Logger | undefined {\n const normalizedAccountId = typeof accountId === \"string\" ? accountId.trim() : \"\";\n if (normalizedAccountId) {\n return loggerByAccountId.get(normalizedAccountId);\n }\n return currentLogger;\n}\n", "/**\n * Type definitions for DingTalk Channel Plugin\n *\n * Provides comprehensive type safety for:\n * - Configuration objects\n * - DingTalk API request/response models\n * - Message content and formats\n * - Media files and streams\n * - Session and token management\n */\n\nimport type {\n ChannelAccountSnapshot as SDKChannelAccountSnapshot,\n ChannelGatewayContext as SDKChannelGatewayContext,\n ChannelLogSink as SDKChannelLogSink,\n} from \"openclaw/plugin-sdk/channel-runtime\";\nimport type { ChannelPlugin as SDKChannelPlugin, OpenClawConfig } from \"openclaw/plugin-sdk/core\";\nimport type { ChannelSetupWizard } from \"openclaw/plugin-sdk/setup\";\nimport type { SecretInput } from \"./secret-input\";\n\nexport type AckReactionMode = \"off\" | \"emoji\" | \"kaomoji\";\n// Accept arbitrary strings for backward compatibility; the recommended\n// explicit modes remain: \"off\" | \"emoji\" | \"kaomoji\".\nexport type AckReactionConfigValue = string;\nexport type CardStreamingMode = \"off\" | \"answer\" | \"all\";\nexport type ContextVisibilityMode = \"all\" | \"allowlist\" | \"allowlist_quote\";\n\n/**\n * DingTalk channel configuration (extends base OpenClaw config)\n */\nexport interface DingTalkConfig extends OpenClawConfig {\n clientId: string;\n clientSecret: SecretInput;\n name?: string;\n enabled?: boolean;\n dmPolicy?: \"open\" | \"pairing\" | \"allowlist\";\n groupPolicy?: \"open\" | \"allowlist\" | \"disabled\";\n allowFrom?: string[];\n groupAllowFrom?: string[];\n displayNameResolution?: \"disabled\" | \"all\";\n contextVisibility?: ContextVisibilityMode;\n mediaUrlAllowlist?: string[];\n journalTTLDays?: number;\n ackReaction?: AckReactionConfigValue;\n debug?: boolean;\n messageType?: \"markdown\" | \"card\";\n /** @deprecated \u5DF2\u56FA\u5B9A\u4F7F\u7528\u5185\u7F6E\u6A21\u677F\u5951\u7EA6 */\n cardTemplateId?: string;\n /** @deprecated \u5DF2\u56FA\u5B9A\u4F7F\u7528\u5185\u7F6E\u6A21\u677F\u5951\u7EA6 */\n cardTemplateKey?: string;\n groups?: Record<\n string,\n { systemPrompt?: string; requireMention?: boolean; groupAllowFrom?: string[] }\n >;\n accounts?: Record<string, DingTalkConfig>;\n // Connection robustness configuration\n maxConnectionAttempts?: number;\n initialReconnectDelay?: number;\n maxReconnectDelay?: number;\n reconnectJitter?: number;\n /** Maximum number of runtime reconnect cycles before giving up (default: 10) */\n maxReconnectCycles?: number;\n /** Maximum time (ms) for a single reconnect cycle before giving up and starting a new cycle (default: 50000) */\n reconnectDeadlineMs?: number;\n /** Whether to use ConnectionManager; when false, use DWClient native keepAlive+autoReconnect */\n useConnectionManager?: boolean;\n /** Maximum inbound media file size in MB (overrides runtime default when set) */\n mediaMaxMb?: number;\n /** Whether to enable underlying stream keepAlive heartbeat; defaults to !useConnectionManager when omitted */\n keepAlive?: boolean;\n /** Bypass system/global HTTP(S) proxy for DingTalk outbound send/card/upload APIs */\n bypassProxyForSend?: boolean;\n proactivePermissionHint?: {\n enabled?: boolean;\n cooldownHours?: number;\n };\n /** Card streaming mode.\n * - off: disable incremental streaming\n * - answer: stream answer text\n * - all: stream answer + reasoning text */\n cardStreamingMode?: CardStreamingMode;\n /** @deprecated Use `cardStreamingMode` instead. */\n cardRealTimeStream?: boolean;\n /** Throttle interval in ms for card stream updates (default 1000) */\n cardStreamInterval?: number;\n /** AICard degrade duration in milliseconds after trigger errors (default 30m) */\n aicardDegradeMs?: number;\n /** Enable local learning loop (events/reflections/session notes/global rules) */\n learningEnabled?: boolean;\n /** Auto-apply generated reflections into session notes/global rules (default false) */\n learningAutoApply?: boolean;\n /** Session learning note TTL in milliseconds (default 6h) */\n learningNoteTtlMs?: number;\n /** Whether to convert markdown tables to plain text for better rendering on some clients (default: true) */\n convertMarkdownTables?: boolean;\n /** @mention the sender after card finalization in group chats; value is the message text */\n cardAtSender?: string;\n /** Status line visibility toggles for the AI card footer */\n cardStatusLine?: {\n model?: boolean;\n effort?: boolean;\n agent?: boolean;\n taskTime?: boolean;\n tokens?: boolean;\n dapiUsage?: boolean;\n };\n}\n\n/**\n * Multi-account DingTalk configuration wrapper\n */\nexport interface DingTalkChannelConfig {\n enabled?: boolean;\n clientId: string;\n clientSecret: SecretInput;\n name?: string;\n dmPolicy?: \"open\" | \"pairing\" | \"allowlist\";\n groupPolicy?: \"open\" | \"allowlist\" | \"disabled\";\n allowFrom?: string[];\n groupAllowFrom?: string[];\n displayNameResolution?: \"disabled\" | \"all\";\n contextVisibility?: ContextVisibilityMode;\n mediaUrlAllowlist?: string[];\n journalTTLDays?: number;\n ackReaction?: AckReactionConfigValue;\n debug?: boolean;\n messageType?: \"markdown\" | \"card\";\n /** @deprecated \u5DF2\u56FA\u5B9A\u4F7F\u7528\u5185\u7F6E\u6A21\u677F\u5951\u7EA6 */\n cardTemplateId?: string;\n /** @deprecated \u5DF2\u56FA\u5B9A\u4F7F\u7528\u5185\u7F6E\u6A21\u677F\u5951\u7EA6 */\n cardTemplateKey?: string;\n groups?: Record<\n string,\n { systemPrompt?: string; requireMention?: boolean; groupAllowFrom?: string[] }\n >;\n accounts?: Record<string, DingTalkConfig>;\n maxConnectionAttempts?: number;\n initialReconnectDelay?: number;\n maxReconnectDelay?: number;\n reconnectJitter?: number;\n /** Maximum number of runtime reconnect cycles before giving up (default: 10) */\n maxReconnectCycles?: number;\n /** Maximum time (ms) for a single reconnect cycle before giving up and starting a new cycle (default: 50000) */\n reconnectDeadlineMs?: number;\n /** Whether to use ConnectionManager; when false, use DWClient native keepAlive+autoReconnect */\n useConnectionManager?: boolean;\n /** Maximum inbound media file size in MB (overrides runtime default when set) */\n mediaMaxMb?: number;\n /** Whether to enable underlying stream keepAlive heartbeat; defaults to !useConnectionManager when omitted */\n keepAlive?: boolean;\n /** Bypass system/global HTTP(S) proxy for DingTalk outbound send/card/upload APIs */\n bypassProxyForSend?: boolean;\n proactivePermissionHint?: {\n enabled?: boolean;\n cooldownHours?: number;\n };\n /** Card streaming mode.\n * - off: disable incremental streaming\n * - answer: stream answer text\n * - all: stream answer + reasoning text */\n cardStreamingMode?: CardStreamingMode;\n /** @deprecated Use `cardStreamingMode` instead. */\n cardRealTimeStream?: boolean;\n /** Throttle interval in ms for card stream updates (default 1000) */\n cardStreamInterval?: number;\n /** AICard degrade duration in milliseconds after trigger errors (default 30m) */\n aicardDegradeMs?: number;\n /** Enable local learning loop (events/reflections/session notes/global rules) */\n learningEnabled?: boolean;\n /** Auto-apply generated reflections into session notes/global rules (default false) */\n learningAutoApply?: boolean;\n /** Session learning note TTL in milliseconds (default 6h) */\n learningNoteTtlMs?: number;\n /** Whether to convert markdown tables to plain text for better rendering on some clients (default: true) */\n convertMarkdownTables?: boolean;\n /** @mention the sender after card finalization in group chats; value is the message text */\n cardAtSender?: string;\n}\n\n/**\n * DingTalk token info for caching\n */\nexport interface TokenInfo {\n accessToken: string;\n expireIn: number;\n}\n\n/**\n * DingTalk API token response\n */\nexport interface TokenResponse {\n accessToken: string;\n expireIn: number;\n}\n\n/**\n * DingTalk API generic response wrapper\n */\nexport interface DingTalkApiResponse<T = unknown> {\n data?: T;\n code?: string;\n message?: string;\n success?: boolean;\n}\n\n/**\n * Media download response from DingTalk API\n */\nexport interface MediaDownloadResponse {\n downloadUrl?: string;\n downloadCode?: string;\n}\n\n/**\n * Media file metadata\n */\nexport interface MediaFile {\n path: string;\n mimeType: string;\n}\n\nexport interface DocInfo {\n docId: string;\n title: string;\n docType: string;\n creatorId?: string;\n updatedAt?: number | string;\n}\n\n/**\n * DingTalk incoming message (Stream mode)\n */\nexport interface DingTalkInboundMessage {\n msgId: string;\n msgtype: string;\n createAt: number;\n /**\n * @ \u63D0\u53CA\u7684\u7528\u6237\u5217\u8868\uFF08\u6D88\u606F\u9876\u5C42\uFF0C\u4E0E text \u540C\u7EA7\uFF09\n * \u5305\u542B\u901A\u8FC7 @picker \u9009\u4E2D\u7684\u6240\u6709\u771F\u5B9E\u9489\u9489\u7528\u6237\u548C\u673A\u5668\u4EBA\n * \u683C\u5F0F: [{ dingtalkId: \"$:LWCP_v1:$xxx\" }]\n */\n atUsers?: Array<{\n dingtalkId: string;\n }>;\n text?: {\n content: string;\n isReplyMsg?: boolean; // \u662F\u5426\u662F\u56DE\u590D\u6D88\u606F\n repliedMsg?: {\n msgType?: string;\n msgId?: string;\n senderId?: string;\n createdAt?: number;\n content?: {\n text?: string;\n downloadCode?: string;\n fileName?: string;\n biz_custom_action_url?: string;\n richText?: Array<{\n msgType?: string;\n type?: string;\n content?: string;\n text?: string;\n code?: string;\n atName?: string;\n downloadCode?: string;\n }>;\n /** chatRecord \u6D88\u606F\u6458\u8981 */\n summary?: string;\n /** chatRecord \u6D88\u606F\u6807\u9898 */\n title?: string;\n };\n };\n };\n content?: {\n downloadCode?: string;\n fileName?: string;\n recognition?: string;\n spaceId?: string;\n fileId?: string;\n text?: string;\n title?: string;\n biz_custom_action_url?: string;\n richText?: Array<{\n type: string;\n text?: string;\n atName?: string;\n atUserId?: string;\n downloadCode?: string;\n }>;\n quoteContent?: string;\n };\n // Legacy \u5F15\u7528\u683C\u5F0F\n quoteMessage?: {\n msgId?: string;\n msgtype?: string;\n text?: { content: string };\n senderNick?: string;\n senderId?: string;\n };\n // \u5BCC\u5A92\u4F53\u5F15\u7528\uFF0C\u4EC5\u6709\u6D88\u606FID\u7684\u60C5\u51B5\uFF08\u5305\u62EC\u624B\u673A\u7AEF\u548CPC\u7AEF\uFF09\n originalMsgId?: string;\n originalProcessQueryKey?: string;\n conversationType: string;\n conversationId: string;\n conversationTitle?: string;\n senderId: string;\n senderStaffId?: string;\n senderNick?: string;\n chatbotUserId: string;\n sessionWebhook: string;\n}\n\nexport type QuotedRefKey =\n | \"msgId\"\n | \"processQueryKey\"\n | \"messageId\"\n | \"outTrackId\"\n | \"cardInstanceId\";\n\nexport type AttachmentTextSource = \"text\" | \"html\" | \"pdf\" | \"docx\";\n\nexport interface QuotedRef {\n targetDirection: \"inbound\" | \"outbound\";\n key?: QuotedRefKey;\n value?: string;\n fallbackCreatedAt?: number;\n}\n\n/**\n * Quoted/reply message metadata extracted from repliedMsg.\n * Populated when isReplyMsg is true; downstream handlers use these fields\n * to download quoted media or look up cached card content.\n */\nexport interface QuotedInfo {\n mediaDownloadCode?: string;\n mediaType?: string;\n isQuotedFile?: boolean;\n isQuotedCard?: boolean;\n isQuotedDocCard?: boolean;\n cardCreatedAt?: number;\n processQueryKey?: string;\n fileCreatedAt?: number;\n fileDownloadCode?: string;\n msgId?: string;\n previewText?: string;\n previewMessageType?: string;\n previewFileName?: string;\n previewSenderId?: string;\n}\n\n/**\n * @ \u63D0\u53CA\u4FE1\u606F\n */\nexport interface AtMention {\n /** @ \u663E\u793A\u7684\u540D\u5B57\uFF08\u53BB\u9664 @ \u524D\u7F00\uFF09 */\n name: string;\n /** \u9489\u9489\u7528\u6237 ID\uFF08\u5982\u679C\u662F @ \u771F\u4EBA\uFF09 */\n userId?: string;\n}\n\n/**\n * Agent \u540D\u5B57\u5339\u914D\u7ED3\u679C\n */\nexport interface AgentNameMatch {\n /** \u5339\u914D\u5230\u7684 agent ID */\n agentId: string;\n /** \u5339\u914D\u6765\u6E90\uFF1A'name' | 'id' */\n matchSource: \"name\" | \"id\";\n /** \u5339\u914D\u5230\u7684\u540D\u5B57 */\n matchedName: string;\n}\n\n/**\n * Extracted message content for unified processing\n */\nexport interface MessageContent {\n text: string;\n mediaPath?: string;\n mediaPaths?: string[];\n mediaType?: string;\n mediaTypes?: string[];\n messageType: string;\n docSpaceId?: string;\n docFileId?: string;\n quoted?: QuotedInfo;\n /** @ \u63D0\u53CA\u5217\u8868\uFF08\u4ECE\u6587\u672C\u6216 richText \u63D0\u53D6\u7684\u540D\u5B57\uFF09 */\n atMentions?: AtMention[];\n /**\n * \u901A\u8FC7 @picker \u9009\u4E2D\u7684\u771F\u5B9E\u9489\u9489\u7528\u6237\u7684 dingtalkId \u5217\u8868\n * - \u4EC5\u5305\u542B\u771F\u5B9E\u9489\u9489\u7528\u6237\u548C\u673A\u5668\u4EBA\uFF0C\u4E0D\u5305\u542B agent \u540D\n * - \u7528\u4E8E\u6392\u9664\u771F\u4EBA\uFF1A\u5982\u679C atMentions \u4E2D\u7684\u540D\u5B57\u5339\u914D\u5230 agent\uFF0C\u8BF4\u660E\u662F agent\uFF1B\n * \u5982\u679C\u6CA1\u5339\u914D\u5230 agent \u4E14\u6709 atUserDingtalkIds\uFF0C\u5219\u53EF\u80FD\u662F\u771F\u4EBA\n * - \u6CE8\u610F\uFF1A\u65E0\u6CD5\u5C06 dingtalkId \u6620\u5C04\u5230\u5177\u4F53\u540D\u5B57\uFF0C\u56E0\u4E3A webhook \u4E0D\u63D0\u4F9B\u6B64\u6620\u5C04\n */\n atUserDingtalkIds?: string[];\n}\n\n/**\n * Send message options\n */\nexport interface SendMessageOptions {\n title?: string;\n useMarkdown?: boolean;\n atUserId?: string | null;\n log?: Logger;\n conversationId?: string;\n mediaPath?: string;\n filePath?: string;\n mediaUrl?: string;\n mediaType?: \"image\" | \"voice\" | \"video\" | \"file\";\n accountId?: string;\n storePath?: string;\n cardUpdateMode?: \"append\";\n quotedRef?: QuotedRef;\n /** Force markdown/text delivery even when messageType is \"card\". Bypasses card\n * creation while preserving journal writes and other side-effects. */\n forceMarkdown?: boolean;\n /** Allowed local roots for sandbox/container media path resolution. */\n mediaLocalRoots?: string[];\n}\n\nexport interface DingTalkTrackingMetadata {\n processQueryKey?: string;\n outTrackId?: string;\n cardInstanceId?: string;\n}\n\n/**\n * Session webhook response\n */\nexport interface SessionWebhookResponse {\n msgtype: string;\n markdown?: {\n title: string;\n text: string;\n };\n text?: {\n content: string;\n };\n at?: {\n atUserIds: string[];\n isAtAll: boolean;\n };\n}\n\n/**\n * Sub-agent routing options for parameterized message handling\n */\nexport interface SubAgentOptions {\n /** The agent ID to route to */\n agentId: string;\n /** Prefix to add to response messages (e.g., \"[AgentName] \") */\n responsePrefix: string;\n /** The matched agent name */\n matchedName: string;\n}\n\n/**\n * Message handler parameters\n */\nexport interface HandleDingTalkMessageParams {\n cfg: OpenClawConfig;\n accountId: string;\n data: DingTalkInboundMessage;\n sessionWebhook: string;\n log?: Logger;\n dingtalkConfig: DingTalkConfig;\n /**\n * When set, routes message to the specified sub-agent instead of main agent.\n * This enables reuse of the main message handling logic for sub-agents.\n */\n subAgentOptions?: SubAgentOptions;\n /**\n * Pre-downloaded media for sub-agent calls.\n * When set, skips media download to avoid duplication in recursive calls.\n */\n preDownloadedMedia?: {\n mediaPath?: string;\n mediaType?: string;\n mediaPaths?: string[];\n mediaTypes?: string[];\n };\n}\n\n/**\n * Proactive message payload\n */\nexport interface ProactiveMessagePayload {\n robotCode: string;\n msgKey: string;\n msgParam: string;\n openConversationId?: string;\n userIds?: string[];\n}\n\n/**\n * Account descriptor\n */\nexport interface AccountDescriptor {\n accountId: string;\n config?: DingTalkConfig;\n enabled?: boolean;\n name?: string;\n configured?: boolean;\n}\n\n/**\n * Account resolver result\n */\nexport interface ResolvedAccount {\n accountId: string;\n config: DingTalkConfig;\n enabled: boolean;\n}\n\n/**\n * HTTP request config for axios\n */\nexport interface AxiosRequestConfig {\n url?: string;\n method?: string;\n data?: unknown;\n headers?: Record<string, string>;\n responseType?: \"arraybuffer\" | \"json\" | \"text\";\n}\n\n/**\n * HTTP response from axios\n */\nexport interface AxiosResponse<T = unknown> {\n data: T;\n status: number;\n statusText: string;\n headers: Record<string, string>;\n}\n\n/**\n * DingTalk Stream callback listener types\n */\nexport interface StreamCallbackResponse {\n headers?: {\n messageId?: string;\n };\n data: string;\n}\n\n/**\n * Reply dispatcher context\n */\nexport interface ReplyDispatchContext {\n responsePrefix?: string;\n deliver: (payload: unknown) => Promise<{ ok: boolean; error?: string }>;\n}\n\n/**\n * Reply dispatcher result\n */\nexport interface ReplyDispatcherResult {\n dispatcher: unknown;\n replyOptions: unknown;\n markDispatchIdle: () => void;\n}\n\n/**\n * Retry options\n */\nexport interface RetryOptions {\n maxRetries?: number;\n baseDelayMs?: number;\n log?: Logger;\n}\n\n/**\n * Channel log sink\n */\nexport type ChannelLogSink = SDKChannelLogSink;\n\n/**\n * @deprecated Use ChannelLogSink instead\n */\nexport type Logger = ChannelLogSink;\n\n/**\n * Channel account snapshot\n */\nexport type ChannelAccountSnapshot = SDKChannelAccountSnapshot;\n\n/**\n * @deprecated Use ChannelAccountSnapshot instead\n */\nexport type ChannelSnapshot = ChannelAccountSnapshot;\n\n/**\n * Plugin gateway start context\n */\nexport type GatewayStartContext = SDKChannelGatewayContext<ResolvedAccount>;\n\n/**\n * Plugin gateway account stop result\n */\nexport interface GatewayStopResult {\n stop: () => void;\n}\n\n/**\n * DingTalk channel plugin definition\n */\nexport type DingTalkChannelPlugin = SDKChannelPlugin<ResolvedAccount & { configured: boolean }> & {\n setupWizard?: ChannelSetupWizard;\n};\n\n/**\n * Result of target resolution validation\n */\nexport interface TargetResolutionResult {\n ok: boolean;\n to?: string;\n error?: Error;\n}\n\n/**\n * Parameters for resolveTarget validation\n */\nexport interface ResolveTargetParams {\n to?: string | null;\n [key: string]: unknown;\n}\n\n/**\n * Parameters for sendText delivery\n */\nexport interface SendTextParams {\n cfg: DingTalkConfig;\n to: string;\n text: string;\n accountId?: string;\n [key: string]: unknown;\n}\n\n/**\n * Parameters for sendMedia delivery\n */\nexport interface SendMediaParams {\n cfg: DingTalkConfig;\n to: string;\n mediaPath: string;\n accountId?: string;\n [key: string]: unknown;\n}\n\n/**\n * DingTalk outbound handler configuration\n */\nexport interface DingTalkOutboundHandler {\n deliveryMode: \"direct\" | \"queued\" | \"batch\";\n resolveTarget: (params: ResolveTargetParams) => TargetResolutionResult;\n sendText: (params: SendTextParams) => Promise<{ ok: boolean; data?: unknown; error?: unknown }>;\n sendMedia?: (\n params: SendMediaParams,\n ) => Promise<{ ok: boolean; data?: unknown; error?: unknown }>;\n}\n\n/**\n * AI Card status constants\n */\nexport const AICardStatus = {\n PROCESSING: \"1\",\n INPUTING: \"2\",\n FINISHED: \"3\",\n STOPPED: \"4\",\n FAILED: \"5\",\n} as const;\n\n/**\n * AI Card state type\n */\nexport type AICardState = (typeof AICardStatus)[keyof typeof AICardStatus];\n\n/**\n * AI Card instance\n */\nexport interface AICardInstance {\n cardInstanceId: string;\n processQueryKey?: string;\n accessToken: string;\n conversationId: string;\n contextConversationId?: string;\n accountId?: string;\n storePath?: string;\n createdAt: number;\n lastUpdated: number;\n state: AICardState; // Current card state: PROCESSING, INPUTING, FINISHED, STOPPED, FAILED\n config?: DingTalkConfig; // Store config reference for token refresh\n lastStreamedContent?: string; // Latest copy/content text shown to user\n lastBlockListJson?: string; // Latest rendered CardBlock[] JSON for V2 instances API\n outTrackId?: string;\n /** Cumulative DingTalk API call count for this card instance. */\n dapiUsage?: number;\n /** True after this card has successfully opened DingTalk's streaming lifecycle. */\n streamLifecycleOpened?: boolean;\n}\n\n/**\n * AI Card streaming update request (new API)\n */\nexport interface AICardStreamingRequest {\n outTrackId: string;\n guid: string;\n key: string;\n content: string;\n isFull: boolean;\n isFinalize: boolean;\n isError: boolean;\n}\n\n/**\n * Connection state enum for lifecycle management\n */\nexport enum ConnectionState {\n DISCONNECTED = \"DISCONNECTED\",\n CONNECTING = \"CONNECTING\",\n CONNECTED = \"CONNECTED\",\n DISCONNECTING = \"DISCONNECTING\",\n FAILED = \"FAILED\",\n}\n\n/**\n * Factory function that creates a fresh DWClient with callback listeners\n * already registered. Used by ConnectionManager to create a new client\n * on reconnection so the new WebSocket can start receiving messages\n * while the old zombie socket is still being cleaned up.\n */\nexport type StreamClientFactory = () => import(\"dingtalk-stream\").DWClient;\n\n/**\n * Connection manager configuration\n */\nexport interface ConnectionManagerConfig {\n maxAttempts: number;\n initialDelay: number;\n maxDelay: number;\n jitter: number;\n /** Maximum number of runtime reconnect cycles before giving up (default: 10) */\n maxReconnectCycles?: number;\n /** Maximum time (ms) for a single reconnect cycle before giving up and starting a new cycle (default: 50000) */\n reconnectDeadlineMs?: number;\n /** Callback invoked when connection state changes */\n onStateChange?: (state: ConnectionState, error?: string) => void;\n}\n\n/**\n * Connection attempt result\n */\nexport interface ConnectionAttemptResult {\n success: boolean;\n attempt: number;\n error?: Error;\n nextDelay?: number;\n}\n/**\n * CardBlock types for AI Card v2 blockList.\n * - 0 = answer (markdown text)\n * - 1 = thinking process\n * - 2 = tool result\n * - 3 = image (uploaded mediaId)\n */\nexport type CardBlock =\n | { type: 0; markdown: string }\n | { type: 1; markdown: string }\n | { type: 2; markdown: string }\n | { type: 3; mediaId: string; text?: string };\n", "import { resolveNativeCommandSessionTargets } from \"openclaw/plugin-sdk/command-auth\";\nimport type { OpenClawConfig } from \"openclaw/plugin-sdk/core\";\nimport { getDingTalkRuntime } from \"../runtime\";\nimport type { Logger } from \"../types\";\n\n/**\n * Dispatch a native targeted `/stop` command through the OpenClaw SDK,\n * replacing the previous self-built Gateway WebSocket `chat.abort` approach.\n *\n * Uses the same `resolveNativeCommandSessionTargets` + `CommandSource: \"native\"`\n * model as Telegram / Discord / Slack slash commands, producing:\n * - A dedicated command SessionKey (`agent:<agentId>:dingtalk:card-stop:<userId>`)\n * - A CommandTargetSessionKey pointing at the real conversation session\n *\n * Inside the SDK, `dispatch-from-config` \u2192 `tryFastAbortFromMessage` picks up\n * the `/stop` body, resolves the target session via `CommandTargetSessionKey`,\n * and executes `abortEmbeddedPiRun` + `clearSessionQueues`.\n *\n * Accesses SDK functions via `getDingTalkRuntime().channel.reply` \u2014 the same\n * pattern used by `inbound-handler.ts` \u2014 while reusing the upstream native\n * command session-target helper exported by the plugin SDK.\n */\nexport async function dispatchDingTalkCardStopCommand(params: {\n cfg: OpenClawConfig;\n accountId: string;\n agentId: string;\n targetSessionKey: string;\n clickerUserId: string;\n log?: Logger;\n}): Promise<{ ok: boolean }> {\n const rt = getDingTalkRuntime();\n\n const { sessionKey: commandSessionKey, commandTargetSessionKey } =\n resolveNativeCommandSessionTargets({\n agentId: params.agentId,\n sessionPrefix: \"dingtalk:card-stop\",\n userId: params.clickerUserId,\n targetSessionKey: params.targetSessionKey,\n });\n\n const ctx = rt.channel.reply.finalizeInboundContext({\n Body: \"/stop\",\n RawBody: \"/stop\",\n CommandBody: \"/stop\",\n SessionKey: commandSessionKey,\n CommandTargetSessionKey: commandTargetSessionKey,\n CommandSource: \"native\" as const,\n CommandAuthorized: true,\n AccountId: params.accountId,\n Provider: \"dingtalk\",\n Surface: \"dingtalk\",\n // \"direct\" because the synthetic /stop body contains no @mentions to strip.\n // The actual chat type of the target session is irrelevant for abort routing.\n ChatType: \"direct\",\n From: `dingtalk:card-stop:${params.clickerUserId}`,\n To: `card-stop:${params.clickerUserId}`,\n SenderId: params.clickerUserId,\n OriginatingChannel: \"dingtalk\",\n });\n\n // DispatchInboundResult = { queuedFinal, counts } \u2014 the return value does\n // not expose whether tryFastAbortFromMessage took the fast-abort path.\n // Treat successful dispatch as best-effort abort, consistent with the\n // previous gateway chat.abort approach.\n await rt.channel.reply.dispatchReplyWithBufferedBlockDispatcher({\n ctx,\n cfg: params.cfg,\n dispatcherOptions: {\n responsePrefix: \"\",\n deliver: async () => {\n // SDK abort confirmation text is swallowed here; the card\n // finalize path handles stopped content independently.\n },\n },\n });\n\n return { ok: true };\n}\n", "import type { PluginRuntime } from \"openclaw/plugin-sdk/core\";\nimport { createPluginRuntimeStore } from \"openclaw/plugin-sdk/runtime-store\";\n\nconst runtimeStore = createPluginRuntimeStore<PluginRuntime>(\"DingTalk runtime not initialized\");\n\nexport function setDingTalkRuntime(next: PluginRuntime): void {\n runtimeStore.setRuntime(next);\n}\n\nexport function getDingTalkRuntime(): PluginRuntime {\n return runtimeStore.getRuntime();\n}\n", "import type { OpenClawConfig } from \"openclaw/plugin-sdk/core\";\nimport { finalizeStoppedAICard } from \"../card-service\";\nimport { dispatchDingTalkCardStopCommand } from \"../command/card-stop-command\";\nimport type { DingTalkConfig, Logger } from \"../types\";\nimport { AICardStatus } from \"../types\";\nimport { markCardRunStopRequested, resolveCardRun } from \"./card-run-registry\";\n\nexport interface StopCardRunResult {\n ok: boolean;\n status: string;\n reason?: string;\n /** Last streamed content before stop, so callback response can preserve it. */\n lastContent?: string;\n}\n\nexport async function stopCardRun(params: {\n cfg: OpenClawConfig;\n accountId: string;\n outTrackId: string;\n config?: DingTalkConfig;\n clickerUserId?: string;\n log?: Logger;\n}): Promise<StopCardRunResult> {\n const record = resolveCardRun(params.outTrackId);\n if (!record) {\n return { ok: false, status: \"missing-run\", reason: \"No active card run registration found.\" };\n }\n\n if (record.stopRequestedAt || record.card?.state === AICardStatus.STOPPED) {\n return { ok: true, status: \"already-stopped\", lastContent: record.card?.lastStreamedContent };\n }\n\n const lastContent = record.controller?.getRenderedContent?.() || record.card?.lastStreamedContent;\n const lastBlockListJson =\n record.controller?.getRenderedBlocks?.() || record.card?.lastBlockListJson;\n\n markCardRunStopRequested(params.outTrackId);\n record.controller?.stop();\n\n // --- Phase 1: Abort agent execution via native /stop command ---\n // Dispatch FIRST so that the current run is guaranteed to still be active\n // on the session. If we finalized the card first, a new run could start on\n // the same sessionKey in the async gap.\n //\n // Only abort when this card is actively dispatching (has a controller).\n // Cards still queued behind session lock have no controller yet \u2014 the stop\n // guard in inbound-handler will skip dispatch when the lock is acquired.\n let nativeStopStatus: string | undefined;\n if (record.controller) {\n try {\n await dispatchDingTalkCardStopCommand({\n cfg: params.cfg,\n accountId: params.accountId,\n agentId: record.agentId,\n targetSessionKey: record.sessionKey,\n clickerUserId: params.clickerUserId ?? record.ownerUserId ?? \"unknown\",\n log: params.log,\n });\n nativeStopStatus = \"stopped\";\n } catch (error) {\n params.log?.warn?.(\n `[${params.accountId}] [DingTalk][CardStop] native stop dispatch failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n nativeStopStatus = \"stopped-dispatch-error\";\n }\n }\n\n // --- Phase 2: Finalize card via instances API so V2 blockList/content stay consistent ---\n if (record.card) {\n try {\n await finalizeStoppedAICard(record.card, {\n reason: \"\u23F9\uFE0F \u5DF2\u505C\u6B62\",\n previousContent: lastContent,\n previousBlockListJson: lastBlockListJson,\n }, params.log);\n } catch (error) {\n params.log?.warn?.(\n `[${params.accountId}] [DingTalk][CardStop] failed to finalize stopped card: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n return { ok: true, status: nativeStopStatus ?? \"stopped-pending\", lastContent };\n}\n", "import type { OpenClawConfig } from \"openclaw/plugin-sdk/core\";\nimport type { CardCallbackAnalysis } from \"../card-callback-service\";\nimport type { DingTalkConfig, Logger } from \"../types\";\nimport { resolveCardRun } from \"./card-run-registry\";\nimport { stopCardRun } from \"./card-stop-handler\";\n\nexport interface CardActionResult {\n handled: boolean;\n}\n\nexport async function handleCardAction(params: {\n analysis: CardCallbackAnalysis;\n cfg: OpenClawConfig;\n accountId: string;\n config: DingTalkConfig;\n log?: Logger;\n}): Promise<CardActionResult> {\n if (params.analysis.actionId !== \"btn_stop\") {\n return { handled: false };\n }\n\n const outTrackId = params.analysis.outTrackId;\n if (!outTrackId) {\n params.log?.warn?.(\n `[${params.accountId}] [DingTalk][CardStop] stop callback missing outTrackId \u2014 cannot route stop request`,\n );\n return { handled: false };\n }\n\n // In group chats, only the user who initiated the conversation can stop it.\n // Fail-closed: reject when clicker identity is missing but owner is known.\n const clickerUserId = params.analysis.userId;\n const record = resolveCardRun(outTrackId);\n if (record?.ownerUserId) {\n if (!clickerUserId || record.ownerUserId !== clickerUserId) {\n params.log?.info?.(\n `[${params.accountId}] [DingTalk][CardStop] rejected: clicker=${clickerUserId ?? \"unknown\"} owner=${record.ownerUserId}`,\n );\n return { handled: true };\n }\n }\n\n const result = await stopCardRun({\n cfg: params.cfg,\n accountId: params.accountId,\n outTrackId,\n config: params.config,\n clickerUserId,\n log: params.log,\n });\n if (!result.ok) {\n params.log?.warn?.(\n `[${params.accountId}] [DingTalk][CardStop] stop failed status=${result.status} reason=${result.reason ?? \"unknown\"}`,\n );\n } else {\n params.log?.info?.(\n `[${params.accountId}] [DingTalk][CardStop] stop succeeded outTrackId=${outTrackId}`,\n );\n }\n\n return { handled: true };\n}\n", "/**\n * Connection Manager for DingTalk Stream Client\n *\n * Provides robust connection lifecycle management with:\n * - Exponential backoff with jitter for reconnection attempts\n * - Configurable max attempts and delay parameters\n * - Connection state tracking and event handling\n * - Proper cleanup of timers and resources\n * - Structured logging for all connection events\n */\n\nimport type { DWClient } from \"dingtalk-stream\";\nimport type {\n ConnectionState,\n ConnectionManagerConfig,\n ConnectionAttemptResult,\n Logger,\n StreamClientFactory,\n} from \"./types\";\nimport { ConnectionState as ConnectionStateEnum } from \"./types\";\n\n/**\n * Thrown when a runtime reconnection cycle exceeds the configured deadline.\n * Identified via instanceof in reconnect() to skip cycle counting.\n */\nexport class ReconnectDeadlineError extends Error {\n constructor(options?: ErrorOptions) {\n super(\"Reconnect deadline exceeded\", options);\n this.name = \"ReconnectDeadlineError\";\n }\n}\n\n/**\n * ConnectionManager handles the robust connection lifecycle for DWClient\n */\nexport class ConnectionManager {\n private config: ConnectionManagerConfig;\n private log?: Logger;\n private accountId: string;\n\n // Connection state tracking\n private state: ConnectionState = ConnectionStateEnum.DISCONNECTED;\n private attemptCount: number = 0;\n private reconnectTimer?: NodeJS.Timeout;\n private stopped: boolean = false;\n private connectedAt?: number;\n private consecutiveUnhealthyChecks: number = 0;\n\n private static readonly HEALTH_CHECK_INTERVAL_MS = 60000;\n private static readonly HEALTH_CHECK_GRACE_MS = 30000;\n private static readonly HEALTH_CHECK_UNHEALTHY_THRESHOLD = 2;\n private static readonly DEFAULT_MAX_RECONNECT_CYCLES = 10;\n private static readonly MAX_CYCLE_BACKOFF_MS = 5000;\n private static readonly MAX_CONSECUTIVE_DEADLINE_TIMEOUTS = 5;\n private static readonly HEARTBEAT_INTERVAL_MS = 20_000;\n private static readonly HEARTBEAT_MISS_THRESHOLD = 2;\n private runtimeReconnectCycles: number = 0;\n private reconnectDeadline?: number;\n private consecutiveDeadlineTimeouts: number = 0;\n private lastSocketActivityAt?: number;\n private lastHeartbeatPingAt?: number;\n private consecutiveHeartbeatMisses: number = 0;\n private runtimeCounters = {\n healthUnhealthyChecks: 0,\n healthTriggeredReconnects: 0,\n heartbeatMisses: 0,\n heartbeatTriggeredReconnects: 0,\n serverDisconnectMessages: 0,\n socketCloseEvents: 0,\n runtimeDisconnects: 0,\n reconnectAttempts: 0,\n reconnectSuccess: 0,\n reconnectFailures: 0,\n };\n\n // Runtime monitoring resources\n private healthCheckInterval?: NodeJS.Timeout;\n private heartbeatInterval?: NodeJS.Timeout;\n private socketCloseHandler?: (code: number, reason: string) => void;\n private socketErrorHandler?: (error: Error) => void;\n private socketMessageHandler?: (data: any) => void;\n private socketPongHandler?: () => void;\n private monitoredSocket?: any;\n\n // Sleep abort control\n private sleepTimeout?: NodeJS.Timeout;\n private sleepResolve?: () => void;\n\n // Stop signal for waitForStop()\n private stopPromiseResolvers: Array<() => void> = [];\n\n // Client reference\n private client: DWClient;\n\n // Warm-reconnect: factory to create fresh DWClient instances with listeners\n // already registered so the new socket starts receiving immediately.\n private clientFactory?: StreamClientFactory;\n // Old client pending cleanup after a warm reconnect swap.\n private pendingOldClient?: DWClient;\n\n constructor(client: DWClient, accountId: string, config: ConnectionManagerConfig, log?: Logger, clientFactory?: StreamClientFactory) {\n this.client = client;\n this.accountId = accountId;\n this.config = config;\n this.log = log;\n this.clientFactory = clientFactory;\n }\n\n private notifyStateChange(error?: string): void {\n if (this.config.onStateChange) {\n this.config.onStateChange(this.state, error);\n }\n }\n\n /**\n * Resolve all pending waitForStop() callers without performing full stop().\n * Called by stop() and terminal FAILED states where the manager will never\n * reconnect again, so startAccount must be allowed to exit.\n */\n private resolveStopWaiters(): void {\n for (const resolve of this.stopPromiseResolvers) {\n resolve();\n }\n this.stopPromiseResolvers = [];\n }\n\n private logRuntimeCounters(reason: string): void {\n const c = this.runtimeCounters;\n this.log?.info?.(\n `[${this.accountId}] Runtime counters (${reason}): healthUnhealthyChecks=${c.healthUnhealthyChecks}, healthTriggeredReconnects=${c.healthTriggeredReconnects}, heartbeatMisses=${c.heartbeatMisses}, heartbeatTriggeredReconnects=${c.heartbeatTriggeredReconnects}, serverDisconnectMessages=${c.serverDisconnectMessages}, socketCloseEvents=${c.socketCloseEvents}, runtimeDisconnects=${c.runtimeDisconnects}, reconnectAttempts=${c.reconnectAttempts}, reconnectSuccess=${c.reconnectSuccess}, reconnectFailures=${c.reconnectFailures}`,\n );\n }\n\n private recordSocketActivity(now: number = Date.now()): void {\n this.lastSocketActivityAt = now;\n this.consecutiveHeartbeatMisses = 0;\n }\n\n private setupHeartbeat(socket: any): void {\n this.cleanupHeartbeatInterval();\n this.heartbeatInterval = setInterval(() => {\n if (this.stopped || this.state !== ConnectionStateEnum.CONNECTED) {\n return;\n }\n\n if (socket.readyState !== 1) {\n return;\n }\n\n const now = Date.now();\n const idleMs = this.lastSocketActivityAt !== undefined\n ? now - this.lastSocketActivityAt\n : ConnectionManager.HEARTBEAT_INTERVAL_MS;\n if (idleMs >= ConnectionManager.HEARTBEAT_INTERVAL_MS) {\n this.consecutiveHeartbeatMisses += 1;\n this.runtimeCounters.heartbeatMisses += 1;\n\n if (this.consecutiveHeartbeatMisses >= ConnectionManager.HEARTBEAT_MISS_THRESHOLD) {\n const lastPingAgoMs = this.lastHeartbeatPingAt !== undefined\n ? now - this.lastHeartbeatPingAt\n : undefined;\n this.log?.warn?.(\n `[${this.accountId}] Connection heartbeat missed ${this.consecutiveHeartbeatMisses}/${ConnectionManager.HEARTBEAT_MISS_THRESHOLD} checks, triggering reconnection (lastPingAgoMs=${lastPingAgoMs ?? \"n/a\"})`,\n );\n this.runtimeCounters.heartbeatTriggeredReconnects += 1;\n this.logRuntimeCounters(\"heartbeat-triggered-reconnect\");\n this.cleanupHeartbeatInterval();\n this.handleRuntimeDisconnection();\n return;\n }\n\n this.log?.debug?.(\n `[${this.accountId}] Connection heartbeat missed (${this.consecutiveHeartbeatMisses}/${ConnectionManager.HEARTBEAT_MISS_THRESHOLD})`,\n );\n }\n\n this.lastHeartbeatPingAt = now;\n try {\n socket.ping(\"\", true);\n } catch (err: any) {\n this.log?.warn?.(\n `[${this.accountId}] Failed to send heartbeat ping: ${err.message}`,\n );\n }\n }, ConnectionManager.HEARTBEAT_INTERVAL_MS);\n }\n\n private cleanupHeartbeatInterval(): void {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = undefined;\n }\n }\n\n private clearClientHeartbeatInterval(client: DWClient): void {\n const clientAny = client as any;\n if (clientAny.heartbeatIntervallId !== undefined) {\n clearInterval(clientAny.heartbeatIntervallId);\n clientAny.heartbeatIntervallId = undefined;\n }\n }\n\n private async waitForSocketOpen(clientAny: any): Promise<void> {\n const socket = clientAny.socket;\n if (!socket) {\n throw new Error(\"Socket unavailable after connect\");\n }\n\n if (socket.readyState === 1 || clientAny.connected) {\n return;\n }\n\n const defaultOpenTimeout = 10_000;\n const openTimeout = this.reconnectDeadline !== undefined\n ? Math.min(defaultOpenTimeout, Math.max(1000, this.reconnectDeadline - Date.now()))\n : defaultOpenTimeout;\n\n await new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n cleanup();\n reject(new Error(\"Socket open timeout\"));\n }, openTimeout);\n const cleanup = () => {\n clearTimeout(timeout);\n socket.removeListener(\"open\", onOpen);\n socket.removeListener(\"error\", onError);\n socket.removeListener(\"close\", onClose);\n };\n const onOpen = () => { cleanup(); resolve(); };\n const onError = (err: Error) => { cleanup(); reject(err); };\n const onClose = () => { cleanup(); reject(new Error(\"Socket closed before open\")); };\n socket.once(\"open\", onOpen);\n socket.once(\"error\", onError);\n socket.once(\"close\", onClose);\n });\n }\n\n /**\n * Calculate next reconnection delay with exponential backoff and jitter\n * Formula: delay = min(initialDelay * 2^attempt, maxDelay) * (1 \u00B1 jitter)\n * @param attempt Zero-based attempt number (0 for first retry, 1 for second, etc.)\n */\n private calculateNextDelay(attempt: number): number {\n const { initialDelay, maxDelay, jitter } = this.config;\n\n // Exponential backoff: initialDelay * 2^attempt\n // For attempt=0 (first retry), this gives initialDelay * 1 = initialDelay\n const exponentialDelay = initialDelay * Math.pow(2, attempt);\n\n // Cap at maxDelay\n const cappedDelay = Math.min(exponentialDelay, maxDelay);\n\n // Apply jitter: randomize \u00B1 jitter%\n const jitterAmount = cappedDelay * jitter;\n const randomJitter = (Math.random() * 2 - 1) * jitterAmount;\n const finalDelay = Math.max(100, cappedDelay + randomJitter); // Minimum 100ms\n\n return Math.floor(finalDelay);\n }\n\n /**\n * Attempt to connect with retry logic\n */\n private async attemptConnection(): Promise<ConnectionAttemptResult> {\n if (this.stopped) {\n return {\n success: false,\n attempt: this.attemptCount,\n error: new Error(\"Connection manager stopped\"),\n };\n }\n\n this.attemptCount++;\n this.state = ConnectionStateEnum.CONNECTING;\n this.notifyStateChange();\n\n this.log?.info?.(\n `[${this.accountId}] Connection attempt ${this.attemptCount}/${this.config.maxAttempts}...`,\n );\n\n try {\n // Warm-reconnect path: create a fresh DWClient so the new WebSocket\n // can start receiving messages while the old zombie socket is cleaned\n // up asynchronously. This minimizes the message-loss window during\n // server-initiated disconnects (DingTalk robot msgs are fire-and-forget).\n if (this.clientFactory) {\n const oldClient = this.client;\n this.pendingOldClient = oldClient;\n try {\n this.client = this.clientFactory();\n this.log?.info?.(\n `[${this.accountId}] Warm reconnect: created fresh DWClient, connecting new socket while old socket is cleaned up`,\n );\n } catch (factoryErr: any) {\n this.log?.warn?.(\n `[${this.accountId}] Client factory failed, falling back to same-client reconnect: ${factoryErr.message}`,\n );\n this.client = oldClient;\n this.pendingOldClient = undefined;\n }\n }\n\n if (!this.pendingOldClient) {\n // Legacy single-client reconnect: disconnect before reconnecting.\n try {\n this.client.disconnect();\n } catch (disconnectErr: any) {\n this.log?.debug?.(\n `[${this.accountId}] pre-connect cleanup disconnect failed: ${disconnectErr.message}`,\n );\n }\n }\n\n // SDK _connect() resolves before socket \"open\" fires. If disconnect() runs\n // before \"open\", heartbeatIntervallId is still undefined and clearInterval\n // is a no-op. The deferred \"open\" handler then creates an interval that\n // outlives the old socket and can terminate the next connection.\n // For the race where interval is created AFTER this cleanup, the socket\n // open timeout below serves as the final safety net.\n // Field name \"heartbeatIntervallId\" (double-l typo) from dingtalk-stream\n // SDK DWClient._connect() open handler (verified in SDK v1.x).\n const clientAny = this.client as any;\n this.clearClientHeartbeatInterval(this.client);\n\n await this.client.connect();\n await this.waitForSocketOpen(clientAny);\n\n if (this.stopped) {\n this.log?.warn?.(\n `[${this.accountId}] Connection succeeded but manager was stopped during connect - disconnecting`,\n );\n try {\n this.client.disconnect();\n } catch (disconnectErr: any) {\n this.log?.debug?.(\n `[${this.accountId}] Error during post-connect disconnect: ${disconnectErr.message}`,\n );\n }\n return {\n success: false,\n attempt: this.attemptCount,\n error: new Error(\"Connection manager stopped during connect\"),\n };\n }\n\n this.state = ConnectionStateEnum.CONNECTED;\n this.connectedAt = Date.now();\n this.recordSocketActivity(this.connectedAt);\n this.lastHeartbeatPingAt = undefined;\n this.reconnectDeadline = undefined;\n this.consecutiveUnhealthyChecks = 0;\n this.consecutiveHeartbeatMisses = 0;\n this.notifyStateChange();\n const successfulAttempt = this.attemptCount;\n this.attemptCount = 0;\n\n this.log?.info?.(`[${this.accountId}] DingTalk Stream client connected successfully`);\n\n this.runtimeReconnectCycles = 0;\n this.consecutiveDeadlineTimeouts = 0;\n // Setup monitoring BEFORE cleaning up old client: setupRuntimeReconnection\n // calls cleanupRuntimeMonitoring() which removes the old socket's event\n // listeners, preventing the old socket's close event (triggered by\n // disconnect below) from erroneously firing handleRuntimeDisconnection.\n this.setupRuntimeReconnection();\n this.cleanupPendingOldClient();\n\n return { success: true, attempt: successfulAttempt };\n } catch (err: any) {\n // Warm-reconnect failed with new client: revert to old client so\n // subsequent retry attempts don't keep creating throwaway instances.\n if (this.pendingOldClient) {\n try { this.client.disconnect(); } catch { /* best-effort cleanup of failed new client */ }\n this.client = this.pendingOldClient;\n this.pendingOldClient = undefined;\n this.log?.debug?.(\n `[${this.accountId}] Warm reconnect failed, reverted to previous client for next retry`,\n );\n }\n\n this.log?.error?.(\n `[${this.accountId}] Connection attempt ${this.attemptCount} failed: ${err.message}`,\n );\n\n // Check if we've exceeded max attempts\n if (this.attemptCount >= this.config.maxAttempts) {\n this.state = ConnectionStateEnum.FAILED;\n this.notifyStateChange(\"Max connection attempts reached\");\n this.log?.error?.(\n `[${this.accountId}] Max connection attempts (${this.config.maxAttempts}) reached. Giving up.`,\n );\n return { success: false, attempt: this.attemptCount, error: err };\n }\n\n // Calculate next retry delay (use attemptCount-1 for zero-based exponent)\n // This ensures first retry uses 2^0 = 1x initialDelay\n const nextDelay = this.calculateNextDelay(this.attemptCount - 1);\n\n this.log?.warn?.(\n `[${this.accountId}] Will retry connection in ${(nextDelay / 1000).toFixed(2)}s (attempt ${this.attemptCount + 1}/${this.config.maxAttempts})`,\n );\n\n return { success: false, attempt: this.attemptCount, error: err, nextDelay };\n }\n }\n\n /**\n * Connect with robust retry logic\n */\n public async connect(): Promise<void> {\n if (this.stopped) {\n throw new Error(\"Cannot connect: connection manager is stopped\");\n }\n\n // Clear any existing reconnect timer\n this.clearReconnectTimer();\n\n this.log?.info?.(\n `[${this.accountId}] Starting DingTalk Stream client with robust connection...`,\n );\n\n while (!this.stopped && this.state !== ConnectionStateEnum.CONNECTED) {\n if (this.reconnectDeadline !== undefined && Date.now() >= this.reconnectDeadline) {\n this.reconnectDeadline = undefined;\n throw new ReconnectDeadlineError();\n }\n\n const result = await this.attemptConnection();\n\n if (result.success) {\n return;\n }\n\n if (result.error?.message === \"Connection manager stopped during connect\") {\n this.log?.info?.(\n `[${this.accountId}] Connection cancelled: manager stopped during connect`,\n );\n throw new Error(\"Connection cancelled: connection manager stopped\");\n }\n\n if (!result.nextDelay || this.attemptCount >= this.config.maxAttempts) {\n throw new Error(`Failed to connect after ${this.attemptCount} attempts`);\n }\n\n // Truncate sleep to remaining deadline budget\n let actualDelay = result.nextDelay;\n if (this.reconnectDeadline !== undefined) {\n const remaining = Math.max(0, this.reconnectDeadline - Date.now());\n actualDelay = Math.min(actualDelay, remaining);\n }\n\n await this.sleep(actualDelay);\n }\n }\n\n /**\n * Setup runtime reconnection handlers\n * Monitors DWClient connection state for automatic reconnection\n */\n private setupRuntimeReconnection(): void {\n this.log?.debug?.(`[${this.accountId}] Setting up runtime reconnection monitoring`);\n\n // Clean up any existing monitoring resources before setting up new ones\n this.cleanupRuntimeMonitoring();\n\n // Access DWClient internals to monitor connection state\n const client = this.client as any;\n\n // Monitor client's 'connected' property changes\n // We'll set up an interval to periodically check connection health\n this.healthCheckInterval = setInterval(() => {\n if (this.stopped) {\n if (this.healthCheckInterval) {\n clearInterval(this.healthCheckInterval);\n }\n return;\n }\n\n if (this.state !== ConnectionStateEnum.CONNECTED) {\n this.consecutiveUnhealthyChecks = 0;\n return;\n }\n\n const now = Date.now();\n const withinGraceWindow =\n this.connectedAt !== undefined &&\n now - this.connectedAt < ConnectionManager.HEALTH_CHECK_GRACE_MS;\n if (withinGraceWindow) {\n this.consecutiveUnhealthyChecks = 0;\n return;\n }\n\n const socketReadyState = (client.socket as { readyState?: number } | undefined)?.readyState;\n const socketOpen = socketReadyState === 1;\n const registered = client.registered as boolean | undefined;\n\n // Unhealthy if:\n // 1. Not connected AND socket not open (full disconnect)\n // 2. Socket is open, client.connected is false, AND not registered\n // (server sent logical \"disconnect\" and the socket is now a zombie)\n const unhealthy =\n (!client.connected && !socketOpen) ||\n (socketOpen && !client.connected && registered === false);\n\n if (!unhealthy) {\n this.consecutiveUnhealthyChecks = 0;\n return;\n }\n\n this.consecutiveUnhealthyChecks += 1;\n this.runtimeCounters.healthUnhealthyChecks += 1;\n if (\n this.consecutiveUnhealthyChecks <\n ConnectionManager.HEALTH_CHECK_UNHEALTHY_THRESHOLD\n ) {\n this.log?.debug?.(\n `[${this.accountId}] Connection health check unhealthy (${this.consecutiveUnhealthyChecks}/${ConnectionManager.HEALTH_CHECK_UNHEALTHY_THRESHOLD}) connected=${String(client.connected)} registered=${String(registered)} socketReadyState=${socketReadyState ?? \"unknown\"}`,\n );\n return;\n }\n\n this.log?.warn?.(\n `[${this.accountId}] Connection health check failed - detected disconnection`,\n );\n this.runtimeCounters.healthTriggeredReconnects += 1;\n this.logRuntimeCounters(\"health-triggered-reconnect\");\n if (this.healthCheckInterval) {\n clearInterval(this.healthCheckInterval);\n }\n this.handleRuntimeDisconnection();\n }, ConnectionManager.HEALTH_CHECK_INTERVAL_MS);\n\n // Additionally, if we have access to the socket, monitor its events\n // The DWClient uses 'ws' WebSocket library which extends EventEmitter\n if (client.socket) {\n const socket = client.socket;\n // Store the socket instance we're attaching listeners to\n this.monitoredSocket = socket;\n this.setupHeartbeat(socket);\n\n // Handler for socket close event\n this.socketCloseHandler = (code: number, reason: string) => {\n this.runtimeCounters.socketCloseEvents += 1;\n this.log?.warn?.(\n `[${this.accountId}] WebSocket closed event (code: ${code}, reason: ${reason || \"none\"})`,\n );\n this.logRuntimeCounters(\"socket-close\");\n\n // Only trigger reconnection if we were previously connected and not stopping\n if (!this.stopped && this.state === ConnectionStateEnum.CONNECTED) {\n if (this.healthCheckInterval) {\n clearInterval(this.healthCheckInterval);\n }\n this.handleRuntimeDisconnection();\n }\n };\n\n // Handler for socket error event\n this.socketErrorHandler = (error: Error) => {\n this.log?.error?.(\n `[${this.accountId}] WebSocket error event: ${error?.message || \"Unknown error\"}`,\n );\n };\n\n socket.once(\"close\", this.socketCloseHandler);\n socket.once(\"error\", this.socketErrorHandler);\n\n // Monitor for server-side disconnect system messages and passive socket\n // activity.\n this.socketMessageHandler = (data: any) => {\n this.recordSocketActivity();\n try {\n const msg = JSON.parse(typeof data === \"string\" ? data : data.toString());\n if (msg?.type === \"SYSTEM\" && msg?.headers?.topic === \"disconnect\") {\n this.runtimeCounters.serverDisconnectMessages += 1;\n this.log?.warn?.(\n `[${this.accountId}] Server disconnect system message received, triggering immediate reconnection`,\n );\n this.logRuntimeCounters(\"server-disconnect\");\n if (this.healthCheckInterval) {\n clearInterval(this.healthCheckInterval);\n }\n this.handleRuntimeDisconnection();\n }\n } catch {\n // Ignore parse errors \u2014 other handlers will process the message\n }\n };\n socket.on(\"message\", this.socketMessageHandler);\n\n this.socketPongHandler = () => {\n this.recordSocketActivity();\n };\n socket.on(\"pong\", this.socketPongHandler);\n }\n }\n\n /**\n * Disconnect and release the old client left over from a warm-reconnect swap.\n */\n private cleanupPendingOldClient(): void {\n if (!this.pendingOldClient) {\n return;\n }\n const old = this.pendingOldClient;\n this.pendingOldClient = undefined;\n try {\n // Clear stale heartbeat interval from old SDK instance.\n const oldAny = old as any;\n if (oldAny.heartbeatIntervallId !== undefined) {\n clearInterval(oldAny.heartbeatIntervallId);\n oldAny.heartbeatIntervallId = undefined;\n }\n old.disconnect();\n this.log?.debug?.(`[${this.accountId}] Warm reconnect: old client disconnected`);\n } catch (err: any) {\n this.log?.debug?.(\n `[${this.accountId}] Warm reconnect: old client cleanup failed: ${err.message}`,\n );\n }\n }\n\n /**\n * Clean up runtime monitoring resources (intervals and event listeners)\n */\n private cleanupRuntimeMonitoring(): void {\n // Clear health check interval\n if (this.healthCheckInterval) {\n clearInterval(this.healthCheckInterval);\n this.healthCheckInterval = undefined;\n this.log?.debug?.(`[${this.accountId}] Health check interval cleared`);\n }\n this.cleanupHeartbeatInterval();\n\n // Remove socket event listeners from the stored socket instance\n if (this.monitoredSocket) {\n const socket = this.monitoredSocket;\n\n if (this.socketCloseHandler) {\n socket.removeListener(\"close\", this.socketCloseHandler);\n this.socketCloseHandler = undefined;\n }\n if (this.socketErrorHandler) {\n socket.removeListener(\"error\", this.socketErrorHandler);\n this.socketErrorHandler = undefined;\n }\n if (this.socketMessageHandler) {\n socket.removeListener(\"message\", this.socketMessageHandler);\n this.socketMessageHandler = undefined;\n }\n if (this.socketPongHandler) {\n socket.removeListener(\"pong\", this.socketPongHandler);\n this.socketPongHandler = undefined;\n }\n\n this.log?.debug?.(`[${this.accountId}] Socket event listeners removed from monitored socket`);\n this.monitoredSocket = undefined;\n }\n }\n\n /**\n * Handle runtime disconnection and trigger reconnection\n */\n private handleRuntimeDisconnection(): void {\n if (this.stopped || this.state !== ConnectionStateEnum.CONNECTED) {\n return;\n }\n\n this.state = ConnectionStateEnum.DISCONNECTED;\n\n this.log?.warn?.(\n `[${this.accountId}] Runtime disconnection detected, initiating reconnection...`,\n );\n this.runtimeCounters.runtimeDisconnects += 1;\n\n this.notifyStateChange(\"Runtime disconnection detected\");\n this.attemptCount = 0;\n this.connectedAt = undefined;\n this.lastSocketActivityAt = undefined;\n this.lastHeartbeatPingAt = undefined;\n this.consecutiveUnhealthyChecks = 0;\n this.consecutiveHeartbeatMisses = 0;\n\n const deadlineMs = this.config.reconnectDeadlineMs ?? 50000;\n this.reconnectDeadline = Date.now() + deadlineMs;\n\n this.clearReconnectTimer();\n\n this.log?.info?.(`[${this.accountId}] Scheduling immediate reconnection`);\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnect().catch((err) => {\n this.log?.error?.(`[${this.accountId}] Reconnection failed: ${err.message}`);\n });\n }, 0);\n }\n\n /**\n * Reconnect after runtime disconnection\n */\n private async reconnect(): Promise<void> {\n if (this.stopped) {\n return;\n }\n\n this.log?.info?.(`[${this.accountId}] Attempting to reconnect...`);\n this.runtimeCounters.reconnectAttempts += 1;\n\n try {\n await this.connect();\n this.log?.info?.(`[${this.accountId}] Reconnection successful`);\n this.runtimeCounters.reconnectSuccess += 1;\n this.logRuntimeCounters(\"reconnect-success\");\n } catch (err: any) {\n if (this.stopped) {\n return;\n }\n\n this.log?.error?.(`[${this.accountId}] Reconnection failed: ${err.message}`);\n this.runtimeCounters.reconnectFailures += 1;\n this.logRuntimeCounters(\"reconnect-failed\");\n\n if (err instanceof ReconnectDeadlineError) {\n this.consecutiveDeadlineTimeouts += 1;\n\n if (this.consecutiveDeadlineTimeouts >= ConnectionManager.MAX_CONSECUTIVE_DEADLINE_TIMEOUTS) {\n this.log?.error?.(\n `[${this.accountId}] Max consecutive deadline timeouts (${ConnectionManager.MAX_CONSECUTIVE_DEADLINE_TIMEOUTS}) reached. Giving up.`,\n );\n this.state = ConnectionStateEnum.FAILED;\n this.connectedAt = undefined;\n this.consecutiveUnhealthyChecks = 0;\n this.reconnectDeadline = undefined;\n this.notifyStateChange(\n `Max consecutive deadline timeouts (${ConnectionManager.MAX_CONSECUTIVE_DEADLINE_TIMEOUTS}) reached`,\n );\n this.resolveStopWaiters();\n return;\n }\n\n const deadlineMs = this.config.reconnectDeadlineMs ?? 50000;\n this.reconnectDeadline = Date.now() + deadlineMs;\n const delay = Math.min(\n this.calculateNextDelay(0),\n ConnectionManager.MAX_CYCLE_BACKOFF_MS,\n );\n this.attemptCount = 0;\n this.clearReconnectTimer();\n this.log?.warn?.(\n `[${this.accountId}] Reconnect deadline exceeded (${this.consecutiveDeadlineTimeouts}/${ConnectionManager.MAX_CONSECUTIVE_DEADLINE_TIMEOUTS}); scheduling next cycle in ${(delay / 1000).toFixed(2)}s`,\n );\n this.reconnectTimer = setTimeout(() => {\n void this.reconnect();\n }, delay);\n return;\n }\n\n this.runtimeReconnectCycles += 1;\n const maxCycles = this.config.maxReconnectCycles ?? ConnectionManager.DEFAULT_MAX_RECONNECT_CYCLES;\n\n if (this.runtimeReconnectCycles >= maxCycles) {\n this.log?.error?.(\n `[${this.accountId}] Max runtime reconnect cycles (${maxCycles}) reached. Giving up. ` +\n `Please check network connectivity or restart the gateway.`,\n );\n this.state = ConnectionStateEnum.FAILED;\n this.connectedAt = undefined;\n this.consecutiveUnhealthyChecks = 0;\n this.reconnectDeadline = undefined;\n this.notifyStateChange(`Max runtime reconnect cycles (${maxCycles}) reached`);\n this.resolveStopWaiters();\n return;\n }\n\n this.state = ConnectionStateEnum.FAILED;\n this.connectedAt = undefined;\n this.consecutiveUnhealthyChecks = 0;\n this.notifyStateChange(err.message);\n\n const rawDelay = this.calculateNextDelay(Math.min(this.runtimeReconnectCycles - 1, 6));\n const delay = Math.min(rawDelay, ConnectionManager.MAX_CYCLE_BACKOFF_MS);\n // Each cycle gets its own deadline so long-running retries don't block indefinitely\n const deadlineMs = this.config.reconnectDeadlineMs ?? 50000;\n this.reconnectDeadline = Date.now() + deadlineMs;\n this.attemptCount = 0;\n this.clearReconnectTimer();\n this.log?.warn?.(\n `[${this.accountId}] Reconnection cycle ${this.runtimeReconnectCycles}/${maxCycles} failed; scheduling next reconnect in ${(delay / 1000).toFixed(2)}s`,\n );\n this.reconnectTimer = setTimeout(() => {\n void this.reconnect();\n }, delay);\n }\n }\n\n /**\n * Stop the connection manager and cleanup resources\n */\n public stop(): void {\n if (this.stopped) {\n return;\n }\n\n this.log?.info?.(`[${this.accountId}] Stopping connection manager...`);\n\n this.stopped = true;\n this.state = ConnectionStateEnum.DISCONNECTING;\n this.connectedAt = undefined;\n this.reconnectDeadline = undefined;\n this.consecutiveDeadlineTimeouts = 0;\n this.consecutiveUnhealthyChecks = 0;\n this.lastSocketActivityAt = undefined;\n this.lastHeartbeatPingAt = undefined;\n this.consecutiveHeartbeatMisses = 0;\n\n // Clear reconnect timer\n this.clearReconnectTimer();\n\n // Cancel any in-flight sleep (retry delay)\n this.cancelSleep();\n\n // Clean up runtime monitoring resources\n this.cleanupRuntimeMonitoring();\n\n // Clean up any pending old client from warm-reconnect swap.\n this.cleanupPendingOldClient();\n\n // Disconnect client\n try {\n this.client.disconnect();\n } catch (err: any) {\n this.log?.warn?.(`[${this.accountId}] Error during disconnect: ${err.message}`);\n }\n\n this.state = ConnectionStateEnum.DISCONNECTED;\n this.log?.info?.(`[${this.accountId}] Connection manager stopped`);\n\n // Resolve all pending waitForStop() promises\n this.resolveStopWaiters();\n }\n\n /**\n * Returns a Promise that resolves when the connection manager is stopped.\n * Useful for keeping a caller alive (e.g. startAccount) until the channel\n * is explicitly stopped via stop() or an abort signal handler that calls stop().\n * Safe to call concurrently; all pending callers are resolved when stop() is called.\n */\n public waitForStop(): Promise<void> {\n if (this.stopped || this.state === ConnectionStateEnum.FAILED) {\n return Promise.resolve();\n }\n return new Promise<void>((resolve) => {\n this.stopPromiseResolvers.push(resolve);\n });\n }\n\n /**\n * Clear reconnection timer\n */\n private clearReconnectTimer(): void {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n this.log?.debug?.(`[${this.accountId}] Reconnect timer cleared`);\n }\n }\n\n /**\n * Sleep utility for retry delays\n * Returns a promise that resolves after ms or can be cancelled via cancelSleep()\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n this.sleepResolve = resolve;\n this.sleepTimeout = setTimeout(() => {\n this.sleepTimeout = undefined;\n this.sleepResolve = undefined;\n resolve();\n }, ms);\n });\n }\n\n /**\n * Cancel any in-flight sleep operation\n * Resolves the pending promise immediately so await unblocks\n */\n private cancelSleep(): void {\n if (this.sleepTimeout) {\n clearTimeout(this.sleepTimeout);\n this.sleepTimeout = undefined;\n this.log?.debug?.(`[${this.accountId}] Sleep timeout cancelled`);\n }\n // Resolve the pending promise so await unblocks immediately\n if (this.sleepResolve) {\n this.sleepResolve();\n this.sleepResolve = undefined;\n }\n }\n\n /**\n * Get current connection state\n */\n public getState(): ConnectionState {\n return this.state;\n }\n\n /**\n * Check if connection is active\n */\n public isConnected(): boolean {\n return this.state === ConnectionStateEnum.CONNECTED;\n }\n\n /**\n * Check if connection manager is stopped\n */\n public isStopped(): boolean {\n return this.stopped;\n }\n}\n", "// ============ Message Deduplication ============\n// Prevent duplicate processing when DingTalk retries delivery.\n// In-memory TTL map + lazy cleanup keeps overhead small.\nexport const DEDUP_NAMESPACE_POLICY = \"memory-only\" as const;\n\nconst processedMessages = new Map<string, number>();\nconst MESSAGE_DEDUP_TTL = 60000;\nconst MESSAGE_DEDUP_MAX_SIZE = 1000;\nlet messageCounter = 0;\n\n// Check whether message is still inside dedup window.\nexport function isMessageProcessed(dedupKey: string): boolean {\n const now = Date.now();\n const expiresAt = processedMessages.get(dedupKey);\n\n if (expiresAt === undefined) {\n return false;\n }\n\n if (now >= expiresAt) {\n processedMessages.delete(dedupKey);\n return false;\n }\n\n return true;\n}\n\n// Mark message as processed and lazily cleanup expired entries.\nexport function markMessageProcessed(dedupKey: string): void {\n const expiresAt = Date.now() + MESSAGE_DEDUP_TTL;\n processedMessages.set(dedupKey, expiresAt);\n\n // Hard cap for burst protection.\n if (processedMessages.size > MESSAGE_DEDUP_MAX_SIZE) {\n const now = Date.now();\n for (const [key, expiry] of processedMessages.entries()) {\n if (now >= expiry) {\n processedMessages.delete(key);\n }\n }\n\n // Safety valve: if still over cap after expired-entry sweep, drop oldest entries.\n if (processedMessages.size > MESSAGE_DEDUP_MAX_SIZE) {\n const removeCount = processedMessages.size - MESSAGE_DEDUP_MAX_SIZE;\n let removed = 0;\n for (const key of processedMessages.keys()) {\n processedMessages.delete(key);\n if (++removed >= removeCount) {\n break;\n }\n }\n }\n return;\n }\n\n // Deterministic lightweight cleanup every 10 messages.\n messageCounter++;\n if (messageCounter >= 10) {\n messageCounter = 0;\n const now = Date.now();\n for (const [key, expiry] of processedMessages.entries()) {\n if (now >= expiry) {\n processedMessages.delete(key);\n }\n }\n }\n}\n", "import { randomUUID } from \"node:crypto\";\nimport {\n appendFeedbackEvent,\n appendOutboundReplySnapshot,\n appendReflectionRecord,\n appendSessionLearningNote,\n deleteScopedRule,\n FeedbackKind,\n FeedbackEventRecord,\n getTargetSet,\n listAllScopedRules,\n listActiveSessionLearningNotes,\n listLearnedRules,\n listOutboundReplySnapshots,\n listTargetSets,\n LearnedRuleRecord,\n OutboundReplySnapshot,\n ReflectionCategory,\n ScopedLearnedRuleRecord,\n disableScopedRule,\n listTargetRules,\n TargetSetRecord,\n upsertTargetRule,\n upsertTargetSet,\n upsertLearnedRule,\n} from \"./feedback-learning-store\";\nimport type { DingTalkConfig, MessageContent } from \"./types\";\n\nconst NEGATIVE_SIGNAL_PATTERNS: Array<{ pattern: RegExp; category: ReflectionCategory }> = [\n { pattern: /(\u6CA1\u770B\u56FE|\u6CA1\u770B\u56FE\u7247|\u770B\u56FE|\u8865\u53D1\u539F\u56FE|\u522B\u731C\u56FE)/i, category: \"missing_image_context\" },\n { pattern: /(\u5F15\u7528|\u539F\u6587|\u539F\u6D88\u606F|\u522B\u731C|\u6CA1\u62FF\u5230|\u6CA1\u770B\u5230)/i, category: \"quoted_context_missing\" },\n { pattern: /(\u4E0D\u662F\u8FD9\u4E2A\u610F\u601D|\u7406\u89E3\u9519|\u7B54\u504F|\u91CD\u65B0\u7B54|\u91CD\u65B0\u56DE\u7B54|\u6211\u95EE\u7684\u662F)/i, category: \"misunderstood_intent\" },\n];\n\nfunction buildRuleInstruction(category: ReflectionCategory): string {\n switch (category) {\n case \"missing_image_context\":\n return \"\u5F53\u7528\u6237\u8981\u6C42\u770B\u56FE/\u5206\u6790\u56FE\u7247\u4F46\u5F53\u524D\u4E0A\u4E0B\u6587\u6CA1\u6709\u56FE\u7247\u672C\u4F53\u65F6\uFF0C\u7981\u6B62\u81C6\u6D4B\u5185\u5BB9\uFF0C\u5148\u660E\u786E\u8981\u6C42\u7528\u6237\u8865\u53D1\u539F\u56FE\u3002\";\n case \"quoted_context_missing\":\n return \"\u5F53\u5F15\u7528\u6D88\u606F\u6B63\u6587\u6216\u9644\u4EF6\u4E0D\u53EF\u89C1\u65F6\uFF0C\u7981\u6B62\u6839\u636E\u4E0A\u4E0B\u6587\u81C6\u6D4B\u5F15\u7528\u5185\u5BB9\uFF0C\u5148\u8BF4\u660E\u7F3A\u5931\u5E76\u8BF7\u7528\u6237\u8865\u53D1\u539F\u6587/\u539F\u6587\u4EF6\u3002\";\n case \"misunderstood_intent\":\n return \"\u5F53\u7528\u6237\u660E\u663E\u5728\u7EA0\u6B63\u4E0A\u4E00\u8F6E\u7406\u89E3\u65F6\uFF0C\u5148\u590D\u8FF0\u5176\u771F\u5B9E\u610F\u56FE\uFF0C\u518D\u7ED9\u51FA\u66F4\u76F4\u63A5\u7684\u4FEE\u6B63\u7B54\u6848\u3002\";\n case \"positive_direct_answer\":\n return \"\u4FDD\u6301\u76F4\u63A5\u3001\u8D34\u9898\u3001\u5C11\u7ED5\u5F2F\u7684\u56DE\u7B54\u65B9\u5F0F\u3002\";\n case \"generic_negative\":\n default:\n return \"\u82E5\u7528\u6237\u5BF9\u4E0A\u4E00\u8F6E\u56DE\u590D\u4E0D\u6EE1\u610F\uFF0C\u4F18\u5148\u7F29\u77ED\u7B54\u6848\u3001\u51CF\u5C11\u5047\u8BBE\uFF0C\u5E76\u5148\u786E\u8BA4\u5173\u952E\u4FE1\u606F\u662F\u5426\u5B8C\u6574\u3002\";\n }\n}\n\nfunction buildDiagnosis(kind: FeedbackKind, category: ReflectionCategory): string {\n if (kind === \"explicit_positive\") {\n return \"\u7528\u6237\u901A\u8FC7\u663E\u5F0F\u6B63\u53CD\u9988\u8BA4\u53EF\u4E86\u4E0A\u4E00\u6761\u56DE\u590D\uFF0C\u53EF\u4EE5\u4FDD\u7559\u5F53\u524D\u56DE\u7B54\u98CE\u683C\u3002\";\n }\n switch (category) {\n case \"missing_image_context\":\n return \"\u4E0A\u4E00\u6761\u56DE\u590D\u5F88\u53EF\u80FD\u5728\u7F3A\u5C11\u56FE\u7247\u672C\u4F53\u7684\u60C5\u51B5\u4E0B\u5C1D\u8BD5\u5206\u6790\u56FE\u7247\uFF0C\u5BFC\u81F4\u7528\u6237\u4E0D\u6EE1\u610F\u3002\";\n case \"quoted_context_missing\":\n return \"\u4E0A\u4E00\u6761\u56DE\u590D\u5F88\u53EF\u80FD\u5728\u5F15\u7528\u6B63\u6587/\u9644\u4EF6\u4E0D\u53EF\u89C1\u65F6\u505A\u4E86\u63A8\u65AD\uFF0C\u5BFC\u81F4\u7528\u6237\u4E0D\u6EE1\u610F\u3002\";\n case \"misunderstood_intent\":\n return \"\u7528\u6237\u5728\u540E\u7EED\u6D88\u606F\u91CC\u660E\u786E\u7EA0\u6B63\u4E86\u4E0A\u4E00\u8F6E\u7406\u89E3\uFF0C\u8BF4\u660E\u56DE\u7B54\u504F\u79BB\u4E86\u771F\u5B9E\u610F\u56FE\u3002\";\n case \"generic_negative\":\n default:\n return \"\u7528\u6237\u5BF9\u4E0A\u4E00\u6761\u56DE\u590D\u4E0D\u6EE1\u610F\uFF0C\u4F46\u5F53\u524D\u8BC1\u636E\u4E0D\u8DB3\u4EE5\u5F52\u5230\u66F4\u5177\u4F53\u7684\u9519\u8BEF\u7C7B\u578B\u3002\";\n }\n}\n\nfunction inferCategory(params: {\n kind: FeedbackKind;\n signalText?: string;\n snapshot?: OutboundReplySnapshot | null;\n content?: MessageContent;\n}): ReflectionCategory {\n if (params.kind === \"explicit_positive\") {\n return \"positive_direct_answer\";\n }\n\n const texts = [\n params.signalText || \"\",\n params.snapshot?.question || \"\",\n params.snapshot?.answer || \"\",\n params.content?.text || \"\",\n ].join(\"\\n\");\n\n if (params.kind === \"explicit_negative\") {\n if (/\u56FE|\u56FE\u7247|\u622A\u56FE|\u770B\u56FE/.test(params.snapshot?.question || \"\")) {\n return \"missing_image_context\";\n }\n if (/\u5F15\u7528|\u539F\u6587|\u539F\u6D88\u606F/.test(params.snapshot?.question || \"\")) {\n return \"quoted_context_missing\";\n }\n }\n\n for (const candidate of NEGATIVE_SIGNAL_PATTERNS) {\n if (candidate.pattern.test(texts)) {\n return candidate.category;\n }\n }\n return \"generic_negative\";\n}\n\nfunction latestSnapshotForTarget(\n storePath: string | undefined,\n accountId: string,\n targetId: string,\n processQueryKey?: string,\n): OutboundReplySnapshot | null {\n const snapshots = listOutboundReplySnapshots({ storePath, accountId, targetId });\n if (snapshots.length === 0) {\n return null;\n }\n if (processQueryKey) {\n const matched = snapshots.find((snapshot) => snapshot.processQueryKey === processQueryKey);\n if (matched) {\n return matched;\n }\n }\n return snapshots[0] || null;\n}\n\nfunction updateLearnedRule(\n storePath: string | undefined,\n accountId: string,\n category: ReflectionCategory,\n kind: FeedbackKind,\n): void {\n if (!storePath || kind === \"explicit_positive\") {\n return;\n }\n const ruleId = `rule_${category}`;\n const existing = listLearnedRules({ storePath, accountId }).find((rule) => rule.ruleId === ruleId);\n const negativeCount = (existing?.negativeCount || 0) + 1;\n const positiveCount = existing?.positiveCount || 0;\n const rule: LearnedRuleRecord = {\n ruleId,\n category,\n instruction: buildRuleInstruction(category),\n negativeCount,\n positiveCount,\n updatedAt: Date.now(),\n enabled: negativeCount >= 2,\n };\n upsertLearnedRule({ storePath, accountId, rule });\n}\n\nexport function isLearningEnabled(config: DingTalkConfig | undefined): boolean {\n return Boolean(config?.learningEnabled);\n}\n\nexport function isLearningAutoApplyEnabled(config: DingTalkConfig | undefined): boolean {\n return Boolean(config?.learningAutoApply);\n}\n\nexport function recordOutboundReplyForLearning(params: {\n enabled: boolean;\n storePath?: string;\n accountId: string;\n targetId: string;\n sessionKey: string;\n question: string;\n answer: string;\n processQueryKey?: string;\n mode?: \"card\" | \"markdown\";\n}): void {\n if (!params.enabled || !params.storePath || !params.answer.trim()) {\n return;\n }\n appendOutboundReplySnapshot({\n storePath: params.storePath,\n accountId: params.accountId,\n targetId: params.targetId,\n snapshot: {\n id: randomUUID(),\n targetId: params.targetId,\n sessionKey: params.sessionKey,\n question: params.question,\n answer: params.answer,\n processQueryKey: params.processQueryKey,\n mode: params.mode,\n createdAt: Date.now(),\n },\n });\n}\n\nexport function recordExplicitFeedbackLearning(params: {\n enabled: boolean;\n autoApply?: boolean;\n storePath?: string;\n accountId: string;\n targetId: string;\n feedbackType: \"feedback_up\" | \"feedback_down\";\n userId?: string;\n processQueryKey?: string;\n noteTtlMs?: number;\n}): void {\n if (!params.enabled || !params.storePath) {\n return;\n }\n const kind: FeedbackKind =\n params.feedbackType === \"feedback_up\" ? \"explicit_positive\" : \"explicit_negative\";\n const snapshot = latestSnapshotForTarget(\n params.storePath,\n params.accountId,\n params.targetId,\n params.processQueryKey,\n );\n const event: FeedbackEventRecord = {\n id: randomUUID(),\n kind,\n targetId: params.targetId,\n userId: params.userId,\n processQueryKey: params.processQueryKey,\n createdAt: Date.now(),\n snapshotId: snapshot?.id,\n };\n appendFeedbackEvent({\n storePath: params.storePath,\n accountId: params.accountId,\n targetId: params.targetId,\n event,\n });\n\n const category = inferCategory({ kind, snapshot });\n const reflection = {\n id: randomUUID(),\n targetId: params.targetId,\n sourceEventId: event.id,\n kind,\n category,\n diagnosis: buildDiagnosis(kind, category),\n suggestedInstruction: buildRuleInstruction(category),\n question: snapshot?.question,\n answer: snapshot?.answer,\n createdAt: Date.now(),\n };\n appendReflectionRecord({\n storePath: params.storePath,\n accountId: params.accountId,\n targetId: params.targetId,\n reflection,\n });\n\n if (params.autoApply && kind !== \"explicit_positive\") {\n appendSessionLearningNote({\n storePath: params.storePath,\n accountId: params.accountId,\n targetId: params.targetId,\n ttlMs: params.noteTtlMs,\n note: {\n id: randomUUID(),\n targetId: params.targetId,\n instruction: reflection.suggestedInstruction,\n source: kind,\n category,\n createdAt: Date.now(),\n },\n });\n }\n if (params.autoApply) {\n updateLearnedRule(params.storePath, params.accountId, category, kind);\n }\n}\n\nexport function analyzeImplicitNegativeFeedback(params: {\n enabled: boolean;\n autoApply?: boolean;\n storePath?: string;\n accountId: string;\n targetId: string;\n signalText: string;\n content: MessageContent;\n noteTtlMs?: number;\n}): void {\n if (!params.enabled || !params.storePath) {\n return;\n }\n\n const snapshot = latestSnapshotForTarget(params.storePath, params.accountId, params.targetId);\n if (!snapshot) {\n return;\n }\n\n const category = inferCategory({\n kind: \"implicit_negative\",\n signalText: params.signalText,\n snapshot,\n content: params.content,\n });\n if (category === \"generic_negative\" && !NEGATIVE_SIGNAL_PATTERNS.some((item) => item.pattern.test(params.signalText))) {\n return;\n }\n\n const event: FeedbackEventRecord = {\n id: randomUUID(),\n kind: \"implicit_negative\",\n targetId: params.targetId,\n createdAt: Date.now(),\n signalText: params.signalText,\n snapshotId: snapshot.id,\n sessionKey: snapshot.sessionKey,\n };\n appendFeedbackEvent({\n storePath: params.storePath,\n accountId: params.accountId,\n targetId: params.targetId,\n event,\n });\n\n const reflection = {\n id: randomUUID(),\n targetId: params.targetId,\n sourceEventId: event.id,\n kind: \"implicit_negative\" as const,\n category,\n diagnosis: buildDiagnosis(\"implicit_negative\", category),\n suggestedInstruction: buildRuleInstruction(category),\n question: snapshot.question,\n answer: snapshot.answer,\n createdAt: Date.now(),\n };\n appendReflectionRecord({\n storePath: params.storePath,\n accountId: params.accountId,\n targetId: params.targetId,\n reflection,\n });\n if (params.autoApply) {\n appendSessionLearningNote({\n storePath: params.storePath,\n accountId: params.accountId,\n targetId: params.targetId,\n ttlMs: params.noteTtlMs,\n note: {\n id: randomUUID(),\n targetId: params.targetId,\n instruction: reflection.suggestedInstruction,\n source: \"implicit_negative\",\n category,\n createdAt: Date.now(),\n },\n });\n updateLearnedRule(params.storePath, params.accountId, category, \"implicit_negative\");\n }\n}\n\nfunction ruleMatchesContent(rule: LearnedRuleRecord, content: MessageContent): boolean {\n if (rule.manual) {\n return true;\n }\n switch (rule.category) {\n case \"missing_image_context\":\n return /\u56FE|\u56FE\u7247|\u622A\u56FE|\u770B\u56FE|\u770B\u4E0B/.test(content.text) && !content.mediaPath;\n case \"quoted_context_missing\":\n return content.text.includes(\"[\u5F15\u7528\u6D88\u606F\") || Boolean(content.quoted);\n case \"misunderstood_intent\":\n return /\u91CD\u65B0|\u518D\u7B54|\u91CD\u7B54|\u8865\u5145/.test(content.text);\n case \"generic_negative\":\n case \"positive_direct_answer\":\n default:\n return false;\n }\n}\n\nexport function buildLearningContextBlock(params: {\n enabled: boolean;\n storePath?: string;\n accountId: string;\n targetId: string;\n content: MessageContent;\n}): string {\n if (!params.enabled || !params.storePath) {\n return \"\";\n }\n const notes = listActiveSessionLearningNotes({\n storePath: params.storePath,\n accountId: params.accountId,\n targetId: params.targetId,\n }).slice(0, 3);\n const rules = listLearnedRules({\n storePath: params.storePath,\n accountId: params.accountId,\n })\n .filter((rule) => rule.enabled && ruleMatchesContent(rule, params.content))\n .slice(0, 3);\n const targetRules = listTargetRules({\n storePath: params.storePath,\n accountId: params.accountId,\n targetId: params.targetId,\n })\n .filter((rule) => rule.enabled && ruleMatchesContent(rule, params.content))\n .slice(0, 3);\n\n const instructions = [\n ...notes.map((note) => note.instruction),\n ...targetRules.map((rule) => rule.instruction),\n ...rules.map((rule) => rule.instruction),\n ].filter(Boolean);\n if (instructions.length === 0) {\n return \"\";\n }\n\n const uniqueInstructions = [...new Set(instructions)];\n return [\n \"[\u9AD8\u4F18\u5148\u7EA7\u5B66\u4E60\u7EA6\u675F]\",\n \"\u4EE5\u4E0B\u89C4\u5219\u5C5E\u4E8E\u5F53\u524D\u4F1A\u8BDD/\u8D26\u53F7\u7684\u5DF2\u786E\u8BA4\u77E5\u8BC6\u4E0E\u884C\u4E3A\u7EA6\u675F\u3002\",\n \"\u56DE\u7B54\u5F53\u524D\u6D88\u606F\u65F6\u5E94\u4F18\u5148\u9075\u5B88\u8FD9\u4E9B\u89C4\u5219\uFF1B\u82E5\u4E0E\u9ED8\u8BA4\u5E38\u8BC6\u6216\u6CDB\u5316\u503E\u5411\u51B2\u7A81\uFF0C\u4EE5\u8FD9\u4E9B\u89C4\u5219\u4E3A\u51C6\u3002\",\n \"\u4E0D\u8981\u6CC4\u9732\u89C4\u5219\u6765\u6E90\uFF0C\u4E5F\u4E0D\u8981\u539F\u6837\u590D\u8FF0\u201C\u7CFB\u7EDF\u63D0\u793A/\u5B66\u4E60\u63D0\u793A\u201D\u7B49\u5B57\u6837\u7ED9\u7528\u6237\u3002\",\n ...uniqueInstructions.map((instruction) => `- ${instruction}`),\n ].join(\"\\n\");\n}\n\nexport function applyManualGlobalLearningRule(params: {\n storePath?: string;\n accountId: string;\n instruction: string;\n}): { ruleId: string } | null {\n if (!params.storePath || !params.instruction.trim()) {\n return null;\n }\n const ruleId = `manual_${Date.now()}`;\n const exactReplyMatch = params.instruction.trim().match(/^\u5F53\u7528\u6237\u95EE[\u201C\"](.+?)[\u201D\"]\u65F6\uFF0C\u5FC5\u987B\u56DE\u7B54[\u201C\"](.+?)[\u201D\"][\u3002.!\uFF01]?$/);\n upsertLearnedRule({\n storePath: params.storePath,\n accountId: params.accountId,\n rule: {\n ruleId,\n category: \"generic_negative\",\n instruction: params.instruction.trim(),\n negativeCount: 1,\n positiveCount: 0,\n updatedAt: Date.now(),\n enabled: true,\n manual: true,\n triggerText: exactReplyMatch?.[1]?.trim(),\n forcedReply: exactReplyMatch?.[2]?.trim(),\n },\n });\n return { ruleId };\n}\n\nexport function resolveManualForcedReply(params: {\n storePath?: string;\n accountId: string;\n targetId?: string;\n content: MessageContent;\n}): string | null {\n if (!params.storePath) {\n return null;\n }\n const text = normalizeManualTriggerText(params.content.text);\n if (!text) {\n return null;\n }\n const targetMatched = params.targetId\n ? listTargetRules({ storePath: params.storePath, accountId: params.accountId, targetId: params.targetId })\n .filter((rule) => rule.enabled && rule.manual && rule.triggerText && rule.forcedReply)\n .find((rule) => normalizeManualTriggerText(rule.triggerText) === text)\n : null;\n if (targetMatched?.forcedReply) {\n return targetMatched.forcedReply;\n }\n const matched = listLearnedRules({ storePath: params.storePath, accountId: params.accountId })\n .filter((rule) => rule.enabled && rule.manual && rule.triggerText && rule.forcedReply)\n .find((rule) => normalizeManualTriggerText(rule.triggerText) === text);\n return matched?.forcedReply || null;\n}\n\nexport function applyManualSessionLearningNote(params: {\n storePath?: string;\n accountId: string;\n targetId: string;\n instruction: string;\n noteTtlMs?: number;\n}): boolean {\n if (!params.storePath || !params.instruction.trim()) {\n return false;\n }\n appendSessionLearningNote({\n storePath: params.storePath,\n accountId: params.accountId,\n targetId: params.targetId,\n ttlMs: params.noteTtlMs,\n note: {\n id: randomUUID(),\n targetId: params.targetId,\n instruction: params.instruction.trim(),\n source: \"implicit_negative\",\n category: \"generic_negative\",\n createdAt: Date.now(),\n },\n });\n return true;\n}\n\nexport function applyManualTargetLearningRule(params: {\n storePath?: string;\n accountId: string;\n targetId: string;\n instruction: string;\n}): { ruleId: string } | null {\n if (!params.storePath || !params.targetId.trim() || !params.instruction.trim()) {\n return null;\n }\n const ruleId = `manual_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n const exactReplyMatch = params.instruction.trim().match(/^\u5F53\u7528\u6237\u95EE[\u201C\"](.+?)[\u201D\"]\u65F6\uFF0C\u5FC5\u987B\u56DE\u7B54[\u201C\"](.+?)[\u201D\"][\u3002.!\uFF01]?$/);\n upsertTargetRule({\n storePath: params.storePath,\n accountId: params.accountId,\n targetId: params.targetId,\n rule: {\n ruleId,\n category: \"generic_negative\",\n instruction: params.instruction.trim(),\n negativeCount: 1,\n positiveCount: 0,\n updatedAt: Date.now(),\n enabled: true,\n manual: true,\n triggerText: exactReplyMatch?.[1]?.trim(),\n forcedReply: exactReplyMatch?.[2]?.trim(),\n },\n });\n return { ruleId };\n}\n\nexport function applyManualTargetsLearningRule(params: {\n storePath?: string;\n accountId: string;\n targetIds: string[];\n instruction: string;\n}): Array<{ targetId: string; ruleId: string }> {\n if (!params.storePath) {\n return [];\n }\n return params.targetIds\n .map((targetId) => applyManualTargetLearningRule({\n storePath: params.storePath,\n accountId: params.accountId,\n targetId,\n instruction: params.instruction,\n }))\n .map((result, index) => result ? { targetId: params.targetIds[index], ruleId: result.ruleId } : null)\n .filter(Boolean) as Array<{ targetId: string; ruleId: string }>;\n}\n\nexport function disableManualRule(params: {\n storePath?: string;\n accountId: string;\n ruleId: string;\n}): { existed: boolean; scope?: \"global\" | \"target\"; targetId?: string } {\n return disableScopedRule(params);\n}\n\nexport function deleteManualRule(params: {\n storePath?: string;\n accountId: string;\n ruleId: string;\n}): { existed: boolean; scope?: \"global\" | \"target\"; targetId?: string } {\n return deleteScopedRule(params);\n}\n\nexport function createOrUpdateTargetSet(params: {\n storePath?: string;\n accountId: string;\n name: string;\n targetIds: string[];\n}): boolean {\n if (!params.storePath || !params.name.trim() || params.targetIds.length === 0) {\n return false;\n }\n upsertTargetSet(params);\n return true;\n}\n\nexport function listLearningTargetSets(params: {\n storePath?: string;\n accountId: string;\n}): TargetSetRecord[] {\n return listTargetSets(params);\n}\n\nexport function applyTargetSetLearningRule(params: {\n storePath?: string;\n accountId: string;\n name: string;\n instruction: string;\n}): Array<{ targetId: string; ruleId: string }> {\n if (!params.storePath) {\n return [];\n }\n const targetSet = getTargetSet({\n storePath: params.storePath,\n accountId: params.accountId,\n name: params.name,\n });\n if (!targetSet) {\n return [];\n }\n return applyManualTargetsLearningRule({\n storePath: params.storePath,\n accountId: params.accountId,\n targetIds: targetSet.targetIds,\n instruction: params.instruction,\n });\n}\n\nexport function listScopedLearningRules(params: {\n storePath?: string;\n accountId: string;\n}): ScopedLearnedRuleRecord[] {\n return listAllScopedRules(params);\n}\n\nexport function normalizeManualTriggerText(input: string | undefined): string {\n return stripLeadingInvisibleChars(String(input || \"\"))\n .trim()\n .replace(/[\u3002.!\uFF01?\uFF1F]+$/g, \"\")\n .replace(/\\s+/g, \" \")\n .toLowerCase();\n}\n\nfunction stripLeadingInvisibleChars(value: string): string {\n let index = 0;\n while (index < value.length) {\n const codePoint = value.codePointAt(index);\n if (\n codePoint === undefined ||\n !(\n (codePoint >= 0x00 && codePoint <= 0x1f) ||\n (codePoint >= 0x7f && codePoint <= 0x9f) ||\n (codePoint >= 0x200b && codePoint <= 0x200f) ||\n codePoint === 0x2060 ||\n codePoint === 0xfeff\n )\n ) {\n break;\n }\n index += codePoint > 0xffff ? 2 : 1;\n }\n return value.slice(index);\n}\n", "import { readNamespaceJson, writeNamespaceJsonAtomic } from \"./persistence-store\";\n\nconst MAX_EVENTS = 200;\nconst MAX_SNAPSHOTS = 100;\nconst MAX_REFLECTIONS = 200;\nconst MAX_SESSION_NOTES = 20;\nconst MAX_RULES = 50;\nconst DEFAULT_NOTE_TTL_MS = 6 * 60 * 60 * 1000;\n\nconst EVENTS_NAMESPACE = \"feedback.events\";\nconst SNAPSHOTS_NAMESPACE = \"feedback.snapshots\";\nconst REFLECTIONS_NAMESPACE = \"feedback.reflections\";\nconst SESSION_NOTES_NAMESPACE = \"feedback.session-notes\";\nconst LEARNED_RULES_NAMESPACE = \"feedback.learned-rules\";\nconst TARGET_RULES_NAMESPACE = \"feedback.target-rules\";\nconst TARGET_RULE_INDEX_NAMESPACE = \"feedback.target-rules-index\";\nconst TARGET_SETS_NAMESPACE = \"feedback.target-sets\";\n\nexport type FeedbackKind = \"explicit_positive\" | \"explicit_negative\" | \"implicit_negative\";\nexport type ReflectionCategory =\n | \"missing_image_context\"\n | \"quoted_context_missing\"\n | \"misunderstood_intent\"\n | \"generic_negative\"\n | \"positive_direct_answer\";\n\nexport interface FeedbackEventRecord {\n id: string;\n kind: FeedbackKind;\n targetId: string;\n sessionKey?: string;\n processQueryKey?: string;\n userId?: string;\n createdAt: number;\n signalText?: string;\n snapshotId?: string;\n}\n\nexport interface OutboundReplySnapshot {\n id: string;\n targetId: string;\n sessionKey: string;\n question: string;\n answer: string;\n createdAt: number;\n processQueryKey?: string;\n mode?: \"card\" | \"markdown\";\n}\n\nexport interface ReflectionRecord {\n id: string;\n targetId: string;\n sourceEventId: string;\n kind: FeedbackKind;\n category: ReflectionCategory;\n diagnosis: string;\n suggestedInstruction: string;\n question?: string;\n answer?: string;\n createdAt: number;\n}\n\nexport interface SessionLearningNote {\n id: string;\n targetId: string;\n instruction: string;\n source: FeedbackKind;\n category: ReflectionCategory;\n createdAt: number;\n expiresAt: number;\n}\n\nexport interface LearnedRuleRecord {\n ruleId: string;\n category: ReflectionCategory;\n instruction: string;\n negativeCount: number;\n positiveCount: number;\n updatedAt: number;\n enabled: boolean;\n manual?: boolean;\n triggerText?: string;\n forcedReply?: string;\n}\n\ninterface ListBucket<T> {\n updatedAt: number;\n entries: T[];\n}\n\ninterface LearnedRuleBucket {\n updatedAt: number;\n rules: Record<string, LearnedRuleRecord>;\n}\n\ninterface TargetRuleIndexBucket {\n updatedAt: number;\n targetIds: string[];\n}\n\nexport interface TargetSetRecord {\n name: string;\n targetIds: string[];\n updatedAt: number;\n}\n\ninterface TargetSetBucket {\n updatedAt: number;\n sets: Record<string, TargetSetRecord>;\n}\n\nexport interface ScopedLearnedRuleRecord extends LearnedRuleRecord {\n scope: \"global\" | \"target\";\n targetId?: string;\n}\n\nfunction trimNewest<T extends { createdAt: number }>(entries: T[], limit: number): T[] {\n return entries.toSorted((left, right) => right.createdAt - left.createdAt).slice(0, limit);\n}\n\nfunction readListBucket<T>(\n namespace: string,\n params: { storePath?: string; accountId: string; targetId: string },\n): ListBucket<T> {\n if (!params.storePath) {\n return { updatedAt: 0, entries: [] };\n }\n return readNamespaceJson<ListBucket<T>>(namespace, {\n storePath: params.storePath,\n scope: { accountId: params.accountId, targetId: params.targetId },\n format: \"json\",\n fallback: { updatedAt: 0, entries: [] },\n });\n}\n\nfunction writeListBucket<T>(\n namespace: string,\n params: { storePath?: string; accountId: string; targetId: string; entries: T[] },\n): void {\n if (!params.storePath) {\n return;\n }\n writeNamespaceJsonAtomic(namespace, {\n storePath: params.storePath,\n scope: { accountId: params.accountId, targetId: params.targetId },\n format: \"json\",\n data: {\n updatedAt: Date.now(),\n entries: params.entries,\n } satisfies ListBucket<T>,\n });\n}\n\nexport function appendFeedbackEvent(\n params: { storePath?: string; accountId: string; targetId: string; event: FeedbackEventRecord },\n): void {\n const bucket = readListBucket<FeedbackEventRecord>(EVENTS_NAMESPACE, params);\n bucket.entries = trimNewest([...bucket.entries, params.event], MAX_EVENTS);\n writeListBucket(EVENTS_NAMESPACE, { ...params, entries: bucket.entries });\n}\n\nexport function listFeedbackEvents(\n params: { storePath?: string; accountId: string; targetId: string },\n): FeedbackEventRecord[] {\n return readListBucket<FeedbackEventRecord>(EVENTS_NAMESPACE, params).entries;\n}\n\nexport function appendOutboundReplySnapshot(\n params: { storePath?: string; accountId: string; targetId: string; snapshot: OutboundReplySnapshot },\n): void {\n const bucket = readListBucket<OutboundReplySnapshot>(SNAPSHOTS_NAMESPACE, params);\n bucket.entries = trimNewest([...bucket.entries, params.snapshot], MAX_SNAPSHOTS);\n writeListBucket(SNAPSHOTS_NAMESPACE, { ...params, entries: bucket.entries });\n}\n\nexport function listOutboundReplySnapshots(\n params: { storePath?: string; accountId: string; targetId: string },\n): OutboundReplySnapshot[] {\n return readListBucket<OutboundReplySnapshot>(SNAPSHOTS_NAMESPACE, params).entries;\n}\n\nexport function appendReflectionRecord(\n params: { storePath?: string; accountId: string; targetId: string; reflection: ReflectionRecord },\n): void {\n const bucket = readListBucket<ReflectionRecord>(REFLECTIONS_NAMESPACE, params);\n bucket.entries = trimNewest([...bucket.entries, params.reflection], MAX_REFLECTIONS);\n writeListBucket(REFLECTIONS_NAMESPACE, { ...params, entries: bucket.entries });\n}\n\nexport function listReflectionRecords(\n params: { storePath?: string; accountId: string; targetId: string },\n): ReflectionRecord[] {\n return readListBucket<ReflectionRecord>(REFLECTIONS_NAMESPACE, params).entries;\n}\n\nexport function appendSessionLearningNote(\n params: {\n storePath?: string;\n accountId: string;\n targetId: string;\n note: Omit<SessionLearningNote, \"expiresAt\"> & { expiresAt?: number };\n ttlMs?: number;\n },\n): void {\n const ttlMs = params.ttlMs && params.ttlMs > 0 ? params.ttlMs : DEFAULT_NOTE_TTL_MS;\n const nowMs = Date.now();\n const bucket = readListBucket<SessionLearningNote>(SESSION_NOTES_NAMESPACE, params);\n const retained = bucket.entries.filter((note) => note.expiresAt > nowMs);\n retained.unshift({\n ...params.note,\n expiresAt: params.note.expiresAt ?? nowMs + ttlMs,\n });\n writeListBucket(SESSION_NOTES_NAMESPACE, {\n ...params,\n entries: trimNewest(retained, MAX_SESSION_NOTES),\n });\n}\n\nexport function listActiveSessionLearningNotes(\n params: { storePath?: string; accountId: string; targetId: string; nowMs?: number },\n): SessionLearningNote[] {\n const nowMs = params.nowMs ?? Date.now();\n return readListBucket<SessionLearningNote>(SESSION_NOTES_NAMESPACE, params).entries.filter(\n (note) => note.expiresAt > nowMs,\n );\n}\n\nexport function upsertLearnedRule(\n params: { storePath?: string; accountId: string; rule: LearnedRuleRecord },\n): void {\n if (!params.storePath) {\n return;\n }\n const bucket = readNamespaceJson<LearnedRuleBucket>(LEARNED_RULES_NAMESPACE, {\n storePath: params.storePath,\n scope: { accountId: params.accountId },\n format: \"json\",\n fallback: { updatedAt: 0, rules: {} },\n });\n bucket.rules[params.rule.ruleId] = params.rule;\n const trimmedRules = Object.values(bucket.rules)\n .toSorted((left, right) => right.updatedAt - left.updatedAt)\n .slice(0, MAX_RULES);\n const rules: Record<string, LearnedRuleRecord> = {};\n for (const rule of trimmedRules) {\n rules[rule.ruleId] = rule;\n }\n writeNamespaceJsonAtomic(LEARNED_RULES_NAMESPACE, {\n storePath: params.storePath,\n scope: { accountId: params.accountId },\n format: \"json\",\n data: { updatedAt: Date.now(), rules } satisfies LearnedRuleBucket,\n });\n}\n\nexport function listLearnedRules(\n params: { storePath?: string; accountId: string },\n): LearnedRuleRecord[] {\n if (!params.storePath) {\n return [];\n }\n const bucket = readNamespaceJson<LearnedRuleBucket>(LEARNED_RULES_NAMESPACE, {\n storePath: params.storePath,\n scope: { accountId: params.accountId },\n format: \"json\",\n fallback: { updatedAt: 0, rules: {} },\n });\n return Object.values(bucket.rules).toSorted((left, right) => right.updatedAt - left.updatedAt);\n}\n\nexport function disableLearnedRule(\n params: { storePath?: string; accountId: string; ruleId: string },\n): boolean {\n if (!params.storePath) {\n return false;\n }\n const bucket = readNamespaceJson<LearnedRuleBucket>(LEARNED_RULES_NAMESPACE, {\n storePath: params.storePath,\n scope: { accountId: params.accountId },\n format: \"json\",\n fallback: { updatedAt: 0, rules: {} },\n });\n const existing = bucket.rules[params.ruleId];\n if (!existing) {\n return false;\n }\n bucket.rules[params.ruleId] = {\n ...existing,\n enabled: false,\n updatedAt: Date.now(),\n };\n writeNamespaceJsonAtomic(LEARNED_RULES_NAMESPACE, {\n storePath: params.storePath,\n scope: { accountId: params.accountId },\n format: \"json\",\n data: { updatedAt: Date.now(), rules: bucket.rules } satisfies LearnedRuleBucket,\n });\n return true;\n}\n\nexport function deleteLearnedRule(\n params: { storePath?: string; accountId: string; ruleId: string },\n): boolean {\n if (!params.storePath) {\n return false;\n }\n const bucket = readNamespaceJson<LearnedRuleBucket>(LEARNED_RULES_NAMESPACE, {\n storePath: params.storePath,\n scope: { accountId: params.accountId },\n format: \"json\",\n fallback: { updatedAt: 0, rules: {} },\n });\n if (!bucket.rules[params.ruleId]) {\n return false;\n }\n delete bucket.rules[params.ruleId];\n writeNamespaceJsonAtomic(LEARNED_RULES_NAMESPACE, {\n storePath: params.storePath,\n scope: { accountId: params.accountId },\n format: \"json\",\n data: { updatedAt: Date.now(), rules: bucket.rules } satisfies LearnedRuleBucket,\n });\n return true;\n}\n\nfunction readTargetRuleIndex(\n params: { storePath?: string; accountId: string },\n): TargetRuleIndexBucket {\n if (!params.storePath) {\n return { updatedAt: 0, targetIds: [] };\n }\n return readNamespaceJson<TargetRuleIndexBucket>(TARGET_RULE_INDEX_NAMESPACE, {\n storePath: params.storePath,\n scope: { accountId: params.accountId },\n format: \"json\",\n fallback: { updatedAt: 0, targetIds: [] },\n });\n}\n\nfunction writeTargetRuleIndex(\n params: { storePath?: string; accountId: string; targetIds: string[] },\n): void {\n if (!params.storePath) {\n return;\n }\n writeNamespaceJsonAtomic(TARGET_RULE_INDEX_NAMESPACE, {\n storePath: params.storePath,\n scope: { accountId: params.accountId },\n format: \"json\",\n data: {\n updatedAt: Date.now(),\n targetIds: [...new Set(params.targetIds.filter((targetId) => targetId.trim()))],\n } satisfies TargetRuleIndexBucket,\n });\n}\n\nfunction readTargetRuleBucket(\n params: { storePath?: string; accountId: string; targetId: string },\n): LearnedRuleBucket {\n if (!params.storePath) {\n return { updatedAt: 0, rules: {} };\n }\n return readNamespaceJson<LearnedRuleBucket>(TARGET_RULES_NAMESPACE, {\n storePath: params.storePath,\n scope: { accountId: params.accountId, targetId: params.targetId },\n format: \"json\",\n fallback: { updatedAt: 0, rules: {} },\n });\n}\n\nfunction writeTargetRuleBucket(\n params: { storePath?: string; accountId: string; targetId: string; bucket: LearnedRuleBucket },\n): void {\n if (!params.storePath) {\n return;\n }\n writeNamespaceJsonAtomic(TARGET_RULES_NAMESPACE, {\n storePath: params.storePath,\n scope: { accountId: params.accountId, targetId: params.targetId },\n format: \"json\",\n data: params.bucket,\n });\n}\n\nexport function upsertTargetRule(\n params: { storePath?: string; accountId: string; targetId: string; rule: LearnedRuleRecord },\n): void {\n if (!params.storePath) {\n return;\n }\n const bucket = readTargetRuleBucket(params);\n bucket.rules[params.rule.ruleId] = params.rule;\n const trimmedRules = Object.values(bucket.rules)\n .toSorted((left, right) => right.updatedAt - left.updatedAt)\n .slice(0, MAX_RULES);\n const rules: Record<string, LearnedRuleRecord> = {};\n for (const rule of trimmedRules) {\n rules[rule.ruleId] = rule;\n }\n writeTargetRuleBucket({\n storePath: params.storePath,\n accountId: params.accountId,\n targetId: params.targetId,\n bucket: { updatedAt: Date.now(), rules },\n });\n const index = readTargetRuleIndex({ storePath: params.storePath, accountId: params.accountId });\n writeTargetRuleIndex({\n storePath: params.storePath,\n accountId: params.accountId,\n targetIds: [...index.targetIds, params.targetId],\n });\n}\n\nexport function listTargetRules(\n params: { storePath?: string; accountId: string; targetId: string },\n): LearnedRuleRecord[] {\n return Object.values(readTargetRuleBucket(params).rules).toSorted(\n (left, right) => right.updatedAt - left.updatedAt,\n );\n}\n\nexport function listAllScopedRules(\n params: { storePath?: string; accountId: string },\n): ScopedLearnedRuleRecord[] {\n const globalRules = listLearnedRules(params).map((rule) => ({ ...rule, scope: \"global\" as const }));\n const targetIds = readTargetRuleIndex(params).targetIds;\n const targetRules = targetIds.flatMap((targetId) =>\n listTargetRules({ ...params, targetId }).map((rule) => ({\n ...rule,\n scope: \"target\" as const,\n targetId,\n })),\n );\n return [...targetRules, ...globalRules].toSorted((left, right) => right.updatedAt - left.updatedAt);\n}\n\nexport function disableScopedRule(\n params: { storePath?: string; accountId: string; ruleId: string },\n): { existed: boolean; scope?: \"global\" | \"target\"; targetId?: string } {\n if (disableLearnedRule(params)) {\n return { existed: true, scope: \"global\" };\n }\n const targetIds = readTargetRuleIndex(params).targetIds;\n for (const targetId of targetIds) {\n const bucket = readTargetRuleBucket({ ...params, targetId });\n const existing = bucket.rules[params.ruleId];\n if (!existing) {\n continue;\n }\n bucket.rules[params.ruleId] = {\n ...existing,\n enabled: false,\n updatedAt: Date.now(),\n };\n writeTargetRuleBucket({\n storePath: params.storePath,\n accountId: params.accountId,\n targetId,\n bucket: { updatedAt: Date.now(), rules: bucket.rules },\n });\n return { existed: true, scope: \"target\", targetId };\n }\n return { existed: false };\n}\n\nexport function deleteScopedRule(\n params: { storePath?: string; accountId: string; ruleId: string },\n): { existed: boolean; scope?: \"global\" | \"target\"; targetId?: string } {\n if (deleteLearnedRule(params)) {\n return { existed: true, scope: \"global\" };\n }\n const targetIds = readTargetRuleIndex(params).targetIds;\n for (const targetId of targetIds) {\n const bucket = readTargetRuleBucket({ ...params, targetId });\n if (!bucket.rules[params.ruleId]) {\n continue;\n }\n delete bucket.rules[params.ruleId];\n writeTargetRuleBucket({\n storePath: params.storePath,\n accountId: params.accountId,\n targetId,\n bucket: { updatedAt: Date.now(), rules: bucket.rules },\n });\n return { existed: true, scope: \"target\", targetId };\n }\n return { existed: false };\n}\n\nexport function upsertTargetSet(\n params: { storePath?: string; accountId: string; name: string; targetIds: string[] },\n): void {\n if (!params.storePath) {\n return;\n }\n const bucket = readNamespaceJson<TargetSetBucket>(TARGET_SETS_NAMESPACE, {\n storePath: params.storePath,\n scope: { accountId: params.accountId },\n format: \"json\",\n fallback: { updatedAt: 0, sets: {} },\n });\n bucket.sets[params.name] = {\n name: params.name,\n targetIds: [...new Set(params.targetIds.filter((targetId) => targetId.trim()))],\n updatedAt: Date.now(),\n };\n writeNamespaceJsonAtomic(TARGET_SETS_NAMESPACE, {\n storePath: params.storePath,\n scope: { accountId: params.accountId },\n format: \"json\",\n data: { updatedAt: Date.now(), sets: bucket.sets } satisfies TargetSetBucket,\n });\n}\n\nexport function getTargetSet(\n params: { storePath?: string; accountId: string; name: string },\n): TargetSetRecord | null {\n if (!params.storePath) {\n return null;\n }\n const bucket = readNamespaceJson<TargetSetBucket>(TARGET_SETS_NAMESPACE, {\n storePath: params.storePath,\n scope: { accountId: params.accountId },\n format: \"json\",\n fallback: { updatedAt: 0, sets: {} },\n });\n return bucket.sets[params.name] || null;\n}\n\nexport function listTargetSets(\n params: { storePath?: string; accountId: string },\n): TargetSetRecord[] {\n if (!params.storePath) {\n return [];\n }\n const bucket = readNamespaceJson<TargetSetBucket>(TARGET_SETS_NAMESPACE, {\n storePath: params.storePath,\n scope: { accountId: params.accountId },\n format: \"json\",\n fallback: { updatedAt: 0, sets: {} },\n });\n return Object.values(bucket.sets).toSorted((left, right) => right.updatedAt - left.updatedAt);\n}\n", "import fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { isAbortRequestText, isBtwRequestText } from \"openclaw/plugin-sdk/reply-runtime\";\nimport { parseInlineDirectives } from \"openclaw/plugin-sdk/text-runtime\";\nimport { normalizeAllowFrom, isSenderAllowed, resolveGroupAccess } from \"./access-control\";\nimport { classifyAckReactionEmoji } from \"./ack-reaction-classifier\";\nimport { attachNativeAckReaction } from \"./ack-reaction-service\";\nimport { createDynamicAckReactionController } from \"./ack-reaction/dynamic-ack-reaction-controller\";\nimport { getAccessToken } from \"./auth\";\nimport { createAICard, commitAICardBlocks, isCardInTerminalState } from \"./card-service\";\nimport { isCardRunStopRequested, registerCardRun, removeCardRun } from \"./card/card-run-registry\";\nimport { renderStatusLine } from \"./card/statusline-renderer\";\nimport { handleInboundCommandDispatch } from \"./command/inbound-command-dispatch-service\";\nimport {\n resolveAckReactionSetting,\n resolveGroupConfig,\n resolveRelativePath,\n resolveRobotCode,\n} from \"./config\";\nimport { buildLearningContextBlock, isLearningEnabled } from \"./feedback-learning-service\";\nimport axios from \"./http-client\";\nimport { setCurrentLogger } from \"./logger-context\";\nimport { prepareMediaInput, resolveOutboundMediaType } from \"./media-utils\";\nimport {\n DEFAULT_MEDIA_CONTEXT_TTL_MS,\n DEFAULT_MESSAGE_CONTEXT_TTL_DAYS,\n upsertInboundMessageContext,\n} from \"./message-context-store\";\nimport { extractMessageContent } from \"./message-utils\";\nimport { extractAttachmentText } from \"./messaging/attachment-text-extractor\";\nimport { deliverBtwReply, stripLeadingMentions } from \"./messaging/btw-deliver\";\nimport { resolveQuotedRuntimeContext } from \"./messaging/quoted-context\";\nimport {\n downloadGroupFile,\n getUnionIdByStaffId,\n resolveQuotedFile,\n} from \"./messaging/quoted-file-service\";\nimport {\n buildInboundQuotedRef,\n createReplyQuotedRef,\n resolveQuotedRecord,\n} from \"./messaging/quoted-ref\";\nimport { registerPeerId } from \"./peer-id-registry\";\nimport {\n clearProactiveRiskObservationsForTest,\n getProactiveRiskObservationForAny,\n} from \"./proactive-risk-registry\";\nimport { createReplyStrategy } from \"./reply-strategy\";\nimport type { DeliverPayload } from \"./reply-strategy-types\";\nimport { getDingTalkRuntime } from \"./runtime\";\nimport { sendBySession, sendMessage, sendProactiveMedia } from \"./send-service\";\nimport { acquireSessionLock } from \"./session-lock\";\nimport {\n clearSessionPeerOverride,\n getSessionPeerOverride,\n setSessionPeerOverride,\n} from \"./session-peer-store\";\nimport { resolveDingTalkSessionPeer } from \"./session-routing\";\nimport { getSessionState, initSessionState } from \"./session-state\";\nimport { getAgentDisplayName } from \"./targeting/agent-name-matcher\";\nimport {\n buildAgentSessionKey,\n resolveSubAgentRoute,\n dispatchSubAgents,\n} from \"./targeting/agent-routing\";\nimport { formatGroupMembers, noteGroupMember } from \"./targeting/group-members-store\";\nimport {\n upsertObservedGroupTarget,\n upsertObservedUserTarget,\n} from \"./targeting/target-directory-store\";\nimport { AICardStatus } from \"./types\";\nimport type { DingTalkConfig, HandleDingTalkMessageParams, Logger, MediaFile } from \"./types\";\nimport {\n formatDingTalkErrorPayloadLog,\n getErrorMessage,\n getErrorResponseData,\n maskSensitiveData,\n parseBooleanLike,\n} from \"./utils\";\n\nconst DEFAULT_PROACTIVE_HINT_COOLDOWN_HOURS = 24;\nconst MIN_THINKING_REACTION_VISIBLE_MS = 1200;\nconst MAX_DYNAMIC_ACK_DISPOSE_WAIT_MS = 500;\nconst ATTACHMENT_TEXT_PREFIX = \"[\u9644\u4EF6\u5185\u5BB9\u6458\u5F55]\";\nconst MEDIA_DIRECTIVE_PREFIX = \"MEDIA:\";\nconst STANDALONE_MEDIA_PATH_EXTENSIONS = new Set([\n \".jpg\",\n \".jpeg\",\n \".png\",\n \".gif\",\n \".bmp\",\n \".ogg\",\n \".amr\",\n \".mp3\",\n \".wav\",\n \".mp4\",\n \".avi\",\n \".mov\",\n \".doc\",\n \".docx\",\n \".xls\",\n \".xlsx\",\n \".ppt\",\n \".pptx\",\n \".zip\",\n \".pdf\",\n \".rar\",\n]);\nconst proactiveHintLastSentAt = new Map<string, number>();\nconst sessionReasoningLevelCache = new Map<\n string,\n {\n updatedAt?: number;\n reasoningLevel?: string;\n }\n>();\n// Prevent concurrent card creation for the same conversation.\n// createAICard runs before acquireSessionLock (for immediate visual feedback),\n// but two inbound messages can race past each other's card-run registration.\n// This synchronous Set closes that window because JavaScript check-and-set here\n// is atomic from the caller's perspective.\nconst cardCreationInFlight = new Set<string>();\ntype ReplyMode = \"card\" | \"markdown\";\n\nfunction resolveQuotedContextAllowFrom(\n config: DingTalkConfig,\n groupId: string,\n): string[] | undefined {\n const groupConfig = resolveGroupConfig(config, groupId);\n return groupConfig?.groupAllowFrom ?? config.groupAllowFrom;\n}\n\nfunction resolveQuotedVisibilitySenderId(params: {\n quotedSenderId?: string;\n currentSenderId: string;\n currentSenderOriginalId: string;\n}): string | undefined {\n const quotedSenderId = (params.quotedSenderId || \"\").trim();\n if (!quotedSenderId) {\n return undefined;\n }\n if (quotedSenderId === params.currentSenderOriginalId) {\n return params.currentSenderId;\n }\n return quotedSenderId;\n}\n\nfunction filterQuotedRuntimeContext(params: {\n context: ReturnType<typeof resolveQuotedRuntimeContext>;\n config: DingTalkConfig;\n isDirect: boolean;\n groupId: string;\n quotedSenderId?: string;\n currentSenderId: string;\n currentSenderOriginalId: string;\n}): ReturnType<typeof resolveQuotedRuntimeContext> {\n const {\n context,\n config,\n isDirect,\n groupId,\n quotedSenderId,\n currentSenderId,\n currentSenderOriginalId,\n } = params;\n if (!context || isDirect) {\n return context;\n }\n\n const mode = config.contextVisibility || \"all\";\n if (mode === \"all\") {\n return context;\n }\n\n const allow = normalizeAllowFrom(resolveQuotedContextAllowFrom(config, groupId));\n const senderId = resolveQuotedVisibilitySenderId({\n quotedSenderId,\n currentSenderId,\n currentSenderOriginalId,\n });\n const senderAllowed =\n allow.hasEntries && !!senderId ? isSenderAllowed({ allow, senderId }) : false;\n\n if (senderAllowed) {\n return context;\n }\n if (mode === \"allowlist_quote\") {\n return {\n ...context,\n untrustedContext: undefined,\n };\n }\n return null;\n}\n\nfunction readSessionReasoningLevel(params: {\n storePath?: string;\n sessionKey: string;\n sessionUpdatedAt?: number;\n log?: Logger;\n}): string | undefined {\n if (!params.storePath || !params.sessionKey) {\n return undefined;\n }\n const cacheKey = `${params.storePath}:${params.sessionKey}`;\n const cached = sessionReasoningLevelCache.get(cacheKey);\n if (\n cached &&\n params.sessionUpdatedAt !== undefined &&\n cached.updatedAt === params.sessionUpdatedAt\n ) {\n return cached.reasoningLevel;\n }\n try {\n const raw = fs.readFileSync(params.storePath, \"utf8\");\n const parsed = JSON.parse(raw) as Record<string, { reasoningLevel?: unknown }>;\n const value = parsed?.[params.sessionKey]?.reasoningLevel;\n const reasoningLevel = typeof value === \"string\" ? value.trim().toLowerCase() : undefined;\n sessionReasoningLevelCache.set(cacheKey, {\n updatedAt: params.sessionUpdatedAt,\n reasoningLevel,\n });\n return reasoningLevel;\n } catch (err: unknown) {\n params.log?.debug?.(\n `[DingTalk][Session] Failed to read session reasoning level from ${params.storePath}: ${getErrorMessage(err)}`,\n );\n return undefined;\n }\n}\n\nfunction shouldDisableBlockStreamingForReplyMode(params: {\n replyMode: ReplyMode;\n reasoningLevel?: string;\n sessionKey: string;\n log?: Logger;\n}): boolean {\n if (params.replyMode === \"markdown\") {\n const shouldDisable = params.reasoningLevel === \"on\" || params.reasoningLevel === \"stream\";\n if (shouldDisable) {\n params.log?.debug?.(\n `[DingTalk][Markdown] Disable block streaming for reasoningLevel=${params.reasoningLevel} sessionKey=${params.sessionKey}`,\n );\n }\n return shouldDisable;\n }\n\n const shouldDisable = params.reasoningLevel !== \"on\";\n if (!shouldDisable) {\n params.log?.debug?.(\n `[DingTalk][Card] Enable block streaming for reasoningLevel=${params.reasoningLevel} sessionKey=${params.sessionKey}`,\n );\n }\n return shouldDisable;\n}\n\nfunction resolveLegacyCardStreamReasoningForInternalUse(params: {\n cfg: HandleDingTalkMessageParams[\"cfg\"];\n accountId: string;\n}): boolean | undefined {\n const dingtalk = (params.cfg?.channels?.dingtalk ?? null) as\n | (Record<string, unknown> & {\n cardStreamReasoning?: unknown;\n accounts?: Record<string, Record<string, unknown> | undefined>;\n })\n | null;\n if (!dingtalk) {\n return undefined;\n }\n const accountConfig = params.accountId ? dingtalk.accounts?.[params.accountId] : undefined;\n if (typeof accountConfig?.cardStreamReasoning === \"boolean\") {\n return accountConfig.cardStreamReasoning;\n }\n if (typeof dingtalk.cardStreamReasoning === \"boolean\") {\n return dingtalk.cardStreamReasoning;\n }\n return undefined;\n}\n\nfunction resolvePinnedMainDmOwner(params: {\n dmScope?: string;\n allowFrom?: string[];\n}): string | null {\n if ((params.dmScope ?? \"main\") !== \"main\") {\n return null;\n }\n const allow = normalizeAllowFrom(params.allowFrom);\n if (allow.hasWildcard) {\n return null;\n }\n return allow.entries.length === 1 ? allow.entries[0] : null;\n}\n\nfunction ttlDaysToMs(ttlDays: number | undefined): number | undefined {\n if (typeof ttlDays !== \"number\" || !Number.isFinite(ttlDays) || ttlDays <= 0) {\n return undefined;\n }\n return ttlDays * 24 * 60 * 60 * 1000;\n}\n\nasync function waitForDynamicAckDispose(params: {\n dispose: () => Promise<void>;\n log?: { debug?: (message: string) => void; warn?: (message: string) => void };\n sessionKey: string;\n}): Promise<void> {\n let timedOut = false;\n let timeoutHandle: ReturnType<typeof setTimeout> | undefined;\n const disposePromise = params.dispose().catch((err: unknown) => {\n params.log?.warn?.(\n `[DingTalk] Dynamic ack reaction cleanup failed for session ${params.sessionKey}: ${getErrorMessage(err)}`,\n );\n });\n\n try {\n await Promise.race([\n disposePromise,\n new Promise<void>((resolve) => {\n timeoutHandle = setTimeout(() => {\n timedOut = true;\n resolve();\n }, MAX_DYNAMIC_ACK_DISPOSE_WAIT_MS);\n }),\n ]);\n } finally {\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n }\n\n if (timedOut) {\n params.log?.debug?.(\n `[DingTalk] Dynamic ack reaction cleanup timed out after ${MAX_DYNAMIC_ACK_DISPOSE_WAIT_MS}ms; releasing session lock for ${params.sessionKey}`,\n );\n }\n}\n\nexport function resetProactivePermissionHintStateForTest(): void {\n proactiveHintLastSentAt.clear();\n clearProactiveRiskObservationsForTest();\n}\n\nfunction shouldSendProactivePermissionHint(params: {\n isDirect: boolean;\n accountId: string;\n senderId: string;\n senderOriginalId?: string;\n senderStaffId?: string;\n config: DingTalkConfig;\n nowMs: number;\n}): boolean {\n if (!params.isDirect) {\n return false;\n }\n\n const hintConfig = params.config.proactivePermissionHint;\n if (hintConfig?.enabled === false) {\n return false;\n }\n\n const targetId = (params.senderId || \"\").trim();\n if (!targetId) {\n return false;\n }\n\n const riskTargets = [params.senderId, params.senderOriginalId, params.senderStaffId]\n .map((id) => (id || \"\").trim())\n .filter((id, index, arr) => Boolean(id) && arr.indexOf(id) === index);\n if (riskTargets.length === 0) {\n return false;\n }\n\n const riskObservation = getProactiveRiskObservationForAny(\n params.accountId,\n riskTargets,\n params.nowMs,\n );\n if (!riskObservation || riskObservation.source !== \"proactive-api\") {\n return false;\n }\n\n const cooldownHours =\n hintConfig?.cooldownHours && hintConfig.cooldownHours > 0\n ? hintConfig.cooldownHours\n : DEFAULT_PROACTIVE_HINT_COOLDOWN_HOURS;\n const cooldownMs = cooldownHours * 60 * 60 * 1000;\n const key = `${params.accountId}:${targetId}`;\n const lastSentAt = proactiveHintLastSentAt.get(key) || 0;\n if (params.nowMs - lastSentAt < cooldownMs) {\n return false;\n }\n\n proactiveHintLastSentAt.set(key, params.nowMs);\n return true;\n}\n\nfunction sanitizeGroupPromptName(value?: string): string {\n return (value || \"\")\n .replace(/[\\r\\n,=]/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\nfunction buildGroupTurnContextPrompt(params: {\n conversationId: string;\n senderDingtalkId: string;\n senderName?: string;\n}): string {\n const sanitizedSenderName = sanitizeGroupPromptName(params.senderName) || \"Unknown\";\n return [\n \"Current DingTalk group turn context:\",\n `- conversationId: ${params.conversationId}`,\n `- senderDingtalkId: ${params.senderDingtalkId}`,\n `- senderName: ${sanitizedSenderName}`,\n \"Treat senderDingtalkId and senderName as the authoritative sender for this turn. Do not guess the current sender from GroupMembers.\",\n ].join(\"\\n\");\n}\n\ntype ReplyStreamPayload = {\n text?: string;\n isReasoning?: boolean;\n mediaUrl?: string;\n mediaUrls?: string[];\n};\n\ntype ReplyChunkInfo = {\n kind?: string;\n};\n\nconst INBOUND_MEDIA_DOWNLOAD_TIMEOUT_MS = 15_000;\nconst DINGTALK_API_HOST = \"api.dingtalk.com\";\n\n/**\n * Download DingTalk media file via runtime media service (sandbox-compatible).\n * Files are stored in the global media inbound directory.\n */\nexport async function downloadMedia(\n config: DingTalkConfig,\n downloadCode: string,\n log?: any,\n originalFilename?: string,\n): Promise<MediaFile | null> {\n const rt = getDingTalkRuntime();\n let downloadUrl: string | undefined;\n let requestStage = \"auth\";\n let requestHost = DINGTALK_API_HOST;\n const formatAxiosErrorData = (value: unknown): string | undefined => {\n if (value === null || value === undefined) {\n return undefined;\n }\n if (Buffer.isBuffer(value)) {\n return `<buffer ${value.length} bytes>`;\n }\n if (value instanceof ArrayBuffer) {\n return `<arraybuffer ${value.byteLength} bytes>`;\n }\n if (typeof value === \"string\") {\n return value.length > 500 ? `${value.slice(0, 500)}\u2026` : value;\n }\n try {\n return JSON.stringify(maskSensitiveData(value));\n } catch {\n return `[unstringifiable ${typeof value}]`;\n }\n };\n\n if (!downloadCode) {\n log?.error?.(\"[DingTalk] downloadMedia requires downloadCode to be provided.\");\n return null;\n }\n const robotCode = resolveRobotCode(config);\n if (!robotCode) {\n if (log?.error) {\n log.error(\"[DingTalk] downloadMedia requires clientId to be configured.\");\n }\n return null;\n }\n try {\n requestStage = \"auth\";\n requestHost = DINGTALK_API_HOST;\n const token = await getAccessToken(config, log);\n requestStage = \"exchange\";\n requestHost = DINGTALK_API_HOST;\n const response = await axios.post(\n \"https://api.dingtalk.com/v1.0/robot/messageFiles/download\",\n { downloadCode, robotCode },\n { headers: { \"x-acs-dingtalk-access-token\": token } },\n );\n const payload = response.data as Record<string, any>;\n downloadUrl = payload?.downloadUrl ?? payload?.data?.downloadUrl;\n if (!downloadUrl) {\n const payloadDetail = formatAxiosErrorData(payload);\n log?.error?.(\n `[DingTalk] downloadMedia missing downloadUrl. payload=${payloadDetail ?? \"unknown\"}`,\n );\n return null;\n }\n requestStage = \"download\";\n requestHost = (() => {\n try {\n return new URL(downloadUrl).host || \"unknown\";\n } catch {\n return \"unknown\";\n }\n })();\n const mediaResponse = await axios.get(downloadUrl, {\n responseType: \"arraybuffer\",\n timeout: INBOUND_MEDIA_DOWNLOAD_TIMEOUT_MS,\n });\n const contentType = mediaResponse.headers[\"content-type\"] || \"application/octet-stream\";\n const buffer = Buffer.from(mediaResponse.data as ArrayBuffer);\n\n const maxBytes =\n config.mediaMaxMb && config.mediaMaxMb > 0 ? config.mediaMaxMb * 1024 * 1024 : undefined;\n const saved = await rt.channel.media.saveMediaBuffer(\n buffer,\n contentType,\n \"inbound\",\n maxBytes,\n originalFilename,\n );\n log?.debug?.(`[DingTalk] Media saved: ${saved.path}`);\n return { path: saved.path, mimeType: saved.contentType ?? contentType };\n } catch (err: any) {\n if (log?.error) {\n if (axios.isAxiosError(err)) {\n const status = err.response?.status;\n const statusText = err.response?.statusText;\n const dataDetail = formatAxiosErrorData(err.response?.data);\n const code = err.code ? ` code=${err.code}` : \"\";\n const statusLabel = status ? ` status=${status}${statusText ? ` ${statusText}` : \"\"}` : \"\";\n log.error(\n `[DingTalk] Failed to download media: stage=${requestStage} host=${requestHost}${statusLabel}${code} message=${err.message}`,\n );\n if (err.response?.data !== undefined) {\n log.error(formatDingTalkErrorPayloadLog(\"inbound.downloadMedia\", err.response.data));\n } else if (dataDetail) {\n log.error(`[DingTalk] downloadMedia response data: ${dataDetail}`);\n }\n } else {\n log.error(\n `[DingTalk] Failed to download media: stage=${requestStage} host=${requestHost} message=${err.message}`,\n );\n }\n }\n return null;\n }\n}\n\nexport async function handleDingTalkMessage(params: HandleDingTalkMessageParams): Promise<void> {\n const {\n cfg,\n accountId,\n data,\n sessionWebhook,\n log,\n dingtalkConfig,\n subAgentOptions,\n preDownloadedMedia,\n } = params;\n const rt = getDingTalkRuntime();\n\n // Save logger globally so shared services can log consistently without threading log everywhere.\n setCurrentLogger(log, accountId);\n\n log?.debug?.(\"[DingTalk] Full Inbound Data: \" + JSON.stringify(maskSensitiveData(data)));\n\n // 1) Ignore self messages from bot.\n if (data.senderId === data.chatbotUserId || data.senderStaffId === data.chatbotUserId) {\n log?.debug?.(\"[DingTalk] Ignoring robot self-message\");\n return;\n }\n\n // Shallow copy: only .text is reassigned below; nested arrays (atMentions, mediaTypes) are read-only downstream.\n const extractedContent = { ...extractMessageContent(data) };\n if (!extractedContent.text) {\n return;\n }\n\n // Preserve raw inbound text before any rewriting (e.g., sub-agent context hint)\n // for use in card quoteContent which should show the user's original message.\n const rawInboundText = extractedContent.text.trim();\n\n // Add context hint for sub-agent mode, stripping quoted prefix to avoid protocol noise in agent context.\n if (subAgentOptions) {\n const cleanText = extractedContent.text.replace(/^\\[\u5F15\u7528[^\\]]*\\]\\s*/, \"\");\n const contextHint = `[\u4F60\u88AB @ \u4E3A\"${subAgentOptions.matchedName}\"]\\n\\n`;\n extractedContent.text = contextHint + cleanText;\n }\n\n const isDirect = data.conversationType === \"1\";\n const isGroup = !isDirect;\n const senderOriginalId = (data.senderId || \"\").trim();\n const senderStaffId = (data.senderStaffId || \"\").trim();\n const senderId = senderStaffId || senderOriginalId;\n const senderName = data.senderNick || \"Unknown\";\n const groupId = data.conversationId;\n const groupName = data.conversationTitle || \"Group\";\n\n // Register original peer IDs to preserve case-sensitive DingTalk conversation IDs.\n if (groupId) {\n registerPeerId(groupId);\n }\n\n if (\n shouldSendProactivePermissionHint({\n isDirect,\n accountId,\n senderId,\n senderOriginalId,\n senderStaffId,\n config: dingtalkConfig,\n nowMs: Date.now(),\n })\n ) {\n try {\n await sendBySession(\n dingtalkConfig,\n sessionWebhook,\n \"\u26A0\uFE0F \u4E3B\u52A8\u63A8\u9001\u53EF\u80FD\u5931\u8D25\\n\\n\u68C0\u6D4B\u5230\u8BE5\u7528\u6237\u6700\u8FD1\u4E00\u6B21\u4E3B\u52A8\u53D1\u9001\u8C03\u7528\u8FD4\u56DE\u4E86\u6743\u9650\u6216\u76EE\u6807\u4E0D\u53EF\u8FBE\u9519\u8BEF\u3002\u5F53\u524D\u4F1A\u8BDD\u56DE\u590D\u4ECD\u53EF\u6B63\u5E38\u4F7F\u7528\uFF0C\u4F46\u5B9A\u65F6/\u4E3B\u52A8\u53D1\u9001\u53EF\u80FD\u5931\u8D25\u3002\\n\\n\u5EFA\u8BAE\uFF1A\\n1) \u5728\u9489\u9489\u5F00\u653E\u5E73\u53F0\u786E\u8BA4\u5E94\u7528\u5DF2\u7533\u8BF7\u5E76\u83B7\u5F97\u4E3B\u52A8\u53D1\u9001\u76F8\u5173\u6743\u9650\\n2) \u786E\u8BA4\u76EE\u6807\u7528\u6237\u5C5E\u4E8E\u5F53\u524D\u4F01\u4E1A\u5E76\u5728\u5E94\u7528\u53EF\u89C1\u8303\u56F4\u5185\\n3) \u4F7F\u7528\u76F8\u540C\u8D26\u53F7\u8FDB\u884C\u4E00\u6B21\u4E3B\u52A8\u53D1\u9001\u9A8C\u8BC1\u5E76\u68C0\u67E5\u9519\u8BEF\u7801\u8BE6\u60C5\",\n { log },\n );\n } catch (err: any) {\n log?.debug?.(`[DingTalk] Failed to send proactive permission hint: ${err.message}`);\n if (err?.response?.data !== undefined) {\n log?.debug?.(\n formatDingTalkErrorPayloadLog(\"inbound.proactivePermissionHint\", err.response.data),\n );\n }\n }\n }\n if (senderId) {\n registerPeerId(senderId);\n }\n\n // 2) Authorization guard (DM/group policy).\n let commandAuthorized = true;\n if (isDirect) {\n const dmPolicy = dingtalkConfig.dmPolicy || \"open\";\n const allowFrom = dingtalkConfig.allowFrom || [];\n\n if (dmPolicy === \"allowlist\") {\n const normalizedAllowFrom = normalizeAllowFrom(allowFrom);\n const isAllowed = isSenderAllowed({ allow: normalizedAllowFrom, senderId });\n\n if (!isAllowed) {\n log?.debug?.(\n `[DingTalk] DM blocked: senderId=${senderId} not in allowlist (dmPolicy=allowlist)`,\n );\n try {\n await sendBySession(\n dingtalkConfig,\n sessionWebhook,\n `\u26D4 \u8BBF\u95EE\u53D7\u9650\\n\\n\u60A8\u7684\u7528\u6237ID\uFF1A\\`${senderId}\\`\\n\\n\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u5C06\u6B64ID\u6DFB\u52A0\u5230\u5141\u8BB8\u5217\u8868\u4E2D\u3002`,\n { log },\n );\n } catch (err: any) {\n log?.debug?.(`[DingTalk] Failed to send access denied message: ${err.message}`);\n if (err?.response?.data !== undefined) {\n log?.debug?.(\n formatDingTalkErrorPayloadLog(\"inbound.accessDeniedReply\", err.response.data),\n );\n }\n }\n\n return;\n }\n\n log?.debug?.(`[DingTalk] DM authorized: senderId=${senderId} in allowlist`);\n } else if (dmPolicy === \"pairing\") {\n // SDK pairing flow performs actual authorization checks.\n commandAuthorized = true;\n } else {\n commandAuthorized = true;\n }\n } else {\n const groupAccess = resolveGroupAccess({\n groupPolicy: dingtalkConfig.groupPolicy || \"open\",\n groupId,\n senderId,\n groups: dingtalkConfig.groups,\n groupAllowFrom: dingtalkConfig.groupAllowFrom,\n allowFrom: dingtalkConfig.allowFrom,\n });\n\n if (groupAccess.legacyFallback) {\n log?.info?.(\n `[DingTalk] DEPRECATED: groupPolicy=allowlist is using \"allowFrom\" for group access control. ` +\n `Please migrate to \"groups\" (group ID allowlist) or \"groupAllowFrom\" (sender allowlist).`,\n );\n }\n\n if (!groupAccess.allowed) {\n if (groupAccess.reason === \"disabled\") {\n log?.debug?.(\n `[DingTalk] Group disabled: all group messages dropped (groupPolicy=disabled)`,\n );\n return;\n }\n\n const denyMessage =\n groupAccess.reason === \"sender_not_allowed\"\n ? `\u26D4 \u8BBF\u95EE\u53D7\u9650\\n\\n\u60A8\u7684\u7528\u6237ID\uFF1A\\`${senderId}\\`\\n\\n\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u5C06\u6B64ID\u6DFB\u52A0\u5230\u7FA4\u804A\u5141\u8BB8\u5217\u8868\u4E2D\u3002`\n : `\u26D4 \u8BBF\u95EE\u53D7\u9650\\n\\n\u60A8\u7684\u7FA4\u804AID\uFF1A\\`${groupId}\\`\\n\\n\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u5C06\u6B64ID\u6DFB\u52A0\u5230\u5141\u8BB8\u5217\u8868\u4E2D\u3002`;\n\n log?.debug?.(\n `[DingTalk] Group blocked: conversationId=${groupId} senderId=${senderId} reason=${groupAccess.reason}`,\n );\n\n try {\n await sendBySession(dingtalkConfig, sessionWebhook, denyMessage, {\n log,\n atUserId: senderId,\n });\n } catch (err: any) {\n log?.debug?.(`[DingTalk] Failed to send group access denied message: ${err.message}`);\n if (err?.response?.data !== undefined) {\n log?.debug?.(\n formatDingTalkErrorPayloadLog(\"inbound.groupAccessDeniedReply\", err.response.data),\n );\n }\n }\n\n return;\n }\n\n log?.debug?.(`[DingTalk] Group authorized: conversationId=${groupId} senderId=${senderId}`);\n }\n\n // Calculate account store path and session peer (for session alias feature)\n const accountStorePath = rt.channel.session.resolveStorePath(cfg.session?.store, {\n agentId: accountId,\n });\n try {\n if (!isDirect && groupId) {\n upsertObservedGroupTarget({\n storePath: accountStorePath,\n accountId,\n conversationId: groupId,\n title: groupName,\n seenAt: data.createAt,\n });\n }\n if (senderId || senderOriginalId) {\n upsertObservedUserTarget({\n storePath: accountStorePath,\n accountId,\n senderId: senderOriginalId || senderId,\n staffId: senderStaffId || undefined,\n displayName: senderName,\n conversationId: groupId,\n seenAt: data.createAt,\n });\n }\n } catch (err) {\n log?.warn?.(\n `[DingTalk] Target directory observe failed: accountId=${accountId} groupId=${groupId || \"-\"} senderId=${senderOriginalId || senderId || \"-\"} storePath=${accountStorePath || \"-\"} error=${String(err)}`,\n );\n }\n const currentSessionSourceKind = isDirect ? \"direct\" : \"group\";\n const currentSessionSourceId = isDirect ? senderId : groupId;\n const peerIdOverride = getSessionPeerOverride({\n storePath: accountStorePath,\n accountId,\n sourceKind: currentSessionSourceKind,\n sourceId: currentSessionSourceId,\n });\n const sessionPeer = resolveDingTalkSessionPeer({\n isDirect,\n senderId,\n conversationId: groupId,\n peerIdOverride,\n config: dingtalkConfig,\n });\n\n const route = subAgentOptions\n ? {\n agentId: subAgentOptions.agentId,\n sessionKey: buildAgentSessionKey({\n rt,\n cfg,\n accountId,\n agentId: subAgentOptions.agentId,\n peerKind: sessionPeer.kind,\n peerId: sessionPeer.peerId,\n }),\n mainSessionKey: \"\",\n }\n : rt.channel.routing.resolveAgentRoute({\n cfg,\n channel: \"dingtalk\",\n accountId,\n peer: { kind: sessionPeer.kind, id: sessionPeer.peerId },\n });\n\n // @Sub-Agent routing: resolve @mentions to agents (skip in recursive sub-agent calls)\n if (!subAgentOptions) {\n const subAgentRoute = await resolveSubAgentRoute({\n extractedContent,\n cfg,\n isGroup,\n dingtalkConfig,\n sessionWebhook,\n senderId,\n log,\n });\n if (subAgentRoute) {\n await dispatchSubAgents({\n ...subAgentRoute,\n cfg,\n accountId,\n data,\n dingtalkConfig,\n sessionWebhook,\n extractedContent,\n handleMessage: handleDingTalkMessage,\n downloadMedia,\n log,\n });\n return;\n }\n }\n\n // Route resolved before media download for session context and routing metadata.\n const storePath = rt.channel.session.resolveStorePath(cfg.session?.store, {\n agentId: route.agentId,\n });\n\n const to = isDirect ? senderId : groupId;\n const commandHandled = await handleInboundCommandDispatch({\n cfg,\n accountId,\n dingtalkConfig,\n senderId,\n isDirect,\n extractedText: extractedContent.text,\n messageType: extractedContent.messageType,\n data: {\n conversationId: data.conversationId,\n senderId: data.senderId,\n senderStaffId: data.senderStaffId,\n },\n accountStorePath,\n currentSessionSourceKind,\n currentSessionSourceId,\n peerIdOverride,\n sessionPeer,\n sendReply: async (text: string) => {\n await sendBySession(dingtalkConfig, sessionWebhook, text, { log });\n },\n clearSessionPeerOverride,\n setSessionPeerOverride,\n });\n if (commandHandled) {\n return;\n }\n\n const journalTTLDays = dingtalkConfig.journalTTLDays ?? DEFAULT_MESSAGE_CONTEXT_TTL_DAYS;\n const quotedRef = buildInboundQuotedRef(data, extractedContent);\n const replyQuotedRef = createReplyQuotedRef(data.msgId);\n const content = extractedContent;\n const isBtwBypass = isBtwRequestText(stripLeadingMentions(content.text).trim());\n const taskInfoConversationId = groupId || to;\n const sessionTaskState = initSessionState(accountId, taskInfoConversationId);\n const initialStatusLine =\n renderStatusLine(\n {\n model: sessionTaskState.model,\n effort: sessionTaskState.effort,\n agent: getAgentDisplayName({\n subAgentOptions,\n agentId: route.agentId,\n agentsList: cfg.agents?.list,\n }),\n },\n dingtalkConfig,\n ) || undefined;\n\n // 3) Select response mode (card vs markdown).\n // Card creation runs BEFORE media download so the user sees immediate visual\n // feedback while large files are still being downloaded.\n // /btw is gated out here (`!isBtwBypass`) because it must never create a card \u2014\n // it has its own bypass dispatch later that returns before reaching the main\n // run. Abort (/stop) is intentionally NOT gated: in card mode the existing\n // abort branch finalizes the card with the abort confirmation text instead of\n // sending a separate plain-text message.\n let useCardMode = dingtalkConfig.messageType === \"card\";\n let currentAICard: import(\"./types\").AICardInstance | undefined;\n\n let cardFlightKey: string | undefined;\n if (useCardMode && !isBtwBypass) {\n const key = `${accountId}:${to}`;\n if (cardCreationInFlight.has(key)) {\n useCardMode = false;\n log?.debug?.(\n `[DingTalk][AICard] Skip card creation - active card already exists for account=${accountId} conversation=${to}`,\n );\n } else {\n cardCreationInFlight.add(key);\n cardFlightKey = key;\n }\n }\n\n if (useCardMode && !isBtwBypass) {\n try {\n log?.debug?.(\n `[DingTalk][AICard] conversationType=${data.conversationType}, conversationId=${to}`,\n );\n // quoteContent always shows the inbound message text so the user can\n // identify which of their messages this card is replying to.\n // Use rawInboundText ( preserved before sub-agent rewriting) to avoid\n // showing internal routing context like \"[\u4F60\u88AB @ \u4E3A...]\" in the card UI.\n const inboundQuoteText = rawInboundText.slice(0, 200);\n const aiCard = await createAICard(dingtalkConfig, to, log, {\n accountId,\n storePath: accountStorePath,\n contextConversationId: groupId,\n quoteContent: inboundQuoteText,\n statusLine: initialStatusLine,\n });\n if (aiCard) {\n currentAICard = aiCard;\n if (aiCard.outTrackId) {\n registerCardRun(aiCard.outTrackId, {\n accountId,\n sessionKey: route.sessionKey,\n agentId: route.agentId,\n ownerUserId: senderId,\n card: aiCard,\n });\n }\n } else {\n useCardMode = false;\n if (cardFlightKey) {\n cardCreationInFlight.delete(cardFlightKey);\n cardFlightKey = undefined;\n }\n log?.warn?.(\n \"[DingTalk] Failed to create AI card (returned null), fallback to text/markdown.\",\n );\n }\n } catch (err: any) {\n useCardMode = false;\n if (cardFlightKey) {\n cardCreationInFlight.delete(cardFlightKey);\n cardFlightKey = undefined;\n }\n log?.warn?.(\n `[DingTalk] Failed to create AI card: ${err.message}, fallback to text/markdown.`,\n );\n }\n }\n // Outer try/finally guarantees cardFlightKey cleanup even when the handler\n // returns or throws between card creation and session-lock release.\n try {\n const hasLegacyQuoteContent =\n typeof data.content?.quoteContent === \"string\" && data.content.quoteContent.trim().length > 0;\n\n if (hasLegacyQuoteContent && !quotedRef) {\n log?.debug?.(\n `[DingTalk] Legacy quoteContent present without resolvable quotedRef: ` +\n `conversationType=${data.conversationType} conversationId=${data.conversationId} ` +\n `msgId=${data.msgId} originalMsgId=${data.originalMsgId || \"(none)\"}`,\n );\n }\n if (quotedRef) {\n log?.debug?.(\n `[DingTalk][QuotedRef] Built inbound quotedRef msgId=${data.msgId} scope=${groupId} ` +\n `quotedRef=${JSON.stringify(quotedRef)}`,\n );\n } else if (\n data.text?.isReplyMsg ||\n data.originalMsgId ||\n data.originalProcessQueryKey ||\n content.quoted\n ) {\n log?.debug?.(\n `[DingTalk][QuotedRef] Reply metadata present without resolvable quotedRef ` +\n `msgId=${data.msgId} scope=${groupId} originalMsgId=${data.originalMsgId || \"(none)\"} ` +\n `originalProcessQueryKey=${data.originalProcessQueryKey || \"(none)\"}`,\n );\n }\n\n try {\n upsertInboundMessageContext({\n storePath: accountStorePath,\n accountId,\n conversationId: groupId,\n msgId: data.msgId,\n messageType: content.messageType,\n text: content.text,\n quotedRef,\n senderId,\n senderName,\n createdAt: data.createAt,\n ttlMs: ttlDaysToMs(journalTTLDays),\n ttlReferenceMs: data.createAt,\n cleanupCreatedAtTtlDays: journalTTLDays,\n topic: null,\n });\n } catch (err) {\n log?.warn?.(`[DingTalk] Message context inbound append failed: ${String(err)}`);\n }\n\n const robotCode = resolveRobotCode(dingtalkConfig);\n let mediaPath: string | undefined;\n let mediaType: string | undefined;\n const mediaPaths: string[] = [];\n const mediaTypes: string[] = [];\n let attachmentContextMsgId = data.msgId;\n let attachmentContextCreatedAt = data.createAt;\n let attachmentContextMessageType = content.messageType;\n let attachmentContextFileName = data.content?.fileName;\n\n // Use pre-downloaded media if available (from sub-agent outer call)\n if (preDownloadedMedia?.mediaPath) {\n mediaPath = preDownloadedMedia.mediaPath;\n mediaType = preDownloadedMedia.mediaType;\n if (preDownloadedMedia.mediaPaths?.length) {\n mediaPaths.push(...preDownloadedMedia.mediaPaths);\n for (let i = 0; i < preDownloadedMedia.mediaPaths.length; i++) {\n mediaTypes.push(\n preDownloadedMedia.mediaTypes?.[i] || preDownloadedMedia.mediaType || \"file\",\n );\n }\n } else {\n mediaPaths.push(mediaPath);\n mediaTypes.push(mediaType || \"file\");\n }\n } else if (robotCode) {\n // Download all media attachments (richText may carry multiple images).\n const downloadCodes =\n content.mediaPaths && content.mediaPaths.length > 0\n ? content.mediaPaths\n : content.mediaPath\n ? [content.mediaPath]\n : [];\n for (const downloadCode of downloadCodes) {\n const media = await downloadMedia(\n dingtalkConfig,\n downloadCode,\n log,\n attachmentContextFileName,\n );\n if (media) {\n if (!mediaPath) {\n mediaPath = media.path;\n mediaType = media.mimeType;\n }\n mediaPaths.push(media.path);\n mediaTypes.push(media.mimeType);\n }\n }\n }\n\n // Cache downloadCode(s) (+ spaceId/fileId) for quoted file lookups (DM + group).\n const allMediaDownloadCodes =\n content.mediaPaths && content.mediaPaths.length > 0\n ? content.mediaPaths\n : content.mediaPath\n ? [content.mediaPath]\n : [];\n if (allMediaDownloadCodes.length > 0 && data.msgId) {\n upsertInboundMessageContext({\n storePath: accountStorePath,\n accountId,\n conversationId: data.conversationId,\n msgId: data.msgId,\n createdAt: data.createAt,\n messageType: content.messageType,\n media: {\n downloadCode: allMediaDownloadCodes[0],\n downloadCodes: allMediaDownloadCodes.length > 1 ? allMediaDownloadCodes : undefined,\n spaceId: data.content?.spaceId,\n fileId: data.content?.fileId,\n },\n attachmentFileName: attachmentContextFileName,\n ttlMs: DEFAULT_MEDIA_CONTEXT_TTL_MS,\n topic: null,\n });\n }\n\n // User-sent DingTalk doc / Drive file card: cache msgId -> {spaceId,fileId}\n // during the original message turn, and try downloading immediately in DM.\n if (\n content.messageType === \"interactiveCardFile\" &&\n data.msgId &&\n content.docSpaceId &&\n content.docFileId\n ) {\n upsertInboundMessageContext({\n storePath: accountStorePath,\n accountId,\n conversationId: data.conversationId,\n msgId: data.msgId,\n createdAt: data.createAt,\n messageType: content.messageType,\n media: {\n spaceId: content.docSpaceId,\n fileId: content.docFileId,\n },\n attachmentFileName: attachmentContextFileName,\n ttlMs: DEFAULT_MEDIA_CONTEXT_TTL_MS,\n topic: null,\n });\n\n if (!mediaPath && isDirect && data.senderStaffId) {\n try {\n const unionId = await getUnionIdByStaffId(dingtalkConfig, data.senderStaffId, log);\n const docMedia = await downloadGroupFile(\n dingtalkConfig,\n content.docSpaceId,\n content.docFileId,\n unionId,\n log,\n attachmentContextFileName,\n );\n if (docMedia) {\n mediaPath = docMedia.path;\n mediaType = docMedia.mimeType;\n mediaPaths.push(docMedia.path);\n mediaTypes.push(docMedia.mimeType);\n }\n } catch (err: any) {\n log?.warn?.(`[DingTalk] Doc card download failed: ${err.message}`);\n }\n }\n }\n\n const quotedRecord = resolveQuotedRecord({\n storePath: accountStorePath,\n accountId,\n conversationId: data.conversationId,\n quotedRef,\n log,\n });\n const quotedRuntimeContext = filterQuotedRuntimeContext({\n context: resolveQuotedRuntimeContext({\n storePath: accountStorePath,\n accountId,\n conversationId: data.conversationId,\n quotedRef,\n firstRecord: quotedRecord,\n firstPreview:\n content.quoted?.previewText || content.quoted?.previewMessageType\n ? {\n text: content.quoted.previewText,\n messageType: content.quoted.previewMessageType,\n senderId: content.quoted.previewSenderId,\n }\n : undefined,\n log,\n }),\n config: dingtalkConfig,\n isDirect,\n groupId,\n quotedSenderId: quotedRecord?.senderId || content.quoted?.previewSenderId,\n currentSenderId: senderId,\n currentSenderOriginalId: senderOriginalId,\n });\n\n // Try downloading a quoted file from cached downloadCode/spaceId+fileId.\n const tryDownloadFromRecord = async (\n record: {\n msgId?: string;\n media?: {\n downloadCode?: string;\n spaceId?: string;\n fileId?: string;\n };\n } | null,\n originalFilename?: string,\n ): Promise<MediaFile | null> => {\n if (!record?.media) {\n return null;\n }\n let media: MediaFile | null = null;\n if (record.media.downloadCode) {\n media = await downloadMedia(\n dingtalkConfig,\n record.media.downloadCode,\n log,\n originalFilename,\n );\n if (media) {\n log?.debug?.(\n `[DingTalk][QuotedRef] Recovered quoted media from cached downloadCode ` +\n `recordMsgId=${record.msgId || \"(none)\"} scope=${data.conversationId}`,\n );\n }\n }\n if (!media && record.media.spaceId && record.media.fileId && data.senderStaffId) {\n try {\n const unionId = await getUnionIdByStaffId(dingtalkConfig, data.senderStaffId, log);\n media = await downloadGroupFile(\n dingtalkConfig,\n record.media.spaceId,\n record.media.fileId,\n unionId,\n log,\n originalFilename,\n );\n if (media) {\n log?.debug?.(\n `[DingTalk][QuotedRef] Recovered quoted media from cached spaceId/fileId ` +\n `recordMsgId=${record.msgId || \"(none)\"} scope=${data.conversationId}`,\n );\n }\n } catch (err: any) {\n log?.warn?.(`[DingTalk] spaceId+fileId fallback failed: ${err.message}`);\n }\n }\n return media;\n };\n\n // Quoted multi-image richText: recover all cached downloadCodes.\n // Placed before the single-image/ file/ doc-card paths so that the\n // !mediaPath guard prevents those paths from downloading only the first image.\n if (\n !mediaPath &&\n quotedRecord?.media?.downloadCodes &&\n quotedRecord.media.downloadCodes.length > 1\n ) {\n const recovered: MediaFile[] = [];\n for (const code of quotedRecord.media.downloadCodes) {\n const result = await downloadMedia(dingtalkConfig, code, log);\n if (result) {\n recovered.push(result);\n }\n }\n if (recovered.length > 0) {\n mediaPath = recovered[0].path;\n mediaType = recovered[0].mimeType;\n for (const m of recovered) {\n mediaPaths.push(m.path);\n mediaTypes.push(m.mimeType);\n }\n attachmentContextMsgId = quotedRecord.msgId || data.msgId;\n attachmentContextCreatedAt = quotedRecord.createdAt || data.createAt;\n attachmentContextMessageType = quotedRecord.messageType || \"richText\";\n log?.debug?.(\n `[DingTalk][QuotedRef] Recovered ${recovered.length} images from cached multi-image richText ` +\n `recordMsgId=${quotedRecord.msgId || \"(none)\"} scope=${data.conversationId}`,\n );\n }\n }\n\n // Quoted picture: download via existing downloadMedia.\n if (!mediaPath && content.quoted?.mediaDownloadCode && robotCode) {\n const quotedOriginalFilename = content.quoted.previewFileName;\n const media =\n (await tryDownloadFromRecord(quotedRecord, quotedOriginalFilename)) ||\n (await downloadMedia(\n dingtalkConfig,\n content.quoted.mediaDownloadCode,\n log,\n quotedOriginalFilename,\n ));\n if (media) {\n if (!quotedRecord) {\n log?.debug?.(\n `[DingTalk][QuotedRef] Recovered quoted image from inbound downloadCode fallback scope=${data.conversationId}`,\n );\n }\n mediaPath = media.path;\n mediaType = media.mimeType;\n mediaPaths.push(media.path);\n mediaTypes.push(media.mimeType);\n attachmentContextMsgId = quotedRecord?.msgId || content.quoted.msgId || data.msgId;\n attachmentContextCreatedAt = quotedRecord?.createdAt || data.createAt;\n attachmentContextMessageType =\n quotedRecord?.messageType || content.quoted.previewMessageType || \"picture\";\n attachmentContextFileName = content.quoted.previewFileName;\n } else {\n content.text = `[\u5F15\u7528\u4E86\u4E00\u5F20\u56FE\u7247\uFF0C\u4F46\u4E0B\u8F7D\u5931\u8D25]\\n\\n${content.text}`;\n }\n }\n\n // Quoted file/audio/video (file/audio/video msgType) or unknownMsgType:\n // Step 0 tries direct downloadCode; Steps 1-2 fall back to cache and group file API.\n if (!mediaPath && content.quoted?.isQuotedFile) {\n let fileResolved = false;\n\n // Step 0: Direct download via downloadCode from quoted payload (file/audio/video msgType).\n if (!fileResolved && content.quoted.fileDownloadCode && robotCode) {\n const media = await downloadMedia(\n dingtalkConfig,\n content.quoted.fileDownloadCode,\n log,\n content.quoted.previewFileName,\n );\n if (media) {\n mediaPath = media.path;\n mediaType = media.mimeType;\n mediaPaths.push(media.path);\n mediaTypes.push(media.mimeType);\n attachmentContextMsgId = content.quoted.msgId || data.msgId;\n attachmentContextCreatedAt = content.quoted.fileCreatedAt || data.createAt;\n attachmentContextMessageType = content.quoted.previewMessageType || \"file\";\n attachmentContextFileName = content.quoted.previewFileName;\n fileResolved = true;\n log?.debug?.(\n `[DingTalk][QuotedRef] Downloaded quoted file via direct downloadCode scope=${data.conversationId}`,\n );\n }\n }\n\n // Step 1: Prefer quotedRef-backed record lookup, then msgId-based cache.\n if (!fileResolved) {\n const cachedMedia = await tryDownloadFromRecord(\n quotedRecord,\n quotedRecord?.attachmentFileName || content.quoted.previewFileName,\n );\n if (cachedMedia) {\n mediaPath = cachedMedia.path;\n mediaType = cachedMedia.mimeType;\n mediaPaths.push(cachedMedia.path);\n mediaTypes.push(cachedMedia.mimeType);\n attachmentContextMsgId = quotedRecord?.msgId || content.quoted.msgId || data.msgId;\n attachmentContextCreatedAt =\n quotedRecord?.createdAt || content.quoted.fileCreatedAt || data.createAt;\n attachmentContextMessageType = quotedRecord?.messageType || \"file\";\n attachmentContextFileName =\n quotedRecord?.attachmentFileName || content.quoted.previewFileName;\n fileResolved = true;\n }\n }\n\n // Step 2 (group only): Cache miss \u2192 fall back to group file API time-based matching.\n if (!fileResolved && !isDirect) {\n const resolved = await resolveQuotedFile(\n dingtalkConfig,\n {\n openConversationId: data.conversationId,\n senderStaffId: data.senderStaffId,\n fileCreatedAt: content.quoted.fileCreatedAt,\n },\n log,\n );\n if (resolved) {\n mediaPath = resolved.media.path;\n mediaType = resolved.media.mimeType;\n mediaPaths.push(resolved.media.path);\n mediaTypes.push(resolved.media.mimeType);\n attachmentContextMsgId = content.quoted.msgId || data.msgId;\n attachmentContextCreatedAt = content.quoted.fileCreatedAt || data.createAt;\n attachmentContextMessageType = \"file\";\n attachmentContextFileName = resolved.name || content.quoted.previewFileName;\n fileResolved = true;\n log?.debug?.(\n `[DingTalk][QuotedRef] Recovered quoted file from group file fallback ` +\n `scope=${data.conversationId} quotedMsgId=${content.quoted.msgId || \"(none)\"}`,\n );\n if (content.quoted.msgId) {\n upsertInboundMessageContext({\n storePath: accountStorePath,\n accountId,\n conversationId: data.conversationId,\n msgId: content.quoted.msgId,\n createdAt: content.quoted.fileCreatedAt || Date.now(),\n messageType: \"file\",\n media: {\n spaceId: resolved.spaceId,\n fileId: resolved.fileId,\n },\n attachmentFileName: resolved.name,\n ttlMs: DEFAULT_MEDIA_CONTEXT_TTL_MS,\n topic: null,\n });\n }\n }\n }\n\n if (!fileResolved) {\n log?.warn?.(\n `[DingTalk] Quoted file unresolved: conversationType=${data.conversationType} conversationId=${data.conversationId} quotedMsgId=${content.quoted.msgId || \"(none)\"}`,\n );\n const hint = isDirect\n ? \"[\u5F15\u7528\u4E86\u4E00\u4E2A\u6587\u4EF6\uFF0C\u5185\u5BB9\u65E0\u6CD5\u81EA\u52A8\u83B7\u53D6\uFF0C\u8BF7\u76F4\u63A5\u53D1\u9001\u8BE5\u6587\u4EF6]\\n\\n\"\n : \"[\u5F15\u7528\u4E86\u4E00\u4E2A\u6587\u4EF6\uFF0C\u4F46\u65E0\u6CD5\u83B7\u53D6\u5185\u5BB9]\\n\\n\";\n content.text = `${hint}${content.text}`;\n }\n }\n\n // Quoted DingTalk doc / Drive file card:\n // 1) Prefer msgId-based cached metadata captured when the original doc card\n // message was seen.\n // 2) In group chats, if the bot never saw the original doc card message,\n // reuse the same group-file fallback chain as ordinary quoted files.\n if (!mediaPath && content.quoted?.isQuotedDocCard) {\n let docResolved = false;\n\n const cachedDocMedia = await tryDownloadFromRecord(\n quotedRecord,\n quotedRecord?.attachmentFileName || content.quoted?.previewFileName,\n );\n if (cachedDocMedia) {\n mediaPath = cachedDocMedia.path;\n mediaType = cachedDocMedia.mimeType;\n mediaPaths.push(cachedDocMedia.path);\n mediaTypes.push(cachedDocMedia.mimeType);\n attachmentContextMsgId = quotedRecord?.msgId || content.quoted.msgId || data.msgId;\n attachmentContextCreatedAt =\n quotedRecord?.createdAt || content.quoted.fileCreatedAt || data.createAt;\n attachmentContextMessageType =\n quotedRecord?.messageType || content.quoted.previewMessageType || \"interactiveCardFile\";\n attachmentContextFileName =\n quotedRecord?.attachmentFileName || content.quoted.previewFileName;\n docResolved = true;\n }\n\n if (!docResolved && !isDirect && content.quoted.fileCreatedAt) {\n const resolved = await resolveQuotedFile(\n dingtalkConfig,\n {\n openConversationId: data.conversationId,\n senderStaffId: data.senderStaffId,\n fileCreatedAt: content.quoted.fileCreatedAt,\n },\n log,\n );\n if (resolved) {\n mediaPath = resolved.media.path;\n mediaType = resolved.media.mimeType;\n mediaPaths.push(resolved.media.path);\n mediaTypes.push(resolved.media.mimeType);\n attachmentContextMsgId = content.quoted.msgId || data.msgId;\n attachmentContextCreatedAt = content.quoted.fileCreatedAt || data.createAt;\n attachmentContextMessageType = \"interactiveCardFile\";\n attachmentContextFileName = resolved.name || content.quoted.previewFileName;\n docResolved = true;\n log?.debug?.(\n `[DingTalk][QuotedRef] Recovered quoted doc card from group file fallback ` +\n `scope=${data.conversationId} quotedMsgId=${content.quoted.msgId || \"(none)\"}`,\n );\n if (content.quoted.msgId) {\n upsertInboundMessageContext({\n storePath: accountStorePath,\n accountId,\n conversationId: data.conversationId,\n msgId: content.quoted.msgId,\n createdAt: content.quoted.fileCreatedAt || Date.now(),\n messageType: \"interactiveCardFile\",\n media: {\n spaceId: resolved.spaceId,\n fileId: resolved.fileId,\n },\n attachmentFileName: resolved.name,\n ttlMs: DEFAULT_MEDIA_CONTEXT_TTL_MS,\n topic: null,\n });\n }\n }\n }\n\n if (!docResolved) {\n log?.warn?.(\n `[DingTalk] Quoted doc card unresolved: conversationType=${data.conversationType} conversationId=${data.conversationId} quotedMsgId=${content.quoted.msgId || \"(none)\"}`,\n );\n const hint = isDirect\n ? \"[\u5F15\u7528\u4E86\u9489\u9489\u6587\u6863\uFF0C\u5185\u5BB9\u65E0\u6CD5\u81EA\u52A8\u83B7\u53D6\uFF0C\u8BF7\u76F4\u63A5\u53D1\u9001\u8BE5\u6587\u6863]\\n\\n\"\n : \"[\u5F15\u7528\u4E86\u9489\u9489\u6587\u6863\uFF0C\u4F46\u65E0\u6CD5\u83B7\u53D6\u5185\u5BB9]\\n\\n\";\n content.text = `${hint}${content.text}`;\n }\n }\n\n let attachmentExtractedText: string | undefined;\n if (mediaPath) {\n try {\n const extracted = await extractAttachmentText({\n path: mediaPath,\n mimeType: mediaType,\n fileName: attachmentContextFileName || data.content?.fileName,\n });\n if (extracted?.text) {\n upsertInboundMessageContext({\n storePath: accountStorePath,\n accountId,\n conversationId: data.conversationId,\n msgId: attachmentContextMsgId,\n createdAt: attachmentContextCreatedAt,\n messageType: attachmentContextMessageType,\n attachmentText: extracted.text,\n attachmentTextSource: extracted.sourceType,\n attachmentTextTruncated: extracted.truncated,\n attachmentFileName: attachmentContextFileName,\n ttlMs: ttlDaysToMs(journalTTLDays),\n topic: null,\n });\n attachmentExtractedText = `${ATTACHMENT_TEXT_PREFIX}\\n${extracted.text}`;\n }\n } catch (err: any) {\n log?.warn?.(`[DingTalk] Failed to extract attachment text: ${err.message}`);\n }\n }\n\n const inboundBody = content.text;\n const inboundText = attachmentExtractedText\n ? `${inboundBody.trimEnd()}\\n\\n${attachmentExtractedText}`\n : inboundBody;\n const learningEnabled = isLearningEnabled(dingtalkConfig);\n const learningContextBlock = buildLearningContextBlock({\n enabled: learningEnabled,\n storePath: accountStorePath,\n accountId,\n targetId: data.conversationId,\n content,\n });\n const envelopeOptions = rt.channel.reply.resolveEnvelopeFormatOptions(cfg);\n const previousTimestamp = rt.channel.session.readSessionUpdatedAt({\n storePath,\n sessionKey: route.sessionKey,\n });\n\n const groupConfig = !isDirect ? resolveGroupConfig(dingtalkConfig, groupId) : undefined;\n // GroupSystemPrompt is injected every turn (not only first-turn intro).\n const groupSystemPromptParts = !isDirect\n ? [\n buildGroupTurnContextPrompt({\n conversationId: groupId,\n senderDingtalkId: senderId,\n senderName,\n }),\n groupConfig?.systemPrompt?.trim(),\n ]\n : [];\n const extraSystemPrompt =\n [...groupSystemPromptParts, learningContextBlock].filter(Boolean).join(\"\\n\\n\") || undefined;\n\n if (!isDirect) {\n noteGroupMember(storePath, groupId, senderId, senderName);\n }\n const groupMembers = !isDirect ? formatGroupMembers(storePath, groupId) : undefined;\n\n const fromLabel = isDirect ? `${senderName} (${senderId})` : `${groupName} - ${senderName}`;\n const body = rt.channel.reply.formatInboundEnvelope({\n channel: \"DingTalk\",\n from: fromLabel,\n timestamp: data.createAt,\n body: inboundText,\n chatType: isDirect ? \"direct\" : \"group\",\n sender: { name: senderName, id: senderId },\n previousTimestamp,\n envelope: envelopeOptions,\n });\n\n const ctx = rt.channel.reply.finalizeInboundContext({\n Body: body,\n RawBody: inboundText,\n CommandBody: inboundText,\n QuotedRef: quotedRef,\n QuotedRefJson: quotedRef ? JSON.stringify(quotedRef) : undefined,\n ReplyToId: quotedRuntimeContext?.replyToId,\n ReplyToBody: quotedRuntimeContext?.replyToBody,\n ReplyToSender: quotedRuntimeContext?.replyToSender,\n ReplyToIsQuote: quotedRuntimeContext?.replyToIsQuote,\n UntrustedContext: quotedRuntimeContext?.untrustedContext\n ? [quotedRuntimeContext.untrustedContext]\n : undefined,\n From: to,\n To: to,\n SessionKey: route.sessionKey,\n AccountId: accountId,\n ChatType: isDirect ? \"direct\" : \"group\",\n ConversationLabel: fromLabel,\n GroupSubject: isDirect ? undefined : groupName,\n SenderName: senderName,\n SenderId: senderId,\n Provider: \"dingtalk\",\n Surface: \"dingtalk\",\n MessageSid: data.msgId,\n Timestamp: data.createAt,\n MediaPath: mediaPath,\n MediaType: mediaType,\n MediaUrl: mediaPath,\n MediaPaths: mediaPaths.length > 0 ? mediaPaths : undefined,\n MediaUrls: mediaPaths.length > 0 ? mediaPaths : undefined,\n MediaTypes: mediaTypes.length > 0 ? mediaTypes : undefined,\n GroupMembers: groupMembers,\n GroupSystemPrompt: extraSystemPrompt,\n GroupChannel: isDirect ? undefined : route.sessionKey,\n CommandAuthorized: commandAuthorized,\n OriginatingChannel: \"dingtalk\",\n OriginatingTo: to,\n });\n\n await rt.channel.session.recordInboundSession({\n storePath,\n sessionKey: ctx.SessionKey || route.sessionKey,\n ctx,\n updateLastRoute: (() => {\n if (!isDirect) {\n return undefined;\n }\n const pinnedMainDmOwner = resolvePinnedMainDmOwner({\n dmScope: cfg.session?.dmScope,\n allowFrom: dingtalkConfig.allowFrom,\n });\n const senderRecipient = (senderOriginalId || senderId || \"\").trim().toLowerCase();\n if (\n pinnedMainDmOwner &&\n senderRecipient &&\n pinnedMainDmOwner.trim().toLowerCase() !== senderRecipient\n ) {\n log?.debug?.(\n `[DingTalk] Skipping main-session last route update for ${senderRecipient} (pinned owner ${pinnedMainDmOwner})`,\n );\n return undefined;\n }\n return { sessionKey: route.mainSessionKey, channel: \"dingtalk\", to, accountId };\n })(),\n onRecordError: (err: unknown) => {\n log?.error?.(`[DingTalk] Failed to record inbound session: ${String(err)}`);\n },\n });\n\n log?.info?.(`[DingTalk] Inbound: from=${senderName} text=\"${content.text.slice(0, 50)}...\"`);\n\n // ---- Pre-lock abort: bypass session lock for stop requests ----\n // isAbortRequestText matches \"/stop\", \"\u505C\u6B62\", \"stop\", \"esc\", etc.\n // Calling dispatchReplyWithBufferedBlockDispatcher without holding the lock lets\n // tryFastAbortFromMessage (inside the SDK) kill any in-flight generation immediately,\n // rather than waiting for it to finish before the stop message is processed.\n //\n // Strip leading @mention tokens before the abort check so that messages like\n // \"@Agent /stop\" are correctly recognised as abort requests in both DM and group\n // chats. In groups DingTalk usually strips @BotName at the protocol level, but\n // in DMs with multi-agent routing the @mention prefix survives all the way here.\n const textForAbortCheck = stripLeadingMentions(inboundText).trim();\n if (isAbortRequestText(textForAbortCheck)) {\n log?.info?.(\n `[DingTalk] Abort request detected, bypassing session lock for session=${route.sessionKey}`,\n );\n // In card mode: capture the abort confirmation text so we can write it into\n // the card (instead of sending a separate plain text message).\n let abortConfirmationText: string | undefined;\n try {\n await rt.channel.reply.dispatchReplyWithBufferedBlockDispatcher({\n ctx,\n cfg,\n dispatcherOptions: {\n responsePrefix: \"\",\n deliver: async (payload) => {\n if (!payload.text) {\n log?.debug?.(`[DingTalk] Abort deliver received non-text payload, skipping`);\n return;\n }\n if (currentAICard) {\n // Card mode: capture text \u2014 will be written to card after dispatch.\n abortConfirmationText = payload.text;\n } else {\n try {\n if (sessionWebhook) {\n await sendBySession(dingtalkConfig, sessionWebhook, payload.text, {\n log,\n accountId,\n storePath: accountStorePath,\n });\n } else {\n await sendMessage(dingtalkConfig, to, payload.text, {\n log,\n accountId,\n storePath: accountStorePath,\n conversationId: groupId,\n });\n }\n } catch (deliverErr) {\n log?.warn?.(\n `[DingTalk] Abort reply delivery failed: ${getErrorMessage(deliverErr)}`,\n );\n }\n }\n },\n },\n });\n } catch (abortErr) {\n log?.warn?.(`[DingTalk] Abort dispatch failed: ${getErrorMessage(abortErr)}`);\n }\n // Finalize the card that was created for this message before the abort check.\n // Without this, the card stays in PROCESSING (\"\u5904\u7406\u4E2D...\") indefinitely.\n // Use V2 finalize (commitAICardBlocks) for consistent state transition.\n if (currentAICard && !isCardInTerminalState(currentAICard.state)) {\n try {\n const abortText = abortConfirmationText ?? \"\u5DF2\u505C\u6B62\";\n const abortBlockList = [{ type: 0, markdown: abortText }];\n const blockListJson = JSON.stringify(abortBlockList);\n\n await commitAICardBlocks(\n currentAICard,\n {\n blockListJson,\n content: abortText,\n },\n log,\n );\n\n log?.debug?.(\n `[DingTalk] Abort card finalized via V2 API: card=${currentAICard.cardInstanceId}`,\n );\n } catch (cardErr) {\n log?.warn?.(`[DingTalk] Abort card finalize failed: ${getErrorMessage(cardErr)}`);\n currentAICard.state = AICardStatus.FAILED;\n }\n }\n return;\n }\n\n // ---- Pre-lock BTW: bypass session lock for /btw side questions ----\n // /btw runs an isolated, tool-less side query in openclaw without polluting\n // the main run's transcript. The dispatch must NOT acquire the session lock,\n // otherwise it would queue behind the in-flight main task and lose its \"side\n // question\" semantics.\n //\n // The `isBtwBypass` flag is computed once early (just after `content` is\n // resolved, just before `createAICard`). The same constant gates `createAICard` above and\n // drives this branch \u2014 single decision, two consequences. See the comment\n // at the flag's definition for why /btw uses pre-OCR `content.text` while\n // abort uses `inboundText`.\n if (isBtwBypass) {\n log?.info?.(\n `[DingTalk] BTW request detected, bypassing session lock for session=${route.sessionKey}`,\n );\n // Empty fallback (NOT \"Unknown\" like the file's main `senderName` variable):\n // when the nickname is missing we want the blockquote to render as\n // `> /btw <question>` rather than `> Unknown: /btw <question>`. Read locally\n // here so the existing `senderName` semantics elsewhere in the file are not\n // affected.\n const btwSenderName = data.senderNick || \"\";\n try {\n await rt.channel.reply.dispatchReplyWithBufferedBlockDispatcher({\n ctx,\n cfg,\n dispatcherOptions: {\n responsePrefix: \"\",\n deliver: async (payload) => {\n if (!payload.text) {\n log?.debug?.(`[DingTalk] BTW deliver received non-text payload, skipping`);\n return;\n }\n await deliverBtwReply({\n config: dingtalkConfig,\n sessionWebhook,\n conversationId: groupId,\n to,\n senderName: btwSenderName,\n // Use pre-OCR content.text (consistent with isBtwBypass detection)\n // so the blockquote shows the user's typed body, not body + OCR.\n rawQuestion: content.text,\n replyText: payload.text,\n log,\n accountId,\n storePath: accountStorePath,\n });\n },\n },\n });\n } catch (btwErr) {\n log?.warn?.(`[DingTalk] BTW dispatch failed: ${getErrorMessage(btwErr)}`);\n }\n return;\n }\n\n const ackReaction =\n typeof dingtalkConfig.ackReaction === \"string\"\n ? dingtalkConfig.ackReaction.trim()\n : resolveAckReactionSetting({\n cfg,\n accountId,\n agentId: route.agentId,\n });\n const normalizedAckReaction = ackReaction === \"off\" ? \"\" : ackReaction;\n const resolvedAckReaction =\n normalizedAckReaction === \"kaomoji\"\n ? classifyAckReactionEmoji(content.text).emoji\n : normalizedAckReaction === \"emoji\"\n ? \"\uD83E\uDD14\u601D\u8003\u4E2D\"\n : normalizedAckReaction;\n const shouldAttachAckReaction = Boolean(resolvedAckReaction);\n let ackReactionAttached = false;\n let ackReactionAttachedAt = 0;\n\n if (shouldAttachAckReaction) {\n ackReactionAttached = await attachNativeAckReaction(\n dingtalkConfig,\n {\n msgId: data.msgId,\n conversationId: groupId,\n reactionName: resolvedAckReaction,\n },\n log,\n );\n if (ackReactionAttached) {\n ackReactionAttachedAt = Date.now();\n log?.debug?.(\n `[DingTalk] Initial ack reaction attached mode=${normalizedAckReaction || \"off\"} reaction=${resolvedAckReaction}`,\n );\n }\n }\n\n function parseInlineReplyPayloadText(text: unknown): {\n text?: string;\n mediaUrls: string[];\n audioAsVoice: boolean;\n } {\n if (typeof text !== \"string\") {\n return { text: undefined, mediaUrls: [], audioAsVoice: false };\n }\n\n const normalizedText = text.replace(/\\r\\n/g, \"\\n\");\n const parsedInline = normalizedText.includes(\"[[\")\n ? parseInlineDirectives(normalizedText, {\n stripAudioTag: true,\n stripReplyTags: false,\n })\n : {\n text: normalizedText,\n audioAsVoice: false,\n replyToCurrent: false,\n hasAudioTag: false,\n hasReplyTag: false,\n };\n const mediaUrls: string[] = [];\n const contentLines: string[] = [];\n\n for (const line of parsedInline.text.split(\"\\n\")) {\n const trimmed = line.trim();\n const mediaCandidate = trimmed.replace(/^(?:\\[\\[[^[\\]]+\\]\\]\\s*)+/, \"\");\n if (mediaCandidate.startsWith(MEDIA_DIRECTIVE_PREFIX)) {\n const mediaSource = mediaCandidate.slice(MEDIA_DIRECTIVE_PREFIX.length).trim();\n if (mediaSource) {\n mediaUrls.push(mediaSource);\n continue;\n }\n }\n contentLines.push(line);\n }\n\n const cleanedText = contentLines.join(\"\\n\").trim();\n const inlineTextWasTransformed = parsedInline.text !== normalizedText;\n if (mediaUrls.length === 0) {\n const standaloneMediaSource = extractStandaloneMediaSource(cleanedText);\n if (standaloneMediaSource) {\n return {\n text: undefined,\n mediaUrls: [standaloneMediaSource],\n audioAsVoice: parsedInline.audioAsVoice,\n };\n }\n }\n\n return {\n // Keep ordinary text formatting stable except for newline normalization.\n // Once inline parsing actually strips directives/media lines, return the\n // cleaned body text instead of the original raw payload.\n text:\n mediaUrls.length > 0 || inlineTextWasTransformed\n ? cleanedText || undefined\n : normalizedText,\n mediaUrls,\n audioAsVoice: parsedInline.audioAsVoice,\n };\n }\n\n function extractStandaloneMediaSource(text: string): string | undefined {\n const trimmed = text.trim();\n if (!trimmed || trimmed.includes(\"\\n\") || /\\s/.test(trimmed)) {\n return undefined;\n }\n\n const hasPathLikeShape =\n /^https?:\\/\\/\\S+$/i.test(trimmed) ||\n trimmed.startsWith(\"~/\") ||\n trimmed.startsWith(\"~\\\\\") ||\n trimmed.startsWith(\"./\") ||\n trimmed.startsWith(\".\\\\\") ||\n trimmed.startsWith(\"../\") ||\n trimmed.startsWith(\"..\\\\\") ||\n trimmed.startsWith(\"/\") ||\n trimmed.startsWith(\"\\\\\") ||\n /^[a-zA-Z]:[\\\\/]/.test(trimmed) ||\n trimmed.includes(\"/\") ||\n trimmed.includes(\"\\\\\");\n if (!hasPathLikeShape) {\n return undefined;\n }\n\n return STANDALONE_MEDIA_PATH_EXTENSIONS.has(path.extname(trimmed).toLowerCase())\n ? trimmed\n : undefined;\n }\n\n // ---- Shared media delivery helper ----\n function extractSharedAudioAsVoice(\n payload: ReplyStreamPayload,\n inlineReplyPayload?: ReturnType<typeof parseInlineReplyPayloadText>,\n ): boolean {\n // Normalize all reply-time voice hints into the shared `audioAsVoice`\n // semantic that strategies and media delivery use downstream.\n const richPayload = payload as ReplyStreamPayload & {\n audioAsVoice?: unknown;\n asVoice?: unknown;\n };\n const sharedValue = parseBooleanLike(richPayload.audioAsVoice);\n if (sharedValue !== undefined) {\n return sharedValue;\n }\n if (parseBooleanLike(richPayload.asVoice) === true) {\n return true;\n }\n return inlineReplyPayload?.audioAsVoice === true;\n }\n\n async function deliverMediaAttachments(urls: string[], options?: { audioAsVoice?: boolean }) {\n for (const rawMediaUrl of urls) {\n const preparedMedia = await prepareMediaInput(\n rawMediaUrl,\n log,\n dingtalkConfig.mediaUrlAllowlist,\n );\n try {\n const actualMediaPath = preparedMedia.cleanup\n ? preparedMedia.path\n : resolveRelativePath(preparedMedia.path);\n const outMediaType = resolveOutboundMediaType({\n mediaPath: actualMediaPath,\n asVoice: options?.audioAsVoice === true,\n });\n if (sessionWebhook) {\n const sendResult = await sendMessage(dingtalkConfig, to, \"\", {\n sessionWebhook,\n mediaPath: actualMediaPath,\n mediaType: outMediaType,\n log,\n accountId,\n storePath: accountStorePath,\n conversationId: groupId,\n quotedRef: replyQuotedRef,\n });\n if (!sendResult.ok) {\n throw new Error(sendResult.error || \"Media reply send failed\");\n }\n } else {\n const sendResult = await sendProactiveMedia(\n dingtalkConfig,\n to,\n actualMediaPath,\n outMediaType,\n {\n accountId,\n log,\n storePath: accountStorePath,\n conversationId: groupId,\n quotedRef: replyQuotedRef,\n },\n );\n if (!sendResult.ok) {\n throw new Error(sendResult.error || \"Media reply send failed\");\n }\n }\n } finally {\n await preparedMedia.cleanup?.();\n }\n }\n }\n\n // ---- Extract mediaUrls from runtime payload ----\n function extractMediaUrls(\n payload: ReplyStreamPayload,\n inlineReplyPayload?: ReturnType<typeof parseInlineReplyPayloadText>,\n ): string[] {\n const richPayload = payload as typeof payload & {\n mediaUrl?: string;\n mediaUrls?: string[];\n };\n const explicitMediaUrls = Array.isArray(richPayload.mediaUrls)\n ? richPayload.mediaUrls.filter(\n (entry: unknown) => typeof entry === \"string\" && entry.trim(),\n )\n : richPayload.mediaUrl &&\n typeof richPayload.mediaUrl === \"string\" &&\n richPayload.mediaUrl.trim()\n ? [richPayload.mediaUrl]\n : [];\n return explicitMediaUrls.length > 0\n ? explicitMediaUrls\n : (inlineReplyPayload?.mediaUrls ?? []);\n }\n\n // Serialize dispatchReply + card finalize per session to prevent the runtime\n // from receiving concurrent dispatch calls on the same session key, which\n // causes empty replies for all but the first caller.\n // Each sub-agent call acquires its own lock since sub-agent sessions have\n // different session keys (different agentId), so no deadlock risk.\n const currentOutTrackId = currentAICard?.outTrackId;\n const shouldTrackDynamicAckReaction =\n (normalizedAckReaction === \"emoji\" || normalizedAckReaction === \"kaomoji\") &&\n shouldAttachAckReaction;\n const runtimeEvents = (\n rt as typeof rt & {\n events?: {\n onAgentEvent?: (listener: (event: unknown) => void) => () => void;\n };\n }\n ).events;\n const releaseSessionLock = await acquireSessionLock(route.sessionKey);\n const dynamicAckReactionController = createDynamicAckReactionController({\n enabled: shouldTrackDynamicAckReaction,\n initialReaction: resolvedAckReaction || \"\",\n initialAttached: ackReactionAttached,\n initialAttachedAt: ackReactionAttachedAt,\n dingtalkConfig,\n msgId: data.msgId,\n conversationId: groupId,\n sessionKey: route.sessionKey,\n log,\n runtimeEvents,\n onReactionDisposed: () => {\n ackReactionAttached = false;\n },\n });\n try {\n if (!ackReactionAttached && shouldAttachAckReaction) {\n log?.debug?.(\"[DingTalk] Native ack reaction unavailable; skipping fallback.\");\n }\n const isCurrentCardStopRequested = () =>\n Boolean(\n currentAICard &&\n (currentAICard.state === AICardStatus.STOPPED ||\n (currentOutTrackId && isCardRunStopRequested(currentOutTrackId))),\n );\n\n if (isCurrentCardStopRequested()) {\n log?.info?.(\n \"[DingTalk][CardStop] Skip dispatch because card was already stopped before session lock was acquired\",\n );\n return;\n }\n\n // ---- Create reply strategy (card or markdown) ----\n const replyMode: ReplyMode = useCardMode && !!currentAICard ? \"card\" : \"markdown\";\n const sessionReasoningLevel = readSessionReasoningLevel({\n storePath,\n sessionKey: route.sessionKey,\n sessionUpdatedAt: previousTimestamp,\n log,\n });\n const legacyCardStreamReasoning = resolveLegacyCardStreamReasoningForInternalUse({\n cfg,\n accountId,\n });\n const strategyConfig =\n legacyCardStreamReasoning === undefined\n ? dingtalkConfig\n : { ...dingtalkConfig, cardStreamReasoning: legacyCardStreamReasoning };\n const sessionTaskState = getSessionState(accountId, taskInfoConversationId);\n const taskMeta = {\n model: sessionTaskState?.model,\n effort: sessionTaskState?.effort,\n elapsedMs:\n typeof sessionTaskState?.taskStartTime === \"number\"\n ? Math.max(0, Date.now() - sessionTaskState.taskStartTime)\n : undefined,\n agent: getAgentDisplayName({\n subAgentOptions,\n agentId: route.agentId,\n agentsList: cfg.agents?.list,\n }),\n };\n\n const strategy = createReplyStrategy({\n config: strategyConfig,\n card: currentAICard,\n useCardMode: replyMode === \"card\",\n to,\n sessionWebhook,\n senderId,\n isDirect,\n accountId,\n storePath: accountStorePath,\n sessionKey: route.sessionKey,\n sessionAgentId: route.agentId,\n disableBlockStreaming: shouldDisableBlockStreamingForReplyMode({\n replyMode,\n sessionKey: route.sessionKey,\n reasoningLevel: sessionReasoningLevel,\n log,\n }),\n groupId,\n log,\n replyQuotedRef,\n deliverMedia: deliverMediaAttachments,\n isStopRequested: isCurrentCardStopRequested,\n inboundText: rawInboundText,\n taskMeta,\n });\n\n try {\n let deliveredFinalCount = 0;\n const dispatchResult = await rt.channel.reply.dispatchReplyWithBufferedBlockDispatcher({\n ctx,\n cfg,\n dispatcherOptions: {\n responsePrefix: subAgentOptions?.responsePrefix || \"\",\n deliver: async (payload: ReplyStreamPayload, info?: ReplyChunkInfo) => {\n if (isCurrentCardStopRequested()) {\n log?.debug?.(\n \"[DingTalk][CardStop] Ignoring reply delivery because stop was already requested\",\n );\n return;\n }\n try {\n if (info?.kind === \"final\") {\n deliveredFinalCount += 1;\n }\n const inlineReplyPayload = parseInlineReplyPayloadText(payload.text);\n const mediaUrls = extractMediaUrls(payload, inlineReplyPayload);\n const richPayload = payload as ReplyStreamPayload & { isReasoning?: boolean };\n await strategy.deliver({\n text: inlineReplyPayload.text,\n mediaUrls,\n audioAsVoice: extractSharedAudioAsVoice(payload, inlineReplyPayload),\n kind: (info?.kind as DeliverPayload[\"kind\"]) || \"block\",\n isReasoning: richPayload.isReasoning === true,\n });\n } catch (err: unknown) {\n log?.error?.(`[DingTalk] Reply failed: ${getErrorMessage(err)}`);\n const responseData = getErrorResponseData(err);\n if (responseData !== undefined) {\n log?.error?.(formatDingTalkErrorPayloadLog(\"inbound.replyDeliver\", responseData));\n }\n throw err;\n }\n },\n },\n replyOptions: strategy.getReplyOptions(),\n });\n\n const bufferedFinal =\n dispatchResult && typeof dispatchResult === \"object\" && \"queuedFinal\" in dispatchResult\n ? (dispatchResult as { queuedFinal?: unknown }).queuedFinal\n : undefined;\n const finalCount =\n dispatchResult && typeof dispatchResult === \"object\" && \"counts\" in dispatchResult\n ? (dispatchResult as { counts?: { final?: unknown } }).counts?.final\n : undefined;\n\n log?.info?.(\n `[DingTalk][Dispatch] completed \u2014 deliveredFinalCount=${deliveredFinalCount} ` +\n `counts.final=${typeof finalCount === \"number\" ? finalCount : \"n/a\"} ` +\n `queuedFinalType=${typeof bufferedFinal}`,\n );\n\n const bufferedFinalPayload =\n typeof bufferedFinal === \"string\"\n ? ({ text: bufferedFinal } satisfies ReplyStreamPayload)\n : bufferedFinal && typeof bufferedFinal === \"object\"\n ? (bufferedFinal as ReplyStreamPayload)\n : undefined;\n\n if (deliveredFinalCount === 0 && bufferedFinalPayload) {\n const inlineReplyPayload = parseInlineReplyPayloadText(bufferedFinalPayload.text);\n const mediaUrls = extractMediaUrls(bufferedFinalPayload, inlineReplyPayload);\n const hasBufferedText =\n typeof bufferedFinalPayload.text === \"string\" &&\n bufferedFinalPayload.text.trim().length > 0;\n if (hasBufferedText || mediaUrls.length > 0) {\n await strategy.deliver({\n text: inlineReplyPayload.text,\n mediaUrls,\n audioAsVoice: extractSharedAudioAsVoice(bufferedFinalPayload, inlineReplyPayload),\n kind: \"final\",\n isReasoning: bufferedFinalPayload.isReasoning === true,\n });\n }\n }\n } catch (dispatchErr: unknown) {\n const error =\n dispatchErr instanceof Error ? dispatchErr : new Error(getErrorMessage(dispatchErr));\n await strategy.abort(error);\n throw dispatchErr;\n }\n\n await strategy.finalize();\n } finally {\n // Only remove the registry entry if no stop was requested. When a stop is\n // in progress, card-stop-handler may still be running async operations\n // (finalize card, hide button, gateway abort) that read the record.\n // In that case, let the 30-minute TTL sweep handle cleanup.\n if (currentOutTrackId && !isCardRunStopRequested(currentOutTrackId)) {\n removeCardRun(currentOutTrackId);\n }\n await waitForDynamicAckDispose({\n dispose: () => dynamicAckReactionController.dispose(MIN_THINKING_REACTION_VISIBLE_MS),\n log,\n sessionKey: route.sessionKey,\n });\n releaseSessionLock();\n }\n } finally {\n if (cardFlightKey) {\n cardCreationInFlight.delete(cardFlightKey);\n }\n }\n}\n", "export type NormalizedAllowFrom = {\n entries: string[];\n entriesLower: string[];\n hasWildcard: boolean;\n hasEntries: boolean;\n};\n\n/**\n * Normalize allowFrom list:\n * - trim whitespace\n * - support \"dingtalk:/dd:/ding:\" prefixes\n * - precompute lower-case list for case-insensitive checks\n */\nexport function normalizeAllowFrom(list?: Array<string>): NormalizedAllowFrom {\n const entries = (list ?? []).map((value) => String(value).trim()).filter(Boolean);\n const hasWildcard = entries.includes(\"*\");\n const normalized = entries\n .filter((value) => value !== \"*\")\n .map((value) => value.replace(/^(dingtalk|dd|ding):/i, \"\"));\n const normalizedLower = normalized.map((value) => value.toLowerCase());\n return {\n entries: normalized,\n entriesLower: normalizedLower,\n hasWildcard,\n hasEntries: entries.length > 0,\n };\n}\n\nexport function isSenderAllowed(params: {\n allow: NormalizedAllowFrom;\n senderId?: string;\n}): boolean {\n const { allow, senderId } = params;\n if (!allow.hasEntries) {\n return true;\n }\n if (allow.hasWildcard) {\n return true;\n }\n if (senderId && allow.entriesLower.includes(senderId.toLowerCase())) {\n return true;\n }\n return false;\n}\n\nexport function isSenderGroupAllowed(params: {\n allow: NormalizedAllowFrom;\n groupId?: string;\n}): boolean {\n const { allow, groupId } = params;\n if (groupId && allow.entriesLower.includes(groupId.toLowerCase())) {\n return true;\n }\n return false;\n}\n\nexport type GroupAccessResult = {\n allowed: boolean;\n reason?: \"disabled\" | \"group_not_allowed\" | \"sender_not_allowed\";\n legacyFallback?: boolean;\n};\n\nexport type GroupAccessParams = {\n groupPolicy: \"open\" | \"allowlist\" | \"disabled\";\n groupId: string;\n senderId: string;\n groups?: Record<string, { groupAllowFrom?: string[] }>;\n groupAllowFrom?: string[];\n allowFrom?: string[]; // legacy fallback\n};\n\nexport function resolveGroupAccess(params: GroupAccessParams): GroupAccessResult {\n const { groupPolicy, groupId, senderId, groups, groupAllowFrom, allowFrom } = params;\n\n // Step 1: disabled \u2192 block all\n if (groupPolicy === \"disabled\") {\n return { allowed: false, reason: \"disabled\" };\n }\n\n // Step 2: allowlist \u2192 group ID check\n let legacyFallback = false;\n if (groupPolicy === \"allowlist\") {\n const groupConfig = groups?.[groupId];\n const wildcardConfig = groups?.[\"*\"];\n const groupInConfig = groupConfig !== undefined || wildcardConfig !== undefined;\n\n if (!groupInConfig) {\n // Legacy fallback: check allowFrom for group ID\n const legacyAllow = normalizeAllowFrom(allowFrom);\n if (isSenderGroupAllowed({ allow: legacyAllow, groupId })) {\n legacyFallback = true;\n // Continue to sender check below\n } else {\n return { allowed: false, reason: \"group_not_allowed\" };\n }\n }\n }\n\n // Step 3: Sender check\n // Priority: per-group > wildcard > top-level\n const perGroupAllowFrom = groups?.[groupId]?.groupAllowFrom;\n const wildcardAllowFrom = groups?.[\"*\"]?.groupAllowFrom;\n const effectiveAllowFrom = perGroupAllowFrom ?? wildcardAllowFrom ?? groupAllowFrom;\n\n if (effectiveAllowFrom == null) {\n return { allowed: true, legacyFallback: legacyFallback || undefined };\n }\n\n // Empty array = block all senders (fail-closed per official design)\n if (effectiveAllowFrom.length === 0) {\n return { allowed: false, reason: \"sender_not_allowed\" };\n }\n\n const normalized = normalizeAllowFrom(effectiveAllowFrom);\n if (isSenderAllowed({ allow: normalized, senderId })) {\n return { allowed: true, legacyFallback: legacyFallback || undefined };\n }\n\n return { allowed: false, reason: \"sender_not_allowed\" };\n}\n\nexport function isSenderOwner(params: {\n allow: NormalizedAllowFrom;\n senderId?: string;\n rawSenderId?: string;\n}): boolean {\n const { allow, senderId, rawSenderId } = params;\n if (!allow.hasEntries) {\n return false;\n }\n if (senderId && allow.entriesLower.includes(senderId.toLowerCase())) {\n return true;\n }\n if (rawSenderId && allow.entriesLower.includes(rawSenderId.toLowerCase())) {\n return true;\n }\n return false;\n}\n", "type SentenceType = \"\u5938\u5956\" | \"\u8D23\u602A\" | \"\u547D\u4EE4\" | \"\u53D9\u4E8B\" | \"\u8BF7\u6C42\" | \"\u672A\u77E5\";\n\ntype AckReactionClassifyResult = {\n type: SentenceType;\n emoji: string;\n};\n\ntype EmojiMap = Record<SentenceType, readonly string[]>;\n\nconst CATCHPHRASE = \"\u53FD \";\n\nconst KEYWORDS = {\n praise: [\"\u771F\u68D2\", \"\u592A\u597D\u4E86\", \"\u5389\u5BB3\", \"\u4F18\u79C0\", \"\u806A\u660E\", \"\u597D\u6837\u7684\", \"\u8D5E\", \"\u725B\", \"\u5B8C\u7F8E\", \"\u51FA\u8272\", \"\u771F\u884C\", \"\u5E72\u5F97\u6F02\u4EAE\", \"\u5929\u624D\", \"\u68D2\u6781\u4E86\"],\n blame: [\"\u600E\u4E48\u53C8\", \"\u641E\u7838\", \"\u592A\u5DEE\u4E86\", \"\u70E6\u6B7B\u4E86\", \"\u8BA8\u538C\", \"\u7B28\", \"\u8822\", \"\u9A6C\u864E\", \"\u4E0D\u8D1F\u8D23\u4EFB\", \"\u4E71\u6765\", \"\u7CDF\u7CD5\", \"\u5E9F\u7269\", \"\u6C14\u6B7B\u6211\u4E86\", \"\u9519\u4E86\"],\n command: [\"\u5FC5\u987B\", \"\u7ACB\u523B\", \"\u9A6C\u4E0A\", \"\u8D76\u7D27\", \"\u4E0D\u51C6\", \"\u4E0D\u8981\", \"\u522B\u52A8\", \"\u522B\u8BF4\", \"\u522B\u505A\", \"\u5FEB\u53BB\", \"\u53BB\u505A\", \"\u7ED9\u6211\", \"\u542C\u7740\", \"\u7AD9\u4F4F\", \"\u95ED\u5634\"],\n request: [\"\u80FD\u4E0D\u80FD\", \"\u53EF\u4EE5\u5417\", \"\u597D\u5417\", \"\u8BF7\", \"\u9EBB\u70E6\", \"\u5E2E\u4E2A\u5FD9\", \"\u5E2E\u5FD9\", \"\u52B3\u9A7E\", \"\u80FD\u5426\", \"\u60F3\u8BF7\u4F60\", \"\u80FD\u5E2E\u6211\", \"\u501F\u6211\", \"\u65B9\u4FBF\u5417\"],\n} as const;\n\nconst POLITE_EXCLUSIONS = [\"\u522B\u5BA2\u6C14\", \"\u522B\u4ECB\u610F\", \"\u522B\u89C1\u602A\", \"\u522B\u62C5\u5FC3\", \"\u522B\u7740\u6025\"] as const;\n\nconst EMOJIS: EmojiMap = {\n // DingTalk `emotion/reply` does not accept every visually valid kaomoji.\n // Keep only the strings that survived repeated direct API retests against\n // the live endpoint using a real message target. Removed as unstable/bad:\n // `\u0669(\u0E51>\u25E1<\u0E51)\u06F6`.\n \"\u5938\u5956\": [\"(\u0E51\u2022\u0300\u3142\u2022\u0301)\u0648\u2727\", \"(\uFF89\u2267\u2200\u2266)\uFF89\", \"(\u2605\u25BD\u2605)\", \"(\u2312\u25BD\u2312)\u2606\", \"(*\u2267\u03C9\u2266)\", \"(\u0E07 \u2022_\u2022)\u0E07\", \"\u30FE(\u2267\u25BD\u2266*)o\"],\n \"\u8D23\u602A\": [\"(\u256C \u00D2\uFE4F\u00D3)\", \"(\u256F\u00B0\u25A1\u00B0\uFF09\u256F\", \"(\u25BC\u76BF\u25BC#)\", \"(\uFF61\u2022\u0301\uFE3F\u2022\u0300\uFF61)\", \"(\u2565\uFE4F\u2565)\", \"\u30FD(\uFF40\u0414\u00B4)\uFF89\", \"(\uFF03\uFF1E\uFF1C)\", \"(\uFF1B\u2032\u2312`)\"],\n // Keep command kaomoji limited to strings that passed local\n // DingTalk emotion/reply verification. Removed as unstable/bad after\n // repeated direct API retests: `\u250C\uFF08\u250C *\uFF40\u0434\u00B4\uFF09\u2510`, `(\u2022\u0300\u3078 \u2022\u0301 \u256E )`.\n \"\u547D\u4EE4\": [\"(\u00AC_\u00AC)\", \"(\uFF40\u03B5\u00B4)\", \"(\uFF03\uFF40\u0414\u00B4)\", \"(\u25CF\uFF40\u2200\u00B4\u25CF)\", \"(\uFF40\u0434\u00B4)\", \"(\uFFE3\u03C9\uFFE3;)\"],\n // Narrative kaomoji must also stay within the subset accepted by\n // DingTalk emotion/reply. Removed as unstable/bad after repeated direct\n // API retests: `(\u00B4\u2022 \u03C9 \u2022`)`.\n \"\u53D9\u4E8B\": [\"(\u3002\u30FB\u03C9\u30FB\u3002)\", \"(\uFFE3\u25BD\uFFE3)\", \"(\u30FB\u30FB?)\", \"(\u3002_\u3002)\", \"(\uFFE3\u03C9\uFFE3)\", \"(\u00B4\u25BD`)\", \"(=_=)\"],\n // Request kaomoji must exclude strings that stayed unstable across\n // repeated direct API retests. Removed as unstable/bad:\n // `(\u3065\uFF61\u25D5\u203F\u203F\u25D5\uFF61)\u3065`, `(\u2044 \u2044\u2022\u2044\u03C9\u2044\u2022\u2044 \u2044)`.\n \"\u8BF7\u6C42\": [\"(\u3063\u00B4\u2200\uFF40)\u3063\", \"(\u0E51\u2022\u0300\u03C9\u2022\u0301\u0E51)\u2727\", \"(p\u2267w\u2266q)\", \"(\u2661\u02D9\uFE36\u02D9\u2661)\", \"(\u00B4;\u03C9;\uFF40)\", \"(\u4EBA\u2022\u1D17\u2022\u273F)\"],\n \"\u672A\u77E5\": [\"(\u2022\u0300_\u2022\u0301)\", \"(\uFF1B\u4E00_\u4E00)\", \"(???)\"],\n};\n\nfunction containsAny(text: string, words: readonly string[]): boolean {\n return words.some(word => text.includes(word));\n}\n\nexport function classifyAckReactionEmoji(sentence: unknown): AckReactionClassifyResult {\n if (!sentence || typeof sentence !== \"string\") {\n return { type: \"\u672A\u77E5\", emoji: `${CATCHPHRASE}(\u2022\u0300_\u2022\u0301)` };\n }\n\n const s = sentence.trim();\n const isPolitePhrase = POLITE_EXCLUSIONS.some(phrase => s.includes(phrase));\n const isQuestion = /\u5417|\u5462|\uFF1F|\\?/.test(s);\n const startsWithPlease = s.startsWith(\"\u8BF7\");\n const hasExclamation = /[!\uFF01]/.test(s);\n const imperativeStart = !isPolitePhrase && /^(\u5FEB|\u522B|\u4E0D\u8981|\u4E0D\u51C6|\u5FC5\u987B|\u9A6C\u4E0A|\u7ACB\u523B)/.test(s);\n\n let type: SentenceType;\n if (containsAny(s, KEYWORDS.request) || (isQuestion && (startsWithPlease || /\u5E2E|\u9EBB\u70E6/.test(s)))) {\n type = \"\u8BF7\u6C42\";\n } else if (imperativeStart || containsAny(s, KEYWORDS.command)) {\n type = \"\u547D\u4EE4\";\n } else if (containsAny(s, KEYWORDS.praise)) {\n type = \"\u5938\u5956\";\n } else if (containsAny(s, KEYWORDS.blame) || (hasExclamation && /\u70E6|\u8BA8\u538C|\u7B28|\u8822|\u5DEE|\u6C14\u6B7B/.test(s))) {\n type = \"\u8D23\u602A\";\n } else {\n type = \"\u53D9\u4E8B\";\n }\n\n const emojiList = EMOJIS[type];\n const emoji = emojiList[Math.floor(Math.random() * emojiList.length)];\n return { type, emoji: `${CATCHPHRASE}${emoji}` };\n}\n", "import axios from \"./http-client\";\nimport { getAccessToken } from \"./auth\";\nimport type { DingTalkConfig } from \"./types\";\nimport { formatDingTalkErrorPayloadLog, getErrorMessage, getProxyBypassOption } from \"./utils\";\n\n// DingTalk currently exposes a dedicated native \"thinking\" reaction flow rather than\n// a generic arbitrary-emoji reaction API for this plugin path.\nconst DINGTALK_NATIVE_ACK_REACTION = \"\uD83E\uDD14\u601D\u8003\u4E2D\";\nconst THINKING_EMOTION_ID = \"2659900\";\nconst THINKING_EMOTION_BACKGROUND_ID = \"im_bg_1\";\n// DingTalk `emotion/reply` occasionally races with just-arrived inbound\n// messages or returns transient 5xx responses. Keep the first attempt\n// immediate, then retry twice with short backoff windows before giving up.\nconst THINKING_REACTION_ATTACH_DELAYS_MS = [0, 400, 1200] as const;\nconst THINKING_REACTION_RECALL_DELAYS_MS = [0, 1500, 5000] as const;\n\ntype AckReactionLogger = {\n debug?: (msg: string) => void;\n info?: (msg: string) => void;\n warn?: (msg: string) => void;\n};\n\ntype AckReactionTarget = {\n msgId: string;\n conversationId: string;\n reactionName?: string;\n};\n\ntype ResolvedAckReactionRequest = {\n msgId: string;\n conversationId: string;\n robotCode: string;\n reactionName: string;\n};\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === \"object\" ? (value as Record<string, unknown>) : undefined;\n}\n\nfunction formatAckReactionTarget(data: {\n msgId: string;\n conversationId: string;\n reactionName: string;\n}): string {\n return `msgId=${data.msgId || \"-\"} conversationId=${data.conversationId || \"-\"} reactionName=${data.reactionName || DINGTALK_NATIVE_ACK_REACTION}`;\n}\n\nfunction resolveAckReactionRequest(\n config: DingTalkConfig,\n data: AckReactionTarget,\n): ResolvedAckReactionRequest | null {\n const robotCode = (config.clientId || \"\").trim();\n const reactionName =\n (data.reactionName || DINGTALK_NATIVE_ACK_REACTION).trim() || DINGTALK_NATIVE_ACK_REACTION;\n if (!robotCode || !data.msgId || !data.conversationId) {\n return null;\n }\n return {\n msgId: data.msgId,\n conversationId: data.conversationId,\n robotCode,\n reactionName,\n };\n}\n\nasync function callEmotionApi(\n config: DingTalkConfig,\n request: ResolvedAckReactionRequest,\n endpoint: \"reply\" | \"recall\",\n successLog: string,\n errorLogPrefix: string,\n errorPayloadKey: \"inbound.ackReactionAttach\" | \"inbound.ackReactionRecall\",\n log?: AckReactionLogger,\n): Promise<{ ok: boolean; error?: unknown }> {\n try {\n const token = await getAccessToken(config, log as any);\n await axios.post(\n `https://api.dingtalk.com/v1.0/robot/emotion/${endpoint}`,\n {\n robotCode: request.robotCode,\n openMsgId: request.msgId,\n openConversationId: request.conversationId,\n emotionType: 2,\n emotionName: request.reactionName,\n textEmotion: {\n emotionId: THINKING_EMOTION_ID,\n emotionName: request.reactionName,\n text: request.reactionName,\n backgroundId: THINKING_EMOTION_BACKGROUND_ID,\n },\n },\n {\n headers: {\n \"x-acs-dingtalk-access-token\": token,\n \"Content-Type\": \"application/json\",\n },\n timeout: 5000,\n ...getProxyBypassOption(config),\n },\n );\n log?.info?.(successLog);\n return { ok: true };\n } catch (err: unknown) {\n const response = asRecord(asRecord(err)?.response);\n log?.warn?.(`${errorLogPrefix}: ${getErrorMessage(err)}`);\n if (response?.data !== undefined) {\n log?.warn?.(formatDingTalkErrorPayloadLog(errorPayloadKey, response.data));\n }\n return { ok: false, error: err };\n }\n}\n\nfunction isRetryableEmotionApiError(err: unknown): boolean {\n const response = asRecord(asRecord(err)?.response);\n const data = asRecord(response?.data);\n const status = Number(response?.status ?? 0);\n const errorCode = String(data?.code || \"\").trim().toLowerCase();\n if (!response) {\n return true;\n }\n if (status >= 500) {\n return true;\n }\n return errorCode === \"system.err\";\n}\n\nexport async function attachNativeAckReaction(\n config: DingTalkConfig,\n data: AckReactionTarget,\n log?: AckReactionLogger,\n): Promise<boolean> {\n const request = resolveAckReactionRequest(config, data);\n if (!request) {\n return false;\n }\n for (let index = 0; index < THINKING_REACTION_ATTACH_DELAYS_MS.length; index += 1) {\n const delayMs = THINKING_REACTION_ATTACH_DELAYS_MS[index];\n if (delayMs > 0) {\n await new Promise(resolve => setTimeout(resolve, delayMs));\n }\n const attempt = index + 1;\n const attemptLabel = `${attempt}/${THINKING_REACTION_ATTACH_DELAYS_MS.length}`;\n const result = await callEmotionApi(\n config,\n request,\n \"reply\",\n `[DingTalk] Native ack reaction attach succeeded (${formatAckReactionTarget(request)} attempt=${attemptLabel})`,\n `[DingTalk] Native ack reaction attach failed (${formatAckReactionTarget(request)} attempt=${attemptLabel})`,\n \"inbound.ackReactionAttach\",\n log,\n );\n if (result.ok) {\n return true;\n }\n const shouldRetry = isRetryableEmotionApiError(result.error);\n if (!shouldRetry || attempt === THINKING_REACTION_ATTACH_DELAYS_MS.length) {\n break;\n }\n log?.debug?.(\n `[DingTalk] Retrying native ack reaction attach (${formatAckReactionTarget(request)} nextAttempt=${attempt + 1}/${THINKING_REACTION_ATTACH_DELAYS_MS.length})`,\n );\n }\n return false;\n}\n\nasync function recallNativeAckReaction(\n config: DingTalkConfig,\n request: ResolvedAckReactionRequest,\n log?: AckReactionLogger,\n): Promise<boolean> {\n const result = await callEmotionApi(\n config,\n request,\n \"recall\",\n \"[DingTalk] Native ack reaction recall succeeded\",\n \"[DingTalk] Native ack reaction recall failed\",\n \"inbound.ackReactionRecall\",\n log,\n );\n return result.ok;\n}\n\nexport async function recallNativeAckReactionWithRetry(\n config: DingTalkConfig,\n data: AckReactionTarget,\n log?: AckReactionLogger,\n): Promise<void> {\n const request = resolveAckReactionRequest(config, data);\n if (!request) {\n return;\n }\n for (const delayMs of THINKING_REACTION_RECALL_DELAYS_MS) {\n if (delayMs > 0) {\n await new Promise(resolve => setTimeout(resolve, delayMs));\n }\n if (await recallNativeAckReaction(config, request, log)) {\n return;\n }\n }\n}\n", "import { getErrorMessage } from \"../utils\";\n\nexport type DynamicAckReactionLogger = {\n debug?: (msg: string) => void;\n info?: (msg: string) => void;\n warn?: (msg: string) => void;\n};\n\nexport type RuntimeAgentEvent = {\n stream?: string;\n runId?: string;\n sessionKey?: string;\n data?: {\n phase?: string;\n name?: string;\n args?: unknown;\n runId?: string;\n sessionKey?: string;\n toolCallId?: string;\n meta?: {\n runId?: string;\n sessionKey?: string;\n } | null;\n };\n};\n\nexport type RuntimeEventsSurface = {\n onAgentEvent?: (listener: (event: unknown) => void) => (() => void);\n};\n\nfunction firstTrimmedString(...values: unknown[]): string | undefined {\n for (const value of values) {\n if (typeof value === \"string\" && value.trim()) {\n return value.trim();\n }\n }\n return undefined;\n}\n\nexport function getEventRunId(event: RuntimeAgentEvent | undefined): string | undefined {\n return firstTrimmedString(event?.runId, event?.data?.runId, event?.data?.meta?.runId);\n}\n\nexport function getEventSessionKey(event: RuntimeAgentEvent | undefined): string | undefined {\n return firstTrimmedString(event?.sessionKey, event?.data?.sessionKey, event?.data?.meta?.sessionKey);\n}\n\nexport function describeEvent(event: RuntimeAgentEvent | undefined): string {\n const stream = firstTrimmedString(event?.stream) || \"-\";\n const phase = firstTrimmedString(event?.data?.phase) || \"-\";\n const toolName = firstTrimmedString(event?.data?.name) || \"-\";\n const toolCallId = firstTrimmedString(event?.data?.toolCallId) || \"-\";\n return `stream=${stream} phase=${phase} runId=${getEventRunId(event) || \"-\"} ` +\n `sessionKey=${getEventSessionKey(event) || \"-\"} toolCallId=${toolCallId} toolName=${toolName}`;\n}\n\nexport function createDynamicAckReactionCorrelator(params: {\n sessionKey: string;\n enabled: boolean;\n createdAt: number;\n optimisticCaptureWindowMs: number;\n log?: DynamicAckReactionLogger;\n}) {\n let activeRunId: string | undefined;\n let correlationUnavailableLogged = false;\n let optimisticCaptureCount = 0;\n\n return (event: RuntimeAgentEvent | undefined): boolean => {\n const eventRunId = getEventRunId(event);\n const eventSessionKey = getEventSessionKey(event);\n const eventStream = firstTrimmedString(event?.stream) || \"\";\n const eventPhase = firstTrimmedString(event?.data?.phase) || \"\";\n\n if (activeRunId) {\n const matched = eventRunId === activeRunId;\n params.log?.debug?.(\n `[DingTalk] Dynamic reaction correlation by runId matched=${matched} activeRunId=${activeRunId} ` +\n `eventRunId=${eventRunId || \"-\"} eventSessionKey=${eventSessionKey || \"-\"}`,\n );\n return matched;\n }\n\n if (eventSessionKey === params.sessionKey) {\n if (eventRunId) {\n activeRunId = eventRunId;\n params.log?.debug?.(\n `[DingTalk] Dynamic reaction captured active runId=${activeRunId} from sessionKey=${params.sessionKey}`,\n );\n } else {\n params.log?.debug?.(\n `[DingTalk] Dynamic reaction correlated by sessionKey=${params.sessionKey} without runId`,\n );\n }\n return true;\n }\n\n if (\n optimisticCaptureCount === 0\n && eventStream === \"lifecycle\"\n && eventPhase === \"start\"\n && eventRunId\n && !eventSessionKey\n && Date.now() - params.createdAt <= params.optimisticCaptureWindowMs\n ) {\n optimisticCaptureCount += 1;\n activeRunId = eventRunId;\n params.log?.debug?.(\n `[DingTalk] Dynamic reaction optimistically captured active runId=${activeRunId} ` +\n `from first lifecycle event without sessionKey windowMs=${params.optimisticCaptureWindowMs}`,\n );\n return true;\n }\n\n if (!correlationUnavailableLogged && params.enabled) {\n correlationUnavailableLogged = true;\n params.log?.debug?.(\n `[DingTalk] Dynamic reaction ignored uncorrelated agent events; ` +\n `reason=${getErrorMessage(eventRunId || eventSessionKey || \"waiting for sessionKey/runId match\")}`,\n );\n }\n return false;\n };\n}\n", "function readToolArgString(args: unknown, keys: string[]): string | undefined {\n if (!args || typeof args !== \"object\") {\n return undefined;\n }\n const record = args as Record<string, unknown>;\n for (const key of keys) {\n const value = record[key];\n if (typeof value === \"string\" && value.trim()) {\n return value.trim();\n }\n }\n return undefined;\n}\n\n/**\n * Tool names here come from the runtime `onAgentEvent` tool-start payload.\n * The runtime does not expose a typed enum on this event surface yet,\n * so this mapping is intentionally best-effort and keeps a safe default.\n */\nexport function resolveToolProgressReaction(toolName: unknown, args: unknown): string {\n const normalizedToolName = typeof toolName === \"string\" ? toolName.trim().toLowerCase() : \"\";\n switch (normalizedToolName) {\n case \"bash\":\n case \"exec\":\n case \"process\": {\n const command = readToolArgString(args, [\"command\", \"cmd\"]);\n if (!command) {\n return \"\uD83D\uDEE0\uFE0F\";\n }\n if (/\\bbrew\\s+install\\s+/i.test(command) || /\\b(?:pnpm|npm|yarn)\\s+(?:add|install)\\s+/i.test(command)) {\n return \"\uD83D\uDCE6\";\n }\n if (/\\bwhich\\s+/i.test(command)) {\n return \"\uD83D\uDD0D\";\n }\n return \"\uD83D\uDEE0\uFE0F\";\n }\n case \"read\":\n case \"view\":\n return \"\uD83D\uDCC2\";\n case \"write\":\n case \"edit\":\n case \"patch\":\n return \"\u270D\uFE0F\";\n case \"web_search\":\n case \"search\":\n case \"browser.search\":\n case \"browser_search\":\n return \"\uD83C\uDF10\";\n case \"fetch\":\n case \"open\":\n case \"open_url\":\n case \"browser.open\":\n case \"browser_open\":\n return \"\uD83D\uDD17\";\n default:\n return \"\uD83D\uDEE0\uFE0F\";\n }\n}\n", "import { attachNativeAckReaction, recallNativeAckReactionWithRetry } from \"../ack-reaction-service\";\nimport type { DingTalkConfig } from \"../types\";\nimport { getErrorMessage } from \"../utils\";\nimport {\n createDynamicAckReactionCorrelator,\n describeEvent,\n type DynamicAckReactionLogger,\n type RuntimeAgentEvent,\n type RuntimeEventsSurface,\n} from \"./dynamic-ack-reaction-events\";\nimport { resolveToolProgressReaction } from \"./dynamic-ack-reaction-progress\";\n\ntype DynamicAckReactionControllerParams = {\n enabled: boolean;\n initialReaction: string;\n initialAttached: boolean;\n initialAttachedAt: number;\n dingtalkConfig: DingTalkConfig;\n msgId: string;\n conversationId: string;\n sessionKey: string;\n log?: DynamicAckReactionLogger;\n runtimeEvents?: RuntimeEventsSurface;\n onReactionDisposed?: () => void;\n};\n\nconst TOOL_REACTION_SILENCE_MS = 55_000;\nconst TOOL_REACTION_HEARTBEAT_INTERVAL_MS = 60_000;\nconst DYNAMIC_REACTION_MIN_SWITCH_INTERVAL_MS = 5_000;\nconst OPTIMISTIC_RUN_ID_CAPTURE_WINDOW_MS = 5_000;\nconst TOOL_HEARTBEAT_REACTION = \"\u23F3\";\n\nexport function createDynamicAckReactionController(params: DynamicAckReactionControllerParams) {\n let dynamicReactionStartedAt = 0;\n let lastDynamicReactionAt = 0;\n let currentAckReaction = params.initialReaction;\n let ackReactionAttached = params.initialAttached;\n let ackReactionAttachedAt = params.initialAttachedAt;\n let progressHeartbeatInFlight = false;\n let progressHeartbeatTimer: NodeJS.Timeout | undefined;\n let dynamicReactionUpdatePromise: Promise<void> = Promise.resolve();\n let lastDynamicReactionSwitchAt = 0;\n let disposed = false;\n const createdAt = Date.now();\n const isCorrelatedEvent = createDynamicAckReactionCorrelator({\n sessionKey: params.sessionKey,\n enabled: params.enabled,\n createdAt,\n optimisticCaptureWindowMs: OPTIMISTIC_RUN_ID_CAPTURE_WINDOW_MS,\n log: params.log,\n });\n\n const updateDynamicAckReaction = async (nextReaction: string) => {\n const normalizedReaction = typeof nextReaction === \"string\" ? nextReaction.trim() : \"\";\n if (disposed || !normalizedReaction || !params.enabled || !ackReactionAttached) {\n params.log?.debug?.(\n `[DingTalk] Dynamic ack reaction update skipped reaction=${normalizedReaction || \"-\"} ` +\n `enabled=${params.enabled} ackReactionAttached=${ackReactionAttached} disposed=${disposed}`,\n );\n return;\n }\n if (normalizedReaction === currentAckReaction) {\n params.log?.debug?.(\n `[DingTalk] Dynamic ack reaction update skipped because reaction is unchanged: ${normalizedReaction}`,\n );\n if (dynamicReactionStartedAt === 0) {\n dynamicReactionStartedAt = Date.now();\n }\n lastDynamicReactionAt = Date.now();\n return;\n }\n if (\n lastDynamicReactionSwitchAt > 0\n && Date.now() - lastDynamicReactionSwitchAt < DYNAMIC_REACTION_MIN_SWITCH_INTERVAL_MS\n ) {\n params.log?.debug?.(\n `[DingTalk] Dynamic ack reaction update throttled previous=${currentAckReaction} next=${normalizedReaction} ` +\n `minIntervalMs=${DYNAMIC_REACTION_MIN_SWITCH_INTERVAL_MS}`,\n );\n return;\n }\n\n const previousReaction = currentAckReaction;\n ackReactionAttached = false;\n await recallNativeAckReactionWithRetry(\n params.dingtalkConfig,\n {\n msgId: params.msgId,\n conversationId: params.conversationId,\n reactionName: previousReaction,\n },\n params.log,\n );\n\n const attached = await attachNativeAckReaction(\n params.dingtalkConfig,\n {\n msgId: params.msgId,\n conversationId: params.conversationId,\n reactionName: normalizedReaction,\n },\n params.log,\n );\n if (!attached) {\n if (disposed) {\n return;\n }\n params.log?.debug?.(\n `[DingTalk] Dynamic ack reaction attach did not succeed for reaction=${normalizedReaction}; restoring previous reaction=${previousReaction}`,\n );\n const restored = await attachNativeAckReaction(\n params.dingtalkConfig,\n {\n msgId: params.msgId,\n conversationId: params.conversationId,\n reactionName: previousReaction,\n },\n params.log,\n );\n ackReactionAttached = restored;\n if (restored) {\n currentAckReaction = previousReaction;\n ackReactionAttachedAt = Date.now();\n if (dynamicReactionStartedAt === 0) {\n dynamicReactionStartedAt = ackReactionAttachedAt;\n }\n lastDynamicReactionAt = ackReactionAttachedAt;\n }\n return;\n }\n\n params.log?.debug?.(`[DingTalk] Dynamic ack reaction switched to ${normalizedReaction}`);\n ackReactionAttached = true;\n currentAckReaction = normalizedReaction;\n ackReactionAttachedAt = Date.now();\n lastDynamicReactionSwitchAt = ackReactionAttachedAt;\n if (dynamicReactionStartedAt === 0) {\n dynamicReactionStartedAt = ackReactionAttachedAt;\n }\n lastDynamicReactionAt = ackReactionAttachedAt;\n };\n\n const queueDynamicAckReactionUpdate = (nextReaction: string) => {\n if (disposed) {\n return dynamicReactionUpdatePromise;\n }\n params.log?.debug?.(\n `[DingTalk] Queue dynamic ack reaction update ${currentAckReaction || \"-\"} -> ${nextReaction || \"-\"}`,\n );\n dynamicReactionUpdatePromise = dynamicReactionUpdatePromise\n .then(() => updateDynamicAckReaction(nextReaction))\n .catch((err: unknown) => {\n params.log?.warn?.(`[DingTalk] Dynamic ack reaction update failed: ${getErrorMessage(err)}`);\n });\n return dynamicReactionUpdatePromise;\n };\n\n const handleAgentEvent = async (event: unknown) => {\n const agentEvent = event as RuntimeAgentEvent | undefined;\n if (!params.enabled || disposed) {\n return;\n }\n params.log?.debug?.(`[DingTalk] Dynamic reaction observed agent event ${describeEvent(agentEvent)}`);\n if (agentEvent?.stream === \"lifecycle\" && agentEvent.data?.phase === \"start\") {\n void isCorrelatedEvent(agentEvent);\n return;\n }\n if (agentEvent?.stream !== \"tool\" || agentEvent.data?.phase !== \"start\") {\n return;\n }\n if (!isCorrelatedEvent(agentEvent)) {\n params.log?.debug?.(\n `[DingTalk] Dynamic reaction ignored uncorrelated tool event ${describeEvent(agentEvent)}`,\n );\n return;\n }\n const toolCallId = typeof agentEvent.data?.toolCallId === \"string\" ? agentEvent.data.toolCallId : \"-\";\n params.log?.debug?.(\n `[DingTalk] Tool event received for dynamic ack reaction: name=${agentEvent.data?.name || \"-\"} toolCallId=${toolCallId}`,\n );\n await queueDynamicAckReactionUpdate(\n resolveToolProgressReaction(agentEvent.data?.name, agentEvent.data?.args),\n );\n };\n\n const unsubscribeAgentEvents = params.enabled && params.runtimeEvents?.onAgentEvent\n ? params.runtimeEvents.onAgentEvent((event: unknown) => {\n void handleAgentEvent(event).catch((err: unknown) => {\n params.log?.warn?.(`[DingTalk] Dynamic ack reaction event handling failed: ${getErrorMessage(err)}`);\n });\n })\n : () => {};\n\n if (params.enabled && !params.runtimeEvents?.onAgentEvent) {\n params.log?.debug?.(\"[DingTalk] onAgentEvent not available, dynamic reaction tracking disabled\");\n }\n\n if (params.enabled) {\n progressHeartbeatTimer = setInterval(() => {\n if (\n disposed\n || !ackReactionAttached\n || progressHeartbeatInFlight\n || dynamicReactionStartedAt === 0\n || lastDynamicReactionAt === 0\n ) {\n return;\n }\n if (Date.now() - lastDynamicReactionAt < TOOL_REACTION_SILENCE_MS) {\n return;\n }\n params.log?.debug?.(\n `[DingTalk] Dynamic ack reaction heartbeat triggered currentReaction=${currentAckReaction} ` +\n `lastDynamicReactionAt=${lastDynamicReactionAt}`,\n );\n progressHeartbeatInFlight = true;\n void queueDynamicAckReactionUpdate(TOOL_HEARTBEAT_REACTION).finally(() => {\n progressHeartbeatInFlight = false;\n });\n }, TOOL_REACTION_HEARTBEAT_INTERVAL_MS);\n }\n\n const stop = (): void => {\n if (disposed) {\n return;\n }\n disposed = true;\n unsubscribeAgentEvents();\n if (progressHeartbeatTimer) {\n clearInterval(progressHeartbeatTimer);\n progressHeartbeatTimer = undefined;\n }\n };\n\n return {\n async awaitDrain(): Promise<void> {\n await dynamicReactionUpdatePromise.catch(() => undefined);\n },\n async dispose(minVisibleMs: number): Promise<void> {\n stop();\n await this.awaitDrain();\n if (!ackReactionAttached) {\n params.onReactionDisposed?.();\n return;\n }\n try {\n const shouldRespectMinVisible = params.enabled && dynamicReactionStartedAt > 0;\n const elapsedMs = ackReactionAttachedAt > 0 ? Date.now() - ackReactionAttachedAt : 0;\n const remainingVisibleMs = shouldRespectMinVisible ? minVisibleMs - elapsedMs : 0;\n if (remainingVisibleMs > 0) {\n await new Promise(resolve => setTimeout(resolve, remainingVisibleMs));\n }\n await recallNativeAckReactionWithRetry(\n params.dingtalkConfig,\n {\n msgId: params.msgId,\n conversationId: params.conversationId,\n reactionName: currentAckReaction,\n },\n params.log,\n );\n } catch (err: unknown) {\n params.log?.warn?.(`[DingTalk] Dynamic ack reaction dispose recall failed: ${getErrorMessage(err)}`);\n } finally {\n ackReactionAttached = false;\n params.onReactionDisposed?.();\n }\n },\n stop,\n };\n}\n", "export function formatTokenCount(n: number): string {\n if (n >= 1_000_000) {\n return `${(n / 1_000_000).toFixed(1)}M`;\n }\n if (n >= 1_000) {\n return `${(n / 1_000).toFixed(1)}k`;\n }\n return String(n);\n}\n\nexport function formatDuration(seconds: number): string {\n if (seconds < 60) {\n return `${seconds}s`;\n }\n const m = Math.floor(seconds / 60);\n const s = seconds % 60;\n return `${m}m ${s}s`;\n}\n\nexport interface StatusLineData {\n model?: string;\n effort?: string;\n agent?: string;\n taskTime?: number;\n inputTokens?: number;\n outputTokens?: number;\n cacheRead?: number;\n dapi_usage?: number;\n}\n\nexport interface StatusLineConfig {\n cardStatusLine?: {\n model?: boolean;\n effort?: boolean;\n agent?: boolean;\n taskTime?: boolean;\n tokens?: boolean;\n dapiUsage?: boolean;\n };\n}\n\ntype SegmentKey = \"model\" | \"effort\" | \"agent\" | \"tokens\" | \"taskTime\" | \"dapiUsage\";\n\ninterface Segment {\n key: SegmentKey;\n defaultOn: boolean;\n render: (d: StatusLineData) => string | undefined;\n}\n\nfunction renderTokenSegment(data: StatusLineData): string | undefined {\n const parts: string[] = [];\n if (typeof data.inputTokens === \"number\") {\n let s = `\u2191${formatTokenCount(data.inputTokens)}`;\n if (typeof data.cacheRead === \"number\" && data.cacheRead > 0) {\n s += `(C:${formatTokenCount(data.cacheRead)})`;\n }\n parts.push(s);\n }\n if (typeof data.outputTokens === \"number\") {\n parts.push(`\u2193${formatTokenCount(data.outputTokens)}`);\n }\n return parts.length > 0 ? parts.join(\" \") : undefined;\n}\n\nconst SEGMENTS: Segment[] = [\n { key: \"model\", defaultOn: true, render: (d) => d.model || undefined },\n { key: \"effort\", defaultOn: true, render: (d) => d.effort || undefined },\n { key: \"agent\", defaultOn: true, render: (d) => d.agent || undefined },\n { key: \"tokens\", defaultOn: false, render: renderTokenSegment },\n { key: \"taskTime\", defaultOn: false, render: (d) => typeof d.taskTime === \"number\" ? formatDuration(d.taskTime) : undefined },\n { key: \"dapiUsage\", defaultOn: false, render: (d) => typeof d.dapi_usage === \"number\" ? `DAPI+${d.dapi_usage}` : undefined },\n];\n\nconst SEGMENTS_PER_LINE = 3;\n\nfunction resolveSegmentEnabled(seg: Segment, config: StatusLineConfig): boolean {\n const value = config.cardStatusLine?.[seg.key];\n return typeof value === \"boolean\" ? value : seg.defaultOn;\n}\n\nexport function renderStatusLine(data: StatusLineData, config: StatusLineConfig): string {\n const rendered = SEGMENTS\n .filter((seg) => resolveSegmentEnabled(seg, config))\n .map((seg) => seg.render(data))\n .filter(Boolean) as string[];\n\n if (rendered.length === 0) { return \"\"; }\n\n const lines: string[] = [];\n for (let i = 0; i < rendered.length; i += SEGMENTS_PER_LINE) {\n lines.push(rendered.slice(i, i + SEGMENTS_PER_LINE).join(\" | \"));\n }\n return lines.join(\"\\n\");\n}\n", "import { normalizeAllowFrom, isSenderOwner } from \"./access-control\";\nimport type { DingTalkConfig } from \"./types\";\n\nexport interface ParsedLearnCommand {\n scope:\n | \"help\"\n | \"global\"\n | \"session\"\n | \"here\"\n | \"target\"\n | \"targets\"\n | \"list\"\n | \"disable\"\n | \"delete\"\n | \"whoami\"\n | \"whereami\"\n | \"owner-status\"\n | \"target-set-create\"\n | \"target-set-apply\"\n | \"unknown\";\n instruction?: string;\n ruleId?: string;\n targetId?: string;\n targetIds?: string[];\n setName?: string;\n}\n\nconst TARGET_DELIMITER = \"#@#\";\n\nexport function parseLearnCommand(text: string | undefined): ParsedLearnCommand {\n const raw = String(text || \"\").trim();\n if (!raw) {\n return { scope: \"unknown\" };\n }\n const normalized = raw.toLowerCase();\n if (\n normalized === \"/learn help\"\n ) {\n return { scope: \"help\" };\n }\n if (\n normalized === \"/learn whoami\"\n || normalized === \"/whoami\"\n || normalized === \"\u6211\u662F\u8C01\"\n || normalized === \"\u6211\u7684\u4FE1\u606F\"\n ) {\n return { scope: \"whoami\" };\n }\n if (\n normalized === \"/learn whereami\"\n || normalized === \"\u8FD9\u91CC\u662F\u8C01\"\n || normalized === \"\u8FD9\u4E2A\u7FA4\u662F\u8C01\"\n || normalized === \"\u8FD9\u4E2A\u4F1A\u8BDD\u662F\u8C01\"\n ) {\n return { scope: \"whereami\" };\n }\n if (\n normalized === \"/learn owner status\"\n || normalized === \"/owner status\"\n || normalized === \"/owner-status\"\n ) {\n return { scope: \"owner-status\" };\n }\n if (normalized === \"/learn list\") {\n return { scope: \"list\" };\n }\n if (normalized === \"/learn target-set list\") {\n return { scope: \"list\" };\n }\n if (normalized.startsWith(\"/learn disable \")) {\n const ruleId = raw.slice(\"/learn disable \".length).trim();\n return ruleId ? { scope: \"disable\", ruleId } : { scope: \"unknown\" };\n }\n if (normalized.startsWith(\"/learn delete \")) {\n const ruleId = raw.slice(\"/learn delete \".length).trim();\n return ruleId ? { scope: \"delete\", ruleId } : { scope: \"unknown\" };\n }\n if (normalized.startsWith(\"/learn global \")) {\n return { scope: \"global\", instruction: raw.slice(\"/learn global \".length).trim() };\n }\n if (normalized.startsWith(\"/learn session \")) {\n return { scope: \"session\", instruction: raw.slice(\"/learn session \".length).trim() };\n }\n if (normalized.startsWith(\"/learn here \")) {\n const rawInstruction = raw.slice(\"/learn here \".length).trim();\n const instruction = rawInstruction.startsWith(TARGET_DELIMITER)\n ? rawInstruction.slice(TARGET_DELIMITER.length).trim()\n : rawInstruction;\n return instruction ? { scope: \"here\", instruction } : { scope: \"unknown\" };\n }\n if (normalized.startsWith(\"/learn target-set create \")) {\n const payload = splitDelimitedPayload(raw.slice(\"/learn target-set create \".length));\n if (!payload) {\n return { scope: \"unknown\" };\n }\n const targetIds = parseTargetIds(payload.body);\n return payload.head && targetIds.length > 0\n ? { scope: \"target-set-create\", setName: payload.head, targetIds }\n : { scope: \"unknown\" };\n }\n if (normalized.startsWith(\"/learn target-set apply \")) {\n const payload = splitDelimitedPayload(raw.slice(\"/learn target-set apply \".length));\n return payload?.head && payload.body\n ? { scope: \"target-set-apply\", setName: payload.head, instruction: payload.body }\n : { scope: \"unknown\" };\n }\n if (normalized.startsWith(\"/learn target \")) {\n const payload = splitDelimitedPayload(raw.slice(\"/learn target \".length));\n return payload?.head && payload.body\n ? { scope: \"target\", targetId: payload.head, instruction: payload.body }\n : { scope: \"unknown\" };\n }\n if (normalized.startsWith(\"/learn targets \")) {\n const payload = splitDelimitedPayload(raw.slice(\"/learn targets \".length));\n if (!payload) {\n return { scope: \"unknown\" };\n }\n const targetIds = parseTargetIds(payload.head);\n return targetIds.length > 0 && payload.body\n ? { scope: \"targets\", targetIds, instruction: payload.body }\n : { scope: \"unknown\" };\n }\n return { scope: \"unknown\" };\n}\n\nfunction splitDelimitedPayload(raw: string): { head: string; body: string } | null {\n const index = raw.indexOf(TARGET_DELIMITER);\n if (index < 0) {\n return null;\n }\n const head = raw.slice(0, index).trim();\n const body = raw.slice(index + TARGET_DELIMITER.length).trim();\n if (!head || !body) {\n return null;\n }\n return { head, body };\n}\n\nfunction parseTargetIds(raw: string): string[] {\n return raw\n .split(\",\")\n .map((item) => item.trim())\n .filter(Boolean);\n}\n\nexport function isLearningOwner(params: {\n cfg?: { commands?: { ownerAllowFrom?: Array<string | number> } };\n config?: DingTalkConfig;\n senderId?: string;\n rawSenderId?: string;\n}): boolean {\n const allow = normalizeAllowFrom(params.cfg?.commands?.ownerAllowFrom as string[] | undefined);\n return isSenderOwner({ allow, senderId: params.senderId, rawSenderId: params.rawSenderId });\n}\n\nexport function formatWhoAmIReply(params: {\n senderId: string;\n rawSenderId?: string;\n senderStaffId?: string;\n isOwner?: boolean;\n}): string {\n return [\n \"\u8FD9\u662F\u4F60\u5F53\u524D\u6D88\u606F\u5BF9\u5E94\u7684\u8EAB\u4EFD\u4FE1\u606F\uFF1A\",\n \"\",\n `- senderId: \\`${params.senderId || \"\"}\\``,\n `- rawSenderId: \\`${params.rawSenderId || \"\"}\\``,\n `- senderStaffId: \\`${params.senderStaffId || \"\"}\\``,\n `- isOwner: \\`${params.isOwner ? \"true\" : \"false\"}\\``,\n \"\",\n \"\u540E\u7EED\u5982\u679C\u8981\u914D\u7F6E owner \u6216\u63A7\u5236\u547D\u4EE4\u6743\u9650\uFF0C\u5C31\u4EE5\u8FD9\u91CC\u8FD4\u56DE\u7684 senderId \u4E3A\u51C6\u3002\",\n ].join(\"\\n\");\n}\n\nexport function formatWhereAmIReply(params: {\n conversationId: string;\n conversationType: \"group\" | \"dm\";\n peerId?: string;\n}): string {\n return [\n params.conversationType === \"group\" ? \"\u8FD9\u662F\u5F53\u524D\u7FA4\u804A\u4FE1\u606F\uFF1A\" : \"\u8FD9\u662F\u5F53\u524D\u4F1A\u8BDD\u4FE1\u606F\uFF1A\",\n \"\",\n `- conversationId: \\`${params.conversationId}\\``,\n `- conversationType: \\`${params.conversationType}\\``,\n params.peerId ? `- peerId: \\`${params.peerId}\\`` : undefined,\n \"\",\n \"\u540E\u7EED\u5982\u679C\u8981\u5B9A\u5411\u6CE8\u5165\u5230\u8FD9\u91CC\uFF0C\u5C31\u4F7F\u7528\u8FD9\u4E2A conversationId\u3002\",\n ].filter(Boolean).join(\"\\n\");\n}\n\nexport function formatOwnerStatusReply(params: {\n senderId: string;\n rawSenderId?: string;\n isOwner: boolean;\n}): string {\n return [\n \"\u5F53\u524D owner \u63A7\u5236\u72B6\u6001\uFF1A\",\n \"\",\n `- senderId: \\`${params.senderId || \"\"}\\``,\n `- rawSenderId: \\`${params.rawSenderId || \"\"}\\``,\n `- isOwner: \\`${params.isOwner ? \"true\" : \"false\"}\\``,\n \"\",\n \"\u5982\u679C\u9700\u8981\u53D8\u66F4 owner\uFF0C\u8BF7\u7531\u5BBF\u4E3B\u4FEE\u6539\u672C\u673A\u8FD0\u884C\u914D\u7F6E\u3002\",\n ].join(\"\\n\");\n}\n\nexport function formatOwnerOnlyDeniedReply(): string {\n return \"\u8FD9\u6761\u5B66\u4E60/\u63A7\u5236\u547D\u4EE4\u4EC5\u5141\u8BB8 owner \u4F7F\u7528\u3002\u5148\u53D1\u9001\u201C\u6211\u662F\u8C01\u201D\u786E\u8BA4\u4F60\u7684 senderId\uFF0C\u518D\u7531\u5BBF\u4E3B\u5C06\u8BE5 senderId \u52A0\u5165 commands.ownerAllowFrom\u3002\";\n}\n\nexport function formatLearnCommandHelp(): string {\n return [\n \"\u53EF\u7528\u7684 owner \u5B66\u4E60\u547D\u4EE4\uFF1A\",\n \"\",\n \"- /learn whoami\uFF1A\u67E5\u770B\u5F53\u524D senderId\",\n \"- /learn owner status\uFF1A\u67E5\u770B\u5F53\u524D owner \u6743\u9650\u72B6\u6001\",\n \"- /learn whereami\uFF1A\u67E5\u770B\u5F53\u524D\u4F1A\u8BDD/\u7FA4 ID\",\n \"- /learn global <\u89C4\u5219>\uFF1A\u53D1\u5E03\u5230\u5F53\u524D\u9489\u9489\u8D26\u53F7\u4E0B\u6240\u6709\u4F1A\u8BDD\",\n \"- /learn session <\u89C4\u5219>\uFF1A\u4EC5\u53D1\u5E03\u5230\u5F53\u524D\u79C1\u804A\u4F1A\u8BDD\",\n \"- /learn here #@# <\u89C4\u5219>\uFF1A\u53D1\u5E03\u5230\u5F53\u524D\u7FA4/\u5F53\u524D\u79C1\u804A\",\n \"- /learn target <conversationId> #@# <\u89C4\u5219>\uFF1A\u53D1\u5E03\u5230\u5355\u4E2A\u6307\u5B9A\u7FA4/\u79C1\u804A\",\n \"- /learn targets <conversationId1,conversationId2> #@# <\u89C4\u5219>\uFF1A\u4E00\u6B21\u53D1\u5E03\u5230\u591A\u4E2A\u6307\u5B9A\u7FA4/\u79C1\u804A\",\n \"- /learn target-set create <\u540D\u79F0> #@# <conversationId1,conversationId2>\uFF1A\u4FDD\u5B58\u4E00\u7EC4\u56FA\u5B9A\u76EE\u6807\",\n \"- /learn target-set apply <\u540D\u79F0> #@# <\u89C4\u5219>\uFF1A\u5411\u4E00\u4E2A\u76EE\u6807\u7EC4\u6279\u91CF\u53D1\u5E03\u89C4\u5219\",\n \"- /learn list\uFF1A\u67E5\u770B\u5F53\u524D\u5168\u5C40\u89C4\u5219\u3001\u76EE\u6807\u89C4\u5219\u4E0E\u76EE\u6807\u7EC4\u6458\u8981\",\n \"- /learn disable <ruleId>\uFF1A\u505C\u7528\u4E00\u6761\u89C4\u5219\uFF0C\u505C\u6B62\u7EE7\u7EED\u547D\u4E2D\uFF0C\u4F46\u4FDD\u7559\u8BB0\u5F55\",\n \"- /learn delete <ruleId>\uFF1A\u5F7B\u5E95\u5220\u9664\u4E00\u6761\u89C4\u5219\u6216\u76EE\u6807\u89C4\u5219\",\n \"\",\n \"\u53EF\u7528\u7684 owner \u4F1A\u8BDD\u63A7\u5236\u547D\u4EE4\uFF1A\",\n \"- /session-alias show\uFF1A\u67E5\u770B\u5F53\u524D\u4F1A\u8BDD\u5171\u4EAB\u4F1A\u8BDD\u522B\u540D\",\n \"- /session-alias set <alias>\uFF1A\u5C06\u5F53\u524D\u4F1A\u8BDD\u7ED1\u5B9A\u5230\u6307\u5B9A\u5171\u4EAB\u4F1A\u8BDD\u522B\u540D\",\n \"- /session-alias clear\uFF1A\u6E05\u9664\u5F53\u524D\u4F1A\u8BDD\u5171\u4EAB\u4F1A\u8BDD\u522B\u540D\uFF0C\u6062\u590D\u4E3A\u9ED8\u8BA4 peerId\",\n \"- /session-alias bind direct <senderId> <alias>\uFF1A\u7531 owner \u8FDC\u7A0B\u7ED1\u5B9A\u67D0\u4E2A\u79C1\u804A senderId\",\n \"- /session-alias bind group <conversationId> <alias>\uFF1A\u7531 owner \u8FDC\u7A0B\u7ED1\u5B9A\u67D0\u4E2A\u7FA4 conversationId\",\n \"- /session-alias unbind direct <senderId>\uFF1A\u7531 owner \u8FDC\u7A0B\u89E3\u9664\u67D0\u4E2A\u79C1\u804A senderId \u7ED1\u5B9A\",\n \"- /session-alias unbind group <conversationId>\uFF1A\u7531 owner \u8FDC\u7A0B\u89E3\u9664\u67D0\u4E2A\u7FA4 conversationId \u7ED1\u5B9A\",\n \"\",\n \"\u6743\u9650\u8BF4\u660E\uFF1A\",\n \"- \u53EA\u6709 owner \u624D\u80FD\u771F\u6B63\u6267\u884C /learn \u7684\u5199\u64CD\u4F5C\u548C\u63A7\u5236\u64CD\u4F5C\u3002\",\n \"- \u5982\u679C\u4F60\u73B0\u5728\u4E0D\u662F owner\uFF0C\u4E5F\u53EF\u4EE5\u5148\u7528 `/learn whoami` \u67E5\u770B senderId\uFF0C\u518D\u7531\u5BBF\u4E3B\u628A\u5B83\u52A0\u5165 commands.ownerAllowFrom\u3002\",\n ].join(\"\\n\");\n}\nexport function formatLearnAppliedReply(params: {\n scope: \"global\" | \"session\" | \"target\" | \"targets\" | \"target-set\";\n instruction: string;\n ruleId?: string;\n targetId?: string;\n targetIds?: string[];\n setName?: string;\n}): string {\n const scopeLine = params.scope === \"global\"\n ? \"- \u751F\u6548\u8303\u56F4\uFF1A\u540C\u4E00\u9489\u9489\u8D26\u53F7\u4E0B\u6240\u6709\u4F1A\u8BDD\uFF0C\u5C06\u5728\u4E0B\u4E00\u6761\u6D88\u606F\u8FDB\u5165\u65F6\u81EA\u52A8\u52A0\u8F7D\"\n : params.scope === \"session\"\n ? \"- \u751F\u6548\u8303\u56F4\uFF1A\u5F53\u524D\u4F1A\u8BDD\uFF0C\u5C06\u5728\u4E0B\u4E00\u6761\u6D88\u606F\u8FDB\u5165\u65F6\u81EA\u52A8\u52A0\u8F7D\"\n : params.scope === \"target\"\n ? `- \u751F\u6548\u8303\u56F4\uFF1A\u6307\u5B9A\u76EE\u6807 \\`${params.targetId}\\``\n : params.scope === \"targets\"\n ? `- \u751F\u6548\u8303\u56F4\uFF1A${params.targetIds?.length || 0} \u4E2A\u76EE\u6807`\n : `- \u751F\u6548\u8303\u56F4\uFF1A\u76EE\u6807\u7EC4 \\`${params.setName}\\``;\n return [\n params.scope === \"global\"\n ? \"\u5DF2\u6CE8\u5165\u5168\u5C40\u77E5\u8BC6\u3002\"\n : params.scope === \"session\"\n ? \"\u5DF2\u6CE8\u5165\u5F53\u524D\u4F1A\u8BDD\u77E5\u8BC6\u3002\"\n : params.scope === \"target\"\n ? \"\u5DF2\u6CE8\u5165\u6307\u5B9A\u76EE\u6807\u77E5\u8BC6\u3002\"\n : params.scope === \"targets\"\n ? \"\u5DF2\u6279\u91CF\u6CE8\u5165\u591A\u4E2A\u76EE\u6807\u3002\"\n : \"\u5DF2\u5411\u76EE\u6807\u7EC4\u6279\u91CF\u6CE8\u5165\u89C4\u5219\u3002\",\n \"\",\n params.ruleId ? `- ruleId: \\`${params.ruleId}\\`` : undefined,\n `- instruction: ${params.instruction}`,\n scopeLine,\n ].filter(Boolean).join(\"\\n\");\n}\n\nexport function formatLearnListReply(lines: string[]): string {\n if (lines.length === 0) {\n return \"\u5F53\u524D\u8FD8\u6CA1\u6709\u89C4\u5219\u6216\u76EE\u6807\u7EC4\u3002\";\n }\n return [\"\u5F53\u524D\u89C4\u5219\u4E0E\u76EE\u6807\u7EC4\u6458\u8981\uFF1A\", \"\", ...lines].join(\"\\n\");\n}\n\nexport function formatLearnDisabledReply(params: {\n ruleId: string;\n existed: boolean;\n scope?: \"global\" | \"target\";\n targetId?: string;\n}): string {\n if (!params.existed) {\n return [\n \"\u672A\u627E\u5230\u5BF9\u5E94\u89C4\u5219\u3002\",\n \"\",\n `- ruleId: \\`${params.ruleId}\\``,\n \"\u53EF\u5148\u4F7F\u7528 `/learn list` \u67E5\u770B\u5F53\u524D\u53EF\u505C\u7528\u7684\u89C4\u5219\u3002\",\n ].join(\"\\n\");\n }\n return [\n \"\u5DF2\u505C\u7528\u89C4\u5219\u3002\",\n \"\",\n `- ruleId: \\`${params.ruleId}\\``,\n params.scope === \"target\" && params.targetId ? `- scope: target (\\`${params.targetId}\\`)` : \"- scope: global\",\n \"- \u5F53\u524D\u6548\u679C\uFF1A\u8FD9\u6761\u89C4\u5219\u4F1A\u505C\u6B62\u751F\u6548\uFF0C\u4F46\u8BB0\u5F55\u4ECD\u4F1A\u4FDD\u7559\uFF0C\u4FBF\u4E8E\u540E\u7EED\u6392\u67E5\u6216\u6062\u590D\u3002\",\n ].join(\"\\n\");\n}\n\nexport function formatLearnDeletedReply(params: {\n ruleId: string;\n existed: boolean;\n scope?: \"global\" | \"target\";\n targetId?: string;\n}): string {\n if (!params.existed) {\n return [\n \"\u672A\u627E\u5230\u5BF9\u5E94\u89C4\u5219\u3002\",\n \"\",\n `- ruleId: \\`${params.ruleId}\\``,\n \"\u53EF\u5148\u4F7F\u7528 `/learn list` \u67E5\u770B\u5F53\u524D\u89C4\u5219\u3002\",\n ].join(\"\\n\");\n }\n return [\n \"\u5DF2\u5220\u9664\u89C4\u5219\u3002\",\n \"\",\n `- ruleId: \\`${params.ruleId}\\``,\n params.scope === \"target\" && params.targetId ? `- scope: target (\\`${params.targetId}\\`)` : \"- scope: global\",\n ].join(\"\\n\");\n}\n\nexport function formatTargetSetSavedReply(params: {\n setName: string;\n targetIds: string[];\n}): string {\n return [\n \"\u5DF2\u4FDD\u5B58\u76EE\u6807\u7EC4\u3002\",\n \"\",\n `- name: \\`${params.setName}\\``,\n `- targetCount: \\`${params.targetIds.length}\\``,\n `- targetIds: ${params.targetIds.map((targetId) => `\\`${targetId}\\``).join(\", \")}`,\n ].join(\"\\n\");\n}\n", "export interface ParsedSessionCommand {\n scope:\n | \"session-alias-show\"\n | \"session-alias-set\"\n | \"session-alias-clear\"\n | \"session-alias-bind\"\n | \"session-alias-unbind\"\n | \"unknown\";\n peerId?: string;\n sourceKind?: \"direct\" | \"group\";\n sourceId?: string;\n}\n\nconst SESSION_ALIAS_PATTERN = /^[a-zA-Z0-9_-]{1,64}$/;\n\nexport function parseSessionCommand(text: string | undefined): ParsedSessionCommand {\n const raw = String(text || \"\").trim();\n if (!raw) {\n return { scope: \"unknown\" };\n }\n const sessionAliasBindMatch = raw.match(/^\\/session-alias\\s+(bind|unbind)\\s+(direct|group)\\s+(\\S+)(?:\\s+(.+))?$/i);\n if (sessionAliasBindMatch) {\n const action = sessionAliasBindMatch[1]?.toLowerCase();\n const sourceKind = sessionAliasBindMatch[2]?.toLowerCase() as \"direct\" | \"group\";\n const sourceId = sessionAliasBindMatch[3]?.trim();\n const rawPeerId = sessionAliasBindMatch[4]?.trim();\n if (action === \"bind\") {\n return sourceId && rawPeerId\n ? { scope: \"session-alias-bind\", sourceKind, sourceId, peerId: rawPeerId }\n : { scope: \"unknown\" };\n }\n if (action === \"unbind\") {\n return sourceId\n ? { scope: \"session-alias-unbind\", sourceKind, sourceId }\n : { scope: \"unknown\" };\n }\n }\n const sessionAliasMatch = raw.match(/^\\/session-alias\\s+(show|clear|set)(?:\\s+(.+))?$/i);\n if (!sessionAliasMatch) {\n return { scope: \"unknown\" };\n }\n const action = sessionAliasMatch[1]?.toLowerCase();\n const rawPeerId = sessionAliasMatch[2]?.trim();\n if (action === \"show\") {\n return { scope: \"session-alias-show\" };\n }\n if (action === \"clear\") {\n return { scope: \"session-alias-clear\" };\n }\n if (action === \"set\") {\n return rawPeerId ? { scope: \"session-alias-set\", peerId: rawPeerId } : { scope: \"unknown\" };\n }\n return { scope: \"unknown\" };\n}\n\nexport function validateSessionAlias(peerId: string | undefined): string | null {\n const value = String(peerId || \"\").trim();\n if (!value) {\n return \"\u5171\u4EAB\u4F1A\u8BDD\u522B\u540D\u4E0D\u80FD\u4E3A\u7A7A\u3002\";\n }\n if (!SESSION_ALIAS_PATTERN.test(value)) {\n return \"\u5171\u4EAB\u4F1A\u8BDD\u522B\u540D\u4EC5\u5141\u8BB8 [a-zA-Z0-9_-]{1,64}\u3002\";\n }\n return null;\n}\n\nexport function formatSessionAliasReply(params: {\n sourceKind: \"direct\" | \"group\";\n sourceId: string;\n peerId: string;\n aliasSource: \"default\" | \"override\";\n}): string {\n return [\n \"\u5F53\u524D\u4F1A\u8BDD\u522B\u540D\uFF1A\",\n \"\",\n `- source: \\`${params.sourceKind}\\``,\n `- sourceId: \\`${params.sourceId}\\``,\n `- peerId: \\`${params.peerId}\\``,\n `- mode: \\`${params.aliasSource}\\``,\n ].join(\"\\n\");\n}\n\nexport function formatSessionAliasSetReply(params: {\n sourceKind: \"direct\" | \"group\";\n sourceId: string;\n peerId: string;\n}): string {\n return [\n \"\u5DF2\u66F4\u65B0\u5F53\u524D\u4F1A\u8BDD\u5171\u4EAB\u4F1A\u8BDD\u522B\u540D\u3002\",\n \"\",\n `- source: \\`${params.sourceKind}\\``,\n `- sourceId: \\`${params.sourceId}\\``,\n `- peerId: \\`${params.peerId}\\``,\n \"\",\n \"\u5C06\u5176\u4ED6\u79C1\u804A\u6216\u7FA4\u4E5F\u8BBE\u7F6E\u4E3A\u540C\u4E00\u4E2A peerId \u540E\uFF0C\u8FD9\u4E9B\u4F1A\u8BDD\u4F1A\u5171\u7528\u540C\u4E00\u6761\u4F1A\u8BDD\u3002\",\n ].join(\"\\n\");\n}\n\nexport function formatSessionAliasValidationErrorReply(error: string): string {\n return [\n \"\u5171\u4EAB\u4F1A\u8BDD\u522B\u540D\u4E0D\u5408\u6CD5\u3002\",\n \"\",\n `- \u539F\u56E0\uFF1A${error}`,\n \"- \u5141\u8BB8\u89C4\u5219\uFF1A`[a-zA-Z0-9_-]{1,64}`\",\n \"- \u793A\u4F8B\uFF1A`shared-dev`\u3001`ops_shared`\",\n ].join(\"\\n\");\n}\n\nexport function formatSessionAliasClearedReply(params: {\n sourceKind: \"direct\" | \"group\";\n sourceId: string;\n}): string {\n return [\n \"\u5DF2\u6E05\u9664\u5F53\u524D\u4F1A\u8BDD\u5171\u4EAB\u4F1A\u8BDD\u522B\u540D\u3002\",\n \"\",\n `- source: \\`${params.sourceKind}\\``,\n `- sourceId: \\`${params.sourceId}\\``,\n `- peerId: \u6062\u590D\u4E3A\u5F53\u524D${params.sourceKind === \"direct\" ? \" senderId\" : \" conversationId\"}`,\n ].join(\"\\n\");\n}\n\nexport function formatSessionAliasBoundReply(params: {\n sourceKind: \"direct\" | \"group\";\n sourceId: string;\n peerId: string;\n}): string {\n return [\n \"\u5DF2\u7ED1\u5B9A\u5171\u4EAB\u4F1A\u8BDD\u522B\u540D\u3002\",\n \"\",\n `- source: \\`${params.sourceKind}\\``,\n `- sourceId: \\`${params.sourceId}\\``,\n `- peerId: \\`${params.peerId}\\``,\n ].join(\"\\n\");\n}\n\nexport function formatSessionAliasUnboundReply(params: {\n sourceKind: \"direct\" | \"group\";\n sourceId: string;\n existed: boolean;\n}): string {\n return [\n params.existed ? \"\u5DF2\u89E3\u9664\u5171\u4EAB\u4F1A\u8BDD\u522B\u540D\u7ED1\u5B9A\u3002\" : \"\u672A\u627E\u5230\u5BF9\u5E94\u7684\u5171\u4EAB\u4F1A\u8BDD\u522B\u540D\u7ED1\u5B9A\u3002\",\n \"\",\n `- source: \\`${params.sourceKind}\\``,\n `- sourceId: \\`${params.sourceId}\\``,\n ].join(\"\\n\");\n}\n", "import {\n applyManualGlobalLearningRule,\n applyManualSessionLearningNote,\n applyManualTargetLearningRule,\n applyManualTargetsLearningRule,\n applyTargetSetLearningRule,\n createOrUpdateTargetSet,\n deleteManualRule,\n disableManualRule,\n listLearningTargetSets,\n listScopedLearningRules,\n resolveManualForcedReply,\n} from \"../feedback-learning-service\";\nimport {\n formatLearnAppliedReply,\n formatLearnCommandHelp,\n formatLearnDeletedReply,\n formatLearnDisabledReply,\n formatLearnListReply,\n formatOwnerOnlyDeniedReply,\n formatOwnerStatusReply,\n formatTargetSetSavedReply,\n formatWhereAmIReply,\n formatWhoAmIReply,\n isLearningOwner,\n parseLearnCommand,\n} from \"../learning-command-service\";\nimport {\n formatSessionAliasBoundReply,\n formatSessionAliasClearedReply,\n formatSessionAliasReply,\n formatSessionAliasSetReply,\n formatSessionAliasUnboundReply,\n formatSessionAliasValidationErrorReply,\n parseSessionCommand,\n validateSessionAlias,\n} from \"../session-command-service\";\nimport type { SessionPeerSourceKind } from \"../session-peer-store\";\nimport type { DingTalkConfig, HandleDingTalkMessageParams, MessageContent } from \"../types\";\n\ntype InboundCommandDispatchParams = {\n cfg: HandleDingTalkMessageParams[\"cfg\"];\n accountId: string;\n dingtalkConfig: DingTalkConfig;\n senderId: string;\n isDirect: boolean;\n extractedText: string;\n messageType: MessageContent[\"messageType\"];\n data: {\n conversationId: string;\n senderId?: string;\n senderStaffId?: string;\n };\n accountStorePath: string;\n currentSessionSourceKind: SessionPeerSourceKind;\n currentSessionSourceId: string;\n peerIdOverride?: string;\n sessionPeer: {\n peerId: string;\n };\n sendReply: (text: string) => Promise<void>;\n clearSessionPeerOverride: (params: {\n storePath: string;\n accountId: string;\n sourceKind: SessionPeerSourceKind;\n sourceId: string;\n }) => boolean;\n setSessionPeerOverride: (params: {\n storePath: string;\n accountId: string;\n sourceKind: SessionPeerSourceKind;\n sourceId: string;\n peerId: string;\n }) => void;\n};\n\nexport async function handleInboundCommandDispatch(\n params: InboundCommandDispatchParams,\n): Promise<boolean> {\n const parsedLearnCommand = parseLearnCommand(params.extractedText);\n const parsedSessionCommand = parseSessionCommand(params.extractedText);\n const isOwner = isLearningOwner({\n cfg: params.cfg,\n config: params.dingtalkConfig,\n senderId: params.senderId,\n rawSenderId: params.data.senderId,\n });\n\n if (params.isDirect && parsedLearnCommand.scope === \"whoami\") {\n await params.sendReply(\n formatWhoAmIReply({\n senderId: params.senderId,\n rawSenderId: params.data.senderId,\n senderStaffId: params.data.senderStaffId,\n isOwner,\n }),\n );\n return true;\n }\n\n if (parsedLearnCommand.scope === \"whereami\") {\n await params.sendReply(\n formatWhereAmIReply({\n conversationId: params.data.conversationId,\n conversationType: params.isDirect ? \"dm\" : \"group\",\n peerId: params.sessionPeer.peerId,\n }),\n );\n return true;\n }\n\n if (params.isDirect && parsedLearnCommand.scope === \"owner-status\") {\n await params.sendReply(\n formatOwnerStatusReply({\n senderId: params.senderId,\n rawSenderId: params.data.senderId,\n isOwner,\n }),\n );\n return true;\n }\n\n if (parsedLearnCommand.scope === \"help\") {\n await params.sendReply(formatLearnCommandHelp());\n return true;\n }\n\n if (\n (parsedLearnCommand.scope === \"global\" ||\n parsedLearnCommand.scope === \"session\" ||\n parsedLearnCommand.scope === \"here\" ||\n parsedLearnCommand.scope === \"target\" ||\n parsedLearnCommand.scope === \"targets\" ||\n parsedLearnCommand.scope === \"list\" ||\n parsedLearnCommand.scope === \"disable\" ||\n parsedLearnCommand.scope === \"delete\" ||\n parsedLearnCommand.scope === \"target-set-create\" ||\n parsedLearnCommand.scope === \"target-set-apply\" ||\n parsedSessionCommand.scope === \"session-alias-show\" ||\n parsedSessionCommand.scope === \"session-alias-set\" ||\n parsedSessionCommand.scope === \"session-alias-clear\" ||\n parsedSessionCommand.scope === \"session-alias-bind\" ||\n parsedSessionCommand.scope === \"session-alias-unbind\") &&\n !isOwner\n ) {\n await params.sendReply(formatOwnerOnlyDeniedReply());\n return true;\n }\n\n if (isOwner) {\n if (parsedSessionCommand.scope === \"session-alias-show\") {\n await params.sendReply(\n formatSessionAliasReply({\n sourceKind: params.currentSessionSourceKind,\n sourceId: params.currentSessionSourceId,\n peerId: params.sessionPeer.peerId,\n aliasSource: params.peerIdOverride ? \"override\" : \"default\",\n }),\n );\n return true;\n }\n\n if (parsedSessionCommand.scope === \"session-alias-set\" && parsedSessionCommand.peerId) {\n const aliasValidationError = validateSessionAlias(parsedSessionCommand.peerId);\n if (aliasValidationError) {\n await params.sendReply(formatSessionAliasValidationErrorReply(aliasValidationError));\n return true;\n }\n params.setSessionPeerOverride({\n storePath: params.accountStorePath,\n accountId: params.accountId,\n sourceKind: params.currentSessionSourceKind,\n sourceId: params.currentSessionSourceId,\n peerId: parsedSessionCommand.peerId,\n });\n await params.sendReply(\n formatSessionAliasSetReply({\n sourceKind: params.currentSessionSourceKind,\n sourceId: params.currentSessionSourceId,\n peerId: parsedSessionCommand.peerId,\n }),\n );\n return true;\n }\n\n if (parsedSessionCommand.scope === \"session-alias-clear\") {\n params.clearSessionPeerOverride({\n storePath: params.accountStorePath,\n accountId: params.accountId,\n sourceKind: params.currentSessionSourceKind,\n sourceId: params.currentSessionSourceId,\n });\n await params.sendReply(\n formatSessionAliasClearedReply({\n sourceKind: params.currentSessionSourceKind,\n sourceId: params.currentSessionSourceId,\n }),\n );\n return true;\n }\n\n if (\n parsedSessionCommand.scope === \"session-alias-bind\" &&\n parsedSessionCommand.sourceKind &&\n parsedSessionCommand.sourceId &&\n parsedSessionCommand.peerId\n ) {\n const aliasValidationError = validateSessionAlias(parsedSessionCommand.peerId);\n if (aliasValidationError) {\n await params.sendReply(formatSessionAliasValidationErrorReply(aliasValidationError));\n return true;\n }\n params.setSessionPeerOverride({\n storePath: params.accountStorePath,\n accountId: params.accountId,\n sourceKind: parsedSessionCommand.sourceKind,\n sourceId: parsedSessionCommand.sourceId,\n peerId: parsedSessionCommand.peerId,\n });\n await params.sendReply(\n formatSessionAliasBoundReply({\n sourceKind: parsedSessionCommand.sourceKind,\n sourceId: parsedSessionCommand.sourceId,\n peerId: parsedSessionCommand.peerId,\n }),\n );\n return true;\n }\n\n if (\n parsedSessionCommand.scope === \"session-alias-unbind\" &&\n parsedSessionCommand.sourceKind &&\n parsedSessionCommand.sourceId\n ) {\n const existed = params.clearSessionPeerOverride({\n storePath: params.accountStorePath,\n accountId: params.accountId,\n sourceKind: parsedSessionCommand.sourceKind,\n sourceId: parsedSessionCommand.sourceId,\n });\n await params.sendReply(\n formatSessionAliasUnboundReply({\n sourceKind: parsedSessionCommand.sourceKind,\n sourceId: parsedSessionCommand.sourceId,\n existed,\n }),\n );\n return true;\n }\n\n if (parsedLearnCommand.scope === \"global\" && parsedLearnCommand.instruction) {\n const applied = applyManualGlobalLearningRule({\n storePath: params.accountStorePath,\n accountId: params.accountId,\n instruction: parsedLearnCommand.instruction,\n });\n await params.sendReply(\n formatLearnAppliedReply({\n scope: \"global\",\n instruction: parsedLearnCommand.instruction,\n ruleId: applied?.ruleId,\n }),\n );\n return true;\n }\n\n if (parsedLearnCommand.scope === \"session\" && parsedLearnCommand.instruction) {\n applyManualSessionLearningNote({\n storePath: params.accountStorePath,\n accountId: params.accountId,\n targetId: params.data.conversationId,\n instruction: parsedLearnCommand.instruction,\n });\n await params.sendReply(\n formatLearnAppliedReply({\n scope: \"session\",\n instruction: parsedLearnCommand.instruction,\n }),\n );\n return true;\n }\n\n if (parsedLearnCommand.scope === \"here\" && parsedLearnCommand.instruction) {\n const applied = applyManualTargetLearningRule({\n storePath: params.accountStorePath,\n accountId: params.accountId,\n targetId: params.data.conversationId,\n instruction: parsedLearnCommand.instruction,\n });\n await params.sendReply(\n formatLearnAppliedReply({\n scope: \"target\",\n targetId: params.data.conversationId,\n instruction: parsedLearnCommand.instruction,\n ruleId: applied?.ruleId,\n }),\n );\n return true;\n }\n\n if (\n parsedLearnCommand.scope === \"target\" &&\n parsedLearnCommand.targetId &&\n parsedLearnCommand.instruction\n ) {\n const applied = applyManualTargetLearningRule({\n storePath: params.accountStorePath,\n accountId: params.accountId,\n targetId: parsedLearnCommand.targetId,\n instruction: parsedLearnCommand.instruction,\n });\n await params.sendReply(\n formatLearnAppliedReply({\n scope: \"target\",\n targetId: parsedLearnCommand.targetId,\n instruction: parsedLearnCommand.instruction,\n ruleId: applied?.ruleId,\n }),\n );\n return true;\n }\n\n if (\n parsedLearnCommand.scope === \"targets\" &&\n parsedLearnCommand.targetIds?.length &&\n parsedLearnCommand.instruction\n ) {\n const applied = applyManualTargetsLearningRule({\n storePath: params.accountStorePath,\n accountId: params.accountId,\n targetIds: parsedLearnCommand.targetIds,\n instruction: parsedLearnCommand.instruction,\n });\n await params.sendReply(\n formatLearnAppliedReply({\n scope: \"targets\",\n targetIds: parsedLearnCommand.targetIds,\n instruction: parsedLearnCommand.instruction,\n ruleId: applied[0]?.ruleId,\n }),\n );\n return true;\n }\n\n if (\n parsedLearnCommand.scope === \"target-set-create\" &&\n parsedLearnCommand.setName &&\n parsedLearnCommand.targetIds?.length\n ) {\n const saved = createOrUpdateTargetSet({\n storePath: params.accountStorePath,\n accountId: params.accountId,\n name: parsedLearnCommand.setName,\n targetIds: parsedLearnCommand.targetIds,\n });\n await params.sendReply(\n saved\n ? formatTargetSetSavedReply({\n setName: parsedLearnCommand.setName,\n targetIds: parsedLearnCommand.targetIds,\n })\n : \"\u76EE\u6807\u7EC4\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u540D\u79F0\u548C\u76EE\u6807\u5217\u8868\u3002\",\n );\n return true;\n }\n\n if (\n parsedLearnCommand.scope === \"target-set-apply\" &&\n parsedLearnCommand.setName &&\n parsedLearnCommand.instruction\n ) {\n const applied = applyTargetSetLearningRule({\n storePath: params.accountStorePath,\n accountId: params.accountId,\n name: parsedLearnCommand.setName,\n instruction: parsedLearnCommand.instruction,\n });\n await params.sendReply(\n applied.length > 0\n ? formatLearnAppliedReply({\n scope: \"target-set\",\n setName: parsedLearnCommand.setName,\n targetIds: applied.map((item) => item.targetId),\n instruction: parsedLearnCommand.instruction,\n ruleId: applied[0]?.ruleId,\n })\n : `\u672A\u627E\u5230\u76EE\u6807\u7EC4 \\`${parsedLearnCommand.setName}\\`\uFF0C\u6216\u8BE5\u76EE\u6807\u7EC4\u4E3A\u7A7A\u3002`,\n );\n return true;\n }\n\n if (parsedLearnCommand.scope === \"list\") {\n const rules = listScopedLearningRules({\n storePath: params.accountStorePath,\n accountId: params.accountId,\n })\n .slice(0, 20)\n .map((rule) => {\n const scope = rule.scope === \"target\" ? `target(${rule.targetId})` : \"global\";\n const status = rule.enabled ? \"enabled\" : \"disabled\";\n return `- [${scope}] ${rule.ruleId} (${status}) => ${rule.instruction}`;\n });\n const targetSets = listLearningTargetSets({\n storePath: params.accountStorePath,\n accountId: params.accountId,\n })\n .slice(0, 10)\n .map((targetSet) => `- [target-set] ${targetSet.name} => ${targetSet.targetIds.join(\", \")}`);\n await params.sendReply(formatLearnListReply([...rules, ...targetSets]));\n return true;\n }\n\n if (parsedLearnCommand.scope === \"disable\" && parsedLearnCommand.ruleId) {\n const result = disableManualRule({\n storePath: params.accountStorePath,\n accountId: params.accountId,\n ruleId: parsedLearnCommand.ruleId,\n });\n await params.sendReply(\n formatLearnDisabledReply({\n ruleId: parsedLearnCommand.ruleId,\n existed: result.existed,\n scope: result.scope,\n targetId: result.targetId,\n }),\n );\n return true;\n }\n\n if (parsedLearnCommand.scope === \"delete\" && parsedLearnCommand.ruleId) {\n const result = deleteManualRule({\n storePath: params.accountStorePath,\n accountId: params.accountId,\n ruleId: parsedLearnCommand.ruleId,\n });\n await params.sendReply(\n formatLearnDeletedReply({\n ruleId: parsedLearnCommand.ruleId,\n existed: result.existed,\n scope: result.scope,\n targetId: result.targetId,\n }),\n );\n return true;\n }\n }\n\n const forcedContent: MessageContent = {\n text: params.extractedText,\n messageType: params.messageType,\n };\n const manualForcedReply = resolveManualForcedReply({\n storePath: params.accountStorePath,\n accountId: params.accountId,\n targetId: params.data.conversationId,\n content: forcedContent,\n });\n if (manualForcedReply) {\n await params.sendReply(manualForcedReply);\n return true;\n }\n\n return false;\n}\n", "// src/media-utils.ts\n\n/**\n * Media handling utilities for DingTalk channel plugin.\n * Provides functions for media type detection and file upload to DingTalk media servers.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { promises as fsPromises } from \"node:fs\";\nimport { lookup as dnsLookup } from \"node:dns/promises\";\nimport { BlockList, isIP } from \"node:net\";\nimport axios from \"./http-client\";\nimport FormData from \"form-data\";\nimport { runFfmpeg, runFfprobe } from \"openclaw/plugin-sdk/media-runtime\";\nimport type { DingTalkConfig, Logger } from \"./types\";\nimport { formatDingTalkErrorPayloadLog, getProxyBypassOption } from \"./utils\";\nimport { getDingTalkRuntime } from \"./runtime\";\n\n/**\n * Extended PluginRuntime with media bridge support.\n * The `media.loadWebMedia` method resolves sandbox/container paths\n * through the runtime bridge when direct host filesystem access fails.\n */\ninterface PluginRuntimeWithMedia {\n media?: {\n loadWebMedia(\n mediaPath: string,\n options?: { localRoots?: readonly string[] | \"any\" },\n ): Promise<{ buffer: Buffer | ArrayBuffer; fileName?: string; contentType?: string } | null>;\n };\n [key: string]: unknown;\n}\n\n/**\n * Calculate MP3 duration in seconds by parsing MPEG frame headers\n * Supports CBR and VBR MP3 files\n * @param filePathOrBuffer Path to the MP3 file, or a pre-read Buffer\n * @param log Optional logger\n * @returns Duration in seconds (0 if parsing fails)\n */\nexport async function getMp3DurationSeconds(filePathOrBuffer: string | Buffer, log?: Logger): Promise<number> {\n try {\n const buffer = typeof filePathOrBuffer === \"string\"\n ? await fsPromises.readFile(filePathOrBuffer)\n : filePathOrBuffer;\n let offset = 0;\n\n // Skip ID3v2 tag if present\n if (buffer.length >= 10 && buffer[0] === 0x49 && buffer[1] === 0x44 && buffer[2] === 0x33) {\n const flags = buffer[5];\n const id3Size =\n ((buffer[6] & 0x7f) << 21) |\n ((buffer[7] & 0x7f) << 14) |\n ((buffer[8] & 0x7f) << 7) |\n (buffer[9] & 0x7f);\n\n // ID3 size excludes the 10-byte header; footer (if present) adds 10 bytes.\n const footerSize = (flags & 0x10) ? 10 : 0;\n offset = 10 + id3Size + footerSize;\n }\n\n // Skip ID3v1 tag at the end (last 128 bytes)\n const endOffset =\n buffer.length > 128 &&\n buffer[buffer.length - 128] === 0x54 &&\n buffer[buffer.length - 127] === 0x41 &&\n buffer[buffer.length - 126] === 0x47\n ? buffer.length - 128\n : buffer.length;\n\n let frameCount = 0;\n let totalSamples = 0;\n let lastSampleRate = 0;\n\n // Sample rate tables\n const sampleRates: Record<\"1\" | \"2\" | \"2.5\", number[]> = {\n \"1\": [44100, 48000, 32000, 0],\n \"2\": [22050, 24000, 16000, 0],\n \"2.5\": [11025, 12000, 8000, 0],\n };\n\n // Bitrate tables (kbps) by (version group -> layer)\n // Note: version group here is MPEG1 vs MPEG2/2.5 for bitrate tables.\n const bitratesLayer1: Record<\"1\" | \"2\", number[]> = {\n \"1\": [0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0],\n \"2\": [0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0],\n };\n const bitratesLayer2: Record<\"1\" | \"2\", number[]> = {\n \"1\": [0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0],\n \"2\": [0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0],\n };\n const bitratesLayer3: Record<\"1\" | \"2\", number[]> = {\n \"1\": [0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0],\n \"2\": [0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0],\n };\n\n while (offset < endOffset - 4) {\n // Frame sync (11 bits set)\n if (buffer[offset] === 0xff && (buffer[offset + 1] & 0xe0) === 0xe0) {\n const versionBits = (buffer[offset + 1] >> 3) & 0x03; // 00=2.5, 01=reserved, 10=2, 11=1\n const layerBits = (buffer[offset + 1] >> 1) & 0x03; // 01=III, 10=II, 11=I, 00=reserved\n const bitrateIndex = (buffer[offset + 2] >> 4) & 0x0f; // 0000/1111 invalid\n const sampleRateIndex = (buffer[offset + 2] >> 2) & 0x03; // 11 invalid\n const paddingBit = (buffer[offset + 2] >> 1) & 0x01;\n\n // quick validity checks to reduce false sync hits\n if (layerBits === 0 || bitrateIndex === 0 || bitrateIndex === 15 || sampleRateIndex === 3) {\n offset++;\n continue;\n }\n\n // MPEG version\n let mpegVersion: \"1\" | \"2\" | \"2.5\";\n if (versionBits === 0) {\n mpegVersion = \"2.5\";\n } else if (versionBits === 2) {\n mpegVersion = \"2\";\n } else if (versionBits === 3) {\n mpegVersion = \"1\";\n } else {\n offset++;\n continue; // reserved\n }\n\n // Layer\n let layer: 1 | 2 | 3;\n if (layerBits === 1) {\n layer = 3; // Layer III\n } else if (layerBits === 2) {\n layer = 2; // Layer II\n } else if (layerBits === 3) {\n layer = 1; // Layer I\n } else {\n offset++;\n continue;\n }\n\n const sampleRate = sampleRates[mpegVersion][sampleRateIndex] || 0;\n if (!sampleRate) {\n offset++;\n continue;\n }\n\n // bitrate tables use group: MPEG1 vs MPEG2/2.5\n const brGroup: \"1\" | \"2\" = mpegVersion === \"1\" ? \"1\" : \"2\";\n let bitrateKbps = 0;\n if (layer === 1) {\n bitrateKbps = bitratesLayer1[brGroup][bitrateIndex] || 0;\n } else if (layer === 2) {\n bitrateKbps = bitratesLayer2[brGroup][bitrateIndex] || 0;\n } else {\n bitrateKbps = bitratesLayer3[brGroup][bitrateIndex] || 0;\n }\n\n if (!bitrateKbps) {\n offset++;\n continue;\n }\n\n // samples per frame\n let samplesPerFrame: number;\n if (layer === 1) {\n samplesPerFrame = 384;\n } else if (layer === 2) {\n samplesPerFrame = 1152;\n } else {\n samplesPerFrame = mpegVersion === \"1\" ? 1152 : 576; // Layer III\n }\n\n // frame size\n let frameSize = 0;\n if (layer === 1) {\n frameSize = Math.floor(((12 * bitrateKbps * 1000) / sampleRate + paddingBit) * 4);\n } else if (layer === 3 && mpegVersion !== \"1\") {\n // Layer III + MPEG2/2.5 uses 72, not 144\n frameSize = Math.floor((72 * bitrateKbps * 1000) / sampleRate + paddingBit);\n } else {\n // Layer II OR Layer III MPEG1\n frameSize = Math.floor((144 * bitrateKbps * 1000) / sampleRate + paddingBit);\n }\n\n if (frameSize > 0 && frameSize < 10000 && offset + frameSize <= endOffset) {\n frameCount++;\n totalSamples += samplesPerFrame;\n lastSampleRate = sampleRate;\n offset += frameSize;\n continue;\n }\n }\n\n offset++;\n }\n\n if (frameCount > 0 && lastSampleRate > 0) {\n const duration = totalSamples / lastSampleRate;\n log?.debug?.(`[DingTalk] Parsed ${frameCount} MP3 frames, duration: ${duration.toFixed(3)}s`);\n return Math.floor(duration);\n }\n\n log?.warn?.(`[DingTalk] Could not parse MP3 duration from ${typeof filePathOrBuffer === \"string\" ? filePathOrBuffer : \"<buffer>\"} (found ${frameCount} frames)`);\n return 0;\n } catch (err: unknown) {\n log?.error?.(`[DingTalk] Failed to get MP3 duration: ${err instanceof Error ? err.message : String(err)}`);\n return 0;\n }\n}\n\nconst DEFAULT_VOICE_DURATION_MS = 1000;\nconst DINGTALK_VOICE_UPLOAD_EXTENSIONS = new Set([\".ogg\", \".amr\"]);\nconst DINGTALK_VOICE_INPUT_EXTENSIONS = new Set([\".ogg\", \".amr\", \".mp3\", \".wav\"]);\n\nasync function getDurationMsWithFfprobe(filePath: string, log?: Logger): Promise<number> {\n try {\n const stdout = await runFfprobe([\n \"-v\",\n \"error\",\n \"-show_entries\",\n \"format=duration\",\n \"-of\",\n \"csv=p=0\",\n filePath,\n ]);\n const duration = Number.parseFloat(stdout.trim());\n if (!Number.isFinite(duration) || duration <= 0) {\n return 0;\n }\n return Math.max(1, Math.round(duration * 1000));\n } catch (err: unknown) {\n log?.warn?.(`[DingTalk] Failed to probe voice duration: ${err instanceof Error ? err.message : String(err)}`);\n return 0;\n }\n}\n\nasync function prepareVoiceUploadPath(\n mediaPath: string,\n log?: Logger,\n): Promise<{ path: string; cleanup?: () => Promise<void> }> {\n const ext = path.extname(mediaPath).toLowerCase();\n if (DINGTALK_VOICE_UPLOAD_EXTENSIONS.has(ext)) {\n return { path: mediaPath };\n }\n\n const outputPath = path.join(os.tmpdir(), `dingtalk_voice_${randomUUID()}.ogg`);\n await runFfmpeg([\n \"-y\",\n \"-i\",\n mediaPath,\n \"-vn\",\n \"-sn\",\n \"-dn\",\n \"-ar\",\n \"16000\",\n \"-ac\",\n \"1\",\n \"-c:a\",\n \"libopus\",\n \"-b:a\",\n \"24k\",\n outputPath,\n ]);\n\n log?.debug?.(`[DingTalk] Transcoded voice upload to OGG: ${mediaPath} -> ${outputPath}`);\n\n return {\n path: outputPath,\n cleanup: async () => {\n await fsPromises.rm(outputPath, { force: true });\n },\n };\n}\n\nfunction getWavDurationMsFromBuffer(buffer: Buffer, log?: Logger): number {\n try {\n if (buffer.length < 44 || buffer.toString(\"ascii\", 0, 4) !== \"RIFF\" || buffer.toString(\"ascii\", 8, 12) !== \"WAVE\") {\n return 0;\n }\n\n let offset = 12;\n let byteRate = 0;\n let sampleRate = 0;\n let channels = 0;\n let bitsPerSample = 0;\n let dataSize = 0;\n\n while (offset + 8 <= buffer.length) {\n const chunkId = buffer.toString(\"ascii\", offset, offset + 4);\n const chunkSize = buffer.readUInt32LE(offset + 4);\n const chunkDataStart = offset + 8;\n const paddedChunkSize = chunkSize + (chunkSize % 2);\n\n if (chunkDataStart + chunkSize > buffer.length) {\n break;\n }\n\n if (chunkId === \"fmt \" && chunkSize >= 16) {\n channels = buffer.readUInt16LE(chunkDataStart + 2);\n sampleRate = buffer.readUInt32LE(chunkDataStart + 4);\n byteRate = buffer.readUInt32LE(chunkDataStart + 8);\n bitsPerSample = buffer.readUInt16LE(chunkDataStart + 14);\n } else if (chunkId === \"data\") {\n dataSize = chunkSize;\n }\n\n if (dataSize > 0 && (byteRate > 0 || (sampleRate > 0 && channels > 0 && bitsPerSample > 0))) {\n break;\n }\n\n offset = chunkDataStart + paddedChunkSize;\n }\n\n const effectiveByteRate = byteRate || (sampleRate > 0 && channels > 0 && bitsPerSample > 0\n ? sampleRate * channels * (bitsPerSample / 8)\n : 0);\n\n if (effectiveByteRate <= 0 || dataSize <= 0) {\n return 0;\n }\n\n return Math.max(1, Math.round((dataSize / effectiveByteRate) * 1000));\n } catch (err: unknown) {\n log?.warn?.(`[DingTalk] Failed to parse WAV duration: ${err instanceof Error ? err.message : String(err)}`);\n return 0;\n }\n}\n\nexport async function getVoiceDurationMs(\n filePath: string,\n mediaType: DingTalkMediaType,\n log?: Logger,\n options?: { mediaLocalRoots?: string[]; preReadBuffer?: Buffer },\n): Promise<number> {\n if (mediaType !== \"voice\") {\n return DEFAULT_VOICE_DURATION_MS;\n }\n\n const ext = path.extname(filePath).toLowerCase();\n\n if (ext === \".mp3\") {\n let durationSec: number;\n try {\n // Reuse pre-read buffer from uploadMedia when available to avoid double read\n const buffer = options?.preReadBuffer\n ?? (await readMediaBuffer(filePath, options, log)).buffer;\n durationSec = await getMp3DurationSeconds(buffer, log);\n } catch {\n durationSec = 0;\n }\n if (durationSec > 0) {\n return Math.max(1, Math.round(durationSec * 1000));\n }\n\n log?.warn?.(\n `[DingTalk] MP3 duration parse returned ${durationSec} for ${filePath}; using fallback ${DEFAULT_VOICE_DURATION_MS}ms`,\n );\n return DEFAULT_VOICE_DURATION_MS;\n }\n\n if (ext === \".wav\") {\n try {\n const buffer = options?.preReadBuffer\n ?? (await readMediaBuffer(filePath, options, log)).buffer;\n const durationMs = getWavDurationMsFromBuffer(buffer, log);\n if (durationMs > 0) {\n return durationMs;\n }\n } catch {\n // Fall through to the safe default below.\n }\n }\n\n if (ext === \".ogg\" || ext === \".amr\") {\n const durationMs = await getDurationMsWithFfprobe(filePath, log);\n if (durationMs > 0) {\n return durationMs;\n }\n }\n\n return DEFAULT_VOICE_DURATION_MS;\n}\n\n\nexport type DingTalkMediaType = \"image\" | \"voice\" | \"video\" | \"file\";\nexport type DingTalkOutboundMediaType = DingTalkMediaType;\n\nexport interface PreparedMediaInput {\n path: string;\n cleanup?: () => Promise<void>;\n}\n\nexport const REMOTE_MEDIA_ERROR_CODES = {\n ALLOWLIST_MISS: \"ERR_MEDIA_ALLOWLIST_MISS\",\n PRIVATE_HOST: \"ERR_MEDIA_PRIVATE_HOST\",\n DNS_UNRESOLVED: \"ERR_MEDIA_DNS_UNRESOLVED\",\n DNS_PRIVATE: \"ERR_MEDIA_DNS_PRIVATE\",\n REDIRECT_HOST: \"ERR_MEDIA_REDIRECT_HOST\",\n} as const;\n\nexport class RemoteMediaError extends Error {\n constructor(\n message: string,\n public readonly code: (typeof REMOTE_MEDIA_ERROR_CODES)[keyof typeof REMOTE_MEDIA_ERROR_CODES],\n ) {\n super(message);\n this.name = \"RemoteMediaError\";\n }\n}\n\nconst REMOTE_MEDIA_DOWNLOAD_TIMEOUT_MS = 10_000;\nconst REMOTE_MEDIA_MAX_BYTES = 20 * 1024 * 1024;\nconst REMOTE_MEDIA_MAX_REDIRECTS = 5;\n\nfunction normalizeAllowlistEntry(entry: string): string {\n return entry.trim().toLowerCase();\n}\n\nfunction normalizeHostname(hostname: string): string {\n return hostname.replace(/^\\[/, \"\").replace(/\\]$/, \"\").trim().toLowerCase();\n}\n\nfunction isIpInCidr(ip: string, cidr: string): boolean {\n const [network, rawMask] = cidr.split(\"/\");\n const mask = Number.parseInt(rawMask || \"\", 10);\n const normalizedIp = normalizeHostname(ip);\n const normalizedNetwork = normalizeHostname(network || \"\");\n if (!normalizedNetwork || Number.isNaN(mask)) {\n return false;\n }\n\n const ipVersion = isIP(normalizedIp);\n const networkVersion = isIP(normalizedNetwork);\n if (ipVersion === 0 || ipVersion !== networkVersion) {\n return false;\n }\n\n const blockList = new BlockList();\n if (ipVersion === 4) {\n blockList.addSubnet(normalizedNetwork, mask, \"ipv4\");\n return blockList.check(normalizedIp, \"ipv4\");\n }\n\n blockList.addSubnet(normalizedNetwork, mask, \"ipv6\");\n return blockList.check(normalizedIp, \"ipv6\");\n}\n\nfunction matchesAllowlistHost(hostname: string, port: string, entry: string): boolean {\n const normalizedHost = normalizeHostname(hostname);\n const normalizedEntry = normalizeAllowlistEntry(entry);\n if (!normalizedEntry) {\n return false;\n }\n\n if (normalizedEntry.includes(\"/\")) {\n return isIpInCidr(normalizedHost, normalizedEntry);\n }\n\n if (normalizedEntry.startsWith(\"*.\")) {\n const suffix = normalizedEntry.slice(1);\n return normalizedHost.endsWith(suffix);\n }\n\n if (normalizedEntry.includes(\":\")) {\n return `${normalizedHost}:${port}` === normalizedEntry;\n }\n\n return normalizedHost === normalizedEntry;\n}\n\nfunction isAllowedByMediaUrlAllowlist(url: URL, mediaUrlAllowlist: string[]): boolean {\n const port = url.port || (url.protocol === \"https:\" ? \"443\" : \"80\");\n return mediaUrlAllowlist.some((entry) => matchesAllowlistHost(url.hostname, port, entry));\n}\n\n/**\n * Detect media type from file extension\n * Matches DingTalk's supported media types:\n * - image: jpg, gif, png, bmp (max 20MB)\n * - voice: ogg, amr, mp3, wav (max 2MB)\n * - video: mp4 (max 20MB)\n * - file: doc, docx, xls, xlsx, ppt, pptx, zip, pdf, rar (max 20MB)\n *\n * @param filePath Path to the media file\n * @returns Detected media type\n */\nexport function detectMediaTypeFromExtension(filePath: string): DingTalkMediaType {\n const ext = path.extname(filePath).toLowerCase();\n\n if ([\".jpg\", \".jpeg\", \".png\", \".gif\", \".bmp\"].includes(ext)) {\n return \"image\";\n } else if ([\".ogg\", \".mp3\", \".amr\", \".wav\"].includes(ext)) {\n return \"voice\";\n } else if ([\".mp4\", \".avi\", \".mov\"].includes(ext)) {\n return \"video\";\n }\n\n return \"file\";\n}\n\nfunction normalizeOutboundMediaType(value?: string | null): DingTalkOutboundMediaType | undefined {\n if (!value) {\n return undefined;\n }\n\n const normalized = value.trim().toLowerCase();\n if (normalized === \"image\" || normalized === \"voice\" || normalized === \"video\" || normalized === \"file\") {\n return normalized;\n }\n\n return undefined;\n}\n\nexport function resolveOutboundMediaType(params: {\n mediaType?: string | null;\n mediaPath: string;\n asVoice: boolean;\n}): DingTalkOutboundMediaType {\n const explicitType = normalizeOutboundMediaType(params.mediaType);\n const detectedType = detectMediaTypeFromExtension(params.mediaPath);\n\n if (params.asVoice) {\n if (explicitType && explicitType !== \"voice\") {\n throw new Error('asVoice requires mediaType=\"voice\" when mediaType is provided.');\n }\n\n if (detectedType !== \"voice\" || !DINGTALK_VOICE_INPUT_EXTENSIONS.has(path.extname(params.mediaPath).toLowerCase())) {\n throw new Error(\"asVoice requires an audio file (ogg, amr, mp3, wav).\");\n }\n\n return \"voice\";\n }\n\n if (explicitType) {\n return explicitType;\n }\n\n // Audio files default to \"file\" (attachment) unless asVoice is explicitly set.\n // This prevents mp3/wav/ogg/amr from being sent as voice messages unexpectedly.\n if (detectedType === \"voice\") {\n return \"file\";\n }\n\n return detectedType;\n}\n\nfunction isRemoteMediaUrl(input: string): boolean {\n try {\n const parsed = new URL(input);\n return parsed.protocol === \"http:\" || parsed.protocol === \"https:\";\n } catch {\n return false;\n }\n}\n\nfunction isPrivateOrLocalHost(hostname: string): boolean {\n const normalized = normalizeHostname(hostname);\n if (!normalized) {\n return true;\n }\n\n if (normalized === \"localhost\" || normalized.endsWith(\".localhost\")) {\n return true;\n }\n\n const ipVersion = isIP(normalized);\n if (ipVersion === 4) {\n const parts = normalized.split(\".\").map((part) => Number.parseInt(part, 10));\n if (parts.length !== 4 || parts.some((part) => Number.isNaN(part))) {\n return true;\n }\n\n const [a, b] = parts;\n return (\n a === 0 ||\n a === 10 ||\n a === 127 ||\n (a === 169 && b === 254) ||\n (a === 172 && b >= 16 && b <= 31) ||\n (a === 192 && b === 168)\n );\n }\n\n if (ipVersion === 6) {\n if (normalized === \"::1\") {\n return true;\n }\n return normalized.startsWith(\"fc\") || normalized.startsWith(\"fd\") || normalized.startsWith(\"fe80\");\n }\n\n return false;\n}\n\nasync function resolveHostname(hostname: string): Promise<Array<{ address: string; family: number }>> {\n const records = await dnsLookup(hostname, { all: true, verbatim: true });\n return Array.isArray(records) ? records : [records];\n}\n\nfunction detectExtensionFromContentType(contentType?: string): string {\n const normalized = contentType?.split(\";\")[0]?.trim().toLowerCase();\n switch (normalized) {\n case \"image/jpeg\":\n return \".jpg\";\n case \"image/png\":\n return \".png\";\n case \"image/gif\":\n return \".gif\";\n case \"image/bmp\":\n return \".bmp\";\n case \"audio/amr\":\n return \".amr\";\n case \"audio/mpeg\":\n return \".mp3\";\n case \"audio/wav\":\n case \"audio/x-wav\":\n return \".wav\";\n case \"video/mp4\":\n return \".mp4\";\n case \"application/pdf\":\n return \".pdf\";\n default:\n return \"\";\n }\n}\n\nexport async function prepareMediaInput(\n input: string,\n log?: Logger,\n mediaUrlAllowlist?: string[],\n): Promise<PreparedMediaInput> {\n const trimmed = input.trim();\n if (!isRemoteMediaUrl(trimmed)) {\n return { path: trimmed };\n }\n\n const allowlist = mediaUrlAllowlist?.filter((entry) => entry.trim().length > 0) || [];\n const allowlistConfigured = allowlist.length > 0;\n\n const assertRemoteUrlAllowed = async (\n url: URL,\n ): Promise<((hostname: string) => Promise<{ address: string; family: number }>) | undefined> => {\n const inAllowlist = allowlistConfigured ? isAllowedByMediaUrlAllowlist(url, allowlist) : false;\n\n if (allowlistConfigured && !inAllowlist) {\n throw new RemoteMediaError(\n `remote media URL host is not in mediaUrlAllowlist: ${url.hostname}`,\n REMOTE_MEDIA_ERROR_CODES.ALLOWLIST_MISS,\n );\n }\n\n if (isPrivateOrLocalHost(url.hostname) && !inAllowlist) {\n throw new RemoteMediaError(\n `remote media URL points to private or local network host: ${url.hostname}`,\n REMOTE_MEDIA_ERROR_CODES.PRIVATE_HOST,\n );\n }\n\n if (isIP(url.hostname) !== 0) {\n return undefined;\n }\n\n const resolvedRecords = await resolveHostname(url.hostname);\n if (resolvedRecords.length === 0) {\n throw new RemoteMediaError(\n `remote media URL host cannot be resolved: ${url.hostname}`,\n REMOTE_MEDIA_ERROR_CODES.DNS_UNRESOLVED,\n );\n }\n\n if (!inAllowlist && resolvedRecords.some((record) => isPrivateOrLocalHost(record.address))) {\n throw new RemoteMediaError(\n `remote media URL host resolves to private or local network address: ${url.hostname}`,\n REMOTE_MEDIA_ERROR_CODES.DNS_PRIVATE,\n );\n }\n\n const pinnedResolved = resolvedRecords[0];\n return async (hostname: string): Promise<{ address: string; family: number }> => {\n if (hostname === url.hostname) {\n return pinnedResolved;\n }\n\n throw new RemoteMediaError(\n `remote media URL redirected to unexpected host: ${hostname}`,\n REMOTE_MEDIA_ERROR_CODES.REDIRECT_HOST,\n );\n };\n };\n\n let currentUrl = new URL(trimmed);\n let response: { data: unknown; headers?: Record<string, unknown>; status: number } | null = null;\n\n for (let redirectCount = 0; redirectCount <= REMOTE_MEDIA_MAX_REDIRECTS; redirectCount += 1) {\n const lookup = await assertRemoteUrlAllowed(currentUrl);\n const currentResponse = await axios.get(currentUrl.toString(), {\n responseType: \"arraybuffer\",\n maxBodyLength: REMOTE_MEDIA_MAX_BYTES,\n maxContentLength: REMOTE_MEDIA_MAX_BYTES,\n timeout: REMOTE_MEDIA_DOWNLOAD_TIMEOUT_MS,\n maxRedirects: 0,\n validateStatus: (status) => status >= 200 && status < 400,\n lookup,\n });\n\n response = currentResponse;\n const statusCode = typeof currentResponse.status === \"number\" ? currentResponse.status : 200;\n if (statusCode < 300 || statusCode >= 400) {\n break;\n }\n\n const locationHeader =\n typeof currentResponse.headers?.location === \"string\"\n ? currentResponse.headers.location\n : Array.isArray(currentResponse.headers?.location)\n ? currentResponse.headers.location[0]\n : undefined;\n if (!locationHeader) {\n throw new Error(`redirect response missing location header: ${statusCode}`);\n }\n\n if (redirectCount === REMOTE_MEDIA_MAX_REDIRECTS) {\n throw new Error(`too many redirects when downloading remote media: ${currentUrl.toString()}`);\n }\n\n const redirectUrl = new URL(locationHeader, currentUrl);\n if (redirectUrl.protocol !== \"http:\" && redirectUrl.protocol !== \"https:\") {\n throw new RemoteMediaError(\n `remote media URL redirected to unsupported scheme: ${redirectUrl.protocol}`,\n REMOTE_MEDIA_ERROR_CODES.REDIRECT_HOST,\n );\n }\n currentUrl = redirectUrl;\n }\n\n if (!response) {\n throw new Error(\"remote media download failed: empty response\");\n }\n\n const contentType =\n typeof response.headers?.[\"content-type\"] === \"string\"\n ? response.headers[\"content-type\"]\n : undefined;\n const urlPath = currentUrl.pathname;\n const ext = path.extname(urlPath) || detectExtensionFromContentType(contentType) || \".bin\";\n const tempPath = path.join(os.tmpdir(), `dingtalk_${randomUUID()}${ext}`);\n const buffer = Buffer.isBuffer(response.data)\n ? response.data\n : Buffer.from(response.data as ArrayBuffer);\n\n await fsPromises.writeFile(tempPath, buffer);\n log?.debug?.(`[DingTalk] Downloaded remote media to temp file: ${tempPath}`);\n\n return {\n path: tempPath,\n cleanup: async () => {\n try {\n await fsPromises.unlink(tempPath);\n } catch (err: unknown) {\n const code = typeof err === \"object\" && err !== null && \"code\" in err ? err.code : undefined;\n if (code !== \"ENOENT\") {\n const message = err instanceof Error ? err.message : String(err);\n log?.warn?.(`[DingTalk] Failed to remove temp media ${tempPath}: ${message}`);\n }\n }\n },\n };\n}\n\n/**\n * File size limits for DingTalk media types (in bytes)\n */\nconst FILE_SIZE_LIMITS: Record<DingTalkMediaType, number> = {\n image: 20 * 1024 * 1024, // 20MB\n voice: 2 * 1024 * 1024, // 2MB\n video: 20 * 1024 * 1024, // 20MB\n file: 20 * 1024 * 1024, // 20MB\n};\n\n/**\n * Read a media file, resolving sandbox/container paths via the runtime bridge\n * when direct host filesystem access fails.\n *\n * Precedence:\n * 1. Direct fs.readFile (works for host-local paths)\n * 2. rt.media.loadWebMedia (resolves sandbox workspace paths via bridge)\n */\nasync function readMediaBuffer(\n mediaPath: string,\n options?: { mediaLocalRoots?: string[] },\n log?: Logger,\n): Promise<{ buffer: Buffer; size: number }> {\n // Try direct host filesystem first\n try {\n const buffer = await fsPromises.readFile(mediaPath);\n return { buffer, size: buffer.length };\n } catch (err: unknown) {\n const errno = err as NodeJS.ErrnoException;\n if (errno.code !== \"ENOENT\") {\n throw err; // Permission errors etc. should propagate immediately\n }\n }\n\n // File not found on host \u2014 try runtime media bridge (sandbox/container paths)\n log?.debug?.(`[DingTalk] File not found on host, trying runtime media bridge: ${mediaPath}`);\n const rt = getDingTalkRuntime() as PluginRuntimeWithMedia;\n if (!rt.media?.loadWebMedia) {\n throw Object.assign(\n new Error(`File not found and runtime media bridge unavailable: ${mediaPath}`),\n { code: \"ENOENT\" },\n );\n }\n\n const media = await rt.media.loadWebMedia(mediaPath, {\n localRoots: options?.mediaLocalRoots,\n });\n\n if (!media || !media.buffer) {\n throw Object.assign(\n new Error(`Runtime media bridge returned no data for: ${mediaPath}`),\n { code: \"ENOENT\" },\n );\n }\n\n const buffer = Buffer.isBuffer(media.buffer)\n ? media.buffer\n : Buffer.from(media.buffer);\n return { buffer, size: buffer.length };\n}\n\nexport interface UploadMediaResult {\n mediaId: string;\n /** The file buffer read during upload, reusable for voice duration parsing etc. */\n buffer: Buffer;\n /**\n * Voice duration captured before any temporary transcoded file is cleaned up.\n * This is the stable field callers should use instead of depending on any\n * upload-time temp path lifecycle.\n */\n durationMs?: number;\n}\n\nexport async function uploadMedia(\n config: DingTalkConfig,\n mediaPath: string,\n mediaType: DingTalkMediaType,\n getAccessToken: (config: DingTalkConfig, log?: Logger) => Promise<string>,\n log?: Logger,\n options?: { mediaLocalRoots?: string[] },\n): Promise<UploadMediaResult | null> {\n let voicePreparedCleanup: (() => Promise<void>) | undefined;\n try {\n const token = await getAccessToken(config, log);\n let resolvedMediaPath = mediaPath;\n\n if (mediaType === \"voice\") {\n const prepared = await prepareVoiceUploadPath(mediaPath, log);\n resolvedMediaPath = prepared.path;\n voicePreparedCleanup = prepared.cleanup;\n }\n\n // Read file via sandbox-aware bridge (falls back to direct fs for host paths)\n const { buffer, size } = await readMediaBuffer(resolvedMediaPath, options, log);\n const durationMs = mediaType === \"voice\"\n ? await getVoiceDurationMs(resolvedMediaPath, mediaType, log, { ...options, preReadBuffer: buffer })\n : undefined;\n\n // Check file size\n const sizeLimit = FILE_SIZE_LIMITS[mediaType];\n if (size > sizeLimit) {\n const sizeMB = (size / (1024 * 1024)).toFixed(2);\n const limitMB = (sizeLimit / (1024 * 1024)).toFixed(2);\n log?.error?.(\n `[DingTalk] Media file too large: ${sizeMB}MB exceeds ${limitMB}MB limit for ${mediaType}`,\n );\n return null;\n }\n\n const filename = path.basename(resolvedMediaPath);\n\n // Upload to DingTalk's media server using form-data\n const form = new FormData();\n form.append(\"media\", buffer, { filename });\n\n const uploadUrl = `https://oapi.dingtalk.com/media/upload?access_token=${token}&type=${mediaType}`;\n\n log?.debug?.(`[DingTalk] Uploading media: ${filename} (${size} bytes) as ${mediaType}`);\n\n const response = await axios.post(uploadUrl, form, {\n headers: form.getHeaders(),\n maxBodyLength: Infinity,\n maxContentLength: Infinity,\n ...getProxyBypassOption(config),\n });\n\n if (response.data?.errcode === 0 && response.data?.media_id) {\n log?.debug?.(\n `[DingTalk] Media uploaded successfully: ${response.data.media_id} (${size} bytes)`,\n );\n return { mediaId: response.data.media_id, buffer, durationMs };\n } else {\n log?.error?.(`[DingTalk] Media upload failed: ${JSON.stringify(response.data)}`);\n return null;\n }\n } catch (err: unknown) {\n // Handle file system errors (e.g., file not found, permission denied)\n const errno = err as NodeJS.ErrnoException;\n if (errno.code === \"ENOENT\") {\n log?.error?.(`[DingTalk] Media file not found (host and sandbox): ${mediaPath}`);\n } else if (errno.code === \"EACCES\") {\n log?.error?.(`[DingTalk] Permission denied accessing media file: ${mediaPath}`);\n } else {\n log?.error?.(`[DingTalk] Failed to upload media: ${err instanceof Error ? err.message : String(err)}`);\n if (axios.isAxiosError(err) && err.response) {\n const status = err.response.status;\n const statusText = err.response.statusText;\n const statusLabel = status ? ` status=${status}${statusText ? ` ${statusText}` : \"\"}` : \"\";\n log?.error?.(`[DingTalk] Upload response${statusLabel}`);\n log?.error?.(formatDingTalkErrorPayloadLog(\"media.upload\", err.response.data));\n }\n }\n return null;\n } finally {\n await voicePreparedCleanup?.();\n }\n}\n", "import type {\n AtMention,\n DingTalkInboundMessage,\n MessageContent,\n QuotedInfo,\n SendMessageOptions,\n} from \"./types\";\n\ninterface DingTalkDocMeta {\n spaceId: string;\n fileId: string;\n}\n\nconst UNKNOWN_PERSON_LABEL = \"\u67D0\u4EBA\";\n\nfunction parseBizCustomActionUrl(url: string | undefined): DingTalkDocMeta | null {\n if (!url || typeof url !== \"string\") {\n return null;\n }\n\n const queryIndex = url.indexOf(\"?\");\n if (queryIndex < 0 || queryIndex === url.length - 1) {\n return null;\n }\n\n try {\n const params = new URLSearchParams(url.slice(queryIndex + 1));\n const route = params.get(\"route\");\n const type = params.get(\"type\");\n const spaceId = params.get(\"spaceId\");\n const fileId = params.get(\"fileId\");\n if (route !== \"previewDentry\" || type !== \"file\" || !spaceId || !fileId) {\n return null;\n }\n return { spaceId, fileId };\n } catch {\n return null;\n }\n}\n\nfunction extractRichTextQuoteParts(\n richText: Array<Record<string, unknown>> | undefined,\n): { summary: string; pictureDownloadCode?: string; pictureDownloadCodes?: string[] } | null {\n if (!Array.isArray(richText) || richText.length === 0) {\n return null;\n }\n\n const textParts: string[] = [];\n const pictureDownloadCodes: string[] = [];\n\n for (const part of richText) {\n const partType =\n typeof part.msgType === \"string\"\n ? part.msgType\n : typeof part.type === \"string\"\n ? part.type\n : undefined;\n const textValue =\n typeof part.content === \"string\"\n ? part.content\n : typeof part.text === \"string\"\n ? part.text\n : undefined;\n\n if ((partType === \"text\" || partType === undefined) && textValue) {\n textParts.push(textValue);\n continue;\n }\n if (partType === \"emoji\" && textValue) {\n textParts.push(textValue);\n continue;\n }\n if (partType === \"picture\") {\n textParts.push(\"[\u56FE\u7247]\");\n if (typeof part.downloadCode === \"string\" && part.downloadCode.trim()) {\n pictureDownloadCodes.push(part.downloadCode.trim());\n }\n continue;\n }\n if (partType === \"at\") {\n const atName =\n typeof part.atName === \"string\"\n ? part.atName\n : typeof textValue === \"string\"\n ? textValue\n : UNKNOWN_PERSON_LABEL;\n textParts.push(`@${atName}`);\n continue;\n }\n if (textValue) {\n textParts.push(textValue);\n }\n }\n\n const summary = textParts.join(\"\").trim();\n const uniquePictureDownloadCodes = [...new Set(pictureDownloadCodes)];\n const pictureDownloadCode = uniquePictureDownloadCodes[0];\n if (!summary && !pictureDownloadCode) {\n return null;\n }\n return {\n summary,\n pictureDownloadCode,\n pictureDownloadCodes:\n uniquePictureDownloadCodes.length > 0 ? uniquePictureDownloadCodes : undefined,\n };\n}\n\nfunction extractAtMentionsFromText(text: string): AtMention[] {\n const mentions: AtMention[] = [];\n const matches = text.matchAll(/(?<!\\w)@([^\\s@.]+)(?!\\.\\w)/g);\n for (const match of matches) {\n mentions.push({ name: match[1].trim() });\n }\n return mentions;\n}\n\nfunction trimString(value: string | undefined): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nconst MAX_CHAT_RECORD_ENTRIES = 30;\n\nfunction stringifyChatRecordContentValue(value: unknown): string | undefined {\n if (typeof value === \"string\") {\n return trimString(value);\n }\n if (!value || typeof value !== \"object\") {\n return undefined;\n }\n const record = value as Record<string, unknown>;\n const content = record.content;\n const contentText =\n typeof content === \"string\"\n ? trimString(content)\n : content && typeof content === \"object\"\n ? trimString((content as Record<string, unknown>).text as string | undefined)\n : undefined;\n\n // Preserve DingTalk's observed chatRecord text priority: explicit text first,\n // then nested content text, then the legacy message fallback.\n return (\n trimString(record.text as string | undefined) ||\n contentText ||\n trimString(record.message as string | undefined)\n );\n}\n\nfunction getChatRecordEntriesSource(content: Record<string, unknown> | undefined): unknown {\n return content?.chatRecord ?? content?.records ?? content?.messages;\n}\n\nfunction formatChatRecordEntries(rawRecord: unknown): string[] {\n let entries = rawRecord;\n if (typeof rawRecord === \"string\") {\n const trimmed = rawRecord.trim();\n if (!trimmed || trimmed === \"[]\") {\n return [];\n }\n try {\n entries = JSON.parse(trimmed);\n } catch {\n return [];\n }\n }\n if (!Array.isArray(entries)) {\n return [];\n }\n return entries\n .map((entry) => {\n if (!entry || typeof entry !== \"object\") {\n return undefined;\n }\n const record = entry as Record<string, unknown>;\n const sender =\n trimString(record.senderName as string | undefined) ||\n trimString(record.senderNick as string | undefined) ||\n trimString(record.sender as string | undefined) ||\n trimString(record.senderId as string | undefined) ||\n UNKNOWN_PERSON_LABEL;\n const body = stringifyChatRecordContentValue(\n record.content ?? record.text ?? record.message ?? record.body,\n );\n return body ? `${sender}: ${body}` : undefined;\n })\n .filter((line): line is string => Boolean(line))\n .slice(0, MAX_CHAT_RECORD_ENTRIES);\n}\n\nfunction formatChatRecordPreview(\n content: Record<string, unknown> | undefined,\n options: { useTitleAsLabel?: boolean } = {},\n): string | undefined {\n const summary = typeof content?.summary === \"string\" ? content.summary.trim() : \"\";\n const title = typeof content?.title === \"string\" ? content.title.trim() : \"\";\n const rawRecord = getChatRecordEntriesSource(content);\n const recordLines = formatChatRecordEntries(rawRecord);\n const parts: string[] = [];\n if (summary && summary !== \"[]\") {\n const label = options.useTitleAsLabel\n ? title\n ? `[${title}] `\n : \"[\u804A\u5929\u8BB0\u5F55] \"\n : \"[\u804A\u5929\u8BB0\u5F55\u6458\u8981] \";\n parts.push(`${label}${summary}`);\n }\n if (recordLines.length > 0) {\n parts.push(`[\u804A\u5929\u8BB0\u5F55\u5185\u5BB9]\\n${recordLines.join(\"\\n\")}`);\n }\n return parts.join(\"\\n\\n\") || undefined;\n}\n\nfunction buildQuotedMessageTypePlaceholder(\n messageType: string | undefined,\n fileName?: string,\n): string | undefined {\n switch (messageType) {\n case \"text\":\n return undefined;\n case \"picture\":\n return \"<media:image>\";\n case \"audio\":\n return \"<media:voice>\";\n case \"video\":\n return \"<media:video>\";\n case \"file\":\n case \"unknownMsgType\":\n return fileName ? `<media:file> (${fileName})` : \"<media:file>\";\n case \"interactiveCardFile\":\n return \"[\u9489\u9489\u6587\u6863]\";\n case \"interactiveCard\":\n return \"[interactiveCard\u6D88\u606F]\";\n case \"richText\":\n return \"[\u5BCC\u6587\u672C\u6D88\u606F]\";\n default:\n return messageType ? `[Quoted ${messageType}]` : undefined;\n }\n}\n\nfunction buildLegacyQuoteMessagePreview(message: DingTalkInboundMessage[\"quoteMessage\"]): {\n previewText?: string;\n previewMessageType?: string;\n previewSenderId?: string;\n} {\n const previewMessageType = trimString(message?.msgtype);\n return {\n previewText:\n trimString(message?.text?.content) || buildQuotedMessageTypePlaceholder(previewMessageType),\n previewMessageType,\n previewSenderId: trimString(message?.senderId),\n };\n}\n\nfunction buildRepliedMessagePreview(params: {\n data: DingTalkInboundMessage;\n repliedMsg: NonNullable<NonNullable<DingTalkInboundMessage[\"text\"]>[\"repliedMsg\"]>;\n}): Partial<QuotedInfo> {\n const { data, repliedMsg } = params;\n const repliedMsgType = trimString(repliedMsg.msgType);\n const content = repliedMsg.content;\n const fileName = trimString(content?.fileName);\n const richTextQuote = extractRichTextQuoteParts(content?.richText);\n const docMeta = parseBizCustomActionUrl(content?.biz_custom_action_url);\n\n if (repliedMsgType === \"picture\") {\n return {\n mediaDownloadCode: trimString(content?.downloadCode),\n mediaType: trimString(content?.downloadCode) ? \"image\" : undefined,\n previewText: buildQuotedMessageTypePlaceholder(\"picture\"),\n previewMessageType: \"picture\",\n previewSenderId: trimString(repliedMsg.senderId),\n };\n }\n\n if (repliedMsgType === \"richText\") {\n return {\n mediaDownloadCode: richTextQuote?.pictureDownloadCode,\n mediaType: richTextQuote?.pictureDownloadCode ? \"image\" : undefined,\n previewText:\n trimString(richTextQuote?.summary) || buildQuotedMessageTypePlaceholder(\"richText\"),\n previewMessageType: \"richText\",\n previewSenderId: trimString(repliedMsg.senderId),\n };\n }\n\n if (repliedMsgType === \"unknownMsgType\") {\n return {\n isQuotedFile: true,\n fileCreatedAt: repliedMsg.createdAt,\n previewText: buildQuotedMessageTypePlaceholder(\"unknownMsgType\", fileName),\n previewMessageType: \"unknownMsgType\",\n previewFileName: fileName,\n previewSenderId: trimString(repliedMsg.senderId),\n };\n }\n\n if (repliedMsgType === \"file\" || repliedMsgType === \"audio\" || repliedMsgType === \"video\") {\n const hasFileName = repliedMsgType === \"file\";\n return {\n isQuotedFile: true,\n fileCreatedAt: repliedMsg.createdAt,\n previewText: buildQuotedMessageTypePlaceholder(\n repliedMsgType,\n hasFileName ? fileName : undefined,\n ),\n previewMessageType: repliedMsgType,\n ...(hasFileName ? { previewFileName: fileName } : {}),\n previewSenderId: trimString(repliedMsg.senderId),\n };\n }\n\n if (repliedMsgType === \"interactiveCard\") {\n const isBotCard = repliedMsg.senderId === data.chatbotUserId;\n if (isBotCard) {\n return {\n isQuotedCard: true,\n cardCreatedAt: repliedMsg.createdAt,\n processQueryKey: trimString(data.originalProcessQueryKey),\n previewText:\n trimString(content?.text) || buildQuotedMessageTypePlaceholder(\"interactiveCard\"),\n previewMessageType: \"interactiveCard\",\n previewSenderId: trimString(repliedMsg.senderId),\n };\n }\n\n return {\n isQuotedDocCard: true,\n fileCreatedAt: repliedMsg.createdAt,\n previewText:\n trimString(content?.text) ||\n buildQuotedMessageTypePlaceholder(docMeta ? \"interactiveCardFile\" : \"interactiveCard\"),\n previewMessageType: docMeta ? \"interactiveCardFile\" : \"interactiveCard\",\n previewSenderId: trimString(repliedMsg.senderId),\n };\n }\n\n if (repliedMsgType === \"chatRecord\") {\n return {\n previewText:\n formatChatRecordPreview(content as Record<string, unknown> | undefined, {\n useTitleAsLabel: true,\n }) || buildQuotedMessageTypePlaceholder(\"chatRecord\"),\n previewMessageType: \"chatRecord\",\n previewSenderId: trimString(repliedMsg.senderId),\n };\n }\n\n const textPreview =\n trimString(content?.text) ||\n trimString(richTextQuote?.summary) ||\n buildQuotedMessageTypePlaceholder(repliedMsgType, fileName);\n\n return {\n mediaDownloadCode: richTextQuote?.pictureDownloadCode,\n mediaType: richTextQuote?.pictureDownloadCode ? \"image\" : undefined,\n previewText: textPreview,\n previewMessageType: repliedMsgType,\n previewFileName: fileName,\n previewSenderId: trimString(repliedMsg.senderId),\n };\n}\n\n/**\n * Auto-detect markdown usage and derive message title.\n * Title extraction follows DingTalk markdown card title constraints.\n */\nexport function detectMarkdownAndExtractTitle(\n text: string,\n options: SendMessageOptions,\n defaultTitle: string,\n): { useMarkdown: boolean; title: string } {\n const hasMarkdown = /^[#*>-]|[*_`#[\\]]/.test(text) || text.includes(\"\\n\");\n const useMarkdown = options.useMarkdown !== false && (options.useMarkdown || hasMarkdown);\n\n const title =\n options.title ||\n (useMarkdown\n ? text\n .split(\"\\n\")[0]\n .replace(/^[#*\\s\\->]+/, \"\")\n .slice(0, 20) || defaultTitle\n : defaultTitle);\n\n return { useMarkdown, title };\n}\n\nfunction isMarkdownTableSeparator(line: string): boolean {\n const normalized = line.trim();\n if (!normalized.includes(\"-\")) {\n return false;\n }\n const cells = normalized\n .replace(/^\\|/, \"\")\n .replace(/\\|$/, \"\")\n .split(\"|\")\n .map((cell) => cell.trim());\n return cells.length > 0 && cells.every((cell) => /^:?-{3,}:?$/.test(cell));\n}\n\nfunction isMarkdownTableRow(line: string): boolean {\n const trimmed = line.trim();\n return trimmed.includes(\"|\") && !trimmed.startsWith(\"```\");\n}\n\nfunction parseMarkdownTableRow(line: string): string[] {\n return line\n .trim()\n .replace(/^\\|/, \"\")\n .replace(/\\|$/, \"\")\n .split(\"|\")\n .map((cell) => cell.trim());\n}\n\nfunction renderMarkdownTable(lines: string[]): string {\n const rows = lines.map(parseMarkdownTableRow).filter((cells) => cells.length > 0);\n return rows.map((cells) => cells.join(\" | \")).join(\" \\n\");\n}\n\nexport function convertMarkdownTablesToPlainText(text: string): string {\n const lines = text.split(\"\\n\");\n const output: string[] = [];\n let index = 0;\n let inCodeFence = false;\n\n while (index < lines.length) {\n const line = lines[index] || \"\";\n if (line.trim().startsWith(\"```\")) {\n inCodeFence = !inCodeFence;\n output.push(line);\n index += 1;\n continue;\n }\n\n if (\n !inCodeFence &&\n index + 1 < lines.length &&\n isMarkdownTableRow(line) &&\n isMarkdownTableSeparator(lines[index + 1] || \"\")\n ) {\n const tableLines = [line];\n index += 2;\n while (index < lines.length && isMarkdownTableRow(lines[index] || \"\")) {\n tableLines.push(lines[index] || \"\");\n index += 1;\n }\n output.push(renderMarkdownTable(tableLines));\n continue;\n }\n\n output.push(line);\n index += 1;\n }\n\n return output.join(\"\\n\");\n}\n\nexport function extractMessageContent(data: DingTalkInboundMessage): MessageContent {\n const msgtype = data.msgtype || \"text\";\n const atMentions: AtMention[] = [];\n\n // \u63D0\u53D6\u901A\u8FC7 @picker \u9009\u4E2D\u7684\u771F\u5B9E\u7528\u6237\u7684 dingtalkId\n // \u8FD9\u4E9B\u662F\u771F\u5B9E\u9489\u9489\u7528\u6237\uFF0C\u4E0D\u5305\u542B agent \u540D\uFF08\u5982 @frontend\uFF09\n const atUserDingtalkIds = data.atUsers?.map((u) => u.dingtalkId).filter(Boolean);\n\n const formatQuotedContent = (): QuotedInfo | null => {\n const textField = data.text;\n\n if (textField?.isReplyMsg && textField?.repliedMsg) {\n const repliedMsg = textField.repliedMsg;\n const repliedMsgType = trimString(repliedMsg.msgType);\n const content = repliedMsg.content;\n const repliedMsgId = trimString(repliedMsg.msgId) || trimString(data.originalMsgId);\n const repliedPreview = buildRepliedMessagePreview({ data, repliedMsg });\n\n if (repliedMsgType === \"picture\" && content?.downloadCode) {\n return {\n mediaDownloadCode: content.downloadCode,\n mediaType: \"image\",\n ...repliedPreview,\n };\n }\n\n if (repliedMsgType === \"richText\") {\n const richTextQuote = extractRichTextQuoteParts(content?.richText);\n if (richTextQuote) {\n return {\n msgId: repliedMsgId,\n mediaDownloadCode: richTextQuote.pictureDownloadCode,\n mediaType: richTextQuote.pictureDownloadCode ? \"image\" : undefined,\n ...repliedPreview,\n };\n }\n }\n\n if (repliedMsgType === \"unknownMsgType\") {\n return {\n isQuotedFile: true,\n fileCreatedAt: repliedMsg.createdAt,\n msgId: repliedMsgId,\n ...repliedPreview,\n };\n }\n\n if (repliedMsgType === \"file\" || repliedMsgType === \"audio\" || repliedMsgType === \"video\") {\n return {\n isQuotedFile: true,\n fileCreatedAt: repliedMsg.createdAt,\n fileDownloadCode: trimString(content?.downloadCode),\n msgId: repliedMsgId,\n ...repliedPreview,\n };\n }\n\n if (repliedMsgType === \"interactiveCard\") {\n const isBotCard = repliedMsg.senderId === data.chatbotUserId;\n if (isBotCard) {\n return {\n isQuotedCard: true,\n cardCreatedAt: repliedMsg.createdAt,\n processQueryKey: data.originalProcessQueryKey,\n msgId: repliedMsgId,\n ...repliedPreview,\n };\n }\n\n return {\n isQuotedDocCard: true,\n fileCreatedAt: repliedMsg.createdAt,\n msgId: repliedMsgId,\n ...repliedPreview,\n };\n }\n\n if (repliedMsgType && repliedMsgId) {\n return { msgId: repliedMsgId, ...repliedPreview };\n }\n\n // No msgType \u2014 backward compat: extract text or richText from content.\n if (content?.text?.trim()) {\n return repliedMsgId ? { msgId: repliedMsgId, ...repliedPreview } : null;\n }\n\n if (content?.richText && Array.isArray(content.richText)) {\n const richTextQuote = extractRichTextQuoteParts(content.richText);\n if (richTextQuote) {\n return {\n msgId: repliedMsgId,\n mediaDownloadCode: richTextQuote.pictureDownloadCode,\n mediaType: richTextQuote.pictureDownloadCode ? \"image\" : undefined,\n ...repliedPreview,\n };\n }\n }\n }\n\n if (textField?.isReplyMsg && !textField?.repliedMsg && data.originalMsgId) {\n return {\n msgId: data.originalMsgId,\n };\n }\n\n if (data.quoteMessage) {\n if (data.quoteMessage.msgId) {\n return {\n msgId: data.quoteMessage.msgId,\n ...buildLegacyQuoteMessagePreview(data.quoteMessage),\n };\n }\n }\n\n return null;\n };\n\n const quoted = formatQuotedContent();\n\n if (msgtype === \"text\") {\n const textContent = data.text?.content?.trim() || \"\";\n\n // Strip quoted prefix before extracting @mentions to avoid matching @names inside quotes.\n const textForAtExtraction = textContent.replace(/^\\[\u5F15\u7528[^\\]]*\\]\\s*/, \"\");\n atMentions.push(...extractAtMentionsFromText(textForAtExtraction));\n\n return {\n text: textContent || quoted?.previewText || \"\",\n messageType: \"text\",\n quoted: quoted ?? undefined,\n atMentions,\n atUserDingtalkIds,\n };\n }\n\n if (msgtype === \"richText\") {\n const richTextParts = data.content?.richText || [];\n let text = \"\";\n const pictureDownloadCodes: string[] = [];\n // Keep first image downloadCode while preserving readable text and @mention parts.\n for (const part of richTextParts) {\n if (part.text && (part.type === \"text\" || part.type === undefined)) {\n text += part.text;\n }\n if (part.type === \"at\" && part.atName) {\n text += `@${part.atName} `;\n // \u63D0\u53D6 @ \u63D0\u53CA\u4FE1\u606F\uFF0C\u5305\u62EC atUserId\n atMentions.push({\n name: part.atName.trim(),\n userId: part.atUserId,\n });\n }\n if (part.type === \"picture\" && part.downloadCode) {\n pictureDownloadCodes.push(part.downloadCode);\n }\n }\n const uniquePictureDownloadCodes = [...new Set(pictureDownloadCodes)];\n const pictureDownloadCode = uniquePictureDownloadCodes[0];\n return {\n text: text.trim() || (pictureDownloadCode ? \"<media:image>\" : \"[\u5BCC\u6587\u672C\u6D88\u606F]\"),\n mediaPath: pictureDownloadCode,\n mediaPaths: uniquePictureDownloadCodes.length > 0 ? uniquePictureDownloadCodes : undefined,\n mediaType: pictureDownloadCode ? \"image\" : undefined,\n mediaTypes:\n uniquePictureDownloadCodes.length > 0\n ? uniquePictureDownloadCodes.map(() => \"image\")\n : undefined,\n messageType: \"richText\",\n quoted: quoted ?? undefined,\n atMentions,\n atUserDingtalkIds,\n };\n }\n\n if (msgtype === \"picture\") {\n return {\n text: \"<media:image>\",\n mediaPath: data.content?.downloadCode,\n mediaType: \"image\",\n messageType: \"picture\",\n atMentions,\n atUserDingtalkIds,\n };\n }\n\n if (msgtype === \"audio\") {\n return {\n text: data.content?.recognition || \"<media:voice>\",\n mediaPath: data.content?.downloadCode,\n mediaType: \"audio\",\n messageType: \"audio\",\n atMentions,\n atUserDingtalkIds,\n };\n }\n\n if (msgtype === \"video\") {\n return {\n text: \"<media:video>\",\n mediaPath: data.content?.downloadCode,\n mediaType: \"video\",\n messageType: \"video\",\n atMentions,\n atUserDingtalkIds,\n };\n }\n\n if (msgtype === \"file\") {\n return {\n text: `<media:file> (${data.content?.fileName || \"\u6587\u4EF6\"})`,\n mediaPath: data.content?.downloadCode,\n mediaType: \"file\",\n messageType: \"file\",\n atMentions,\n atUserDingtalkIds,\n };\n }\n\n if (msgtype === \"markdown\") {\n const mdText = typeof data.content?.text === \"string\" ? data.content.text.trim() : \"\";\n atMentions.push(...extractAtMentionsFromText(mdText));\n return {\n text: mdText || \"[markdown\u6D88\u606F]\",\n messageType: \"markdown\",\n quoted: quoted ?? undefined,\n atMentions,\n atUserDingtalkIds,\n };\n }\n\n if (msgtype === \"interactiveCard\") {\n const docMeta = parseBizCustomActionUrl(data.content?.biz_custom_action_url);\n if (docMeta) {\n return {\n text: \"[\u9489\u9489\u6587\u6863]\\n\\n\",\n messageType: \"interactiveCardFile\",\n docSpaceId: docMeta.spaceId,\n docFileId: docMeta.fileId,\n quoted: quoted ?? undefined,\n atMentions,\n atUserDingtalkIds,\n };\n }\n return {\n text: data.text?.content?.trim() || \"[interactiveCard\u6D88\u606F]\",\n messageType: msgtype,\n quoted: quoted ?? undefined,\n atMentions,\n atUserDingtalkIds,\n };\n }\n if (msgtype === \"chatRecord\") {\n const content = data.content as Record<string, unknown> | undefined;\n const summary = typeof content?.summary === \"string\" ? content.summary.trim() : \"\";\n const rawRecord = getChatRecordEntriesSource(content);\n const chatRecordText = formatChatRecordPreview(content);\n if (\n summary === \"[]\" ||\n (typeof rawRecord === \"string\" && rawRecord.trim() === \"[]\") ||\n (Array.isArray(rawRecord) && rawRecord.length === 0)\n ) {\n return {\n text: \"[\u7CFB\u7EDF\u63D0\u793A] \u6CA1\u6709\u8BFB\u5230\u5F15\u7528\u8BB0\u5F55\uFF08chatRecord \u4E3A\u7A7A\uFF09\u3002\u8BF7\u6539\u7528\u9010\u6761\u8F6C\u53D1\u3001\u590D\u5236\u539F\u6587\uFF0C\u6216\u91CD\u65B0\u8F6C\u53D1\u975E\u7A7A\u804A\u5929\u8BB0\u5F55\u3002\",\n messageType: \"chatRecord\",\n quoted: quoted ?? undefined,\n atMentions,\n atUserDingtalkIds,\n };\n }\n if (chatRecordText) {\n return {\n text: chatRecordText,\n messageType: \"chatRecord\",\n quoted: quoted ?? undefined,\n atMentions,\n atUserDingtalkIds,\n };\n }\n return {\n text: \"[chatRecord\u6D88\u606F: \u65E0\u53EF\u8BFB\u5185\u5BB9]\",\n messageType: \"chatRecord\",\n quoted: quoted ?? undefined,\n atMentions,\n atUserDingtalkIds,\n };\n }\n\n return {\n text: data.text?.content?.trim() || `[${msgtype}\u6D88\u606F]`,\n messageType: msgtype,\n quoted: quoted ?? undefined,\n atMentions,\n atUserDingtalkIds,\n };\n}\n", "import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { AttachmentTextSource } from \"../types\";\n\nconst MAX_EXTRACTED_TEXT_CHARS = 6000;\nconst MAX_ATTACHMENT_EXTRACT_BYTES = 2 * 1024 * 1024;\n\nexport interface AttachmentTextExtractionInput {\n path: string;\n mimeType?: string;\n fileName?: string;\n}\n\nexport interface AttachmentTextExtractionResult {\n text: string;\n truncated: boolean;\n sourceType: AttachmentTextSource;\n}\n\nasync function isFileTooLarge(filePath: string): Promise<boolean> {\n const stat = await fs.stat(filePath);\n return stat.size > MAX_ATTACHMENT_EXTRACT_BYTES;\n}\n\nfunction isTextLikeMimeType(mimeType: string | undefined): boolean {\n if (!mimeType) {\n return false;\n }\n return (\n mimeType.startsWith(\"text/\") ||\n mimeType === \"application/json\" ||\n mimeType === \"application/xml\" ||\n mimeType === \"application/javascript\"\n );\n}\n\nfunction normalizeWhitespace(text: string): string {\n return text\n .replace(/\\r\\n/g, \"\\n\")\n .split(\"\\u0000\").join(\"\")\n .replace(/[ \\t]{2,}/g, \" \")\n .replace(/[ \\t]+\\n/g, \"\\n\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .trim();\n}\n\nfunction limitExtractedText(text: string): AttachmentTextExtractionResult | null {\n const normalized = normalizeWhitespace(text);\n if (!normalized) {\n return null;\n }\n const truncated = normalized.length > MAX_EXTRACTED_TEXT_CHARS;\n const limited = truncated ? `${normalized.slice(0, MAX_EXTRACTED_TEXT_CHARS)}\\n\\n[\u5185\u5BB9\u5DF2\u622A\u65AD]` : normalized;\n return {\n text: limited,\n truncated,\n sourceType: \"text\",\n };\n}\n\nfunction stripHtml(html: string): string {\n return html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, \" \")\n .replace(/<style[\\s\\S]*?<\\/style>/gi, \" \")\n .replace(/<[^>]+>/g, \" \")\n .replace(/&nbsp;/gi, \" \")\n .replace(/&lt;/gi, \"<\")\n .replace(/&gt;/gi, \">\")\n .replace(/&amp;/gi, \"&\")\n .replace(/&#39;/gi, \"'\")\n .replace(/&quot;/gi, \"\\\"\");\n}\n\nasync function extractTextLikeFile(filePath: string): Promise<AttachmentTextExtractionResult | null> {\n const raw = await fs.readFile(filePath, \"utf8\");\n return limitExtractedText(raw);\n}\n\nasync function extractPdf(filePath: string): Promise<AttachmentTextExtractionResult | null> {\n const pdfParseModule = await import(\"pdf-parse\");\n const fileBuffer = await fs.readFile(filePath);\n const parser = new pdfParseModule.PDFParse({ data: new Uint8Array(fileBuffer) });\n try {\n const result = await parser.getText();\n const limited = limitExtractedText(result.text || \"\");\n return limited ? { ...limited, sourceType: \"pdf\" } : null;\n } finally {\n await parser.destroy();\n }\n}\n\nasync function extractDocx(filePath: string): Promise<AttachmentTextExtractionResult | null> {\n const mammothModule = await import(\"mammoth\");\n const result = await mammothModule.extractRawText({ path: filePath });\n const limited = limitExtractedText(result.value || \"\");\n return limited ? { ...limited, sourceType: \"docx\" } : null;\n}\n\nasync function extractHtml(filePath: string): Promise<AttachmentTextExtractionResult | null> {\n const raw = await fs.readFile(filePath, \"utf8\");\n const limited = limitExtractedText(stripHtml(raw));\n return limited ? { ...limited, sourceType: \"html\" } : null;\n}\n\nexport async function extractAttachmentText(\n input: AttachmentTextExtractionInput,\n): Promise<AttachmentTextExtractionResult | null> {\n const mimeType = input.mimeType?.toLowerCase();\n const fileName = (input.fileName || path.basename(input.path)).toLowerCase();\n\n if (mimeType?.startsWith(\"image/\") || mimeType?.startsWith(\"audio/\") || mimeType?.startsWith(\"video/\")) {\n return null;\n }\n\n if (await isFileTooLarge(input.path)) {\n return null;\n }\n\n if (\n mimeType === \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\" ||\n fileName.endsWith(\".docx\")\n ) {\n return extractDocx(input.path);\n }\n\n if (mimeType === \"application/pdf\" || fileName.endsWith(\".pdf\")) {\n return extractPdf(input.path);\n }\n\n if (mimeType === \"text/html\" || mimeType === \"application/xhtml+xml\" || fileName.endsWith(\".html\") || fileName.endsWith(\".htm\")) {\n return extractHtml(input.path);\n }\n\n if (\n isTextLikeMimeType(mimeType) ||\n fileName.endsWith(\".txt\") ||\n fileName.endsWith(\".md\") ||\n fileName.endsWith(\".markdown\") ||\n fileName.endsWith(\".csv\") ||\n fileName.endsWith(\".json\") ||\n fileName.endsWith(\".xml\") ||\n fileName.endsWith(\".log\")\n ) {\n return extractTextLikeFile(input.path);\n }\n\n return null;\n}\n", "import * as path from \"node:path\";\nimport axios from \"./http-client\";\nimport { getAccessToken } from \"./auth\";\nimport { resolveCardRunByConversation, resolveCardRunByOwner } from \"./card/card-run-registry\";\n\nimport {\n isCardInTerminalState,\n sendProactiveCardText,\n} from \"./card-service\";\nimport { resolveRobotCode, stripTargetPrefix } from \"./config\";\nimport { getLogger } from \"./logger-context\";\nimport {\n getVoiceDurationMs,\n prepareMediaInput,\n resolveOutboundMediaType,\n uploadMedia as uploadMediaUtil,\n} from \"./media-utils\";\nimport { convertMarkdownTablesToPlainText, detectMarkdownAndExtractTitle } from \"./message-utils\";\nimport {\n DEFAULT_MESSAGE_CONTEXT_TTL_DAYS,\n DEFAULT_OUTBOUND_SENDER,\n inferConversationChatType,\n upsertOutboundMessageContext,\n} from \"./message-context-store\";\nimport { resolveOriginalPeerId } from \"./peer-id-registry\";\nimport {\n deleteProactiveRiskObservation,\n getProactiveRiskObservation,\n recordProactiveRiskObservation,\n} from \"./proactive-risk-registry\";\nimport { formatDingTalkErrorPayloadLog, getProxyBypassOption } from \"./utils\";\nimport type { UploadMediaResult } from \"./media-utils\";\nimport type {\n AICardInstance,\n AxiosResponse,\n DingTalkConfig,\n DingTalkTrackingMetadata,\n Logger,\n ProactiveMessagePayload,\n QuotedRef,\n SendMessageOptions,\n SessionWebhookResponse,\n} from \"./types\";\n\nexport { detectMediaTypeFromExtension } from \"./media-utils\";\n\nconst MARKDOWN_LOCAL_IMAGE_RE =\n /!\\[([^\\]]*)\\]\\((file:\\/\\/\\/[^)]+|\\/(?:tmp|var|private|Users|home|root)[^)]+|[A-Za-z]:[\\\\/][^)]+)\\)/g;\n\nfunction decodeMarkdownLocalImagePath(rawPath: string): string {\n const unescapedPath = rawPath.replace(/\\\\ /g, \" \");\n if (unescapedPath.startsWith(\"file://\")) {\n try {\n return decodeURIComponent(unescapedPath.replace(\"file://\", \"\"));\n } catch {\n return unescapedPath.replace(\"file://\", \"\");\n }\n }\n return unescapedPath;\n}\n\nasync function replaceMarkdownLocalImages(params: {\n config: DingTalkConfig;\n text: string;\n log?: Logger;\n mediaLocalRoots?: string[];\n}): Promise<string> {\n const matches = [...params.text.matchAll(MARKDOWN_LOCAL_IMAGE_RE)];\n if (matches.length === 0) {\n return params.text;\n }\n\n let result = params.text;\n for (const match of matches) {\n const [fullMatch, altText, rawPath] = match;\n const mediaPath = decodeMarkdownLocalImagePath(rawPath);\n const uploadResult = await uploadMedia(params.config, mediaPath, \"image\", params.log, {\n mediaLocalRoots: params.mediaLocalRoots,\n });\n\n if (!uploadResult?.mediaId) {\n params.log?.warn?.(\n `[DingTalk] Markdown local image upload failed, keep original reference: ${mediaPath}`,\n );\n continue;\n }\n\n result = result.replace(fullMatch, () => `![${altText}](${uploadResult.mediaId})`);\n }\n\n return result;\n}\n\ntype ProactiveTextSendResult = AxiosResponse | { tracking: DingTalkTrackingMetadata };\n\nfunction isTrackingResult(result: ProactiveTextSendResult): result is { tracking: DingTalkTrackingMetadata } {\n return \"tracking\" in result;\n}\n\nfunction firstTrimmedString(...candidates: unknown[]): string | undefined {\n for (const candidate of candidates) {\n if (typeof candidate === \"string\" && candidate.trim()) {\n return candidate.trim();\n }\n }\n return undefined;\n}\n\nfunction extractOutboundDeliveryMetadata(payload: unknown): {\n messageId?: string;\n processQueryKey?: string;\n outTrackId?: string;\n cardInstanceId?: string;\n} {\n if (!payload || typeof payload !== \"object\") {\n return {};\n }\n const data = payload as Record<string, unknown>;\n const tracking =\n data.tracking && typeof data.tracking === \"object\"\n ? (data.tracking as Record<string, unknown>)\n : undefined;\n const messageId = firstTrimmedString(data.messageId, data.msgid, tracking?.messageId, tracking?.msgid);\n const processQueryKey = firstTrimmedString(data.processQueryKey, tracking?.processQueryKey);\n const outTrackId = firstTrimmedString(data.outTrackId, tracking?.outTrackId);\n const cardInstanceId = firstTrimmedString(data.cardInstanceId, tracking?.cardInstanceId);\n return { messageId, processQueryKey, outTrackId, cardInstanceId };\n}\n\nfunction persistOutboundMessageContext(params: {\n storePath?: string;\n accountId?: string;\n conversationId: string;\n text?: string;\n messageType?: string;\n createdAt?: number;\n quotedRef?: QuotedRef;\n log?: Logger;\n senderId?: string;\n senderName?: string;\n chatType?: \"direct\" | \"group\";\n delivery: {\n messageId?: string;\n processQueryKey?: string;\n outTrackId?: string;\n cardInstanceId?: string;\n kind?: \"session\" | \"proactive-text\" | \"proactive-card\" | \"proactive-media\";\n };\n}): void {\n if (!params.storePath || !params.accountId) {\n return;\n }\n params.log?.debug?.(\n `[DingTalk][QuotedRef][Persist] direction=outbound scope=${params.conversationId} ` +\n `messageType=${params.messageType || \"(none)\"} processQueryKey=${params.delivery.processQueryKey || \"(none)\"} ` +\n `messageId=${params.delivery.messageId || \"(none)\"} quotedRef=${params.quotedRef ? JSON.stringify(params.quotedRef) : \"(none)\"}`,\n );\n upsertOutboundMessageContext({\n storePath: params.storePath,\n accountId: params.accountId,\n conversationId: params.conversationId,\n createdAt: params.createdAt ?? Date.now(),\n text: params.text,\n messageType: params.messageType,\n senderId: params.senderId,\n senderName: params.senderName,\n chatType: params.chatType,\n ttlMs: DEFAULT_MESSAGE_CONTEXT_TTL_DAYS * 24 * 60 * 60 * 1000,\n topic: null,\n quotedRef: params.quotedRef,\n delivery: params.delivery,\n });\n}\n\nfunction buildPersistedOutboundText(text: string, options: SendMessageOptions): string {\n if (text) {\n return text;\n }\n if (options.mediaPath && options.mediaType) {\n return `[media:${options.mediaType}] ${options.mediaPath}`;\n }\n return text;\n}\n\nconst DINGTALK_TEXT_CHUNK_LIMIT = 3800;\nconst CARD_MEDIA_CONTROLLER_ATTACH_WAIT_MS = 150;\nconst CARD_MEDIA_CONTROLLER_ATTACH_POLL_MS = 25;\n\nasync function waitForCardControllerAttachment(\n activeRun: ReturnType<typeof resolveCardRunByConversation>,\n): Promise<NonNullable<ReturnType<typeof resolveCardRunByConversation>>[\"controller\"] | null> {\n if (!activeRun) {\n return null;\n }\n if (activeRun.controller?.appendImageBlock) {\n return activeRun.controller;\n }\n\n const deadline = Date.now() + CARD_MEDIA_CONTROLLER_ATTACH_WAIT_MS;\n while (Date.now() < deadline) {\n await new Promise((resolve) => setTimeout(resolve, CARD_MEDIA_CONTROLLER_ATTACH_POLL_MS));\n if (activeRun.controller?.appendImageBlock) {\n return activeRun.controller;\n }\n }\n\n return activeRun.controller?.appendImageBlock ? activeRun.controller : null;\n}\n\nfunction splitMarkdownChunks(text: string, limit = DINGTALK_TEXT_CHUNK_LIMIT): string[] {\n if (!text || text.length <= limit) {\n return [text];\n }\n const chunks: string[] = [];\n let buf = \"\";\n const lines = text.split(\"\\n\");\n let inCode = false;\n\n for (const line of lines) {\n const fenceCount = (line.match(/```/g) || []).length;\n if (buf.length + line.length + 1 > limit && buf.length > 0) {\n if (inCode) {\n buf += \"\\n```\";\n }\n chunks.push(buf);\n buf = inCode ? \"```\\n\" : \"\";\n }\n buf += (buf ? \"\\n\" : \"\") + line;\n if (fenceCount % 2 === 1) {\n inCode = !inCode;\n }\n }\n if (buf) {\n chunks.push(buf);\n }\n return chunks;\n}\n\nfunction extractErrorCodeFromResponseData(data: unknown): string | null {\n if (!data || typeof data !== \"object\") {\n return null;\n }\n\n const payload = data as Record<string, unknown>;\n const errcode = payload.errcode;\n if (typeof errcode === \"number\" && Number.isFinite(errcode)) {\n return String(errcode);\n }\n if (typeof errcode === \"string\" && errcode.trim()) {\n return errcode.trim();\n }\n\n const code = payload.code;\n if (typeof code === \"string\" && code.trim()) {\n return code.trim();\n }\n\n const subCode = payload.subCode;\n if (typeof subCode === \"string\" && subCode.trim()) {\n return subCode.trim();\n }\n\n return null;\n}\n\nfunction summarizeSessionWebhookResponse(data: unknown): string {\n if (!data || typeof data !== \"object\") {\n return `type=${typeof data}`;\n }\n const payload = data as Record<string, unknown>;\n const code = extractErrorCodeFromResponseData(payload) || \"(none)\";\n const message = firstTrimmedString(\n payload.message,\n payload.errmsg,\n payload.msg,\n payload.errorMessage,\n ) || \"(none)\";\n const success =\n typeof payload.success === \"boolean\"\n ? String(payload.success)\n : typeof payload.result === \"boolean\"\n ? String(payload.result)\n : \"(none)\";\n const delivery = extractOutboundDeliveryMetadata(payload);\n return (\n `success=${success} code=${code} message=${message} ` +\n `messageId=${delivery.messageId || \"(none)\"} ` +\n `processQueryKey=${delivery.processQueryKey || \"(none)\"} ` +\n `outTrackId=${delivery.outTrackId || \"(none)\"}`\n );\n}\n\nfunction ensureSessionWebhookBusinessSuccess(\n data: unknown,\n context: { msgtype: string },\n): void {\n if (!data || typeof data !== \"object\") {\n return;\n }\n const payload = data as Record<string, unknown>;\n const code = extractErrorCodeFromResponseData(payload);\n const message = firstTrimmedString(\n payload.message,\n payload.errmsg,\n payload.msg,\n payload.errorMessage,\n ) || \"unknown error\";\n\n const hasFailureSuccessFlag = payload.success === false || payload.result === false;\n const hasFailureCode = typeof code === \"string\" && code !== \"\" && code !== \"0\";\n if (!hasFailureSuccessFlag && !hasFailureCode) {\n return;\n }\n\n const reason = [\n code && code !== \"0\" ? `code=${code}` : \"\",\n message !== \"unknown error\" ? `message=${message}` : \"\",\n ].filter(Boolean).join(\" \");\n throw new Error(`Session webhook ${context.msgtype} send failed${reason ? `: ${reason}` : \"\"}`);\n}\n\nfunction isProactivePermissionOrScopeError(code: string | null): boolean {\n if (!code) {\n return false;\n }\n return (\n code.startsWith(\"Forbidden.AccessDenied\") ||\n code === \"invalidParameter.userIds.invalid\" ||\n code === \"invalidParameter.userIds.empty\" ||\n code === \"invalidParameter.openConversationId.invalid\" ||\n code === \"invalidParameter.robotCode.empty\"\n );\n}\n\n/**\n * Wrapper to upload media with shared getAccessToken binding.\n */\nexport async function uploadMedia(\n config: DingTalkConfig,\n mediaPath: string,\n mediaType: \"image\" | \"voice\" | \"video\" | \"file\",\n log?: Logger,\n options?: { mediaLocalRoots?: string[] },\n): Promise<UploadMediaResult | null> {\n return uploadMediaUtil(config, mediaPath, mediaType, getAccessToken, log, options);\n}\n\nexport async function sendProactiveTextOrMarkdown(\n config: DingTalkConfig,\n target: string,\n text: string,\n options: SendMessageOptions = {},\n): Promise<ProactiveTextSendResult> {\n const log = options.log || getLogger();\n\n // Support group:/user: prefix and restore original case-sensitive conversationId.\n const { targetId, isExplicitUser } = stripTargetPrefix(target);\n const resolvedTarget = resolveOriginalPeerId(targetId);\n const isGroup = !isExplicitUser && resolvedTarget.startsWith(\"cid\");\n const proactiveRisk = options.accountId\n ? getProactiveRiskObservation(options.accountId, resolvedTarget)\n : null;\n const proactiveRiskTag = proactiveRisk\n ? ` proactiveRisk=${proactiveRisk.level}:${proactiveRisk.reason}`\n : \"\";\n\n // In card mode, use card API to avoid oToMessages/batchSend permission requirement.\n const messageType = config.messageType || \"markdown\";\n if (messageType === \"card\" && !options.forceMarkdown) {\n log?.debug?.(\n `[DingTalk] Using card API for proactive message to user ${resolvedTarget}${proactiveRiskTag}`,\n );\n const result = await sendProactiveCardText(config, resolvedTarget, text, log);\n if (result.ok) {\n if (options.accountId) {\n deleteProactiveRiskObservation(options.accountId, resolvedTarget);\n }\n return {\n tracking: {\n processQueryKey: result.processQueryKey,\n outTrackId: result.outTrackId,\n cardInstanceId: result.cardInstanceId,\n },\n };\n }\n log?.warn?.(\n `[DingTalk] Proactive card send failed, fallback to proactive template API: ${result.error || \"unknown\"}`,\n );\n }\n\n const token = await getAccessToken(config, log);\n const url = isGroup\n ? \"https://api.dingtalk.com/v1.0/robot/groupMessages/send\"\n : \"https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend\";\n\n const textWithUploadedLocalImages = await replaceMarkdownLocalImages({\n config,\n text,\n log,\n mediaLocalRoots: options.mediaLocalRoots,\n });\n const normalizedText =\n config.convertMarkdownTables !== false\n ? convertMarkdownTablesToPlainText(textWithUploadedLocalImages)\n : textWithUploadedLocalImages;\n const { useMarkdown, title } = detectMarkdownAndExtractTitle(normalizedText, options, \"OpenClaw \u63D0\u9192\");\n\n log?.debug?.(\n `[DingTalk] Sending proactive message to ${isGroup ? \"group\" : \"user\"} ${resolvedTarget} with title \"${title}\"${proactiveRiskTag}`,\n );\n\n // DingTalk proactive API uses message templates (sampleMarkdown / sampleText).\n const msgKey = useMarkdown ? \"sampleMarkdown\" : \"sampleText\";\n const msgParam = useMarkdown\n ? JSON.stringify({ title, text: normalizedText })\n : JSON.stringify({ content: normalizedText });\n\n const payload: ProactiveMessagePayload = {\n robotCode: resolveRobotCode(config),\n msgKey,\n msgParam,\n };\n\n if (isGroup) {\n payload.openConversationId = resolvedTarget;\n } else {\n payload.userIds = [resolvedTarget];\n }\n\n try {\n const result = await axios({\n url,\n method: \"POST\",\n data: payload,\n headers: { \"x-acs-dingtalk-access-token\": token, \"Content-Type\": \"application/json\" },\n ...getProxyBypassOption(config),\n });\n if (options.accountId) {\n deleteProactiveRiskObservation(options.accountId, resolvedTarget);\n }\n return result.data;\n } catch (err: unknown) {\n const maybeAxiosError = err as {\n response?: { status?: number; statusText?: string; data?: unknown };\n message?: string;\n };\n if (maybeAxiosError?.response) {\n const errCode = extractErrorCodeFromResponseData(maybeAxiosError.response.data);\n if (options.accountId && isProactivePermissionOrScopeError(errCode)) {\n recordProactiveRiskObservation({\n accountId: options.accountId,\n targetId: resolvedTarget,\n level: \"high\",\n reason: errCode || \"proactive-permission-error\",\n source: \"proactive-api\",\n });\n }\n const status = maybeAxiosError.response.status;\n const statusText = maybeAxiosError.response.statusText;\n const statusLabel = status ? ` status=${status}${statusText ? ` ${statusText}` : \"\"}` : \"\";\n log?.error?.(\n `[DingTalk] Failed to send proactive message:${statusLabel} message=${\n maybeAxiosError.message || String(err)\n }${proactiveRiskTag}`,\n );\n if (maybeAxiosError.response.data !== undefined) {\n log?.error?.(\n formatDingTalkErrorPayloadLog(\"send.proactiveMessage\", maybeAxiosError.response.data),\n );\n }\n } else if (err instanceof Error) {\n log?.error?.(`[DingTalk] Failed to send proactive message: ${err.message}`);\n } else {\n log?.error?.(`[DingTalk] Failed to send proactive message: ${String(err)}`);\n }\n throw err;\n }\n}\n\nexport async function sendProactiveMedia(\n config: DingTalkConfig,\n target: string,\n mediaPath: string,\n mediaType: \"image\" | \"voice\" | \"video\" | \"file\",\n options: SendMessageOptions & { accountId?: string } = {},\n): Promise<{ ok: boolean; error?: string; data?: any; messageId?: string; mediaId?: string }> {\n const log = options.log || getLogger();\n\n try {\n // Upload first, then send by media_id.\n const uploadResult = await uploadMedia(config, mediaPath, mediaType, log, {\n mediaLocalRoots: options.mediaLocalRoots,\n });\n if (!uploadResult) {\n return { ok: false, error: \"Failed to upload media\" };\n }\n const { mediaId, buffer, durationMs: uploadedDurationMs } = uploadResult;\n\n const token = await getAccessToken(config, log);\n const { targetId, isExplicitUser } = stripTargetPrefix(target);\n const resolvedTarget = resolveOriginalPeerId(targetId);\n const isGroup = !isExplicitUser && resolvedTarget.startsWith(\"cid\");\n\n const dingtalkApi = \"https://api.dingtalk.com\";\n const url = isGroup\n ? `${dingtalkApi}/v1.0/robot/groupMessages/send`\n : `${dingtalkApi}/v1.0/robot/oToMessages/batchSend`;\n\n // Build DingTalk template payload by media type.\n let msgKey: string;\n let msgParam: string;\n\n if (mediaType === \"image\") {\n msgKey = \"sampleImageMsg\";\n msgParam = JSON.stringify({ photoURL: mediaId });\n } else if (mediaType === \"voice\") {\n msgKey = \"sampleAudio\";\n const durationMs = uploadedDurationMs\n ?? await getVoiceDurationMs(mediaPath, mediaType, log, { preReadBuffer: buffer });\n msgParam = JSON.stringify({ mediaId, duration: String(durationMs) });\n } else {\n // sampleVideo requires picMediaId; fallback to sampleFile for broader compatibility.\n const filename = path.basename(mediaPath);\n const defaultExt = mediaType === \"video\" ? \"mp4\" : \"file\";\n const ext = path.extname(mediaPath).slice(1) || defaultExt;\n msgKey = \"sampleFile\";\n msgParam = JSON.stringify({ mediaId, fileName: filename, fileType: ext });\n }\n\n const payload: ProactiveMessagePayload = {\n robotCode: resolveRobotCode(config),\n msgKey,\n msgParam,\n };\n\n if (isGroup) {\n payload.openConversationId = resolvedTarget;\n } else {\n payload.userIds = [resolvedTarget];\n }\n\n log?.debug?.(\n `[DingTalk] Sending proactive ${mediaType} message to ${isGroup ? \"group\" : \"user\"} ${resolvedTarget}`,\n );\n\n const result = await axios({\n url,\n method: \"POST\",\n data: payload,\n headers: { \"x-acs-dingtalk-access-token\": token, \"Content-Type\": \"application/json\" },\n ...getProxyBypassOption(config),\n });\n if (options.accountId) {\n deleteProactiveRiskObservation(options.accountId, resolvedTarget);\n }\n\n const delivery = extractOutboundDeliveryMetadata(result.data);\n const messageId = delivery.messageId || delivery.processQueryKey || delivery.outTrackId;\n persistOutboundMessageContext({\n storePath: options.storePath,\n accountId: options.accountId,\n conversationId: options.conversationId || resolvedTarget,\n text: `[media:${mediaType}] ${mediaPath}`,\n messageType: \"outbound-proactive-media\",\n quotedRef: options.quotedRef,\n log,\n ...DEFAULT_OUTBOUND_SENDER,\n chatType: inferConversationChatType(options.conversationId || resolvedTarget),\n delivery: {\n ...delivery,\n kind: \"proactive-media\",\n },\n });\n return { ok: true, data: result.data, messageId, mediaId };\n } catch (err: any) {\n log?.error?.(`[DingTalk] Failed to send proactive media: ${err.message}`);\n const normalizedTarget = resolveOriginalPeerId(stripTargetPrefix(target).targetId);\n const proactiveRisk = options.accountId\n ? getProactiveRiskObservation(options.accountId, normalizedTarget)\n : null;\n const proactiveRiskTag = proactiveRisk\n ? ` proactiveRisk=${proactiveRisk.level}:${proactiveRisk.reason}`\n : \"\";\n if (axios.isAxiosError(err) && err.response) {\n const errCode = extractErrorCodeFromResponseData(err.response.data);\n if (options.accountId && isProactivePermissionOrScopeError(errCode)) {\n recordProactiveRiskObservation({\n accountId: options.accountId,\n targetId: normalizedTarget,\n level: \"high\",\n reason: errCode || \"proactive-permission-error\",\n source: \"proactive-api\",\n });\n }\n const status = err.response.status;\n const statusText = err.response.statusText;\n const statusLabel = status ? ` status=${status}${statusText ? ` ${statusText}` : \"\"}` : \"\";\n log?.error?.(`[DingTalk] Proactive media response${statusLabel}${proactiveRiskTag}`);\n log?.error?.(formatDingTalkErrorPayloadLog(\"send.proactiveMedia\", err.response.data));\n }\n\n // Fallback: ensure user still gets a usable link/path text.\n const fallbackDisplayText = `\uD83D\uDCCE \u5A92\u4F53\u53D1\u9001\u5931\u8D25\uFF0C\u515C\u5E95\u94FE\u63A5/\u8DEF\u5F84\uFF1A${mediaPath}`;\n const fallbackPersistedText = `\u5A92\u4F53\u53D1\u9001\u5931\u8D25\uFF0C\u515C\u5E95\u94FE\u63A5/\u8DEF\u5F84\uFF1A${mediaPath}`;\n const fallback = await sendProactiveTextOrMarkdown(\n config,\n target,\n fallbackDisplayText,\n options,\n ).catch((fallbackErr: any) => ({ __fallbackError: fallbackErr }));\n\n if ((fallback as any)?.__fallbackError) {\n return { ok: false, error: `${err.message}; fallback failed: ${(fallback as any).__fallbackError?.message || \"unknown\"}` };\n }\n\n const fallbackDelivery = extractOutboundDeliveryMetadata(fallback);\n const fallbackMessageId =\n fallbackDelivery.messageId || fallbackDelivery.processQueryKey || fallbackDelivery.outTrackId;\n persistOutboundMessageContext({\n storePath: options.storePath,\n accountId: options.accountId,\n conversationId: options.conversationId || normalizedTarget,\n text: fallbackPersistedText,\n messageType: \"outbound-proactive-fallback\",\n quotedRef: options.quotedRef,\n log,\n ...DEFAULT_OUTBOUND_SENDER,\n chatType: inferConversationChatType(options.conversationId || normalizedTarget),\n delivery: {\n ...fallbackDelivery,\n kind: isTrackingResult(fallback as ProactiveTextSendResult) ? \"proactive-card\" : \"proactive-text\",\n },\n });\n return { ok: true, data: fallback, messageId: fallbackMessageId };\n }\n}\n\nexport async function sendMedia(\n config: DingTalkConfig,\n target: string,\n mediaInput: string,\n options: SendMessageOptions & {\n mediaType?: \"image\" | \"voice\" | \"video\" | \"file\";\n audioAsVoice?: boolean;\n expectedCardOwnerId?: string;\n } = {},\n): Promise<{ ok: boolean; error?: string; data?: any; messageId?: string; mediaId?: string }> {\n const log = options.log || getLogger();\n let preparedMedia: Awaited<ReturnType<typeof prepareMediaInput>> | undefined;\n\n try {\n preparedMedia = await prepareMediaInput(mediaInput, log, config.mediaUrlAllowlist);\n const mediaPath = preparedMedia.cleanup\n ? preparedMedia.path\n : path.resolve(process.cwd(), preparedMedia.path);\n const mediaType = resolveOutboundMediaType({\n mediaType: options.mediaType,\n mediaPath,\n asVoice: options.audioAsVoice === true,\n });\n\n if (config.messageType === \"card\" && mediaType === \"image\") {\n const accountId = options.accountId ?? \"default\";\n\n // Three-tier lookup strategy to handle sessionKey=- from runtime:\n // 1. If conversationId is available: try owner-filtered then conversation-only\n // 2. If conversationId is undefined but owner is provided: try owner-only lookup\n // 3. Otherwise: no active card found\n let activeRun = null;\n\n if (options.conversationId) {\n // conversationId explicitly provided (parsed from sessionKey)\n activeRun = options.expectedCardOwnerId\n ? resolveCardRunByConversation(accountId, options.conversationId, {\n ownerUserId: options.expectedCardOwnerId,\n }) ?? resolveCardRunByConversation(accountId, options.conversationId, undefined)\n : resolveCardRunByConversation(accountId, options.conversationId, undefined);\n } else if (options.expectedCardOwnerId) {\n // Fallback: when sessionKey=- causes conversationId to be undefined,\n // try owner-only matching as last resort\n activeRun = resolveCardRunByOwner(accountId, options.expectedCardOwnerId);\n if (activeRun) {\n log?.debug?.(\n `[DingTalk] Matched active card by owner-only lookup (conversationId unavailable) ` +\n `accountId=${accountId} ownerUserId=${options.expectedCardOwnerId} outTrackId=${activeRun.outTrackId}`,\n );\n }\n }\n\n const uploadResult = await uploadMedia(config, mediaPath, \"image\", log, {\n mediaLocalRoots: options.mediaLocalRoots,\n });\n if (!uploadResult?.mediaId) {\n return { ok: false, error: \"Failed to upload media\" };\n }\n\n const activeController = await waitForCardControllerAttachment(activeRun);\n if (activeController?.appendImageBlock) {\n await activeController.appendImageBlock(uploadResult.mediaId);\n return { ok: true, mediaId: uploadResult.mediaId };\n }\n\n if (activeRun) {\n log?.debug?.(\n `[DingTalk] Active card matched but controller was not attached in time; fallback to proactive media send`,\n );\n } else {\n log?.debug?.(\n `[DingTalk] No active card found for media embedding; fallback to proactive media send`,\n );\n }\n }\n\n return await sendProactiveMedia(config, target, mediaPath, mediaType, options);\n } finally {\n await preparedMedia?.cleanup?.();\n }\n}\n\nexport async function sendBySession(\n config: DingTalkConfig,\n sessionWebhook: string,\n text: string,\n options: SendMessageOptions = {},\n): Promise<AxiosResponse> {\n const token = await getAccessToken(config, options.log);\n const log = options.log || getLogger();\n\n // Session webhook supports native media messages; prefer that when media info is available.\n if (options.mediaPath && options.mediaType) {\n const uploadResult = await uploadMedia(config, options.mediaPath, options.mediaType, log, {\n mediaLocalRoots: options.mediaLocalRoots,\n });\n if (uploadResult) {\n const { mediaId, buffer, durationMs: uploadedDurationMs } = uploadResult;\n let body: any;\n\n if (options.mediaType === \"image\") {\n body = { msgtype: \"image\", image: { media_id: mediaId } };\n } else if (options.mediaType === \"voice\") {\n const durationMs = uploadedDurationMs\n ?? await getVoiceDurationMs(options.mediaPath, options.mediaType, log, { preReadBuffer: buffer });\n body = { msgtype: \"voice\", voice: { media_id: mediaId, duration: String(durationMs) } };\n log?.debug?.(\n `[DingTalk] Sending session voice message mediaId=${mediaId} durationMs=${durationMs}`,\n );\n } else if (options.mediaType === \"video\") {\n body = { msgtype: \"video\", video: { media_id: mediaId } };\n } else if (options.mediaType === \"file\") {\n body = { msgtype: \"file\", file: { media_id: mediaId } };\n }\n\n if (body) {\n const result = await axios({\n url: sessionWebhook,\n method: \"POST\",\n data: body,\n headers: { \"x-acs-dingtalk-access-token\": token, \"Content-Type\": \"application/json\" },\n ...getProxyBypassOption(config),\n });\n log?.debug?.(\n `[DingTalk] Session webhook response msgtype=${body.msgtype} ${summarizeSessionWebhookResponse(result.data)}`,\n );\n ensureSessionWebhookBusinessSuccess(result.data, { msgtype: body.msgtype });\n const delivery = extractOutboundDeliveryMetadata(result.data);\n if (!delivery.messageId && !delivery.processQueryKey && !delivery.outTrackId) {\n log?.warn?.(\n `[DingTalk] Session webhook ${body.msgtype} response missing delivery metadata; ` +\n summarizeSessionWebhookResponse(result.data),\n );\n }\n return result.data;\n }\n } else {\n const mediaHint = options.mediaUrl || options.mediaPath || options.filePath || \"(\u5A92\u4F53\u53D1\u9001\u5931\u8D25)\";\n text = `${text}\\n\\n\uD83D\uDCCE \u5A92\u4F53\u53D1\u9001\u5931\u8D25\uFF0C\u515C\u5E95\u94FE\u63A5/\u8DEF\u5F84\uFF1A${mediaHint}`.trim();\n log?.warn?.(\"[DingTalk] Media upload failed, falling back to text description\");\n }\n }\n\n // Fallback to text/markdown reply payload.\n const textWithUploadedLocalImages = await replaceMarkdownLocalImages({\n config,\n text,\n log,\n mediaLocalRoots: options.mediaLocalRoots,\n });\n const normalizedText =\n config.convertMarkdownTables !== false\n ? convertMarkdownTablesToPlainText(textWithUploadedLocalImages)\n : textWithUploadedLocalImages;\n const { useMarkdown, title } = detectMarkdownAndExtractTitle(normalizedText, options, \"Clawdbot \u6D88\u606F\");\n const chunks = splitMarkdownChunks(normalizedText, DINGTALK_TEXT_CHUNK_LIMIT);\n\n let lastResult: any = null;\n for (const [idx, chunk] of chunks.entries()) {\n let body: SessionWebhookResponse;\n if (useMarkdown) {\n let finalText = chunk;\n if (options.atUserId && idx === chunks.length - 1) {\n finalText = `${finalText} @${options.atUserId}`;\n }\n body = { msgtype: \"markdown\", markdown: { title: chunks.length > 1 ? `${title} (${idx + 1}/${chunks.length})` : title, text: finalText } };\n } else {\n body = { msgtype: \"text\", text: { content: chunk } };\n }\n\n if (options.atUserId && idx === chunks.length - 1) {\n body.at = { atUserIds: [options.atUserId], isAtAll: false };\n }\n\n const result = await axios({\n url: sessionWebhook,\n method: \"POST\",\n data: body,\n headers: { \"x-acs-dingtalk-access-token\": token, \"Content-Type\": \"application/json\" },\n ...getProxyBypassOption(config),\n });\n log?.debug?.(\n `[DingTalk] Session webhook response msgtype=${body.msgtype} ${summarizeSessionWebhookResponse(result.data)}`,\n );\n ensureSessionWebhookBusinessSuccess(result.data, { msgtype: body.msgtype });\n lastResult = result.data;\n }\n return lastResult;\n}\n\nexport async function sendMessage(\n config: DingTalkConfig,\n conversationId: string,\n text: string,\n options: SendMessageOptions & { sessionWebhook?: string; card?: AICardInstance; accountId?: string } = {},\n): Promise<{ ok: boolean; error?: string; data?: AxiosResponse; messageId?: string; tracking?: DingTalkTrackingMetadata }> {\n try {\n const messageType = config.messageType || \"markdown\";\n const log = options.log || getLogger();\n\n if (messageType === \"card\" && options.card && !options.forceMarkdown) {\n const card = options.card;\n if (isCardInTerminalState(card.state)) {\n if (options.sessionWebhook) {\n await sendBySession(config, options.sessionWebhook, text, options);\n return { ok: true };\n }\n\n const proactiveResult = await sendProactiveCardText(config, conversationId, text, log);\n if (!proactiveResult.ok) {\n return { ok: false, error: proactiveResult.error || \"Card send failed\" };\n }\n return {\n ok: true,\n tracking: {\n processQueryKey: proactiveResult.processQueryKey,\n outTrackId: proactiveResult.outTrackId,\n cardInstanceId: proactiveResult.cardInstanceId,\n },\n };\n }\n }\n\n if (options.sessionWebhook && options.mediaPath && options.mediaType === \"voice\") {\n log?.debug?.(\n \"[DingTalk] Session webhook does not support voice replies reliably; \" +\n \"using proactive media API for this voice response\",\n );\n const proactiveVoiceResult = await sendProactiveMedia(\n config,\n conversationId,\n options.mediaPath,\n options.mediaType,\n options,\n );\n if (!proactiveVoiceResult.ok) {\n return { ok: false, error: proactiveVoiceResult.error || \"Voice reply send failed\" };\n }\n return {\n ok: true,\n data: proactiveVoiceResult.data,\n messageId: proactiveVoiceResult.messageId,\n };\n }\n\n if (options.sessionWebhook) {\n const data = await sendBySession(config, options.sessionWebhook, text, options);\n const delivery = extractOutboundDeliveryMetadata(data);\n const messageId = delivery.messageId || delivery.processQueryKey || delivery.outTrackId;\n const persistedText = buildPersistedOutboundText(text, options);\n persistOutboundMessageContext({\n storePath: options.storePath,\n accountId: options.accountId,\n conversationId: options.conversationId || conversationId,\n text: persistedText,\n messageType: options.mediaPath && options.mediaType ? \"outbound-media\" : \"outbound\",\n quotedRef: options.quotedRef,\n log,\n ...DEFAULT_OUTBOUND_SENDER,\n chatType: inferConversationChatType(options.conversationId || conversationId),\n delivery: {\n ...delivery,\n kind: \"session\",\n },\n });\n return { ok: true, data, messageId };\n }\n\n const result = await sendProactiveTextOrMarkdown(config, conversationId, text, options);\n const delivery = extractOutboundDeliveryMetadata(result);\n const messageId = delivery.messageId || delivery.processQueryKey || delivery.outTrackId;\n persistOutboundMessageContext({\n storePath: options.storePath,\n accountId: options.accountId,\n conversationId: options.conversationId || conversationId,\n text,\n messageType: \"outbound-proactive\",\n quotedRef: options.quotedRef,\n log,\n ...DEFAULT_OUTBOUND_SENDER,\n chatType: inferConversationChatType(options.conversationId || conversationId),\n delivery: {\n ...delivery,\n kind: isTrackingResult(result) ? \"proactive-card\" : \"proactive-text\",\n },\n });\n if (isTrackingResult(result)) {\n return { ok: true, tracking: result.tracking };\n }\n return { ok: true, data: result, messageId };\n } catch (err: any) {\n options.log?.error?.(`[DingTalk] Send message failed: ${err.message}`);\n if (err?.response?.data !== undefined) {\n options.log?.error?.(formatDingTalkErrorPayloadLog(\"send.message\", err.response.data));\n }\n return { ok: false, error: err.message };\n }\n}\n", "type ProactiveRiskLevel = \"low\" | \"medium\" | \"high\";\n\nexport interface ProactiveRiskObservation {\n accountId: string;\n targetId: string;\n level: ProactiveRiskLevel;\n reason: string;\n source: string;\n observedAtMs?: number;\n}\n\nexport interface ProactiveRiskSnapshot {\n level: ProactiveRiskLevel;\n reason: string;\n source: string;\n observedAtMs: number;\n}\n\nconst DEFAULT_TTL_MS = 7 * 24 * 60 * 60 * 1000;\nconst store = new Map<string, ProactiveRiskSnapshot>();\n\nfunction keyOf(accountId: string, targetId: string): string {\n return `${accountId}:${targetId.trim()}`;\n}\n\nexport function recordProactiveRiskObservation(observation: ProactiveRiskObservation): void {\n const targetId = observation.targetId?.trim();\n if (!observation.accountId || !targetId) {\n return;\n }\n\n store.set(keyOf(observation.accountId, targetId), {\n level: observation.level,\n reason: observation.reason,\n source: observation.source,\n observedAtMs: observation.observedAtMs ?? Date.now(),\n });\n}\n\nexport function getProactiveRiskObservation(\n accountId: string,\n targetId: string,\n nowMs = Date.now(),\n): ProactiveRiskSnapshot | null {\n const target = targetId?.trim();\n if (!accountId || !target) {\n return null;\n }\n\n const key = keyOf(accountId, target);\n const entry = store.get(key);\n if (!entry) {\n return null;\n }\n if (nowMs - entry.observedAtMs > DEFAULT_TTL_MS) {\n store.delete(key);\n return null;\n }\n return entry;\n}\n\nexport function getProactiveRiskObservationForAny(\n accountId: string,\n targetIds: Array<string | null | undefined>,\n nowMs = Date.now(),\n): ProactiveRiskSnapshot | null {\n for (const candidate of targetIds) {\n if (!candidate) {\n continue;\n }\n const observation = getProactiveRiskObservation(accountId, candidate, nowMs);\n if (observation) {\n return observation;\n }\n }\n return null;\n}\n\nexport function deleteProactiveRiskObservation(accountId: string, targetId: string): void {\n const target = targetId?.trim();\n if (!accountId || !target) {\n return;\n }\n store.delete(keyOf(accountId, target));\n}\n\nexport function clearProactiveRiskObservationsForTest(): void {\n store.clear();\n}\n", "import { sendMessage } from \"../send-service\";\nimport type { DingTalkConfig, Logger } from \"../types\";\n\nconst MAX_QUESTION_LENGTH = 80;\nconst LEADING_MENTIONS_RE = /^(?:@\\S+\\s+)*/u;\n\n/**\n * Strip leading `@mention` tokens from inbound text. Used by both the abort and\n * BTW bypass branches in `inbound-handler.ts` so that command detection works\n * uniformly in DM and group chats.\n */\nexport function stripLeadingMentions(text: string): string {\n return text.replace(LEADING_MENTIONS_RE, \"\");\n}\n\nexport function buildBtwBlockquote(senderName: string, rawQuestion: string): string {\n const stripped = stripLeadingMentions(rawQuestion);\n // Iterate by Unicode code points (not UTF-16 code units) so emoji /\n // surrogate pairs aren't sliced in half at the truncation boundary.\n const codePoints = Array.from(stripped);\n const truncated =\n codePoints.length > MAX_QUESTION_LENGTH\n ? `${codePoints.slice(0, MAX_QUESTION_LENGTH).join(\"\")}\u2026`\n : stripped;\n const senderPrefix = senderName ? `${senderName}: ` : \"\";\n return `> ${senderPrefix}${truncated}\\n\\n`;\n}\n\nexport interface DeliverBtwReplyArgs {\n config: DingTalkConfig;\n sessionWebhook: string | undefined;\n conversationId: string;\n to: string;\n senderName: string;\n rawQuestion: string;\n replyText: string;\n log: Logger | undefined;\n accountId?: string;\n storePath?: string;\n}\n\n/**\n * Deliver a BTW reply through the unified `sendMessage` entry point.\n *\n * BTW is a special inbound trigger, but the *outbound* reply is still a regular\n * markdown/text message and must inherit the standard send-service semantics:\n * persistence into the message context store, delivery metadata tracking, and\n * the single `{ ok, error, ... }` contract. We pass `forceMarkdown: true` so\n * that `sendMessage` skips the card branch even when the channel is configured\n * for card mode \u2014 BTW must never create or touch an AI Card (see CLAUDE.md\n * anti-pattern: \"Do not create multiple active AI Cards for the same\n * `accountId:conversationId`\").\n *\n * When `sessionWebhook` is present `sendMessage` internally dispatches via\n * `sendBySession`; otherwise it falls back to the proactive text/markdown API.\n * Either way the caller sees the same return shape, and failures propagate as\n * `{ ok: false }` instead of being silently swallowed.\n */\nexport async function deliverBtwReply(\n args: DeliverBtwReplyArgs,\n): Promise<{ ok: boolean; error?: string }> {\n const blockquote = buildBtwBlockquote(args.senderName, args.rawQuestion);\n const fullText = `${blockquote}${args.replyText}`;\n\n try {\n const result = await sendMessage(args.config, args.to, fullText, {\n log: args.log,\n accountId: args.accountId,\n storePath: args.storePath,\n conversationId: args.conversationId,\n sessionWebhook: args.sessionWebhook,\n forceMarkdown: true,\n });\n if (!result.ok) {\n args.log?.warn?.(\n `[DingTalk] BTW reply delivery returned not-ok: ${result.error ?? \"unknown\"}`,\n );\n }\n return { ok: result.ok, error: result.error };\n } catch (err) {\n const error = err instanceof Error ? err.message : String(err);\n args.log?.warn?.(`[DingTalk] BTW reply delivery threw: ${error}`);\n return { ok: false, error };\n }\n}\n", "import {\n resolveByQuotedRef,\n type MessageRecord,\n} from \"../message-context-store\";\nimport type { DingTalkInboundMessage, Logger, MessageContent, QuotedRef } from \"../types\";\n\nfunction firstTrimmedString(...candidates: Array<string | undefined>): string | undefined {\n for (const candidate of candidates) {\n if (typeof candidate === \"string\" && candidate.trim()) {\n return candidate.trim();\n }\n }\n return undefined;\n}\n\nfunction firstFiniteNumber(...candidates: Array<number | undefined>): number | undefined {\n for (const candidate of candidates) {\n if (typeof candidate === \"number\" && Number.isFinite(candidate)) {\n return candidate;\n }\n }\n return undefined;\n}\n\nexport function buildInboundQuotedRef(\n data: DingTalkInboundMessage,\n content: MessageContent,\n): QuotedRef | undefined {\n const repliedMsg = data.text?.repliedMsg;\n const repliedMsgId = firstTrimmedString(repliedMsg?.msgId, data.originalMsgId, content.quoted?.msgId);\n const fallbackCreatedAt = firstFiniteNumber(\n repliedMsg?.createdAt,\n content.quoted?.cardCreatedAt,\n content.quoted?.fileCreatedAt,\n );\n const isOutboundQuoted =\n firstTrimmedString(data.originalProcessQueryKey) !== undefined ||\n repliedMsg?.senderId === data.chatbotUserId ||\n content.quoted?.isQuotedCard === true;\n if (isOutboundQuoted) {\n const processQueryKey = firstTrimmedString(data.originalProcessQueryKey, content.quoted?.processQueryKey);\n if (processQueryKey) {\n return {\n targetDirection: \"outbound\",\n key: \"processQueryKey\",\n value: processQueryKey,\n fallbackCreatedAt,\n };\n }\n if (!fallbackCreatedAt) {\n return undefined;\n }\n return {\n targetDirection: \"outbound\",\n fallbackCreatedAt,\n };\n }\n if (!repliedMsgId) {\n return undefined;\n }\n return {\n targetDirection: \"inbound\",\n key: \"msgId\",\n value: repliedMsgId,\n };\n}\n\nexport function createReplyQuotedRef(msgId: string | undefined): QuotedRef | undefined {\n const value = firstTrimmedString(msgId);\n if (!value) {\n return undefined;\n }\n return {\n targetDirection: \"inbound\",\n key: \"msgId\",\n value,\n };\n}\n\nexport function resolveQuotedRecord(params: {\n storePath?: string;\n accountId: string;\n conversationId: string | null;\n quotedRef?: QuotedRef;\n log?: Logger;\n}): MessageRecord | null {\n if (!params.quotedRef) {\n return null;\n }\n return resolveByQuotedRef({\n storePath: params.storePath,\n accountId: params.accountId,\n conversationId: params.conversationId,\n quotedRef: params.quotedRef,\n log: params.log,\n });\n}\n", "import type { MessageRecord } from \"../message-context-store\";\nimport type { Logger, QuotedRef } from \"../types\";\nimport { resolveQuotedRecord } from \"./quoted-ref\";\n\nconst DEFAULT_MAX_DEPTH = 3;\nconst DEFAULT_PER_HOP_BODY_LIMIT = 1200;\nconst DEFAULT_TOTAL_BODY_LIMIT = 3600;\n\nexport interface QuotedChainEntry {\n depth: number;\n direction: MessageRecord[\"direction\"];\n messageType: string;\n sender?: string;\n body: string;\n createdAt: number;\n}\n\nexport interface ResolvedQuotedRuntimeContext {\n replyToId?: string;\n replyToBody: string;\n replyToSender?: string;\n replyToIsQuote: true;\n chain: QuotedChainEntry[];\n untrustedContext?: string;\n}\n\nexport interface QuotedRuntimePreview {\n text?: string;\n messageType?: string;\n senderId?: string;\n}\n\nfunction normalizePositiveInteger(value: number | undefined, fallback: number): number {\n return typeof value === \"number\" && Number.isFinite(value) && value > 0\n ? Math.floor(value)\n : fallback;\n}\n\nfunction trimmedString(value: string | undefined): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction deriveReplyToId(record: MessageRecord): string | undefined {\n if (record.direction === \"inbound\") {\n return trimmedString(record.msgId);\n }\n return (\n trimmedString(record.delivery?.processQueryKey) ||\n trimmedString(record.delivery?.messageId) ||\n trimmedString(record.delivery?.outTrackId) ||\n trimmedString(record.delivery?.cardInstanceId) ||\n trimmedString(record.msgId)\n );\n}\n\nfunction deriveSender(record: MessageRecord): string | undefined {\n return record.direction === \"outbound\" ? \"assistant\" : undefined;\n}\n\nfunction deriveMessageType(record: MessageRecord): string {\n return trimmedString(record.messageType) || \"unknown\";\n}\n\nfunction buildBodyPlaceholder(record: MessageRecord): string {\n const messageType = trimmedString(record.messageType) || \"message\";\n return `[Quoted ${messageType}]`;\n}\n\nfunction buildPreviewPlaceholder(preview: QuotedRuntimePreview | undefined): string {\n const messageType = trimmedString(preview?.messageType) || \"message\";\n return `[Quoted ${messageType}]`;\n}\n\nfunction resolveRecordBody(record: MessageRecord): string {\n return (\n trimmedString(record.attachmentText) ||\n trimmedString(record.text) ||\n buildBodyPlaceholder(record)\n );\n}\n\nfunction resolvePreviewBody(preview: QuotedRuntimePreview | undefined): string | undefined {\n return trimmedString(preview?.text) || (preview ? buildPreviewPlaceholder(preview) : undefined);\n}\n\nfunction deriveReplyToIdFromQuotedRef(quotedRef: QuotedRef | undefined): string | undefined {\n if (!quotedRef?.key || !quotedRef.value) {\n return undefined;\n }\n return trimmedString(quotedRef.value);\n}\n\nfunction derivePreviewSender(quotedRef?: QuotedRef): string | undefined {\n if (quotedRef?.targetDirection === \"outbound\") {\n return \"assistant\";\n }\n return undefined;\n}\n\nfunction truncateBody(value: string, limit: number): string {\n if (limit <= 0) {\n return \"\";\n }\n return value.length <= limit ? value : value.slice(0, limit);\n}\n\nfunction fingerprintQuotedRef(quotedRef: QuotedRef | undefined): string | undefined {\n if (!quotedRef) {\n return undefined;\n }\n const direction = quotedRef.targetDirection;\n const key = quotedRef.key || \"\";\n const value = quotedRef.value || \"\";\n const fallbackCreatedAt =\n typeof quotedRef.fallbackCreatedAt === \"number\" && Number.isFinite(quotedRef.fallbackCreatedAt)\n ? String(quotedRef.fallbackCreatedAt)\n : \"\";\n if (!direction) {\n return undefined;\n }\n return JSON.stringify([direction, key, value, fallbackCreatedAt]);\n}\n\nfunction buildChainEntry(params: {\n record: MessageRecord;\n depth: number;\n remainingBodyBudget: number;\n perHopBodyLimit: number;\n}): QuotedChainEntry | null {\n const limit = Math.min(params.perHopBodyLimit, params.remainingBodyBudget);\n if (limit <= 0) {\n return null;\n }\n const body = truncateBody(resolveRecordBody(params.record), limit);\n return {\n depth: params.depth,\n direction: params.record.direction,\n messageType: deriveMessageType(params.record),\n sender: deriveSender(params.record),\n body,\n createdAt: params.record.createdAt,\n };\n}\n\nexport function resolveQuotedRuntimeContext(params: {\n storePath?: string;\n accountId: string;\n conversationId: string | null;\n quotedRef?: QuotedRef;\n firstRecord?: MessageRecord | null;\n firstPreview?: QuotedRuntimePreview;\n log?: Logger;\n maxDepth?: number;\n perHopBodyLimit?: number;\n totalBodyLimit?: number;\n}): ResolvedQuotedRuntimeContext | null {\n if (!params.quotedRef) {\n return null;\n }\n\n const maxDepth = normalizePositiveInteger(params.maxDepth, DEFAULT_MAX_DEPTH);\n const perHopBodyLimit = normalizePositiveInteger(\n params.perHopBodyLimit,\n DEFAULT_PER_HOP_BODY_LIMIT,\n );\n const totalBodyLimit = normalizePositiveInteger(params.totalBodyLimit, DEFAULT_TOTAL_BODY_LIMIT);\n\n const chain: QuotedChainEntry[] = [];\n const seenRecordIds = new Set<string>();\n const seenQuotedRefFingerprints = new Set<string>();\n let firstResolvedRecord: MessageRecord | null = null;\n let remainingBodyBudget = totalBodyLimit;\n let currentQuotedRef: QuotedRef | undefined = params.quotedRef;\n let currentRecord = params.firstRecord ?? null;\n\n for (let depth = 1; depth <= maxDepth && currentQuotedRef; depth += 1) {\n if (depth > 1 || !currentRecord) {\n currentRecord = resolveQuotedRecord({\n storePath: params.storePath,\n accountId: params.accountId,\n conversationId: params.conversationId,\n quotedRef: currentQuotedRef,\n log: params.log,\n });\n }\n if (!currentRecord) {\n break;\n }\n if (!firstResolvedRecord) {\n firstResolvedRecord = currentRecord;\n }\n\n const recordId = `${currentRecord.direction}:${currentRecord.msgId}`;\n if (seenRecordIds.has(recordId)) {\n break;\n }\n seenRecordIds.add(recordId);\n\n const currentFingerprint = fingerprintQuotedRef(currentQuotedRef);\n if (currentFingerprint) {\n if (seenQuotedRefFingerprints.has(currentFingerprint)) {\n break;\n }\n seenQuotedRefFingerprints.add(currentFingerprint);\n }\n\n const entry = buildChainEntry({\n record: currentRecord,\n depth,\n remainingBodyBudget,\n perHopBodyLimit,\n });\n if (!entry) {\n break;\n }\n chain.push(entry);\n remainingBodyBudget -= entry.body.length;\n\n const nextQuotedRef = currentRecord.quotedRef;\n if (!nextQuotedRef) {\n break;\n }\n\n const nextFingerprint = fingerprintQuotedRef(nextQuotedRef);\n if (nextFingerprint && seenQuotedRefFingerprints.has(nextFingerprint)) {\n break;\n }\n\n currentQuotedRef = nextQuotedRef;\n currentRecord = null;\n }\n\n const replyToRecord = firstResolvedRecord ?? params.firstRecord ?? null;\n const stableReplyToId = replyToRecord ? deriveReplyToId(replyToRecord) : undefined;\n if (replyToRecord && stableReplyToId) {\n return {\n replyToId: stableReplyToId,\n replyToBody: chain[0].body,\n replyToSender: chain[0].sender,\n replyToIsQuote: true,\n chain,\n untrustedContext:\n chain.length > 1\n ? JSON.stringify({\n quotedChain: chain.slice(1),\n })\n : undefined,\n };\n }\n\n const previewBody = resolvePreviewBody(params.firstPreview);\n const previewReplyToId = deriveReplyToIdFromQuotedRef(params.quotedRef);\n if (!previewBody) {\n return null;\n }\n\n return {\n replyToId: previewReplyToId,\n replyToBody: truncateBody(previewBody, perHopBodyLimit),\n replyToSender: derivePreviewSender(params.quotedRef),\n replyToIsQuote: true,\n chain: [],\n untrustedContext: undefined,\n };\n}\n", "import http from \"node:http\";\nimport https from \"node:https\";\nimport axios from \"../http-client\";\nimport { getAccessToken } from \"../auth\";\nimport { getDingTalkRuntime } from \"../runtime\";\nimport type { DingTalkConfig, Logger, MediaFile } from \"../types\";\nimport { formatDingTalkErrorPayload, formatDingTalkErrorPayloadLog } from \"../utils\";\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return undefined;\n }\n return value as Record<string, unknown>;\n}\n\nconst ipv4OnlyHttpAgent = new http.Agent({ family: 4 });\nconst ipv4OnlyHttpsAgent = new https.Agent({ family: 4 });\n\nconst DINGTALK_API = \"https://api.dingtalk.com\";\nconst DINGTALK_OAPI = \"https://oapi.dingtalk.com\";\n\nconst MATCH_WINDOW_MS = 10_000;\nconst MAX_PAGES = 3;\nconst PAGE_SIZE = 50;\n\nconst UNION_ID_CACHE_MAX = 5000;\nconst SPACE_ID_CACHE_MAX = 500;\n\nfunction describeResolveError(err: unknown): string {\n if (axios.isAxiosError(err)) {\n const status = err.response?.status;\n const statusText = err.response?.statusText;\n const statusLabel = status ? `status=${status}${statusText ? ` ${statusText}` : \"\"}` : \"status=unknown\";\n const code = typeof err.code === \"string\" && err.code ? ` code=${err.code}` : \"\";\n const hasRequest = err.request ? \" request=yes\" : \" request=no\";\n const hasResponse = err.response ? \" response=yes\" : \" response=no\";\n if (err.response?.data !== undefined) {\n return `${statusLabel}${code}${hasRequest}${hasResponse} ${formatDingTalkErrorPayload(err.response.data)}`;\n }\n return `${statusLabel}${code}${hasRequest}${hasResponse} message=${err.message || \"unknown axios error\"}`;\n }\n if (err instanceof Error) {\n return `${err.name || \"Error\"} message=${err.message || \"unknown error\"}`;\n }\n try {\n return JSON.stringify(err);\n } catch {\n return String(err);\n }\n}\n\n// ============ LRU caches ============\n\nconst unionIdCache = new Map<string, string>();\nconst spaceIdCache = new Map<string, string>();\n\nfunction lruSet<V>(map: Map<string, V>, key: string, value: V, maxSize: number): void {\n if (map.has(key)) {\n map.delete(key);\n }\n map.set(key, value);\n if (map.size > maxSize) {\n const oldest = map.keys().next().value;\n if (oldest !== undefined) {\n map.delete(oldest);\n }\n }\n}\n\nfunction lruGet<V>(map: Map<string, V>, key: string): V | undefined {\n const value = map.get(key);\n if (value === undefined) {\n return undefined;\n }\n map.delete(key);\n map.set(key, value);\n return value;\n}\n\n// ============ Time parsing ============\n\nexport function parseDingTalkFileTime(timeStr: string): number {\n const normalized = timeStr.replace(/\\bCST\\b/, \"+0800\");\n const ms = new Date(normalized).getTime();\n if (Number.isNaN(ms)) {\n throw new Error(`Cannot parse DingTalk file time: ${timeStr}`);\n }\n return ms;\n}\n\n// ============ API helpers ============\n\nexport async function getUnionIdByStaffId(\n config: DingTalkConfig,\n staffId: string,\n log?: Logger,\n): Promise<string> {\n const cacheKey = `${config.clientId}:${staffId}`;\n const cached = lruGet(unionIdCache, cacheKey);\n if (cached) {\n return cached;\n }\n\n const token = await getAccessToken(config, log);\n const resp = await axios.post(\n `${DINGTALK_OAPI}/topapi/v2/user/get?access_token=${token}`,\n { userid: staffId },\n );\n\n const payload = asRecord(resp.data) ?? {};\n const errcode = typeof payload.errcode === \"number\" || typeof payload.errcode === \"string\"\n ? String(payload.errcode)\n : \"unknown\";\n const errmsg = typeof payload.errmsg === \"string\" ? payload.errmsg : \"unknown\";\n if (payload.errcode !== 0) {\n throw new Error(`topapi/v2/user/get failed: errcode=${errcode} errmsg=${errmsg}`);\n }\n\n const unionIdValue = asRecord(payload.result)?.unionid;\n const unionId = typeof unionIdValue === \"string\" ? unionIdValue : undefined;\n if (!unionId) {\n throw new Error(`topapi/v2/user/get returned no unionid for staffId=${staffId}`);\n }\n\n lruSet(unionIdCache, cacheKey, unionId, UNION_ID_CACHE_MAX);\n return unionId;\n}\n\nexport async function getGroupFileSpaceId(\n config: DingTalkConfig,\n openConversationId: string,\n unionId: string,\n log?: Logger,\n): Promise<string> {\n const cacheKey = `${config.clientId}:${openConversationId}`;\n const cached = lruGet(spaceIdCache, cacheKey);\n if (cached) {\n return cached;\n }\n\n const token = await getAccessToken(config, log);\n const resp = await axios.post(\n `${DINGTALK_API}/v1.0/convFile/conversations/spaces/query`,\n { openConversationId, unionId },\n { headers: { \"x-acs-dingtalk-access-token\": token } },\n );\n\n const spaceIdValue = asRecord(asRecord(resp.data)?.space)?.spaceId;\n const spaceId = typeof spaceIdValue === \"string\" ? spaceIdValue : undefined;\n if (!spaceId) {\n throw new Error(`convFile spaces/query returned no spaceId for conversationId=${openConversationId}`);\n }\n\n lruSet(spaceIdCache, cacheKey, spaceId, SPACE_ID_CACHE_MAX);\n return spaceId;\n}\n\ninterface DentryMatch {\n dentryId: string;\n name: string;\n}\n\nexport interface ResolvedQuotedFile {\n media: MediaFile;\n spaceId: string;\n fileId: string;\n name?: string;\n}\n\nexport async function findFileByTimestamp(\n config: DingTalkConfig,\n spaceId: string,\n unionId: string,\n createdAt: number,\n log?: Logger,\n): Promise<DentryMatch | null> {\n const token = await getAccessToken(config, log);\n\n let bestMatch: DentryMatch | null = null;\n let bestDelta = Infinity;\n let nextToken: string | undefined;\n\n for (let page = 0; page < MAX_PAGES; page++) {\n const body: Record<string, unknown> = {\n option: { maxResults: PAGE_SIZE },\n };\n if (nextToken) {\n (body.option as { nextToken?: string }).nextToken = nextToken;\n }\n\n const resp = await axios.post(\n `${DINGTALK_API}/v1.0/storage/spaces/${spaceId}/dentries/listAll?unionId=${unionId}`,\n body,\n { headers: { \"x-acs-dingtalk-access-token\": token } },\n );\n\n const data = asRecord(resp.data) ?? {};\n const dentries = Array.isArray(data.dentries) ? data.dentries as Array<Record<string, unknown>> : [];\n\n for (const entry of dentries) {\n if (entry.type !== \"FILE\" || !entry.createTime) {\n continue;\n }\n try {\n const fileTime = parseDingTalkFileTime(entry.createTime as string);\n const delta = Math.abs(fileTime - createdAt);\n if (delta <= MATCH_WINDOW_MS && delta < bestDelta) {\n bestDelta = delta;\n bestMatch = { dentryId: entry.id as string, name: entry.name as string };\n }\n } catch {\n const createTime = typeof entry.createTime === \"string\" ? entry.createTime : JSON.stringify(entry.createTime);\n log?.debug?.(`[DingTalk][QuotedFile] Failed to parse createTime: ${createTime}`);\n }\n }\n\n nextToken = typeof data.nextToken === \"string\" ? data.nextToken : undefined;\n if (!nextToken) {\n break;\n }\n }\n\n return bestMatch;\n}\n\nexport async function downloadGroupFile(\n config: DingTalkConfig,\n spaceId: string,\n dentryId: string,\n unionId: string,\n log?: Logger,\n originalFilename?: string,\n): Promise<MediaFile | null> {\n const rt = getDingTalkRuntime();\n const token = await getAccessToken(config, log);\n let resourceUrl = \"\";\n let contentType = \"application/octet-stream\";\n\n try {\n const infoResp = await axios.post(\n `${DINGTALK_API}/v1.0/storage/spaces/${spaceId}/dentries/${dentryId}/downloadInfos/query?unionId=${unionId}`,\n {},\n { headers: { \"x-acs-dingtalk-access-token\": token } },\n );\n\n const info = asRecord(infoResp.data) ?? {};\n const headerSig = asRecord(info.headerSignatureInfo);\n const resourceUrls = headerSig && Array.isArray(headerSig.resourceUrls) ? headerSig.resourceUrls : undefined;\n resourceUrl = typeof resourceUrls?.[0] === \"string\" ? resourceUrls[0] : \"\";\n if (!resourceUrl) {\n log?.warn?.(\"[DingTalk][QuotedFile] downloadInfos/query returned no resourceUrl\");\n return null;\n }\n\n const sigHeaders: Record<string, string> = {};\n const headerMap = asRecord(headerSig?.headers);\n if (headerMap) {\n for (const [k, v] of Object.entries(headerMap)) {\n if (typeof v === \"string\") {\n sigHeaders[k] = v;\n }\n }\n }\n let fileResp;\n try {\n fileResp = await axios.get(resourceUrl, {\n headers: sigHeaders,\n responseType: \"arraybuffer\",\n timeout: 15000,\n });\n } catch (firstErr: unknown) {\n log?.warn?.(\n `[DingTalk][QuotedFile] CDN download failed on default network path, retrying with IPv4-only: ${describeResolveError(firstErr)}`,\n );\n try {\n fileResp = await axios.get(resourceUrl, {\n headers: sigHeaders,\n responseType: \"arraybuffer\",\n httpAgent: ipv4OnlyHttpAgent,\n httpsAgent: ipv4OnlyHttpsAgent,\n timeout: 15000,\n });\n } catch (retryErr: unknown) {\n const host = resourceUrl ? new URL(resourceUrl).host : \"(unknown-host)\";\n throw new Error(\n `download-resource failed host=${host} detail=${describeResolveError(retryErr)}`,\n { cause: retryErr },\n );\n }\n }\n\n contentType = (fileResp.headers[\"content-type\"] as string) || \"application/octet-stream\";\n const buffer = Buffer.from(fileResp.data as ArrayBuffer);\n\n const maxBytes =\n config.mediaMaxMb && config.mediaMaxMb > 0 ? config.mediaMaxMb * 1024 * 1024 : undefined;\n try {\n const saved = await rt.channel.media.saveMediaBuffer(\n buffer,\n contentType,\n \"inbound\",\n maxBytes,\n originalFilename,\n );\n\n return { path: saved.path, mimeType: saved.contentType ?? contentType };\n } catch (err: unknown) {\n throw new Error(\n `save-buffer failed contentType=${contentType} detail=${describeResolveError(err)}`,\n { cause: err },\n );\n }\n } catch (err: unknown) {\n if (axios.isAxiosError(err) && err.response?.data !== undefined) {\n log?.warn?.(formatDingTalkErrorPayloadLog(\"quotedFile.downloadGroupFile\", err.response.data));\n }\n log?.warn?.(\n `[DingTalk][QuotedFile] downloadGroupFile failed: spaceId=${spaceId} dentryId=${dentryId} resourceUrl=${resourceUrl || \"(none)\"} contentType=${contentType} error=${describeResolveError(err)}`,\n );\n return null;\n }\n}\n\n// ============ Composite entry point ============\n\nexport interface ResolveQuotedFileParams {\n openConversationId: string;\n senderStaffId?: string;\n fileCreatedAt?: number;\n}\n\nexport async function resolveQuotedFile(\n config: DingTalkConfig,\n params: ResolveQuotedFileParams,\n log?: Logger,\n): Promise<ResolvedQuotedFile | null> {\n const { openConversationId, senderStaffId, fileCreatedAt } = params;\n let stage = \"init\";\n\n if (!senderStaffId || !fileCreatedAt) {\n log?.warn?.(\"[DingTalk][QuotedFile] Missing senderStaffId or fileCreatedAt, skipping\");\n return null;\n }\n\n try {\n stage = \"resolve-unionId\";\n const unionId = await getUnionIdByStaffId(config, senderStaffId, log);\n stage = \"resolve-spaceId\";\n const spaceId = await getGroupFileSpaceId(config, openConversationId, unionId, log);\n stage = \"list-and-match\";\n const match = await findFileByTimestamp(config, spaceId, unionId, fileCreatedAt, log);\n\n if (!match) {\n log?.warn?.(\n `[DingTalk][QuotedFile] No file matched within \u00B1${MATCH_WINDOW_MS}ms window for createdAt=${fileCreatedAt}`,\n );\n return null;\n }\n\n stage = \"download-file\";\n const media = await downloadGroupFile(config, spaceId, match.dentryId, unionId, log, match.name);\n if (!media) {\n return null;\n }\n\n return {\n media,\n spaceId,\n fileId: match.dentryId,\n name: match.name,\n };\n } catch (err: unknown) {\n if (log?.warn) {\n if (axios.isAxiosError(err) && err.response?.data !== undefined) {\n log.warn(formatDingTalkErrorPayloadLog(\"quotedFile.resolve\", err.response.data));\n }\n log.warn(\n `[DingTalk][QuotedFile] Failed to resolve quoted file: stage=${stage} conversationId=${openConversationId} senderStaffId=${senderStaffId} fileCreatedAt=${fileCreatedAt} error=${describeResolveError(err)}`,\n );\n }\n return null;\n }\n}\n\n// ============ Test helpers ============\n\nexport function clearQuotedFileServiceCachesForTest(): void {\n unionIdCache.clear();\n spaceIdCache.clear();\n}\n", "export interface CardReasoningAnswerSplit {\n reasoningText?: string;\n answerText?: string;\n}\n\nconst THINKING_TAG_RE = /<\\s*(\\/?)\\s*(?:think(?:ing)?|thought|antthinking)\\b[^<>]*>/gi;\n\nfunction isWrappedReasoningLine(line: string): boolean {\n const trimmed = line.trim();\n return trimmed.startsWith(\"_\") && trimmed.endsWith(\"_\") && trimmed.length >= 3;\n}\n\nfunction cleanReasoningLine(line: string): string {\n const trimmed = line.trim();\n if (!trimmed) {\n return \"\";\n }\n return trimmed.replace(/^_/, \"\").replace(/_$/, \"\").trim();\n}\n\nfunction joinAnswerParts(parts: string[]): string | undefined {\n const joined = parts.map((part) => part.trim()).filter(Boolean).join(\"\\n\\n\").trim();\n return joined || undefined;\n}\n\nfunction hasStructuredMarkdown(text: string): boolean {\n const trimmed = text.trim();\n if (!trimmed) {\n return false;\n }\n return (\n trimmed.includes(\"**\")\n || trimmed.includes(\"```\")\n || /(^|\\n)\\s*(?:[-*+]\\s|#{1,6}\\s|>\\s|\\d+\\.\\s)/.test(trimmed)\n );\n}\n\nfunction splitTopLevelReasoningPrefix(text: string): CardReasoningAnswerSplit | null {\n const markerIndex = text.indexOf(\"Reasoning:\");\n if (markerIndex < 0) {\n return null;\n }\n\n const before = text.slice(0, markerIndex).trim();\n if (before && hasStructuredMarkdown(before)) {\n return {\n answerText: text,\n };\n }\n\n const trailing = text.slice(markerIndex + \"Reasoning:\".length);\n const lines = trailing.split(\"\\n\");\n const reasoningLines: string[] = [];\n let started = false;\n let remainderIndex = -1;\n\n for (let index = 0; index < lines.length; index += 1) {\n const line = lines[index];\n const trimmed = line.trim();\n\n if (!started) {\n if (!trimmed) {\n continue;\n }\n if (!isWrappedReasoningLine(trimmed)) {\n return {\n answerText: text,\n };\n }\n started = true;\n reasoningLines.push(cleanReasoningLine(trimmed));\n continue;\n }\n\n if (!trimmed) {\n continue;\n }\n\n if (isWrappedReasoningLine(trimmed)) {\n reasoningLines.push(cleanReasoningLine(trimmed));\n continue;\n }\n\n remainderIndex = index;\n break;\n }\n\n if (reasoningLines.length === 0) {\n return {\n answerText: text,\n };\n }\n\n const after = remainderIndex >= 0 ? lines.slice(remainderIndex).join(\"\\n\").trim() : \"\";\n return {\n reasoningText: reasoningLines.join(\"\\n\").trim() || undefined,\n answerText: joinAnswerParts([before, after]),\n };\n}\n\nfunction splitTopLevelThinkingTags(text: string): CardReasoningAnswerSplit | null {\n if (!THINKING_TAG_RE.test(text)) {\n return null;\n }\n THINKING_TAG_RE.lastIndex = 0;\n\n let reasoning = \"\";\n let answer = \"\";\n let lastIndex = 0;\n let inThinking = false;\n\n for (const match of text.matchAll(THINKING_TAG_RE)) {\n const matchIndex = match.index ?? 0;\n const segment = text.slice(lastIndex, matchIndex);\n if (inThinking) {\n reasoning += segment;\n } else {\n answer += segment;\n }\n inThinking = match[1] !== \"/\";\n lastIndex = matchIndex + match[0].length;\n }\n\n const tail = text.slice(lastIndex);\n if (inThinking) {\n reasoning += tail;\n } else {\n answer += tail;\n }\n\n const cleanedReasoning = reasoning.trim();\n if (!cleanedReasoning) {\n return {\n answerText: text,\n };\n }\n\n return {\n reasoningText: cleanedReasoning,\n answerText: answer.trim() || undefined,\n };\n}\n\nexport function splitCardReasoningAnswerText(text?: string): CardReasoningAnswerSplit {\n if (typeof text !== \"string\") {\n return {};\n }\n\n const prefixed = splitTopLevelReasoningPrefix(text);\n if (prefixed) {\n return prefixed;\n }\n\n const tagged = splitTopLevelThinkingTags(text);\n if (tagged) {\n return tagged;\n }\n\n return {\n answerText: text,\n };\n}\n", "export interface ReasoningBlockAssembler {\n ingestSnapshot: (text: string | undefined) => string[];\n flushPendingAtBoundary: () => string[];\n reset: () => void;\n}\n\nfunction stripReasoningPrefix(text: string): string {\n const trimmed = text.trim();\n if (trimmed.startsWith(\"Reasoning:\")) {\n return trimmed.slice(\"Reasoning:\".length).trimStart();\n }\n return trimmed;\n}\n\nfunction cleanReasoningLine(line: string): string {\n return line.trim().replace(/^_/, \"\").replace(/_$/, \"\").trim();\n}\n\nfunction isClosedReasoningLine(line: string): boolean {\n const trimmed = line.trim();\n return trimmed.startsWith(\"_\") && trimmed.endsWith(\"_\") && trimmed.length >= 2;\n}\n\nfunction startsReasonBlock(line: string): boolean {\n return cleanReasoningLine(line).startsWith(\"Reason:\");\n}\n\nfunction blocksStartWithPrefix(blocks: string[], prefix: string[]): boolean {\n if (prefix.length > blocks.length) {\n return false;\n }\n return prefix.every((entry, index) => blocks[index] === entry);\n}\n\nfunction parseReasoningSnapshot(text: string | undefined): {\n completeBlocks: string[];\n pendingBlock: string;\n} {\n const normalized = typeof text === \"string\" ? stripReasoningPrefix(text) : \"\";\n if (!normalized.trim()) {\n return {\n completeBlocks: [],\n pendingBlock: \"\",\n };\n }\n\n const lines = normalized\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line.length > 0);\n\n const completeBlocks: string[] = [];\n let currentLines: string[] = [];\n let currentMode: \"explicit\" | \"implicit\" | null = null;\n let currentComplete = true;\n\n const finalizeCurrent = () => {\n if (currentLines.length === 0) {\n return;\n }\n if (currentMode === \"explicit\" && currentComplete) {\n completeBlocks.push(currentLines.join(\"\\n\"));\n }\n };\n\n for (const line of lines) {\n if (startsReasonBlock(line)) {\n finalizeCurrent();\n currentLines = [cleanReasoningLine(line)];\n currentMode = \"explicit\";\n currentComplete = isClosedReasoningLine(line);\n continue;\n }\n\n if (currentLines.length === 0) {\n const trimmedLine = line.trim();\n const cleanedLine = cleanReasoningLine(line);\n if (!cleanedLine) {\n continue;\n }\n if (!trimmedLine.startsWith(\"_\")) {\n continue;\n }\n currentLines = [cleanedLine];\n currentMode = \"implicit\";\n currentComplete = false;\n continue;\n }\n\n currentLines.push(cleanReasoningLine(line));\n currentComplete = currentMode === \"explicit\"\n ? currentComplete && isClosedReasoningLine(line)\n : false;\n }\n\n if (currentLines.length === 0) {\n return {\n completeBlocks,\n pendingBlock: \"\",\n };\n }\n\n if (currentMode === \"explicit\" && currentComplete) {\n completeBlocks.push(currentLines.join(\"\\n\"));\n return {\n completeBlocks,\n pendingBlock: \"\",\n };\n }\n\n return {\n completeBlocks,\n pendingBlock: currentLines.join(\"\\n\").trim(),\n };\n}\n\nexport function createReasoningBlockAssembler(): ReasoningBlockAssembler {\n let emittedBlocks: string[] = [];\n let pendingBlock = \"\";\n\n return {\n ingestSnapshot(text: string | undefined): string[] {\n const parsed = parseReasoningSnapshot(text);\n pendingBlock = parsed.pendingBlock;\n\n if (parsed.completeBlocks.length === 0) {\n return [];\n }\n\n if (blocksStartWithPrefix(parsed.completeBlocks, emittedBlocks)) {\n const nextBlocks = parsed.completeBlocks.slice(emittedBlocks.length);\n emittedBlocks = [...parsed.completeBlocks];\n return nextBlocks;\n }\n\n if (blocksStartWithPrefix(emittedBlocks, parsed.completeBlocks)) {\n return [];\n }\n\n return [];\n },\n\n flushPendingAtBoundary(): string[] {\n if (!pendingBlock.trim()) {\n return [];\n }\n const flushed = pendingBlock;\n pendingBlock = \"\";\n return [flushed];\n },\n\n reset(): void {\n emittedBlocks = [];\n pendingBlock = \"\";\n },\n };\n}\n", "import type { DingTalkConfig } from \"../types\";\n\nexport type CardStreamingMode = \"off\" | \"answer\" | \"all\";\n\n// Process-lifetime one-shot warnings are intentional here: a given config key\n// should only emit the deprecation notice once per runtime.\nconst warnedLegacyConfigs = new Set<string>();\n\nexport function resolveCardStreamingMode(\n config: Pick<DingTalkConfig, \"cardStreamingMode\" | \"cardRealTimeStream\">,\n): {\n mode: CardStreamingMode;\n usedDeprecatedCardRealTimeStream: boolean;\n} {\n if (config.cardStreamingMode) {\n return { mode: config.cardStreamingMode, usedDeprecatedCardRealTimeStream: false };\n }\n if (config.cardRealTimeStream === true) {\n return { mode: \"all\", usedDeprecatedCardRealTimeStream: true };\n }\n return { mode: \"off\", usedDeprecatedCardRealTimeStream: false };\n}\n\nexport function shouldWarnDeprecatedCardRealTimeStreamOnce(configKey: string): boolean {\n if (warnedLegacyConfigs.has(configKey)) {\n return false;\n }\n warnedLegacyConfigs.add(configKey);\n return true;\n}\n", "export type MarkdownImageUrlClassification = \"public\" | \"local\" | \"unsupported\";\n\nexport interface MarkdownImageCandidate {\n alt: string;\n url: string;\n raw: string;\n classification: MarkdownImageUrlClassification;\n start: number;\n end: number;\n}\n\nconst MARKDOWN_IMAGE_RE = /!\\[([^\\]]*)\\]\\(([^)]+)\\)/g;\nconst PRIVATE_HOST_RE = /^(?:localhost|127\\.0\\.0\\.1|10\\.\\d+\\.\\d+\\.\\d+|192\\.168\\.\\d+\\.\\d+|172\\.(?:1[6-9]|2\\d|3[0-1])\\.\\d+\\.\\d+)$/;\n\nfunction isLikelyPlainRelativePath(url: string): boolean {\n return !/^[a-zA-Z][a-zA-Z\\d+.-]*:/.test(url) && !url.startsWith(\"//\");\n}\n\nfunction isLikelyLocalPath(url: string): boolean {\n return url.startsWith(\"./\") || url.startsWith(\"../\") || url.startsWith(\"/\") || isLikelyPlainRelativePath(url);\n}\n\nfunction safeFileNameFromUrl(url: string): string {\n const trimmed = url.trim();\n if (!trimmed) {\n return \"\";\n }\n\n if (trimmed.startsWith(\"file://\")) {\n const withoutScheme = trimmed.slice(\"file://\".length);\n const segments = withoutScheme.split(\"/\").filter(Boolean);\n return segments.at(-1) ?? \"\";\n }\n\n if (isLikelyLocalPath(trimmed)) {\n const segments = trimmed.split(/[\\\\/]/).filter(Boolean);\n return segments.at(-1) ?? \"\";\n }\n\n try {\n const parsed = new URL(trimmed);\n const segments = parsed.pathname.split(\"/\").filter(Boolean);\n return segments.at(-1) ?? \"\";\n } catch {\n return \"\";\n }\n}\n\nexport function classifyMarkdownImageUrl(url: string): MarkdownImageUrlClassification {\n const trimmed = url.trim();\n if (!trimmed) {\n return \"unsupported\";\n }\n\n if (trimmed.startsWith(\"file://\") || isLikelyLocalPath(trimmed)) {\n return \"local\";\n }\n\n try {\n const parsed = new URL(trimmed);\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n return \"unsupported\";\n }\n if (PRIVATE_HOST_RE.test(parsed.hostname)) {\n return \"local\";\n }\n return \"public\";\n } catch {\n return \"unsupported\";\n }\n}\n\nexport function buildImagePlaceholderText(input: { alt: string; url: string }): string {\n const alt = input.alt.trim();\n if (alt) {\n return `\u89C1\u4E0B\u56FE${alt}`;\n }\n\n const fileName = safeFileNameFromUrl(input.url);\n if (fileName) {\n return `\u89C1\u4E0B\u56FE${fileName}`;\n }\n\n return \"\u89C1\u4E0B\u56FE\u56FE\u7247\";\n}\n\nexport function extractMarkdownImageCandidates(text: string): MarkdownImageCandidate[] {\n const candidates: MarkdownImageCandidate[] = [];\n\n for (const match of text.matchAll(MARKDOWN_IMAGE_RE)) {\n const raw = match[0] ?? \"\";\n const alt = match[1] ?? \"\";\n const url = match[2] ?? \"\";\n const start = match.index ?? 0;\n candidates.push({\n alt,\n url,\n raw,\n classification: classifyMarkdownImageUrl(url),\n start,\n end: start + raw.length,\n });\n }\n\n return candidates;\n}\n", "/**\n * Throttled stream loop for fire-and-forget draft updates.\n *\n * Ported from OpenClaw core (channels/draft-stream-loop.ts) because the module\n * is not exported via the plugin-sdk. Keeps the same interface so that future\n * sync with upstream is straightforward.\n *\n * Key safety properties:\n * - Single-flight: at most one `sendOrEditStreamMessage` is in-flight at any time.\n * - Latest-wins: multiple `update()` calls during in-flight only keep the last text.\n * - Throttle: respects `throttleMs` between consecutive sends.\n * - `flush()` drains all pending + waits for in-flight before returning.\n * - `stop()` clears pending and timers; subsequent `update()` calls are ignored.\n */\n\nexport type DraftStreamLoop = {\n update: (text: string) => void;\n flush: () => Promise<void>;\n stop: () => void;\n resetPending: () => void;\n resetThrottleWindow: () => void;\n waitForInFlight: () => Promise<void>;\n};\n\nexport function createDraftStreamLoop(params: {\n throttleMs: number;\n isStopped: () => boolean;\n sendOrEditStreamMessage: (text: string) => Promise<void | boolean>;\n}): DraftStreamLoop {\n let lastSentAt = 0;\n let pendingText = \"\";\n let inFlightPromise: Promise<void | boolean> | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n const flush = async () => {\n if (timer) {\n clearTimeout(timer);\n timer = undefined;\n }\n while (!params.isStopped()) {\n if (inFlightPromise) {\n await inFlightPromise;\n continue;\n }\n const text = pendingText;\n if (!text.trim()) {\n pendingText = \"\";\n return;\n }\n pendingText = \"\";\n const current = params.sendOrEditStreamMessage(text).finally(() => {\n if (inFlightPromise === current) {\n inFlightPromise = undefined;\n }\n });\n inFlightPromise = current;\n const sent = await current;\n if (sent === false) {\n pendingText = text;\n return;\n }\n lastSentAt = Date.now();\n if (!pendingText) {\n return;\n }\n }\n };\n\n const schedule = () => {\n if (timer) {\n return;\n }\n const delay = Math.max(0, params.throttleMs - (Date.now() - lastSentAt));\n timer = setTimeout(() => {\n void flush();\n }, delay);\n };\n\n return {\n update: (text: string) => {\n if (params.isStopped()) {\n return;\n }\n pendingText = text;\n if (inFlightPromise) {\n schedule();\n return;\n }\n if (!timer && Date.now() - lastSentAt >= params.throttleMs) {\n void flush();\n return;\n }\n schedule();\n },\n flush,\n stop: () => {\n pendingText = \"\";\n if (timer) {\n clearTimeout(timer);\n timer = undefined;\n }\n },\n resetPending: () => {\n pendingText = \"\";\n },\n resetThrottleWindow: () => {\n lastSentAt = 0;\n if (timer) {\n clearTimeout(timer);\n timer = undefined;\n }\n },\n waitForInFlight: async () => {\n if (inFlightPromise) {\n await inFlightPromise;\n }\n },\n };\n}\n", "/**\n * Card draft controller for throttled AI Card streaming updates.\n *\n * The controller keeps a single rendered card timeline made of:\n * - sealed process blocks (`thinking` / `tool`)\n * - an optional live thinking block\n * - accumulated answer turns rendered as JSON CardBlock[]\n *\n * It delegates throttling and single-flight transport guarantees to\n * {@link createDraftStreamLoop}.\n */\n\nimport {\n clearAICardStreamingContent,\n streamAICardContent,\n updateAICardBlockList,\n} from \"./card-service\";\nimport { createDraftStreamLoop } from \"./draft-stream-loop\";\nimport type { AICardInstance, CardBlock, Logger } from \"./types\";\n\ntype TimelineEntryKind = \"thinking\" | \"tool\" | \"answer\" | \"image\";\n\ntype TimelineEntry = {\n kind: TimelineEntryKind;\n text: string;\n mediaId?: string;\n};\n\n// DingTalk markdown variable token definitions:\n// https://open.dingtalk.com/document/development/markdown-variable-new\nconst PROCESS_BLOCK_FONT_SIZE_TOKEN = \"common_footnote_text_style__font_size\";\n// DingTalk markdown variable token definitions:\n// https://open.dingtalk.com/document/development/markdown-variable-new\nconst PROCESS_BLOCK_FONT_COLOR_TOKEN_V2 = \"common_level2_base_color\";\n\nexport interface CardDraftController {\n updateAnswer: (text: string, options?: { stream?: boolean; renderBlocks?: boolean }) => Promise<void>;\n updateReasoning: (text: string) => Promise<void>;\n updateThinking: (text: string) => Promise<void>;\n appendThinkingBlock: (text: string) => Promise<void>;\n updateTool: (text: string) => Promise<void>;\n appendTool: (text: string) => Promise<void>;\n /** Append an image block (type=3) with an uploaded mediaId. */\n appendImageBlock: (mediaId: string, text?: string) => Promise<void>;\n appendToolBeforeCurrentAnswer: (text: string) => Promise<void>;\n /** Drop the current answer draft while keeping sealed earlier turns intact. */\n discardCurrentAnswer: () => void;\n /** Signal that a new assistant turn has started (e.g. after a tool call). */\n notifyNewAssistantTurn: (options?: {\n discardActiveAnswer?: boolean;\n }) => Promise<void>;\n startAssistantTurn: () => Promise<void>;\n /** Seal the active thinking entry (keep it in timeline) without removing it. */\n sealActiveThinking: () => Promise<void>;\n flush: () => Promise<void>;\n waitForInFlight: () => Promise<void>;\n stop: () => void;\n isFailed: () => boolean;\n /** Last content successfully sent to card. */\n getLastContent: () => string;\n /** Last answer-only content successfully sent to card. */\n getLastAnswerContent: () => string;\n /** Current answer-only content composed from all completed answer turns. */\n getFinalAnswerContent: () => string;\n /** Current rendered timeline as CardBlock[] JSON string for blockList parameter. */\n getRenderedBlocks: (options?: {\n fallbackAnswer?: string;\n overrideAnswer?: string;\n compactProcessAnswerSpacing?: boolean;\n }) => string;\n /** Current rendered timeline as pure markdown text for content parameter and fallback. */\n getRenderedContent: (options?: {\n fallbackAnswer?: string;\n overrideAnswer?: string;\n compactProcessAnswerSpacing?: boolean;\n }) => string;\n /** Stream answer text to content key for real-time display. Only available when realTimeStreamEnabled=true. */\n streamContent?: (text: string) => Promise<void>;\n /** Clear the streaming content key. Only available when realTimeStreamEnabled=true. */\n clearStreamingContent?: () => Promise<void>;\n /** Whether real-time streaming is enabled. */\n isRealTimeStreamEnabled: () => boolean;\n}\n\nfunction normalizeProcessText(text: string | undefined): string {\n return typeof text === \"string\" ? text.trim() : \"\";\n}\n\nfunction normalizeAnswerText(text: string | undefined): string {\n return typeof text === \"string\" ? text.trimStart() : \"\";\n}\n\nfunction wrapProcessBlockMarkdown(text: string): string {\n const lines = text.split(\"\\n\").filter((line) => line.trim());\n return lines\n .map((line) => `> <font sizeToken=${PROCESS_BLOCK_FONT_SIZE_TOKEN} colorTokenV2=${PROCESS_BLOCK_FONT_COLOR_TOKEN_V2}>${line}</font>`)\n .join(\"\\n\");\n}\n\nexport function createCardDraftController(params: {\n card: AICardInstance;\n throttleMs?: number;\n /** Legacy compatibility: verbose mode previously lowered the throttle. */\n verboseMode?: boolean;\n /** Enable real-time streaming to content key for answer display. */\n realTimeStreamEnabled?: boolean;\n /** Optional callback to get the current statusLine for piggy-backing on blockList updates. */\n getStatusLine?: () => string | undefined;\n log?: Logger;\n}): CardDraftController {\n let failed = false;\n let stopped = false;\n let lastSentContent = \"\";\n let lastQueuedContent = \"\";\n let inFlightContent = \"\";\n let lastAnswerContent = \"\";\n let lastSentStreamingContent = \"\";\n let lastQueuedStreamingContent = \"\";\n let inFlightStreamingContent = \"\";\n\n let timelineEntries: TimelineEntry[] = [];\n let activeThinkingIndex: number | null = null;\n let activeAnswerIndex: number | null = null;\n let pendingBoundaryPromise: Promise<void> | null = null;\n\n const effectiveThrottleMs = params.throttleMs ?? (params.verboseMode ? 50 : 300);\n const realTimeStreamEnabled = params.realTimeStreamEnabled ?? false;\n let hasStreamingContent = false;\n\n const clearPendingStreamingContent = () => {\n contentLoop.resetPending();\n lastQueuedStreamingContent = \"\";\n };\n\n const streamContentToCard = async (text: string) => {\n if (!realTimeStreamEnabled) {\n return;\n }\n const normalized = normalizeAnswerText(text);\n if (!normalized.trim()) {\n clearPendingStreamingContent();\n return;\n }\n if (normalized === lastSentStreamingContent) {\n const hasNewerInFlight = !!inFlightStreamingContent && inFlightStreamingContent !== normalized;\n if (!hasNewerInFlight) {\n clearPendingStreamingContent();\n return;\n }\n }\n if (normalized === lastQueuedStreamingContent) {\n return;\n }\n lastQueuedStreamingContent = normalized;\n contentLoop.update(normalized);\n };\n\n const clearStreamingContentFromCard = async () => {\n clearPendingStreamingContent();\n await contentLoop.waitForInFlight();\n if (!realTimeStreamEnabled || !hasStreamingContent) {\n return;\n }\n try {\n await clearAICardStreamingContent(params.card, params.log);\n hasStreamingContent = false;\n lastSentStreamingContent = \"\";\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n params.log?.debug?.(`[DingTalk][AICard] Failed to clear streaming content: ${message}`);\n }\n };\n\n const getFinalAnswerContent = (): string => {\n return timelineEntries\n .filter((entry) => entry.kind === \"answer\" && entry.text)\n .map((entry) => entry.text)\n .join(\"\\n\\n\");\n };\n\n const removeTimelineEntry = (index: number) => {\n timelineEntries.splice(index, 1);\n if (activeThinkingIndex !== null) {\n if (activeThinkingIndex === index) {\n activeThinkingIndex = null;\n } else if (activeThinkingIndex > index) {\n activeThinkingIndex -= 1;\n }\n }\n if (activeAnswerIndex !== null) {\n if (activeAnswerIndex === index) {\n activeAnswerIndex = null;\n } else if (activeAnswerIndex > index) {\n activeAnswerIndex -= 1;\n }\n }\n };\n\n const appendTimelineEntry = (kind: TimelineEntryKind, text: string): number => {\n timelineEntries.push({ kind, text });\n return timelineEntries.length - 1;\n };\n\n const findCurrentSegmentAnswerIndex = (): number | null => {\n return activeAnswerIndex;\n };\n\n const findLastAnswerEntryIndex = (): number | null => {\n for (let index = timelineEntries.length - 1; index >= 0; index -= 1) {\n if (timelineEntries[index]?.kind === \"answer\") {\n return index;\n }\n }\n return null;\n };\n\n const renderTimelineAsBlocks = (options: {\n fallbackAnswer?: string;\n overrideAnswer?: string;\n } = {}): CardBlock[] => {\n const entries = timelineEntries.map((entry) => ({ ...entry }));\n\n const insertAnswerEntry = (text: string) => {\n const firstImageIndex = entries.findIndex((entry) => entry.kind === \"image\");\n if (firstImageIndex >= 0) {\n entries.splice(firstImageIndex, 0, { kind: \"answer\", text });\n return;\n }\n entries.push({ kind: \"answer\", text });\n };\n\n const overrideAnswer = normalizeAnswerText(options.overrideAnswer);\n if (overrideAnswer) {\n const lastAnswerIndex = [...entries]\n .map((entry, index) => ({ entry, index }))\n .toReversed()\n .find(({ entry }) => entry.kind === \"answer\")?.index;\n if (lastAnswerIndex !== undefined) {\n entries[lastAnswerIndex] = { kind: \"answer\", text: overrideAnswer };\n } else {\n insertAnswerEntry(overrideAnswer);\n }\n } else if (!entries.some((entry) => entry.kind === \"answer\" && entry.text)) {\n const fallbackAnswer = normalizeAnswerText(options.fallbackAnswer);\n if (fallbackAnswer) {\n insertAnswerEntry(fallbackAnswer);\n }\n }\n\n const blocks: CardBlock[] = [];\n for (const entry of entries) {\n if (!entry) { continue; }\n switch (entry.kind) {\n case \"answer\":\n if (entry.text?.trim()) {\n blocks.push({ type: 0, markdown: entry.text });\n }\n break;\n case \"thinking\":\n if (entry.text?.trim()) {\n blocks.push({ type: 1, markdown: wrapProcessBlockMarkdown(entry.text) });\n }\n break;\n case \"tool\":\n if (entry.text?.trim()) {\n blocks.push({ type: 2, markdown: wrapProcessBlockMarkdown(entry.text) });\n }\n break;\n case \"image\":\n if (entry.mediaId?.trim()) {\n blocks.push({\n type: 3,\n mediaId: entry.mediaId,\n ...(entry.text?.trim() ? { text: entry.text } : {}),\n });\n }\n break;\n }\n }\n return blocks;\n };\n\n const sealLiveThinking = () => {\n activeThinkingIndex = null;\n };\n\n const sealCurrentAnswer = () => {\n activeAnswerIndex = null;\n };\n\n const discardCurrentAnswer = () => {\n if (activeAnswerIndex === null) {\n return;\n }\n removeTimelineEntry(activeAnswerIndex);\n queueRender();\n };\n\n const clearPendingRender = () => {\n loop.resetPending();\n lastQueuedContent = \"\";\n };\n\n const queueRender = () => {\n const blocks = renderTimelineAsBlocks();\n const rendered = JSON.stringify(blocks);\n\n // Always update blockList via instances API (throttled)\n if (blocks.length === 0) {\n clearPendingRender();\n return;\n }\n if (rendered === lastSentContent) {\n const hasNewerInFlight = !!inFlightContent && inFlightContent !== rendered;\n if (!hasNewerInFlight) {\n clearPendingRender();\n return;\n }\n }\n if (rendered === lastQueuedContent) {\n return;\n }\n lastQueuedContent = rendered;\n loop.update(rendered);\n };\n\n const flushBoundaryFrame = async () => {\n if (stopped || failed) {\n return;\n }\n await contentLoop.flush();\n await contentLoop.waitForInFlight();\n // Clear streaming content before committing blockList at boundary\n if (hasStreamingContent) {\n await clearStreamingContentFromCard();\n }\n await loop.flush();\n await loop.waitForInFlight();\n contentLoop.resetThrottleWindow();\n loop.resetThrottleWindow();\n };\n\n const beginBoundaryFlush = () => {\n if (pendingBoundaryPromise) {\n return pendingBoundaryPromise;\n }\n const current = flushBoundaryFrame().finally(() => {\n if (pendingBoundaryPromise === current) {\n pendingBoundaryPromise = null;\n }\n });\n pendingBoundaryPromise = current;\n return current;\n };\n\n const waitForPendingBoundary = async () => {\n if (pendingBoundaryPromise) {\n await pendingBoundaryPromise;\n }\n };\n\n const loop = createDraftStreamLoop({\n throttleMs: effectiveThrottleMs,\n isStopped: () => stopped || failed,\n sendOrEditStreamMessage: async (content: string) => {\n inFlightContent = content;\n try {\n // Use instances API for blockList (not streaming API)\n const statusLine = params.getStatusLine?.();\n await updateAICardBlockList(params.card, content, params.log, statusLine ? { statusLine } : undefined);\n lastSentContent = content;\n lastQueuedContent = \"\";\n lastAnswerContent = getFinalAnswerContent();\n } catch (err: unknown) {\n failed = true;\n const message = err instanceof Error ? err.message : String(err);\n params.log?.warn?.(`[DingTalk][AICard] BlockList update failed: ${message}`);\n } finally {\n if (inFlightContent === content) {\n inFlightContent = \"\";\n }\n }\n },\n });\n\n const contentLoop = createDraftStreamLoop({\n throttleMs: effectiveThrottleMs,\n isStopped: () => stopped || failed,\n sendOrEditStreamMessage: async (content: string) => {\n inFlightStreamingContent = content;\n try {\n await streamAICardContent(params.card, content, params.log);\n hasStreamingContent = true;\n lastSentStreamingContent = content;\n lastQueuedStreamingContent = \"\";\n lastAnswerContent = content;\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n params.log?.debug?.(`[DingTalk][AICard] Failed to stream content: ${message}`);\n } finally {\n if (inFlightStreamingContent === content) {\n inFlightStreamingContent = \"\";\n }\n }\n },\n });\n\n const updateReasoning = async (text: string) => {\n await waitForPendingBoundary();\n if (stopped || failed || activeAnswerIndex !== null) {\n return;\n }\n const normalized = normalizeProcessText(text);\n if (!normalized) {\n return;\n }\n if (activeThinkingIndex === null && timelineEntries.length > 0) {\n const lastKind = timelineEntries.at(-1)?.kind;\n if (lastKind && lastKind !== \"thinking\") {\n await flushBoundaryFrame();\n }\n }\n if (activeThinkingIndex !== null) {\n timelineEntries[activeThinkingIndex] = { kind: \"thinking\", text: normalized };\n } else {\n activeThinkingIndex = appendTimelineEntry(\"thinking\", normalized);\n }\n queueRender();\n };\n\n const updateAnswer = async (text: string, options: { stream?: boolean; renderBlocks?: boolean } = {}) => {\n await waitForPendingBoundary();\n if (stopped || failed) {\n return;\n }\n const normalized = normalizeAnswerText(text);\n if (!normalized.trim()) {\n return;\n }\n if (activeAnswerIndex === null && timelineEntries.length > 0) {\n const lastKind = timelineEntries.at(-1)?.kind;\n if (lastKind && lastKind !== \"answer\") {\n await flushBoundaryFrame();\n }\n }\n sealLiveThinking();\n if (activeAnswerIndex !== null) {\n timelineEntries[activeAnswerIndex] = { kind: \"answer\", text: normalized };\n } else {\n activeAnswerIndex = appendTimelineEntry(\"answer\", normalized);\n }\n if (options.stream !== false) {\n await streamContentToCard(normalized);\n } else {\n clearPendingStreamingContent();\n }\n const shouldRenderBlocks = options.renderBlocks ?? (options.stream !== false);\n if (!shouldRenderBlocks) {\n clearPendingRender();\n return;\n }\n queueRender();\n };\n\n const updateTool = async (text: string) => {\n await waitForPendingBoundary();\n if (stopped || failed) {\n return;\n }\n const normalized = normalizeProcessText(text);\n if (!normalized) {\n return;\n }\n if (timelineEntries.length > 0) {\n await flushBoundaryFrame();\n }\n sealLiveThinking();\n sealCurrentAnswer();\n appendTimelineEntry(\"tool\", normalized);\n queueRender();\n };\n\n const appendThinkingBlock = async (text: string) => {\n await waitForPendingBoundary();\n if (stopped || failed) {\n return;\n }\n const normalized = normalizeProcessText(text);\n if (!normalized) {\n return;\n }\n if (timelineEntries.length > 0) {\n await flushBoundaryFrame();\n }\n sealLiveThinking();\n const currentSegmentAnswerIndex = findCurrentSegmentAnswerIndex();\n if (currentSegmentAnswerIndex !== null) {\n timelineEntries.splice(currentSegmentAnswerIndex, 0, { kind: \"thinking\", text: normalized });\n if (activeAnswerIndex !== null && activeAnswerIndex >= currentSegmentAnswerIndex) {\n activeAnswerIndex += 1;\n }\n } else {\n sealCurrentAnswer();\n appendTimelineEntry(\"thinking\", normalized);\n }\n queueRender();\n };\n\n const appendToolBeforeCurrentAnswer = async (text: string) => {\n await waitForPendingBoundary();\n if (stopped || failed) {\n return;\n }\n const normalized = normalizeProcessText(text);\n if (!normalized) {\n return;\n }\n if (timelineEntries.length > 0) {\n await flushBoundaryFrame();\n }\n sealLiveThinking();\n const insertionIndex = findCurrentSegmentAnswerIndex() ?? findLastAnswerEntryIndex();\n if (insertionIndex !== null) {\n timelineEntries.splice(insertionIndex, 0, { kind: \"tool\", text: normalized });\n if (activeAnswerIndex !== null && activeAnswerIndex >= insertionIndex) {\n activeAnswerIndex += 1;\n }\n if (activeThinkingIndex !== null && activeThinkingIndex >= insertionIndex) {\n activeThinkingIndex += 1;\n }\n } else {\n sealCurrentAnswer();\n appendTimelineEntry(\"tool\", normalized);\n }\n queueRender();\n };\n\n const notifyNewAssistantTurn = async (options: {\n discardActiveAnswer?: boolean;\n } = {}) => {\n if (stopped || failed) {\n return;\n }\n if (activeAnswerIndex !== null) {\n if (options.discardActiveAnswer) {\n discardCurrentAnswer();\n } else {\n sealCurrentAnswer();\n }\n await beginBoundaryFlush();\n return;\n }\n if (activeThinkingIndex !== null) {\n removeTimelineEntry(activeThinkingIndex);\n clearPendingRender();\n }\n };\n\n const appendImageBlock = async (mediaId: string, text = \"\") => {\n await waitForPendingBoundary();\n if (stopped || failed) {\n return;\n }\n if (!mediaId.trim()) {\n return;\n }\n if (timelineEntries.length > 0) {\n await flushBoundaryFrame();\n }\n sealLiveThinking();\n sealCurrentAnswer();\n timelineEntries.push({ kind: \"image\", text, mediaId });\n queueRender();\n };\n\n return {\n updateAnswer,\n updateReasoning,\n updateThinking: updateReasoning,\n appendThinkingBlock,\n updateTool,\n appendTool: updateTool,\n appendImageBlock,\n appendToolBeforeCurrentAnswer,\n discardCurrentAnswer,\n notifyNewAssistantTurn,\n startAssistantTurn: notifyNewAssistantTurn,\n sealActiveThinking: async () => {\n if (stopped || failed) {\n return;\n }\n if (activeThinkingIndex !== null) {\n sealLiveThinking();\n await beginBoundaryFlush();\n }\n },\n flush: async () => {\n await contentLoop.flush();\n await loop.flush();\n },\n waitForInFlight: async () => {\n await contentLoop.waitForInFlight();\n await loop.waitForInFlight();\n },\n\n stop: () => {\n stopped = true;\n contentLoop.stop();\n loop.stop();\n },\n\n isFailed: () => failed,\n getLastContent: () => lastSentContent,\n getLastAnswerContent: () => lastAnswerContent,\n getFinalAnswerContent,\n getRenderedBlocks: (options?: { fallbackAnswer?: string; overrideAnswer?: string }) => {\n const blocks = renderTimelineAsBlocks(options);\n if (blocks.length === 0) {\n return \"\";\n }\n return JSON.stringify(blocks);\n },\n getRenderedContent: (options?: { fallbackAnswer?: string; overrideAnswer?: string; compactProcessAnswerSpacing?: boolean }) => {\n const blocks = renderTimelineAsBlocks(options);\n // Extract markdown from answer blocks (type: 0) and join with double newlines\n const answerTexts = blocks\n .filter((block) => block.type === 0 && \"markdown\" in block && block.markdown)\n .map((block) => (\"markdown\" in block ? block.markdown : \"\"));\n return answerTexts.join(\"\\n\\n\");\n },\n\n streamContent: realTimeStreamEnabled ? streamContentToCard : undefined,\n clearStreamingContent: realTimeStreamEnabled ? clearStreamingContentFromCard : undefined,\n isRealTimeStreamEnabled: () => realTimeStreamEnabled,\n };\n}\n", "interface SessionState {\n model?: string;\n effort?: string;\n taskStartTime: number;\n}\n\nconst sessionStore = new Map<string, SessionState>();\n\nfunction sessionKey(accountId: string, conversationId: string): string {\n return `${accountId}:${conversationId}`;\n}\n\nexport function initSessionState(accountId: string, conversationId: string): SessionState {\n const key = sessionKey(accountId, conversationId);\n const existing = sessionStore.get(key);\n if (existing) {\n existing.taskStartTime = Date.now();\n return existing;\n }\n const state: SessionState = {\n taskStartTime: Date.now(),\n };\n sessionStore.set(key, state);\n return state;\n}\n\nexport function getSessionState(accountId: string, conversationId: string): SessionState | undefined {\n return sessionStore.get(sessionKey(accountId, conversationId));\n}\n\nexport function updateSessionState(\n accountId: string,\n conversationId: string,\n patch: Partial<Pick<SessionState, \"model\" | \"effort\">>,\n): void {\n const state = sessionStore.get(sessionKey(accountId, conversationId));\n if (!state) {\n return;\n }\n if (patch.model !== undefined) {\n state.model = patch.model;\n }\n if (patch.effort !== undefined) {\n state.effort = patch.effort;\n }\n}\n\nexport function getTaskTimeSeconds(accountId: string, conversationId: string): number | undefined {\n const state = sessionStore.get(sessionKey(accountId, conversationId));\n if (!state) {\n return undefined;\n }\n return Math.round((Date.now() - state.taskStartTime) / 1000);\n}\n\nexport function clearSessionState(accountId: string, conversationId: string): void {\n sessionStore.delete(sessionKey(accountId, conversationId));\n}\n\nexport function clearAllSessionStatesForTest(): void {\n sessionStore.clear();\n}\n", "export interface UsageAccumulation {\n input?: number;\n output?: number;\n cacheRead?: number;\n cacheWrite?: number;\n total?: number;\n}\n\nconst usageStore = new Map<string, UsageAccumulation>();\n\nexport function recordRunStart(runId: string): void {\n if (!usageStore.has(runId)) {\n usageStore.set(runId, {});\n }\n}\n\nexport function accumulateUsage(runId: string, usage: UsageAccumulation): void {\n const existing = usageStore.get(runId);\n if (!existing) { return; }\n\n for (const field of [\"input\", \"output\", \"cacheRead\", \"cacheWrite\", \"total\"] as const) {\n const value = usage[field];\n if (typeof value === \"number\") {\n existing[field] = (existing[field] ?? 0) + value;\n }\n }\n}\n\nexport function getUsageByRunId(runId: string): UsageAccumulation | undefined {\n return usageStore.get(runId);\n}\n\nexport function getAggregatedUsage(runIds: Set<string> | undefined): UsageAccumulation {\n const result: UsageAccumulation = {};\n if (!runIds) { return result; }\n for (const runId of runIds) {\n const usage = usageStore.get(runId);\n if (!usage) { continue; }\n for (const field of [\"input\", \"output\", \"cacheRead\", \"cacheWrite\", \"total\"] as const) {\n if (typeof usage[field] === \"number\") {\n result[field] = (result[field] ?? 0) + usage[field];\n }\n }\n }\n return result;\n}\n\nexport function clearRun(runId: string | undefined): void {\n if (runId) { usageStore.delete(runId); }\n}\n\nexport function clearRuns(runIds: Set<string> | undefined): void {\n if (!runIds) { return; }\n for (const runId of runIds) { usageStore.delete(runId); }\n}\n\nexport function clearAllForTest(): void {\n usageStore.clear();\n}\n", "/**\n * AI Card reply strategy.\n *\n * Encapsulates the card draft controller lifecycle, deliver routing\n * (final / tool / block), finalization, and failure fallback so that\n * inbound-handler only coordinates \u2014 it no longer owns card state.\n */\n\nimport {\n commitAICardBlocks,\n isCardInTerminalState,\n updateAICardStatusLine,\n} from \"./card-service\";\nimport { splitCardReasoningAnswerText } from \"./card/reasoning-answer-split\";\nimport { createReasoningBlockAssembler } from \"./card/reasoning-block-assembler\";\nimport {\n resolveCardStreamingMode,\n shouldWarnDeprecatedCardRealTimeStreamOnce,\n} from \"./card/card-streaming-mode\";\nimport {\n buildImagePlaceholderText,\n extractMarkdownImageCandidates,\n} from \"./card/card-markdown-image-reroute\";\nimport { createCardDraftController } from \"./card-draft-controller\";\nimport { attachCardRunController } from \"./card/card-run-registry\";\nimport type { DeliverPayload, ReplyOptions, ReplyStrategy, ReplyStrategyContext } from \"./reply-strategy-types\";\nimport { resolveRelativePath } from \"./config\";\nimport { prepareMediaInput, resolveOutboundMediaType } from \"./media-utils\";\nimport { getTaskTimeSeconds, updateSessionState } from \"./session-state\";\nimport { renderStatusLine } from \"./card/statusline-renderer\";\nimport type { StatusLineData } from \"./card/statusline-renderer\";\nimport { recordRunStart, getAggregatedUsage, clearRuns } from \"./run-usage-store\";\nimport { sendBySession, sendMessage, sendProactiveMedia, uploadMedia } from \"./send-service\";\nimport type { AICardInstance } from \"./types\";\nimport { AICardStatus } from \"./types\";\nimport { formatDingTalkErrorPayloadLog } from \"./utils\";\n\nconst EMPTY_FINAL_REPLY = \"\u2705 Done\";\nconst DEFAULT_CARD_FAILED_MESSAGE = \"\u56DE\u590D\u751F\u6210\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\";\ntype CardReplyLifecycleState = \"open\" | \"final_seen\" | \"sealed\";\n\n/** Deferred media attachment for out-of-card delivery */\ninterface DeferredMedia {\n url: string;\n type: \"voice\" | \"video\" | \"file\";\n}\n\nexport function createCardReplyStrategy(\n ctx: ReplyStrategyContext & { card: AICardInstance; isStopRequested?: () => boolean },\n): ReplyStrategy {\n const { card, config, log, isStopRequested } = ctx;\n\n const buildStatusLine = (): string | undefined => {\n if (!ctx.taskMeta) {\n return undefined;\n }\n const resolvedUsage =\n typeof card.dapiUsage === \"number\"\n ? card.dapiUsage\n : typeof ctx.taskMeta.usage === \"number\"\n ? ctx.taskMeta.usage\n : undefined;\n\n const sessionTaskTimeSeconds = card.accountId && card.conversationId\n ? getTaskTimeSeconds(card.accountId, card.contextConversationId || card.conversationId)\n : undefined;\n const cardElapsedMs = Math.max(0, Date.now() - card.createdAt);\n const sessionElapsedMs = typeof sessionTaskTimeSeconds === \"number\"\n ? sessionTaskTimeSeconds * 1000\n : undefined;\n const metaElapsedMs = typeof ctx.taskMeta.elapsedMs === \"number\" && ctx.taskMeta.elapsedMs > 0\n ? ctx.taskMeta.elapsedMs\n : undefined;\n ctx.taskMeta.elapsedMs = Math.max(\n cardElapsedMs,\n sessionElapsedMs ?? 0,\n metaElapsedMs ?? 0,\n );\n\n let inputTokens: number | undefined;\n let outputTokens: number | undefined;\n let cacheRead: number | undefined;\n if (ctx.taskMeta.runIds && ctx.taskMeta.runIds.size > 0) {\n const tokenUsage = getAggregatedUsage(ctx.taskMeta.runIds);\n if (typeof tokenUsage.input === \"number\") { inputTokens = tokenUsage.input; }\n if (typeof tokenUsage.output === \"number\") { outputTokens = tokenUsage.output; }\n if (typeof tokenUsage.cacheRead === \"number\") { cacheRead = tokenUsage.cacheRead; }\n }\n\n const statusLineData: StatusLineData = {\n model: ctx.taskMeta.model,\n effort: ctx.taskMeta.effort,\n agent: ctx.taskMeta.agent,\n taskTime: typeof ctx.taskMeta.elapsedMs === \"number\" ? Math.round(ctx.taskMeta.elapsedMs / 1000) : undefined,\n inputTokens,\n outputTokens,\n cacheRead,\n dapi_usage: resolvedUsage,\n };\n const statusLine = renderStatusLine(statusLineData, config);\n return statusLine || undefined;\n };\n const { mode, usedDeprecatedCardRealTimeStream } = resolveCardStreamingMode(config);\n const streamAnswerLive = mode === \"answer\" || mode === \"all\";\n const renderAnswerBlocksLive = mode === \"all\";\n const streamThinkingLive = mode === \"all\";\n let lifecycleState: CardReplyLifecycleState = \"open\";\n const shouldAcceptAnswerSnapshot = () => lifecycleState === \"open\";\n const isLifecycleSealed = () => lifecycleState === \"sealed\";\n\n if (usedDeprecatedCardRealTimeStream) {\n const warningKey = `dingtalk-card-streaming:${ctx.accountId || config.clientId || \"default\"}`;\n if (shouldWarnDeprecatedCardRealTimeStreamOnce(warningKey)) {\n log?.warn?.(\n \"[DingTalk][Config] `cardRealTimeStream` is deprecated. Use `cardStreamingMode` with `off` | `answer` | `all`.\",\n );\n }\n }\n\n const controller = createCardDraftController({\n card,\n log,\n realTimeStreamEnabled: streamAnswerLive,\n throttleMs: config.cardStreamInterval ?? 1000,\n getStatusLine: buildStatusLine,\n });\n const reasoningAssembler = createReasoningBlockAssembler();\n if (card.outTrackId) {\n attachCardRunController(card.outTrackId, controller);\n }\n let finalTextForFallback: string | undefined;\n let sawFinalDelivery = false;\n /** Tracks the latest reasoning snapshot text for non-streaming boundary flush. */\n let latestReasoningSnapshot = \"\";\n /** Non-image media attachments deferred for out-of-card delivery. */\n let pendingNonImageMedia: DeferredMedia[] = [];\n\n const getRenderedTimeline = (options: { preferFinalAnswer?: boolean } = {}): string => {\n const fallbackAnswer = finalTextForFallback || (sawFinalDelivery ? EMPTY_FINAL_REPLY : undefined);\n return controller.getRenderedContent({\n fallbackAnswer,\n overrideAnswer: options.preferFinalAnswer ? finalTextForFallback : undefined,\n });\n };\n\n const appendAssembledThinkingBlocks = async (blocks: string[]): Promise<void> => {\n for (const block of blocks) {\n if (!block.trim() || isStopRequested?.()) {\n continue;\n }\n await controller.appendThinkingBlock(block);\n }\n };\n\n const applyModeAwareDeliveredReasoning = async (text: string | undefined): Promise<void> => {\n if (typeof text !== \"string\" || !text.trim() || isStopRequested?.()) {\n return;\n }\n if (streamThinkingLive) {\n await controller.appendThinkingBlock(text);\n return;\n }\n await applyModeAwareReasoningSnapshot(text);\n };\n\n const applyModeAwareReasoningSnapshot = async (text: string | undefined): Promise<void> => {\n if (typeof text !== \"string\" || !text.trim() || isStopRequested?.()) {\n return;\n }\n if (streamThinkingLive) {\n latestReasoningSnapshot = text;\n await controller.updateReasoning(text);\n return;\n }\n const blocks = reasoningAssembler.ingestSnapshot(text);\n const trimmed = text.trimStart();\n if (\n blocks.length === 0\n && !trimmed.startsWith(\"Reasoning:\")\n ) {\n if (trimmed.startsWith(\"Reason:\")) {\n latestReasoningSnapshot = \"\";\n return;\n }\n latestReasoningSnapshot = text.trim();\n return;\n }\n latestReasoningSnapshot = \"\";\n await appendAssembledThinkingBlocks(blocks);\n };\n\n const flushPendingReasoning = async (): Promise<void> => {\n if (streamThinkingLive) {\n await controller.sealActiveThinking();\n latestReasoningSnapshot = \"\";\n return;\n }\n const blocks = reasoningAssembler.flushPendingAtBoundary();\n if (latestReasoningSnapshot) {\n blocks.push(latestReasoningSnapshot);\n latestReasoningSnapshot = \"\";\n }\n await appendAssembledThinkingBlocks(blocks);\n };\n\n const handleAssistantBoundary = async (): Promise<void> => {\n if (streamThinkingLive) {\n await controller.sealActiveThinking();\n latestReasoningSnapshot = \"\";\n reasoningAssembler.reset();\n await controller.notifyNewAssistantTurn();\n return;\n }\n const pendingReasoningBlocks = reasoningAssembler.flushPendingAtBoundary();\n if (latestReasoningSnapshot) {\n pendingReasoningBlocks.push(latestReasoningSnapshot);\n latestReasoningSnapshot = \"\";\n }\n reasoningAssembler.reset();\n const turnBoundary = controller.notifyNewAssistantTurn();\n if (pendingReasoningBlocks.length > 0) {\n await turnBoundary;\n await appendAssembledThinkingBlocks(pendingReasoningBlocks);\n return;\n }\n await turnBoundary;\n };\n\n const normalizeDeliveredText = (\n text: string,\n options: { isReasoning: boolean },\n ): { reasoningText?: string; answerText?: string } => {\n if (options.isReasoning) {\n const split = splitCardReasoningAnswerText(text);\n return { reasoningText: split.reasoningText || text };\n }\n const split = splitCardReasoningAnswerText(text);\n return {\n reasoningText: split.reasoningText,\n answerText: split.answerText,\n };\n };\n\n const applyDeliveredContent = async (\n normalized: { reasoningText?: string; answerText?: string },\n options: {\n routeReasoningThroughModePolicy: boolean;\n answerHandling?: \"update\" | \"capture\" | \"ignore\";\n },\n ): Promise<void> => {\n if (normalized.reasoningText) {\n if (options.routeReasoningThroughModePolicy) {\n await applyModeAwareDeliveredReasoning(normalized.reasoningText);\n } else {\n // Conservative local split fallback: keep existing behavior for mixed payloads.\n await controller.appendThinkingBlock(normalized.reasoningText);\n }\n }\n if (normalized.answerText && options.answerHandling !== \"ignore\") {\n if (options.answerHandling === \"capture\") {\n finalTextForFallback = normalized.answerText;\n return;\n }\n await controller.updateAnswer(normalized.answerText);\n }\n };\n\n const rewriteLocalMarkdownImagesToPlaceholders = (text: string): string => {\n const candidates = extractMarkdownImageCandidates(text);\n if (candidates.length === 0) {\n return text;\n }\n\n let nextText = text;\n for (const candidate of candidates.toReversed()) {\n if (candidate.classification !== \"local\") {\n continue;\n }\n const placeholder = buildImagePlaceholderText({ alt: candidate.alt, url: candidate.url });\n nextText = `${nextText.slice(0, candidate.start)}${placeholder}${nextText.slice(candidate.end)}`;\n }\n return nextText;\n };\n\n const handleAnswerSnapshot = async (text: string | undefined): Promise<void> => {\n if (!shouldAcceptAnswerSnapshot() || isStopRequested?.()) {\n return;\n }\n if (!text) {\n return;\n }\n const rewrittenSnapshot = rewriteLocalMarkdownImagesToPlaceholders(text);\n const normalizedSnapshot = normalizeDeliveredText(rewrittenSnapshot, { isReasoning: false });\n\n if (normalizedSnapshot.reasoningText) {\n await applyModeAwareReasoningSnapshot(normalizedSnapshot.reasoningText);\n }\n\n const answerSnapshot = normalizedSnapshot.answerText\n ?? (!normalizedSnapshot.reasoningText ? rewrittenSnapshot : undefined);\n if (!answerSnapshot) {\n return;\n }\n\n await controller.updateAnswer(answerSnapshot, {\n stream: streamAnswerLive,\n renderBlocks: renderAnswerBlocksLive,\n });\n };\n\n const applySplitTextToTimeline = async (\n text: string,\n options: { answerHandling?: \"update\" | \"capture\" | \"ignore\" } = {},\n ) => {\n const normalized = normalizeDeliveredText(text, { isReasoning: false });\n await applyDeliveredContent(normalized, {\n routeReasoningThroughModePolicy: true,\n answerHandling: options.answerHandling ?? \"update\",\n });\n return normalized;\n };\n\n const rerouteMarkdownImagesFromAnswer = async (text: string): Promise<string> => {\n const candidates = extractMarkdownImageCandidates(text);\n if (candidates.length === 0) {\n return text;\n }\n\n type SuccessfulReroute = {\n start: number;\n end: number;\n placeholder: string;\n mediaId: string;\n blockText: string;\n };\n\n let nextText = text;\n const successfulReroutes: SuccessfulReroute[] = [];\n\n for (const candidate of candidates.toReversed()) {\n if (candidate.classification !== \"local\") {\n continue;\n }\n\n let prepared: Awaited<ReturnType<typeof prepareMediaInput>> | undefined;\n try {\n prepared = await prepareMediaInput(candidate.url, log, config.mediaUrlAllowlist);\n const mediaPath = prepared.cleanup\n ? prepared.path\n : resolveRelativePath(prepared.path);\n const mediaType = resolveOutboundMediaType({ mediaPath, asVoice: false });\n if (mediaType !== \"image\") {\n continue;\n }\n\n const result = await uploadMedia(config, mediaPath, \"image\", log);\n if (!result?.mediaId) {\n continue;\n }\n\n const placeholder = buildImagePlaceholderText({ alt: candidate.alt, url: candidate.url });\n const blockText = candidate.alt.trim() || placeholder.replace(/^\u89C1\u4E0B\u56FE/, \"\").trim() || \"\u56FE\u7247\";\n successfulReroutes.push({\n start: candidate.start,\n end: candidate.end,\n placeholder,\n mediaId: result.mediaId,\n blockText,\n });\n nextText = `${nextText.slice(0, candidate.start)}${placeholder}${nextText.slice(candidate.end)}`;\n } catch {\n // Failure fallback: keep the original markdown unchanged.\n } finally {\n await prepared?.cleanup?.();\n }\n }\n\n for (const reroute of successfulReroutes.toSorted((left, right) => left.start - right.start)) {\n await controller.appendImageBlock(reroute.mediaId, reroute.blockText);\n }\n\n return nextText;\n };\n\n return {\n getReplyOptions(): ReplyOptions {\n return {\n // Card mode keeps runtime block streaming disabled, but still consumes\n // reasoning blocks through explicit callbacks and delivery metadata.\n disableBlockStreaming: ctx.disableBlockStreaming ?? true,\n\n onAssistantMessageStart: async () => {\n if (isLifecycleSealed() || isStopRequested?.()) {\n return;\n }\n await handleAssistantBoundary();\n },\n\n onAgentRunStart: (runId: string) => {\n if (isLifecycleSealed()) {\n return;\n }\n recordRunStart(runId);\n if (ctx.taskMeta) {\n if (!ctx.taskMeta.runIds) { ctx.taskMeta.runIds = new Set(); }\n ctx.taskMeta.runIds.add(runId);\n }\n },\n\n onPartialReply: async (payload) => {\n await handleAnswerSnapshot(payload.text);\n },\n\n onReasoningStream: async (payload) => {\n if (isLifecycleSealed() || isStopRequested?.()) {\n return;\n }\n await applyModeAwareReasoningSnapshot(payload.text);\n },\n\n onModelSelected: (selected) => {\n if (!card.accountId || !card.conversationId) {\n return;\n }\n updateSessionState(card.accountId, card.contextConversationId || card.conversationId, {\n model: selected.model,\n effort: selected.thinkLevel,\n });\n if (ctx.taskMeta) {\n ctx.taskMeta.model = selected.model;\n ctx.taskMeta.effort = selected.thinkLevel;\n }\n const statusLine = buildStatusLine();\n if (statusLine) {\n void updateAICardStatusLine(card, statusLine, log);\n }\n },\n };\n },\n\n async deliver(payload: DeliverPayload): Promise<void> {\n if (isLifecycleSealed()) {\n return;\n }\n const textToSend = payload.text;\n\n // Empty-payload guard \u2014 card final is an exception (e.g. file-only response).\n if ((typeof textToSend !== \"string\" || textToSend.length === 0) && payload.mediaUrls.length === 0) {\n if (payload.kind !== \"final\") {\n return;\n }\n }\n\n // ---- final: defer to finalize, just save text ----\n if (payload.kind === \"final\") {\n const isFirstFinalDelivery = !sawFinalDelivery;\n lifecycleState = \"final_seen\";\n await flushPendingReasoning();\n if (isFirstFinalDelivery) {\n sawFinalDelivery = true;\n }\n log?.info?.(\n `[DingTalk][Finalize] deliver(final) received \u2014 cardState=${card.state} ` +\n `textLen=${typeof textToSend === \"string\" ? textToSend.length : \"null\"} ` +\n `mediaUrls=${payload.mediaUrls.length} ` +\n `lastAnswer=\"${(controller.getLastAnswerContent() ?? \"\").slice(0, 80)}\" ` +\n `lastContent=\"${(controller.getLastContent() ?? \"\").slice(0, 80)}\"`,\n );\n // Inline media upload \u2192 image blocks in card; defer non-image attachments\n if (payload.mediaUrls.length > 0) {\n for (const url of payload.mediaUrls) {\n try {\n const prepared = await prepareMediaInput(url, log, config.mediaUrlAllowlist);\n const mediaType = resolveOutboundMediaType({ mediaPath: prepared.path, asVoice: false });\n if (mediaType !== \"image\") {\n log?.debug?.(`[DingTalk][Card] Deferring non-image media (${mediaType}) for out-of-card delivery: ${url}`);\n // Collect non-image attachments for later delivery\n if (mediaType === \"voice\" || mediaType === \"video\" || mediaType === \"file\") {\n pendingNonImageMedia.push({ url, type: mediaType });\n }\n await prepared.cleanup?.();\n continue;\n }\n const result = await uploadMedia(config, prepared.path, \"image\", log);\n await prepared.cleanup?.();\n if (result?.mediaId) {\n await controller.appendImageBlock(result.mediaId);\n }\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n log?.debug?.(`[DingTalk][Card] Failed to upload media as image block: ${msg}`);\n }\n }\n }\n const rawFinalText = typeof textToSend === \"string\" ? textToSend : \"\";\n if (rawFinalText) {\n if (payload.isReasoning === true) {\n await applyModeAwareReasoningSnapshot(rawFinalText);\n await flushPendingReasoning();\n } else {\n const rewrittenFinalText = await rerouteMarkdownImagesFromAnswer(rawFinalText);\n const normalizedFinal = await applySplitTextToTimeline(rewrittenFinalText, {\n answerHandling: \"capture\",\n });\n if (isFirstFinalDelivery && !normalizedFinal.answerText && !normalizedFinal.reasoningText) {\n finalTextForFallback = rewrittenFinalText;\n }\n await flushPendingReasoning();\n }\n }\n return;\n }\n\n // ---- tool: append to card ----\n if (payload.kind === \"tool\") {\n if (controller.isFailed() || isCardInTerminalState(card.state)) {\n log?.debug?.(\"[DingTalk] Card failed, skipping tool result (will send full reply on final)\");\n return;\n }\n await flushPendingReasoning();\n log?.info?.(\n `[DingTalk] Tool result received, streaming to AI Card: ${(textToSend ?? \"\").slice(0, 100)}`,\n );\n if (lifecycleState === \"final_seen\") {\n await controller.appendToolBeforeCurrentAnswer(textToSend ?? \"\");\n } else {\n await controller.appendTool(textToSend ?? \"\");\n }\n return;\n }\n\n const isReasoningBlock = payload.isReasoning === true;\n if (typeof textToSend === \"string\" && textToSend.trim()) {\n if (isReasoningBlock) {\n const normalized = normalizeDeliveredText(textToSend, { isReasoning: true });\n await applyDeliveredContent(normalized, {\n routeReasoningThroughModePolicy: false,\n answerHandling: \"ignore\",\n });\n } else {\n await applySplitTextToTimeline(rewriteLocalMarkdownImagesToPlaceholders(textToSend), {\n answerHandling: lifecycleState === \"open\" ? \"update\" : \"capture\",\n });\n }\n }\n\n // ---- block: only handle reasoning/media (other text blocks are unused) ----\n if (payload.mediaUrls.length > 0) {\n for (const url of payload.mediaUrls) {\n try {\n const prepared = await prepareMediaInput(url, log, config.mediaUrlAllowlist);\n const mediaType = resolveOutboundMediaType({ mediaPath: prepared.path, asVoice: false });\n if (mediaType !== \"image\") {\n log?.debug?.(`[DingTalk][Card] Deferring non-image media (${mediaType}) for out-of-card delivery: ${url}`);\n pendingNonImageMedia.push({ url, type: mediaType });\n await prepared.cleanup?.();\n continue;\n }\n const result = await uploadMedia(config, prepared.path, \"image\", log);\n await prepared.cleanup?.();\n if (result?.mediaId) {\n await controller.appendImageBlock(result.mediaId);\n }\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n log?.debug?.(`[DingTalk][Card] Failed to upload media as image block: ${msg}`);\n }\n }\n }\n },\n\n async finalize(): Promise<void> {\n log?.info?.(\n `[DingTalk][Finalize] Step 5 entry \u2014 ` +\n `cardState=${card.state ?? \"N/A\"} ` +\n `controllerFailed=${controller.isFailed()} ` +\n `finalTextForFallback=\"${(finalTextForFallback ?? \"\").slice(0, 80)}\" ` +\n `lastAnswer=\"${(controller.getLastAnswerContent() ?? \"\").slice(0, 80)}\" ` +\n `lastContent=\"${(controller.getLastContent() ?? \"\").slice(0, 80)}\"`,\n );\n\n if (isStopRequested?.()) {\n log?.info?.(\"[DingTalk][Finalize] Skipping \u2014 card stop was requested\");\n lifecycleState = \"sealed\";\n if (card.accountId && card.conversationId) {\n clearRuns(ctx.taskMeta?.runIds);\n }\n return;\n }\n\n if (card.state === AICardStatus.FINISHED) {\n // Card was already finalized (e.g. first embedded run timed out).\n // If session-recovery triggered a second run that produced new content,\n // deliver it as a markdown fallback so the user sees the final result.\n // The user may see partial overlap with the frozen card's content, but\n // delivering the full answer is preferred over silence.\n const recoveryText = getRenderedTimeline({ preferFinalAnswer: true })\n || finalTextForFallback\n || controller.getLastAnswerContent()\n || controller.getLastContent();\n if (recoveryText) {\n log?.info?.(\n `[DingTalk][Finalize] Card already FINISHED \u2014 sending markdown fallback for session-recovery content ` +\n `len=${recoveryText.length} preview=\"${recoveryText.slice(0, 80)}\"`,\n );\n const sendResult = await sendMessage(ctx.config, ctx.to, recoveryText, {\n sessionWebhook: ctx.sessionWebhook,\n atUserId: !ctx.isDirect ? ctx.senderId : null,\n log,\n accountId: ctx.accountId,\n storePath: ctx.storePath,\n conversationId: ctx.groupId,\n quotedRef: ctx.replyQuotedRef,\n forceMarkdown: true,\n });\n if (!sendResult.ok) {\n log?.warn?.(\n `[DingTalk][Finalize] Markdown fallback after FINISHED card failed: ${sendResult.error}`,\n );\n }\n } else {\n log?.info?.(\"[DingTalk][Finalize] Skipping \u2014 card already FINISHED and no new content\");\n }\n lifecycleState = \"sealed\";\n if (card.accountId && card.conversationId) {\n clearRuns(ctx.taskMeta?.runIds);\n }\n return;\n }\n\n if (card.state === AICardStatus.STOPPED) {\n log?.info?.(\"[DingTalk][Finalize] Skipping \u2014 card already STOPPED\");\n lifecycleState = \"sealed\";\n if (card.accountId && card.conversationId) {\n clearRuns(ctx.taskMeta?.runIds);\n }\n return;\n }\n\n // Card failed -> markdown fallback (bypass sendMessage to avoid duplicate card).\n if (card.state === AICardStatus.FAILED || controller.isFailed()) {\n const fallbackText = getRenderedTimeline({ preferFinalAnswer: true })\n || controller.getLastAnswerContent()\n || DEFAULT_CARD_FAILED_MESSAGE;\n if (fallbackText) {\n log?.debug?.(\"[DingTalk] Card failed during streaming, sending markdown fallback\");\n const sendResult = await sendMessage(ctx.config, ctx.to, fallbackText, {\n sessionWebhook: ctx.sessionWebhook,\n atUserId: !ctx.isDirect ? ctx.senderId : null,\n log,\n accountId: ctx.accountId,\n storePath: ctx.storePath,\n conversationId: ctx.groupId,\n quotedRef: ctx.replyQuotedRef,\n forceMarkdown: true,\n });\n if (!sendResult.ok) {\n throw new Error(sendResult.error || \"Markdown fallback send failed after card failure\");\n }\n } else {\n log?.debug?.(\"[DingTalk] Card failed but no content to fallback with\");\n }\n lifecycleState = \"sealed\";\n if (card.accountId && card.conversationId) {\n clearRuns(ctx.taskMeta?.runIds);\n }\n return;\n }\n\n // Normal finalize (V2 template path: single instances API call).\n try {\n await flushPendingReasoning();\n\n await controller.flush();\n await controller.waitForInFlight();\n\n // Prepare finalize options for single instances API call\n const fallbackAnswer = finalTextForFallback || (sawFinalDelivery ? EMPTY_FINAL_REPLY : undefined);\n const blockListJson = controller.getRenderedBlocks({\n fallbackAnswer,\n overrideAnswer: finalTextForFallback,\n });\n const content = controller.getRenderedContent({\n fallbackAnswer,\n overrideAnswer: finalTextForFallback,\n }) || fallbackAnswer || EMPTY_FINAL_REPLY;\n\n controller.stop();\n log?.info?.(\n `[DingTalk][Finalize] Calling commitAICardBlocks \u2014 ` +\n `blockListLen=${blockListJson.length} contentLen=${content.length} ` +\n `source=${finalTextForFallback ? \"final.payload\" : controller.getFinalAnswerContent() ? \"timeline.answer\" : sawFinalDelivery ? \"timeline.fileOnly\" : \"fallbackDone\"} ` +\n `preview=\"${content.slice(0, 120)}\"`,\n );\n\n // Build statusLine for card template\n const statusLine = buildStatusLine();\n\n await commitAICardBlocks(card, {\n blockListJson,\n content,\n statusLine,\n quotedRef: ctx.replyQuotedRef,\n }, log);\n\n // Send deferred non-image attachments after card finalize\n // Use sessionWebhook for reply-session semantics; fallback to proactive if unavailable.\n if (pendingNonImageMedia.length > 0) {\n log?.debug?.(`[DingTalk][Card] Sending ${pendingNonImageMedia.length} deferred non-image attachments`);\n for (const { url, type } of pendingNonImageMedia) {\n try {\n const prepared = await prepareMediaInput(url, log, config.mediaUrlAllowlist);\n const actualMediaPath = prepared.path;\n\n // Prefer sessionWebhook for reply-session permission semantics\n if (ctx.sessionWebhook) {\n const sendResult = await sendMessage(config, ctx.to, \"\", {\n sessionWebhook: ctx.sessionWebhook,\n mediaPath: actualMediaPath,\n mediaType: type,\n log,\n accountId: ctx.accountId,\n storePath: ctx.storePath,\n });\n if (!sendResult.ok) {\n log?.warn?.(`[DingTalk][Card] Deferred media session send failed: ${sendResult.error || \"unknown\"}`);\n }\n } else {\n // Fallback: proactive send when no reply session available\n const result = await sendProactiveMedia(config, ctx.to, actualMediaPath, type, {\n log,\n accountId: ctx.accountId,\n });\n if (!result.ok) {\n log?.warn?.(`[DingTalk][Card] Deferred media proactive send failed: ${result.error || \"unknown\"}`);\n }\n }\n\n await prepared.cleanup?.();\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n log?.warn?.(`[DingTalk][Card] Failed to send deferred media: ${msg}`);\n }\n }\n pendingNonImageMedia = []; // Clear after sending\n }\n\n lifecycleState = \"sealed\";\n\n // In group chats, send a lightweight @mention via session webhook\n // so the sender gets a notification \u2014 card API doesn't support @mention.\n const cardAtSenderText = (ctx.config.cardAtSender || \"\").trim();\n if (!ctx.isDirect && ctx.senderId && ctx.sessionWebhook && cardAtSenderText) {\n try {\n await sendBySession(ctx.config, ctx.sessionWebhook, cardAtSenderText, {\n atUserId: ctx.senderId,\n log,\n });\n } catch (atErr: unknown) {\n const msg = atErr instanceof Error ? atErr.message : String(atErr);\n log?.debug?.(`[DingTalk] Post-card @mention send failed: ${msg}`);\n }\n }\n } catch (err: unknown) {\n log?.debug?.(`[DingTalk] AI Card finalization failed: ${(err as Error).message}`);\n const errObj = err as { response?: { data?: unknown } };\n if (errObj?.response?.data !== undefined) {\n log?.debug?.(formatDingTalkErrorPayloadLog(\"inbound.cardFinalize\", errObj.response.data));\n }\n if ((card.state as string) !== AICardStatus.FINISHED) {\n card.state = AICardStatus.FAILED;\n card.lastUpdated = Date.now();\n }\n } finally {\n lifecycleState = \"sealed\";\n if (card.accountId && card.conversationId) {\n clearRuns(ctx.taskMeta?.runIds);\n }\n }\n },\n\n async abort(_error: Error): Promise<void> {\n lifecycleState = \"sealed\";\n if (card.accountId && card.conversationId) {\n clearRuns(ctx.taskMeta?.runIds);\n }\n if (!isCardInTerminalState(card.state)) {\n controller.stop();\n await controller.waitForInFlight();\n try {\n // For V2 template, finalize via instances API\n const errorBlockListJson = JSON.stringify([{ type: 0, markdown: \"\u274C \u5904\u7406\u5931\u8D25\" }]);\n await commitAICardBlocks(card, {\n blockListJson: errorBlockListJson,\n content: \"\u274C \u5904\u7406\u5931\u8D25\",\n }, log);\n } catch (cardCloseErr: unknown) {\n log?.debug?.(`[DingTalk] Failed to finalize card after dispatch error: ${(cardCloseErr as Error).message}`);\n card.state = AICardStatus.FAILED;\n card.lastUpdated = Date.now();\n }\n }\n },\n\n getFinalText(): string | undefined {\n return finalTextForFallback\n || controller.getFinalAnswerContent()\n || (sawFinalDelivery ? EMPTY_FINAL_REPLY : undefined);\n },\n };\n}\n", "/**\n * Markdown / text reply strategy.\n *\n * DingTalk cannot edit prior messages in place, so markdown mode emits\n * incremental answer tails from dispatcher-delivered block/final payloads.\n * Reasoning display is intentionally unsupported on DingTalk markdown.\n */\n\nimport type { DeliverPayload, ReplyOptions, ReplyStrategy, ReplyStrategyContext } from \"./reply-strategy-types\";\nimport { sendMessage } from \"./send-service\";\n\nconst EMPTY_FINAL_FALLBACK_TEXT = \"\u2705 Done\";\n\nfunction renderQuotedSegment(text: string): string {\n return text\n .split(\"\\n\")\n .map((line) => line.length > 0 ? `> ${line}` : \">\")\n .join(\"\\n\");\n}\n\nfunction computeIncrementalSuffix(previous: string, next: string): string {\n const prev = previous || \"\";\n const current = next || \"\";\n if (!current.trim()) {\n return \"\";\n }\n if (!prev) {\n return current;\n }\n if (!current.startsWith(prev)) {\n return \"\";\n }\n const suffix = current.slice(prev.length);\n return suffix.trim() ? suffix : \"\";\n}\n\nfunction computeSharedPrefixTail(previous: string, next: string): string {\n const prev = previous || \"\";\n const current = next || \"\";\n if (!prev || !current.trim()) {\n return \"\";\n }\n const limit = Math.min(prev.length, current.length);\n let sharedPrefixLength = 0;\n while (sharedPrefixLength < limit && prev[sharedPrefixLength] === current[sharedPrefixLength]) {\n sharedPrefixLength += 1;\n }\n if (sharedPrefixLength === 0) {\n return \"\";\n }\n const suffix = current.slice(sharedPrefixLength);\n return suffix.trim() ? suffix : \"\";\n}\n\nexport function createMarkdownReplyStrategy(\n ctx: ReplyStrategyContext,\n): ReplyStrategy {\n let finalText: string | undefined;\n let activeAnswerText = \"\";\n let lastSentAnswerText = \"\";\n let sentVisibleContent = false;\n\n const sendMarkdownSegment = async (text: string): Promise<void> => {\n if (!text.trim()) {\n return;\n }\n const sendResult = await sendMessage(ctx.config, ctx.to, text, {\n sessionWebhook: ctx.sessionWebhook,\n atUserId: !ctx.isDirect ? ctx.senderId : null,\n log: ctx.log,\n accountId: ctx.accountId,\n storePath: ctx.storePath,\n conversationId: ctx.groupId,\n quotedRef: ctx.replyQuotedRef,\n });\n if (!sendResult.ok) {\n throw new Error(sendResult.error || \"Reply send failed\");\n }\n sentVisibleContent = true;\n };\n\n const emitAnswerSuffix = async (text: string | undefined): Promise<void> => {\n const current = typeof text === \"string\" ? text : \"\";\n if (current.length > 0) {\n activeAnswerText = current;\n finalText = current;\n }\n\n const suffix = computeIncrementalSuffix(lastSentAnswerText, current);\n if (suffix) {\n await sendMarkdownSegment(suffix);\n lastSentAnswerText = current;\n return;\n }\n\n if (current.trim() && lastSentAnswerText && !current.startsWith(lastSentAnswerText)) {\n const suffix = computeSharedPrefixTail(lastSentAnswerText, current);\n ctx.log?.warn?.(\n `[DingTalk][Markdown] answer prefix drift detected; falling back to shared-prefix tail ` +\n `prevLen=${lastSentAnswerText.length} currentLen=${current.length}`,\n );\n lastSentAnswerText = \"\";\n if (suffix) {\n await sendMarkdownSegment(suffix);\n lastSentAnswerText = current;\n return;\n }\n await sendMarkdownSegment(current);\n lastSentAnswerText = current;\n }\n };\n\n return {\n getReplyOptions(): ReplyOptions {\n return {\n disableBlockStreaming: ctx.disableBlockStreaming === true,\n };\n },\n\n async deliver(payload: DeliverPayload): Promise<void> {\n if (payload.mediaUrls.length > 0) {\n await ctx.deliverMedia(payload.mediaUrls, { audioAsVoice: payload.audioAsVoice });\n sentVisibleContent = true;\n }\n\n if (payload.kind === \"tool\") {\n const text = typeof payload.text === \"string\" ? payload.text : \"\";\n if (!text.trim()) {\n return;\n }\n await sendMarkdownSegment(renderQuotedSegment(text));\n return;\n }\n\n if (\n (payload.kind === \"block\" || payload.kind === \"final\")\n && typeof payload.text === \"string\"\n ) {\n await emitAnswerSuffix(payload.text);\n }\n },\n\n async finalize(): Promise<void> {\n if (sentVisibleContent) {\n return;\n }\n finalText = EMPTY_FINAL_FALLBACK_TEXT;\n activeAnswerText = EMPTY_FINAL_FALLBACK_TEXT;\n await sendMarkdownSegment(EMPTY_FINAL_FALLBACK_TEXT);\n },\n\n async abort(): Promise<void> {\n // Nothing to clean up.\n },\n\n getFinalText(): string | undefined {\n return finalText || activeAnswerText || undefined;\n },\n };\n}\n", "/**\n * Reply strategy factory for DingTalk message delivery.\n *\n * Delegates the \"how to deliver a reply\" concern to card or markdown\n * strategy implementations. Type definitions live in reply-strategy-types.ts.\n */\n\nimport type { AICardInstance } from \"./types\";\nimport type { ReplyStrategy, ReplyStrategyContext } from \"./reply-strategy-types\";\nimport { createCardReplyStrategy } from \"./reply-strategy-card\";\nimport { createMarkdownReplyStrategy } from \"./reply-strategy-markdown\";\n\n// Re-export all types so existing consumers that import from \"./reply-strategy\"\n// continue to work without changes beyond the ones we explicitly migrate.\nexport type {\n DeliverPayload,\n ReplyOptions,\n ReplyStrategy,\n ReplyStrategyContext,\n TaskMeta,\n} from \"./reply-strategy-types\";\n\n// ---- Factory -----------------------------------------------------\n\nexport function createReplyStrategy(\n params: ReplyStrategyContext & {\n card: AICardInstance | undefined;\n useCardMode: boolean;\n },\n): ReplyStrategy {\n if (params.useCardMode && params.card) {\n return createCardReplyStrategy({ ...params, card: params.card });\n }\n return createMarkdownReplyStrategy(params);\n}\n", "// Per-session mutex to serialize dispatchReply calls for the same session.\n// Prevents concurrent dispatch from producing empty replies when the runtime\n// cannot handle overlapping requests on the same session key.\n\nconst locks = new Map<string, Promise<void>>();\n\nexport const SESSION_LOCK_NAMESPACE_POLICY = \"memory-only\" as const;\n\n/**\n * Acquire a per-session lock. Returns a release function that MUST be called\n * (typically in a `finally` block) to unblock the next queued caller.\n *\n * Different session keys run in parallel; same key runs serially.\n */\nexport async function acquireSessionLock(sessionKey: string): Promise<() => void> {\n let release!: () => void;\n const gate = new Promise<void>((r) => {\n release = r;\n });\n const prev = locks.get(sessionKey) ?? Promise.resolve();\n locks.set(sessionKey, gate);\n await prev;\n return () => {\n if (locks.get(sessionKey) === gate) {\n locks.delete(sessionKey);\n }\n release();\n };\n}\n\n/** Visible for testing only. */\nexport function _getLocksMapForTest(): Map<string, Promise<void>> {\n return locks;\n}\n", "import { readNamespaceJson, writeNamespaceJsonAtomic } from \"./persistence-store\";\n\nconst SESSION_PEER_OVERRIDE_NAMESPACE = \"session-peer-overrides\";\n\nexport type SessionPeerSourceKind = \"direct\" | \"group\";\n\ninterface SessionPeerOverrideBucket {\n peers: Record<string, string>;\n}\n\nfunction buildSourceKey(sourceKind: SessionPeerSourceKind, sourceId: string): string {\n return `${sourceKind}:${sourceId}`;\n}\n\nfunction readBucket(storePath: string, accountId: string): SessionPeerOverrideBucket {\n return readNamespaceJson<SessionPeerOverrideBucket>(SESSION_PEER_OVERRIDE_NAMESPACE, {\n storePath,\n scope: { accountId },\n fallback: { peers: {} },\n });\n}\n\nfunction writeBucket(storePath: string, accountId: string, bucket: SessionPeerOverrideBucket): void {\n writeNamespaceJsonAtomic(SESSION_PEER_OVERRIDE_NAMESPACE, {\n storePath,\n scope: { accountId },\n data: bucket,\n });\n}\n\nexport function getSessionPeerOverride(params: {\n storePath: string;\n accountId: string;\n sourceKind: SessionPeerSourceKind;\n sourceId: string;\n}): string | undefined {\n const bucket = readBucket(params.storePath, params.accountId);\n const sourceKey = buildSourceKey(params.sourceKind, params.sourceId);\n const legacyKey = params.sourceKind === \"group\" ? params.sourceId : undefined;\n const value = bucket.peers[sourceKey] ?? (legacyKey ? bucket.peers[legacyKey] : undefined);\n return typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n}\n\nexport function setSessionPeerOverride(params: {\n storePath: string;\n accountId: string;\n sourceKind: SessionPeerSourceKind;\n sourceId: string;\n peerId: string;\n}): void {\n const bucket = readBucket(params.storePath, params.accountId);\n const sourceKey = buildSourceKey(params.sourceKind, params.sourceId);\n bucket.peers[sourceKey] = params.peerId.trim();\n writeBucket(params.storePath, params.accountId, bucket);\n}\n\nexport function clearSessionPeerOverride(params: {\n storePath: string;\n accountId: string;\n sourceKind: SessionPeerSourceKind;\n sourceId: string;\n}): boolean {\n const bucket = readBucket(params.storePath, params.accountId);\n const sourceKey = buildSourceKey(params.sourceKind, params.sourceId);\n const legacyKey = params.sourceKind === \"group\" ? params.sourceId : undefined;\n const existed = Object.prototype.hasOwnProperty.call(bucket.peers, sourceKey)\n || (legacyKey ? Object.prototype.hasOwnProperty.call(bucket.peers, legacyKey) : false);\n if (!existed) {\n return false;\n }\n delete bucket.peers[sourceKey];\n if (legacyKey) {\n delete bucket.peers[legacyKey];\n }\n writeBucket(params.storePath, params.accountId, bucket);\n return true;\n}\n", "import type { DingTalkConfig } from \"./types\";\n\nexport interface ResolveDingTalkSessionPeerParams {\n isDirect: boolean;\n senderId: string;\n conversationId: string;\n peerIdOverride?: string;\n config: DingTalkConfig;\n}\n\nexport interface ResolvedDingTalkSessionPeer {\n kind: \"direct\" | \"group\";\n peerId: string;\n}\n\n// Keep DingTalk aligned with Feishu's explicit peerId -> sessionKey model:\n// resolve a stable peer identity first, then let OpenClaw build the final session key.\nexport function resolveDingTalkSessionPeer(\n params: ResolveDingTalkSessionPeerParams,\n): ResolvedDingTalkSessionPeer {\n const normalizedPeerIdOverride = params.peerIdOverride?.trim();\n if (params.isDirect) {\n return {\n kind: \"direct\",\n peerId: normalizedPeerIdOverride || params.senderId,\n };\n }\n\n return {\n kind: \"group\",\n peerId: normalizedPeerIdOverride || params.conversationId,\n };\n}\n", "/**\n * Agent name matcher for @sub-agent feature\n *\n * Matches @mentions to agent IDs based on name and id fields in agents.list config.\n */\n\nimport type { OpenClawConfig } from \"openclaw/plugin-sdk/core\";\nimport type { AtMention, AgentNameMatch } from \"../types\";\n\ninterface AgentConfig {\n id: string;\n name?: string;\n default?: boolean;\n}\n\n/**\n * Normalize name for case-insensitive matching\n */\nfunction normalizeName(name: string): string {\n return name.trim().toLowerCase();\n}\n\n/**\n * Get main agent ID from agents.list\n */\nexport function getMainAgentId(agents: AgentConfig[] | undefined): string {\n if (!agents || agents.length === 0) {\n return \"main\";\n }\n\n const defaultAgent = agents.find((a) => a.default);\n if (defaultAgent) {\n return defaultAgent.id;\n }\n\n return agents[0].id;\n}\n\n/**\n * Match a single @name to an agent\n */\nfunction matchAtName(atName: string, agents: AgentConfig[]): AgentNameMatch | null {\n const normalizedAtName = normalizeName(atName);\n\n for (const agent of agents) {\n // 1. Match by name field\n if (agent.name && normalizeName(agent.name) === normalizedAtName) {\n return {\n agentId: agent.id,\n matchSource: \"name\",\n matchedName: agent.name,\n };\n }\n\n // 2. Match by id field\n if (normalizeName(agent.id) === normalizedAtName) {\n return {\n agentId: agent.id,\n matchSource: \"id\",\n matchedName: agent.id,\n };\n }\n }\n\n return null;\n}\n\n/**\n * Resolve @mentions to agent matches\n *\n * @param atMentions - List of @mentions extracted from message\n * @param cfg - OpenClaw configuration\n * @param atUserDingtalkIds - dingtalkIds from webhook atUsers field (real users selected via @picker)\n * @returns Matched agents, unmatched names, main agent ID, and whether there are invalid agent names\n *\n * @remarks\n * Exclusion logic for unmatched @mentions:\n * - If mention.userId is set (from richText), it's a real user \u2192 excluded from unmatchedNames\n * - In text mode, we cannot map dingtalkIds to specific @mention names\n * - To avoid false positives (reporting real user names as missing agents),\n * we use a conservative heuristic:\n * - If realUserCount > 0, hasInvalidAgentNames is always false\n * - This means we never report \"agent not found\" in text mode when there are real users\n * - In richText mode, mention.userId allows precise exclusion, so the heuristic is not needed\n */\nexport function resolveAtAgents(\n atMentions: AtMention[],\n cfg: OpenClawConfig,\n atUserDingtalkIds?: string[],\n): {\n matchedAgents: AgentNameMatch[];\n unmatchedNames: string[];\n mainAgentId: string;\n /** Count of @mentions that are likely real users (from atUserDingtalkIds) */\n realUserCount: number;\n /** Whether there are invalid agent names (conservative: false if realUserCount > 0) */\n hasInvalidAgentNames: boolean;\n} {\n const agents = cfg?.agents?.list as AgentConfig[] | undefined;\n const mainAgentId = getMainAgentId(agents);\n\n if (!atMentions || atMentions.length === 0) {\n return {\n matchedAgents: [],\n unmatchedNames: [],\n mainAgentId,\n realUserCount: 0,\n hasInvalidAgentNames: false,\n };\n }\n\n const matchedAgents: AgentNameMatch[] = [];\n const unmatchedNames: string[] = [];\n\n for (const mention of atMentions) {\n const match = agents ? matchAtName(mention.name, agents) : null;\n\n if (match) {\n // Avoid duplicate agents\n if (!matchedAgents.some((m) => m.agentId === match.agentId)) {\n matchedAgents.push(match);\n }\n } else {\n // Exclude @real users (those with userId are real users from richText)\n if (!mention.userId) {\n unmatchedNames.push(mention.name);\n }\n }\n }\n\n // Count real users from atUserDingtalkIds\n // These are real DingTalk users selected via @picker, but we don't know which names they correspond to\n const realUserCount = atUserDingtalkIds?.length || 0;\n\n // Conservative heuristic: if there are real users, never report invalid agent names\n // This avoids false positives where real user names are incorrectly reported as missing agents\n // In text mode, we cannot distinguish which @mentions correspond to real users\n // In richText mode, mention.userId provides precise exclusion, so this is just a safety net\n const hasInvalidAgentNames = realUserCount === 0 && unmatchedNames.length > 0;\n\n return {\n matchedAgents,\n unmatchedNames,\n mainAgentId,\n realUserCount,\n hasInvalidAgentNames,\n };\n}\n\n/**\n * Get agent display name for statusLine in card template.\n *\n * Priority:\n * 1. subAgentOptions.matchedName - user-friendly name from @mention (e.g., \"\u4EE3\u7801\u4E13\u5BB6\")\n * 2. agents.list lookup - name field from agent config\n * 3. agentId fallback - technical identifier\n */\nexport function getAgentDisplayName(params: {\n subAgentOptions?: { matchedName?: string };\n agentId: string;\n agentsList?: Array<{ id: string; name?: string }>;\n}): string {\n // Priority 1: sub-agent matchedName (user-friendly)\n if (params.subAgentOptions?.matchedName) {\n return params.subAgentOptions.matchedName;\n }\n // Priority 2: lookup from agents.list\n if (params.agentsList) {\n const agent = params.agentsList.find((a) => a.id === params.agentId);\n if (agent?.name) {\n return agent.name;\n }\n }\n // Priority 3: fallback to agentId\n return params.agentId;\n}\n", "/**\n * Sub-agent routing for @mention-based multi-agent support.\n *\n * Extracts @mentions from inbound messages and resolves them to agent IDs\n * using agents.list configuration. This is a plugin-layer routing mechanism\n * because the framework's resolveAgentRoute only supports static matching\n * (channel + accountId + peer), not content-based dynamic routing.\n */\n\nimport type { OpenClawConfig } from \"openclaw/plugin-sdk/core\";\nimport { maybeResolveTextAlias } from \"openclaw/plugin-sdk/command-auth\";\nimport { resolveAtAgents } from \"./agent-name-matcher\";\nimport { resolveRobotCode } from \"../config\";\nimport { parseLearnCommand } from \"../learning-command-service\";\nimport { getDingTalkRuntime } from \"../runtime\";\nimport { sendBySession } from \"../send-service\";\nimport { getErrorMessage } from \"../utils\";\nimport type { AgentNameMatch, DingTalkConfig, DingTalkInboundMessage, HandleDingTalkMessageParams, Logger, MessageContent } from \"../types\";\n\nexport class HostRoutingHelperUnavailableError extends Error {\n constructor(message = \"DingTalk sub-agent routing requires runtime.channel.routing.buildAgentSessionKey from the host runtime.\") {\n super(message);\n this.name = \"HostRoutingHelperUnavailableError\";\n }\n}\n\n/**\n * Build a session key for a specific agent using the runtime API.\n * On supported host versions, sub-agent routing must use the shared helper\n * instead of synthesizing plugin-local fallback keys.\n */\nexport function buildAgentSessionKey(params: {\n rt: ReturnType<typeof getDingTalkRuntime>;\n cfg: OpenClawConfig;\n accountId: string;\n agentId: string;\n peerKind: \"direct\" | \"group\";\n peerId: string;\n}): string {\n const { rt, cfg, accountId, agentId, peerKind, peerId } = params;\n const routing = rt.channel.routing as Record<string, unknown>;\n if (typeof routing.buildAgentSessionKey !== \"function\") {\n throw new HostRoutingHelperUnavailableError();\n }\n return (\n (routing.buildAgentSessionKey as (p: unknown) => string)({\n agentId,\n channel: \"dingtalk\",\n accountId,\n peer: { kind: peerKind, id: peerId },\n dmScope: cfg.session?.dmScope,\n identityLinks: cfg.session?.identityLinks,\n })\n ).toLowerCase();\n}\n\n/**\n * Sanitize agent name for safe use in markdown prefix and context hints.\n * Strips brackets, newlines, and control characters to prevent markdown\n * breakage and prompt injection.\n */\nfunction sanitizeAgentName(name: string): string {\n return name.replace(/[[\\]\\r\\n]/g, \"\").trim();\n}\n\n/**\n * Resolve @mention-based sub-agent routing for a group or direct message.\n *\n * In group chats, @mentions are populated by the DingTalk SDK (atMentions field).\n * In direct messages (DM), the SDK also populates atMentions for text-type messages\n * via extractMessageContent in message-utils.ts, so the same field is reused here.\n * The !isGroup guard is removed to enable sub-agent routing in DM as well.\n *\n * Returns matched agents if any @mentions resolve to configured agents,\n * or null if the message should be handled by the default agent.\n */\nexport async function resolveSubAgentRoute(params: {\n extractedContent: MessageContent;\n cfg: OpenClawConfig;\n isGroup: boolean;\n dingtalkConfig: DingTalkConfig;\n sessionWebhook: string;\n senderId: string;\n log?: Logger;\n}): Promise<{\n matchedAgents: AgentNameMatch[];\n preDownloadedMedia?: { mediaPath?: string; mediaType?: string };\n} | null> {\n const { extractedContent, cfg, isGroup, dingtalkConfig, sessionWebhook, senderId, log } = params;\n\n const atMentions = extractedContent.atMentions || [];\n // DM has no @picker list from DingTalk; only group chats provide atUsers for real-user hints.\n const atUserDingtalkIds = isGroup ? extractedContent.atUserDingtalkIds : undefined;\n // Strip quoted prefix before checking commands to avoid false positives\n // when the quoted message itself contains a command.\n const textForCommandCheck = extractedContent.text.replace(/^\\[\u5F15\u7528[^\\]]*\\]\\s*/, \"\");\n const isLearnCommand = parseLearnCommand(textForCommandCheck).scope !== \"unknown\";\n // Slash commands like /new, /stop, /reasoning etc. must bypass sub-agent\n // routing so they reach the framework's own command handling layer.\n // Strip leading @mention tokens first since DM text may look like \"@Agent /new\".\n const textWithoutMentions = textForCommandCheck.replace(/^(?:@\\S+\\s+)*/u, \"\").trim();\n const isSlashCommand = maybeResolveTextAlias(textWithoutMentions, cfg) !== null;\n\n if (\n atMentions.length === 0 ||\n !cfg.agents?.list ||\n cfg.agents.list.length === 0 ||\n isLearnCommand ||\n isSlashCommand\n ) {\n return null;\n }\n\n const { matchedAgents, unmatchedNames, realUserCount, hasInvalidAgentNames } = resolveAtAgents(\n atMentions,\n cfg,\n atUserDingtalkIds,\n );\n log?.info?.(\n `[DingTalk] Sub-agent resolve: matched=${matchedAgents.map((a) => a.agentId).join(\",\")} unmatched=${unmatchedNames.join(\",\")} realUsers=${realUserCount}`,\n );\n\n // Send fallback notice for unmatched agent names\n if (hasInvalidAgentNames) {\n const fallbackReason = `\u672A\u627E\u5230\u540D\u4E3A\"${unmatchedNames.join(\"\u3001\")}\"\u7684\u52A9\u624B`;\n try {\n const sendOptions = isGroup ? { atUserId: senderId, log } : { log };\n await sendBySession(dingtalkConfig, sessionWebhook, `\u26A0\uFE0F ${fallbackReason}`, {\n ...sendOptions,\n });\n } catch (err: unknown) {\n log?.debug?.(`[DingTalk] Failed to send fallback notice: ${getErrorMessage(err)}`);\n }\n }\n\n if (matchedAgents.length === 0) {\n return null;\n }\n\n return { matchedAgents };\n}\n\n/**\n * Process matched sub-agents by dispatching each to handleDingTalkMessage.\n */\nexport async function dispatchSubAgents(params: {\n matchedAgents: AgentNameMatch[];\n cfg: OpenClawConfig;\n accountId: string;\n data: DingTalkInboundMessage;\n dingtalkConfig: DingTalkConfig;\n sessionWebhook: string;\n extractedContent: MessageContent;\n handleMessage: (params: HandleDingTalkMessageParams) => Promise<void>;\n downloadMedia: (config: DingTalkConfig, mediaPath: string, log?: Logger) => Promise<{ path: string; mimeType: string } | null>;\n log?: Logger;\n}): Promise<void> {\n const { matchedAgents, cfg, accountId, data, dingtalkConfig, sessionWebhook, extractedContent, handleMessage, downloadMedia: download, log } = params;\n\n // Pre-download media once to avoid duplication across sub-agents\n let preDownloadedMedia: {\n mediaPath?: string;\n mediaType?: string;\n mediaPaths?: string[];\n mediaTypes?: string[];\n } | undefined;\n const robotCode = resolveRobotCode(dingtalkConfig);\n if (robotCode) {\n const downloadCodes =\n extractedContent.mediaPaths && extractedContent.mediaPaths.length > 0\n ? extractedContent.mediaPaths\n : extractedContent.mediaPath\n ? [extractedContent.mediaPath]\n : [];\n const mediaPaths: string[] = [];\n const mediaTypes: string[] = [];\n for (const downloadCode of downloadCodes) {\n const media = await download(dingtalkConfig, downloadCode, log);\n if (media) {\n mediaPaths.push(media.path);\n mediaTypes.push(media.mimeType);\n }\n }\n if (mediaPaths.length > 0) {\n preDownloadedMedia = {\n mediaPath: mediaPaths[0],\n mediaType: mediaTypes[0],\n mediaPaths,\n mediaTypes,\n };\n }\n }\n let helperMissingWarningSent = false;\n\n for (const agentMatch of matchedAgents) {\n try {\n await handleMessage({\n cfg,\n accountId,\n data,\n sessionWebhook,\n log,\n dingtalkConfig,\n subAgentOptions: {\n agentId: agentMatch.agentId,\n responsePrefix: `> \uD83E\uDD16 **${sanitizeAgentName(agentMatch.matchedName)}**:\\n\\n`,\n matchedName: agentMatch.matchedName,\n },\n preDownloadedMedia,\n });\n } catch (error) {\n const message = getErrorMessage(error);\n log?.error?.(\n `[DingTalk] Sub-agent ${agentMatch.agentId} failed: ${message}`,\n );\n if (error instanceof HostRoutingHelperUnavailableError && !helperMissingWarningSent) {\n helperMissingWarningSent = true;\n try {\n const isGroup = data.conversationType !== \"1\";\n const sendOptions = isGroup ? { atUserId: data.senderId, log } : { log };\n await sendBySession(\n dingtalkConfig,\n sessionWebhook,\n \"\u26A0\uFE0F \u5F53\u524D\u5BBF\u4E3B\u7248\u672C\u4E0D\u652F\u6301 DingTalk \u5B50\u52A9\u624B\u8DEF\u7531\u6240\u9700\u7684 session helper\uFF0C\u8BF7\u5347\u7EA7 OpenClaw \u540E\u91CD\u8BD5\u3002\",\n sendOptions,\n );\n } catch (notifyError: unknown) {\n log?.debug?.(\n `[DingTalk] Failed to send sub-agent helper-missing notice: ${getErrorMessage(notifyError)}`,\n );\n }\n }\n }\n }\n}\n", "import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { readNamespaceJson, writeNamespaceJsonAtomic } from \"../persistence-store\";\n\nconst GROUP_MEMBERS_NAMESPACE = \"members.group-roster\";\n\nfunction groupMembersFilePath(storePath: string, groupId: string): string {\n const dir = path.join(path.dirname(storePath), \"dingtalk-members\");\n const safeId = groupId.replace(/\\+/g, \"-\").replace(/\\//g, \"_\");\n return path.join(dir, `${safeId}.json`);\n}\n\nfunction readLegacyRoster(storePath: string, groupId: string): Record<string, string> | null {\n const filePath = groupMembersFilePath(storePath, groupId);\n try {\n return JSON.parse(fs.readFileSync(filePath, \"utf-8\")) as Record<string, string>;\n } catch {\n return null;\n }\n}\n\nfunction readRoster(storePath: string, groupId: string): Record<string, string> {\n const namespaced = readNamespaceJson<Record<string, string>>(GROUP_MEMBERS_NAMESPACE, {\n storePath,\n scope: { groupId },\n format: \"json\",\n fallback: {},\n });\n if (Object.keys(namespaced).length > 0) {\n return namespaced;\n }\n\n const legacy = readLegacyRoster(storePath, groupId);\n if (legacy && Object.keys(legacy).length > 0) {\n writeNamespaceJsonAtomic(GROUP_MEMBERS_NAMESPACE, {\n storePath,\n scope: { groupId },\n format: \"json\",\n data: legacy,\n });\n return legacy;\n }\n return {};\n}\n\nfunction writeRoster(storePath: string, groupId: string, roster: Record<string, string>): void {\n writeNamespaceJsonAtomic(GROUP_MEMBERS_NAMESPACE, {\n storePath,\n scope: { groupId },\n format: \"json\",\n data: roster,\n });\n}\n\nexport function noteGroupMember(\n storePath: string,\n groupId: string,\n userId: string,\n name: string,\n): void {\n if (!userId || !name) {\n return;\n }\n const roster = readRoster(storePath, groupId);\n if (roster[userId] === name) {\n return;\n }\n roster[userId] = name;\n writeRoster(storePath, groupId, roster);\n}\n\nexport function formatGroupMembers(storePath: string, groupId: string): string | undefined {\n const roster = readRoster(storePath, groupId);\n const entries = Object.entries(roster);\n if (entries.length === 0) {\n return undefined;\n }\n return entries.map(([id, name]) => `${name} (${id})`).join(\", \");\n}\n", "import { readNamespaceJson, writeNamespaceJsonAtomic } from \"../persistence-store\";\n\nconst TARGET_DIRECTORY_NAMESPACE = \"targets.directory\";\nconst MAX_HISTORICAL_NAMES = 20;\nconst MAX_RECENT_CONVERSATIONS = 20;\nconst LAST_SEEN_WRITE_THROTTLE_MS = 60 * 1000;\n\nexport interface GroupTargetEntry {\n conversationId: string;\n currentTitle: string;\n historicalTitles: string[];\n lastSeenAt: number;\n}\n\nexport interface UserTargetEntry {\n canonicalUserId: string;\n staffId?: string;\n senderId: string;\n currentDisplayName: string;\n historicalDisplayNames: string[];\n lastSeenAt: number;\n lastSeenInConversationIds: string[];\n}\n\ninterface TargetDirectoryState {\n version: 1;\n groups: Record<string, GroupTargetEntry>;\n users: Record<string, UserTargetEntry>;\n}\n\nconst inMemoryFallbackState = new Map<string, TargetDirectoryState>();\nconst persistedStateCache = new Map<string, TargetDirectoryState>();\n\nfunction fallbackState(): TargetDirectoryState {\n return {\n version: 1,\n groups: {},\n users: {},\n };\n}\n\nfunction trimValue(value: string | undefined): string {\n return String(value || \"\").trim();\n}\n\nfunction normalizeLookup(value: string | undefined): string {\n return trimValue(value).replace(/\\s+/g, \" \").toLowerCase();\n}\n\nfunction normalizeScopeKey(storePath: string | undefined, accountId: string): string {\n return JSON.stringify([storePath || \"__memory__\", accountId]);\n}\n\nfunction readState(params: { storePath?: string; accountId: string }): TargetDirectoryState {\n const scopeKey = normalizeScopeKey(params.storePath, params.accountId);\n if (!params.storePath) {\n return inMemoryFallbackState.get(scopeKey) || fallbackState();\n }\n const cached = persistedStateCache.get(scopeKey);\n if (cached) {\n return cached;\n }\n const state = readNamespaceJson<TargetDirectoryState>(TARGET_DIRECTORY_NAMESPACE, {\n storePath: params.storePath,\n scope: { accountId: params.accountId },\n fallback: fallbackState(),\n });\n persistedStateCache.set(scopeKey, state);\n return state;\n}\n\nfunction writeState(params: {\n storePath?: string;\n accountId: string;\n state: TargetDirectoryState;\n}): void {\n const scopeKey = normalizeScopeKey(params.storePath, params.accountId);\n if (!params.storePath) {\n inMemoryFallbackState.set(scopeKey, params.state);\n return;\n }\n persistedStateCache.set(scopeKey, params.state);\n writeNamespaceJsonAtomic(TARGET_DIRECTORY_NAMESPACE, {\n storePath: params.storePath,\n scope: { accountId: params.accountId },\n data: params.state,\n });\n}\n\nexport function clearTargetDirectoryStateCache(): void {\n inMemoryFallbackState.clear();\n persistedStateCache.clear();\n}\n\nfunction appendUniqueText(list: string[], value: string, maxSize: number): string[] {\n const normalized = normalizeLookup(value);\n if (!normalized) {\n return list;\n }\n const existingIndex = list.findIndex((item) => normalizeLookup(item) === normalized);\n if (existingIndex >= 0) {\n return list;\n }\n const nextList = [...list, value.trim()];\n return nextList.length > maxSize ? nextList.slice(nextList.length - maxSize) : nextList;\n}\n\nfunction appendUniqueRecentConversation(list: string[], value: string, maxSize: number): string[] {\n const normalized = normalizeLookup(value);\n if (!normalized) {\n return list;\n }\n const exists = list.some((item) => normalizeLookup(item) === normalized);\n if (exists) {\n return list;\n }\n const nextList = [...list, value.trim()];\n return nextList.length > maxSize ? nextList.slice(nextList.length - maxSize) : nextList;\n}\n\nfunction shouldRefreshLastSeen(\n existingLastSeen: number | undefined,\n nextLastSeen: number,\n): boolean {\n const previous = Number.isFinite(existingLastSeen) ? Number(existingLastSeen) : 0;\n if (previous <= 0) {\n return true;\n }\n if (nextLastSeen <= previous) {\n return false;\n }\n return nextLastSeen - previous >= LAST_SEEN_WRITE_THROTTLE_MS;\n}\n\nfunction findUserKeyByIdentifiers(\n state: TargetDirectoryState,\n params: { canonicalUserId?: string; staffId?: string; senderId?: string },\n): string | undefined {\n const canonical = normalizeLookup(params.canonicalUserId);\n if (canonical && state.users[params.canonicalUserId || \"\"]) {\n return params.canonicalUserId;\n }\n\n const staffNorm = normalizeLookup(params.staffId);\n const senderNorm = normalizeLookup(params.senderId);\n for (const [key, entry] of Object.entries(state.users)) {\n if (canonical && normalizeLookup(key) === canonical) {\n return key;\n }\n if (staffNorm && normalizeLookup(entry.staffId) === staffNorm) {\n return key;\n }\n if (senderNorm && normalizeLookup(entry.senderId) === senderNorm) {\n return key;\n }\n }\n return undefined;\n}\n\nexport function upsertObservedGroupTarget(params: {\n storePath?: string;\n accountId: string;\n conversationId: string;\n title?: string;\n seenAt?: number;\n}): void {\n const conversationId = trimValue(params.conversationId);\n if (!conversationId) {\n return;\n }\n const nowMs = params.seenAt && Number.isFinite(params.seenAt) ? params.seenAt : Date.now();\n const title = trimValue(params.title) || conversationId;\n const state = readState({ storePath: params.storePath, accountId: params.accountId });\n const existingEntry = state.groups[conversationId];\n\n if (!existingEntry) {\n const nextState: TargetDirectoryState = {\n ...state,\n groups: {\n ...state.groups,\n [conversationId]: {\n conversationId,\n currentTitle: title,\n historicalTitles: [],\n lastSeenAt: nowMs,\n },\n },\n };\n writeState({ storePath: params.storePath, accountId: params.accountId, state: nextState });\n return;\n }\n\n const titleChanged = normalizeLookup(existingEntry.currentTitle) !== normalizeLookup(title);\n const nextHistoricalTitles = titleChanged\n ? appendUniqueText(\n existingEntry.historicalTitles,\n existingEntry.currentTitle,\n MAX_HISTORICAL_NAMES,\n )\n : existingEntry.historicalTitles;\n const nextLastSeenCandidate = Math.max(existingEntry.lastSeenAt || 0, nowMs);\n const nextLastSeenAt =\n titleChanged || nextHistoricalTitles !== existingEntry.historicalTitles\n ? nextLastSeenCandidate\n : shouldRefreshLastSeen(existingEntry.lastSeenAt, nextLastSeenCandidate)\n ? nextLastSeenCandidate\n : existingEntry.lastSeenAt;\n\n if (\n !titleChanged &&\n nextHistoricalTitles === existingEntry.historicalTitles &&\n nextLastSeenAt === existingEntry.lastSeenAt\n ) {\n return;\n }\n\n const nextEntry: GroupTargetEntry = {\n conversationId,\n currentTitle: titleChanged ? title : existingEntry.currentTitle,\n historicalTitles: nextHistoricalTitles,\n lastSeenAt: nextLastSeenAt,\n };\n const nextState: TargetDirectoryState = {\n ...state,\n groups: {\n ...state.groups,\n [conversationId]: nextEntry,\n },\n };\n writeState({ storePath: params.storePath, accountId: params.accountId, state: nextState });\n}\n\nexport function upsertObservedUserTarget(params: {\n storePath?: string;\n accountId: string;\n senderId: string;\n staffId?: string;\n displayName?: string;\n conversationId?: string;\n seenAt?: number;\n}): void {\n const senderId = trimValue(params.senderId);\n if (!senderId) {\n return;\n }\n const staffId = trimValue(params.staffId);\n const canonicalUserId = staffId || senderId;\n const nowMs = params.seenAt && Number.isFinite(params.seenAt) ? params.seenAt : Date.now();\n const displayName = trimValue(params.displayName) || canonicalUserId;\n const conversationId = trimValue(params.conversationId);\n\n const state = readState({ storePath: params.storePath, accountId: params.accountId });\n const existingKey = findUserKeyByIdentifiers(state, {\n canonicalUserId,\n staffId,\n senderId,\n });\n const existingEntry = existingKey ? state.users[existingKey] : undefined;\n\n if (!existingEntry) {\n const nextState: TargetDirectoryState = {\n ...state,\n users: {\n ...state.users,\n [canonicalUserId]: {\n canonicalUserId,\n staffId: staffId || undefined,\n senderId,\n currentDisplayName: displayName,\n historicalDisplayNames: [],\n lastSeenAt: nowMs,\n lastSeenInConversationIds: conversationId ? [conversationId] : [],\n },\n },\n };\n writeState({ storePath: params.storePath, accountId: params.accountId, state: nextState });\n return;\n }\n\n const displayNameChanged =\n normalizeLookup(existingEntry.currentDisplayName) !== normalizeLookup(displayName);\n const nextHistoricalDisplayNames = displayNameChanged\n ? appendUniqueText(\n existingEntry.historicalDisplayNames,\n existingEntry.currentDisplayName,\n MAX_HISTORICAL_NAMES,\n )\n : existingEntry.historicalDisplayNames;\n const nextConversationIds = conversationId\n ? appendUniqueRecentConversation(\n existingEntry.lastSeenInConversationIds,\n conversationId,\n MAX_RECENT_CONVERSATIONS,\n )\n : existingEntry.lastSeenInConversationIds;\n const normalizedStaffId = staffId || undefined;\n const staffIdChanged = existingEntry.staffId !== normalizedStaffId;\n const senderIdChanged = existingEntry.senderId !== senderId;\n const canonicalUserIdChanged =\n existingEntry.canonicalUserId !== canonicalUserId || existingKey !== canonicalUserId;\n const metadataChanged =\n displayNameChanged ||\n nextHistoricalDisplayNames !== existingEntry.historicalDisplayNames ||\n nextConversationIds !== existingEntry.lastSeenInConversationIds ||\n staffIdChanged ||\n senderIdChanged ||\n canonicalUserIdChanged;\n const nextLastSeenCandidate = Math.max(existingEntry.lastSeenAt || 0, nowMs);\n const nextLastSeenAt = metadataChanged\n ? nextLastSeenCandidate\n : shouldRefreshLastSeen(existingEntry.lastSeenAt, nextLastSeenCandidate)\n ? nextLastSeenCandidate\n : existingEntry.lastSeenAt;\n\n if (!metadataChanged && nextLastSeenAt === existingEntry.lastSeenAt) {\n return;\n }\n\n const nextEntry: UserTargetEntry = {\n canonicalUserId,\n staffId: normalizedStaffId,\n senderId,\n currentDisplayName: displayNameChanged ? displayName : existingEntry.currentDisplayName,\n historicalDisplayNames: nextHistoricalDisplayNames,\n lastSeenAt: nextLastSeenAt,\n lastSeenInConversationIds: nextConversationIds,\n };\n\n const nextUsers =\n existingKey && existingKey !== canonicalUserId\n ? Object.fromEntries(Object.entries(state.users).filter(([key]) => key !== existingKey))\n : { ...state.users };\n nextUsers[canonicalUserId] = nextEntry;\n\n const nextState: TargetDirectoryState = {\n ...state,\n users: nextUsers,\n };\n writeState({ storePath: params.storePath, accountId: params.accountId, state: nextState });\n}\n\nfunction matchesGroupQuery(entry: GroupTargetEntry, query: string): boolean {\n const normalizedQuery = normalizeLookup(query);\n if (!normalizedQuery) {\n return true;\n }\n const candidates = [entry.conversationId, entry.currentTitle, ...entry.historicalTitles];\n return candidates.some((value) => normalizeLookup(value) === normalizedQuery);\n}\n\nfunction matchesUserQuery(entry: UserTargetEntry, query: string): boolean {\n const normalizedQuery = normalizeLookup(query);\n if (!normalizedQuery) {\n return true;\n }\n const candidates = [\n entry.canonicalUserId,\n entry.staffId || \"\",\n entry.senderId,\n entry.currentDisplayName,\n ...entry.historicalDisplayNames,\n ];\n return candidates.some((value) => normalizeLookup(value) === normalizedQuery);\n}\n\nexport function listKnownGroupTargets(params: {\n storePath?: string;\n accountId: string;\n query?: string;\n limit?: number;\n}): GroupTargetEntry[] {\n const state = readState({ storePath: params.storePath, accountId: params.accountId });\n const entries = Object.values(state.groups)\n .filter((entry) => matchesGroupQuery(entry, params.query || \"\"))\n .toSorted((a, b) => b.lastSeenAt - a.lastSeenAt);\n if (params.limit && params.limit > 0) {\n return entries.slice(0, params.limit);\n }\n return entries;\n}\n\nexport function listKnownUserTargets(params: {\n storePath?: string;\n accountId: string;\n query?: string;\n limit?: number;\n}): UserTargetEntry[] {\n const state = readState({ storePath: params.storePath, accountId: params.accountId });\n const entries = Object.values(state.users)\n .filter((entry) => matchesUserQuery(entry, params.query || \"\"))\n .toSorted((a, b) => b.lastSeenAt - a.lastSeenAt);\n if (params.limit && params.limit > 0) {\n return entries.slice(0, params.limit);\n }\n return entries;\n}\n", "import type {\n ChannelSetupAdapter,\n ChannelSetupInput,\n ChannelSetupWizard,\n OpenClawConfig,\n WizardPrompter,\n} from \"openclaw/plugin-sdk/setup\";\nimport { DEFAULT_ACCOUNT_ID, formatDocsLink, normalizeAccountId } from \"openclaw/plugin-sdk/setup\";\nimport { listDingTalkAccountIds, resolveDingTalkAccount } from \"./config.js\";\nimport {\n beginDeviceRegistration,\n RegistrationError,\n} from \"./device-registration.js\";\nimport {\n hasConfiguredSecretInput,\n normalizeSecretInputString,\n parseSecretInputString,\n} from \"./secret-input.js\";\nimport type { DingTalkConfig, DingTalkChannelConfig } from \"./types.js\";\n\nconst channel = \"dingtalk\" as const;\n\nfunction isConfigured(account: DingTalkConfig): boolean {\n return Boolean(account.clientId && hasConfiguredSecretInput(account.clientSecret));\n}\n\nfunction applyAccountNameToChannelSection(params: {\n cfg: OpenClawConfig;\n channelKey: string;\n accountId: string;\n name?: string;\n}): OpenClawConfig {\n const { cfg, channelKey, name } = params;\n if (!name) {\n return cfg;\n }\n const base = cfg.channels?.[channelKey] as DingTalkChannelConfig | undefined;\n return {\n ...cfg,\n channels: {\n ...cfg.channels,\n [channelKey]: { ...base, name },\n },\n };\n}\n\nasync function promptDingTalkAccountId(options: {\n cfg: OpenClawConfig;\n prompter: WizardPrompter;\n label: string;\n currentId: string;\n listAccountIds: (cfg: OpenClawConfig) => string[];\n defaultAccountId: string;\n}): Promise<string> {\n const existingIds = options.listAccountIds(options.cfg);\n const hasDefault = existingIds.includes(options.defaultAccountId);\n const namedIds = existingIds.filter((id) => id !== options.defaultAccountId);\n const action = await options.prompter.select({\n message: `Choose ${options.label} account`,\n options: [\n {\n label: hasDefault ? \"Configure default account\" : \"Add default account\",\n value: \"default\",\n },\n ...(namedIds.length > 0\n ? [{ label: \"Modify existing named account\", value: \"existing\" }]\n : []),\n { label: \"Add named account\", value: \"new\" },\n ],\n initialValue: hasDefault ? \"default\" : namedIds.length > 0 ? \"existing\" : \"default\",\n });\n\n if (action === \"default\") {\n return options.defaultAccountId;\n }\n\n if (action === \"existing\") {\n const selected = await options.prompter.select({\n message: `Select existing ${options.label} account`,\n options: namedIds.map((accountId) => ({\n label: accountId,\n value: accountId,\n })),\n initialValue: namedIds[0],\n });\n return normalizeAccountId(String(selected));\n }\n\n while (true) {\n const raw = await options.prompter.text({\n message: `New ${options.label} account ID`,\n placeholder: \"work\",\n initialValue: \"\",\n });\n const normalized = normalizeAccountId(String(raw));\n if (!normalized || normalized === options.defaultAccountId) {\n await options.prompter.note(\n \"Enter a non-default account ID, for example: work\",\n \"DingTalk account\",\n );\n continue;\n }\n if (existingIds.includes(normalized)) {\n await options.prompter.note(\n `Account \"${normalized}\" already exists. Choose Modify existing named account to edit it.`,\n \"DingTalk account\",\n );\n continue;\n }\n return normalized;\n }\n}\n\nasync function noteDingTalkHelp(prompter: WizardPrompter): Promise<void> {\n await prompter.note(\n [\n \"You need DingTalk application credentials.\",\n \"1. Visit https://open-dev.dingtalk.com/\",\n \"2. Create an enterprise internal application\",\n \"3. Enable 'Robot' capability\",\n \"4. Configure message receiving mode as 'Stream mode'\",\n \"5. Copy Client ID (AppKey) and Client Secret (AppSecret)\",\n `Docs: ${formatDocsLink(\"https://github.com/soimy/openclaw-channel-dingtalk\", \"plugin docs\")}`,\n ].join(\"\\n\"),\n \"DingTalk setup\",\n );\n}\n\nasync function noteDmAllowlistGuidance(prompter: WizardPrompter): Promise<void> {\n await prompter.note(\n [\n \"DM allowlist requires DingTalk userId values.\",\n \"Ask each target user to send a direct message to this bot.\",\n \"The plugin will show the observed userId so an admin can add it to channels.dingtalk.allowFrom.\",\n ].join(\"\\n\"),\n \"DingTalk DM allowlist\",\n );\n}\n\nasync function noteGroupAllowlistGuidance(prompter: WizardPrompter): Promise<void> {\n await prompter.note(\n [\n \"Group allowlist requires DingTalk conversationId values.\",\n \"Ask a member to @mention this bot in the target group.\",\n \"The plugin will show the observed group ID so an admin can configure channels.dingtalk.groups or related allowlist settings.\",\n ].join(\"\\n\"),\n \"DingTalk group allowlist\",\n );\n}\n\nasync function noteDingTalkSetupComplete(prompter: WizardPrompter): Promise<void> {\n await prompter.note(\n [\n \"DingTalk configuration has been saved.\",\n \"For named accounts, configuration lives under channels.dingtalk.accounts.\",\n \"If you selected allowlist policies, ask the target user or group to message this bot first; the plugin will show IDs that an admin can add manually.\",\n \"Advanced runtime settings can be edited in the config UI or openclaw.json.\",\n \"Restart the gateway to apply changes:\",\n \" openclaw gateway restart\",\n ].join(\"\\n\"),\n \"DingTalk setup complete\",\n );\n}\n\nfunction validateMinInteger(min: number) {\n return (value: string): string | undefined => {\n const raw = String(value ?? \"\").trim();\n const num = Number(raw);\n if (!raw) {\n return \"Required\";\n }\n if (!Number.isInteger(num) || num < min) {\n return `Must be an integer >= ${min}`;\n }\n return undefined;\n };\n}\n\ntype CardAdvancedConfig = Partial<\n Pick<\n DingTalkConfig,\n \"cardStreamingMode\" | \"cardStreamInterval\" | \"cardAtSender\" | \"cardStatusLine\"\n >\n>;\n\nasync function promptCardAdvancedConfig(params: {\n resolved: DingTalkConfig;\n prompter: WizardPrompter;\n}): Promise<CardAdvancedConfig> {\n const { resolved, prompter } = params;\n const cardStreamingMode = (await prompter.select({\n message: \"Card streaming mode\",\n options: [\n { label: \"Off - answer does not stream incrementally\", value: \"off\" },\n { label: \"Answer - only answer streams incrementally\", value: \"answer\" },\n { label: \"All - answer and thinking stream incrementally\", value: \"all\" },\n ],\n initialValue: resolved.cardStreamingMode ?? (resolved.cardRealTimeStream ? \"all\" : \"off\"),\n })) as DingTalkConfig[\"cardStreamingMode\"];\n\n const cardStreamInterval = Number(\n String(\n await prompter.text({\n message: \"Card stream interval (ms)\",\n placeholder: \"1000\",\n initialValue: String(resolved.cardStreamInterval ?? 1000),\n validate: validateMinInteger(200),\n }),\n ).trim(),\n );\n\n const cardAtSenderRaw = String(\n await prompter.text({\n message: \"Card completion @mention text (optional)\",\n placeholder: \"Reply complete\",\n initialValue: resolved.cardAtSender || undefined,\n }),\n ).trim();\n\n const wantsStatusLine = await prompter.confirm({\n message: \"Customize AI card status line?\",\n initialValue: Boolean(resolved.cardStatusLine),\n });\n\n let cardStatusLine: DingTalkConfig[\"cardStatusLine\"] | undefined;\n if (wantsStatusLine) {\n const current = resolved.cardStatusLine ?? {};\n cardStatusLine = {\n model: await prompter.confirm({\n message: \"Show model name?\",\n initialValue: current.model ?? true,\n }),\n effort: await prompter.confirm({\n message: \"Show thinking effort?\",\n initialValue: current.effort ?? true,\n }),\n agent: await prompter.confirm({\n message: \"Show agent name?\",\n initialValue: current.agent ?? true,\n }),\n taskTime: await prompter.confirm({\n message: \"Show task elapsed time?\",\n initialValue: current.taskTime ?? false,\n }),\n tokens: await prompter.confirm({\n message: \"Show token usage?\",\n initialValue: current.tokens ?? false,\n }),\n dapiUsage: await prompter.confirm({\n message: \"Show DingTalk API usage?\",\n initialValue: current.dapiUsage ?? false,\n }),\n };\n }\n\n return {\n cardStreamingMode,\n cardStreamInterval,\n ...(cardAtSenderRaw ? { cardAtSender: cardAtSenderRaw } : {}),\n ...(cardStatusLine ? { cardStatusLine } : {}),\n };\n}\n\nfunction applyAccountConfig(params: {\n cfg: OpenClawConfig;\n accountId: string;\n input: Partial<DingTalkConfig>;\n}): OpenClawConfig {\n const { cfg, accountId, input } = params;\n const useDefault = accountId === DEFAULT_ACCOUNT_ID;\n\n const namedConfig = applyAccountNameToChannelSection({\n cfg,\n channelKey: \"dingtalk\",\n accountId,\n name: input.name,\n });\n const base = namedConfig.channels?.dingtalk as DingTalkChannelConfig | undefined;\n\n const payload: Partial<DingTalkConfig> = {\n ...(input.clientId ? { clientId: input.clientId } : {}),\n ...(input.clientSecret ? { clientSecret: input.clientSecret } : {}),\n ...(input.dmPolicy ? { dmPolicy: input.dmPolicy } : {}),\n ...(input.groupPolicy ? { groupPolicy: input.groupPolicy } : {}),\n ...(input.allowFrom && input.allowFrom.length > 0 ? { allowFrom: input.allowFrom } : {}),\n ...(input.groupAllowFrom && input.groupAllowFrom.length > 0\n ? { groupAllowFrom: input.groupAllowFrom }\n : {}),\n ...(input.displayNameResolution ? { displayNameResolution: input.displayNameResolution } : {}),\n ...(input.contextVisibility ? { contextVisibility: input.contextVisibility } : {}),\n ...(input.mediaUrlAllowlist && input.mediaUrlAllowlist.length > 0\n ? { mediaUrlAllowlist: input.mediaUrlAllowlist }\n : {}),\n ...(input.messageType ? { messageType: input.messageType } : {}),\n ...(input.cardStreamingMode ? { cardStreamingMode: input.cardStreamingMode } : {}),\n ...(typeof input.cardStreamInterval === \"number\"\n ? { cardStreamInterval: input.cardStreamInterval }\n : {}),\n ...(input.cardAtSender ? { cardAtSender: input.cardAtSender } : {}),\n ...(input.cardStatusLine ? { cardStatusLine: input.cardStatusLine } : {}),\n ...(typeof input.maxReconnectCycles === \"number\"\n ? { maxReconnectCycles: input.maxReconnectCycles }\n : {}),\n ...(typeof input.useConnectionManager === \"boolean\"\n ? { useConnectionManager: input.useConnectionManager }\n : {}),\n ...(typeof input.mediaMaxMb === \"number\" ? { mediaMaxMb: input.mediaMaxMb } : {}),\n ...(typeof input.journalTTLDays === \"number\" ? { journalTTLDays: input.journalTTLDays } : {}),\n };\n\n if (useDefault) {\n return {\n ...namedConfig,\n channels: {\n ...namedConfig.channels,\n dingtalk: {\n ...base,\n enabled: true,\n ...payload,\n },\n },\n };\n }\n\n const accounts = (base as { accounts?: Record<string, unknown> }).accounts ?? {};\n const existingAccount =\n (base as { accounts?: Record<string, Record<string, unknown>> }).accounts?.[accountId] ?? {};\n\n return {\n ...namedConfig,\n channels: {\n ...namedConfig.channels,\n dingtalk: {\n ...base,\n enabled: base?.enabled ?? true,\n accounts: {\n ...accounts,\n [accountId]: {\n ...existingAccount,\n enabled: true,\n ...payload,\n },\n },\n },\n },\n };\n}\n\nfunction applyGenericSetupInput(params: {\n cfg: OpenClawConfig;\n accountId: string;\n input: ChannelSetupInput;\n}): OpenClawConfig {\n return applyAccountConfig({\n cfg: params.cfg,\n accountId: params.accountId,\n input: {\n name: params.input.name,\n clientId: typeof params.input.token === \"string\" ? params.input.token.trim() : undefined,\n clientSecret:\n typeof params.input.password === \"string\"\n ? parseSecretInputString(params.input.password)\n : undefined,\n },\n });\n}\n\nasync function configureDingTalkAccount(params: {\n cfg: OpenClawConfig;\n accountId: string;\n prompter: WizardPrompter;\n}): Promise<OpenClawConfig> {\n const { cfg, accountId, prompter } = params;\n const resolved = resolveDingTalkAccount(cfg, accountId);\n\n // \u2500\u2500 Credential acquisition: auto-register or manual \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const hasExistingCredentials = Boolean(\n resolved.clientId && hasConfiguredSecretInput(resolved.clientSecret),\n );\n const credentialMethod = await prompter.select({\n message: \"How do you want to get DingTalk bot credentials?\",\n options: [\n { label: \"Auto-register an OpenClaw DingTalk bot\", value: \"auto\" },\n { label: \"Enter an existing DingTalk bot Client ID / Client Secret\", value: \"manual\" },\n ],\n initialValue: hasExistingCredentials ? \"manual\" : \"auto\",\n });\n\n let clientId: string;\n let clientSecret: string;\n\n if (credentialMethod === \"auto\") {\n try {\n const session = await beginDeviceRegistration();\n\n await prompter.note(\n [\n \"Open this authorization page in your browser:\",\n session.verificationUrl,\n \"\",\n \"Scan the authorization code in DingTalk to finish registration.\",\n ].join(\"\\n\"),\n \"DingTalk bot auto-registration\",\n );\n\n let lastWaitingNote = 0;\n const result = await session.waitForResult({\n onWaiting: () => {\n const now = Date.now();\n if (now - lastWaitingNote >= 15_000) {\n lastWaitingNote = now;\n prompter\n .note(\"Waiting for authorization. Please finish the scan in DingTalk...\", \"Polling\")\n .catch(() => {});\n }\n },\n });\n clientId = result.clientId;\n clientSecret = result.clientSecret;\n\n await prompter.note(\n [\n \"Registration succeeded!\",\n `Client ID: ${clientId}`,\n \"Client Secret: [captured; see config file]\",\n ].join(\"\\n\"),\n \"Registration complete\",\n );\n } catch (err) {\n const message = err instanceof RegistrationError ? err.message : String(err);\n await prompter.note(\n [`Auto-registration failed: ${message}`, \"\", \"Falling back to manual input.\"].join(\"\\n\"),\n \"Registration failed\",\n );\n // Fall through to manual path\n await noteDingTalkHelp(prompter);\n clientId = String(\n await prompter.text({\n message: \"Client ID (AppKey)\",\n placeholder: \"dingxxxxxxxx\",\n initialValue: resolved.clientId ?? undefined,\n validate: (value: string) => (String(value ?? \"\").trim() ? undefined : \"Required\"),\n }),\n ).trim();\n clientSecret = String(\n await prompter.text({\n message: \"Client Secret (AppSecret)\",\n placeholder: \"xxx-xxx-xxx-xxx\",\n initialValue: normalizeSecretInputString(resolved.clientSecret),\n validate: (value: string) => (String(value ?? \"\").trim() ? undefined : \"Required\"),\n }),\n ).trim();\n }\n } else {\n // Manual path \u2014 existing behavior\n await noteDingTalkHelp(prompter);\n clientId = String(\n await prompter.text({\n message: \"Client ID (AppKey)\",\n placeholder: \"dingxxxxxxxx\",\n initialValue: resolved.clientId ?? undefined,\n validate: (value: string) => (String(value ?? \"\").trim() ? undefined : \"Required\"),\n }),\n ).trim();\n clientSecret = String(\n await prompter.text({\n message: \"Client Secret (AppSecret)\",\n placeholder: \"xxx-xxx-xxx-xxx\",\n initialValue: normalizeSecretInputString(resolved.clientSecret),\n validate: (value: string) => (String(value ?? \"\").trim() ? undefined : \"Required\"),\n }),\n ).trim();\n }\n\n const dmPolicyValue = (await prompter.select({\n message: \"Direct message policy\",\n options: [\n { label: \"Open - anyone can DM\", value: \"open\" },\n { label: \"Pairing - require OpenClaw pairing approval\", value: \"pairing\" },\n { label: \"Allowlist - only manually allowed users\", value: \"allowlist\" },\n ],\n initialValue: resolved.dmPolicy ?? \"open\",\n })) as \"open\" | \"pairing\" | \"allowlist\";\n\n if (dmPolicyValue === \"allowlist\") {\n await noteDmAllowlistGuidance(prompter);\n }\n\n const groupPolicyValue = (await prompter.select({\n message: \"Group message policy\",\n options: [\n { label: \"Open - any group can use bot\", value: \"open\" },\n { label: \"Allowlist - only manually configured groups\", value: \"allowlist\" },\n { label: \"Disabled - block all group messages\", value: \"disabled\" },\n ],\n initialValue: resolved.groupPolicy ?? \"open\",\n })) as \"open\" | \"allowlist\" | \"disabled\";\n\n if (groupPolicyValue === \"allowlist\") {\n await noteGroupAllowlistGuidance(prompter);\n }\n\n const messageType = (await prompter.select({\n message: \"Reply message type\",\n options: [\n { label: \"Markdown - standard DingTalk messages\", value: \"markdown\" },\n { label: \"AI Card - interactive card replies\", value: \"card\" },\n ],\n initialValue: resolved.messageType ?? \"markdown\",\n })) as \"markdown\" | \"card\";\n\n const wantsAdvanced = await prompter.confirm({\n message: \"Configure advanced DingTalk options?\",\n initialValue: false,\n });\n let cardAdvanced: CardAdvancedConfig = {};\n if (wantsAdvanced && messageType === \"card\") {\n cardAdvanced = await promptCardAdvancedConfig({ resolved, prompter });\n } else if (wantsAdvanced) {\n await prompter.note(\n \"No markdown-specific advanced onboarding options are required. Other advanced settings can be edited in the config UI or openclaw.json.\",\n \"DingTalk advanced options\",\n );\n }\n\n const nextCfg = applyAccountConfig({\n cfg,\n accountId,\n input: {\n clientId: String(clientId).trim(),\n clientSecret: parseSecretInputString(clientSecret),\n dmPolicy: dmPolicyValue,\n groupPolicy: groupPolicyValue,\n messageType,\n ...cardAdvanced,\n },\n });\n await noteDingTalkSetupComplete(prompter);\n return nextCfg;\n}\n\nexport const dingtalkSetupAdapter: ChannelSetupAdapter = {\n resolveAccountId: ({ accountId }) => normalizeAccountId(accountId ?? DEFAULT_ACCOUNT_ID),\n applyAccountName: ({ cfg, accountId, name }) =>\n applyAccountNameToChannelSection({ cfg, channelKey: channel, accountId, name }),\n applyAccountConfig: ({ cfg, accountId, input }) =>\n applyGenericSetupInput({\n cfg,\n accountId,\n input,\n }),\n};\n\nexport const dingtalkSetupWizard: ChannelSetupWizard = {\n channel,\n credentials: [],\n status: {\n configuredLabel: \"configured\",\n unconfiguredLabel: \"needs setup\",\n resolveConfigured: ({ cfg }) => {\n const accountIds = listDingTalkAccountIds(cfg);\n return accountIds.length > 0\n ? accountIds.some((accountId) => isConfigured(resolveDingTalkAccount(cfg, accountId)))\n : isConfigured(resolveDingTalkAccount(cfg, DEFAULT_ACCOUNT_ID));\n },\n resolveStatusLines: ({ configured }) => [\n `DingTalk: ${configured ? \"configured\" : \"needs setup\"}`,\n ],\n resolveSelectionHint: ({ configured }) =>\n configured ? \"configured\" : \"DingTalk enterprise bot\",\n resolveQuickstartScore: ({ configured }) => (configured ? 1 : 4),\n },\n resolveShouldPromptAccountIds: () => true,\n resolveAccountIdForConfigure: async ({\n cfg,\n prompter,\n accountOverride,\n shouldPromptAccountIds,\n listAccountIds,\n defaultAccountId,\n }) => {\n const resolvedAccountId = accountOverride\n ? normalizeAccountId(accountOverride)\n : defaultAccountId;\n if (!shouldPromptAccountIds || accountOverride) {\n return resolvedAccountId;\n }\n return await promptDingTalkAccountId({\n cfg,\n prompter,\n label: \"DingTalk\",\n currentId: resolvedAccountId,\n listAccountIds,\n defaultAccountId,\n });\n },\n finalize: async ({ cfg, accountId, prompter }) => ({\n cfg: await configureDingTalkAccount({\n cfg,\n accountId,\n prompter,\n }),\n }),\n};\n", "import httpClient from \"./http-client.js\";\n\n// \u2500\u2500 Constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst REGISTRATION_BASE_URL = \"https://oapi.dingtalk.com\";\nconst REGISTRATION_SOURCE = \"openClaw\";\nconst RETRY_WINDOW_MS = 120_000; // 2 minutes for transient errors\n\n// \u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class RegistrationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"RegistrationError\";\n }\n}\n\nexport interface RegistrationResult {\n clientId: string;\n clientSecret: string;\n}\n\ninterface BeginResult {\n deviceCode: string;\n verificationUrl: string;\n expiresIn: number;\n interval: number;\n}\n\ntype PollStatus = \"WAITING\" | \"SUCCESS\" | \"FAIL\" | \"EXPIRED\";\n\ninterface PollResult {\n status: PollStatus;\n clientId?: string;\n clientSecret?: string;\n failReason?: string;\n}\n\n// \u2500\u2500 Internal helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction asString(value: unknown): string {\n return typeof value === \"string\" ? value : \"\";\n}\n\nasync function apiPost(\n path: string,\n payload: Record<string, unknown>,\n): Promise<Record<string, unknown>> {\n const url = `${REGISTRATION_BASE_URL}${path}`;\n const resp = await httpClient.post(url, payload, { timeout: 15_000 });\n const data = resp.data as Record<string, unknown>;\n const errcode = data.errcode;\n if (errcode !== undefined && errcode !== 0) {\n const errmsg = asString(data.errmsg) || \"unknown error\";\n throw new RegistrationError(`API error [${path}]: ${errmsg} (errcode=${typeof errcode === \"number\" ? errcode : asString(errcode)})`);\n }\n return data;\n}\n\n// \u2500\u2500 Step 1: init \u2192 nonce \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nasync function initRegistration(): Promise<string> {\n const data = await apiPost(\"/app/registration/init\", { source: REGISTRATION_SOURCE });\n const nonce = asString(data.nonce).trim();\n if (!nonce) {\n throw new RegistrationError(\"init response missing nonce\");\n }\n return nonce;\n}\n\n// \u2500\u2500 Step 2: begin \u2192 deviceCode + verificationUrl \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nasync function beginRegistration(nonce: string): Promise<BeginResult> {\n const data = await apiPost(\"/app/registration/begin\", { nonce });\n const deviceCode = asString(data.device_code).trim();\n const verificationUrl = asString(data.verification_uri_complete).trim();\n if (!deviceCode) {\n throw new RegistrationError(\"begin response missing device_code\");\n }\n if (!verificationUrl) {\n throw new RegistrationError(\"begin response missing verification_uri_complete\");\n }\n return {\n deviceCode,\n verificationUrl,\n expiresIn: Number(data.expires_in ?? 7200) || 7200,\n interval: Math.max(Number(data.interval ?? 3) || 3, 2),\n };\n}\n\n// \u2500\u2500 Step 3: poll \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nasync function pollRegistration(deviceCode: string): Promise<PollResult> {\n const data = await apiPost(\"/app/registration/poll\", { device_code: deviceCode });\n const raw = asString(data.status).trim().toUpperCase();\n const status: PollStatus = [\"WAITING\", \"SUCCESS\", \"FAIL\", \"EXPIRED\"].includes(raw)\n ? (raw as PollStatus)\n : \"FAIL\";\n return {\n status,\n clientId: asString(data.client_id).trim() || undefined,\n clientSecret: asString(data.client_secret).trim() || undefined,\n failReason: asString(data.fail_reason).trim() || undefined,\n };\n}\n\n// \u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface DeviceRegistrationSession {\n verificationUrl: string;\n waitForResult: (options?: {\n onWaiting?: () => void;\n signal?: AbortSignal;\n }) => Promise<RegistrationResult>;\n}\n\nexport async function beginDeviceRegistration(): Promise<DeviceRegistrationSession> {\n const nonce = await initRegistration();\n const { deviceCode, verificationUrl, expiresIn, interval } = await beginRegistration(nonce);\n\n const waitForResult = async (options?: {\n onWaiting?: () => void;\n signal?: AbortSignal;\n }): Promise<RegistrationResult> => {\n const deadline = Date.now() + expiresIn * 1000;\n let networkRetryStart = 0;\n let statusRetryStart = 0;\n\n const signal = options?.signal;\n let abortHandler: (() => void) | null = null;\n const abortPromise = signal\n ? new Promise<never>((_resolve, reject) => {\n abortHandler = () => reject(new RegistrationError(\"registration cancelled\"));\n signal.addEventListener(\"abort\", abortHandler, { once: true });\n })\n : null;\n // Suppress unhandled rejection when abort fires outside Promise.race\n abortPromise?.catch(() => {});\n\n const sleep = () =>\n new Promise((resolve) => setTimeout(resolve, interval * 1000));\n\n try {\n while (Date.now() < deadline) {\n if (signal?.aborted) {\n throw new RegistrationError(\"registration cancelled\");\n }\n\n // AbortSignal-aware sleep\n await (abortPromise ? Promise.race([sleep(), abortPromise]) : sleep());\n\n // Check again after sleep \u2014 abort may have fired during sleep\n if (signal?.aborted) {\n throw new RegistrationError(\"registration cancelled\");\n }\n\n let result: PollResult;\n try {\n result = await pollRegistration(deviceCode);\n } catch {\n if (!networkRetryStart) {\n networkRetryStart = Date.now();\n }\n if (Date.now() - networkRetryStart < RETRY_WINDOW_MS) {\n continue;\n }\n throw new RegistrationError(\"registration polling failed after retry window\");\n }\n\n // Successful poll resets network retry window\n networkRetryStart = 0;\n\n const { status } = result;\n\n if (status === \"WAITING\") {\n statusRetryStart = 0;\n options?.onWaiting?.();\n continue;\n }\n\n if (status === \"SUCCESS\") {\n const clientId = result.clientId;\n const clientSecret = result.clientSecret;\n if (!clientId || !clientSecret) {\n throw new RegistrationError(\"authorization succeeded but credentials are missing\");\n }\n return { clientId, clientSecret };\n }\n\n if (status === \"EXPIRED\") {\n throw new RegistrationError(\"authorization expired, please restart registration\");\n }\n\n // FAIL \u2014 retry within window\n if (!statusRetryStart) {\n statusRetryStart = Date.now();\n }\n if (Date.now() - statusRetryStart < RETRY_WINDOW_MS) {\n continue;\n }\n throw new RegistrationError(`authorization failed: ${result.failReason ?? status}`);\n }\n\n throw new RegistrationError(\"authorization timed out, please retry\");\n } finally {\n if (abortHandler && signal) {\n signal.removeEventListener(\"abort\", abortHandler);\n }\n }\n };\n\n return { verificationUrl, waitForResult };\n}\n", "import { jsonResult } from \"openclaw/plugin-sdk/channel-actions\";\nimport type { ChannelMessageActionAdapter } from \"openclaw/plugin-sdk/channel-contract\";\nimport type { OpenClawConfig } from \"openclaw/plugin-sdk/core\";\nimport { readStringParam } from \"openclaw/plugin-sdk/param-readers\";\nimport { extractToolSend } from \"openclaw/plugin-sdk/tool-send\";\nimport { getConfig, stripTargetPrefix } from \"../config\";\nimport { getLogger } from \"../logger-context\";\nimport { resolveOriginalPeerId } from \"../peer-id-registry\";\nimport { hasConfiguredSecretInput } from \"../secret-input\";\nimport { sendMedia, sendMessage } from \"../send-service\";\nimport { parseBooleanLike } from \"../utils\";\n\nfunction readBooleanLikeParam(params: Record<string, unknown>, key: string): boolean | undefined {\n return parseBooleanLike(params[key]);\n}\n\nfunction readSharedAudioAsVoiceParam(params: Record<string, unknown>): boolean {\n const sharedValue = readBooleanLikeParam(params, \"audioAsVoice\");\n if (sharedValue !== undefined) {\n return sharedValue;\n }\n return readBooleanLikeParam(params, \"asVoice\") === true;\n}\n\nfunction resolveConversationIdFromSessionKey(sessionKey?: string | null): string | undefined {\n const trimmed = sessionKey?.trim();\n if (!trimmed) {\n return undefined;\n }\n\n const markers = [\":group:\", \":channel:\", \":direct:\"] as const;\n const marker = markers.find((candidate) => trimmed.includes(candidate));\n if (!marker) {\n return undefined;\n }\n\n const suffix = trimmed.slice(trimmed.indexOf(marker) + marker.length);\n const threadMarker = \":topic:\";\n const threadIndex = suffix.indexOf(threadMarker);\n const conversationId = (threadIndex >= 0 ? suffix.slice(0, threadIndex) : suffix).trim();\n return conversationId || undefined;\n}\n\nfunction inferCardOwnerIdFromTarget(target: string): string | undefined {\n const trimmed = target.trim();\n if (!trimmed || trimmed.startsWith(\"cid\")) {\n return undefined;\n }\n return trimmed;\n}\n\nfunction describeDingTalkMessageTool(cfg: OpenClawConfig) {\n const config = getConfig(cfg);\n const configured = Boolean(config.clientId && hasConfiguredSecretInput(config.clientSecret));\n if (!configured && !(config.accounts && Object.keys(config.accounts).length > 0)) {\n return { actions: [], capabilities: [], schema: null };\n }\n const hasCardMode =\n config.messageType === \"card\" ||\n (config.accounts && Object.values(config.accounts).some((account) => account?.messageType === \"card\"));\n return {\n actions: [\"send\"] as const,\n capabilities: hasCardMode ? ([\"cards\"] as const) : [],\n schema: null,\n };\n}\n\nexport function createDingTalkMessageActions(): ChannelMessageActionAdapter {\n return {\n describeMessageTool: ({ cfg }) => describeDingTalkMessageTool(cfg),\n supportsAction: ({ action }) => action === \"send\",\n extractToolSend: ({ args }) => extractToolSend(args, \"sendMessage\"),\n handleAction: async ({ action, params, cfg, accountId, dryRun, mediaLocalRoots, sessionKey }) => {\n if (action !== \"send\") {\n throw new Error(`Action ${action} is not supported for provider dingtalk.`);\n }\n\n const to = readStringParam(params, \"to\", { required: true });\n const mediaInput =\n readStringParam(params, \"media\", { trim: false }) ??\n readStringParam(params, \"path\", { trim: false }) ??\n readStringParam(params, \"filePath\", { trim: false }) ??\n readStringParam(params, \"mediaUrl\", { trim: false });\n\n const hasMedia = Boolean(mediaInput && mediaInput.trim());\n const caption = readStringParam(params, \"caption\", { allowEmpty: true }) ?? \"\";\n let message =\n readStringParam(params, \"message\", {\n required: !hasMedia,\n allowEmpty: true,\n }) ?? \"\";\n\n if (!message.trim() && caption.trim()) {\n message = caption;\n }\n\n const asVoice = readSharedAudioAsVoiceParam(params);\n const requestedMediaType = readStringParam(params, \"mediaType\") as\n | \"image\"\n | \"voice\"\n | \"video\"\n | \"file\"\n | undefined;\n\n const target = resolveOriginalPeerId(stripTargetPrefix(to).targetId);\n\n if (dryRun) {\n return jsonResult({\n ok: true,\n dryRun: true,\n to: target,\n hasMedia,\n asVoice,\n });\n }\n\n const log = getLogger();\n const config = getConfig(cfg, accountId ?? undefined);\n\n if (hasMedia && mediaInput) {\n const conversationId = resolveConversationIdFromSessionKey(sessionKey) ?? target;\n const expectedCardOwnerId =\n readStringParam(params, \"expectedCardOwnerId\") ?? inferCardOwnerIdFromTarget(target);\n const result = await sendMedia(config, target, mediaInput, {\n log,\n accountId: accountId ?? undefined,\n conversationId,\n mediaType: requestedMediaType ?? undefined,\n audioAsVoice: asVoice,\n mediaLocalRoots: mediaLocalRoots ? [...mediaLocalRoots] : undefined,\n expectedCardOwnerId: expectedCardOwnerId ?? undefined,\n });\n\n if (!result.ok) {\n throw new Error(result.error || \"send media failed\");\n }\n\n return jsonResult({\n ok: true,\n to: target,\n messageId: result.messageId ?? null,\n result: result.data ?? null,\n });\n }\n\n if (asVoice) {\n throw new Error(\n \"DingTalk send with asVoice requires media/path/filePath/mediaUrl pointing to an audio file.\",\n );\n }\n\n if (!message.trim()) {\n throw new Error(\"send requires message when media is not provided\");\n }\n\n const result = await sendMessage(config, target, message, {\n log,\n accountId: accountId ?? undefined,\n });\n\n if (!result.ok) {\n throw new Error(result.error || \"send message failed\");\n }\n\n const data = result.data as any;\n return jsonResult({\n ok: true,\n to: target,\n messageId: data?.processQueryKey || data?.messageId || null,\n result: data ?? null,\n });\n },\n };\n}\n", "import { randomUUID } from \"node:crypto\";\nimport { getConfig } from \"../config\";\nimport { getLogger } from \"../logger-context\";\nimport { getDingTalkRuntime } from \"../runtime\";\nimport { sendMedia, sendMessage } from \"../send-service\";\nimport { normalizeResolvedDingTalkTarget } from \"../targeting/target-directory-adapter\";\nimport type { DingTalkChannelPlugin } from \"../types\";\nimport { formatDingTalkErrorPayloadLog, parseBooleanLike } from \"../utils\";\n\nfunction readBooleanLikeParam(params: Record<string, unknown>, key: string): boolean | undefined {\n return parseBooleanLike(params[key]);\n}\n\nfunction readSharedAudioAsVoiceParam(params: Record<string, unknown>): boolean {\n const sharedValue = readBooleanLikeParam(params, \"audioAsVoice\");\n if (sharedValue !== undefined) {\n return sharedValue;\n }\n return readBooleanLikeParam(params, \"asVoice\") === true;\n}\n\nexport function createDingTalkOutbound(): NonNullable<DingTalkChannelPlugin[\"outbound\"]> {\n return {\n deliveryMode: \"direct\",\n resolveTarget: ({ to }: any) => {\n const trimmed = to?.trim();\n if (!trimmed) {\n return {\n ok: false as const,\n error: new Error(\"DingTalk message requires --to <conversationId>\"),\n };\n }\n return { ok: true as const, to: normalizeResolvedDingTalkTarget(trimmed) };\n },\n sendText: async ({ cfg, to, text, accountId, log }: any) => {\n const config = getConfig(cfg, accountId);\n const runtime = getDingTalkRuntime();\n const storePath = runtime.channel.session.resolveStorePath(cfg.session?.store, {\n agentId: accountId,\n });\n const effectiveLog = getLogger(accountId) || log;\n try {\n const result = await sendMessage(config, to, text, {\n log: effectiveLog,\n accountId,\n storePath,\n conversationId: to,\n });\n effectiveLog?.debug?.(`[DingTalk] sendText: \"${text}\" result: ${JSON.stringify(result)}`);\n if (!result.ok) {\n throw new Error(result.error || \"sendText failed\");\n }\n const data = result.data as any;\n const messageId = String(data?.processQueryKey || data?.messageId || randomUUID());\n const meta =\n result.data || result.tracking\n ? {\n ...(result.data ? { data: result.data as unknown as Record<string, unknown> } : {}),\n ...(result.tracking ? { tracking: result.tracking } : {}),\n }\n : undefined;\n return {\n channel: \"dingtalk\",\n messageId,\n meta,\n };\n } catch (err: any) {\n if (err?.response?.data !== undefined) {\n effectiveLog?.error?.(formatDingTalkErrorPayloadLog(\"outbound.sendText\", err.response.data));\n }\n throw new Error(\n typeof err?.response?.data === \"string\"\n ? err.response.data\n : err?.message || \"sendText failed\",\n { cause: err },\n );\n }\n },\n sendMedia: async ({\n cfg,\n to,\n mediaPath,\n filePath,\n mediaUrl,\n mediaType: providedMediaType,\n audioAsVoice,\n asVoice,\n accountId,\n mediaLocalRoots,\n log,\n expectedCardOwnerId,\n }: any) => {\n const config = getConfig(cfg, accountId);\n const runtime = getDingTalkRuntime();\n const storePath = runtime.channel.session.resolveStorePath(cfg.session?.store, {\n agentId: accountId,\n });\n const effectiveLog = getLogger(accountId) || log;\n if (!config.clientId) {\n throw new Error(\"DingTalk not configured\");\n }\n\n const rawMediaPath = mediaPath || filePath || mediaUrl;\n if (!rawMediaPath) {\n throw new Error(\n `mediaPath, filePath, or mediaUrl is required. Received: ${JSON.stringify({\n to,\n mediaPath,\n filePath,\n mediaUrl,\n })}`,\n );\n }\n\n const requestedMediaType = typeof providedMediaType === \"string\"\n ? (providedMediaType as \"image\" | \"voice\" | \"video\" | \"file\")\n : undefined;\n\n try {\n const result = await sendMedia(config, to, rawMediaPath, {\n log: effectiveLog,\n accountId,\n storePath,\n conversationId: to,\n mediaType: requestedMediaType,\n audioAsVoice: readSharedAudioAsVoiceParam({ audioAsVoice, asVoice }),\n mediaLocalRoots,\n expectedCardOwnerId,\n });\n effectiveLog?.debug?.(`[DingTalk] sendMedia result: ${JSON.stringify(result)}`);\n if (!result.ok) {\n throw new Error(result.error || \"sendMedia failed\");\n }\n const data = result.data;\n const messageId = String(\n result.messageId || data?.processQueryKey || data?.messageId || randomUUID(),\n );\n return {\n channel: \"dingtalk\",\n messageId,\n meta: result.data\n ? { data: result.data as unknown as Record<string, unknown> }\n : undefined,\n };\n } catch (err: any) {\n if (err?.response?.data !== undefined) {\n effectiveLog?.error?.(formatDingTalkErrorPayloadLog(\"outbound.sendMedia\", err.response.data));\n }\n throw new Error(\n typeof err?.response?.data === \"string\"\n ? err.response.data\n : err?.message || \"sendMedia failed\",\n { cause: err },\n );\n }\n },\n };\n}\n", "import type { OpenClawConfig } from \"openclaw/plugin-sdk/core\";\nimport type { ChannelDirectoryEntry } from \"openclaw/plugin-sdk/directory-runtime\";\nimport { getConfig, stripTargetPrefix } from \"../config\";\nimport { resolveOriginalPeerId } from \"../peer-id-registry\";\nimport { getDingTalkRuntime } from \"../runtime\";\nimport { listKnownGroupTargets, listKnownUserTargets } from \"./target-directory-store\";\n\nexport type DirectoryListParams = {\n cfg: OpenClawConfig;\n accountId?: string | null;\n query?: string | null;\n limit?: number | null;\n runtime?: unknown;\n};\n\ntype RuntimeSessionResolver = {\n resolveStorePath?: (store: unknown, options: { agentId?: string | null | undefined }) => string;\n};\n\nfunction normalizeDirectoryAccountId(accountId?: string | null): string {\n const resolved = String(accountId || \"default\").trim();\n return resolved || \"default\";\n}\n\nfunction normalizeDirectoryLimit(limit?: number | null): number | undefined {\n if (typeof limit !== \"number\" || !Number.isFinite(limit) || limit <= 0) {\n return undefined;\n }\n return Math.floor(limit);\n}\n\nfunction resolveDirectoryStorePath(params: {\n cfg: OpenClawConfig;\n accountId?: string | null;\n runtime?: unknown;\n}): string | undefined {\n const normalizedAccountId = normalizeDirectoryAccountId(params.accountId);\n const runtimeSession = (\n params.runtime as { channel?: { session?: RuntimeSessionResolver } } | undefined\n )?.channel?.session;\n if (runtimeSession?.resolveStorePath) {\n return runtimeSession.resolveStorePath(params.cfg.session?.store, {\n agentId: normalizedAccountId,\n });\n }\n try {\n const rt = getDingTalkRuntime();\n return rt.channel.session.resolveStorePath(params.cfg.session?.store, {\n agentId: normalizedAccountId,\n });\n } catch {\n return undefined;\n }\n}\n\nfunction shouldFilterDirectoryByQuery(params: DirectoryListParams): boolean {\n // OpenClaw target-resolver currently uses a query-insensitive cache key and\n // always calls directory list APIs with limit=undefined. If we filter by\n // query at this layer during resolver calls, one miss can poison cache for\n // later different queries. Keep resolver reads query-agnostic.\n return params.limit !== undefined;\n}\n\nfunction isDisplayNameResolutionEnabled(params: {\n cfg: OpenClawConfig;\n accountId?: string | null;\n}): boolean {\n const mode = getConfig(params.cfg, params.accountId ?? undefined).displayNameResolution;\n // Current upstream target resolution does not pass requester owner/authz context into\n // plugin targetResolver/directory callbacks, so owner-only resolution is not yet safe.\n // Keep the config explicit: only \"all\" enables learned displayName resolution for now.\n // TODO(upstream target-resolver): add a true owner-only mode once requester authorization\n // is plumbed into plugin resolver and directory entry points.\n return mode === \"all\";\n}\n\nexport function listDingTalkDirectoryGroups(params: DirectoryListParams): ChannelDirectoryEntry[] {\n if (!isDisplayNameResolutionEnabled(params)) {\n return [];\n }\n const accountId = normalizeDirectoryAccountId(params.accountId);\n const storePath = resolveDirectoryStorePath(params);\n const filterByQuery = shouldFilterDirectoryByQuery(params);\n const groups = listKnownGroupTargets({\n storePath,\n accountId,\n query: filterByQuery ? (params.query ?? undefined) : undefined,\n limit: filterByQuery ? normalizeDirectoryLimit(params.limit) : undefined,\n });\n const groupEntries: ChannelDirectoryEntry[] = groups.map((entry) => ({\n kind: \"group\" as const,\n id: resolveOriginalPeerId(entry.conversationId),\n name: entry.currentTitle,\n handle: entry.conversationId,\n rank: entry.lastSeenAt,\n raw: entry,\n }));\n\n if (filterByQuery) {\n return groupEntries;\n }\n\n // TODO(upstream target-resolver): remove this fallback once bare user labels\n // can be classified and routed to listPeers() instead of only listGroups().\n // Temporary hack for the current upstream target-resolver flow: bare names\n // are classified as \"group\" before directory lookup, so user displayName\n // targets never reach listPeers(). Merge users into the resolver-only group\n // lookup set so \"displayName -> targetId\" can still resolve for DingTalk.\n const users = listKnownUserTargets({\n storePath,\n accountId,\n });\n const userEntries: ChannelDirectoryEntry[] = users.map((entry) => ({\n kind: \"user\" as const,\n id: entry.canonicalUserId,\n name: entry.currentDisplayName,\n handle: entry.staffId || entry.senderId,\n rank: entry.lastSeenAt,\n raw: entry,\n }));\n\n return [...groupEntries, ...userEntries].toSorted(\n (left, right) => (right.rank || 0) - (left.rank || 0),\n );\n}\n\nexport function listDingTalkDirectoryUsers(params: DirectoryListParams): ChannelDirectoryEntry[] {\n if (!isDisplayNameResolutionEnabled(params)) {\n return [];\n }\n const accountId = normalizeDirectoryAccountId(params.accountId);\n const storePath = resolveDirectoryStorePath(params);\n const filterByQuery = shouldFilterDirectoryByQuery(params);\n const users = listKnownUserTargets({\n storePath,\n accountId,\n query: filterByQuery ? (params.query ?? undefined) : undefined,\n limit: filterByQuery ? normalizeDirectoryLimit(params.limit) : undefined,\n });\n return users.map((entry) => ({\n kind: \"user\",\n id: entry.canonicalUserId,\n name: entry.currentDisplayName,\n handle: entry.staffId || entry.senderId,\n rank: entry.lastSeenAt,\n raw: entry,\n }));\n}\n\nexport function normalizeResolvedDingTalkTarget(raw: string): string {\n return resolveOriginalPeerId(stripTargetPrefix(raw).targetId);\n}\n", "import { getAccessToken } from \"../auth\";\nimport type { DingTalkChannelPlugin } from \"../types\";\nimport { getCurrentTimestamp } from \"../utils\";\n\nexport function createDingTalkStatus(): NonNullable<DingTalkChannelPlugin[\"status\"]> {\n return {\n defaultRuntime: {\n accountId: \"default\",\n running: false,\n connected: false,\n lastEventAt: null,\n lastConnectedAt: null,\n lastInboundAt: null,\n lastStartAt: null,\n lastStopAt: null,\n lastError: null,\n },\n collectStatusIssues: (accounts: any[]) => {\n return accounts.flatMap((account) => {\n if (!account.configured) {\n return [\n {\n channel: \"dingtalk\",\n accountId: account.accountId,\n kind: \"config\" as const,\n message: \"Account not configured (missing clientId or clientSecret)\",\n },\n ];\n }\n return [];\n });\n },\n buildChannelSummary: ({ snapshot }: any) => ({\n configured: snapshot?.configured ?? false,\n running: snapshot?.running ?? false,\n lastStartAt: snapshot?.lastStartAt ?? null,\n lastStopAt: snapshot?.lastStopAt ?? null,\n lastError: snapshot?.lastError ?? null,\n }),\n probeAccount: async ({ account, timeoutMs }: any) => {\n if (!account.configured || !account.config?.clientId || !account.config?.clientSecret) {\n return { ok: false, error: \"Not configured\" };\n }\n try {\n const controller = new AbortController();\n const timeoutId = timeoutMs ? setTimeout(() => controller.abort(), timeoutMs) : undefined;\n try {\n await getAccessToken(account.config);\n return { ok: true, details: { clientId: account.config.clientId } };\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n } catch (error: any) {\n return { ok: false, error: error.message };\n }\n },\n buildAccountSnapshot: ({ account, runtime, snapshot, probe }: any) => {\n const running = runtime?.running ?? snapshot?.running ?? false;\n const persistedLastEventAt = runtime?.lastEventAt ?? snapshot?.lastEventAt ?? null;\n\n return {\n accountId: account.accountId,\n name: account.name,\n enabled: account.enabled,\n configured: account.configured,\n clientId: account.config?.clientId ?? null,\n running,\n connected: runtime?.connected ?? snapshot?.connected ?? null,\n lastEventAt: running ? getCurrentTimestamp() : persistedLastEventAt,\n lastConnectedAt: runtime?.lastConnectedAt ?? snapshot?.lastConnectedAt ?? null,\n lastInboundAt: runtime?.lastInboundAt ?? snapshot?.lastInboundAt ?? null,\n lastStartAt: runtime?.lastStartAt ?? snapshot?.lastStartAt ?? null,\n lastStopAt: runtime?.lastStopAt ?? snapshot?.lastStopAt ?? null,\n lastError: runtime?.lastError ?? snapshot?.lastError ?? null,\n probe,\n };\n },\n };\n}\n", "import { stripTargetPrefix } from \"../config\";\n\nfunction stripProviderPrefix(raw: string): string {\n return raw.replace(/^(dingtalk|dd|ding)\\s*:\\s*/i, \"\");\n}\n\nfunction parseDingTalkTargetInput(raw: string): {\n targetId: string;\n explicitUser: boolean;\n explicitGroup: boolean;\n} {\n const providerStripped = stripProviderPrefix(raw.trim()).trim();\n const explicitGroup = providerStripped.startsWith(\"group:\");\n const { targetId, isExplicitUser } = stripTargetPrefix(providerStripped);\n return {\n targetId: targetId.trim(),\n explicitUser: isExplicitUser,\n explicitGroup,\n };\n}\n\nexport function normalizeDingTalkTarget(raw: string): string | undefined {\n const trimmed = raw.trim();\n if (!trimmed) {\n return undefined;\n }\n const providerStripped = stripProviderPrefix(trimmed).trim();\n const { targetId } = stripTargetPrefix(providerStripped);\n const normalized = targetId.trim();\n return normalized || undefined;\n}\n\nexport function looksLikeDingTalkTargetId(raw: string, normalized?: string): boolean {\n const trimmed = raw.trim();\n if (!trimmed) {\n return false;\n }\n const parsed = parseDingTalkTargetInput(trimmed);\n if (parsed.explicitUser || parsed.explicitGroup) {\n return true;\n }\n const candidate = (normalized || parsed.targetId).trim();\n if (!candidate) {\n return false;\n }\n if (/^cid[\\w+\\-/=]*$/i.test(candidate)) {\n return true;\n }\n if (/^\\+?\\d{6,}$/.test(candidate)) {\n return true;\n }\n if (/^[A-Za-z0-9+/=]{16,}$/.test(candidate) && /[+/=]/.test(candidate)) {\n return true;\n }\n if (/^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z0-9]{24,}$/.test(candidate)) {\n return true;\n }\n if (/^[A-Za-z0-9_-]{24,}$/.test(candidate) && /\\d/.test(candidate)) {\n return true;\n }\n return false;\n}\n", "import axios, { DEFAULT_HTTP_TIMEOUT_MS } from \"./http-client\";\nimport { getAccessToken } from \"./auth\";\nimport { getLogger } from \"./logger-context\";\nimport { getProxyBypassOption } from \"./utils\";\nimport type { DingTalkConfig, DocInfo, Logger } from \"./types\";\n\nconst DINGTALK_API = \"https://api.dingtalk.com\";\n\nasync function buildHeaders(config: DingTalkConfig, log?: Logger): Promise<Record<string, string>> {\n const token = await getAccessToken(config, log);\n return {\n \"x-acs-dingtalk-access-token\": token,\n \"Content-Type\": \"application/json\",\n };\n}\n\ntype CreateDocResponse = {\n docId?: string;\n title?: string;\n name?: string;\n docType?: string;\n creatorId?: string;\n updatedAt?: number | string;\n};\n\ntype SearchDocItem = {\n docId?: string;\n title?: string;\n docType?: string;\n creatorId?: string;\n updatedAt?: number | string;\n};\n\ntype ListDentryItem = {\n dentryUuid?: string;\n name?: string;\n dentryType?: string;\n creatorId?: string;\n updatedAt?: number | string;\n};\n\ntype AppendDocResponse = {\n success?: boolean;\n};\n\nexport class DocCreateAppendError extends Error {\n readonly doc: DocInfo;\n\n constructor(doc: DocInfo, cause?: unknown) {\n super(\"initial content append failed after document creation\");\n this.name = \"DocCreateAppendError\";\n this.doc = doc;\n this.cause = cause;\n }\n}\n\nfunction mapCreatedDoc(item: CreateDocResponse): DocInfo {\n return {\n docId: item.docId ?? \"\",\n title: item.title ?? item.name ?? \"\",\n docType: item.docType ?? \"unknown\",\n creatorId: item.creatorId,\n updatedAt: item.updatedAt,\n };\n}\n\nfunction mapSearchDoc(item: SearchDocItem): DocInfo {\n return {\n docId: item.docId ?? \"\",\n title: item.title ?? \"\",\n docType: item.docType ?? \"unknown\",\n creatorId: item.creatorId,\n updatedAt: item.updatedAt,\n };\n}\n\nfunction mapListDentry(item: ListDentryItem): DocInfo {\n return {\n docId: item.dentryUuid ?? \"\",\n title: item.name ?? \"\",\n docType: item.dentryType ?? \"unknown\",\n creatorId: item.creatorId,\n updatedAt: item.updatedAt,\n };\n}\n\nexport async function createDoc(\n config: DingTalkConfig,\n spaceId: string,\n title: string,\n content?: string,\n log = getLogger(),\n parentId?: string,\n): Promise<DocInfo> {\n const headers = await buildHeaders(config, log);\n const createResp = await axios.post(\n `${DINGTALK_API}/v1.0/doc/spaces/${spaceId}/docs`,\n {\n spaceId,\n ...(parentId ? { parentDentryId: parentId } : { parentDentryId: \"\" }),\n name: title,\n docType: \"alidoc\",\n },\n {\n headers,\n timeout: DEFAULT_HTTP_TIMEOUT_MS,\n ...getProxyBypassOption(config),\n },\n );\n const createdBase = mapCreatedDoc((createResp.data ?? {}) as CreateDocResponse);\n const created = {\n ...createdBase,\n title: createdBase.title || title,\n docType: createdBase.docType || \"alidoc\",\n };\n if (content?.trim() && created.docId) {\n try {\n await appendToDoc(config, created.docId, content, log);\n } catch (error) {\n throw new DocCreateAppendError(created, error);\n }\n }\n return created;\n}\n\nexport async function appendToDoc(\n config: DingTalkConfig,\n docId: string,\n content: string,\n log = getLogger(),\n index = -1,\n): Promise<{ success: true }> {\n const headers = await buildHeaders(config, log);\n // DingTalk document block API accepts `index = -1` to append content at the end.\n const resp = await axios.post(\n `${DINGTALK_API}/v1.0/doc/documents/${docId}/blocks/root/children`,\n {\n blockType: \"PARAGRAPH\",\n body: { text: content },\n index,\n },\n {\n headers,\n timeout: DEFAULT_HTTP_TIMEOUT_MS,\n ...getProxyBypassOption(config),\n },\n );\n if ((resp.data as AppendDocResponse | undefined)?.success === false) {\n throw new Error(\"appendToDoc failed\");\n }\n return { success: true };\n}\n\nexport async function searchDocs(\n config: DingTalkConfig,\n keyword: string,\n spaceId?: string,\n log = getLogger(),\n): Promise<DocInfo[]> {\n const headers = await buildHeaders(config, log);\n const resp = await axios.post(\n `${DINGTALK_API}/v1.0/doc/docs/search`,\n {\n keyword,\n maxResults: 20,\n ...(spaceId ? { spaceId } : {}),\n },\n {\n headers,\n timeout: DEFAULT_HTTP_TIMEOUT_MS,\n ...getProxyBypassOption(config),\n },\n );\n return Array.isArray(resp.data?.items)\n ? (resp.data.items as SearchDocItem[]).map(mapSearchDoc)\n : [];\n}\n\nexport async function listDocs(\n config: DingTalkConfig,\n spaceId: string,\n parentId?: string,\n log = getLogger(),\n): Promise<DocInfo[]> {\n const headers = await buildHeaders(config, log);\n const resp = await axios.get(`${DINGTALK_API}/v1.0/doc/spaces/${spaceId}/dentries`, {\n headers,\n params: {\n maxResults: 50,\n ...(parentId ? { parentDentryId: parentId } : {}),\n },\n timeout: DEFAULT_HTTP_TIMEOUT_MS,\n ...getProxyBypassOption(config),\n });\n return Array.isArray(resp.data?.items)\n ? (resp.data.items as ListDentryItem[]).map(mapListDentry)\n : [];\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["readStringParam", "os", "path", "resolve", "z", "fs", "path", "z", "asRecord", "fs", "path", "readFileSync", "readdirSync", "os", "join", "join", "readdirSync", "readFileSync", "DINGTALK_API", "DINGTALK_API", "records", "DINGTALK_API", "resolve", "deadlineMs", "delay", "randomUUID", "rule", "randomUUID", "randomUUID", "fs", "path", "asRecord", "resolve", "resolve", "action", "rawPeerId", "randomUUID", "os", "path", "randomUUID", "records", "buffer", "getAccessToken", "fs", "path", "path", "uploadMedia", "firstTrimmedString", "resolve", "delivery", "messageId", "firstTrimmedString", "asRecord", "DINGTALK_API", "cleanReasoningLine", "split", "uploadMedia", "suffix", "sessionKey", "fs", "path", "fallbackState", "writeState", "nextState", "writeState", "fs", "shouldDisable", "resolve", "sessionTaskState", "client", "resolve", "DEFAULT_ACCOUNT_ID", "path", "resolve", "isConfigured", "DEFAULT_ACCOUNT_ID", "sessionKey", "result", "randomUUID", "readBooleanLikeParam", "readSharedAudioAsVoiceParam", "randomUUID", "DINGTALK_API", "readStringParam", "getErrorMessage"]
7
+ }