@soimy/dingtalk 3.6.5 → 3.6.6

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.
package/README.md CHANGED
@@ -150,6 +150,8 @@ openclaw configure --section channels
150
150
 
151
151
  使用该能力无需额外配置模板 ID;插件内置钉钉互动卡片模板。若当前 OpenClaw 运行时不支持工具注册,插件会跳过该工具注册,不影响既有钉钉消息收发、AI 卡片和反馈学习能力。
152
152
 
153
+ 使用说明见 [表单互动卡片](docs/user/features/form-interactive-card.md)。
154
+
153
155
  ## 重要功能文档
154
156
 
155
157
  - [消息类型支持](docs/user/features/message-types.md)
package/dist/index.js CHANGED
@@ -1667,7 +1667,7 @@ var BUILTIN_DINGTALK_CARD_TEMPLATE_ID = process.env.DINGTALK_CARD_TEMPLATE_ID ||
1667
1667
  var BUILTIN_DINGTALK_CARD_CONTENT_KEY = "content";
1668
1668
  var BUILTIN_DINGTALK_CARD_BLOCK_LIST_KEY = "blockList";
1669
1669
  var BUILTIN_DINGTALK_CARD_COPY_CONTENT_KEY = "copy_content";
1670
- var BUILTIN_DINGTALK_ASK_USER_CARD_TEMPLATE_ID = "89d0c6fe-3822-44c8-950e-e950f562546d.schema";
1670
+ var BUILTIN_DINGTALK_ASK_USER_CARD_TEMPLATE_ID = "c2a6355b-9724-4f7e-9653-d33fcb3311bb.schema";
1671
1671
  var DINGTALK_CARD_TEMPLATE = Object.freeze({
1672
1672
  templateId: BUILTIN_DINGTALK_CARD_TEMPLATE_ID,
1673
1673
  contentKey: BUILTIN_DINGTALK_CARD_CONTENT_KEY,
@@ -3514,6 +3514,36 @@ function renderStatusLine(data, config) {
3514
3514
  return lines.join("\n");
3515
3515
  }
3516
3516
 
3517
+ // src/card/task-model-metadata.ts
3518
+ function readPrimaryModelRef(value) {
3519
+ if (typeof value === "string") {
3520
+ return value.trim() || void 0;
3521
+ }
3522
+ if (value && typeof value === "object" && typeof value.primary === "string") {
3523
+ return value.primary.trim() || void 0;
3524
+ }
3525
+ return void 0;
3526
+ }
3527
+ function normalizeModelDisplayName(modelRef) {
3528
+ const trimmed = typeof modelRef === "string" ? modelRef.trim() : "";
3529
+ if (!trimmed) {
3530
+ return void 0;
3531
+ }
3532
+ const parts = trimmed.split("/").map((part) => part.trim()).filter(Boolean);
3533
+ return parts.at(-1) || void 0;
3534
+ }
3535
+ function resolveConfiguredTaskModelMetadata(params) {
3536
+ const agents = params.cfg.agents;
3537
+ const agentId = String(params.agentId || "").trim();
3538
+ const agent = Array.isArray(agents?.list) ? agents.list.find((entry) => String(entry.id || "").trim() === agentId) : void 0;
3539
+ const modelRef = readPrimaryModelRef(agent?.model) ?? readPrimaryModelRef(agents?.defaults?.model);
3540
+ const effort = typeof agent?.thinkingDefault === "string" && agent.thinkingDefault.trim() ? agent.thinkingDefault.trim() : typeof agents?.defaults?.thinkingDefault === "string" && agents.defaults.thinkingDefault.trim() ? agents.defaults.thinkingDefault.trim() : void 0;
3541
+ return {
3542
+ model: normalizeModelDisplayName(modelRef),
3543
+ effort
3544
+ };
3545
+ }
3546
+
3517
3547
  // src/command/card-stop-command.ts
3518
3548
  import { resolveNativeCommandSessionTargets } from "openclaw/plugin-sdk/command-auth";
3519
3549
 
@@ -8528,27 +8558,43 @@ function createCardDraftController(params) {
8528
8558
 
8529
8559
  // src/session-state.ts
8530
8560
  var sessionStore = /* @__PURE__ */ new Map();
8531
- function sessionKey(accountId, conversationId) {
8532
- return `${accountId}:${conversationId}`;
8561
+ function sessionKey(scope) {
8562
+ return `${scope.accountId}:${scope.agentId}:${scope.conversationId}`;
8563
+ }
8564
+ function normalizeMetadataValue(value) {
8565
+ const trimmed = typeof value === "string" ? value.trim() : "";
8566
+ return trimmed || void 0;
8567
+ }
8568
+ function seedMissingSessionStateMetadata(state, metadata) {
8569
+ const model = normalizeMetadataValue(metadata?.model);
8570
+ const effort = normalizeMetadataValue(metadata?.effort);
8571
+ if (state.model === void 0 && model !== void 0) {
8572
+ state.model = model;
8573
+ }
8574
+ if (state.effort === void 0 && effort !== void 0) {
8575
+ state.effort = effort;
8576
+ }
8533
8577
  }
8534
- function initSessionState(accountId, conversationId) {
8535
- const key = sessionKey(accountId, conversationId);
8578
+ function initSessionState(scope, metadata) {
8579
+ const key = sessionKey(scope);
8536
8580
  const existing = sessionStore.get(key);
8537
8581
  if (existing) {
8538
8582
  existing.taskStartTime = Date.now();
8583
+ seedMissingSessionStateMetadata(existing, metadata);
8539
8584
  return existing;
8540
8585
  }
8541
8586
  const state = {
8542
8587
  taskStartTime: Date.now()
8543
8588
  };
8589
+ seedMissingSessionStateMetadata(state, metadata);
8544
8590
  sessionStore.set(key, state);
8545
8591
  return state;
8546
8592
  }
8547
- function getSessionState(accountId, conversationId) {
8548
- return sessionStore.get(sessionKey(accountId, conversationId));
8593
+ function getSessionState(scope) {
8594
+ return sessionStore.get(sessionKey(scope));
8549
8595
  }
8550
- function updateSessionState(accountId, conversationId, patch) {
8551
- const state = sessionStore.get(sessionKey(accountId, conversationId));
8596
+ function updateSessionState(scope, patch) {
8597
+ const state = sessionStore.get(sessionKey(scope));
8552
8598
  if (!state) {
8553
8599
  return;
8554
8600
  }
@@ -8559,8 +8605,8 @@ function updateSessionState(accountId, conversationId, patch) {
8559
8605
  state.effort = patch.effort;
8560
8606
  }
8561
8607
  }
8562
- function getTaskTimeSeconds(accountId, conversationId) {
8563
- const state = sessionStore.get(sessionKey(accountId, conversationId));
8608
+ function getTaskTimeSeconds(scope) {
8609
+ const state = sessionStore.get(sessionKey(scope));
8564
8610
  if (!state) {
8565
8611
  return void 0;
8566
8612
  }
@@ -8618,12 +8664,17 @@ var EMPTY_FINAL_REPLY = "\u2705 Done";
8618
8664
  var DEFAULT_CARD_FAILED_MESSAGE = "\u56DE\u590D\u751F\u6210\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5";
8619
8665
  function createCardReplyStrategy(ctx) {
8620
8666
  const { card, config, log, isStopRequested } = ctx;
8667
+ const sessionTaskStateScope = card.accountId && card.conversationId && ctx.sessionAgentId ? {
8668
+ accountId: card.accountId,
8669
+ conversationId: card.contextConversationId || card.conversationId,
8670
+ agentId: ctx.sessionAgentId
8671
+ } : void 0;
8621
8672
  const buildStatusLine = () => {
8622
8673
  if (!ctx.taskMeta) {
8623
8674
  return void 0;
8624
8675
  }
8625
8676
  const resolvedUsage = typeof card.dapiUsage === "number" ? card.dapiUsage : typeof ctx.taskMeta.usage === "number" ? ctx.taskMeta.usage : void 0;
8626
- const sessionTaskTimeSeconds = card.accountId && card.conversationId ? getTaskTimeSeconds(card.accountId, card.contextConversationId || card.conversationId) : void 0;
8677
+ const sessionTaskTimeSeconds = sessionTaskStateScope ? getTaskTimeSeconds(sessionTaskStateScope) : void 0;
8627
8678
  const cardElapsedMs = Math.max(0, Date.now() - card.createdAt);
8628
8679
  const sessionElapsedMs = typeof sessionTaskTimeSeconds === "number" ? sessionTaskTimeSeconds * 1e3 : void 0;
8629
8680
  const metaElapsedMs = typeof ctx.taskMeta.elapsedMs === "number" && ctx.taskMeta.elapsedMs > 0 ? ctx.taskMeta.elapsedMs : void 0;
@@ -8938,10 +8989,12 @@ function createCardReplyStrategy(ctx) {
8938
8989
  if (!card.accountId || !card.conversationId) {
8939
8990
  return;
8940
8991
  }
8941
- updateSessionState(card.accountId, card.contextConversationId || card.conversationId, {
8942
- model: selected.model,
8943
- effort: selected.thinkLevel
8944
- });
8992
+ if (sessionTaskStateScope) {
8993
+ updateSessionState(sessionTaskStateScope, {
8994
+ model: selected.model,
8995
+ effort: selected.thinkLevel
8996
+ });
8997
+ }
8945
8998
  if (ctx.taskMeta) {
8946
8999
  ctx.taskMeta.model = selected.model;
8947
9000
  ctx.taskMeta.effort = selected.thinkLevel;
@@ -8964,6 +9017,13 @@ function createCardReplyStrategy(ctx) {
8964
9017
  }
8965
9018
  }
8966
9019
  if (payload.kind === "final") {
9020
+ const hasPreservableReply = Boolean(
9021
+ finalTextForFallback?.trim() || controller.getFinalAnswerContent().trim()
9022
+ ) || processedMediaUrls.size > 0 || pendingNonImageMedia.length > 0;
9023
+ if (payload.isError === true && sawFinalDelivery && payload.mediaUrls.length === 0 && hasPreservableReply) {
9024
+ log?.debug?.("[DingTalk][Finalize] Ignoring late error final after answer delivery");
9025
+ return;
9026
+ }
8967
9027
  const isFirstFinalDelivery = !sawFinalDelivery;
8968
9028
  lifecycleState = "final_seen";
8969
9029
  await flushPendingReasoning();
@@ -10798,16 +10858,26 @@ async function handleDingTalkMessageInner(params) {
10798
10858
  const content = extractedContent;
10799
10859
  const isBtwBypass = isBtwRequestText(stripLeadingMentions(content.text).trim());
10800
10860
  const taskInfoConversationId = groupId || to;
10801
- const sessionTaskState = initSessionState(accountId, taskInfoConversationId);
10861
+ const agentDisplayName = getAgentDisplayName({
10862
+ subAgentOptions,
10863
+ agentId: route.agentId,
10864
+ agentsList: cfg.agents?.list
10865
+ });
10866
+ const configuredTaskMetadata = resolveConfiguredTaskModelMetadata({
10867
+ cfg,
10868
+ agentId: route.agentId
10869
+ });
10870
+ const sessionTaskStateScope = {
10871
+ accountId,
10872
+ conversationId: taskInfoConversationId,
10873
+ agentId: route.agentId
10874
+ };
10875
+ const sessionTaskState = initSessionState(sessionTaskStateScope, configuredTaskMetadata);
10802
10876
  const initialStatusLine = renderStatusLine(
10803
10877
  {
10804
10878
  model: sessionTaskState.model,
10805
10879
  effort: sessionTaskState.effort,
10806
- agent: getAgentDisplayName({
10807
- subAgentOptions,
10808
- agentId: route.agentId,
10809
- agentsList: cfg.agents?.list
10810
- })
10880
+ agent: agentDisplayName
10811
10881
  },
10812
10882
  dingtalkConfig
10813
10883
  ) || void 0;
@@ -11768,16 +11838,12 @@ ${attachmentExtractedText}` : inboundBody;
11768
11838
  accountId
11769
11839
  });
11770
11840
  const strategyConfig = legacyCardStreamReasoning === void 0 ? dingtalkConfig : { ...dingtalkConfig, cardStreamReasoning: legacyCardStreamReasoning };
11771
- const sessionTaskState2 = getSessionState(accountId, taskInfoConversationId);
11841
+ const sessionTaskState2 = getSessionState(sessionTaskStateScope);
11772
11842
  const taskMeta = {
11773
11843
  model: sessionTaskState2?.model,
11774
11844
  effort: sessionTaskState2?.effort,
11775
11845
  elapsedMs: typeof sessionTaskState2?.taskStartTime === "number" ? Math.max(0, Date.now() - sessionTaskState2.taskStartTime) : void 0,
11776
- agent: getAgentDisplayName({
11777
- subAgentOptions,
11778
- agentId: route.agentId,
11779
- agentsList: cfg.agents?.list
11780
- })
11846
+ agent: agentDisplayName
11781
11847
  };
11782
11848
  const strategy = createReplyStrategy({
11783
11849
  config: strategyConfig,
@@ -11838,6 +11904,7 @@ ${attachmentExtractedText}` : inboundBody;
11838
11904
  mediaUrls,
11839
11905
  audioAsVoice: extractSharedAudioAsVoice(payload, inlineReplyPayload),
11840
11906
  kind: replyKind,
11907
+ isError: payload.isError === true,
11841
11908
  isReasoning: richPayload.isReasoning === true
11842
11909
  });
11843
11910
  } catch (err) {