@soimy/dingtalk 3.2.0 → 3.4.0
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/LICENSE +21 -0
- package/README.md +796 -42
- package/index.ts +62 -0
- package/package.json +4 -2
- package/src/access-control.ts +83 -0
- package/src/ack-reaction/dynamic-ack-reaction-controller.ts +271 -0
- package/src/ack-reaction/dynamic-ack-reaction-events.ts +123 -0
- package/src/ack-reaction/dynamic-ack-reaction-progress.ts +59 -0
- package/src/ack-reaction-classifier.ts +75 -0
- package/src/ack-reaction-service.ts +182 -0
- package/src/attachment-text-extractor.ts +148 -0
- package/src/card-callback-service.ts +119 -0
- package/src/card-draft-controller.ts +114 -0
- package/src/card-service.ts +666 -26
- package/src/channel.ts +455 -150
- package/src/config-schema.ts +64 -6
- package/src/config.ts +161 -5
- package/src/connection-manager.ts +354 -47
- package/src/dedup.ts +1 -0
- package/src/docs-service.ts +198 -0
- package/src/draft-stream-loop.ts +119 -0
- package/src/feedback-learning-service.ts +643 -0
- package/src/feedback-learning-store.ts +543 -0
- package/src/group-members-store.ts +48 -14
- package/src/inbound-handler.ts +1374 -259
- package/src/learning-command-service.ts +339 -0
- package/src/media-utils.ts +94 -50
- package/src/message-context-store.ts +787 -0
- package/src/message-utils.ts +487 -46
- package/src/messaging/quoted-context.ts +269 -0
- package/src/messaging/quoted-ref.ts +97 -0
- package/src/onboarding.ts +96 -1
- package/src/peer-id-registry.ts +102 -0
- package/src/persistence-store.ts +131 -0
- package/src/quoted-file-service.ts +385 -0
- package/src/reply-strategy-card.ts +225 -0
- package/src/reply-strategy-markdown.ts +55 -0
- package/src/reply-strategy-with-reaction.ts +190 -0
- package/src/reply-strategy.ts +72 -0
- package/src/send-service.ts +267 -45
- package/src/session-command-service.ts +147 -0
- package/src/session-lock.ts +2 -0
- package/src/session-peer-store.ts +77 -0
- package/src/session-routing.ts +33 -0
- package/src/targeting/agent-name-matcher.ts +148 -0
- package/src/targeting/agent-routing.ts +181 -0
- package/src/targeting/target-directory-adapter.ts +151 -0
- package/src/targeting/target-directory-store.ts +396 -0
- package/src/targeting/target-input.ts +62 -0
- package/src/types.ts +261 -28
- package/src/utils.ts +231 -12
package/src/types.ts
CHANGED
|
@@ -17,6 +17,12 @@ import type {
|
|
|
17
17
|
ChannelGatewayContext as SDKChannelGatewayContext,
|
|
18
18
|
ChannelPlugin as SDKChannelPlugin,
|
|
19
19
|
} from "openclaw/plugin-sdk";
|
|
20
|
+
import { mergeAccountWithDefaults } from "./config";
|
|
21
|
+
|
|
22
|
+
export type AckReactionMode = "off" | "emoji" | "kaomoji";
|
|
23
|
+
// Accept arbitrary strings for backward compatibility; the recommended
|
|
24
|
+
// explicit modes remain: "off" | "emoji" | "kaomoji".
|
|
25
|
+
export type AckReactionConfigValue = string;
|
|
20
26
|
|
|
21
27
|
export interface DingtalkPluginModule {
|
|
22
28
|
id: string;
|
|
@@ -38,15 +44,18 @@ export interface DingTalkConfig extends OpenClawConfig {
|
|
|
38
44
|
name?: string;
|
|
39
45
|
enabled?: boolean;
|
|
40
46
|
dmPolicy?: "open" | "pairing" | "allowlist";
|
|
41
|
-
groupPolicy?: "open" | "allowlist";
|
|
47
|
+
groupPolicy?: "open" | "allowlist" | "disabled";
|
|
42
48
|
allowFrom?: string[];
|
|
49
|
+
groupAllowFrom?: string[];
|
|
50
|
+
displayNameResolution?: "disabled" | "all";
|
|
43
51
|
mediaUrlAllowlist?: string[];
|
|
44
|
-
|
|
52
|
+
journalTTLDays?: number;
|
|
53
|
+
ackReaction?: AckReactionConfigValue;
|
|
45
54
|
debug?: boolean;
|
|
46
55
|
messageType?: "markdown" | "card";
|
|
47
56
|
cardTemplateId?: string;
|
|
48
57
|
cardTemplateKey?: string;
|
|
49
|
-
groups?: Record<string, { systemPrompt?: string }>;
|
|
58
|
+
groups?: Record<string, { systemPrompt?: string; requireMention?: boolean; groupAllowFrom?: string[] }>;
|
|
50
59
|
accounts?: Record<string, DingTalkConfig>;
|
|
51
60
|
// Connection robustness configuration
|
|
52
61
|
maxConnectionAttempts?: number;
|
|
@@ -55,14 +64,40 @@ export interface DingTalkConfig extends OpenClawConfig {
|
|
|
55
64
|
reconnectJitter?: number;
|
|
56
65
|
/** Maximum number of runtime reconnect cycles before giving up (default: 10) */
|
|
57
66
|
maxReconnectCycles?: number;
|
|
67
|
+
/** Maximum time (ms) for a single reconnect cycle before giving up and starting a new cycle (default: 50000) */
|
|
68
|
+
reconnectDeadlineMs?: number;
|
|
58
69
|
/** Whether to use ConnectionManager; when false, use DWClient native keepAlive+autoReconnect */
|
|
59
70
|
useConnectionManager?: boolean;
|
|
60
71
|
/** Maximum inbound media file size in MB (overrides runtime default when set) */
|
|
61
72
|
mediaMaxMb?: number;
|
|
73
|
+
/** Whether to enable underlying stream keepAlive heartbeat; defaults to !useConnectionManager when omitted */
|
|
74
|
+
keepAlive?: boolean;
|
|
75
|
+
/** Bypass system/global HTTP(S) proxy for DingTalk outbound send/card/upload APIs */
|
|
76
|
+
bypassProxyForSend?: boolean;
|
|
62
77
|
proactivePermissionHint?: {
|
|
63
78
|
enabled?: boolean;
|
|
64
79
|
cooldownHours?: number;
|
|
65
80
|
};
|
|
81
|
+
/** Enable real-time card streaming (default false, true = 300ms throttled per-token updates) */
|
|
82
|
+
cardRealTimeStream?: boolean;
|
|
83
|
+
/** AICard degrade duration in milliseconds after trigger errors (default 30m) */
|
|
84
|
+
aicardDegradeMs?: number;
|
|
85
|
+
/** Enable local learning loop (events/reflections/session notes/global rules) */
|
|
86
|
+
learningEnabled?: boolean;
|
|
87
|
+
/** Auto-apply generated reflections into session notes/global rules (default false) */
|
|
88
|
+
learningAutoApply?: boolean;
|
|
89
|
+
/** Session learning note TTL in milliseconds (default 6h) */
|
|
90
|
+
learningNoteTtlMs?: number;
|
|
91
|
+
/** @deprecated Use learningEnabled */
|
|
92
|
+
feedbackLearningEnabled?: boolean;
|
|
93
|
+
/** @deprecated Use learningAutoApply */
|
|
94
|
+
feedbackLearningAutoApply?: boolean;
|
|
95
|
+
/** @deprecated Use learningNoteTtlMs */
|
|
96
|
+
feedbackLearningNoteTtlMs?: number;
|
|
97
|
+
/** Whether to convert markdown tables to plain text for better rendering on some clients (default: true) */
|
|
98
|
+
convertMarkdownTables?: boolean;
|
|
99
|
+
/** @mention the sender after card finalization in group chats; value is the message text */
|
|
100
|
+
cardAtSender?: string;
|
|
66
101
|
}
|
|
67
102
|
|
|
68
103
|
/**
|
|
@@ -77,15 +112,18 @@ export interface DingTalkChannelConfig {
|
|
|
77
112
|
agentId?: string;
|
|
78
113
|
name?: string;
|
|
79
114
|
dmPolicy?: "open" | "pairing" | "allowlist";
|
|
80
|
-
groupPolicy?: "open" | "allowlist";
|
|
115
|
+
groupPolicy?: "open" | "allowlist" | "disabled";
|
|
81
116
|
allowFrom?: string[];
|
|
117
|
+
groupAllowFrom?: string[];
|
|
118
|
+
displayNameResolution?: "disabled" | "all";
|
|
82
119
|
mediaUrlAllowlist?: string[];
|
|
83
|
-
|
|
120
|
+
journalTTLDays?: number;
|
|
121
|
+
ackReaction?: AckReactionConfigValue;
|
|
84
122
|
debug?: boolean;
|
|
85
123
|
messageType?: "markdown" | "card";
|
|
86
124
|
cardTemplateId?: string;
|
|
87
125
|
cardTemplateKey?: string;
|
|
88
|
-
groups?: Record<string, { systemPrompt?: string }>;
|
|
126
|
+
groups?: Record<string, { systemPrompt?: string; requireMention?: boolean; groupAllowFrom?: string[] }>;
|
|
89
127
|
accounts?: Record<string, DingTalkConfig>;
|
|
90
128
|
maxConnectionAttempts?: number;
|
|
91
129
|
initialReconnectDelay?: number;
|
|
@@ -93,14 +131,40 @@ export interface DingTalkChannelConfig {
|
|
|
93
131
|
reconnectJitter?: number;
|
|
94
132
|
/** Maximum number of runtime reconnect cycles before giving up (default: 10) */
|
|
95
133
|
maxReconnectCycles?: number;
|
|
134
|
+
/** Maximum time (ms) for a single reconnect cycle before giving up and starting a new cycle (default: 50000) */
|
|
135
|
+
reconnectDeadlineMs?: number;
|
|
96
136
|
/** Whether to use ConnectionManager; when false, use DWClient native keepAlive+autoReconnect */
|
|
97
137
|
useConnectionManager?: boolean;
|
|
98
138
|
/** Maximum inbound media file size in MB (overrides runtime default when set) */
|
|
99
139
|
mediaMaxMb?: number;
|
|
140
|
+
/** Whether to enable underlying stream keepAlive heartbeat; defaults to !useConnectionManager when omitted */
|
|
141
|
+
keepAlive?: boolean;
|
|
142
|
+
/** Bypass system/global HTTP(S) proxy for DingTalk outbound send/card/upload APIs */
|
|
143
|
+
bypassProxyForSend?: boolean;
|
|
100
144
|
proactivePermissionHint?: {
|
|
101
145
|
enabled?: boolean;
|
|
102
146
|
cooldownHours?: number;
|
|
103
147
|
};
|
|
148
|
+
/** Enable real-time card streaming (default false, true = 300ms throttled per-token updates) */
|
|
149
|
+
cardRealTimeStream?: boolean;
|
|
150
|
+
/** AICard degrade duration in milliseconds after trigger errors (default 30m) */
|
|
151
|
+
aicardDegradeMs?: number;
|
|
152
|
+
/** Enable local learning loop (events/reflections/session notes/global rules) */
|
|
153
|
+
learningEnabled?: boolean;
|
|
154
|
+
/** Auto-apply generated reflections into session notes/global rules (default false) */
|
|
155
|
+
learningAutoApply?: boolean;
|
|
156
|
+
/** Session learning note TTL in milliseconds (default 6h) */
|
|
157
|
+
learningNoteTtlMs?: number;
|
|
158
|
+
/** @deprecated Use learningEnabled */
|
|
159
|
+
feedbackLearningEnabled?: boolean;
|
|
160
|
+
/** @deprecated Use learningAutoApply */
|
|
161
|
+
feedbackLearningAutoApply?: boolean;
|
|
162
|
+
/** @deprecated Use learningNoteTtlMs */
|
|
163
|
+
feedbackLearningNoteTtlMs?: number;
|
|
164
|
+
/** Whether to convert markdown tables to plain text for better rendering on some clients (default: true) */
|
|
165
|
+
convertMarkdownTables?: boolean;
|
|
166
|
+
/** @mention the sender after card finalization in group chats; value is the message text */
|
|
167
|
+
cardAtSender?: string;
|
|
104
168
|
}
|
|
105
169
|
|
|
106
170
|
/**
|
|
@@ -145,6 +209,14 @@ export interface MediaFile {
|
|
|
145
209
|
mimeType: string;
|
|
146
210
|
}
|
|
147
211
|
|
|
212
|
+
export interface DocInfo {
|
|
213
|
+
docId: string;
|
|
214
|
+
title: string;
|
|
215
|
+
docType: string;
|
|
216
|
+
creatorId?: string;
|
|
217
|
+
updatedAt?: number | string;
|
|
218
|
+
}
|
|
219
|
+
|
|
148
220
|
/**
|
|
149
221
|
* DingTalk incoming message (Stream mode)
|
|
150
222
|
*/
|
|
@@ -152,19 +224,35 @@ export interface DingTalkInboundMessage {
|
|
|
152
224
|
msgId: string;
|
|
153
225
|
msgtype: string;
|
|
154
226
|
createAt: number;
|
|
227
|
+
/**
|
|
228
|
+
* @ 提及的用户列表(消息顶层,与 text 同级)
|
|
229
|
+
* 包含通过 @picker 选中的所有真实钉钉用户和机器人
|
|
230
|
+
* 格式: [{ dingtalkId: "$:LWCP_v1:$xxx" }]
|
|
231
|
+
*/
|
|
232
|
+
atUsers?: Array<{
|
|
233
|
+
dingtalkId: string;
|
|
234
|
+
}>;
|
|
155
235
|
text?: {
|
|
156
236
|
content: string;
|
|
157
237
|
isReplyMsg?: boolean; // 是否是回复消息
|
|
158
238
|
repliedMsg?: {
|
|
159
|
-
|
|
239
|
+
msgType?: string;
|
|
240
|
+
msgId?: string;
|
|
241
|
+
senderId?: string;
|
|
242
|
+
createdAt?: number;
|
|
160
243
|
content?: {
|
|
161
244
|
text?: string;
|
|
245
|
+
downloadCode?: string;
|
|
246
|
+
fileName?: string;
|
|
247
|
+
biz_custom_action_url?: string;
|
|
162
248
|
richText?: Array<{
|
|
163
249
|
msgType?: string;
|
|
164
250
|
type?: string;
|
|
165
251
|
content?: string;
|
|
252
|
+
text?: string;
|
|
166
253
|
code?: string;
|
|
167
254
|
atName?: string;
|
|
255
|
+
downloadCode?: string;
|
|
168
256
|
}>;
|
|
169
257
|
};
|
|
170
258
|
};
|
|
@@ -173,13 +261,17 @@ export interface DingTalkInboundMessage {
|
|
|
173
261
|
downloadCode?: string;
|
|
174
262
|
fileName?: string;
|
|
175
263
|
recognition?: string;
|
|
264
|
+
spaceId?: string;
|
|
265
|
+
fileId?: string;
|
|
266
|
+
biz_custom_action_url?: string;
|
|
176
267
|
richText?: Array<{
|
|
177
268
|
type: string;
|
|
178
269
|
text?: string;
|
|
179
270
|
atName?: string;
|
|
180
|
-
|
|
271
|
+
atUserId?: string;
|
|
272
|
+
downloadCode?: string;
|
|
181
273
|
}>;
|
|
182
|
-
quoteContent?: string;
|
|
274
|
+
quoteContent?: string;
|
|
183
275
|
};
|
|
184
276
|
// Legacy 引用格式
|
|
185
277
|
quoteMessage?: {
|
|
@@ -191,6 +283,7 @@ export interface DingTalkInboundMessage {
|
|
|
191
283
|
};
|
|
192
284
|
// 富媒体引用,仅有消息ID的情况(包括手机端和PC端)
|
|
193
285
|
originalMsgId?: string;
|
|
286
|
+
originalProcessQueryKey?: string;
|
|
194
287
|
conversationType: string;
|
|
195
288
|
conversationId: string;
|
|
196
289
|
conversationTitle?: string;
|
|
@@ -201,14 +294,83 @@ export interface DingTalkInboundMessage {
|
|
|
201
294
|
sessionWebhook: string;
|
|
202
295
|
}
|
|
203
296
|
|
|
297
|
+
export type QuotedRefKey = "msgId" | "processQueryKey" | "messageId" | "outTrackId" | "cardInstanceId";
|
|
298
|
+
|
|
299
|
+
export type AttachmentTextSource = "text" | "html" | "pdf" | "docx";
|
|
300
|
+
|
|
301
|
+
export interface QuotedRef {
|
|
302
|
+
targetDirection: "inbound" | "outbound";
|
|
303
|
+
key?: QuotedRefKey;
|
|
304
|
+
value?: string;
|
|
305
|
+
fallbackCreatedAt?: number;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Quoted/reply message metadata extracted from repliedMsg.
|
|
310
|
+
* Populated when isReplyMsg is true; downstream handlers use these fields
|
|
311
|
+
* to download quoted media or look up cached card content.
|
|
312
|
+
*/
|
|
313
|
+
export interface QuotedInfo {
|
|
314
|
+
mediaDownloadCode?: string;
|
|
315
|
+
mediaType?: string;
|
|
316
|
+
isQuotedFile?: boolean;
|
|
317
|
+
isQuotedCard?: boolean;
|
|
318
|
+
isQuotedDocCard?: boolean;
|
|
319
|
+
cardCreatedAt?: number;
|
|
320
|
+
processQueryKey?: string;
|
|
321
|
+
fileCreatedAt?: number;
|
|
322
|
+
msgId?: string;
|
|
323
|
+
previewText?: string;
|
|
324
|
+
previewMessageType?: string;
|
|
325
|
+
previewFileName?: string;
|
|
326
|
+
previewSenderId?: string;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* @ 提及信息
|
|
331
|
+
*/
|
|
332
|
+
export interface AtMention {
|
|
333
|
+
/** @ 显示的名字(去除 @ 前缀) */
|
|
334
|
+
name: string;
|
|
335
|
+
/** 钉钉用户 ID(如果是 @ 真人) */
|
|
336
|
+
userId?: string;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Agent 名字匹配结果
|
|
341
|
+
*/
|
|
342
|
+
export interface AgentNameMatch {
|
|
343
|
+
/** 匹配到的 agent ID */
|
|
344
|
+
agentId: string;
|
|
345
|
+
/** 匹配来源:'name' | 'id' */
|
|
346
|
+
matchSource: "name" | "id";
|
|
347
|
+
/** 匹配到的名字 */
|
|
348
|
+
matchedName: string;
|
|
349
|
+
}
|
|
350
|
+
|
|
204
351
|
/**
|
|
205
352
|
* Extracted message content for unified processing
|
|
206
353
|
*/
|
|
207
354
|
export interface MessageContent {
|
|
208
355
|
text: string;
|
|
209
356
|
mediaPath?: string;
|
|
357
|
+
mediaPaths?: string[];
|
|
210
358
|
mediaType?: string;
|
|
359
|
+
mediaTypes?: string[];
|
|
211
360
|
messageType: string;
|
|
361
|
+
docSpaceId?: string;
|
|
362
|
+
docFileId?: string;
|
|
363
|
+
quoted?: QuotedInfo;
|
|
364
|
+
/** @ 提及列表(从文本或 richText 提取的名字) */
|
|
365
|
+
atMentions?: AtMention[];
|
|
366
|
+
/**
|
|
367
|
+
* 通过 @picker 选中的真实钉钉用户的 dingtalkId 列表
|
|
368
|
+
* - 仅包含真实钉钉用户和机器人,不包含 agent 名
|
|
369
|
+
* - 用于排除真人:如果 atMentions 中的名字匹配到 agent,说明是 agent;
|
|
370
|
+
* 如果没匹配到 agent 且有 atUserDingtalkIds,则可能是真人
|
|
371
|
+
* - 注意:无法将 dingtalkId 映射到具体名字,因为 webhook 不提供此映射
|
|
372
|
+
*/
|
|
373
|
+
atUserDingtalkIds?: string[];
|
|
212
374
|
}
|
|
213
375
|
|
|
214
376
|
/**
|
|
@@ -218,14 +380,25 @@ export interface SendMessageOptions {
|
|
|
218
380
|
title?: string;
|
|
219
381
|
useMarkdown?: boolean;
|
|
220
382
|
atUserId?: string | null;
|
|
221
|
-
log?:
|
|
383
|
+
log?: Logger;
|
|
384
|
+
conversationId?: string;
|
|
222
385
|
mediaPath?: string;
|
|
223
386
|
filePath?: string;
|
|
224
387
|
mediaUrl?: string;
|
|
225
388
|
mediaType?: "image" | "voice" | "video" | "file";
|
|
226
389
|
accountId?: string;
|
|
227
|
-
|
|
228
|
-
|
|
390
|
+
storePath?: string;
|
|
391
|
+
cardUpdateMode?: "append";
|
|
392
|
+
quotedRef?: QuotedRef;
|
|
393
|
+
/** Force markdown/text delivery even when messageType is "card". Bypasses card
|
|
394
|
+
* creation while preserving journal writes and other side-effects. */
|
|
395
|
+
forceMarkdown?: boolean;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
export interface DingTalkTrackingMetadata {
|
|
399
|
+
processQueryKey?: string;
|
|
400
|
+
outTrackId?: string;
|
|
401
|
+
cardInstanceId?: string;
|
|
229
402
|
}
|
|
230
403
|
|
|
231
404
|
/**
|
|
@@ -246,6 +419,18 @@ export interface SessionWebhookResponse {
|
|
|
246
419
|
};
|
|
247
420
|
}
|
|
248
421
|
|
|
422
|
+
/**
|
|
423
|
+
* Sub-agent routing options for parameterized message handling
|
|
424
|
+
*/
|
|
425
|
+
export interface SubAgentOptions {
|
|
426
|
+
/** The agent ID to route to */
|
|
427
|
+
agentId: string;
|
|
428
|
+
/** Prefix to add to response messages (e.g., "[AgentName] ") */
|
|
429
|
+
responsePrefix: string;
|
|
430
|
+
/** The matched agent name */
|
|
431
|
+
matchedName: string;
|
|
432
|
+
}
|
|
433
|
+
|
|
249
434
|
/**
|
|
250
435
|
* Message handler parameters
|
|
251
436
|
*/
|
|
@@ -254,8 +439,21 @@ export interface HandleDingTalkMessageParams {
|
|
|
254
439
|
accountId: string;
|
|
255
440
|
data: DingTalkInboundMessage;
|
|
256
441
|
sessionWebhook: string;
|
|
257
|
-
log?:
|
|
442
|
+
log?: Logger;
|
|
258
443
|
dingtalkConfig: DingTalkConfig;
|
|
444
|
+
/**
|
|
445
|
+
* When set, routes message to the specified sub-agent instead of main agent.
|
|
446
|
+
* This enables reuse of the main message handling logic for sub-agents.
|
|
447
|
+
*/
|
|
448
|
+
subAgentOptions?: SubAgentOptions;
|
|
449
|
+
/**
|
|
450
|
+
* Pre-downloaded media for sub-agent calls.
|
|
451
|
+
* When set, skips media download to avoid duplication in recursive calls.
|
|
452
|
+
*/
|
|
453
|
+
preDownloadedMedia?: {
|
|
454
|
+
mediaPath?: string;
|
|
455
|
+
mediaType?: string;
|
|
456
|
+
};
|
|
259
457
|
}
|
|
260
458
|
|
|
261
459
|
/**
|
|
@@ -295,7 +493,7 @@ export interface ResolvedAccount {
|
|
|
295
493
|
export interface AxiosRequestConfig {
|
|
296
494
|
url?: string;
|
|
297
495
|
method?: string;
|
|
298
|
-
data?:
|
|
496
|
+
data?: unknown;
|
|
299
497
|
headers?: Record<string, string>;
|
|
300
498
|
responseType?: "arraybuffer" | "json" | "text";
|
|
301
499
|
}
|
|
@@ -303,7 +501,7 @@ export interface AxiosRequestConfig {
|
|
|
303
501
|
/**
|
|
304
502
|
* HTTP response from axios
|
|
305
503
|
*/
|
|
306
|
-
export interface AxiosResponse<T =
|
|
504
|
+
export interface AxiosResponse<T = unknown> {
|
|
307
505
|
data: T;
|
|
308
506
|
status: number;
|
|
309
507
|
statusText: string;
|
|
@@ -325,15 +523,15 @@ export interface StreamCallbackResponse {
|
|
|
325
523
|
*/
|
|
326
524
|
export interface ReplyDispatchContext {
|
|
327
525
|
responsePrefix?: string;
|
|
328
|
-
deliver: (payload:
|
|
526
|
+
deliver: (payload: unknown) => Promise<{ ok: boolean; error?: string }>;
|
|
329
527
|
}
|
|
330
528
|
|
|
331
529
|
/**
|
|
332
530
|
* Reply dispatcher result
|
|
333
531
|
*/
|
|
334
532
|
export interface ReplyDispatcherResult {
|
|
335
|
-
dispatcher:
|
|
336
|
-
replyOptions:
|
|
533
|
+
dispatcher: unknown;
|
|
534
|
+
replyOptions: unknown;
|
|
337
535
|
markDispatchIdle: () => void;
|
|
338
536
|
}
|
|
339
537
|
|
|
@@ -343,7 +541,7 @@ export interface ReplyDispatcherResult {
|
|
|
343
541
|
export interface RetryOptions {
|
|
344
542
|
maxRetries?: number;
|
|
345
543
|
baseDelayMs?: number;
|
|
346
|
-
log?:
|
|
544
|
+
log?: Logger;
|
|
347
545
|
}
|
|
348
546
|
|
|
349
547
|
/**
|
|
@@ -397,7 +595,7 @@ export interface TargetResolutionResult {
|
|
|
397
595
|
*/
|
|
398
596
|
export interface ResolveTargetParams {
|
|
399
597
|
to?: string | null;
|
|
400
|
-
[key: string]:
|
|
598
|
+
[key: string]: unknown;
|
|
401
599
|
}
|
|
402
600
|
|
|
403
601
|
/**
|
|
@@ -408,7 +606,7 @@ export interface SendTextParams {
|
|
|
408
606
|
to: string;
|
|
409
607
|
text: string;
|
|
410
608
|
accountId?: string;
|
|
411
|
-
[key: string]:
|
|
609
|
+
[key: string]: unknown;
|
|
412
610
|
}
|
|
413
611
|
|
|
414
612
|
/**
|
|
@@ -419,7 +617,7 @@ export interface SendMediaParams {
|
|
|
419
617
|
to: string;
|
|
420
618
|
mediaPath: string;
|
|
421
619
|
accountId?: string;
|
|
422
|
-
[key: string]:
|
|
620
|
+
[key: string]: unknown;
|
|
423
621
|
}
|
|
424
622
|
|
|
425
623
|
/**
|
|
@@ -428,8 +626,8 @@ export interface SendMediaParams {
|
|
|
428
626
|
export interface DingTalkOutboundHandler {
|
|
429
627
|
deliveryMode: "direct" | "queued" | "batch";
|
|
430
628
|
resolveTarget: (params: ResolveTargetParams) => TargetResolutionResult;
|
|
431
|
-
sendText: (params: SendTextParams) => Promise<{ ok: boolean; data?:
|
|
432
|
-
sendMedia?: (params: SendMediaParams) => Promise<{ ok: boolean; data?:
|
|
629
|
+
sendText: (params: SendTextParams) => Promise<{ ok: boolean; data?: unknown; error?: unknown }>;
|
|
630
|
+
sendMedia?: (params: SendMediaParams) => Promise<{ ok: boolean; data?: unknown; error?: unknown }>;
|
|
433
631
|
}
|
|
434
632
|
|
|
435
633
|
/**
|
|
@@ -452,13 +650,18 @@ export type AICardState = (typeof AICardStatus)[keyof typeof AICardStatus];
|
|
|
452
650
|
*/
|
|
453
651
|
export interface AICardInstance {
|
|
454
652
|
cardInstanceId: string;
|
|
653
|
+
processQueryKey?: string;
|
|
455
654
|
accessToken: string;
|
|
456
655
|
conversationId: string;
|
|
656
|
+
contextConversationId?: string;
|
|
657
|
+
accountId?: string;
|
|
658
|
+
storePath?: string;
|
|
457
659
|
createdAt: number;
|
|
458
660
|
lastUpdated: number;
|
|
459
661
|
state: AICardState; // Current card state: PROCESSING, INPUTING, FINISHED, FAILED
|
|
460
662
|
config?: DingTalkConfig; // Store config reference for token refresh
|
|
461
663
|
lastStreamedContent?: string;
|
|
664
|
+
outTrackId?: string;
|
|
462
665
|
}
|
|
463
666
|
|
|
464
667
|
/**
|
|
@@ -485,6 +688,14 @@ export enum ConnectionState {
|
|
|
485
688
|
FAILED = "FAILED",
|
|
486
689
|
}
|
|
487
690
|
|
|
691
|
+
/**
|
|
692
|
+
* Factory function that creates a fresh DWClient with callback listeners
|
|
693
|
+
* already registered. Used by ConnectionManager to create a new client
|
|
694
|
+
* on reconnection so the new WebSocket can start receiving messages
|
|
695
|
+
* while the old zombie socket is still being cleaned up.
|
|
696
|
+
*/
|
|
697
|
+
export type StreamClientFactory = () => import("dingtalk-stream").DWClient;
|
|
698
|
+
|
|
488
699
|
/**
|
|
489
700
|
* Connection manager configuration
|
|
490
701
|
*/
|
|
@@ -495,6 +706,8 @@ export interface ConnectionManagerConfig {
|
|
|
495
706
|
jitter: number;
|
|
496
707
|
/** Maximum number of runtime reconnect cycles before giving up (default: 10) */
|
|
497
708
|
maxReconnectCycles?: number;
|
|
709
|
+
/** Maximum time (ms) for a single reconnect cycle before giving up and starting a new cycle (default: 50000) */
|
|
710
|
+
reconnectDeadlineMs?: number;
|
|
498
711
|
/** Callback invoked when connection state changes */
|
|
499
712
|
onStateChange?: (state: ConnectionState, error?: string) => void;
|
|
500
713
|
}
|
|
@@ -568,7 +781,10 @@ export function resolveDingTalkAccount(
|
|
|
568
781
|
dmPolicy: dingtalk?.dmPolicy,
|
|
569
782
|
groupPolicy: dingtalk?.groupPolicy,
|
|
570
783
|
allowFrom: dingtalk?.allowFrom,
|
|
571
|
-
|
|
784
|
+
groupAllowFrom: dingtalk?.groupAllowFrom,
|
|
785
|
+
displayNameResolution: dingtalk?.displayNameResolution,
|
|
786
|
+
journalTTLDays: dingtalk?.journalTTLDays,
|
|
787
|
+
ackReaction: dingtalk?.ackReaction,
|
|
572
788
|
debug: dingtalk?.debug,
|
|
573
789
|
messageType: dingtalk?.messageType,
|
|
574
790
|
cardTemplateId: dingtalk?.cardTemplateId,
|
|
@@ -580,9 +796,22 @@ export function resolveDingTalkAccount(
|
|
|
580
796
|
maxReconnectDelay: dingtalk?.maxReconnectDelay,
|
|
581
797
|
reconnectJitter: dingtalk?.reconnectJitter,
|
|
582
798
|
maxReconnectCycles: dingtalk?.maxReconnectCycles,
|
|
799
|
+
reconnectDeadlineMs: dingtalk?.reconnectDeadlineMs,
|
|
583
800
|
useConnectionManager: dingtalk?.useConnectionManager,
|
|
584
801
|
mediaMaxMb: dingtalk?.mediaMaxMb,
|
|
802
|
+
keepAlive: dingtalk?.keepAlive,
|
|
803
|
+
bypassProxyForSend: dingtalk?.bypassProxyForSend,
|
|
585
804
|
proactivePermissionHint: dingtalk?.proactivePermissionHint,
|
|
805
|
+
cardRealTimeStream: dingtalk?.cardRealTimeStream,
|
|
806
|
+
aicardDegradeMs: dingtalk?.aicardDegradeMs,
|
|
807
|
+
learningEnabled: dingtalk?.learningEnabled ?? dingtalk?.feedbackLearningEnabled,
|
|
808
|
+
learningAutoApply: dingtalk?.learningAutoApply ?? dingtalk?.feedbackLearningAutoApply,
|
|
809
|
+
learningNoteTtlMs: dingtalk?.learningNoteTtlMs ?? dingtalk?.feedbackLearningNoteTtlMs,
|
|
810
|
+
feedbackLearningEnabled: dingtalk?.feedbackLearningEnabled,
|
|
811
|
+
feedbackLearningAutoApply: dingtalk?.feedbackLearningAutoApply,
|
|
812
|
+
feedbackLearningNoteTtlMs: dingtalk?.feedbackLearningNoteTtlMs,
|
|
813
|
+
convertMarkdownTables: dingtalk?.convertMarkdownTables,
|
|
814
|
+
cardAtSender: dingtalk?.cardAtSender,
|
|
586
815
|
};
|
|
587
816
|
return {
|
|
588
817
|
...config,
|
|
@@ -591,13 +820,17 @@ export function resolveDingTalkAccount(
|
|
|
591
820
|
};
|
|
592
821
|
}
|
|
593
822
|
|
|
594
|
-
// If named account,
|
|
823
|
+
// If named account, merge channel-level defaults with account-level overrides
|
|
595
824
|
const accountConfig = dingtalk?.accounts?.[id];
|
|
596
825
|
if (accountConfig) {
|
|
826
|
+
const merged = mergeAccountWithDefaults(
|
|
827
|
+
dingtalk as DingTalkConfig,
|
|
828
|
+
accountConfig,
|
|
829
|
+
);
|
|
597
830
|
return {
|
|
598
|
-
...
|
|
831
|
+
...merged,
|
|
599
832
|
accountId: id,
|
|
600
|
-
configured: Boolean(
|
|
833
|
+
configured: Boolean(merged.clientId && merged.clientSecret),
|
|
601
834
|
};
|
|
602
835
|
}
|
|
603
836
|
|