@xmanrui/dsh-im 4.21.2 → 4.23.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/README.en.md +10 -5
- package/README.md +10 -5
- package/docs/client-integration.md +81 -0
- package/lib/client.js +2565 -1134
- package/lib/index.js +292 -301
- package/package.json +9 -1
- package/plugin-src/client/channel-card-meta.js +2 -0
- package/plugin-src/client/channel-logos.js +11 -0
- package/plugin-src/client/channels/dingtalk/api.js +5 -1
- package/plugin-src/client/channels/dingtalk/index.js +15 -13
- package/plugin-src/client/channels/email/api.js +52 -0
- package/plugin-src/client/channels/email/index.js +728 -0
- package/plugin-src/client/channels/email/styles.js +51 -0
- package/plugin-src/client/channels/feishu/api.js +4 -2
- package/plugin-src/client/channels/feishu/index.js +16 -3
- package/plugin-src/client/channels/imessage/index.js +2 -1
- package/plugin-src/client/channels/office/api.js +2 -0
- package/plugin-src/client/channels/office/index.js +6 -5
- package/plugin-src/client/channels/qq/api.js +7 -0
- package/plugin-src/client/channels/qq/index.js +16 -3
- package/plugin-src/client/channels/shared/token-api.js +5 -1
- package/plugin-src/client/channels/shared/token-channel.js +28 -3
- package/plugin-src/client/channels/slack/index.js +2 -1
- package/plugin-src/client/channels/wecom/api.js +7 -1
- package/plugin-src/client/channels/wecom/index.js +16 -3
- package/plugin-src/client/channels/wecom-app/api.js +6 -1
- package/plugin-src/client/channels/wecom-app/index.js +16 -3
- package/plugin-src/client/channels/weixin/api.js +2 -1
- package/plugin-src/client/channels/weixin/connection-error.js +1 -71
- package/plugin-src/client/channels/whatsapp/api.js +5 -0
- package/plugin-src/client/channels/whatsapp/index.js +16 -3
- package/plugin-src/client/connection-error.js +87 -0
- package/plugin-src/client/global-settings.js +81 -1
- package/plugin-src/client/i18n.js +62 -0
- package/plugin-src/client/index.js +122 -28
- package/plugin-src/client/last-message-error.js +2 -1
- package/plugin-src/client/panel-error-boundary.js +21 -0
- package/plugin-src/client/styles.js +6 -0
- package/plugin-src/host/build.mjs +4 -0
- package/plugin-src/host/channels/dingtalk/production.mjs +5 -1
- package/plugin-src/host/channels/dingtalk/rpc.mjs +7 -4
- package/plugin-src/host/channels/email/availability.mjs +60 -0
- package/plugin-src/host/channels/email/index.mjs +36 -0
- package/plugin-src/host/channels/email/production.mjs +58 -0
- package/plugin-src/host/channels/email/rpc.mjs +163 -0
- package/plugin-src/host/channels/feishu/production.mjs +6 -1
- package/plugin-src/host/channels/feishu/rpc.mjs +7 -4
- package/plugin-src/host/channels/imessage/rpc.mjs +13 -6
- package/plugin-src/host/channels/office/rpc.mjs +3 -1
- package/plugin-src/host/channels/qq/production.mjs +5 -1
- package/plugin-src/host/channels/qq/rpc.mjs +5 -3
- package/plugin-src/host/channels/shared/production.mjs +55 -6
- package/plugin-src/host/channels/shared/rpc.mjs +5 -3
- package/plugin-src/host/channels/shared/startup-error.mjs +4 -3
- package/plugin-src/host/channels/shared/startup.mjs +11 -6
- package/plugin-src/host/channels/slack/production.mjs +5 -1
- package/plugin-src/host/channels/slack/rpc.mjs +5 -3
- package/plugin-src/host/channels/wecom/production.mjs +5 -1
- package/plugin-src/host/channels/wecom/rpc.mjs +5 -3
- package/plugin-src/host/channels/wecom-app/production.mjs +5 -1
- package/plugin-src/host/channels/wecom-app/rpc.mjs +5 -3
- package/plugin-src/host/channels/weixin/production.mjs +5 -1
- package/plugin-src/host/channels/whatsapp/production.mjs +5 -1
- package/plugin-src/host/channels/whatsapp/rpc.mjs +5 -3
- package/plugin-src/host/delivery-adapter.mjs +11 -0
- package/plugin-src/host/image-input-rpc.mjs +24 -0
- package/plugin-src/host/inbound-ttl-rpc.mjs +6 -1
- package/plugin-src/host/index.mjs +3 -0
- package/plugin-src/management-rpc.mjs +12 -2
- package/scripts/verify-package.mjs +3 -1
- package/src/channels/dingtalk/connection-error.mjs +5 -12
- package/src/channels/dingtalk/device-auth.mjs +4 -1
- package/src/channels/dingtalk/dingtalk-bridge.mjs +6 -4
- package/src/channels/dingtalk/dingtalk-controller.mjs +60 -45
- package/src/channels/dingtalk/dingtalk-runtime.mjs +20 -4
- package/src/channels/discord/discord-api.mjs +3 -3
- package/src/channels/discord/discord-runtime.mjs +18 -12
- package/src/channels/email/config-store.mjs +194 -0
- package/src/channels/email/email-api.mjs +20 -0
- package/src/channels/email/email-bridge.mjs +17 -0
- package/src/channels/email/email-controller.mjs +824 -0
- package/src/channels/email/email-runtime.mjs +692 -0
- package/src/channels/email/harness-client.mjs +7 -0
- package/src/channels/email/mail-format.mjs +91 -0
- package/src/channels/email/state-store.mjs +176 -0
- package/src/channels/email/transport.mjs +64 -0
- package/src/channels/email/transports/agent-mail.mjs +593 -0
- package/src/channels/email/transports/agently-cli.mjs +288 -0
- package/src/channels/email/transports/imap-smtp.mjs +165 -0
- package/src/channels/feishu/bridge.mjs +8 -7
- package/src/channels/feishu/feishu-runtime.mjs +15 -8
- package/src/channels/feishu/group-message-permission-manager.mjs +2 -1
- package/src/channels/feishu/message-utils.mjs +3 -2
- package/src/channels/feishu/multi-bot-controller.mjs +56 -47
- package/src/channels/feishu/registration-manager.mjs +8 -4
- package/src/channels/feishu/repair-manager.mjs +2 -1
- package/src/channels/imessage/runtime.mjs +9 -5
- package/src/channels/office/office-controller.mjs +23 -12
- package/src/channels/office/office-runtime.mjs +6 -3
- package/src/channels/office/office-transport.mjs +1 -0
- package/src/channels/qq/qq-bridge.mjs +7 -5
- package/src/channels/qq/qq-controller.mjs +56 -42
- package/src/channels/qq/qq-runtime.mjs +16 -11
- package/src/channels/shared/bot-workspace-store.mjs +37 -21
- package/src/channels/shared/connection-error.mjs +191 -0
- package/src/channels/shared/connection-test.mjs +3 -1
- package/src/channels/shared/conversation-state-store.mjs +46 -1
- package/src/channels/shared/default-workspace.mjs +28 -0
- package/src/channels/shared/diagnostic-details.mjs +95 -0
- package/src/channels/shared/harness-client.mjs +111 -20
- package/src/channels/shared/harness-session-binding.mjs +13 -8
- package/src/channels/shared/i18n-en/diagnostics.mjs +55 -0
- package/src/channels/shared/i18n-en/email.mjs +25 -0
- package/src/channels/shared/i18n-en/image-input.mjs +17 -0
- package/src/channels/shared/i18n-en/shared-a.mjs +1 -0
- package/src/channels/shared/i18n-en/shared-c.mjs +1 -1
- package/src/channels/shared/i18n-en.mjs +6 -0
- package/src/channels/shared/image-input-policy.mjs +35 -0
- package/src/channels/shared/image-input-settings-store.mjs +60 -0
- package/src/channels/shared/image-input.mjs +124 -0
- package/src/channels/shared/image-prompt.mjs +15 -7
- package/src/channels/shared/message-failure.mjs +12 -0
- package/src/channels/shared/semantic/reply-reference.mjs +3 -3
- package/src/channels/shared/text-harness-bridge.mjs +90 -11
- package/src/channels/shared/token-bot-controller.mjs +52 -47
- package/src/channels/slack/slack-api.mjs +3 -3
- package/src/channels/slack/slack-controller.mjs +59 -51
- package/src/channels/slack/slack-runtime.mjs +18 -12
- package/src/channels/telegram/telegram-api.mjs +2 -2
- package/src/channels/telegram/telegram-runtime.mjs +17 -13
- package/src/channels/wecom/wecom-bridge.mjs +15 -6
- package/src/channels/wecom/wecom-controller.mjs +51 -37
- package/src/channels/wecom/wecom-runtime.mjs +10 -6
- package/src/channels/wecom-app/wecom-app-bridge.mjs +7 -5
- package/src/channels/wecom-app/wecom-app-controller.mjs +50 -37
- package/src/channels/wecom-app/wecom-app-runtime.mjs +2 -1
- package/src/channels/weixin/connection-error.mjs +26 -92
- package/src/channels/weixin/diagnostic-details.mjs +1 -63
- package/src/channels/weixin/weixin-bridge.mjs +7 -5
- package/src/channels/whatsapp/whatsapp-controller.mjs +34 -17
- package/src/channels/whatsapp/whatsapp-runtime.mjs +35 -8
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getImageInputSettingsStore } from '../../../../src/channels/shared/image-input-settings-store.mjs';
|
|
1
2
|
import { unlink } from 'node:fs/promises';
|
|
2
3
|
import { resolve } from 'node:path';
|
|
3
4
|
|
|
@@ -12,6 +13,7 @@ import {
|
|
|
12
13
|
createWorkspaceAwareController,
|
|
13
14
|
observeBotWorkspaceRemovals,
|
|
14
15
|
} from '../../../../src/channels/shared/bot-workspace-store.mjs';
|
|
16
|
+
import { prepareBotWorkspace } from '../../../../src/channels/shared/default-workspace.mjs';
|
|
15
17
|
import { listAgentPresetCatalog } from '../../../../src/channels/shared/agent-preset.mjs';
|
|
16
18
|
import { listModelCatalog } from '../../../../src/channels/shared/model-setting.mjs';
|
|
17
19
|
import { createDeliveryAdapter } from '../../delivery-adapter.mjs';
|
|
@@ -44,7 +46,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
44
46
|
const agentPresetCatalog = () => listAgentPresetCatalog(ctx);
|
|
45
47
|
const paths = pluginPaths(config, 'slack');
|
|
46
48
|
const configStore = await new ResolvedConfigStore(paths.config).load();
|
|
47
|
-
const defaultWorkspace =
|
|
49
|
+
const { defaultWorkspace, ungroupedWorkspace } = await prepareBotWorkspace(config);
|
|
48
50
|
const WorkspaceStore = internals.WorkspaceStore ?? BotWorkspaceStore;
|
|
49
51
|
const workspaces = internals.workspaces
|
|
50
52
|
?? await new WorkspaceStore(paths.workspaces, { defaultWorkspace }).load();
|
|
@@ -84,12 +86,14 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
84
86
|
const harness = new ResolvedHarness({
|
|
85
87
|
...connection,
|
|
86
88
|
workspace: defaultWorkspace,
|
|
89
|
+
ungroupedWorkspace,
|
|
87
90
|
autostart: false,
|
|
88
91
|
dshBin: config.dshBin ?? 'dsh',
|
|
89
92
|
...(commandExecutor ? { commandExecutor } : {}),
|
|
90
93
|
...(controlExecutor ? { controlExecutor } : {}),
|
|
91
94
|
...(sessionMaintenanceExecutor ? { sessionMaintenanceExecutor } : {}),
|
|
92
95
|
...(fileIngressExecutor ? { fileIngressExecutor } : {}),
|
|
96
|
+
imageInputPolicy: () => getImageInputSettingsStore(config).get(),
|
|
93
97
|
});
|
|
94
98
|
const modelCatalog = () => listModelCatalog(harness);
|
|
95
99
|
const coreController = new ResolvedController({
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createConnectionDiagnostics, diagnosticRpcResult } from '../../../../src/channels/shared/connection-error.mjs';
|
|
1
2
|
import { SET_ALIAS_ENDPOINT, validAliasPayload } from '../shared/bot-alias-rpc.mjs';
|
|
2
3
|
import { registerManagementRpc } from '../../../management-rpc.mjs';
|
|
3
4
|
import { SET_CONTEXT_ENHANCEMENT_ENDPOINT, validContextEnhancementPayload } from '../shared/context-enhancement-rpc.mjs';
|
|
@@ -131,6 +132,7 @@ function operationError(error) {
|
|
|
131
132
|
}
|
|
132
133
|
|
|
133
134
|
export function createSlackRpcHandler(controller) {
|
|
135
|
+
const diagnostics = controller.diagnostics ?? createConnectionDiagnostics({ channel: 'slack' });
|
|
134
136
|
for (const method of ['status', 'bindCredentials', 'reconnectBot', 'deleteBot']) {
|
|
135
137
|
if (typeof controller?.[method] !== 'function') {
|
|
136
138
|
throw new TypeError(`A complete Slack controller is required (${method})`);
|
|
@@ -171,7 +173,7 @@ export function createSlackRpcHandler(controller) {
|
|
|
171
173
|
} catch (error) {
|
|
172
174
|
testError = error;
|
|
173
175
|
}
|
|
174
|
-
value = { ...value, testMessage: publicConnectionTestResult(testError) };
|
|
176
|
+
value = { ...value, testMessage: publicConnectionTestResult(testError, { diagnostics, botId: payload.botId }) };
|
|
175
177
|
}
|
|
176
178
|
}
|
|
177
179
|
else if (endpoint === SLACK_ENDPOINTS.setWorkspace) {
|
|
@@ -203,9 +205,9 @@ export function createSlackRpcHandler(controller) {
|
|
|
203
205
|
? { ok: false, error: { code: 'cancelled', message: 'The request was cancelled.' } }
|
|
204
206
|
: { ok: true, value: sanitizePublic(value) };
|
|
205
207
|
} catch (error) {
|
|
206
|
-
return signal?.aborted
|
|
208
|
+
return diagnosticRpcResult(diagnostics, error, signal?.aborted
|
|
207
209
|
? { ok: false, error: { code: 'cancelled', message: 'The request was cancelled.' } }
|
|
208
|
-
: { ok: false, error: operationError(error) };
|
|
210
|
+
: { ok: false, error: operationError(error) }, { operation: endpoint, botId: payload?.botId });
|
|
209
211
|
}
|
|
210
212
|
};
|
|
211
213
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getImageInputSettingsStore } from '../../../../src/channels/shared/image-input-settings-store.mjs';
|
|
1
2
|
import { unlink } from 'node:fs/promises';
|
|
2
3
|
import { homedir } from 'node:os';
|
|
3
4
|
import { join, resolve } from 'node:path';
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
createWorkspaceAwareController,
|
|
15
16
|
observeBotWorkspaceRemovals,
|
|
16
17
|
} from '../../../../src/channels/shared/bot-workspace-store.mjs';
|
|
18
|
+
import { prepareBotWorkspace } from '../../../../src/channels/shared/default-workspace.mjs';
|
|
17
19
|
import { listAgentPresetCatalog } from '../../../../src/channels/shared/agent-preset.mjs';
|
|
18
20
|
import { listModelCatalog } from '../../../../src/channels/shared/model-setting.mjs';
|
|
19
21
|
import { createDeliveryAdapter } from '../../delivery-adapter.mjs';
|
|
@@ -55,7 +57,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
55
57
|
const agentPresetCatalog = () => listAgentPresetCatalog(ctx);
|
|
56
58
|
const paths = pluginPaths(config);
|
|
57
59
|
const configStore = await new ConfigStore(paths.config).load();
|
|
58
|
-
const defaultWorkspace =
|
|
60
|
+
const { defaultWorkspace, ungroupedWorkspace } = await prepareBotWorkspace(config);
|
|
59
61
|
const WorkspaceStore = internals.WorkspaceStore ?? BotWorkspaceStore;
|
|
60
62
|
const workspaces = internals.workspaces
|
|
61
63
|
?? await new WorkspaceStore(paths.workspaces, { defaultWorkspace }).load();
|
|
@@ -99,12 +101,14 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
99
101
|
const harness = new Harness({
|
|
100
102
|
...connection,
|
|
101
103
|
workspace: defaultWorkspace,
|
|
104
|
+
ungroupedWorkspace,
|
|
102
105
|
autostart: false,
|
|
103
106
|
dshBin: config.dshBin ?? 'dsh',
|
|
104
107
|
...(commandExecutor ? { commandExecutor } : {}),
|
|
105
108
|
...(controlExecutor ? { controlExecutor } : {}),
|
|
106
109
|
...(sessionMaintenanceExecutor ? { sessionMaintenanceExecutor } : {}),
|
|
107
110
|
...(fileIngressExecutor ? { fileIngressExecutor } : {}),
|
|
111
|
+
imageInputPolicy: () => getImageInputSettingsStore(config).get(),
|
|
108
112
|
});
|
|
109
113
|
const modelCatalog = () => listModelCatalog(harness);
|
|
110
114
|
const coreController = new Controller({
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createConnectionDiagnostics, diagnosticRpcResult } from '../../../../src/channels/shared/connection-error.mjs';
|
|
1
2
|
import { SET_ALIAS_ENDPOINT, validAliasPayload } from '../shared/bot-alias-rpc.mjs';
|
|
2
3
|
import { registerManagementRpc } from '../../../management-rpc.mjs';
|
|
3
4
|
import QRCode from 'qrcode';
|
|
@@ -131,6 +132,7 @@ async function publicStatus(status, encodeQr) {
|
|
|
131
132
|
}
|
|
132
133
|
|
|
133
134
|
export function createWecomRpcHandler(controller, { encodeQr = qrDataUrl } = {}) {
|
|
135
|
+
const diagnostics = controller.diagnostics ?? createConnectionDiagnostics({ channel: 'wecom' });
|
|
134
136
|
for (const method of ['status', 'startProvisioning', 'registrationStatus', 'cancelProvisioning', 'bindCredentials', 'reconnectBot', 'deleteBot']) {
|
|
135
137
|
if (typeof controller?.[method] !== 'function') {
|
|
136
138
|
throw new TypeError(`A complete Enterprise WeChat controller is required (${method})`);
|
|
@@ -185,7 +187,7 @@ export function createWecomRpcHandler(controller, { encodeQr = qrDataUrl } = {})
|
|
|
185
187
|
await controller.sendConnectionTest(payload.botId);
|
|
186
188
|
testMessage = publicConnectionTestResult();
|
|
187
189
|
} catch (error) {
|
|
188
|
-
testMessage = publicConnectionTestResult(error);
|
|
190
|
+
testMessage = publicConnectionTestResult(error, { diagnostics, botId: payload.botId });
|
|
189
191
|
}
|
|
190
192
|
}
|
|
191
193
|
}
|
|
@@ -231,10 +233,10 @@ export function createWecomRpcHandler(controller, { encodeQr = qrDataUrl } = {})
|
|
|
231
233
|
: { ok: true, value };
|
|
232
234
|
} catch (error) {
|
|
233
235
|
const workspaceError = publicWorkspaceError(error);
|
|
234
|
-
return signal?.aborted
|
|
236
|
+
return diagnosticRpcResult(diagnostics, error, signal?.aborted
|
|
235
237
|
? { ok: false, error: { code: 'cancelled', message: 'The request was cancelled.' } }
|
|
236
238
|
: { ok: false, error: workspaceError
|
|
237
|
-
?? { code: 'wecom-operation-failed', message: '企业微信操作失败,请稍后重试。' } };
|
|
239
|
+
?? { code: 'wecom-operation-failed', message: '企业微信操作失败,请稍后重试。' } }, { operation: endpoint, botId: payload?.botId });
|
|
238
240
|
}
|
|
239
241
|
};
|
|
240
242
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getImageInputSettingsStore } from '../../../../src/channels/shared/image-input-settings-store.mjs';
|
|
1
2
|
import { unlink } from 'node:fs/promises';
|
|
2
3
|
import { homedir } from 'node:os';
|
|
3
4
|
import { join, resolve } from 'node:path';
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
createWorkspaceAwareController,
|
|
15
16
|
observeBotWorkspaceRemovals,
|
|
16
17
|
} from '../../../../src/channels/shared/bot-workspace-store.mjs';
|
|
18
|
+
import { prepareBotWorkspace } from '../../../../src/channels/shared/default-workspace.mjs';
|
|
17
19
|
import { listAgentPresetCatalog } from '../../../../src/channels/shared/agent-preset.mjs';
|
|
18
20
|
import { listModelCatalog } from '../../../../src/channels/shared/model-setting.mjs';
|
|
19
21
|
import { createDeliveryAdapter } from '../../delivery-adapter.mjs';
|
|
@@ -69,7 +71,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
69
71
|
const agentPresetCatalog = () => listAgentPresetCatalog(ctx);
|
|
70
72
|
const paths = pluginPaths(config);
|
|
71
73
|
const configStore = await new ConfigStore(paths.config).load();
|
|
72
|
-
const defaultWorkspace =
|
|
74
|
+
const { defaultWorkspace, ungroupedWorkspace } = await prepareBotWorkspace(config);
|
|
73
75
|
const WorkspaceStore = internals.WorkspaceStore ?? BotWorkspaceStore;
|
|
74
76
|
const workspaces = internals.workspaces
|
|
75
77
|
?? await new WorkspaceStore(paths.workspaces, { defaultWorkspace }).load();
|
|
@@ -133,12 +135,14 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
133
135
|
const harness = new Harness({
|
|
134
136
|
...connection,
|
|
135
137
|
workspace: defaultWorkspace,
|
|
138
|
+
ungroupedWorkspace,
|
|
136
139
|
autostart: false,
|
|
137
140
|
dshBin: config.dshBin ?? 'dsh',
|
|
138
141
|
...(commandExecutor ? { commandExecutor } : {}),
|
|
139
142
|
...(controlExecutor ? { controlExecutor } : {}),
|
|
140
143
|
...(sessionMaintenanceExecutor ? { sessionMaintenanceExecutor } : {}),
|
|
141
144
|
...(fileIngressExecutor ? { fileIngressExecutor } : {}),
|
|
145
|
+
imageInputPolicy: () => getImageInputSettingsStore(config).get(),
|
|
142
146
|
});
|
|
143
147
|
const modelCatalog = () => listModelCatalog(harness);
|
|
144
148
|
const coreController = new Controller({
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createConnectionDiagnostics, diagnosticRpcResult } from '../../../../src/channels/shared/connection-error.mjs';
|
|
1
2
|
import { SET_ALIAS_ENDPOINT, validAliasPayload } from '../shared/bot-alias-rpc.mjs';
|
|
2
3
|
import { registerManagementRpc } from '../../../management-rpc.mjs';
|
|
3
4
|
import { SET_CONTEXT_ENHANCEMENT_ENDPOINT, validContextEnhancementPayload } from '../shared/context-enhancement-rpc.mjs';
|
|
@@ -136,6 +137,7 @@ function publicStatus(status) {
|
|
|
136
137
|
}
|
|
137
138
|
|
|
138
139
|
export function createWecomAppRpcHandler(controller) {
|
|
140
|
+
const diagnostics = controller.diagnostics ?? createConnectionDiagnostics({ channel: 'wecom-app' });
|
|
139
141
|
for (const method of ['status', 'bindApp', 'updateAppSettings', 'resetCallbackSecret', 'reconnectBot', 'deleteBot']) {
|
|
140
142
|
if (typeof controller?.[method] !== 'function') {
|
|
141
143
|
throw new TypeError(`A complete Enterprise WeChat app controller is required (${method})`);
|
|
@@ -178,7 +180,7 @@ export function createWecomAppRpcHandler(controller) {
|
|
|
178
180
|
await controller.sendConnectionTest(payload.botId);
|
|
179
181
|
testMessage = publicConnectionTestResult();
|
|
180
182
|
} catch (error) {
|
|
181
|
-
testMessage = publicConnectionTestResult(error);
|
|
183
|
+
testMessage = publicConnectionTestResult(error, { diagnostics, botId: payload.botId });
|
|
182
184
|
}
|
|
183
185
|
}
|
|
184
186
|
}
|
|
@@ -215,11 +217,11 @@ export function createWecomAppRpcHandler(controller) {
|
|
|
215
217
|
: { ok: true, value };
|
|
216
218
|
} catch (error) {
|
|
217
219
|
const workspaceError = publicWorkspaceError(error);
|
|
218
|
-
return signal?.aborted
|
|
220
|
+
return diagnosticRpcResult(diagnostics, error, signal?.aborted
|
|
219
221
|
? { ok: false, error: { code: 'cancelled', message: 'The request was cancelled.', details: {} } }
|
|
220
222
|
: { ok: false, error: workspaceError
|
|
221
223
|
? { ...workspaceError, details: {} }
|
|
222
|
-
: { code: 'wecom-app-operation-failed', message: '企业微信应用操作失败,请稍后重试。', details: {} } };
|
|
224
|
+
: { code: 'wecom-app-operation-failed', message: '企业微信应用操作失败,请稍后重试。', details: {} } }, { operation: endpoint, botId: payload?.botId });
|
|
223
225
|
}
|
|
224
226
|
};
|
|
225
227
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getImageInputSettingsStore } from '../../../../src/channels/shared/image-input-settings-store.mjs';
|
|
1
2
|
import { unlink } from 'node:fs/promises';
|
|
2
3
|
import { homedir } from 'node:os';
|
|
3
4
|
import { join, resolve } from 'node:path';
|
|
@@ -18,6 +19,7 @@ import {
|
|
|
18
19
|
createWorkspaceAwareController,
|
|
19
20
|
observeBotWorkspaceRemovals,
|
|
20
21
|
} from '../../../../src/channels/shared/bot-workspace-store.mjs';
|
|
22
|
+
import { prepareBotWorkspace } from '../../../../src/channels/shared/default-workspace.mjs';
|
|
21
23
|
import { listAgentPresetCatalog } from '../../../../src/channels/shared/agent-preset.mjs';
|
|
22
24
|
import { listModelCatalog } from '../../../../src/channels/shared/model-setting.mjs';
|
|
23
25
|
import { createDeliveryAdapter } from '../../delivery-adapter.mjs';
|
|
@@ -90,7 +92,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
90
92
|
const agentPresetCatalog = () => listAgentPresetCatalog(ctx);
|
|
91
93
|
const paths = pluginPaths(config);
|
|
92
94
|
const configStore = await new ConfigStore(paths.config).load();
|
|
93
|
-
const defaultWorkspace =
|
|
95
|
+
const { defaultWorkspace, ungroupedWorkspace } = await prepareBotWorkspace(config);
|
|
94
96
|
const WorkspaceStore = internals.WorkspaceStore ?? BotWorkspaceStore;
|
|
95
97
|
const workspaces = diagnosticWorkspaces(internals.workspaces
|
|
96
98
|
?? await new WorkspaceStore(paths.workspaces, { defaultWorkspace }).load());
|
|
@@ -131,12 +133,14 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
131
133
|
const harness = new Harness({
|
|
132
134
|
...connection,
|
|
133
135
|
workspace: defaultWorkspace,
|
|
136
|
+
ungroupedWorkspace,
|
|
134
137
|
autostart: false,
|
|
135
138
|
dshBin: config.dshBin ?? 'dsh',
|
|
136
139
|
...(commandExecutor ? { commandExecutor } : {}),
|
|
137
140
|
...(controlExecutor ? { controlExecutor } : {}),
|
|
138
141
|
...(sessionMaintenanceExecutor ? { sessionMaintenanceExecutor } : {}),
|
|
139
142
|
...(fileIngressExecutor ? { fileIngressExecutor } : {}),
|
|
143
|
+
imageInputPolicy: () => getImageInputSettingsStore(config).get(),
|
|
140
144
|
});
|
|
141
145
|
const modelCatalog = () => listModelCatalog(harness);
|
|
142
146
|
const coreController = new Controller({
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getImageInputSettingsStore } from '../../../../src/channels/shared/image-input-settings-store.mjs';
|
|
1
2
|
import { rm, unlink } from 'node:fs/promises';
|
|
2
3
|
import { homedir } from 'node:os';
|
|
3
4
|
import { join, resolve } from 'node:path';
|
|
@@ -17,6 +18,7 @@ import {
|
|
|
17
18
|
createWorkspaceAwareController,
|
|
18
19
|
observeBotWorkspaceRemovals,
|
|
19
20
|
} from '../../../../src/channels/shared/bot-workspace-store.mjs';
|
|
21
|
+
import { prepareBotWorkspace } from '../../../../src/channels/shared/default-workspace.mjs';
|
|
20
22
|
import { listAgentPresetCatalog } from '../../../../src/channels/shared/agent-preset.mjs';
|
|
21
23
|
import { listModelCatalog } from '../../../../src/channels/shared/model-setting.mjs';
|
|
22
24
|
import { createDeliveryAdapter } from '../../delivery-adapter.mjs';
|
|
@@ -65,7 +67,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
65
67
|
const createSupervisor = internals.createConnectionSupervisor ?? createTokenConnectionSupervisor;
|
|
66
68
|
const paths = pluginPaths(config);
|
|
67
69
|
const configStore = await new ConfigStore(paths.config).load();
|
|
68
|
-
const defaultWorkspace =
|
|
70
|
+
const { defaultWorkspace, ungroupedWorkspace } = await prepareBotWorkspace(config);
|
|
69
71
|
const WorkspaceStore = internals.WorkspaceStore ?? BotWorkspaceStore;
|
|
70
72
|
const workspaces = internals.workspaces
|
|
71
73
|
?? await new WorkspaceStore(paths.workspaces, { defaultWorkspace }).load();
|
|
@@ -105,12 +107,14 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
105
107
|
const harness = new Harness({
|
|
106
108
|
...connection,
|
|
107
109
|
workspace: defaultWorkspace,
|
|
110
|
+
ungroupedWorkspace,
|
|
108
111
|
autostart: false,
|
|
109
112
|
dshBin: config.dshBin ?? 'dsh',
|
|
110
113
|
...(commandExecutor ? { commandExecutor } : {}),
|
|
111
114
|
...(controlExecutor ? { controlExecutor } : {}),
|
|
112
115
|
...(sessionMaintenanceExecutor ? { sessionMaintenanceExecutor } : {}),
|
|
113
116
|
...(fileIngressExecutor ? { fileIngressExecutor } : {}),
|
|
117
|
+
imageInputPolicy: () => getImageInputSettingsStore(config).get(),
|
|
114
118
|
});
|
|
115
119
|
const modelCatalog = () => listModelCatalog(harness);
|
|
116
120
|
const coreController = new Controller({
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createConnectionDiagnostics, diagnosticRpcResult } from '../../../../src/channels/shared/connection-error.mjs';
|
|
1
2
|
import { SET_ALIAS_ENDPOINT, validAliasPayload } from '../shared/bot-alias-rpc.mjs';
|
|
2
3
|
import { registerManagementRpc } from '../../../management-rpc.mjs';
|
|
3
4
|
import QRCode from 'qrcode';
|
|
@@ -116,6 +117,7 @@ async function publicStatus(value, encodeQr) {
|
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
export function createWhatsappRpcHandler(controller, { encodeQr = qrDataUrl } = {}) {
|
|
120
|
+
const diagnostics = controller.diagnostics ?? createConnectionDiagnostics({ channel: 'whatsapp' });
|
|
119
121
|
for (const method of ['status', 'startProvisioning', 'registrationStatus', 'cancelProvisioning', 'reconnectBot', 'deleteBot']) {
|
|
120
122
|
if (typeof controller?.[method] !== 'function') {
|
|
121
123
|
throw new TypeError(`A complete WhatsApp controller is required (${method})`);
|
|
@@ -176,7 +178,7 @@ export function createWhatsappRpcHandler(controller, { encodeQr = qrDataUrl } =
|
|
|
176
178
|
testError = error;
|
|
177
179
|
}
|
|
178
180
|
}
|
|
179
|
-
value = { ...value, testMessage: publicConnectionTestResult(testError) };
|
|
181
|
+
value = { ...value, testMessage: publicConnectionTestResult(testError, { diagnostics, botId: payload.botId }) };
|
|
180
182
|
}
|
|
181
183
|
} else if (endpoint === WHATSAPP_ENDPOINTS.setWorkspace) {
|
|
182
184
|
if (typeof controller.updateWorkspace !== 'function') throw new Error('Workspace update is unavailable');
|
|
@@ -223,10 +225,10 @@ export function createWhatsappRpcHandler(controller, { encodeQr = qrDataUrl } =
|
|
|
223
225
|
: { ok: true, value };
|
|
224
226
|
} catch (error) {
|
|
225
227
|
const workspaceError = publicWorkspaceError(error);
|
|
226
|
-
return signal?.aborted
|
|
228
|
+
return diagnosticRpcResult(diagnostics, error, signal?.aborted
|
|
227
229
|
? { ok: false, error: { code: 'cancelled', message: 'The request was cancelled.' } }
|
|
228
230
|
: { ok: false, error: workspaceError
|
|
229
|
-
?? { code: 'whatsapp-operation-failed', message: 'WhatsApp 操作失败,请稍后重试。' } };
|
|
231
|
+
?? { code: 'whatsapp-operation-failed', message: 'WhatsApp 操作失败,请稍后重试。' } }, { operation: endpoint, botId: payload?.botId });
|
|
230
232
|
}
|
|
231
233
|
};
|
|
232
234
|
}
|
|
@@ -16,6 +16,7 @@ const CHANNELS = new Set([
|
|
|
16
16
|
'discord',
|
|
17
17
|
'whatsapp',
|
|
18
18
|
'imessage',
|
|
19
|
+
'email',
|
|
19
20
|
]);
|
|
20
21
|
|
|
21
22
|
export function supportsDeliveryChannel(channel) {
|
|
@@ -126,6 +127,16 @@ function normalizeRoute(channel, kind, route) {
|
|
|
126
127
|
case 'imessage':
|
|
127
128
|
oneOf(kind, ['user']);
|
|
128
129
|
return routeWithStrings(route, ['chatGuid']);
|
|
130
|
+
case 'email': {
|
|
131
|
+
oneOf(kind, ['user']);
|
|
132
|
+
const normalized = routeWithStrings(route, ['address']);
|
|
133
|
+
// Mail addresses are normalized to lower case everywhere so a target
|
|
134
|
+
// created from a mixed-case address still matches.
|
|
135
|
+
if (!/^[^\s@<>]+@[^\s@<>]+\.[^\s@<>]+$/.test(normalized.address)) {
|
|
136
|
+
throw invalidTarget('route.address must be a valid email address');
|
|
137
|
+
}
|
|
138
|
+
return { address: normalized.address.toLowerCase() };
|
|
139
|
+
}
|
|
129
140
|
default:
|
|
130
141
|
throw new TypeError(`Unsupported delivery channel: ${channel}`);
|
|
131
142
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { normalizeImageInputSettings } from '../../src/channels/shared/image-input-policy.mjs';
|
|
2
|
+
|
|
3
|
+
export const IMAGE_INPUT_ENDPOINTS = Object.freeze({
|
|
4
|
+
get: 'settings.image-input.get',
|
|
5
|
+
set: 'settings.image-input.set',
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export function createImageInputRpcHandler(store) {
|
|
9
|
+
return async (endpoint, payload, signal) => {
|
|
10
|
+
const object = payload && typeof payload === 'object' && !Array.isArray(payload);
|
|
11
|
+
const valid = object && (endpoint === IMAGE_INPUT_ENDPOINTS.get
|
|
12
|
+
? Object.keys(payload).length === 0
|
|
13
|
+
: endpoint === IMAGE_INPUT_ENDPOINTS.set && Object.keys(payload).length === 4
|
|
14
|
+
&& normalizeImageInputSettings(payload));
|
|
15
|
+
if (!valid) return { ok: false, error: { code: 'bad-request', message: '图片限制无效:请输入正整数,原图接收上限和总量上限不能小于单图上限。' } };
|
|
16
|
+
if (signal?.aborted) return { ok: false, error: { code: 'cancelled', message: 'Request cancelled.' } };
|
|
17
|
+
try {
|
|
18
|
+
const value = endpoint === IMAGE_INPUT_ENDPOINTS.get ? await store.get() : await store.set(payload);
|
|
19
|
+
return { ok: true, value };
|
|
20
|
+
} catch {
|
|
21
|
+
return { ok: false, error: { code: 'image-input-settings-unavailable', message: '无法读取或保存图片设置,请稍后重试。' } };
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { registerManagementRpc } from '../management-rpc.mjs';
|
|
2
2
|
import { normalizeInboundTtlHours } from '../../src/channels/shared/inbound-ttl.mjs';
|
|
3
3
|
import { getInboundTtlRuntime } from './inbound-ttl-runtime.mjs';
|
|
4
|
+
import { getImageInputSettingsStore } from '../../src/channels/shared/image-input-settings-store.mjs';
|
|
5
|
+
import { createImageInputRpcHandler, IMAGE_INPUT_ENDPOINTS } from './image-input-rpc.mjs';
|
|
4
6
|
|
|
5
7
|
export const INBOUND_TTL_RPC_CHANNEL = '/dsh-im-settings';
|
|
6
8
|
export const INBOUND_TTL_ENDPOINTS = Object.freeze({
|
|
@@ -73,9 +75,12 @@ export function installInboundTtlRpc(ctx, options = {}) {
|
|
|
73
75
|
const runtime = options.runtime ?? getInboundTtlRuntime(ctx, options.config);
|
|
74
76
|
const logger = typeof ctx?.logger === 'function'
|
|
75
77
|
? ctx.logger('dsh-im:inbound-ttl') : (ctx?.logger ?? null);
|
|
78
|
+
const ttl = createInboundTtlRpcHandler({ ...runtime, logger });
|
|
79
|
+
const image = createImageInputRpcHandler(getImageInputSettingsStore(options.config));
|
|
76
80
|
return registerManagementRpc(ctx,
|
|
77
81
|
INBOUND_TTL_RPC_CHANNEL,
|
|
78
|
-
|
|
82
|
+
(endpoint, payload, signal) => Object.values(IMAGE_INPUT_ENDPOINTS).includes(endpoint)
|
|
83
|
+
? image(endpoint, payload, signal) : ttl(endpoint, payload, signal),
|
|
79
84
|
{ authority: 'loopback' },
|
|
80
85
|
);
|
|
81
86
|
}
|
|
@@ -10,6 +10,7 @@ import { apply as applyWecomApp } from './channels/wecom-app/index.mjs';
|
|
|
10
10
|
import { apply as applyWeixin } from './channels/weixin/index.mjs';
|
|
11
11
|
import { apply as applyWhatsapp } from './channels/whatsapp/index.mjs';
|
|
12
12
|
import { apply as applyIMessage } from './channels/imessage/index.mjs';
|
|
13
|
+
import { apply as applyEmail } from './channels/email/index.mjs';
|
|
13
14
|
import { installOutboundArtifactTool } from '../../src/channels/shared/semantic/artifact.mjs';
|
|
14
15
|
import { installHostLanguage } from './host-language.mjs';
|
|
15
16
|
import { installHostLanguageRpc } from './host-language-rpc.mjs';
|
|
@@ -60,6 +61,7 @@ export function createImHostPlugin(internals = {}) {
|
|
|
60
61
|
const startOffice = internals.applyOffice ?? applyOffice;
|
|
61
62
|
const startWhatsapp = internals.applyWhatsapp ?? applyWhatsapp;
|
|
62
63
|
const startIMessage = internals.applyIMessage ?? applyIMessage;
|
|
64
|
+
const startEmail = internals.applyEmail ?? applyEmail;
|
|
63
65
|
const channels = [
|
|
64
66
|
['feishu', startFeishu],
|
|
65
67
|
['weixin', startWeixin],
|
|
@@ -72,6 +74,7 @@ export function createImHostPlugin(internals = {}) {
|
|
|
72
74
|
['discord', startDiscord],
|
|
73
75
|
['whatsapp', startWhatsapp],
|
|
74
76
|
['imessage', startIMessage],
|
|
77
|
+
['email', startEmail],
|
|
75
78
|
['office', startOffice],
|
|
76
79
|
];
|
|
77
80
|
return Object.freeze({
|
|
@@ -72,6 +72,16 @@ export function registerManagementRpc(ctx, channel, handler, { authority } = {})
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
/** Keep channel UI callers unchanged while using DSH's native correlation and response validation. */
|
|
75
|
-
export function callManagementRpc(connection, channel, method, payload, signal) {
|
|
76
|
-
|
|
75
|
+
export async function callManagementRpc(connection, channel, method, payload, signal) {
|
|
76
|
+
try {
|
|
77
|
+
return await connection.rpc.call('/api', rpcEndpoint(channel), { method, payload }, signal);
|
|
78
|
+
} catch (cause) {
|
|
79
|
+
if (signal?.aborted || cause?.name === 'AbortError') throw cause;
|
|
80
|
+
const error = new Error('无法访问 DSH 管理接口,请检查 DSH 连接或重新登录后重试。', { cause });
|
|
81
|
+
error.code = 'management-unreachable';
|
|
82
|
+
error.details = { operation: method, stage: 'management.request', occurredAt: new Date().toISOString(),
|
|
83
|
+
...(Number.isInteger(cause?.status) && cause.status >= 100 && cause.status <= 599 ? { httpStatus: cause.status } : {}),
|
|
84
|
+
};
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
77
87
|
}
|
|
@@ -147,9 +147,11 @@ if (client.includes('settings.plugins.tab') || clientSources.includes('settings.
|
|
|
147
147
|
// template; the delivery target adds one ordinary checkbox template.
|
|
148
148
|
const contextEditorSource = await readFile(resolve(root, 'plugin-src/client/context-enhancement.js'), 'utf8');
|
|
149
149
|
const deliverySettingsSource = await readFile(resolve(root, 'plugin-src/client/delivery-settings.js'), 'utf8');
|
|
150
|
+
const emailSettingsSource = await readFile(resolve(root, 'plugin-src/client/channels/email/index.js'), 'utf8');
|
|
150
151
|
const otherClientSources = clientSources
|
|
151
152
|
.replace(contextEditorSource, '')
|
|
152
|
-
.replace(deliverySettingsSource, '')
|
|
153
|
+
.replace(deliverySettingsSource, '')
|
|
154
|
+
.replace(emailSettingsSource, '');
|
|
153
155
|
if (/role:\s*["']switch|type:\s*["']checkbox/.test(otherClientSources)
|
|
154
156
|
|| (deliverySettingsSource.match(/type:\s*["']checkbox["']/g) ?? []).length !== 1
|
|
155
157
|
|| /role:\s*["']switch["']/u.test(deliverySettingsSource)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { connectionErrorChain, connectionStageError } from '../shared/connection-error.mjs';
|
|
1
2
|
import { randomUUID } from 'node:crypto';
|
|
2
3
|
import { createRequire } from 'node:module';
|
|
3
4
|
|
|
@@ -62,17 +63,7 @@ export function installedDingtalkConnectionDependencies() {
|
|
|
62
63
|
return installedDependencyVersions;
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
function errorChain(error) {
|
|
66
|
-
const chain = [];
|
|
67
|
-
const seen = new Set();
|
|
68
|
-
let current = error;
|
|
69
|
-
while (current && typeof current === 'object' && chain.length < 4 && !seen.has(current)) {
|
|
70
|
-
seen.add(current);
|
|
71
|
-
chain.push(current);
|
|
72
|
-
current = current.cause;
|
|
73
|
-
}
|
|
74
|
-
return chain;
|
|
75
|
-
}
|
|
66
|
+
function errorChain(error) { return connectionErrorChain(error).chain; }
|
|
76
67
|
|
|
77
68
|
function statusFrom(error) {
|
|
78
69
|
if (Number.isInteger(error?.status)) return error.status;
|
|
@@ -153,7 +144,9 @@ export function dingtalkRuntimeStartError(code, cause) {
|
|
|
153
144
|
);
|
|
154
145
|
error.name = 'DingtalkRuntimeStartError';
|
|
155
146
|
error.code = STAGE_CODES.has(code) ? code : 'dingtalk-runtime-prepare-failed';
|
|
156
|
-
return error
|
|
147
|
+
return connectionStageError(error, ({ 'dingtalk-harness-connect-failed': 'harness.check',
|
|
148
|
+
'dingtalk-runtime-prepare-failed': 'runtime.prepare', 'dingtalk-stream-client-load-failed': 'sdk.load',
|
|
149
|
+
'dingtalk-stream-listener-failed': 'runtime.prepare', 'dingtalk-stream-connect-failed': 'connection.start' })[error.code]);
|
|
157
150
|
}
|
|
158
151
|
|
|
159
152
|
/** Creates browser-safe guidance plus a redacted Host-log diagnostic for one connection failure. */
|
|
@@ -68,6 +68,8 @@ export class DingtalkDeviceAuthError extends Error {
|
|
|
68
68
|
this.name = 'DingtalkDeviceAuthError';
|
|
69
69
|
this.code = code;
|
|
70
70
|
this.action = action;
|
|
71
|
+
if (Number.isInteger(options.status)) this.status = options.status;
|
|
72
|
+
if (Number.isFinite(options.timeoutMs)) this.timeoutMs = options.timeoutMs;
|
|
71
73
|
}
|
|
72
74
|
}
|
|
73
75
|
|
|
@@ -199,7 +201,7 @@ export class DingtalkDeviceAuth {
|
|
|
199
201
|
'timeout',
|
|
200
202
|
`DingTalk ${action} request timed out`,
|
|
201
203
|
action,
|
|
202
|
-
{ cause: error },
|
|
204
|
+
{ cause: error, timeoutMs: this.#timeoutMs },
|
|
203
205
|
);
|
|
204
206
|
}
|
|
205
207
|
if (error?.name === 'AbortError') throw error;
|
|
@@ -215,6 +217,7 @@ export class DingtalkDeviceAuth {
|
|
|
215
217
|
'http-error',
|
|
216
218
|
`DingTalk ${action} request failed`,
|
|
217
219
|
action,
|
|
220
|
+
{ status: response?.status },
|
|
218
221
|
);
|
|
219
222
|
}
|
|
220
223
|
let value;
|
|
@@ -65,6 +65,7 @@ import {
|
|
|
65
65
|
import { recoverAssistantTextByTimestamp } from '../shared/session-reply-recovery.mjs';
|
|
66
66
|
import { DINGTALK_RECENT_OUTBOUND_MATCH_TOLERANCE_MS } from './state-store.mjs';
|
|
67
67
|
import {
|
|
68
|
+
messageFailureDiagnostic,
|
|
68
69
|
channelDeliveryFailure,
|
|
69
70
|
clearLastMessageFailure,
|
|
70
71
|
messageFailureText,
|
|
@@ -740,7 +741,7 @@ export class DingtalkHarnessBridge {
|
|
|
740
741
|
const failure = setLastMessageFailure(this.#status, error);
|
|
741
742
|
this.#logger.error?.(
|
|
742
743
|
`[dsh-dingtalk] failed to process a command [${failure.referenceId}]`,
|
|
743
|
-
|
|
744
|
+
messageFailureDiagnostic(error, failure),
|
|
744
745
|
);
|
|
745
746
|
return this.#send(sessionWebhook, messageFailureText(failure), this.#atUsersFor(message)).catch(() => undefined);
|
|
746
747
|
}).finally(() => {
|
|
@@ -1207,7 +1208,7 @@ export class DingtalkHarnessBridge {
|
|
|
1207
1208
|
const failure = setLastMessageFailure(this.#status, error);
|
|
1208
1209
|
this.#logger.error?.(
|
|
1209
1210
|
`[dsh-dingtalk] failed to process a batch input message [${failure.referenceId}]`,
|
|
1210
|
-
|
|
1211
|
+
messageFailureDiagnostic(error, failure),
|
|
1211
1212
|
);
|
|
1212
1213
|
await this.#send(sessionWebhook, messageFailureText(failure)).catch(() => undefined);
|
|
1213
1214
|
}).finally(() => {
|
|
@@ -1338,7 +1339,7 @@ export class DingtalkHarnessBridge {
|
|
|
1338
1339
|
signal: this.#signal,
|
|
1339
1340
|
});
|
|
1340
1341
|
let content = hasInboundImages(modelMessage) || hasReply
|
|
1341
|
-
? await promptContentForInboundMessage(modelMessage, { signal: this.#signal })
|
|
1342
|
+
? await promptContentForInboundMessage(modelMessage, { signal: this.#signal, deferImages: true })
|
|
1342
1343
|
: undefined;
|
|
1343
1344
|
const snapshot = this.#acceptedMessageIds.get(messageId);
|
|
1344
1345
|
let contextEnhanced = false;
|
|
@@ -1395,6 +1396,7 @@ export class DingtalkHarnessBridge {
|
|
|
1395
1396
|
}),
|
|
1396
1397
|
onInteractionResolved: (resolution) => this.#handleInteractionResolved(resolution),
|
|
1397
1398
|
files: modelMessage.files,
|
|
1399
|
+
images: modelMessage.images,
|
|
1398
1400
|
},
|
|
1399
1401
|
});
|
|
1400
1402
|
if (batchSubmission) {
|
|
@@ -1486,7 +1488,7 @@ export class DingtalkHarnessBridge {
|
|
|
1486
1488
|
});
|
|
1487
1489
|
this.#logger.error?.(
|
|
1488
1490
|
`[dsh-dingtalk] failed to process an inbound message [${failure.referenceId}]`,
|
|
1489
|
-
|
|
1491
|
+
messageFailureDiagnostic(error, failure),
|
|
1490
1492
|
);
|
|
1491
1493
|
try {
|
|
1492
1494
|
const errorText = messageFailureText(failure);
|