@soimy/dingtalk 3.6.8 → 3.6.10
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.d.ts +3 -12
- package/dist/index.js +1030 -318
- package/dist/src/access-control.d.ts +0 -1
- package/dist/src/ack-reaction/dynamic-ack-reaction-controller.d.ts +0 -1
- package/dist/src/ack-reaction/dynamic-ack-reaction-events.d.ts +0 -1
- package/dist/src/ack-reaction/dynamic-ack-reaction-progress.d.ts +0 -1
- package/dist/src/ack-reaction-classifier.d.ts +0 -1
- package/dist/src/ack-reaction-service.d.ts +0 -1
- package/dist/src/auth.d.ts +0 -1
- package/dist/src/card/ask-user-question-context.d.ts +0 -1
- package/dist/src/card/ask-user-question-store.d.ts +0 -1
- package/dist/src/card/ask-user-question.d.ts +0 -1
- package/dist/src/card/card-action-handler.d.ts +0 -1
- package/dist/src/card/card-markdown-image-reroute.d.ts +0 -1
- package/dist/src/card/card-run-registry.d.ts +0 -1
- package/dist/src/card/card-stop-handler.d.ts +0 -1
- package/dist/src/card/card-streaming-mode.d.ts +0 -1
- package/dist/src/card/card-template.d.ts +0 -1
- package/dist/src/card/reasoning-answer-split.d.ts +0 -1
- package/dist/src/card/reasoning-block-assembler.d.ts +0 -1
- package/dist/src/card/statusline-renderer.d.ts +0 -1
- package/dist/src/card/task-model-metadata.d.ts +0 -1
- package/dist/src/card-callback-service.d.ts +0 -1
- package/dist/src/card-draft-controller.d.ts +0 -1
- package/dist/src/card-service.d.ts +0 -1
- package/dist/src/channel.d.ts +0 -1
- package/dist/src/command/card-stop-command.d.ts +0 -1
- package/dist/src/command/inbound-command-dispatch-service.d.ts +0 -1
- package/dist/src/config-schema.d.ts +0 -1
- package/dist/src/config.d.ts +0 -1
- package/dist/src/connection-manager.d.ts +0 -1
- package/dist/src/dedup.d.ts +0 -1
- package/dist/src/device-registration.d.ts +0 -1
- package/dist/src/docs-service.d.ts +0 -1
- package/dist/src/draft-stream-loop.d.ts +0 -1
- package/dist/src/feedback-learning-service.d.ts +0 -1
- package/dist/src/feedback-learning-store.d.ts +0 -1
- package/dist/src/gateway/channel-gateway.d.ts +0 -1
- package/dist/src/gateway/inbound-session-queue-dispatcher.d.ts +0 -1
- package/dist/src/gateway/inbound-session-queue.d.ts +0 -1
- package/dist/src/gateway/reply-session-conflict.d.ts +0 -1
- package/dist/src/http-client.d.ts +0 -1
- package/dist/src/inbound-handler.d.ts +0 -1
- package/dist/src/learning-command-service.d.ts +0 -1
- package/dist/src/logger-context.d.ts +0 -1
- package/dist/src/media-utils.d.ts +0 -1
- package/dist/src/message-context-store.d.ts +0 -1
- package/dist/src/message-utils.d.ts +0 -1
- package/dist/src/messaging/attachment-text-extractor.d.ts +0 -1
- package/dist/src/messaging/btw-deliver.d.ts +0 -1
- package/dist/src/messaging/channel-actions.d.ts +0 -1
- package/dist/src/messaging/channel-outbound.d.ts +0 -1
- package/dist/src/messaging/quoted-context.d.ts +0 -1
- package/dist/src/messaging/quoted-file-service.d.ts +0 -1
- package/dist/src/messaging/quoted-ref.d.ts +0 -1
- package/dist/src/onboarding.d.ts +0 -1
- package/dist/src/path-utils.d.ts +0 -1
- package/dist/src/peer-id-registry.d.ts +0 -12
- package/dist/src/persistence-store.d.ts +0 -1
- package/dist/src/platform/channel-status.d.ts +0 -1
- package/dist/src/plugin-sdk-channel-actions-augment.d.ts +0 -1
- package/dist/src/proactive-risk-registry.d.ts +0 -1
- package/dist/src/reply-strategy-card.d.ts +0 -1
- package/dist/src/reply-strategy-markdown.d.ts +0 -1
- package/dist/src/reply-strategy-types.d.ts +0 -1
- package/dist/src/reply-strategy-with-reaction.d.ts +0 -1
- package/dist/src/reply-strategy.d.ts +0 -1
- package/dist/src/run-usage-store.d.ts +0 -1
- package/dist/src/runtime.d.ts +0 -1
- package/dist/src/secret-input.d.ts +3 -3
- package/dist/src/send-service.d.ts +0 -1
- package/dist/src/session-command-service.d.ts +0 -1
- package/dist/src/session-lock.d.ts +0 -1
- package/dist/src/session-peer-store.d.ts +0 -1
- package/dist/src/session-routing.d.ts +0 -1
- package/dist/src/session-state.d.ts +0 -1
- package/dist/src/signature.d.ts +0 -1
- package/dist/src/targeting/agent-name-matcher.d.ts +0 -1
- package/dist/src/targeting/agent-routing.d.ts +0 -1
- package/dist/src/targeting/group-members-store.d.ts +0 -1
- package/dist/src/targeting/target-directory-adapter.d.ts +0 -1
- package/dist/src/targeting/target-directory-store.d.ts +0 -1
- package/dist/src/targeting/target-input.d.ts +0 -1
- package/dist/src/types.d.ts +0 -1
- package/dist/src/utils.d.ts +0 -1
- package/index.ts +8 -2
- package/openclaw.plugin.json +4 -3
- package/package.json +10 -8
- package/src/channel.ts +4 -3
- package/src/gateway/channel-gateway.ts +67 -4
- package/src/messaging/channel-actions.ts +1 -4
- package/src/peer-id-registry.ts +0 -100
- package/src/secret-input.ts +33 -33
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -7
- package/dist/src/access-control.d.ts.map +0 -1
- package/dist/src/ack-reaction/dynamic-ack-reaction-controller.d.ts.map +0 -1
- package/dist/src/ack-reaction/dynamic-ack-reaction-events.d.ts.map +0 -1
- package/dist/src/ack-reaction/dynamic-ack-reaction-progress.d.ts.map +0 -1
- package/dist/src/ack-reaction-classifier.d.ts.map +0 -1
- package/dist/src/ack-reaction-service.d.ts.map +0 -1
- package/dist/src/auth.d.ts.map +0 -1
- package/dist/src/card/ask-user-question-context.d.ts.map +0 -1
- package/dist/src/card/ask-user-question-store.d.ts.map +0 -1
- package/dist/src/card/ask-user-question.d.ts.map +0 -1
- package/dist/src/card/card-action-handler.d.ts.map +0 -1
- package/dist/src/card/card-markdown-image-reroute.d.ts.map +0 -1
- package/dist/src/card/card-run-registry.d.ts.map +0 -1
- package/dist/src/card/card-stop-handler.d.ts.map +0 -1
- package/dist/src/card/card-streaming-mode.d.ts.map +0 -1
- package/dist/src/card/card-template.d.ts.map +0 -1
- package/dist/src/card/reasoning-answer-split.d.ts.map +0 -1
- package/dist/src/card/reasoning-block-assembler.d.ts.map +0 -1
- package/dist/src/card/statusline-renderer.d.ts.map +0 -1
- package/dist/src/card/task-model-metadata.d.ts.map +0 -1
- package/dist/src/card-callback-service.d.ts.map +0 -1
- package/dist/src/card-draft-controller.d.ts.map +0 -1
- package/dist/src/card-service.d.ts.map +0 -1
- package/dist/src/channel.d.ts.map +0 -1
- package/dist/src/command/card-stop-command.d.ts.map +0 -1
- package/dist/src/command/inbound-command-dispatch-service.d.ts.map +0 -1
- package/dist/src/config-schema.d.ts.map +0 -1
- package/dist/src/config.d.ts.map +0 -1
- package/dist/src/connection-manager.d.ts.map +0 -1
- package/dist/src/dedup.d.ts.map +0 -1
- package/dist/src/device-registration.d.ts.map +0 -1
- package/dist/src/docs-service.d.ts.map +0 -1
- package/dist/src/draft-stream-loop.d.ts.map +0 -1
- package/dist/src/feedback-learning-service.d.ts.map +0 -1
- package/dist/src/feedback-learning-store.d.ts.map +0 -1
- package/dist/src/gateway/channel-gateway.d.ts.map +0 -1
- package/dist/src/gateway/inbound-session-queue-dispatcher.d.ts.map +0 -1
- package/dist/src/gateway/inbound-session-queue.d.ts.map +0 -1
- package/dist/src/gateway/reply-session-conflict.d.ts.map +0 -1
- package/dist/src/http-client.d.ts.map +0 -1
- package/dist/src/inbound-handler.d.ts.map +0 -1
- package/dist/src/learning-command-service.d.ts.map +0 -1
- package/dist/src/logger-context.d.ts.map +0 -1
- package/dist/src/media-utils.d.ts.map +0 -1
- package/dist/src/message-context-store.d.ts.map +0 -1
- package/dist/src/message-utils.d.ts.map +0 -1
- package/dist/src/messaging/attachment-text-extractor.d.ts.map +0 -1
- package/dist/src/messaging/btw-deliver.d.ts.map +0 -1
- package/dist/src/messaging/channel-actions.d.ts.map +0 -1
- package/dist/src/messaging/channel-outbound.d.ts.map +0 -1
- package/dist/src/messaging/quoted-context.d.ts.map +0 -1
- package/dist/src/messaging/quoted-file-service.d.ts.map +0 -1
- package/dist/src/messaging/quoted-ref.d.ts.map +0 -1
- package/dist/src/onboarding.d.ts.map +0 -1
- package/dist/src/path-utils.d.ts.map +0 -1
- package/dist/src/peer-id-registry.d.ts.map +0 -1
- package/dist/src/persistence-store.d.ts.map +0 -1
- package/dist/src/platform/channel-status.d.ts.map +0 -1
- package/dist/src/plugin-sdk-channel-actions-augment.d.ts.map +0 -1
- package/dist/src/proactive-risk-registry.d.ts.map +0 -1
- package/dist/src/reply-strategy-card.d.ts.map +0 -1
- package/dist/src/reply-strategy-markdown.d.ts.map +0 -1
- package/dist/src/reply-strategy-types.d.ts.map +0 -1
- package/dist/src/reply-strategy-with-reaction.d.ts.map +0 -1
- package/dist/src/reply-strategy.d.ts.map +0 -1
- package/dist/src/run-usage-store.d.ts.map +0 -1
- package/dist/src/runtime.d.ts.map +0 -1
- package/dist/src/secret-input.d.ts.map +0 -1
- package/dist/src/send-service.d.ts.map +0 -1
- package/dist/src/session-command-service.d.ts.map +0 -1
- package/dist/src/session-lock.d.ts.map +0 -1
- package/dist/src/session-peer-store.d.ts.map +0 -1
- package/dist/src/session-routing.d.ts.map +0 -1
- package/dist/src/session-state.d.ts.map +0 -1
- package/dist/src/signature.d.ts.map +0 -1
- package/dist/src/targeting/agent-name-matcher.d.ts.map +0 -1
- package/dist/src/targeting/agent-routing.d.ts.map +0 -1
- package/dist/src/targeting/group-members-store.d.ts.map +0 -1
- package/dist/src/targeting/target-directory-adapter.d.ts.map +0 -1
- package/dist/src/targeting/target-directory-store.d.ts.map +0 -1
- package/dist/src/targeting/target-input.d.ts.map +0 -1
- package/dist/src/types.d.ts.map +0 -1
- package/dist/src/utils.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,51 +1,24 @@
|
|
|
1
1
|
// index.ts
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
defineChannelPluginEntry
|
|
4
|
+
} from "openclaw/plugin-sdk/core";
|
|
3
5
|
import { readStringParam as readStringParam2 } from "openclaw/plugin-sdk/param-readers";
|
|
4
6
|
|
|
5
7
|
// src/secret-input.ts
|
|
6
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
hasConfiguredSecretInput as hasConfiguredOpenClawSecretInput,
|
|
10
|
+
resolveConfiguredSecretInputString
|
|
11
|
+
} from "openclaw/plugin-sdk/secret-input-runtime";
|
|
7
12
|
import { z } from "zod";
|
|
8
13
|
|
|
9
|
-
// src/
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"Windows",
|
|
18
|
-
"Documents and Settings"
|
|
19
|
-
]);
|
|
20
|
-
function resolveRelativePath(input) {
|
|
21
|
-
const trimmed = input.trim();
|
|
22
|
-
if (!trimmed) {
|
|
23
|
-
return trimmed;
|
|
24
|
-
}
|
|
25
|
-
const segments = (value) => value.split(/[\\/]+/).filter(Boolean);
|
|
26
|
-
const pathSegments = segments(trimmed);
|
|
27
|
-
const firstSegment = pathSegments[0];
|
|
28
|
-
if (trimmed === "~") {
|
|
29
|
-
return path.resolve(os.homedir());
|
|
30
|
-
}
|
|
31
|
-
if (trimmed.startsWith("~/") || trimmed.startsWith("~\\")) {
|
|
32
|
-
return path.resolve(os.homedir(), ...segments(trimmed.slice(2)));
|
|
33
|
-
}
|
|
34
|
-
if (process.platform === "win32") {
|
|
35
|
-
if (/^[a-zA-Z]:[\\/]/.test(trimmed)) {
|
|
36
|
-
return path.win32.normalize(trimmed);
|
|
37
|
-
}
|
|
38
|
-
if (firstSegment && /^[a-zA-Z]:$/.test(firstSegment)) {
|
|
39
|
-
return path.win32.resolve(`${firstSegment}\\`, ...pathSegments.slice(1));
|
|
40
|
-
}
|
|
41
|
-
if (firstSegment && WINDOWS_ROOT_DIRECTORIES.has(firstSegment)) {
|
|
42
|
-
return path.win32.resolve("\\", ...pathSegments);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
if (/^[\\/]/.test(trimmed)) {
|
|
46
|
-
return path.resolve(path.sep, ...pathSegments);
|
|
47
|
-
}
|
|
48
|
-
return path.resolve(process.cwd(), ...pathSegments);
|
|
14
|
+
// src/runtime.ts
|
|
15
|
+
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
|
16
|
+
var runtimeStore = createPluginRuntimeStore("DingTalk runtime not initialized");
|
|
17
|
+
function setDingTalkRuntime(next) {
|
|
18
|
+
runtimeStore.setRuntime(next);
|
|
19
|
+
}
|
|
20
|
+
function getDingTalkRuntime() {
|
|
21
|
+
return runtimeStore.getRuntime();
|
|
49
22
|
}
|
|
50
23
|
|
|
51
24
|
// src/secret-input.ts
|
|
@@ -62,16 +35,6 @@ function buildSecretInputFailure(value, reason) {
|
|
|
62
35
|
function formatSecretInputResolutionFailure(failure) {
|
|
63
36
|
return `${failure.source}:${failure.provider}:${failure.id} - ${failure.reason}`;
|
|
64
37
|
}
|
|
65
|
-
function buildSecretInputSchema() {
|
|
66
|
-
return z.union([
|
|
67
|
-
z.string(),
|
|
68
|
-
z.object({
|
|
69
|
-
source: z.enum(["env", "file"]),
|
|
70
|
-
provider: z.string().min(1).max(1024).regex(SECRET_INPUT_PROVIDER_PATTERN),
|
|
71
|
-
id: z.string().min(1).max(1024).regex(SECRET_INPUT_ID_PATTERN)
|
|
72
|
-
})
|
|
73
|
-
]);
|
|
74
|
-
}
|
|
75
38
|
function isSecretInputRef(value) {
|
|
76
39
|
if (!value || typeof value !== "object") {
|
|
77
40
|
return false;
|
|
@@ -80,16 +43,7 @@ function isSecretInputRef(value) {
|
|
|
80
43
|
return (ref.source === "env" || ref.source === "file") && typeof ref.provider === "string" && ref.provider.trim().length > 0 && SECRET_INPUT_PROVIDER_PATTERN.test(ref.provider) && typeof ref.id === "string" && ref.id.trim().length > 0 && SECRET_INPUT_ID_PATTERN.test(ref.id);
|
|
81
44
|
}
|
|
82
45
|
function hasConfiguredSecretInput(value) {
|
|
83
|
-
|
|
84
|
-
return value.trim().length > 0;
|
|
85
|
-
}
|
|
86
|
-
if (!isSecretInputRef(value)) {
|
|
87
|
-
return false;
|
|
88
|
-
}
|
|
89
|
-
if (value.source === "env") {
|
|
90
|
-
return Boolean(process.env[value.id]?.trim());
|
|
91
|
-
}
|
|
92
|
-
return true;
|
|
46
|
+
return hasConfiguredOpenClawSecretInput(value);
|
|
93
47
|
}
|
|
94
48
|
function normalizeSecretInputString(value) {
|
|
95
49
|
if (typeof value === "string") {
|
|
@@ -119,7 +73,7 @@ function parseSecretInputString(value) {
|
|
|
119
73
|
id: match[3]
|
|
120
74
|
};
|
|
121
75
|
}
|
|
122
|
-
async function resolveSecretInputStringWithFailure(value, log) {
|
|
76
|
+
async function resolveSecretInputStringWithFailure(value, log, hostConfig) {
|
|
123
77
|
if (typeof value === "string") {
|
|
124
78
|
const trimmed = value.trim();
|
|
125
79
|
return { value: trimmed || void 0 };
|
|
@@ -127,32 +81,40 @@ async function resolveSecretInputStringWithFailure(value, log) {
|
|
|
127
81
|
if (!isSecretInputRef(value)) {
|
|
128
82
|
return {};
|
|
129
83
|
}
|
|
130
|
-
if (
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
84
|
+
if (!hostConfig) {
|
|
85
|
+
try {
|
|
86
|
+
hostConfig = getDingTalkRuntime().config.current();
|
|
87
|
+
} catch {
|
|
88
|
+
hostConfig = {};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
const resolved = await resolveConfiguredSecretInputString({
|
|
93
|
+
config: hostConfig,
|
|
94
|
+
env: process.env,
|
|
95
|
+
value,
|
|
96
|
+
path: "channels.dingtalk.clientSecret",
|
|
97
|
+
unresolvedReasonStyle: "detailed"
|
|
98
|
+
});
|
|
99
|
+
if (resolved.value) {
|
|
100
|
+
return { value: resolved.value };
|
|
134
101
|
}
|
|
135
|
-
const failure = buildSecretInputFailure(
|
|
136
|
-
|
|
102
|
+
const failure = buildSecretInputFailure(
|
|
103
|
+
value,
|
|
104
|
+
resolved.unresolvedRefReason || "secret reference is unresolved"
|
|
105
|
+
);
|
|
106
|
+
log?.warn?.("[DingTalk][SecretInput] Failed to resolve secret", {
|
|
137
107
|
provider: value.provider,
|
|
138
108
|
id: value.id,
|
|
139
109
|
error: failure.reason
|
|
140
110
|
});
|
|
141
111
|
return { failure };
|
|
142
|
-
}
|
|
143
|
-
try {
|
|
144
|
-
const filePath = resolveRelativePath(value.id);
|
|
145
|
-
const secret = (await readFile(filePath, "utf8")).trim();
|
|
146
|
-
if (secret) {
|
|
147
|
-
return { value: secret };
|
|
148
|
-
}
|
|
149
|
-
return { failure: buildSecretInputFailure(value, "file secret is empty") };
|
|
150
112
|
} catch (error) {
|
|
151
113
|
const failure = buildSecretInputFailure(
|
|
152
114
|
value,
|
|
153
115
|
error instanceof Error ? error.message : String(error)
|
|
154
116
|
);
|
|
155
|
-
log?.warn?.("[DingTalk][SecretInput] Failed to
|
|
117
|
+
log?.warn?.("[DingTalk][SecretInput] Failed to resolve secret", {
|
|
156
118
|
provider: value.provider,
|
|
157
119
|
id: value.id,
|
|
158
120
|
error: failure.reason
|
|
@@ -169,6 +131,48 @@ async function resolveDingTalkSecretConfig(config, log) {
|
|
|
169
131
|
};
|
|
170
132
|
}
|
|
171
133
|
|
|
134
|
+
// src/path-utils.ts
|
|
135
|
+
import * as os from "node:os";
|
|
136
|
+
import * as path from "node:path";
|
|
137
|
+
var WINDOWS_ROOT_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
138
|
+
"Users",
|
|
139
|
+
"Program Files",
|
|
140
|
+
"Program Files (x86)",
|
|
141
|
+
"ProgramData",
|
|
142
|
+
"Windows",
|
|
143
|
+
"Documents and Settings"
|
|
144
|
+
]);
|
|
145
|
+
function resolveRelativePath(input) {
|
|
146
|
+
const trimmed = input.trim();
|
|
147
|
+
if (!trimmed) {
|
|
148
|
+
return trimmed;
|
|
149
|
+
}
|
|
150
|
+
const segments = (value) => value.split(/[\\/]+/).filter(Boolean);
|
|
151
|
+
const pathSegments = segments(trimmed);
|
|
152
|
+
const firstSegment = pathSegments[0];
|
|
153
|
+
if (trimmed === "~") {
|
|
154
|
+
return path.resolve(os.homedir());
|
|
155
|
+
}
|
|
156
|
+
if (trimmed.startsWith("~/") || trimmed.startsWith("~\\")) {
|
|
157
|
+
return path.resolve(os.homedir(), ...segments(trimmed.slice(2)));
|
|
158
|
+
}
|
|
159
|
+
if (process.platform === "win32") {
|
|
160
|
+
if (/^[a-zA-Z]:[\\/]/.test(trimmed)) {
|
|
161
|
+
return path.win32.normalize(trimmed);
|
|
162
|
+
}
|
|
163
|
+
if (firstSegment && /^[a-zA-Z]:$/.test(firstSegment)) {
|
|
164
|
+
return path.win32.resolve(`${firstSegment}\\`, ...pathSegments.slice(1));
|
|
165
|
+
}
|
|
166
|
+
if (firstSegment && WINDOWS_ROOT_DIRECTORIES.has(firstSegment)) {
|
|
167
|
+
return path.win32.resolve("\\", ...pathSegments);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (/^[\\/]/.test(trimmed)) {
|
|
171
|
+
return path.resolve(path.sep, ...pathSegments);
|
|
172
|
+
}
|
|
173
|
+
return path.resolve(process.cwd(), ...pathSegments);
|
|
174
|
+
}
|
|
175
|
+
|
|
172
176
|
// src/config.ts
|
|
173
177
|
var DEFAULT_LEARNING_NOTE_TTL_MS = 6 * 60 * 60 * 1e3;
|
|
174
178
|
function normalizeLearningConfig(config, options) {
|
|
@@ -1679,110 +1683,20 @@ var DINGTALK_ASK_USER_CARD_TEMPLATE = Object.freeze({
|
|
|
1679
1683
|
templateId: BUILTIN_DINGTALK_ASK_USER_CARD_TEMPLATE_ID
|
|
1680
1684
|
});
|
|
1681
1685
|
|
|
1682
|
-
// src/peer-id-registry.ts
|
|
1683
|
-
import { readFileSync, readdirSync as readdirSync2 } from "fs";
|
|
1684
|
-
import * as os3 from "os";
|
|
1685
|
-
import { join as join2 } from "path";
|
|
1686
|
-
|
|
1687
|
-
// src/logger-context.ts
|
|
1688
|
-
var currentLogger;
|
|
1689
|
-
var loggerByAccountId = /* @__PURE__ */ new Map();
|
|
1690
|
-
function setCurrentLogger(log, accountId) {
|
|
1691
|
-
currentLogger = log;
|
|
1692
|
-
const normalizedAccountId = typeof accountId === "string" ? accountId.trim() : "";
|
|
1693
|
-
if (!normalizedAccountId) {
|
|
1694
|
-
return;
|
|
1695
|
-
}
|
|
1696
|
-
if (log) {
|
|
1697
|
-
loggerByAccountId.set(normalizedAccountId, log);
|
|
1698
|
-
return;
|
|
1699
|
-
}
|
|
1700
|
-
loggerByAccountId.delete(normalizedAccountId);
|
|
1701
|
-
}
|
|
1702
|
-
function getLogger(accountId) {
|
|
1703
|
-
const normalizedAccountId = typeof accountId === "string" ? accountId.trim() : "";
|
|
1704
|
-
if (normalizedAccountId) {
|
|
1705
|
-
return loggerByAccountId.get(normalizedAccountId);
|
|
1706
|
-
}
|
|
1707
|
-
return currentLogger;
|
|
1708
|
-
}
|
|
1709
|
-
|
|
1710
1686
|
// src/peer-id-registry.ts
|
|
1711
1687
|
var peerIdMap = /* @__PURE__ */ new Map();
|
|
1712
|
-
var preloaded = false;
|
|
1713
1688
|
function registerPeerId(originalId) {
|
|
1714
1689
|
if (!originalId) {
|
|
1715
1690
|
return;
|
|
1716
1691
|
}
|
|
1717
1692
|
peerIdMap.set(originalId.toLowerCase(), originalId);
|
|
1718
1693
|
}
|
|
1719
|
-
function maybeRegisterDingTalkGroupPeerId(value) {
|
|
1720
|
-
if (typeof value === "string" && value.startsWith("cid")) {
|
|
1721
|
-
registerPeerId(value);
|
|
1722
|
-
}
|
|
1723
|
-
}
|
|
1724
1694
|
function resolveOriginalPeerId(id) {
|
|
1725
1695
|
if (!id) {
|
|
1726
1696
|
return id;
|
|
1727
1697
|
}
|
|
1728
|
-
if (!preloaded) {
|
|
1729
|
-
preloadPeerIdsFromSessions();
|
|
1730
|
-
}
|
|
1731
1698
|
return peerIdMap.get(id.toLowerCase()) || id;
|
|
1732
1699
|
}
|
|
1733
|
-
function preloadPeerIdsFromSessions(homeDir) {
|
|
1734
|
-
if (!homeDir && preloaded) {
|
|
1735
|
-
return;
|
|
1736
|
-
}
|
|
1737
|
-
const home = homeDir || os3.homedir();
|
|
1738
|
-
const agentsDir = join2(home, ".openclaw", "agents");
|
|
1739
|
-
const log = getLogger();
|
|
1740
|
-
let preloadCompleted = false;
|
|
1741
|
-
try {
|
|
1742
|
-
const agentDirs = readdirSync2(agentsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
1743
|
-
for (const agentName of agentDirs) {
|
|
1744
|
-
const sessionsPath = join2(agentsDir, agentName, "sessions", "sessions.json");
|
|
1745
|
-
try {
|
|
1746
|
-
const raw = readFileSync(sessionsPath, "utf-8");
|
|
1747
|
-
const parsed = JSON.parse(raw);
|
|
1748
|
-
if (!parsed || typeof parsed !== "object") {
|
|
1749
|
-
continue;
|
|
1750
|
-
}
|
|
1751
|
-
for (const session of Object.values(parsed)) {
|
|
1752
|
-
if (!session || typeof session !== "object") {
|
|
1753
|
-
continue;
|
|
1754
|
-
}
|
|
1755
|
-
const sessionRecord = session;
|
|
1756
|
-
maybeRegisterDingTalkGroupPeerId(sessionRecord.lastTo);
|
|
1757
|
-
const origin = sessionRecord.origin;
|
|
1758
|
-
if (!origin || typeof origin !== "object") {
|
|
1759
|
-
continue;
|
|
1760
|
-
}
|
|
1761
|
-
const originRecord = origin;
|
|
1762
|
-
maybeRegisterDingTalkGroupPeerId(originRecord.from);
|
|
1763
|
-
maybeRegisterDingTalkGroupPeerId(originRecord.to);
|
|
1764
|
-
}
|
|
1765
|
-
} catch (err) {
|
|
1766
|
-
log?.debug?.(
|
|
1767
|
-
`[DingTalk][PeerIdRegistry] Failed to parse preload sessions file ${sessionsPath}: ${err instanceof Error ? err.message : String(err)}`
|
|
1768
|
-
);
|
|
1769
|
-
}
|
|
1770
|
-
}
|
|
1771
|
-
preloadCompleted = true;
|
|
1772
|
-
} catch (err) {
|
|
1773
|
-
const errorCode = err?.code;
|
|
1774
|
-
if (errorCode === "ENOENT") {
|
|
1775
|
-
preloadCompleted = true;
|
|
1776
|
-
} else {
|
|
1777
|
-
log?.debug?.(
|
|
1778
|
-
`[DingTalk][PeerIdRegistry] Failed to scan preload directory ${agentsDir}: ${err instanceof Error ? err.message : String(err)}`
|
|
1779
|
-
);
|
|
1780
|
-
}
|
|
1781
|
-
}
|
|
1782
|
-
if (!homeDir && preloadCompleted) {
|
|
1783
|
-
preloaded = true;
|
|
1784
|
-
}
|
|
1785
|
-
}
|
|
1786
1700
|
|
|
1787
1701
|
// src/persistence-store.ts
|
|
1788
1702
|
import * as fs2 from "node:fs";
|
|
@@ -3639,18 +3553,6 @@ function resolveConfiguredTaskModelMetadata(params) {
|
|
|
3639
3553
|
|
|
3640
3554
|
// src/command/card-stop-command.ts
|
|
3641
3555
|
import { resolveNativeCommandSessionTargets } from "openclaw/plugin-sdk/command-auth";
|
|
3642
|
-
|
|
3643
|
-
// src/runtime.ts
|
|
3644
|
-
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
|
3645
|
-
var runtimeStore = createPluginRuntimeStore("DingTalk runtime not initialized");
|
|
3646
|
-
function setDingTalkRuntime(next) {
|
|
3647
|
-
runtimeStore.setRuntime(next);
|
|
3648
|
-
}
|
|
3649
|
-
function getDingTalkRuntime() {
|
|
3650
|
-
return runtimeStore.getRuntime();
|
|
3651
|
-
}
|
|
3652
|
-
|
|
3653
|
-
// src/command/card-stop-command.ts
|
|
3654
3556
|
async function dispatchDingTalkCardStopCommand(params) {
|
|
3655
3557
|
const rt = getDingTalkRuntime();
|
|
3656
3558
|
const { sessionKey: commandSessionKey, commandTargetSessionKey } = resolveNativeCommandSessionTargets({
|
|
@@ -5161,9 +5063,32 @@ function pickQueueBusyAckPhrase(seed) {
|
|
|
5161
5063
|
// src/send-service.ts
|
|
5162
5064
|
import * as path6 from "node:path";
|
|
5163
5065
|
|
|
5066
|
+
// src/logger-context.ts
|
|
5067
|
+
var currentLogger;
|
|
5068
|
+
var loggerByAccountId = /* @__PURE__ */ new Map();
|
|
5069
|
+
function setCurrentLogger(log, accountId) {
|
|
5070
|
+
currentLogger = log;
|
|
5071
|
+
const normalizedAccountId = typeof accountId === "string" ? accountId.trim() : "";
|
|
5072
|
+
if (!normalizedAccountId) {
|
|
5073
|
+
return;
|
|
5074
|
+
}
|
|
5075
|
+
if (log) {
|
|
5076
|
+
loggerByAccountId.set(normalizedAccountId, log);
|
|
5077
|
+
return;
|
|
5078
|
+
}
|
|
5079
|
+
loggerByAccountId.delete(normalizedAccountId);
|
|
5080
|
+
}
|
|
5081
|
+
function getLogger(accountId) {
|
|
5082
|
+
const normalizedAccountId = typeof accountId === "string" ? accountId.trim() : "";
|
|
5083
|
+
if (normalizedAccountId) {
|
|
5084
|
+
return loggerByAccountId.get(normalizedAccountId);
|
|
5085
|
+
}
|
|
5086
|
+
return currentLogger;
|
|
5087
|
+
}
|
|
5088
|
+
|
|
5164
5089
|
// src/media-utils.ts
|
|
5165
5090
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
5166
|
-
import * as
|
|
5091
|
+
import * as os3 from "node:os";
|
|
5167
5092
|
import * as path5 from "node:path";
|
|
5168
5093
|
import { promises as fsPromises } from "node:fs";
|
|
5169
5094
|
import { lookup as dnsLookup } from "node:dns/promises";
|
|
@@ -5319,7 +5244,7 @@ async function prepareVoiceUploadPath(mediaPath, log) {
|
|
|
5319
5244
|
if (DINGTALK_VOICE_UPLOAD_EXTENSIONS.has(ext)) {
|
|
5320
5245
|
return { path: mediaPath };
|
|
5321
5246
|
}
|
|
5322
|
-
const outputPath = path5.join(
|
|
5247
|
+
const outputPath = path5.join(os3.tmpdir(), `dingtalk_voice_${randomUUID3()}.ogg`);
|
|
5323
5248
|
await runFfmpeg([
|
|
5324
5249
|
"-y",
|
|
5325
5250
|
"-i",
|
|
@@ -5684,7 +5609,7 @@ async function prepareMediaInput(input, log, mediaUrlAllowlist) {
|
|
|
5684
5609
|
const contentType = typeof response.headers?.["content-type"] === "string" ? response.headers["content-type"] : void 0;
|
|
5685
5610
|
const urlPath = currentUrl.pathname;
|
|
5686
5611
|
const ext = path5.extname(urlPath) || detectExtensionFromContentType(contentType) || ".bin";
|
|
5687
|
-
const tempPath = path5.join(
|
|
5612
|
+
const tempPath = path5.join(os3.tmpdir(), `dingtalk_${randomUUID3()}${ext}`);
|
|
5688
5613
|
const buffer = Buffer.isBuffer(response.data) ? response.data : Buffer.from(response.data);
|
|
5689
5614
|
await fsPromises.writeFile(tempPath, buffer);
|
|
5690
5615
|
log?.debug?.(`[DingTalk] Downloaded remote media to temp file: ${tempPath}`);
|
|
@@ -13826,139 +13751,869 @@ function registerDingTalkAskUserQuestionTool(api) {
|
|
|
13826
13751
|
}
|
|
13827
13752
|
|
|
13828
13753
|
// src/channel.ts
|
|
13829
|
-
import {
|
|
13754
|
+
import { buildJsonChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-schema";
|
|
13830
13755
|
|
|
13831
|
-
//
|
|
13832
|
-
|
|
13833
|
-
|
|
13834
|
-
|
|
13835
|
-
|
|
13836
|
-
|
|
13837
|
-
]
|
|
13838
|
-
|
|
13839
|
-
|
|
13840
|
-
|
|
13841
|
-
|
|
13842
|
-
|
|
13843
|
-
|
|
13844
|
-
|
|
13845
|
-
|
|
13846
|
-
|
|
13847
|
-
|
|
13848
|
-
|
|
13849
|
-
|
|
13850
|
-
|
|
13851
|
-
|
|
13852
|
-
|
|
13853
|
-
|
|
13854
|
-
|
|
13855
|
-
|
|
13856
|
-
|
|
13857
|
-
|
|
13858
|
-
|
|
13859
|
-
|
|
13860
|
-
|
|
13861
|
-
|
|
13862
|
-
|
|
13863
|
-
|
|
13864
|
-
|
|
13865
|
-
|
|
13866
|
-
|
|
13867
|
-
|
|
13868
|
-
|
|
13869
|
-
|
|
13870
|
-
|
|
13871
|
-
|
|
13872
|
-
|
|
13873
|
-
|
|
13874
|
-
|
|
13875
|
-
|
|
13876
|
-
|
|
13877
|
-
|
|
13878
|
-
|
|
13879
|
-
|
|
13880
|
-
|
|
13881
|
-
|
|
13882
|
-
|
|
13883
|
-
|
|
13884
|
-
|
|
13885
|
-
|
|
13886
|
-
|
|
13887
|
-
|
|
13888
|
-
|
|
13889
|
-
|
|
13890
|
-
|
|
13891
|
-
|
|
13892
|
-
|
|
13893
|
-
|
|
13894
|
-
|
|
13895
|
-
|
|
13896
|
-
|
|
13897
|
-
|
|
13898
|
-
|
|
13899
|
-
|
|
13900
|
-
|
|
13901
|
-
|
|
13902
|
-
|
|
13903
|
-
|
|
13904
|
-
|
|
13905
|
-
|
|
13906
|
-
|
|
13907
|
-
|
|
13908
|
-
|
|
13909
|
-
|
|
13910
|
-
|
|
13911
|
-
|
|
13912
|
-
|
|
13913
|
-
|
|
13914
|
-
|
|
13915
|
-
|
|
13916
|
-
|
|
13917
|
-
|
|
13918
|
-
|
|
13919
|
-
|
|
13920
|
-
|
|
13921
|
-
|
|
13922
|
-
|
|
13923
|
-
|
|
13924
|
-
|
|
13925
|
-
|
|
13926
|
-
|
|
13927
|
-
|
|
13928
|
-
|
|
13929
|
-
|
|
13930
|
-
|
|
13931
|
-
|
|
13932
|
-
|
|
13933
|
-
|
|
13934
|
-
|
|
13935
|
-
|
|
13936
|
-
|
|
13937
|
-
|
|
13938
|
-
|
|
13939
|
-
|
|
13940
|
-
|
|
13941
|
-
|
|
13942
|
-
|
|
13943
|
-
|
|
13944
|
-
|
|
13945
|
-
|
|
13946
|
-
|
|
13947
|
-
|
|
13948
|
-
|
|
13949
|
-
|
|
13950
|
-
|
|
13951
|
-
|
|
13952
|
-
|
|
13756
|
+
// openclaw.plugin.json
|
|
13757
|
+
var openclaw_plugin_default = {
|
|
13758
|
+
id: "dingtalk",
|
|
13759
|
+
name: "DingTalk",
|
|
13760
|
+
channels: ["dingtalk"],
|
|
13761
|
+
contracts: {
|
|
13762
|
+
tools: ["dingtalk_ask_user_question"]
|
|
13763
|
+
},
|
|
13764
|
+
configSchema: {
|
|
13765
|
+
type: "object",
|
|
13766
|
+
additionalProperties: true,
|
|
13767
|
+
properties: {}
|
|
13768
|
+
},
|
|
13769
|
+
channelConfigs: {
|
|
13770
|
+
dingtalk: {
|
|
13771
|
+
label: "DingTalk",
|
|
13772
|
+
description: "\u9489\u9489\u4F01\u4E1A\u5185\u90E8\u673A\u5668\u4EBA\uFF0C\u4F7F\u7528 Stream \u6A21\u5F0F\uFF0C\u65E0\u9700\u516C\u7F51 IP\u3002",
|
|
13773
|
+
schema: {
|
|
13774
|
+
type: "object",
|
|
13775
|
+
additionalProperties: false,
|
|
13776
|
+
properties: {
|
|
13777
|
+
name: {
|
|
13778
|
+
type: "string",
|
|
13779
|
+
description: "Optional display name shown for this DingTalk channel or default account."
|
|
13780
|
+
},
|
|
13781
|
+
enabled: {
|
|
13782
|
+
type: "boolean",
|
|
13783
|
+
default: true,
|
|
13784
|
+
description: "Enable or disable this DingTalk channel configuration without deleting saved credentials."
|
|
13785
|
+
},
|
|
13786
|
+
agentId: {
|
|
13787
|
+
type: "integer",
|
|
13788
|
+
description: "Legacy compatibility field from older setup flows. The current Stream-mode runtime no longer reads this value, so new configs should omit it."
|
|
13789
|
+
},
|
|
13790
|
+
corpId: {
|
|
13791
|
+
type: "string",
|
|
13792
|
+
description: "Legacy compatibility field from older enterprise app setup flows. The current Stream-mode runtime no longer needs or reads this value."
|
|
13793
|
+
},
|
|
13794
|
+
clientId: {
|
|
13795
|
+
type: "string",
|
|
13796
|
+
description: "DingTalk App Key (Client ID) used to authenticate API and Stream connections."
|
|
13797
|
+
},
|
|
13798
|
+
clientSecret: {
|
|
13799
|
+
anyOf: [
|
|
13800
|
+
{ type: "string" },
|
|
13801
|
+
{
|
|
13802
|
+
type: "object",
|
|
13803
|
+
additionalProperties: false,
|
|
13804
|
+
required: ["source", "provider", "id"],
|
|
13805
|
+
properties: {
|
|
13806
|
+
source: { type: "string", enum: ["env", "file"] },
|
|
13807
|
+
provider: {
|
|
13808
|
+
type: "string",
|
|
13809
|
+
minLength: 1,
|
|
13810
|
+
maxLength: 1024,
|
|
13811
|
+
pattern: "^[^:>]+$"
|
|
13812
|
+
},
|
|
13813
|
+
id: {
|
|
13814
|
+
type: "string",
|
|
13815
|
+
minLength: 1,
|
|
13816
|
+
maxLength: 1024,
|
|
13817
|
+
pattern: "^[^>]+$"
|
|
13818
|
+
}
|
|
13819
|
+
}
|
|
13820
|
+
}
|
|
13821
|
+
],
|
|
13822
|
+
description: "DingTalk App Secret (Client Secret) used to obtain DingTalk access tokens. Supports env/file SecretInput references resolved by configured OpenClaw secret providers."
|
|
13823
|
+
},
|
|
13824
|
+
dmPolicy: {
|
|
13825
|
+
type: "string",
|
|
13826
|
+
enum: ["open", "pairing", "allowlist"],
|
|
13827
|
+
default: "open",
|
|
13828
|
+
description: "Direct-message access policy. open allows any DM, pairing requires host pairing, and allowlist only permits IDs listed in allowFrom."
|
|
13829
|
+
},
|
|
13830
|
+
groupPolicy: {
|
|
13831
|
+
type: "string",
|
|
13832
|
+
enum: ["open", "allowlist", "disabled"],
|
|
13833
|
+
default: "open",
|
|
13834
|
+
description: "Group-message access policy. open allows all groups, allowlist restricts by groupAllowFrom, and disabled blocks group handling."
|
|
13835
|
+
},
|
|
13836
|
+
allowFrom: {
|
|
13837
|
+
type: "array",
|
|
13838
|
+
items: { type: "string" },
|
|
13839
|
+
description: "User IDs allowed when dmPolicy is allowlist. Accepts DingTalk IDs or host-normalized IDs."
|
|
13840
|
+
},
|
|
13841
|
+
groupAllowFrom: {
|
|
13842
|
+
type: "array",
|
|
13843
|
+
items: { type: "string" },
|
|
13844
|
+
description: "Sender IDs allowed when groupPolicy is allowlist. Leave empty unless you want per-sender restrictions in groups."
|
|
13845
|
+
},
|
|
13846
|
+
displayNameResolution: {
|
|
13847
|
+
type: "string",
|
|
13848
|
+
enum: ["disabled", "all"],
|
|
13849
|
+
default: "disabled",
|
|
13850
|
+
description: "Whether learned display names can be used to resolve DingTalk users or groups. Keep disabled unless you explicitly accept stale or ambiguous-name routing risk."
|
|
13851
|
+
},
|
|
13852
|
+
contextVisibility: {
|
|
13853
|
+
type: "string",
|
|
13854
|
+
enum: ["all", "allowlist", "allowlist_quote"],
|
|
13855
|
+
description: "Host-level context filtering before prompts are sent to the runtime. allowlist_quote is the safest advanced mode when only explicit quote or reply context should remain visible."
|
|
13856
|
+
},
|
|
13857
|
+
mediaUrlAllowlist: {
|
|
13858
|
+
type: "array",
|
|
13859
|
+
items: { type: "string" },
|
|
13860
|
+
description: "Allowed download hosts, IPs, or CIDRs for remote media fetches. Use this for internal file servers or custom CDN domains."
|
|
13861
|
+
},
|
|
13862
|
+
ackReaction: {
|
|
13863
|
+
anyOf: [
|
|
13864
|
+
{ type: "string", const: "" },
|
|
13865
|
+
{ type: "string", enum: ["off", "emoji", "kaomoji"] },
|
|
13866
|
+
{ type: "string", minLength: 1 }
|
|
13867
|
+
],
|
|
13868
|
+
description: "Acknowledgement reaction mode. Supports off, emoji, kaomoji, or a custom compatibility string."
|
|
13869
|
+
},
|
|
13870
|
+
journalTTLDays: {
|
|
13871
|
+
type: "integer",
|
|
13872
|
+
minimum: 1,
|
|
13873
|
+
default: 7,
|
|
13874
|
+
description: "Retention window in days for short-lived message context used by quoting, media recovery, and related reply context features."
|
|
13875
|
+
},
|
|
13876
|
+
debug: {
|
|
13877
|
+
type: "boolean",
|
|
13878
|
+
default: false,
|
|
13879
|
+
description: "Enable verbose DingTalk channel debug logging."
|
|
13880
|
+
},
|
|
13881
|
+
messageType: {
|
|
13882
|
+
type: "string",
|
|
13883
|
+
enum: ["markdown", "card"],
|
|
13884
|
+
default: "markdown",
|
|
13885
|
+
description: "Default reply delivery mode. markdown uses standard messages; card uses DingTalk AI cards when available."
|
|
13886
|
+
},
|
|
13887
|
+
cardTemplateId: {
|
|
13888
|
+
type: "string",
|
|
13889
|
+
description: "Deprecated and ignored. AI card replies now always use the built-in DingTalk template contract; keep only for compatibility with old configs."
|
|
13890
|
+
},
|
|
13891
|
+
cardTemplateKey: {
|
|
13892
|
+
type: "string",
|
|
13893
|
+
default: "content",
|
|
13894
|
+
description: "Deprecated and ignored. The built-in AI card contract owns the streaming field mapping; keep only for compatibility with old configs."
|
|
13895
|
+
},
|
|
13896
|
+
groups: {
|
|
13897
|
+
type: "object",
|
|
13898
|
+
description: 'Per-group overrides keyed by conversationId. Supports "*" as a wildcard fallback.',
|
|
13899
|
+
additionalProperties: {
|
|
13900
|
+
type: "object",
|
|
13901
|
+
additionalProperties: false,
|
|
13902
|
+
properties: {
|
|
13903
|
+
systemPrompt: {
|
|
13904
|
+
type: "string",
|
|
13905
|
+
description: "Additional system prompt appended for this group."
|
|
13906
|
+
},
|
|
13907
|
+
requireMention: {
|
|
13908
|
+
type: "boolean",
|
|
13909
|
+
description: "Require an explicit @mention before the bot answers in this group."
|
|
13910
|
+
},
|
|
13911
|
+
groupAllowFrom: {
|
|
13912
|
+
type: "array",
|
|
13913
|
+
items: { type: "string" },
|
|
13914
|
+
description: "Per-group sender allowlist used when you want tighter access control than the channel default."
|
|
13915
|
+
}
|
|
13916
|
+
}
|
|
13917
|
+
}
|
|
13918
|
+
},
|
|
13919
|
+
maxConnectionAttempts: {
|
|
13920
|
+
type: "integer",
|
|
13921
|
+
minimum: 1,
|
|
13922
|
+
default: 10,
|
|
13923
|
+
description: "Maximum connection attempts in a single reconnect cycle before backing off or giving up."
|
|
13924
|
+
},
|
|
13925
|
+
initialReconnectDelay: {
|
|
13926
|
+
type: "integer",
|
|
13927
|
+
minimum: 100,
|
|
13928
|
+
default: 1e3,
|
|
13929
|
+
description: "Initial reconnect backoff delay in milliseconds."
|
|
13930
|
+
},
|
|
13931
|
+
maxReconnectDelay: {
|
|
13932
|
+
type: "integer",
|
|
13933
|
+
minimum: 1e3,
|
|
13934
|
+
default: 6e4,
|
|
13935
|
+
description: "Upper bound for reconnect backoff delay in milliseconds."
|
|
13936
|
+
},
|
|
13937
|
+
reconnectJitter: {
|
|
13938
|
+
type: "number",
|
|
13939
|
+
minimum: 0,
|
|
13940
|
+
maximum: 1,
|
|
13941
|
+
default: 0.3,
|
|
13942
|
+
description: "Randomization factor added to reconnect backoff to avoid synchronized reconnect storms."
|
|
13943
|
+
},
|
|
13944
|
+
maxReconnectCycles: {
|
|
13945
|
+
type: "integer",
|
|
13946
|
+
minimum: 1,
|
|
13947
|
+
default: 10,
|
|
13948
|
+
description: "Maximum reconnect cycles before the channel stops retrying and waits for the next lifecycle restart."
|
|
13949
|
+
},
|
|
13950
|
+
reconnectDeadlineMs: {
|
|
13951
|
+
type: "integer",
|
|
13952
|
+
minimum: 5e3,
|
|
13953
|
+
default: 5e4,
|
|
13954
|
+
description: "Time limit in milliseconds for one reconnect cycle before starting a fresh cycle."
|
|
13955
|
+
},
|
|
13956
|
+
useConnectionManager: {
|
|
13957
|
+
type: "boolean",
|
|
13958
|
+
default: true,
|
|
13959
|
+
description: "Enable the plugin connection manager. Disable only when you intentionally rely on the DingTalk client keepAlive and autoReconnect behavior."
|
|
13960
|
+
},
|
|
13961
|
+
mediaMaxMb: {
|
|
13962
|
+
type: "integer",
|
|
13963
|
+
minimum: 1,
|
|
13964
|
+
description: "Maximum inbound media size in MB accepted by the plugin. When omitted, the runtime default is used."
|
|
13965
|
+
},
|
|
13966
|
+
keepAlive: {
|
|
13967
|
+
type: "boolean",
|
|
13968
|
+
description: "Enable the underlying Stream client heartbeat. When omitted, runtime derives a default from useConnectionManager."
|
|
13969
|
+
},
|
|
13970
|
+
bypassProxyForSend: {
|
|
13971
|
+
type: "boolean",
|
|
13972
|
+
default: false,
|
|
13973
|
+
description: "Bypass global or system HTTP(S) proxy settings for DingTalk send, upload, and card APIs."
|
|
13974
|
+
},
|
|
13975
|
+
proactivePermissionHint: {
|
|
13976
|
+
type: "object",
|
|
13977
|
+
description: "Controls the proactive-send permission reminder shown when a conversation has not granted send rights yet.",
|
|
13978
|
+
additionalProperties: false,
|
|
13979
|
+
properties: {
|
|
13980
|
+
enabled: {
|
|
13981
|
+
type: "boolean",
|
|
13982
|
+
default: true,
|
|
13983
|
+
description: "Show the proactive-send permission hint when the runtime detects missing DingTalk proactive permission."
|
|
13984
|
+
},
|
|
13985
|
+
cooldownHours: {
|
|
13986
|
+
type: "integer",
|
|
13987
|
+
minimum: 1,
|
|
13988
|
+
maximum: 720,
|
|
13989
|
+
default: 24,
|
|
13990
|
+
description: "Minimum cooldown in hours before the same proactive permission hint can be shown again."
|
|
13991
|
+
}
|
|
13992
|
+
}
|
|
13993
|
+
},
|
|
13994
|
+
cardRealTimeStream: {
|
|
13995
|
+
type: "boolean",
|
|
13996
|
+
default: false,
|
|
13997
|
+
description: 'Deprecated compatibility flag. If true and cardStreamingMode is unset, runtime falls back to cardStreamingMode="all". Do not use in new configs.'
|
|
13998
|
+
},
|
|
13999
|
+
cardStreamingMode: {
|
|
14000
|
+
type: "string",
|
|
14001
|
+
enum: ["off", "answer", "all"],
|
|
14002
|
+
description: "AI card incremental streaming mode. off disables streaming, answer streams answer text only, and all streams answer plus reasoning or thinking text."
|
|
14003
|
+
},
|
|
14004
|
+
cardStreamInterval: {
|
|
14005
|
+
type: "integer",
|
|
14006
|
+
minimum: 200,
|
|
14007
|
+
default: 1e3,
|
|
14008
|
+
description: "Throttle interval in milliseconds between AI card streaming updates."
|
|
14009
|
+
},
|
|
14010
|
+
aicardDegradeMs: {
|
|
14011
|
+
type: "integer",
|
|
14012
|
+
minimum: 6e4,
|
|
14013
|
+
default: 18e5,
|
|
14014
|
+
description: "Cooldown window in milliseconds after AI card trigger errors. During this window replies fall back to non-card delivery."
|
|
14015
|
+
},
|
|
14016
|
+
learningEnabled: {
|
|
14017
|
+
type: "boolean",
|
|
14018
|
+
description: "Enable the local feedback-learning loop for notes, reflections, and command-assisted learning."
|
|
14019
|
+
},
|
|
14020
|
+
learningAutoApply: {
|
|
14021
|
+
type: "boolean",
|
|
14022
|
+
description: "Automatically apply generated learning output into session notes or global rules when available."
|
|
14023
|
+
},
|
|
14024
|
+
learningNoteTtlMs: {
|
|
14025
|
+
type: "integer",
|
|
14026
|
+
minimum: 6e4,
|
|
14027
|
+
description: "Retention window in milliseconds for temporary learning notes."
|
|
14028
|
+
},
|
|
14029
|
+
convertMarkdownTables: {
|
|
14030
|
+
type: "boolean",
|
|
14031
|
+
default: true,
|
|
14032
|
+
description: "Convert markdown tables to plain text before sending when you want more consistent DingTalk rendering."
|
|
14033
|
+
},
|
|
14034
|
+
cardAtSender: {
|
|
14035
|
+
type: "string",
|
|
14036
|
+
description: "Send a follow-up @mention text after card finalization in group chats. Any non-empty string becomes the message body."
|
|
14037
|
+
},
|
|
14038
|
+
cardStatusLine: {
|
|
14039
|
+
type: "object",
|
|
14040
|
+
description: "Status line visibility toggles for the AI card footer.",
|
|
14041
|
+
additionalProperties: false,
|
|
14042
|
+
default: { model: true, effort: true, agent: true, taskTime: false, tokens: false, dapiUsage: false },
|
|
14043
|
+
properties: {
|
|
14044
|
+
model: {
|
|
14045
|
+
type: "boolean",
|
|
14046
|
+
default: true,
|
|
14047
|
+
description: "Show model name in AI card status line footer."
|
|
14048
|
+
},
|
|
14049
|
+
effort: {
|
|
14050
|
+
type: "boolean",
|
|
14051
|
+
default: true,
|
|
14052
|
+
description: "Show thinking effort level in AI card status line footer."
|
|
14053
|
+
},
|
|
14054
|
+
agent: {
|
|
14055
|
+
type: "boolean",
|
|
14056
|
+
default: true,
|
|
14057
|
+
description: "Show agent display name in AI card status line footer."
|
|
14058
|
+
},
|
|
14059
|
+
taskTime: {
|
|
14060
|
+
type: "boolean",
|
|
14061
|
+
default: false,
|
|
14062
|
+
description: "Show task elapsed time in AI card status line footer."
|
|
14063
|
+
},
|
|
14064
|
+
tokens: {
|
|
14065
|
+
type: "boolean",
|
|
14066
|
+
default: false,
|
|
14067
|
+
description: "Show token usage summary (input/output/cache) in AI card status line footer."
|
|
14068
|
+
},
|
|
14069
|
+
dapiUsage: {
|
|
14070
|
+
type: "boolean",
|
|
14071
|
+
default: false,
|
|
14072
|
+
description: "Show DingTalk API call count in AI card status line footer."
|
|
14073
|
+
}
|
|
14074
|
+
}
|
|
14075
|
+
},
|
|
14076
|
+
showThinkingStream: {
|
|
14077
|
+
type: "boolean",
|
|
14078
|
+
description: "Legacy compatibility field from older card streaming behavior. It is not used by the current runtime and new configs should omit it."
|
|
14079
|
+
},
|
|
14080
|
+
asyncMode: {
|
|
14081
|
+
type: "boolean",
|
|
14082
|
+
description: "Legacy compatibility field from older host or runtime integrations. It is not used by the current runtime and new configs should omit it."
|
|
14083
|
+
},
|
|
14084
|
+
accounts: {
|
|
14085
|
+
type: "object",
|
|
14086
|
+
description: "Named multi-account DingTalk configurations. Each account can override most top-level settings and inherits unspecified values from the top level.",
|
|
14087
|
+
additionalProperties: {
|
|
14088
|
+
type: "object",
|
|
14089
|
+
additionalProperties: false,
|
|
14090
|
+
properties: {
|
|
14091
|
+
name: {
|
|
14092
|
+
type: "string",
|
|
14093
|
+
description: "Optional display name shown for this named DingTalk account."
|
|
14094
|
+
},
|
|
14095
|
+
enabled: {
|
|
14096
|
+
type: "boolean",
|
|
14097
|
+
default: true,
|
|
14098
|
+
description: "Enable or disable this DingTalk account without deleting saved credentials."
|
|
14099
|
+
},
|
|
14100
|
+
clientId: {
|
|
14101
|
+
type: "string",
|
|
14102
|
+
description: "DingTalk App Key (Client ID) used to authenticate API and Stream connections."
|
|
14103
|
+
},
|
|
14104
|
+
clientSecret: {
|
|
14105
|
+
anyOf: [
|
|
14106
|
+
{ type: "string" },
|
|
14107
|
+
{
|
|
14108
|
+
type: "object",
|
|
14109
|
+
additionalProperties: false,
|
|
14110
|
+
required: ["source", "provider", "id"],
|
|
14111
|
+
properties: {
|
|
14112
|
+
source: { type: "string", enum: ["env", "file"] },
|
|
14113
|
+
provider: {
|
|
14114
|
+
type: "string",
|
|
14115
|
+
minLength: 1,
|
|
14116
|
+
maxLength: 1024,
|
|
14117
|
+
pattern: "^[^:>]+$"
|
|
14118
|
+
},
|
|
14119
|
+
id: {
|
|
14120
|
+
type: "string",
|
|
14121
|
+
minLength: 1,
|
|
14122
|
+
maxLength: 1024,
|
|
14123
|
+
pattern: "^[^>]+$"
|
|
14124
|
+
}
|
|
14125
|
+
}
|
|
14126
|
+
}
|
|
14127
|
+
],
|
|
14128
|
+
description: "DingTalk App Secret (Client Secret) used to obtain DingTalk access tokens. Supports env/file SecretInput references resolved by configured OpenClaw secret providers."
|
|
14129
|
+
},
|
|
14130
|
+
dmPolicy: {
|
|
14131
|
+
type: "string",
|
|
14132
|
+
enum: ["open", "pairing", "allowlist"],
|
|
14133
|
+
default: "open",
|
|
14134
|
+
description: "Direct-message access policy. open allows any DM, pairing requires host pairing, and allowlist only permits IDs listed in allowFrom."
|
|
14135
|
+
},
|
|
14136
|
+
groupPolicy: {
|
|
14137
|
+
type: "string",
|
|
14138
|
+
enum: ["open", "allowlist", "disabled"],
|
|
14139
|
+
default: "open",
|
|
14140
|
+
description: "Group-message access policy. open allows all groups, allowlist restricts by groupAllowFrom, and disabled blocks group handling."
|
|
14141
|
+
},
|
|
14142
|
+
allowFrom: {
|
|
14143
|
+
type: "array",
|
|
14144
|
+
items: { type: "string" },
|
|
14145
|
+
description: "User IDs allowed when dmPolicy is allowlist. Accepts DingTalk IDs or host-normalized IDs."
|
|
14146
|
+
},
|
|
14147
|
+
groupAllowFrom: {
|
|
14148
|
+
type: "array",
|
|
14149
|
+
items: { type: "string" },
|
|
14150
|
+
description: "Sender IDs allowed when groupPolicy is allowlist. Leave empty unless you want per-sender restrictions in groups."
|
|
14151
|
+
},
|
|
14152
|
+
displayNameResolution: {
|
|
14153
|
+
type: "string",
|
|
14154
|
+
enum: ["disabled", "all"],
|
|
14155
|
+
default: "disabled",
|
|
14156
|
+
description: "Whether learned display names can be used to resolve DingTalk users or groups. Keep disabled unless you explicitly accept stale or ambiguous-name routing risk."
|
|
14157
|
+
},
|
|
14158
|
+
contextVisibility: {
|
|
14159
|
+
type: "string",
|
|
14160
|
+
enum: ["all", "allowlist", "allowlist_quote"],
|
|
14161
|
+
description: "Host-level context filtering before prompts are sent to the runtime. allowlist_quote is the safest advanced mode when only explicit quote or reply context should remain visible."
|
|
14162
|
+
},
|
|
14163
|
+
mediaUrlAllowlist: {
|
|
14164
|
+
type: "array",
|
|
14165
|
+
items: { type: "string" },
|
|
14166
|
+
description: "Allowed download hosts, IPs, or CIDRs for remote media fetches. Use this for internal file servers or custom CDN domains."
|
|
14167
|
+
},
|
|
14168
|
+
ackReaction: {
|
|
14169
|
+
anyOf: [
|
|
14170
|
+
{ type: "string", const: "" },
|
|
14171
|
+
{ type: "string", enum: ["off", "emoji", "kaomoji"] },
|
|
14172
|
+
{ type: "string", minLength: 1 }
|
|
14173
|
+
],
|
|
14174
|
+
description: "Acknowledgement reaction mode. Supports off, emoji, kaomoji, or a custom compatibility string."
|
|
14175
|
+
},
|
|
14176
|
+
journalTTLDays: {
|
|
14177
|
+
type: "integer",
|
|
14178
|
+
minimum: 1,
|
|
14179
|
+
default: 7,
|
|
14180
|
+
description: "Retention window in days for short-lived message context used by quoting, media recovery, and related reply context features."
|
|
14181
|
+
},
|
|
14182
|
+
debug: {
|
|
14183
|
+
type: "boolean",
|
|
14184
|
+
default: false,
|
|
14185
|
+
description: "Enable verbose DingTalk channel debug logging."
|
|
14186
|
+
},
|
|
14187
|
+
messageType: {
|
|
14188
|
+
type: "string",
|
|
14189
|
+
enum: ["markdown", "card"],
|
|
14190
|
+
default: "markdown",
|
|
14191
|
+
description: "Default reply delivery mode. markdown uses standard messages; card uses DingTalk AI cards when available."
|
|
14192
|
+
},
|
|
14193
|
+
cardTemplateId: {
|
|
14194
|
+
type: "string",
|
|
14195
|
+
description: "Deprecated and ignored. AI card replies now always use the built-in DingTalk template contract; keep only for compatibility with old configs."
|
|
14196
|
+
},
|
|
14197
|
+
cardTemplateKey: {
|
|
14198
|
+
type: "string",
|
|
14199
|
+
default: "content",
|
|
14200
|
+
description: "Deprecated and ignored. The built-in AI card contract owns the streaming field mapping; keep only for compatibility with old configs."
|
|
14201
|
+
},
|
|
14202
|
+
groups: {
|
|
14203
|
+
type: "object",
|
|
14204
|
+
description: 'Per-group overrides keyed by conversationId. Supports "*" as a wildcard fallback.',
|
|
14205
|
+
additionalProperties: {
|
|
14206
|
+
type: "object",
|
|
14207
|
+
additionalProperties: false,
|
|
14208
|
+
properties: {
|
|
14209
|
+
systemPrompt: {
|
|
14210
|
+
type: "string",
|
|
14211
|
+
description: "Additional system prompt appended for this group."
|
|
14212
|
+
},
|
|
14213
|
+
requireMention: {
|
|
14214
|
+
type: "boolean",
|
|
14215
|
+
description: "Require an explicit @mention before the bot answers in this group."
|
|
14216
|
+
},
|
|
14217
|
+
groupAllowFrom: {
|
|
14218
|
+
type: "array",
|
|
14219
|
+
items: { type: "string" },
|
|
14220
|
+
description: "Per-group sender allowlist used when you want tighter access control than the channel default."
|
|
14221
|
+
}
|
|
14222
|
+
}
|
|
14223
|
+
}
|
|
14224
|
+
},
|
|
14225
|
+
maxConnectionAttempts: {
|
|
14226
|
+
type: "integer",
|
|
14227
|
+
minimum: 1,
|
|
14228
|
+
default: 10,
|
|
14229
|
+
description: "Maximum connection attempts in a single reconnect cycle before backing off or giving up."
|
|
14230
|
+
},
|
|
14231
|
+
initialReconnectDelay: {
|
|
14232
|
+
type: "integer",
|
|
14233
|
+
minimum: 100,
|
|
14234
|
+
default: 1e3,
|
|
14235
|
+
description: "Initial reconnect backoff delay in milliseconds."
|
|
14236
|
+
},
|
|
14237
|
+
maxReconnectDelay: {
|
|
14238
|
+
type: "integer",
|
|
14239
|
+
minimum: 1e3,
|
|
14240
|
+
default: 6e4,
|
|
14241
|
+
description: "Upper bound for reconnect backoff delay in milliseconds."
|
|
14242
|
+
},
|
|
14243
|
+
reconnectJitter: {
|
|
14244
|
+
type: "number",
|
|
14245
|
+
minimum: 0,
|
|
14246
|
+
maximum: 1,
|
|
14247
|
+
default: 0.3,
|
|
14248
|
+
description: "Randomization factor added to reconnect backoff to avoid synchronized reconnect storms."
|
|
14249
|
+
},
|
|
14250
|
+
maxReconnectCycles: {
|
|
14251
|
+
type: "integer",
|
|
14252
|
+
minimum: 1,
|
|
14253
|
+
default: 10,
|
|
14254
|
+
description: "Maximum reconnect cycles before the channel stops retrying and waits for the next lifecycle restart."
|
|
14255
|
+
},
|
|
14256
|
+
reconnectDeadlineMs: {
|
|
14257
|
+
type: "integer",
|
|
14258
|
+
minimum: 5e3,
|
|
14259
|
+
default: 5e4,
|
|
14260
|
+
description: "Time limit in milliseconds for one reconnect cycle before starting a fresh cycle."
|
|
14261
|
+
},
|
|
14262
|
+
useConnectionManager: {
|
|
14263
|
+
type: "boolean",
|
|
14264
|
+
default: true,
|
|
14265
|
+
description: "Enable the plugin connection manager. Disable only when you intentionally rely on the DingTalk client keepAlive and autoReconnect behavior."
|
|
14266
|
+
},
|
|
14267
|
+
mediaMaxMb: {
|
|
14268
|
+
type: "integer",
|
|
14269
|
+
minimum: 1,
|
|
14270
|
+
description: "Maximum inbound media size in MB accepted by the plugin. When omitted, the runtime default is used."
|
|
14271
|
+
},
|
|
14272
|
+
keepAlive: {
|
|
14273
|
+
type: "boolean",
|
|
14274
|
+
description: "Enable the underlying Stream client heartbeat. When omitted, runtime derives a default from useConnectionManager."
|
|
14275
|
+
},
|
|
14276
|
+
bypassProxyForSend: {
|
|
14277
|
+
type: "boolean",
|
|
14278
|
+
default: false,
|
|
14279
|
+
description: "Bypass global or system HTTP(S) proxy settings for DingTalk send, upload, and card APIs."
|
|
14280
|
+
},
|
|
14281
|
+
proactivePermissionHint: {
|
|
14282
|
+
type: "object",
|
|
14283
|
+
description: "Controls the proactive-send permission reminder shown when a conversation has not granted send rights yet.",
|
|
14284
|
+
additionalProperties: false,
|
|
14285
|
+
properties: {
|
|
14286
|
+
enabled: {
|
|
14287
|
+
type: "boolean",
|
|
14288
|
+
default: true,
|
|
14289
|
+
description: "Show the proactive-send permission hint when the runtime detects missing DingTalk proactive permission."
|
|
14290
|
+
},
|
|
14291
|
+
cooldownHours: {
|
|
14292
|
+
type: "integer",
|
|
14293
|
+
minimum: 1,
|
|
14294
|
+
maximum: 720,
|
|
14295
|
+
default: 24,
|
|
14296
|
+
description: "Minimum cooldown in hours before the same proactive permission hint can be shown again."
|
|
14297
|
+
}
|
|
14298
|
+
}
|
|
14299
|
+
},
|
|
14300
|
+
cardRealTimeStream: {
|
|
14301
|
+
type: "boolean",
|
|
14302
|
+
default: false,
|
|
14303
|
+
description: 'Deprecated compatibility flag. If true and cardStreamingMode is unset, runtime falls back to cardStreamingMode="all". Do not use in new configs.'
|
|
14304
|
+
},
|
|
14305
|
+
cardStreamingMode: {
|
|
14306
|
+
type: "string",
|
|
14307
|
+
enum: ["off", "answer", "all"],
|
|
14308
|
+
description: "AI card incremental streaming mode. off disables streaming, answer streams answer text only, and all streams answer plus reasoning or thinking text."
|
|
14309
|
+
},
|
|
14310
|
+
cardStreamInterval: {
|
|
14311
|
+
type: "integer",
|
|
14312
|
+
minimum: 200,
|
|
14313
|
+
default: 1e3,
|
|
14314
|
+
description: "Throttle interval in milliseconds between AI card streaming updates."
|
|
14315
|
+
},
|
|
14316
|
+
aicardDegradeMs: {
|
|
14317
|
+
type: "integer",
|
|
14318
|
+
minimum: 6e4,
|
|
14319
|
+
default: 18e5,
|
|
14320
|
+
description: "Cooldown window in milliseconds after AI card trigger errors. During this window replies fall back to non-card delivery."
|
|
14321
|
+
},
|
|
14322
|
+
learningEnabled: {
|
|
14323
|
+
type: "boolean",
|
|
14324
|
+
description: "Enable the local feedback-learning loop for notes, reflections, and command-assisted learning."
|
|
14325
|
+
},
|
|
14326
|
+
learningAutoApply: {
|
|
14327
|
+
type: "boolean",
|
|
14328
|
+
description: "Automatically apply generated learning output into session notes or global rules when available."
|
|
14329
|
+
},
|
|
14330
|
+
learningNoteTtlMs: {
|
|
14331
|
+
type: "integer",
|
|
14332
|
+
minimum: 6e4,
|
|
14333
|
+
description: "Retention window in milliseconds for temporary learning notes."
|
|
14334
|
+
},
|
|
14335
|
+
convertMarkdownTables: {
|
|
14336
|
+
type: "boolean",
|
|
14337
|
+
default: true,
|
|
14338
|
+
description: "Convert markdown tables to plain text before sending when you want more consistent DingTalk rendering."
|
|
14339
|
+
},
|
|
14340
|
+
cardAtSender: {
|
|
14341
|
+
type: "string",
|
|
14342
|
+
description: "Send a follow-up @mention text after card finalization in group chats. Any non-empty string becomes the message body."
|
|
14343
|
+
},
|
|
14344
|
+
cardStatusLine: {
|
|
14345
|
+
type: "object",
|
|
14346
|
+
description: "Status line visibility toggles for the AI card footer.",
|
|
14347
|
+
additionalProperties: false,
|
|
14348
|
+
default: { model: true, effort: true, agent: true, taskTime: false, tokens: false, dapiUsage: false },
|
|
14349
|
+
properties: {
|
|
14350
|
+
model: {
|
|
14351
|
+
type: "boolean",
|
|
14352
|
+
default: true,
|
|
14353
|
+
description: "Show model name in AI card status line footer."
|
|
14354
|
+
},
|
|
14355
|
+
effort: {
|
|
14356
|
+
type: "boolean",
|
|
14357
|
+
default: true,
|
|
14358
|
+
description: "Show thinking effort level in AI card status line footer."
|
|
14359
|
+
},
|
|
14360
|
+
agent: {
|
|
14361
|
+
type: "boolean",
|
|
14362
|
+
default: true,
|
|
14363
|
+
description: "Show agent display name in AI card status line footer."
|
|
14364
|
+
},
|
|
14365
|
+
taskTime: {
|
|
14366
|
+
type: "boolean",
|
|
14367
|
+
default: false,
|
|
14368
|
+
description: "Show task elapsed time in AI card status line footer."
|
|
14369
|
+
},
|
|
14370
|
+
tokens: {
|
|
14371
|
+
type: "boolean",
|
|
14372
|
+
default: false,
|
|
14373
|
+
description: "Show token usage summary (input/output/cache) in AI card status line footer."
|
|
14374
|
+
},
|
|
14375
|
+
dapiUsage: {
|
|
14376
|
+
type: "boolean",
|
|
14377
|
+
default: false,
|
|
14378
|
+
description: "Show DingTalk API call count in AI card status line footer."
|
|
14379
|
+
}
|
|
14380
|
+
}
|
|
14381
|
+
}
|
|
14382
|
+
}
|
|
14383
|
+
}
|
|
14384
|
+
}
|
|
14385
|
+
}
|
|
14386
|
+
},
|
|
14387
|
+
uiHints: {
|
|
14388
|
+
"": {
|
|
14389
|
+
label: "DingTalk",
|
|
14390
|
+
help: "DingTalk Stream-mode channel configuration including auth, delivery, targeting, and AI Card behavior."
|
|
14391
|
+
},
|
|
14392
|
+
name: {
|
|
14393
|
+
label: "Display Name",
|
|
14394
|
+
help: "Optional display name for the default DingTalk account shown in host configuration surfaces."
|
|
14395
|
+
},
|
|
14396
|
+
enabled: {
|
|
14397
|
+
label: "Enabled",
|
|
14398
|
+
help: "Turn the DingTalk channel on or off without deleting the saved configuration."
|
|
14399
|
+
},
|
|
14400
|
+
agentId: {
|
|
14401
|
+
label: "Legacy Agent ID",
|
|
14402
|
+
help: "Deprecated compatibility field from older setup flows. The current runtime ignores it, so leave it empty in new configs."
|
|
14403
|
+
},
|
|
14404
|
+
corpId: {
|
|
14405
|
+
label: "Legacy Corp ID",
|
|
14406
|
+
help: "Deprecated compatibility field from older enterprise app setup flows. Stream mode no longer needs or reads it."
|
|
14407
|
+
},
|
|
14408
|
+
clientId: {
|
|
14409
|
+
label: "DingTalk Client ID",
|
|
14410
|
+
help: "App Key used to authenticate DingTalk API requests."
|
|
14411
|
+
},
|
|
14412
|
+
clientSecret: {
|
|
14413
|
+
label: "DingTalk Client Secret",
|
|
14414
|
+
help: "App Secret used to obtain DingTalk access tokens. SecretInput references are resolved by configured OpenClaw secret providers.",
|
|
14415
|
+
sensitive: true
|
|
14416
|
+
},
|
|
14417
|
+
dmPolicy: {
|
|
14418
|
+
label: "Direct Message Policy",
|
|
14419
|
+
help: "Choose who can talk to the bot in direct messages: open, host pairing only, or explicit allowlist."
|
|
14420
|
+
},
|
|
14421
|
+
groupPolicy: {
|
|
14422
|
+
label: "Group Message Policy",
|
|
14423
|
+
help: "Choose whether group messages are open to all groups, restricted by allowlist, or completely disabled."
|
|
14424
|
+
},
|
|
14425
|
+
allowFrom: {
|
|
14426
|
+
label: "DM Allowlist",
|
|
14427
|
+
help: "User IDs allowed when direct message policy is set to allowlist."
|
|
14428
|
+
},
|
|
14429
|
+
groupAllowFrom: {
|
|
14430
|
+
label: "Group Sender Allowlist",
|
|
14431
|
+
help: "Sender IDs allowed when group policy is allowlist or when you want tighter group sender restrictions."
|
|
14432
|
+
},
|
|
14433
|
+
messageType: {
|
|
14434
|
+
label: "Reply Message Type",
|
|
14435
|
+
help: "Choose markdown for standard replies or card for AI Card delivery."
|
|
14436
|
+
},
|
|
14437
|
+
ackReaction: {
|
|
14438
|
+
label: "Ack Reaction",
|
|
14439
|
+
help: "Native acknowledgement reaction mode. Supports preset values or a custom string for backward compatibility."
|
|
14440
|
+
},
|
|
14441
|
+
displayNameResolution: {
|
|
14442
|
+
label: "Display Name Resolution",
|
|
14443
|
+
help: "Keep disabled unless you explicitly want learned display-name targeting for all callers."
|
|
14444
|
+
},
|
|
14445
|
+
contextVisibility: {
|
|
14446
|
+
label: "Context Visibility",
|
|
14447
|
+
help: "Host-level context filtering. allowlist_quote is the safest advanced mode when you only want explicit quote/reply context."
|
|
14448
|
+
},
|
|
14449
|
+
mediaUrlAllowlist: {
|
|
14450
|
+
label: "Media URL Allowlist",
|
|
14451
|
+
help: "Allow remote media downloads only from the specified hosts, IPs, or CIDR ranges."
|
|
14452
|
+
},
|
|
14453
|
+
journalTTLDays: {
|
|
14454
|
+
label: "Message Context TTL (days)",
|
|
14455
|
+
help: "Retention period for short-lived quoted message and media recovery context."
|
|
14456
|
+
},
|
|
14457
|
+
debug: {
|
|
14458
|
+
label: "Debug Logging",
|
|
14459
|
+
help: "Enable verbose DingTalk channel debug logs for diagnostics."
|
|
14460
|
+
},
|
|
14461
|
+
cardTemplateId: {
|
|
14462
|
+
label: "AI Card Template ID",
|
|
14463
|
+
help: "Deprecated and ignored. AI card replies now always use the built-in DingTalk template contract."
|
|
14464
|
+
},
|
|
14465
|
+
cardTemplateKey: {
|
|
14466
|
+
label: "AI Card Template Field Key",
|
|
14467
|
+
help: "Deprecated and ignored. The built-in AI card contract owns the streaming field mapping."
|
|
14468
|
+
},
|
|
14469
|
+
groups: {
|
|
14470
|
+
label: "Per-Group Overrides",
|
|
14471
|
+
help: "Configure conversationId-specific overrides, or use * as a wildcard fallback."
|
|
14472
|
+
},
|
|
14473
|
+
"groups.systemPrompt": {
|
|
14474
|
+
label: "Group System Prompt",
|
|
14475
|
+
help: "Extra system prompt appended only for the selected group."
|
|
14476
|
+
},
|
|
14477
|
+
"groups.requireMention": {
|
|
14478
|
+
label: "Require Mention",
|
|
14479
|
+
help: "Require an explicit @mention before the bot answers in that group."
|
|
14480
|
+
},
|
|
14481
|
+
"groups.groupAllowFrom": {
|
|
14482
|
+
label: "Per-Group Sender Allowlist",
|
|
14483
|
+
help: "Optional sender allowlist that overrides or tightens the channel-level group access rule."
|
|
14484
|
+
},
|
|
14485
|
+
maxConnectionAttempts: {
|
|
14486
|
+
label: "Max Connection Attempts",
|
|
14487
|
+
help: "How many connection attempts are allowed within a reconnect cycle before the cycle backs off or ends."
|
|
14488
|
+
},
|
|
14489
|
+
initialReconnectDelay: {
|
|
14490
|
+
label: "Initial Reconnect Delay",
|
|
14491
|
+
help: "Initial reconnect backoff delay in milliseconds."
|
|
14492
|
+
},
|
|
14493
|
+
maxReconnectDelay: {
|
|
14494
|
+
label: "Max Reconnect Delay",
|
|
14495
|
+
help: "Upper bound for reconnect backoff delay in milliseconds."
|
|
14496
|
+
},
|
|
14497
|
+
reconnectJitter: {
|
|
14498
|
+
label: "Reconnect Jitter",
|
|
14499
|
+
help: "Randomization factor added to reconnect backoff to reduce synchronized reconnect storms."
|
|
14500
|
+
},
|
|
14501
|
+
maxReconnectCycles: {
|
|
14502
|
+
label: "Max Reconnect Cycles",
|
|
14503
|
+
help: "Maximum reconnect cycles before the channel stops retrying and waits for a later restart."
|
|
14504
|
+
},
|
|
14505
|
+
reconnectDeadlineMs: {
|
|
14506
|
+
label: "Reconnect Cycle Deadline",
|
|
14507
|
+
help: "Time limit in milliseconds for one reconnect cycle before starting a fresh cycle."
|
|
14508
|
+
},
|
|
14509
|
+
useConnectionManager: {
|
|
14510
|
+
label: "Use Connection Manager",
|
|
14511
|
+
help: "Recommended default. Disable only when you intentionally rely on the DingTalk client keepAlive and autoReconnect behavior."
|
|
14512
|
+
},
|
|
14513
|
+
mediaMaxMb: {
|
|
14514
|
+
label: "Max Media Size (MB)",
|
|
14515
|
+
help: "Maximum inbound media size accepted by the plugin. Leave empty to use the runtime default."
|
|
14516
|
+
},
|
|
14517
|
+
keepAlive: {
|
|
14518
|
+
label: "Stream KeepAlive",
|
|
14519
|
+
help: "Optional explicit heartbeat toggle for the underlying Stream client."
|
|
14520
|
+
},
|
|
14521
|
+
bypassProxyForSend: {
|
|
14522
|
+
label: "Bypass Proxy For Send",
|
|
14523
|
+
help: "Skip global or system HTTP(S) proxy settings for DingTalk send, upload, and card APIs."
|
|
14524
|
+
},
|
|
14525
|
+
cardRealTimeStream: {
|
|
14526
|
+
label: "Legacy Real-Time Card Stream",
|
|
14527
|
+
help: "Deprecated compatibility flag. When true and cardStreamingMode is unset, runtime falls back to all-streaming. Do not use in new configs."
|
|
14528
|
+
},
|
|
14529
|
+
cardStreamingMode: {
|
|
14530
|
+
label: "Card Streaming Mode",
|
|
14531
|
+
help: "Choose off, answer, or all. answer streams only answer text, while all streams answer plus reasoning or thinking text."
|
|
14532
|
+
},
|
|
14533
|
+
cardStreamInterval: {
|
|
14534
|
+
label: "Card Stream Interval (ms)",
|
|
14535
|
+
help: "Throttle interval in milliseconds between AI card incremental updates."
|
|
14536
|
+
},
|
|
14537
|
+
aicardDegradeMs: {
|
|
14538
|
+
label: "AI Card Degrade Window (ms)",
|
|
14539
|
+
help: "Cooldown window after AI card trigger errors. Replies fall back to non-card delivery during this period."
|
|
14540
|
+
},
|
|
14541
|
+
learningEnabled: {
|
|
14542
|
+
label: "Learning Enabled",
|
|
14543
|
+
help: "Enable the local feedback-learning loop for notes, reflections, and learning commands."
|
|
14544
|
+
},
|
|
14545
|
+
learningAutoApply: {
|
|
14546
|
+
label: "Learning Auto Apply",
|
|
14547
|
+
help: "Automatically apply generated learning output into session notes or global rules when available."
|
|
14548
|
+
},
|
|
14549
|
+
learningNoteTtlMs: {
|
|
14550
|
+
label: "Learning Note TTL (ms)",
|
|
14551
|
+
help: "Retention period for temporary learning notes."
|
|
14552
|
+
},
|
|
14553
|
+
convertMarkdownTables: {
|
|
14554
|
+
label: "Convert Markdown Tables",
|
|
14555
|
+
help: "Flatten markdown tables into plain text before sending when you want more consistent DingTalk rendering."
|
|
14556
|
+
},
|
|
14557
|
+
cardAtSender: {
|
|
14558
|
+
label: "Card Mention Follow-Up",
|
|
14559
|
+
help: "Send a follow-up @mention text after card finalization in group chats. Any non-empty string becomes the message body."
|
|
14560
|
+
},
|
|
14561
|
+
cardStatusLine: {
|
|
14562
|
+
label: "Status Line",
|
|
14563
|
+
help: "Configure which information segments appear in the AI card footer status line."
|
|
14564
|
+
},
|
|
14565
|
+
"cardStatusLine.model": {
|
|
14566
|
+
label: "Model Name",
|
|
14567
|
+
help: "Show the LLM model name in the AI card footer status line."
|
|
14568
|
+
},
|
|
14569
|
+
"cardStatusLine.effort": {
|
|
14570
|
+
label: "Thinking Effort",
|
|
14571
|
+
help: "Show the thinking effort level (e.g. high, medium) in the AI card footer."
|
|
14572
|
+
},
|
|
14573
|
+
"cardStatusLine.agent": {
|
|
14574
|
+
label: "Agent Name",
|
|
14575
|
+
help: "Show the agent display name in the AI card footer."
|
|
14576
|
+
},
|
|
14577
|
+
"cardStatusLine.taskTime": {
|
|
14578
|
+
label: "Task Time",
|
|
14579
|
+
help: "Show elapsed task time in the AI card footer."
|
|
14580
|
+
},
|
|
14581
|
+
"cardStatusLine.tokens": {
|
|
14582
|
+
label: "Token Usage",
|
|
14583
|
+
help: "Show a compact token usage summary (input/output/cache) in the AI card footer."
|
|
14584
|
+
},
|
|
14585
|
+
"cardStatusLine.dapiUsage": {
|
|
14586
|
+
label: "API Calls",
|
|
14587
|
+
help: "Show the DingTalk API call count in the AI card footer."
|
|
14588
|
+
},
|
|
14589
|
+
showThinkingStream: {
|
|
14590
|
+
label: "Legacy Show Thinking Stream",
|
|
14591
|
+
help: "Deprecated compatibility field from older card streaming behavior. The current runtime ignores it."
|
|
14592
|
+
},
|
|
14593
|
+
asyncMode: {
|
|
14594
|
+
label: "Legacy Async Mode",
|
|
14595
|
+
help: "Deprecated compatibility field from older host or runtime integrations. The current runtime ignores it."
|
|
14596
|
+
},
|
|
14597
|
+
accounts: {
|
|
14598
|
+
label: "Named Accounts",
|
|
14599
|
+
help: "Create named DingTalk accounts when one plugin instance must serve multiple apps or tenants."
|
|
14600
|
+
},
|
|
14601
|
+
"proactivePermissionHint.enabled": {
|
|
14602
|
+
label: "Proactive Permission Hint Enabled",
|
|
14603
|
+
help: "Show a reminder when DingTalk proactive-send permission has not been granted."
|
|
14604
|
+
},
|
|
14605
|
+
"proactivePermissionHint.cooldownHours": {
|
|
14606
|
+
label: "Proactive Hint Cooldown (hours)",
|
|
14607
|
+
help: "Minimum cooldown before the same proactive permission hint can be shown again."
|
|
14608
|
+
}
|
|
14609
|
+
}
|
|
14610
|
+
}
|
|
14611
|
+
}
|
|
13953
14612
|
};
|
|
13954
|
-
var DingTalkAccountConfigSchema = z2.object(DingTalkAccountConfigShape);
|
|
13955
|
-
var DingTalkConfigSchema = DingTalkAccountConfigSchema.extend({
|
|
13956
|
-
/** Multi-account configuration */
|
|
13957
|
-
accounts: z2.record(z2.string(), DingTalkAccountConfigSchema.optional()).optional()
|
|
13958
|
-
});
|
|
13959
14613
|
|
|
13960
14614
|
// src/gateway/channel-gateway.ts
|
|
13961
14615
|
import { DWClient, TOPIC_CARD, TOPIC_ROBOT } from "dingtalk-stream";
|
|
14616
|
+
import { listAgentIds } from "openclaw/plugin-sdk/agent-runtime";
|
|
13962
14617
|
|
|
13963
14618
|
// src/card/card-stop-handler.ts
|
|
13964
14619
|
async function stopCardRun(params) {
|
|
@@ -14929,11 +15584,69 @@ function createDingTalkGateway() {
|
|
|
14929
15584
|
debug: config.debug,
|
|
14930
15585
|
baseLog: ctx.log
|
|
14931
15586
|
});
|
|
15587
|
+
try {
|
|
15588
|
+
const knownGroupIds = /* @__PURE__ */ new Set();
|
|
15589
|
+
for (const group of listKnownGroupTargets({
|
|
15590
|
+
storePath: accountStorePath,
|
|
15591
|
+
accountId: account.accountId
|
|
15592
|
+
})) {
|
|
15593
|
+
registerPeerId(group.conversationId);
|
|
15594
|
+
knownGroupIds.add(group.conversationId.toLowerCase());
|
|
15595
|
+
}
|
|
15596
|
+
const runtime = getDingTalkRuntime();
|
|
15597
|
+
for (const agentId of listAgentIds(cfg)) {
|
|
15598
|
+
const sessionStorePath = runtime.channel.session.resolveStorePath(cfg.session?.store, {
|
|
15599
|
+
agentId
|
|
15600
|
+
});
|
|
15601
|
+
for (const { entry } of runtime.agent.session.listSessionEntries({
|
|
15602
|
+
agentId,
|
|
15603
|
+
storePath: sessionStorePath,
|
|
15604
|
+
readConsistency: "latest"
|
|
15605
|
+
})) {
|
|
15606
|
+
const isDingTalkSession = [
|
|
15607
|
+
entry.lastChannel,
|
|
15608
|
+
entry.channel,
|
|
15609
|
+
entry.origin?.provider,
|
|
15610
|
+
entry.origin?.surface
|
|
15611
|
+
].some((value) => value === "dingtalk");
|
|
15612
|
+
const sessionAccountId = entry.lastAccountId || entry.origin?.accountId;
|
|
15613
|
+
if (!isDingTalkSession || sessionAccountId !== account.accountId) {
|
|
15614
|
+
continue;
|
|
15615
|
+
}
|
|
15616
|
+
for (const peerId of [entry.lastTo, entry.origin?.from, entry.origin?.to]) {
|
|
15617
|
+
if (typeof peerId !== "string" || !peerId.startsWith("cid")) {
|
|
15618
|
+
continue;
|
|
15619
|
+
}
|
|
15620
|
+
registerPeerId(peerId);
|
|
15621
|
+
const normalizedPeerId = peerId.toLowerCase();
|
|
15622
|
+
if (!knownGroupIds.has(normalizedPeerId)) {
|
|
15623
|
+
upsertObservedGroupTarget({
|
|
15624
|
+
storePath: accountStorePath,
|
|
15625
|
+
accountId: account.accountId,
|
|
15626
|
+
conversationId: peerId,
|
|
15627
|
+
seenAt: entry.updatedAt
|
|
15628
|
+
});
|
|
15629
|
+
knownGroupIds.add(normalizedPeerId);
|
|
15630
|
+
}
|
|
15631
|
+
}
|
|
15632
|
+
}
|
|
15633
|
+
}
|
|
15634
|
+
for (const user of listKnownUserTargets({
|
|
15635
|
+
storePath: accountStorePath,
|
|
15636
|
+
accountId: account.accountId
|
|
15637
|
+
})) {
|
|
15638
|
+
registerPeerId(user.canonicalUserId);
|
|
15639
|
+
registerPeerId(user.staffId || "");
|
|
15640
|
+
registerPeerId(user.senderId);
|
|
15641
|
+
}
|
|
15642
|
+
} catch (err) {
|
|
15643
|
+
pluginLog?.warn?.(
|
|
15644
|
+
`[${account.accountId}] Failed to restore peer IDs: ${err instanceof Error ? err.message : String(err)}`
|
|
15645
|
+
);
|
|
15646
|
+
}
|
|
14932
15647
|
const runtimeConfig = await resolveRuntimeConfig(config, pluginLog);
|
|
14933
15648
|
setCurrentLogger(pluginLog, account.accountId);
|
|
14934
15649
|
pluginLog?.info?.(`[${account.accountId}] Initializing DingTalk Stream client...`);
|
|
14935
|
-
preloadPeerIdsFromSessions();
|
|
14936
|
-
pluginLog?.debug?.(`[${account.accountId}] Peer ID registry preloaded from sessions`);
|
|
14937
15650
|
cleanupOrphanedTempFiles(pluginLog);
|
|
14938
15651
|
try {
|
|
14939
15652
|
const recovered = await recoverPendingCardsForAccount(
|
|
@@ -16013,10 +16726,9 @@ function describeDingTalkMessageTool(cfg) {
|
|
|
16013
16726
|
if (!configured && !(config.accounts && Object.keys(config.accounts).length > 0)) {
|
|
16014
16727
|
return { actions: [], capabilities: [], schema: null };
|
|
16015
16728
|
}
|
|
16016
|
-
const hasCardMode = config.messageType === "card" || config.accounts && Object.values(config.accounts).some((account) => account?.messageType === "card");
|
|
16017
16729
|
return {
|
|
16018
16730
|
actions: ["send"],
|
|
16019
|
-
capabilities:
|
|
16731
|
+
capabilities: [],
|
|
16020
16732
|
schema: null
|
|
16021
16733
|
};
|
|
16022
16734
|
}
|
|
@@ -16485,7 +17197,7 @@ var dingtalkPlugin = {
|
|
|
16485
17197
|
blurb: "\u9489\u9489\u4F01\u4E1A\u5185\u90E8\u673A\u5668\u4EBA\uFF0C\u4F7F\u7528 Stream \u6A21\u5F0F\uFF0C\u65E0\u9700\u516C\u7F51 IP\u3002",
|
|
16486
17198
|
aliases: ["dd", "ding"]
|
|
16487
17199
|
},
|
|
16488
|
-
configSchema:
|
|
17200
|
+
configSchema: buildJsonChannelConfigSchema(openclaw_plugin_default.channelConfigs.dingtalk.schema),
|
|
16489
17201
|
setup: dingtalkSetupAdapter,
|
|
16490
17202
|
setupWizard: dingtalkSetupWizard,
|
|
16491
17203
|
capabilities: {
|
|
@@ -16936,7 +17648,7 @@ var dingtalkEntry = defineChannelPluginEntry({
|
|
|
16936
17648
|
);
|
|
16937
17649
|
}
|
|
16938
17650
|
});
|
|
16939
|
-
var
|
|
17651
|
+
var pluginDefinition = {
|
|
16940
17652
|
...dingtalkEntry,
|
|
16941
17653
|
register(api) {
|
|
16942
17654
|
const registrationMode = api.registrationMode;
|
|
@@ -16950,9 +17662,9 @@ var index_default = {
|
|
|
16950
17662
|
dingtalkEntry.register(api);
|
|
16951
17663
|
}
|
|
16952
17664
|
};
|
|
17665
|
+
var index_default = pluginDefinition;
|
|
16953
17666
|
export {
|
|
16954
17667
|
index_default as default,
|
|
16955
17668
|
dingtalkPlugin,
|
|
16956
17669
|
setDingTalkRuntime
|
|
16957
17670
|
};
|
|
16958
|
-
//# sourceMappingURL=index.js.map
|