@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 +2 -0
- package/dist/index.js +95 -28
- package/dist/index.js.map +3 -3
- package/dist/src/card/card-template.d.ts +1 -1
- package/dist/src/card/task-model-metadata.d.ts +11 -0
- package/dist/src/card/task-model-metadata.d.ts.map +1 -0
- package/dist/src/inbound-handler.d.ts.map +1 -1
- package/dist/src/reply-strategy-card.d.ts.map +1 -1
- package/dist/src/reply-strategy-types.d.ts +1 -0
- package/dist/src/reply-strategy-types.d.ts.map +1 -1
- package/dist/src/session-state.d.ts +11 -5
- package/dist/src/session-state.d.ts.map +1 -1
- package/docs/assets/dingtalk-ask-user-card-template.json +6 -0
- package/package.json +2 -1
- package/src/card/card-template.ts +1 -1
- package/src/card/task-model-metadata.ts +51 -0
- package/src/inbound-handler.ts +21 -12
- package/src/reply-strategy-card.ts +30 -6
- package/src/reply-strategy-types.ts +1 -0
- package/src/session-state.ts +44 -13
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 = "
|
|
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(
|
|
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(
|
|
8535
|
-
const key = sessionKey(
|
|
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(
|
|
8548
|
-
return sessionStore.get(sessionKey(
|
|
8593
|
+
function getSessionState(scope) {
|
|
8594
|
+
return sessionStore.get(sessionKey(scope));
|
|
8549
8595
|
}
|
|
8550
|
-
function updateSessionState(
|
|
8551
|
-
const state = sessionStore.get(sessionKey(
|
|
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(
|
|
8563
|
-
const state = sessionStore.get(sessionKey(
|
|
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 =
|
|
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
|
-
|
|
8942
|
-
|
|
8943
|
-
|
|
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
|
|
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:
|
|
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(
|
|
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:
|
|
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) {
|