@xmanrui/dsh-im 4.18.1 → 4.19.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 +1 -0
- package/README.md +1 -0
- package/lib/client.js +805 -515
- package/lib/index.js +269 -267
- package/package.json +1 -1
- package/plugin-src/client/bot-alias.js +92 -0
- package/plugin-src/client/channels/dingtalk/api.js +3 -0
- package/plugin-src/client/channels/dingtalk/index.js +7 -1
- package/plugin-src/client/channels/feishu/api.js +3 -0
- package/plugin-src/client/channels/feishu/index.js +7 -1
- package/plugin-src/client/channels/qq/api.js +3 -0
- package/plugin-src/client/channels/qq/index.js +9 -1
- package/plugin-src/client/channels/shared/token-api.js +3 -0
- package/plugin-src/client/channels/shared/token-channel.js +9 -2
- package/plugin-src/client/channels/wecom/api.js +3 -0
- package/plugin-src/client/channels/wecom/index.js +9 -1
- package/plugin-src/client/channels/wecom-app/api.js +3 -0
- package/plugin-src/client/channels/wecom-app/index.js +9 -1
- package/plugin-src/client/channels/weixin/api.js +3 -0
- package/plugin-src/client/channels/weixin/index.js +7 -1
- package/plugin-src/client/channels/whatsapp/api.js +3 -0
- package/plugin-src/client/channels/whatsapp/index.js +9 -1
- package/plugin-src/client/i18n.js +10 -0
- package/plugin-src/client/styles.js +26 -0
- package/plugin-src/host/channels/dingtalk/rpc.mjs +11 -0
- package/plugin-src/host/channels/feishu/production.mjs +22 -0
- package/plugin-src/host/channels/feishu/rpc.mjs +14 -0
- package/plugin-src/host/channels/imessage/rpc.mjs +1 -0
- package/plugin-src/host/channels/qq/rpc.mjs +11 -0
- package/plugin-src/host/channels/shared/bot-alias-rpc.mjs +15 -0
- package/plugin-src/host/channels/shared/rpc.mjs +9 -0
- package/plugin-src/host/channels/slack/rpc.mjs +10 -0
- package/plugin-src/host/channels/wecom/rpc.mjs +11 -0
- package/plugin-src/host/channels/wecom-app/rpc.mjs +10 -0
- package/plugin-src/host/channels/weixin/rpc.mjs +11 -0
- package/plugin-src/host/channels/whatsapp/rpc.mjs +13 -0
- package/plugin-src/host/session-sync-coordinator.mjs +19 -1
- package/src/channels/feishu/bridge.mjs +370 -7
- package/src/channels/feishu/feishu-cards.mjs +1 -1
- package/src/channels/feishu/feishu-runtime.mjs +6 -0
- package/src/channels/feishu/state-store.mjs +17 -0
- package/src/channels/shared/bot-alias.mjs +29 -0
- package/src/channels/shared/bot-workspace-store.mjs +71 -3
- package/src/channels/shared/i18n-en/shared-a.mjs +2 -2
- package/src/channels/shared/message-failure.mjs +2 -1
- package/src/channels/shared/model-command.mjs +3 -2
- package/src/channels/shared/session-sync-registry.mjs +34 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SET_ALIAS_ENDPOINT, validAliasPayload } from '../shared/bot-alias-rpc.mjs';
|
|
1
2
|
import { registerManagementRpc } from '../../../management-rpc.mjs';
|
|
2
3
|
import QRCode from 'qrcode';
|
|
3
4
|
import { SET_CONTEXT_ENHANCEMENT_ENDPOINT, validContextEnhancementPayload } from '../shared/context-enhancement-rpc.mjs';
|
|
@@ -25,6 +26,7 @@ export const DINGTALK_ENDPOINTS = Object.freeze({
|
|
|
25
26
|
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
26
27
|
setContextEnhancement: SET_CONTEXT_ENHANCEMENT_ENDPOINT,
|
|
27
28
|
setAccessPolicy: SET_ACCESS_POLICY_ENDPOINT,
|
|
29
|
+
setAlias: SET_ALIAS_ENDPOINT,
|
|
28
30
|
approveSender: 'bot.sender.approve',
|
|
29
31
|
revokeSender: 'bot.sender.revoke',
|
|
30
32
|
});
|
|
@@ -112,6 +114,10 @@ function payloadFailure(endpoint, payload) {
|
|
|
112
114
|
return validAccessPolicyPayload(payload)
|
|
113
115
|
? null : '请提交有效的访问设置。';
|
|
114
116
|
}
|
|
117
|
+
if (endpoint === DINGTALK_ENDPOINTS.setAlias) {
|
|
118
|
+
return validAliasPayload(payload)
|
|
119
|
+
? null : '请输入有效的别名(最多 80 个字符)。';
|
|
120
|
+
}
|
|
115
121
|
if (endpoint === DINGTALK_ENDPOINTS.approveSender) {
|
|
116
122
|
return exactKeys(payload, ['botId', 'requestId', 'confirm'])
|
|
117
123
|
&& validId(payload.botId)
|
|
@@ -301,6 +307,11 @@ export function createDingtalkRpcHandler(controller, { encodeQr = qrDataUrl } =
|
|
|
301
307
|
value = await controller.updateContextEnhancement(
|
|
302
308
|
payload.botId, payload.config, (status) => publicStatus(status, cachedEncode),
|
|
303
309
|
);
|
|
310
|
+
} else if (endpoint === DINGTALK_ENDPOINTS.setAlias) {
|
|
311
|
+
if (typeof controller.updateAlias !== 'function') throw new Error('Alias update is unavailable');
|
|
312
|
+
value = await controller.updateAlias(
|
|
313
|
+
payload.botId, payload.alias, (status) => publicStatus(status, cachedEncode),
|
|
314
|
+
);
|
|
304
315
|
} else if (endpoint === DINGTALK_ENDPOINTS.setAccessPolicy) {
|
|
305
316
|
if (typeof controller.updateAccessPolicy !== 'function') throw new Error('Access policy update is unavailable');
|
|
306
317
|
value = await controller.updateAccessPolicy(
|
|
@@ -162,6 +162,27 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
162
162
|
if (!botConfig) throw new Error('Unknown Feishu bot');
|
|
163
163
|
return stateFor(botConfig);
|
|
164
164
|
};
|
|
165
|
+
// Session-sync mirror targets: which synced DMs (openId) belong to a
|
|
166
|
+
// Session. Resolved lazily per turn start so rebinding a delivery target
|
|
167
|
+
// takes effect without a restart.
|
|
168
|
+
const sessionSyncTargetsFor = async (sessionId) => {
|
|
169
|
+
if (typeof workspaces.listSessionSyncTargets !== 'function') return [];
|
|
170
|
+
const matches = [];
|
|
171
|
+
for (const entry of workspaces.listSessionSyncTargets()) {
|
|
172
|
+
let state;
|
|
173
|
+
try {
|
|
174
|
+
state = await stateForBotId(entry.botId);
|
|
175
|
+
} catch {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const bound = state?.snapshot?.().sessions?.[entry.conversationKey];
|
|
179
|
+
if (bound !== sessionId) continue;
|
|
180
|
+
const target = workspaces.deliveryTargetFor(entry.botId, entry.targetId);
|
|
181
|
+
const openId = target?.route?.openId;
|
|
182
|
+
if (openId) matches.push({ openId, botId: entry.botId, targetId: entry.targetId });
|
|
183
|
+
}
|
|
184
|
+
return matches;
|
|
185
|
+
};
|
|
165
186
|
const commandExecutor = createHarnessCommandExecutor(ctx, internals.commandExecutor);
|
|
166
187
|
const inboundTtl = internals.inboundTtl ?? getInboundTtlRuntime(ctx, config);
|
|
167
188
|
const inboundTtlService = inboundTtl?.service ?? inboundTtl;
|
|
@@ -220,6 +241,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
220
241
|
groupTopicReply: botConfig.groupTopicReply,
|
|
221
242
|
stepPush: botConfig.stepPush,
|
|
222
243
|
stepPushMode: botConfig.stepPushMode,
|
|
244
|
+
sessionSyncTargetsFor: sessionSyncTargetsFor,
|
|
223
245
|
ownerOpenIds: botConfig.ownerOpenIds ?? [botConfig.ownerOpenId],
|
|
224
246
|
harness: workspaceScope.harness,
|
|
225
247
|
state: workspaceScope.state,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { normalizeBotAlias } from '../../../../src/channels/shared/bot-alias.mjs';
|
|
2
|
+
import { SET_ALIAS_ENDPOINT, validAliasPayload } from '../shared/bot-alias-rpc.mjs';
|
|
1
3
|
import { registerManagementRpc } from '../../../management-rpc.mjs';
|
|
2
4
|
import QRCode from 'qrcode';
|
|
3
5
|
import {
|
|
@@ -34,6 +36,7 @@ import {
|
|
|
34
36
|
export const FEISHU_ENDPOINTS = Object.freeze({
|
|
35
37
|
...FEISHU_CLIENT_ENDPOINTS,
|
|
36
38
|
setAccessPolicy: SET_ACCESS_POLICY_ENDPOINT,
|
|
39
|
+
setAlias: SET_ALIAS_ENDPOINT,
|
|
37
40
|
});
|
|
38
41
|
export { FEISHU_RPC_CHANNEL };
|
|
39
42
|
export const FEISHU_MULTI_ENDPOINTS = Object.freeze({
|
|
@@ -214,6 +217,7 @@ function connectionFacts(connection) {
|
|
|
214
217
|
function publicBot(bot) {
|
|
215
218
|
const source = bot && typeof bot === 'object' ? bot : {};
|
|
216
219
|
const result = {
|
|
220
|
+
...normalizeBotAlias(source),
|
|
217
221
|
name: typeof source.name === 'string' && source.name.length > 0 ? source.name : '飞书机器人',
|
|
218
222
|
};
|
|
219
223
|
if (typeof source.avatarUrl === 'string') result.avatarUrl = source.avatarUrl;
|
|
@@ -451,6 +455,10 @@ function validPayload(endpoint, payload) {
|
|
|
451
455
|
return validAccessPolicyPayload(payload)
|
|
452
456
|
? null : '请提交有效的访问设置。';
|
|
453
457
|
}
|
|
458
|
+
if (endpoint === FEISHU_ENDPOINTS.setAlias) {
|
|
459
|
+
return validAliasPayload(payload)
|
|
460
|
+
? null : '请输入有效的别名(最多 80 个字符)。';
|
|
461
|
+
}
|
|
454
462
|
if (endpoint === FEISHU_ENDPOINTS.setGroupResponseMode) {
|
|
455
463
|
return hasOnlyKeys(payload, new Set(['botId', 'groupResponseMode']))
|
|
456
464
|
&& safeOpaqueId(payload.botId)
|
|
@@ -735,6 +743,12 @@ export function createFeishuRpcHandler(controller, { encodeQr = qrCodeDataUrl }
|
|
|
735
743
|
payload.botId, payload.config,
|
|
736
744
|
(status) => toPublicFeishuStatus(status, { encodeQr: cachedEncodeQr }),
|
|
737
745
|
);
|
|
746
|
+
} else if (endpoint === FEISHU_ENDPOINTS.setAlias) {
|
|
747
|
+
if (typeof controller.updateAlias !== 'function') throw new Error('Alias update is unavailable');
|
|
748
|
+
value = await controller.updateAlias(
|
|
749
|
+
payload.botId, payload.alias,
|
|
750
|
+
(status) => toPublicFeishuStatus(status, { encodeQr: cachedEncodeQr }),
|
|
751
|
+
);
|
|
738
752
|
} else if (endpoint === FEISHU_ENDPOINTS.setAccessPolicy) {
|
|
739
753
|
if (typeof controller.updateAccessPolicy !== 'function') throw new Error('Access policy update is unavailable');
|
|
740
754
|
value = await controller.updateAccessPolicy(
|
|
@@ -15,6 +15,7 @@ export const IMESSAGE_ENDPOINTS = Object.freeze({
|
|
|
15
15
|
setAgentPreset: 'bot.agent-preset.set',
|
|
16
16
|
setContextEnhancement: 'bot.context-enhancement.set',
|
|
17
17
|
setAccessPolicy: 'bot.access-policy.set',
|
|
18
|
+
setAlias: 'bot.alias.set',
|
|
18
19
|
});
|
|
19
20
|
export const IMESSAGE_RPC_ENDPOINTS = Object.freeze(Object.values(IMESSAGE_ENDPOINTS));
|
|
20
21
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SET_ALIAS_ENDPOINT, validAliasPayload } from '../shared/bot-alias-rpc.mjs';
|
|
1
2
|
import { registerManagementRpc } from '../../../management-rpc.mjs';
|
|
2
3
|
import QRCode from 'qrcode';
|
|
3
4
|
import {
|
|
@@ -25,6 +26,7 @@ export const QQ_ENDPOINTS = Object.freeze({
|
|
|
25
26
|
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
26
27
|
setContextEnhancement: SET_CONTEXT_ENHANCEMENT_ENDPOINT,
|
|
27
28
|
setAccessPolicy: SET_ACCESS_POLICY_ENDPOINT,
|
|
29
|
+
setAlias: SET_ALIAS_ENDPOINT,
|
|
28
30
|
});
|
|
29
31
|
export const QQ_RPC_ENDPOINTS = Object.freeze(Object.values(QQ_ENDPOINTS));
|
|
30
32
|
|
|
@@ -94,6 +96,10 @@ function payloadFailure(endpoint, payload) {
|
|
|
94
96
|
return validAccessPolicyPayload(payload)
|
|
95
97
|
? null : '请提交有效的访问设置。';
|
|
96
98
|
}
|
|
99
|
+
if (endpoint === QQ_ENDPOINTS.setAlias) {
|
|
100
|
+
return validAliasPayload(payload)
|
|
101
|
+
? null : '请输入有效的别名(最多 80 个字符)。';
|
|
102
|
+
}
|
|
97
103
|
return 'Unknown QQ endpoint.';
|
|
98
104
|
}
|
|
99
105
|
|
|
@@ -200,6 +206,11 @@ export function createQqRpcHandler(controller, { encodeQr = qrDataUrl } = {}) {
|
|
|
200
206
|
value = await controller.updateContextEnhancement(
|
|
201
207
|
payload.botId, payload.config, (status) => publicStatus(status, cachedEncode),
|
|
202
208
|
);
|
|
209
|
+
} else if (endpoint === QQ_ENDPOINTS.setAlias) {
|
|
210
|
+
if (typeof controller.updateAlias !== 'function') throw new Error('Alias update is unavailable');
|
|
211
|
+
value = await controller.updateAlias(
|
|
212
|
+
payload.botId, payload.alias, (status) => publicStatus(status, cachedEncode),
|
|
213
|
+
);
|
|
203
214
|
} else if (endpoint === QQ_ENDPOINTS.setAccessPolicy) {
|
|
204
215
|
if (typeof controller.updateAccessPolicy !== 'function') throw new Error('Access policy update is unavailable');
|
|
205
216
|
value = await controller.updateAccessPolicy(
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { validateBotAlias } from '../../../../src/channels/shared/bot-alias.mjs';
|
|
2
|
+
export { SET_ALIAS_ENDPOINT } from '../../../../src/channels/shared/bot-alias.mjs';
|
|
3
|
+
|
|
4
|
+
export function validAliasPayload(payload) {
|
|
5
|
+
try {
|
|
6
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload)
|
|
7
|
+
|| Object.keys(payload).length !== 2
|
|
8
|
+
|| typeof payload.botId !== 'string'
|
|
9
|
+
|| !/^[A-Za-z0-9_-]{1,128}$/.test(payload.botId)) return false;
|
|
10
|
+
validateBotAlias(payload.alias);
|
|
11
|
+
return true;
|
|
12
|
+
} catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SET_ALIAS_ENDPOINT, validAliasPayload } from './bot-alias-rpc.mjs';
|
|
1
2
|
import { registerManagementRpc } from '../../../management-rpc.mjs';
|
|
2
3
|
import { SET_CONTEXT_ENHANCEMENT_ENDPOINT, validContextEnhancementPayload } from './context-enhancement-rpc.mjs';
|
|
3
4
|
import { SET_ACCESS_POLICY_ENDPOINT, validAccessPolicyPayload } from './access-policy-rpc.mjs';
|
|
@@ -24,6 +25,7 @@ export const TOKEN_BOT_ENDPOINTS = Object.freeze({
|
|
|
24
25
|
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
25
26
|
setContextEnhancement: SET_CONTEXT_ENHANCEMENT_ENDPOINT,
|
|
26
27
|
setAccessPolicy: SET_ACCESS_POLICY_ENDPOINT,
|
|
28
|
+
setAlias: SET_ALIAS_ENDPOINT,
|
|
27
29
|
});
|
|
28
30
|
|
|
29
31
|
const ENDPOINTS = Object.freeze(Object.values(TOKEN_BOT_ENDPOINTS));
|
|
@@ -90,6 +92,10 @@ function payloadFailure(endpoint, payload) {
|
|
|
90
92
|
return validAccessPolicyPayload(payload)
|
|
91
93
|
? null : '请提交有效的访问设置。';
|
|
92
94
|
}
|
|
95
|
+
if (endpoint === TOKEN_BOT_ENDPOINTS.setAlias) {
|
|
96
|
+
return validAliasPayload(payload)
|
|
97
|
+
? null : '请输入有效的别名(最多 80 个字符)。';
|
|
98
|
+
}
|
|
93
99
|
return 'Unknown bot endpoint.';
|
|
94
100
|
}
|
|
95
101
|
|
|
@@ -177,6 +183,9 @@ export function createTokenBotRpcHandler(controller, { channel }) {
|
|
|
177
183
|
} else if (endpoint === TOKEN_BOT_ENDPOINTS.setContextEnhancement) {
|
|
178
184
|
if (typeof controller.updateContextEnhancement !== 'function') throw new Error('Context enhancement update is unavailable');
|
|
179
185
|
value = await controller.updateContextEnhancement(payload.botId, payload.config);
|
|
186
|
+
} else if (endpoint === TOKEN_BOT_ENDPOINTS.setAlias) {
|
|
187
|
+
if (typeof controller.updateAlias !== 'function') throw new Error('Alias update is unavailable');
|
|
188
|
+
value = await controller.updateAlias(payload.botId, payload.alias);
|
|
180
189
|
} else if (endpoint === TOKEN_BOT_ENDPOINTS.setAccessPolicy) {
|
|
181
190
|
if (typeof controller.updateAccessPolicy !== 'function') throw new Error('Access policy update is unavailable');
|
|
182
191
|
value = await controller.updateAccessPolicy(payload.botId, payload.policy);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SET_ALIAS_ENDPOINT, validAliasPayload } from '../shared/bot-alias-rpc.mjs';
|
|
1
2
|
import { registerManagementRpc } from '../../../management-rpc.mjs';
|
|
2
3
|
import { SET_CONTEXT_ENHANCEMENT_ENDPOINT, validContextEnhancementPayload } from '../shared/context-enhancement-rpc.mjs';
|
|
3
4
|
import { SET_ACCESS_POLICY_ENDPOINT, validAccessPolicyPayload } from '../shared/access-policy-rpc.mjs';
|
|
@@ -25,6 +26,7 @@ export const SLACK_ENDPOINTS = Object.freeze({
|
|
|
25
26
|
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
26
27
|
setContextEnhancement: SET_CONTEXT_ENHANCEMENT_ENDPOINT,
|
|
27
28
|
setAccessPolicy: SET_ACCESS_POLICY_ENDPOINT,
|
|
29
|
+
setAlias: SET_ALIAS_ENDPOINT,
|
|
28
30
|
});
|
|
29
31
|
export const SLACK_RPC_ENDPOINTS = Object.freeze(Object.values(SLACK_ENDPOINTS));
|
|
30
32
|
|
|
@@ -93,6 +95,10 @@ function payloadFailure(endpoint, payload) {
|
|
|
93
95
|
return validAccessPolicyPayload(payload)
|
|
94
96
|
? null : '请提交有效的访问设置。';
|
|
95
97
|
}
|
|
98
|
+
if (endpoint === SLACK_ENDPOINTS.setAlias) {
|
|
99
|
+
return validAliasPayload(payload)
|
|
100
|
+
? null : '请输入有效的别名(最多 80 个字符)。';
|
|
101
|
+
}
|
|
96
102
|
return 'Unknown Slack endpoint.';
|
|
97
103
|
}
|
|
98
104
|
|
|
@@ -180,6 +186,10 @@ export function createSlackRpcHandler(controller) {
|
|
|
180
186
|
if (typeof controller.updateContextEnhancement !== 'function') throw new Error('Context enhancement update is unavailable');
|
|
181
187
|
value = await controller.updateContextEnhancement(payload.botId, payload.config);
|
|
182
188
|
}
|
|
189
|
+
else if (endpoint === SLACK_ENDPOINTS.setAlias) {
|
|
190
|
+
if (typeof controller.updateAlias !== 'function') throw new Error('Alias update is unavailable');
|
|
191
|
+
value = await controller.updateAlias(payload.botId, payload.alias);
|
|
192
|
+
}
|
|
183
193
|
else if (endpoint === SLACK_ENDPOINTS.setAccessPolicy) {
|
|
184
194
|
if (typeof controller.updateAccessPolicy !== 'function') throw new Error('Access policy update is unavailable');
|
|
185
195
|
value = await controller.updateAccessPolicy(payload.botId, payload.policy);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SET_ALIAS_ENDPOINT, validAliasPayload } from '../shared/bot-alias-rpc.mjs';
|
|
1
2
|
import { registerManagementRpc } from '../../../management-rpc.mjs';
|
|
2
3
|
import QRCode from 'qrcode';
|
|
3
4
|
import { SET_CONTEXT_ENHANCEMENT_ENDPOINT, validContextEnhancementPayload } from '../shared/context-enhancement-rpc.mjs';
|
|
@@ -25,6 +26,7 @@ export const WECOM_ENDPOINTS = Object.freeze({
|
|
|
25
26
|
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
26
27
|
setContextEnhancement: SET_CONTEXT_ENHANCEMENT_ENDPOINT,
|
|
27
28
|
setAccessPolicy: SET_ACCESS_POLICY_ENDPOINT,
|
|
29
|
+
setAlias: SET_ALIAS_ENDPOINT,
|
|
28
30
|
});
|
|
29
31
|
export const WECOM_RPC_ENDPOINTS = Object.freeze(Object.values(WECOM_ENDPOINTS));
|
|
30
32
|
|
|
@@ -94,6 +96,10 @@ function payloadFailure(endpoint, payload) {
|
|
|
94
96
|
return validAccessPolicyPayload(payload)
|
|
95
97
|
? null : '请提交有效的访问设置。';
|
|
96
98
|
}
|
|
99
|
+
if (endpoint === WECOM_ENDPOINTS.setAlias) {
|
|
100
|
+
return validAliasPayload(payload)
|
|
101
|
+
? null : '请输入有效的别名(最多 80 个字符)。';
|
|
102
|
+
}
|
|
97
103
|
return 'Unknown Enterprise WeChat endpoint.';
|
|
98
104
|
}
|
|
99
105
|
|
|
@@ -201,6 +207,11 @@ export function createWecomRpcHandler(controller, { encodeQr = qrDataUrl } = {})
|
|
|
201
207
|
value = await controller.updateContextEnhancement(
|
|
202
208
|
payload.botId, payload.config, (status) => publicStatus(status, cachedEncode),
|
|
203
209
|
);
|
|
210
|
+
} else if (endpoint === WECOM_ENDPOINTS.setAlias) {
|
|
211
|
+
if (typeof controller.updateAlias !== 'function') throw new Error('Alias update is unavailable');
|
|
212
|
+
value = await controller.updateAlias(
|
|
213
|
+
payload.botId, payload.alias, (status) => publicStatus(status, cachedEncode),
|
|
214
|
+
);
|
|
204
215
|
} else if (endpoint === WECOM_ENDPOINTS.setAccessPolicy) {
|
|
205
216
|
if (typeof controller.updateAccessPolicy !== 'function') throw new Error('Access policy update is unavailable');
|
|
206
217
|
value = await controller.updateAccessPolicy(
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SET_ALIAS_ENDPOINT, validAliasPayload } from '../shared/bot-alias-rpc.mjs';
|
|
1
2
|
import { registerManagementRpc } from '../../../management-rpc.mjs';
|
|
2
3
|
import { SET_CONTEXT_ENHANCEMENT_ENDPOINT, validContextEnhancementPayload } from '../shared/context-enhancement-rpc.mjs';
|
|
3
4
|
import { SET_ACCESS_POLICY_ENDPOINT, validAccessPolicyPayload } from '../shared/access-policy-rpc.mjs';
|
|
@@ -23,6 +24,7 @@ export const WECOM_APP_ENDPOINTS = Object.freeze({
|
|
|
23
24
|
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
24
25
|
setContextEnhancement: SET_CONTEXT_ENHANCEMENT_ENDPOINT,
|
|
25
26
|
setAccessPolicy: SET_ACCESS_POLICY_ENDPOINT,
|
|
27
|
+
setAlias: SET_ALIAS_ENDPOINT,
|
|
26
28
|
});
|
|
27
29
|
export const WECOM_APP_RPC_ENDPOINTS = Object.freeze(Object.values(WECOM_APP_ENDPOINTS));
|
|
28
30
|
|
|
@@ -113,6 +115,9 @@ function payloadFailure(endpoint, payload) {
|
|
|
113
115
|
if (endpoint === WECOM_APP_ENDPOINTS.setAccessPolicy) {
|
|
114
116
|
return validAccessPolicyPayload(payload) ? null : '请提交有效的访问设置。';
|
|
115
117
|
}
|
|
118
|
+
if (endpoint === WECOM_APP_ENDPOINTS.setAlias) {
|
|
119
|
+
return validAliasPayload(payload) ? null : '请输入有效的别名(最多 80 个字符)。';
|
|
120
|
+
}
|
|
116
121
|
return 'Unknown Enterprise WeChat app endpoint.';
|
|
117
122
|
}
|
|
118
123
|
|
|
@@ -189,6 +194,11 @@ export function createWecomAppRpcHandler(controller) {
|
|
|
189
194
|
value = await controller.updateContextEnhancement(
|
|
190
195
|
payload.botId, payload.config, (status) => publicStatus(status),
|
|
191
196
|
);
|
|
197
|
+
} else if (endpoint === WECOM_APP_ENDPOINTS.setAlias) {
|
|
198
|
+
if (typeof controller.updateAlias !== 'function') throw new Error('Alias update is unavailable');
|
|
199
|
+
value = await controller.updateAlias(
|
|
200
|
+
payload.botId, payload.alias, (status) => publicStatus(status),
|
|
201
|
+
);
|
|
192
202
|
} else if (endpoint === WECOM_APP_ENDPOINTS.setAccessPolicy) {
|
|
193
203
|
if (typeof controller.updateAccessPolicy !== 'function') throw new Error('Access policy update is unavailable');
|
|
194
204
|
value = await controller.updateAccessPolicy(
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SET_ALIAS_ENDPOINT, validAliasPayload } from '../shared/bot-alias-rpc.mjs';
|
|
1
2
|
import { registerManagementRpc } from '../../../management-rpc.mjs';
|
|
2
3
|
import QRCode from 'qrcode';
|
|
3
4
|
import { SET_CONTEXT_ENHANCEMENT_ENDPOINT, validContextEnhancementPayload } from '../shared/context-enhancement-rpc.mjs';
|
|
@@ -32,6 +33,7 @@ export const WEIXIN_ENDPOINTS = Object.freeze({
|
|
|
32
33
|
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
33
34
|
setContextEnhancement: SET_CONTEXT_ENHANCEMENT_ENDPOINT,
|
|
34
35
|
setAccessPolicy: SET_ACCESS_POLICY_ENDPOINT,
|
|
36
|
+
setAlias: SET_ALIAS_ENDPOINT,
|
|
35
37
|
});
|
|
36
38
|
export const WEIXIN_RPC_ENDPOINTS = Object.freeze(Object.values(WEIXIN_ENDPOINTS));
|
|
37
39
|
|
|
@@ -101,6 +103,10 @@ function payloadFailure(endpoint, payload) {
|
|
|
101
103
|
return validAccessPolicyPayload(payload)
|
|
102
104
|
? null : '请提交有效的访问设置。';
|
|
103
105
|
}
|
|
106
|
+
if (endpoint === WEIXIN_ENDPOINTS.setAlias) {
|
|
107
|
+
return validAliasPayload(payload)
|
|
108
|
+
? null : '请输入有效的别名(最多 80 个字符)。';
|
|
109
|
+
}
|
|
104
110
|
return 'Unknown Weixin endpoint.';
|
|
105
111
|
}
|
|
106
112
|
|
|
@@ -236,6 +242,11 @@ export function createWeixinRpcHandler(controller, { encodeQr = qrDataUrl } = {}
|
|
|
236
242
|
value = await controller.updateContextEnhancement(
|
|
237
243
|
payload.botId, payload.config, (status) => publicStatus(status, cachedEncode),
|
|
238
244
|
);
|
|
245
|
+
} else if (endpoint === WEIXIN_ENDPOINTS.setAlias) {
|
|
246
|
+
if (typeof controller.updateAlias !== 'function') throw new Error('Alias update is unavailable');
|
|
247
|
+
value = await controller.updateAlias(
|
|
248
|
+
payload.botId, payload.alias, (status) => publicStatus(status, cachedEncode),
|
|
249
|
+
);
|
|
239
250
|
} else if (endpoint === WEIXIN_ENDPOINTS.setAccessPolicy) {
|
|
240
251
|
if (typeof controller.updateAccessPolicy !== 'function') throw new Error('Access policy update is unavailable');
|
|
241
252
|
value = await controller.updateAccessPolicy(
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SET_ALIAS_ENDPOINT, validAliasPayload } from '../shared/bot-alias-rpc.mjs';
|
|
1
2
|
import { registerManagementRpc } from '../../../management-rpc.mjs';
|
|
2
3
|
import QRCode from 'qrcode';
|
|
3
4
|
|
|
@@ -18,6 +19,7 @@ export const WHATSAPP_ENDPOINTS = Object.freeze({
|
|
|
18
19
|
reconnectBot: 'bot.reconnect',
|
|
19
20
|
deleteBot: 'bot.delete',
|
|
20
21
|
setAccessPolicy: SET_ACCESS_POLICY_ENDPOINT,
|
|
22
|
+
setAlias: SET_ALIAS_ENDPOINT,
|
|
21
23
|
setWorkspace: SET_WORKSPACE_ENDPOINT,
|
|
22
24
|
setModel: SET_MODEL_ENDPOINT,
|
|
23
25
|
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
@@ -61,6 +63,10 @@ function payloadFailure(endpoint, payload) {
|
|
|
61
63
|
return validAccessPolicyPayload(payload)
|
|
62
64
|
? null : '请提交有效的访问设置。';
|
|
63
65
|
}
|
|
66
|
+
if (endpoint === WHATSAPP_ENDPOINTS.setAlias) {
|
|
67
|
+
return validAliasPayload(payload)
|
|
68
|
+
? null : '请输入有效的别名(最多 80 个字符)。';
|
|
69
|
+
}
|
|
64
70
|
if (endpoint === WHATSAPP_ENDPOINTS.setWorkspace) {
|
|
65
71
|
return validWorkspacePayload(payload)
|
|
66
72
|
? null : '请输入工作区绝对路径。';
|
|
@@ -195,6 +201,13 @@ export function createWhatsappRpcHandler(controller, { encodeQr = qrDataUrl } =
|
|
|
195
201
|
await controller.updateAgentPreset(payload.botId, payload.agentPreset),
|
|
196
202
|
cachedEncode,
|
|
197
203
|
);
|
|
204
|
+
} else if (endpoint === WHATSAPP_ENDPOINTS.setAlias) {
|
|
205
|
+
if (typeof controller.updateAlias !== 'function') throw new Error('Alias update is unavailable');
|
|
206
|
+
value = await controller.updateAlias(
|
|
207
|
+
payload.botId,
|
|
208
|
+
payload.alias,
|
|
209
|
+
(status) => publicStatus(status, cachedEncode),
|
|
210
|
+
);
|
|
198
211
|
} else if (endpoint === WHATSAPP_ENDPOINTS.setAccessPolicy) {
|
|
199
212
|
if (typeof controller.updateAccessPolicy !== 'function') throw new Error('Access policy update is unavailable');
|
|
200
213
|
value = await controller.updateAccessPolicy(
|
|
@@ -3,6 +3,10 @@ import {
|
|
|
3
3
|
consumeDshImInputOrigin,
|
|
4
4
|
textFromHarnessContent,
|
|
5
5
|
} from '../../src/channels/shared/harness-client.mjs';
|
|
6
|
+
import {
|
|
7
|
+
isSessionSyncMirrored,
|
|
8
|
+
releaseSessionSyncMirror,
|
|
9
|
+
} from '../../src/channels/shared/session-sync-registry.mjs';
|
|
6
10
|
|
|
7
11
|
const DSH_USER_PREFIX = '[来自 DSH]\n';
|
|
8
12
|
const DSH_ASSISTANT_PREFIX = '[DSH 助手]\n';
|
|
@@ -111,6 +115,10 @@ export function createSessionSyncCoordinator({ deliveryService, logger = console
|
|
|
111
115
|
if (event.surfaceOp !== 'append') return;
|
|
112
116
|
if (state.origin === 'unknown') state.origin = origin;
|
|
113
117
|
if (state.origin !== 'dsh' || origin !== 'dsh') return;
|
|
118
|
+
// The user echo stays as plain text even when the mirror owns the
|
|
119
|
+
// turn: the card also quotes the question, but keeping the echo here
|
|
120
|
+
// guarantees recipients are established so a failed mirror can still
|
|
121
|
+
// fall back to the final-answer text delivery.
|
|
114
122
|
const text = textFromHarnessContent(event.data?.content);
|
|
115
123
|
if (!text) return;
|
|
116
124
|
|
|
@@ -151,9 +159,19 @@ export function createSessionSyncCoordinator({ deliveryService, logger = console
|
|
|
151
159
|
turns.delete(sessionId);
|
|
152
160
|
if (state.origin !== 'dsh' || !completedTurn(event.data?.reason)
|
|
153
161
|
|| !state.recipients?.size || !state.assistant.text) return;
|
|
162
|
+
// Per-target suppression: targets whose process-card mirror delivered
|
|
163
|
+
// the answer are skipped; every other synced target still gets the text.
|
|
164
|
+
const mirrored = [];
|
|
165
|
+
const plain = [];
|
|
166
|
+
for (const target of state.recipients.values()) {
|
|
167
|
+
if (isSessionSyncMirrored(sessionId, target.targetId, state.turn)) mirrored.push(target);
|
|
168
|
+
else plain.push(target);
|
|
169
|
+
}
|
|
170
|
+
for (const target of mirrored) releaseSessionSyncMirror(sessionId, target.targetId);
|
|
171
|
+
if (plain.length === 0) return;
|
|
154
172
|
await deliver(
|
|
155
173
|
sessionId,
|
|
156
|
-
|
|
174
|
+
plain,
|
|
157
175
|
`${DSH_ASSISTANT_PREFIX}${state.assistant.text}`,
|
|
158
176
|
'assistant delivery',
|
|
159
177
|
);
|