@jeik/dingtalk-connector 0.8.21-fix13 → 0.8.21-fix16
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/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as initDingtalkPluginConfigSchema, i as dingtalkPlugin, n as setDingtalkRuntime } from "./runtime-
|
|
1
|
+
import { a as initDingtalkPluginConfigSchema, i as dingtalkPlugin, n as setDingtalkRuntime } from "./runtime-CaDlY3DU.mjs";
|
|
2
2
|
import { t as registerGatewayMethods } from "./gateway-methods-5IlNoS6J.mjs";
|
|
3
3
|
//#region index.ts
|
|
4
4
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { u as uploadMediaToDingTalk } from "./media-cz72EVS3.mjs";
|
|
2
2
|
import { a as resolveDingtalkAccount } from "./accounts-BAzdqkAV.mjs";
|
|
3
|
-
import { r as CHANNEL_ID, t as getDingtalkRuntime } from "./runtime-
|
|
3
|
+
import { r as CHANNEL_ID, t as getDingtalkRuntime } from "./runtime-CaDlY3DU.mjs";
|
|
4
4
|
import { n as createLoggerFromConfig } from "./logger-mZ9OSbmD.mjs";
|
|
5
5
|
import { t as dingtalkHttp } from "./http-client-DFWZgO1n.mjs";
|
|
6
6
|
import { i as getOapiAccessToken } from "./utils-CIfI_3Jh.mjs";
|
|
@@ -399,6 +399,7 @@ function createDingtalkReplyDispatcher(params) {
|
|
|
399
399
|
log.info(`[DingTalk][closeStreaming] 开始关闭 AI Card...`);
|
|
400
400
|
try {
|
|
401
401
|
let finalText = finalClean(pickFinalText());
|
|
402
|
+
const hadRealAnswer = finalText.trim().length > 0;
|
|
402
403
|
log.info(`[DingTalk][closeStreaming] 最终答案来源=${finalMarkedText !== null ? "marker[-final-]" : lastAnswerText ? "非reasoning答案" : "accumulatedText兜底"},长度=${finalText.length}`);
|
|
403
404
|
if (!finalText.trim()) {
|
|
404
405
|
finalText = "✅ 任务执行完成(无文本输出)";
|
|
@@ -451,19 +452,28 @@ function createDingtalkReplyDispatcher(params) {
|
|
|
451
452
|
}
|
|
452
453
|
finalText = await applyReplyTemplate(finalText);
|
|
453
454
|
if (account.config?.answerCard === true) {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
log.info(`[DingTalk][closeStreaming]
|
|
455
|
+
const finalizeOriginalToDone = async () => {
|
|
456
|
+
try {
|
|
457
|
+
await streamAICard(cardSnapshot, "✅ 思考完成", true, account.config, log);
|
|
458
|
+
await finishAICard(cardSnapshot, "✅ 思考完成", account.config, log);
|
|
459
|
+
} catch (e) {
|
|
460
|
+
log.warn(`[DingTalk][closeStreaming] 原卡定格思考完成失败(忽略):${e?.message || e}`);
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
if (!hadRealAnswer) {
|
|
464
|
+
log.info(`[DingTalk][closeStreaming] answerCard 模式:无真实答案,仅定格原卡思考完成(不建答案卡)`);
|
|
465
|
+
await finalizeOriginalToDone();
|
|
464
466
|
} else {
|
|
465
|
-
log.
|
|
466
|
-
await
|
|
467
|
+
log.info(`[DingTalk][closeStreaming] answerCard 模式:原卡定格思考完成 + 新建答案卡`);
|
|
468
|
+
await finalizeOriginalToDone();
|
|
469
|
+
const answerCard = await createAICardForTarget(account.config, target, log, ANSWER_CARD_TEMPLATE_ID);
|
|
470
|
+
if (answerCard) {
|
|
471
|
+
await finishAICard(answerCard, finalText, account.config, log);
|
|
472
|
+
log.info(`[DingTalk][closeStreaming] ✅ 答案卡投放成功`);
|
|
473
|
+
} else {
|
|
474
|
+
log.warn(`[DingTalk][closeStreaming] 答案卡创建失败,降级定稿原卡`);
|
|
475
|
+
await finishAICard(cardSnapshot, finalText, account.config, log);
|
|
476
|
+
}
|
|
467
477
|
}
|
|
468
478
|
} else {
|
|
469
479
|
log.info(`[DingTalk][closeStreaming] 准备调用 finishAICard,文本长度=${finalText.length}`);
|
|
@@ -666,6 +676,23 @@ function createDingtalkReplyDispatcher(params) {
|
|
|
666
676
|
} else log.debug(`[DingTalk][onPartialReply] 节流控制,跳过本次更新(距离上次更新 ${now - lastUpdateTime}ms)`);
|
|
667
677
|
} else log.warn(`[DingTalk][onPartialReply] ⚠️ AI Card 不存在,跳过更新`);
|
|
668
678
|
} },
|
|
679
|
+
onToolStart: async (payload) => {
|
|
680
|
+
const toolName = (payload?.name || "").trim();
|
|
681
|
+
if (!toolName) return;
|
|
682
|
+
if (payload?.phase === "end" || payload?.phase === "complete") return;
|
|
683
|
+
if (!streamingEnabled || asyncMode || finalMarkedText !== null) return;
|
|
684
|
+
try {
|
|
685
|
+
await startStreaming();
|
|
686
|
+
if (!currentCardTarget) return;
|
|
687
|
+
const now = Date.now();
|
|
688
|
+
if (now - lastUpdateTime < updateInterval) return;
|
|
689
|
+
lastUpdateTime = now;
|
|
690
|
+
await streamAICard(currentCardTarget, `🔧 正在调用工具:${toolName}`, false, account.config, log, account.config?.cardContentVar || "msgContent");
|
|
691
|
+
log.debug(`[DingTalk][onToolStart] 工具进度写卡:${toolName}(phase=${payload?.phase})`);
|
|
692
|
+
} catch (e) {
|
|
693
|
+
if (!isQpsLimitError(e)) log.warn(`[DingTalk][onToolStart] 工具进度写卡失败:${e?.message || e}`);
|
|
694
|
+
}
|
|
695
|
+
},
|
|
669
696
|
onCommandOutput: (payload) => {
|
|
670
697
|
const dwsMatch = (payload.title || payload.name || "").match(DWS_PRODUCT_PATTERN) || payload.output?.match(DWS_PRODUCT_PATTERN);
|
|
671
698
|
if (dwsMatch) {
|
|
@@ -922,7 +922,7 @@ async function monitorDingtalkProvider(opts = {}) {
|
|
|
922
922
|
const log = createLogger(cfg.channels?.["dingtalk-connector"]?.debug ?? false);
|
|
923
923
|
const [accountsModule, monitorAccountModule, monitorSingleModule] = await Promise.all([
|
|
924
924
|
import("./accounts-BQptOmgB.mjs"),
|
|
925
|
-
import("./message-handler-
|
|
925
|
+
import("./message-handler-CCyUaGHW.mjs"),
|
|
926
926
|
import("./connection-DHHFFNQJ.mjs")
|
|
927
927
|
]);
|
|
928
928
|
const { resolveDingtalkAccount, listEnabledDingtalkAccounts } = accountsModule;
|
package/package.json
CHANGED
package/src/reply-dispatcher.ts
CHANGED
|
@@ -391,6 +391,9 @@ export function createDingtalkReplyDispatcher(params: CreateDingtalkReplyDispatc
|
|
|
391
391
|
try {
|
|
392
392
|
// 选定最终答案:marker 优先 → 最近非 reasoning 答案 → accumulatedText 兜底,并剥离尾标记
|
|
393
393
|
let finalText = finalClean(pickFinalText());
|
|
394
|
+
// 是否有真实对话答案(在套兜底文案之前判断)。纯工具进度/无回复时为 false,
|
|
395
|
+
// 用于 answerCard 模式下决定"不另建无文本输出答案卡"。
|
|
396
|
+
const hadRealAnswer = finalText.trim().length > 0;
|
|
394
397
|
log.info(
|
|
395
398
|
`[DingTalk][closeStreaming] 最终答案来源=${finalMarkedText !== null ? "marker[-final-]" : (lastAnswerText ? "非reasoning答案" : "accumulatedText兜底")},长度=${finalText.length}`
|
|
396
399
|
);
|
|
@@ -506,27 +509,40 @@ export function createDingtalkReplyDispatcher(params: CreateDingtalkReplyDispatc
|
|
|
506
509
|
// 代价:多一条消息,但渲染正确、更快。
|
|
507
510
|
const useAnswerCard = (account.config as any)?.answerCard === true;
|
|
508
511
|
if (useAnswerCard) {
|
|
509
|
-
|
|
510
|
-
//
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
await
|
|
525
|
-
log.info(`[DingTalk][closeStreaming] ✅ 答案卡投放成功`);
|
|
512
|
+
// 原卡定格"思考完成"。必须用流式端点 streamAICard 覆盖可见内容——
|
|
513
|
+
// FINISHED(/card/instances) 不会刷新已流式过的内容(钉钉 bug),先 streamAICard 盖文本再 FINISHED。
|
|
514
|
+
const finalizeOriginalToDone = async () => {
|
|
515
|
+
try {
|
|
516
|
+
await streamAICard(cardSnapshot as any, "✅ 思考完成", true, account.config as DingtalkConfig, log);
|
|
517
|
+
await finishAICard(cardSnapshot as any, "✅ 思考完成", account.config as DingtalkConfig, log);
|
|
518
|
+
} catch (e: any) {
|
|
519
|
+
log.warn(`[DingTalk][closeStreaming] 原卡定格思考完成失败(忽略):${e?.message || e}`);
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
if (!hadRealAnswer) {
|
|
524
|
+
// 只有工具进度 / 没真实对话答案 → 只把原卡定格"思考完成",不另建"无文本输出"答案卡,
|
|
525
|
+
// 避免重新引入"多段/纯工具轮次留空卡"问题。
|
|
526
|
+
log.info(`[DingTalk][closeStreaming] answerCard 模式:无真实答案,仅定格原卡思考完成(不建答案卡)`);
|
|
527
|
+
await finalizeOriginalToDone();
|
|
526
528
|
} else {
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
529
|
+
log.info(`[DingTalk][closeStreaming] answerCard 模式:原卡定格思考完成 + 新建答案卡`);
|
|
530
|
+
await finalizeOriginalToDone();
|
|
531
|
+
// 新建答案专用卡(静态模板)并投放最终答案
|
|
532
|
+
const answerCard = await createAICardForTarget(
|
|
533
|
+
account.config as DingtalkConfig,
|
|
534
|
+
target,
|
|
535
|
+
log,
|
|
536
|
+
ANSWER_CARD_TEMPLATE_ID,
|
|
537
|
+
);
|
|
538
|
+
if (answerCard) {
|
|
539
|
+
await finishAICard(answerCard, finalText, account.config as DingtalkConfig, log);
|
|
540
|
+
log.info(`[DingTalk][closeStreaming] ✅ 答案卡投放成功`);
|
|
541
|
+
} else {
|
|
542
|
+
// 答案卡建失败 → 降级直接定稿原卡,保证用户能看到回复
|
|
543
|
+
log.warn(`[DingTalk][closeStreaming] 答案卡创建失败,降级定稿原卡`);
|
|
544
|
+
await finishAICard(cardSnapshot as any, finalText, account.config as DingtalkConfig, log);
|
|
545
|
+
}
|
|
530
546
|
}
|
|
531
547
|
} else {
|
|
532
548
|
log.info(`[DingTalk][closeStreaming] 准备调用 finishAICard,文本长度=${finalText.length}`);
|
|
@@ -594,7 +610,7 @@ export function createDingtalkReplyDispatcher(params: CreateDingtalkReplyDispatc
|
|
|
594
610
|
|
|
595
611
|
// 观察标记:更新最终答案认定(marker / 非 reasoning 兜底)
|
|
596
612
|
observeReply(payload.text, (payload as any).isReasoning);
|
|
597
|
-
|
|
613
|
+
|
|
598
614
|
// ✅ 在 final 响应时,先处理裸露的文件路径
|
|
599
615
|
if (info?.kind === "final" && text.trim()) {
|
|
600
616
|
const target: AICardTarget = isDirect
|
|
@@ -877,6 +893,32 @@ export function createDingtalkReplyDispatcher(params: CreateDingtalkReplyDispatc
|
|
|
877
893
|
}
|
|
878
894
|
},
|
|
879
895
|
}),
|
|
896
|
+
// ===== 工具调用进度:开始调用工具时,往原卡流式显示"正在调用工具:工具名" =====
|
|
897
|
+
// OpenClaw 的 onToolStart 带干净的工具名(payload.name)。已进入最终答案 / 异步 / 非流式则跳过。
|
|
898
|
+
onToolStart: async (payload: { name?: string; phase?: string; args?: Record<string, unknown> }) => {
|
|
899
|
+
const toolName = (payload?.name || "").trim();
|
|
900
|
+
if (!toolName) return;
|
|
901
|
+
if (payload?.phase === "end" || payload?.phase === "complete") return;
|
|
902
|
+
if (!streamingEnabled || asyncMode || finalMarkedText !== null) return;
|
|
903
|
+
try {
|
|
904
|
+
await startStreaming();
|
|
905
|
+
if (!currentCardTarget) return;
|
|
906
|
+
const now = Date.now();
|
|
907
|
+
if (now - lastUpdateTime < updateInterval) return;
|
|
908
|
+
lastUpdateTime = now;
|
|
909
|
+
await streamAICard(
|
|
910
|
+
currentCardTarget as any,
|
|
911
|
+
`🔧 正在调用工具:${toolName}`,
|
|
912
|
+
false,
|
|
913
|
+
account.config as DingtalkConfig,
|
|
914
|
+
log,
|
|
915
|
+
(account.config as DingtalkConfig)?.cardContentVar as string || "msgContent",
|
|
916
|
+
);
|
|
917
|
+
log.debug(`[DingTalk][onToolStart] 工具进度写卡:${toolName}(phase=${payload?.phase})`);
|
|
918
|
+
} catch (e: any) {
|
|
919
|
+
if (!isQpsLimitError(e)) log.warn(`[DingTalk][onToolStart] 工具进度写卡失败:${e?.message || e}`);
|
|
920
|
+
}
|
|
921
|
+
},
|
|
880
922
|
// ===== 养成系统:监听 dws 命令执行 =====
|
|
881
923
|
onCommandOutput: (payload: {
|
|
882
924
|
itemId?: string;
|