@xmanrui/dsh-im 4.10.0 → 4.12.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/PROACTIVE_DELIVERY.en.md +15 -1
- package/PROACTIVE_DELIVERY.md +15 -1
- package/README.en.md +7 -2
- package/README.md +8 -3
- package/lib/client.js +2341 -1315
- package/lib/index.js +250 -245
- package/package.json +4 -3
- package/plugin-src/client/channel-card-meta.js +9 -1
- package/plugin-src/client/channels/dingtalk/api.js +4 -0
- package/plugin-src/client/channels/dingtalk/index.js +41 -7
- package/plugin-src/client/channels/feishu/api.js +4 -0
- package/plugin-src/client/channels/feishu/group-settings.js +581 -0
- package/plugin-src/client/channels/feishu/index.js +64 -233
- package/plugin-src/client/channels/qq/api.js +4 -0
- package/plugin-src/client/channels/qq/index.js +41 -7
- package/plugin-src/client/channels/shared/collapsible-account.js +80 -0
- package/plugin-src/client/channels/shared/token-api.js +4 -0
- package/plugin-src/client/channels/shared/token-channel.js +62 -29
- package/plugin-src/client/channels/wecom/api.js +4 -0
- package/plugin-src/client/channels/wecom/index.js +41 -7
- package/plugin-src/client/channels/weixin/api.js +4 -0
- package/plugin-src/client/channels/weixin/index.js +41 -7
- package/plugin-src/client/channels/whatsapp/api.js +4 -0
- package/plugin-src/client/channels/whatsapp/index.js +40 -7
- package/plugin-src/client/delivery-settings.js +73 -5
- package/plugin-src/client/i18n.js +22 -0
- package/plugin-src/client/model-setting.js +104 -0
- package/plugin-src/client/styles.js +62 -0
- package/plugin-src/host/channels/dingtalk/production.mjs +3 -0
- package/plugin-src/host/channels/dingtalk/rpc.mjs +11 -0
- package/plugin-src/host/channels/feishu/production.mjs +3 -0
- package/plugin-src/host/channels/feishu/rpc.mjs +16 -0
- package/plugin-src/host/channels/qq/production.mjs +3 -0
- package/plugin-src/host/channels/qq/rpc.mjs +11 -0
- package/plugin-src/host/channels/shared/model-setting-rpc.mjs +19 -0
- package/plugin-src/host/channels/shared/production.mjs +3 -0
- package/plugin-src/host/channels/shared/rpc.mjs +9 -0
- package/plugin-src/host/channels/shared/workspace-rpc.mjs +2 -0
- package/plugin-src/host/channels/slack/production.mjs +3 -0
- package/plugin-src/host/channels/slack/rpc.mjs +9 -0
- package/plugin-src/host/channels/wecom/production.mjs +3 -0
- package/plugin-src/host/channels/wecom/rpc.mjs +11 -0
- package/plugin-src/host/channels/weixin/production.mjs +3 -0
- package/plugin-src/host/channels/weixin/rpc.mjs +11 -0
- package/plugin-src/host/channels/whatsapp/production.mjs +3 -0
- package/plugin-src/host/channels/whatsapp/rpc.mjs +11 -0
- package/plugin-src/host/delivery-adapter.mjs +141 -3
- package/plugin-src/host/delivery-rpc.mjs +12 -0
- package/plugin-src/host/delivery-service.mjs +110 -3
- package/plugin-src/host/delivery-suggestions.mjs +46 -0
- package/plugin-src/host/harness-session-coordinator.mjs +6 -5
- package/plugin-src/host/index.mjs +18 -1
- package/plugin-src/host/session-sync-coordinator.mjs +217 -0
- package/scripts/verify-package.mjs +12 -6
- package/src/channels/shared/bot-workspace-store.mjs +285 -38
- package/src/channels/shared/harness-client.mjs +124 -43
- package/src/channels/shared/i18n-en/wecom.mjs +24 -0
- package/src/channels/shared/model-setting.mjs +110 -0
- package/src/channels/wecom/wecom-bridge.mjs +275 -2
- package/src/channels/wecom/wecom-cards.mjs +101 -0
- package/src/channels/wecom/wecom-runtime.mjs +2 -0
- package/src/channels/whatsapp/whatsapp-runtime.mjs +78 -26
|
@@ -5,10 +5,15 @@ import {
|
|
|
5
5
|
} from '../../../../src/channels/shared/agent-preset.mjs';
|
|
6
6
|
import { publicConnectionTestResult } from '../../../../src/channels/shared/connection-test.mjs';
|
|
7
7
|
import { publicMessageFailure } from '../../../../src/channels/shared/message-failure.mjs';
|
|
8
|
+
import {
|
|
9
|
+
normalizeModelCatalog,
|
|
10
|
+
normalizeModelSelection,
|
|
11
|
+
} from '../../../../src/channels/shared/model-setting.mjs';
|
|
8
12
|
import { normalizeAccessPolicy } from '../../../../src/channels/shared/access-policy.mjs';
|
|
9
13
|
import { resolveRpcAuthority } from '../../rpc-authority.mjs';
|
|
10
14
|
import { publicWorkspaceError, validWorkspacePayload } from '../shared/workspace-rpc.mjs';
|
|
11
15
|
import { validAgentPresetPayload } from '../shared/agent-preset-rpc.mjs';
|
|
16
|
+
import { validModelPayload } from '../shared/model-setting-rpc.mjs';
|
|
12
17
|
import { validContextEnhancementPayload } from '../shared/context-enhancement-rpc.mjs';
|
|
13
18
|
import { SET_ACCESS_POLICY_ENDPOINT, validAccessPolicyPayload } from '../shared/access-policy-rpc.mjs';
|
|
14
19
|
import { normalizeContextEnhancementConfig } from '../../../../src/channels/shared/context-enhancement.mjs';
|
|
@@ -283,6 +288,7 @@ function publicBotEntry(entry) {
|
|
|
283
288
|
state: connectionState(source, registration, connected),
|
|
284
289
|
connected,
|
|
285
290
|
configured: source.configured === true,
|
|
291
|
+
model: normalizeModelSelection(source.model),
|
|
286
292
|
agentPreset: normalizeAgentPresetId(source.agentPreset),
|
|
287
293
|
contextEnhancement: normalizeContextEnhancementConfig(source.contextEnhancement),
|
|
288
294
|
accessPolicy: normalizeAccessPolicy(source.accessPolicy),
|
|
@@ -333,6 +339,7 @@ export async function toPublicFeishuStatus(status, { encodeQr = qrCodeDataUrl }
|
|
|
333
339
|
health: publicHealth(source, connected),
|
|
334
340
|
bots,
|
|
335
341
|
agentPresetCatalog: normalizeAgentPresetCatalog(source.agentPresetCatalog),
|
|
342
|
+
modelCatalog: normalizeModelCatalog(source.modelCatalog),
|
|
336
343
|
totals: {
|
|
337
344
|
configured: bots.length || (source.configured === true ? 1 : 0),
|
|
338
345
|
connected: bots.length ? bots.filter((bot) => bot.connected).length : (connected ? 1 : 0),
|
|
@@ -422,6 +429,9 @@ function validPayload(endpoint, payload) {
|
|
|
422
429
|
return validWorkspacePayload(payload)
|
|
423
430
|
? null : '请输入工作区绝对路径。';
|
|
424
431
|
}
|
|
432
|
+
if (endpoint === FEISHU_ENDPOINTS.setModel) {
|
|
433
|
+
return validModelPayload(payload) ? null : '请选择有效模型。';
|
|
434
|
+
}
|
|
425
435
|
if (endpoint === FEISHU_ENDPOINTS.setAgentPreset) {
|
|
426
436
|
return validAgentPresetPayload(payload)
|
|
427
437
|
? null : '请选择 Agent Preset。';
|
|
@@ -692,6 +702,12 @@ export function createFeishuRpcHandler(controller, { encodeQr = qrCodeDataUrl }
|
|
|
692
702
|
await controller.updateWorkspace(payload.botId, payload.workspace),
|
|
693
703
|
{ encodeQr: cachedEncodeQr },
|
|
694
704
|
);
|
|
705
|
+
} else if (endpoint === FEISHU_ENDPOINTS.setModel) {
|
|
706
|
+
if (typeof controller.updateModel !== 'function') throw new Error('Model update is unavailable');
|
|
707
|
+
value = await toPublicFeishuStatus(
|
|
708
|
+
await controller.updateModel(payload.botId, payload.model),
|
|
709
|
+
{ encodeQr: cachedEncodeQr },
|
|
710
|
+
);
|
|
695
711
|
} else if (endpoint === FEISHU_ENDPOINTS.setContextEnhancement) {
|
|
696
712
|
if (typeof controller.updateContextEnhancement !== 'function') throw new Error('Context enhancement update is unavailable');
|
|
697
713
|
value = await controller.updateContextEnhancement(
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
observeBotWorkspaceRemovals,
|
|
16
16
|
} from '../../../../src/channels/shared/bot-workspace-store.mjs';
|
|
17
17
|
import { listAgentPresetCatalog } from '../../../../src/channels/shared/agent-preset.mjs';
|
|
18
|
+
import { listModelCatalog } from '../../../../src/channels/shared/model-setting.mjs';
|
|
18
19
|
import { createDeliveryAdapter } from '../../delivery-adapter.mjs';
|
|
19
20
|
import { createConnectionSupervisor } from './connection-supervisor.mjs';
|
|
20
21
|
import { createHarnessCommandExecutor } from '../../harness-command-executor.mjs';
|
|
@@ -102,6 +103,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
102
103
|
...(sessionMaintenanceExecutor ? { sessionMaintenanceExecutor } : {}),
|
|
103
104
|
...(fileIngressExecutor ? { fileIngressExecutor } : {}),
|
|
104
105
|
});
|
|
106
|
+
const modelCatalog = () => listModelCatalog(harness);
|
|
105
107
|
const coreController = new Controller({
|
|
106
108
|
qrAuth,
|
|
107
109
|
credentials: ctx.credentials,
|
|
@@ -153,6 +155,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
153
155
|
workspaces,
|
|
154
156
|
stateFor,
|
|
155
157
|
agentPresetCatalog,
|
|
158
|
+
modelCatalog,
|
|
156
159
|
});
|
|
157
160
|
const supervisor = createSupervisor({
|
|
158
161
|
controller,
|
|
@@ -8,6 +8,7 @@ import { SET_ACCESS_POLICY_ENDPOINT, validAccessPolicyPayload } from '../shared/
|
|
|
8
8
|
import { resolveRpcAuthority } from '../../rpc-authority.mjs';
|
|
9
9
|
import { publicWorkspaceError, SET_WORKSPACE_ENDPOINT, validWorkspacePayload } from '../shared/workspace-rpc.mjs';
|
|
10
10
|
import { SET_AGENT_PRESET_ENDPOINT, validAgentPresetPayload } from '../shared/agent-preset-rpc.mjs';
|
|
11
|
+
import { SET_MODEL_ENDPOINT, validModelPayload } from '../shared/model-setting-rpc.mjs';
|
|
11
12
|
|
|
12
13
|
export const QQ_RPC_CHANNEL = '/qq';
|
|
13
14
|
export const QQ_ENDPOINTS = Object.freeze({
|
|
@@ -19,6 +20,7 @@ export const QQ_ENDPOINTS = Object.freeze({
|
|
|
19
20
|
reconnectBot: 'bot.reconnect',
|
|
20
21
|
deleteBot: 'bot.delete',
|
|
21
22
|
setWorkspace: SET_WORKSPACE_ENDPOINT,
|
|
23
|
+
setModel: SET_MODEL_ENDPOINT,
|
|
22
24
|
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
23
25
|
setContextEnhancement: SET_CONTEXT_ENHANCEMENT_ENDPOINT,
|
|
24
26
|
setAccessPolicy: SET_ACCESS_POLICY_ENDPOINT,
|
|
@@ -76,6 +78,9 @@ function payloadFailure(endpoint, payload) {
|
|
|
76
78
|
return validWorkspacePayload(payload)
|
|
77
79
|
? null : '请输入工作区绝对路径。';
|
|
78
80
|
}
|
|
81
|
+
if (endpoint === QQ_ENDPOINTS.setModel) {
|
|
82
|
+
return validModelPayload(payload) ? null : '请选择有效模型。';
|
|
83
|
+
}
|
|
79
84
|
if (endpoint === QQ_ENDPOINTS.setAgentPreset) {
|
|
80
85
|
return validAgentPresetPayload(payload)
|
|
81
86
|
? null : '请选择 Agent Preset。';
|
|
@@ -183,6 +188,12 @@ export function createQqRpcHandler(controller, { encodeQr = qrDataUrl } = {}) {
|
|
|
183
188
|
await controller.updateWorkspace(payload.botId, payload.workspace),
|
|
184
189
|
cachedEncode,
|
|
185
190
|
);
|
|
191
|
+
} else if (endpoint === QQ_ENDPOINTS.setModel) {
|
|
192
|
+
if (typeof controller.updateModel !== 'function') throw new Error('Model update is unavailable');
|
|
193
|
+
value = await publicStatus(
|
|
194
|
+
await controller.updateModel(payload.botId, payload.model),
|
|
195
|
+
cachedEncode,
|
|
196
|
+
);
|
|
186
197
|
} else if (endpoint === QQ_ENDPOINTS.setContextEnhancement) {
|
|
187
198
|
if (typeof controller.updateContextEnhancement !== 'function') throw new Error('Context enhancement update is unavailable');
|
|
188
199
|
value = await controller.updateContextEnhancement(
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { normalizeModelSelection } from '../../../../src/channels/shared/model-setting.mjs';
|
|
2
|
+
|
|
3
|
+
export const SET_MODEL_ENDPOINT = 'bot.model.set';
|
|
4
|
+
|
|
5
|
+
function isRecord(value) {
|
|
6
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function validModelPayload(payload) {
|
|
10
|
+
if (!isRecord(payload)
|
|
11
|
+
|| !Object.keys(payload).every((key) => ['botId', 'model'].includes(key))
|
|
12
|
+
|| typeof payload.botId !== 'string'
|
|
13
|
+
|| !/^[A-Za-z0-9_-]{1,128}$/.test(payload.botId)) return false;
|
|
14
|
+
if (payload.model === null) return true;
|
|
15
|
+
return isRecord(payload.model)
|
|
16
|
+
&& Object.keys(payload.model).length === 2
|
|
17
|
+
&& Object.keys(payload.model).every((key) => ['provider', 'model'].includes(key))
|
|
18
|
+
&& normalizeModelSelection(payload.model) !== null;
|
|
19
|
+
}
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
observeBotWorkspaceRemovals,
|
|
18
18
|
} from '../../../../src/channels/shared/bot-workspace-store.mjs';
|
|
19
19
|
import { listAgentPresetCatalog } from '../../../../src/channels/shared/agent-preset.mjs';
|
|
20
|
+
import { listModelCatalog } from '../../../../src/channels/shared/model-setting.mjs';
|
|
20
21
|
import {
|
|
21
22
|
createDeliveryAdapter,
|
|
22
23
|
supportsDeliveryChannel,
|
|
@@ -111,6 +112,7 @@ export async function createTokenProductionController(ctx, config, internals, de
|
|
|
111
112
|
...(sessionMaintenanceExecutor ? { sessionMaintenanceExecutor } : {}),
|
|
112
113
|
...(fileIngressExecutor ? { fileIngressExecutor } : {}),
|
|
113
114
|
});
|
|
115
|
+
const modelCatalog = () => listModelCatalog(harness);
|
|
114
116
|
const coreController = new ResolvedController({
|
|
115
117
|
credentials: ctx.credentials,
|
|
116
118
|
configStore: observedConfigStore,
|
|
@@ -161,6 +163,7 @@ export async function createTokenProductionController(ctx, config, internals, de
|
|
|
161
163
|
workspaces,
|
|
162
164
|
stateFor,
|
|
163
165
|
agentPresetCatalog,
|
|
166
|
+
modelCatalog,
|
|
164
167
|
});
|
|
165
168
|
const supervisor = createSupervisor({
|
|
166
169
|
channel,
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
SET_AGENT_PRESET_ENDPOINT,
|
|
12
12
|
validAgentPresetPayload,
|
|
13
13
|
} from './agent-preset-rpc.mjs';
|
|
14
|
+
import { SET_MODEL_ENDPOINT, validModelPayload } from './model-setting-rpc.mjs';
|
|
14
15
|
|
|
15
16
|
export const TOKEN_BOT_ENDPOINTS = Object.freeze({
|
|
16
17
|
status: 'connection.status',
|
|
@@ -18,6 +19,7 @@ export const TOKEN_BOT_ENDPOINTS = Object.freeze({
|
|
|
18
19
|
reconnectBot: 'bot.reconnect',
|
|
19
20
|
deleteBot: 'bot.delete',
|
|
20
21
|
setWorkspace: SET_WORKSPACE_ENDPOINT,
|
|
22
|
+
setModel: SET_MODEL_ENDPOINT,
|
|
21
23
|
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
22
24
|
setContextEnhancement: SET_CONTEXT_ENHANCEMENT_ENDPOINT,
|
|
23
25
|
setAccessPolicy: SET_ACCESS_POLICY_ENDPOINT,
|
|
@@ -71,6 +73,10 @@ function payloadFailure(endpoint, payload) {
|
|
|
71
73
|
return validWorkspacePayload(payload)
|
|
72
74
|
? null : '请输入工作区绝对路径。';
|
|
73
75
|
}
|
|
76
|
+
if (endpoint === TOKEN_BOT_ENDPOINTS.setModel) {
|
|
77
|
+
return validModelPayload(payload)
|
|
78
|
+
? null : '请选择有效模型。';
|
|
79
|
+
}
|
|
74
80
|
if (endpoint === TOKEN_BOT_ENDPOINTS.setAgentPreset) {
|
|
75
81
|
return validAgentPresetPayload(payload)
|
|
76
82
|
? null : '请选择 Agent Preset。';
|
|
@@ -164,6 +170,9 @@ export function createTokenBotRpcHandler(controller, { channel }) {
|
|
|
164
170
|
} else if (endpoint === TOKEN_BOT_ENDPOINTS.setWorkspace) {
|
|
165
171
|
if (typeof controller.updateWorkspace !== 'function') throw new Error('Workspace update is unavailable');
|
|
166
172
|
value = await controller.updateWorkspace(payload.botId, payload.workspace);
|
|
173
|
+
} else if (endpoint === TOKEN_BOT_ENDPOINTS.setModel) {
|
|
174
|
+
if (typeof controller.updateModel !== 'function') throw new Error('Model update is unavailable');
|
|
175
|
+
value = await controller.updateModel(payload.botId, payload.model);
|
|
167
176
|
} else if (endpoint === TOKEN_BOT_ENDPOINTS.setContextEnhancement) {
|
|
168
177
|
if (typeof controller.updateContextEnhancement !== 'function') throw new Error('Context enhancement update is unavailable');
|
|
169
178
|
value = await controller.updateContextEnhancement(payload.botId, payload.config);
|
|
@@ -22,6 +22,8 @@ export function publicWorkspaceError(error) {
|
|
|
22
22
|
'workspace-bot-not-found',
|
|
23
23
|
'agent-preset-invalid',
|
|
24
24
|
'agent-preset-unavailable',
|
|
25
|
+
'model-selection-invalid',
|
|
26
|
+
'model-selection-unavailable',
|
|
25
27
|
'context-enhancement-invalid',
|
|
26
28
|
].includes(error?.code)) return null;
|
|
27
29
|
return { code: error.code, message: error.message };
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
observeBotWorkspaceRemovals,
|
|
14
14
|
} from '../../../../src/channels/shared/bot-workspace-store.mjs';
|
|
15
15
|
import { listAgentPresetCatalog } from '../../../../src/channels/shared/agent-preset.mjs';
|
|
16
|
+
import { listModelCatalog } from '../../../../src/channels/shared/model-setting.mjs';
|
|
16
17
|
import { createDeliveryAdapter } from '../../delivery-adapter.mjs';
|
|
17
18
|
import { createTokenConnectionSupervisor } from '../shared/connection-supervisor.mjs';
|
|
18
19
|
import { pluginPaths } from '../shared/production.mjs';
|
|
@@ -90,6 +91,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
90
91
|
...(sessionMaintenanceExecutor ? { sessionMaintenanceExecutor } : {}),
|
|
91
92
|
...(fileIngressExecutor ? { fileIngressExecutor } : {}),
|
|
92
93
|
});
|
|
94
|
+
const modelCatalog = () => listModelCatalog(harness);
|
|
93
95
|
const coreController = new ResolvedController({
|
|
94
96
|
credentials: ctx.credentials,
|
|
95
97
|
configStore: observedConfigStore,
|
|
@@ -142,6 +144,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
142
144
|
workspaces,
|
|
143
145
|
stateFor,
|
|
144
146
|
agentPresetCatalog,
|
|
147
|
+
modelCatalog,
|
|
145
148
|
});
|
|
146
149
|
const supervisor = createSupervisor({
|
|
147
150
|
channel: 'slack',
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
SET_AGENT_PRESET_ENDPOINT,
|
|
12
12
|
validAgentPresetPayload,
|
|
13
13
|
} from '../shared/agent-preset-rpc.mjs';
|
|
14
|
+
import { SET_MODEL_ENDPOINT, validModelPayload } from '../shared/model-setting-rpc.mjs';
|
|
14
15
|
|
|
15
16
|
export const SLACK_RPC_CHANNEL = '/slack';
|
|
16
17
|
export const SLACK_ENDPOINTS = Object.freeze({
|
|
@@ -19,6 +20,7 @@ export const SLACK_ENDPOINTS = Object.freeze({
|
|
|
19
20
|
reconnectBot: 'bot.reconnect',
|
|
20
21
|
deleteBot: 'bot.delete',
|
|
21
22
|
setWorkspace: SET_WORKSPACE_ENDPOINT,
|
|
23
|
+
setModel: SET_MODEL_ENDPOINT,
|
|
22
24
|
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
23
25
|
setContextEnhancement: SET_CONTEXT_ENHANCEMENT_ENDPOINT,
|
|
24
26
|
setAccessPolicy: SET_ACCESS_POLICY_ENDPOINT,
|
|
@@ -75,6 +77,9 @@ function payloadFailure(endpoint, payload) {
|
|
|
75
77
|
return validWorkspacePayload(payload)
|
|
76
78
|
? null : '请输入工作区绝对路径。';
|
|
77
79
|
}
|
|
80
|
+
if (endpoint === SLACK_ENDPOINTS.setModel) {
|
|
81
|
+
return validModelPayload(payload) ? null : '请选择有效模型。';
|
|
82
|
+
}
|
|
78
83
|
if (endpoint === SLACK_ENDPOINTS.setAgentPreset) {
|
|
79
84
|
return validAgentPresetPayload(payload)
|
|
80
85
|
? null : '请选择 Agent Preset。';
|
|
@@ -166,6 +171,10 @@ export function createSlackRpcHandler(controller) {
|
|
|
166
171
|
if (typeof controller.updateWorkspace !== 'function') throw new Error('Workspace update is unavailable');
|
|
167
172
|
value = await controller.updateWorkspace(payload.botId, payload.workspace);
|
|
168
173
|
}
|
|
174
|
+
else if (endpoint === SLACK_ENDPOINTS.setModel) {
|
|
175
|
+
if (typeof controller.updateModel !== 'function') throw new Error('Model update is unavailable');
|
|
176
|
+
value = await controller.updateModel(payload.botId, payload.model);
|
|
177
|
+
}
|
|
169
178
|
else if (endpoint === SLACK_ENDPOINTS.setContextEnhancement) {
|
|
170
179
|
if (typeof controller.updateContextEnhancement !== 'function') throw new Error('Context enhancement update is unavailable');
|
|
171
180
|
value = await controller.updateContextEnhancement(payload.botId, payload.config);
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
observeBotWorkspaceRemovals,
|
|
16
16
|
} from '../../../../src/channels/shared/bot-workspace-store.mjs';
|
|
17
17
|
import { listAgentPresetCatalog } from '../../../../src/channels/shared/agent-preset.mjs';
|
|
18
|
+
import { listModelCatalog } from '../../../../src/channels/shared/model-setting.mjs';
|
|
18
19
|
import { createDeliveryAdapter } from '../../delivery-adapter.mjs';
|
|
19
20
|
import { createConnectionSupervisor } from './connection-supervisor.mjs';
|
|
20
21
|
import { createHarnessCommandExecutor } from '../../harness-command-executor.mjs';
|
|
@@ -105,6 +106,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
105
106
|
...(sessionMaintenanceExecutor ? { sessionMaintenanceExecutor } : {}),
|
|
106
107
|
...(fileIngressExecutor ? { fileIngressExecutor } : {}),
|
|
107
108
|
});
|
|
109
|
+
const modelCatalog = () => listModelCatalog(harness);
|
|
108
110
|
const coreController = new Controller({
|
|
109
111
|
qrAuth,
|
|
110
112
|
credentials: ctx.credentials,
|
|
@@ -157,6 +159,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
157
159
|
workspaces,
|
|
158
160
|
stateFor,
|
|
159
161
|
agentPresetCatalog,
|
|
162
|
+
modelCatalog,
|
|
160
163
|
});
|
|
161
164
|
const supervisor = createSupervisor({
|
|
162
165
|
controller,
|
|
@@ -4,6 +4,7 @@ import { SET_ACCESS_POLICY_ENDPOINT, validAccessPolicyPayload } from '../shared/
|
|
|
4
4
|
import { resolveRpcAuthority } from '../../rpc-authority.mjs';
|
|
5
5
|
import { publicWorkspaceError, SET_WORKSPACE_ENDPOINT, validWorkspacePayload } from '../shared/workspace-rpc.mjs';
|
|
6
6
|
import { SET_AGENT_PRESET_ENDPOINT, validAgentPresetPayload } from '../shared/agent-preset-rpc.mjs';
|
|
7
|
+
import { SET_MODEL_ENDPOINT, validModelPayload } from '../shared/model-setting-rpc.mjs';
|
|
7
8
|
import {
|
|
8
9
|
connectionTestTargetUnavailable,
|
|
9
10
|
publicConnectionTestResult,
|
|
@@ -19,6 +20,7 @@ export const WECOM_ENDPOINTS = Object.freeze({
|
|
|
19
20
|
reconnectBot: 'bot.reconnect',
|
|
20
21
|
deleteBot: 'bot.delete',
|
|
21
22
|
setWorkspace: SET_WORKSPACE_ENDPOINT,
|
|
23
|
+
setModel: SET_MODEL_ENDPOINT,
|
|
22
24
|
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
23
25
|
setContextEnhancement: SET_CONTEXT_ENHANCEMENT_ENDPOINT,
|
|
24
26
|
setAccessPolicy: SET_ACCESS_POLICY_ENDPOINT,
|
|
@@ -76,6 +78,9 @@ function payloadFailure(endpoint, payload) {
|
|
|
76
78
|
return validWorkspacePayload(payload)
|
|
77
79
|
? null : '请输入工作区绝对路径。';
|
|
78
80
|
}
|
|
81
|
+
if (endpoint === WECOM_ENDPOINTS.setModel) {
|
|
82
|
+
return validModelPayload(payload) ? null : '请选择有效模型。';
|
|
83
|
+
}
|
|
79
84
|
if (endpoint === WECOM_ENDPOINTS.setAgentPreset) {
|
|
80
85
|
return validAgentPresetPayload(payload)
|
|
81
86
|
? null : '请选择 Agent Preset。';
|
|
@@ -184,6 +189,12 @@ export function createWecomRpcHandler(controller, { encodeQr = qrDataUrl } = {})
|
|
|
184
189
|
await controller.updateWorkspace(payload.botId, payload.workspace),
|
|
185
190
|
cachedEncode,
|
|
186
191
|
);
|
|
192
|
+
} else if (endpoint === WECOM_ENDPOINTS.setModel) {
|
|
193
|
+
if (typeof controller.updateModel !== 'function') throw new Error('Model update is unavailable');
|
|
194
|
+
value = await publicStatus(
|
|
195
|
+
await controller.updateModel(payload.botId, payload.model),
|
|
196
|
+
cachedEncode,
|
|
197
|
+
);
|
|
187
198
|
} else if (endpoint === WECOM_ENDPOINTS.setContextEnhancement) {
|
|
188
199
|
if (typeof controller.updateContextEnhancement !== 'function') throw new Error('Context enhancement update is unavailable');
|
|
189
200
|
value = await controller.updateContextEnhancement(
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
observeBotWorkspaceRemovals,
|
|
19
19
|
} from '../../../../src/channels/shared/bot-workspace-store.mjs';
|
|
20
20
|
import { listAgentPresetCatalog } from '../../../../src/channels/shared/agent-preset.mjs';
|
|
21
|
+
import { listModelCatalog } from '../../../../src/channels/shared/model-setting.mjs';
|
|
21
22
|
import { createDeliveryAdapter } from '../../delivery-adapter.mjs';
|
|
22
23
|
import { createConnectionSupervisor } from './connection-supervisor.mjs';
|
|
23
24
|
import { createHarnessCommandExecutor } from '../../harness-command-executor.mjs';
|
|
@@ -108,6 +109,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
108
109
|
...(sessionMaintenanceExecutor ? { sessionMaintenanceExecutor } : {}),
|
|
109
110
|
...(fileIngressExecutor ? { fileIngressExecutor } : {}),
|
|
110
111
|
});
|
|
112
|
+
const modelCatalog = () => listModelCatalog(harness);
|
|
111
113
|
const coreController = new Controller({
|
|
112
114
|
api,
|
|
113
115
|
credentials: ctx.credentials,
|
|
@@ -160,6 +162,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
160
162
|
workspaces,
|
|
161
163
|
stateFor,
|
|
162
164
|
agentPresetCatalog,
|
|
165
|
+
modelCatalog,
|
|
163
166
|
});
|
|
164
167
|
const supervisor = createSupervisor({
|
|
165
168
|
controller,
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
SET_AGENT_PRESET_ENDPOINT,
|
|
12
12
|
validAgentPresetPayload,
|
|
13
13
|
} from '../shared/agent-preset-rpc.mjs';
|
|
14
|
+
import { SET_MODEL_ENDPOINT, validModelPayload } from '../shared/model-setting-rpc.mjs';
|
|
14
15
|
import {
|
|
15
16
|
connectionTestTargetUnavailable,
|
|
16
17
|
publicConnectionTestResult,
|
|
@@ -26,6 +27,7 @@ export const WEIXIN_ENDPOINTS = Object.freeze({
|
|
|
26
27
|
reconnectBot: 'bot.reconnect',
|
|
27
28
|
deleteBot: 'bot.delete',
|
|
28
29
|
setWorkspace: SET_WORKSPACE_ENDPOINT,
|
|
30
|
+
setModel: SET_MODEL_ENDPOINT,
|
|
29
31
|
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
30
32
|
setContextEnhancement: SET_CONTEXT_ENHANCEMENT_ENDPOINT,
|
|
31
33
|
setAccessPolicy: SET_ACCESS_POLICY_ENDPOINT,
|
|
@@ -83,6 +85,9 @@ function payloadFailure(endpoint, payload) {
|
|
|
83
85
|
return validWorkspacePayload(payload)
|
|
84
86
|
? null : '请输入工作区绝对路径。';
|
|
85
87
|
}
|
|
88
|
+
if (endpoint === WEIXIN_ENDPOINTS.setModel) {
|
|
89
|
+
return validModelPayload(payload) ? null : '请选择有效模型。';
|
|
90
|
+
}
|
|
86
91
|
if (endpoint === WEIXIN_ENDPOINTS.setAgentPreset) {
|
|
87
92
|
return validAgentPresetPayload(payload)
|
|
88
93
|
? null : '请选择 Agent Preset。';
|
|
@@ -219,6 +224,12 @@ export function createWeixinRpcHandler(controller, { encodeQr = qrDataUrl } = {}
|
|
|
219
224
|
await controller.updateWorkspace(payload.botId, payload.workspace),
|
|
220
225
|
cachedEncode,
|
|
221
226
|
);
|
|
227
|
+
} else if (endpoint === WEIXIN_ENDPOINTS.setModel) {
|
|
228
|
+
if (typeof controller.updateModel !== 'function') throw new Error('Model update is unavailable');
|
|
229
|
+
value = await publicStatus(
|
|
230
|
+
await controller.updateModel(payload.botId, payload.model),
|
|
231
|
+
cachedEncode,
|
|
232
|
+
);
|
|
222
233
|
} else if (endpoint === WEIXIN_ENDPOINTS.setContextEnhancement) {
|
|
223
234
|
if (typeof controller.updateContextEnhancement !== 'function') throw new Error('Context enhancement update is unavailable');
|
|
224
235
|
value = await controller.updateContextEnhancement(
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
observeBotWorkspaceRemovals,
|
|
19
19
|
} from '../../../../src/channels/shared/bot-workspace-store.mjs';
|
|
20
20
|
import { listAgentPresetCatalog } from '../../../../src/channels/shared/agent-preset.mjs';
|
|
21
|
+
import { listModelCatalog } from '../../../../src/channels/shared/model-setting.mjs';
|
|
21
22
|
import { createDeliveryAdapter } from '../../delivery-adapter.mjs';
|
|
22
23
|
import { createTokenConnectionSupervisor } from '../shared/connection-supervisor.mjs';
|
|
23
24
|
import { createHarnessCommandExecutor } from '../../harness-command-executor.mjs';
|
|
@@ -111,6 +112,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
111
112
|
...(sessionMaintenanceExecutor ? { sessionMaintenanceExecutor } : {}),
|
|
112
113
|
...(fileIngressExecutor ? { fileIngressExecutor } : {}),
|
|
113
114
|
});
|
|
115
|
+
const modelCatalog = () => listModelCatalog(harness);
|
|
114
116
|
const coreController = new Controller({
|
|
115
117
|
configStore: observedConfigStore,
|
|
116
118
|
authPath: paths.authPath,
|
|
@@ -167,6 +169,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
167
169
|
workspaces,
|
|
168
170
|
stateFor,
|
|
169
171
|
agentPresetCatalog,
|
|
172
|
+
modelCatalog,
|
|
170
173
|
});
|
|
171
174
|
const supervisor = createSupervisor({
|
|
172
175
|
channel: 'whatsapp',
|
|
@@ -6,6 +6,7 @@ import { SET_CONTEXT_ENHANCEMENT_ENDPOINT, validContextEnhancementPayload } from
|
|
|
6
6
|
import { resolveRpcAuthority } from '../../rpc-authority.mjs';
|
|
7
7
|
import { publicWorkspaceError, SET_WORKSPACE_ENDPOINT, validWorkspacePayload } from '../shared/workspace-rpc.mjs';
|
|
8
8
|
import { SET_AGENT_PRESET_ENDPOINT, validAgentPresetPayload } from '../shared/agent-preset-rpc.mjs';
|
|
9
|
+
import { SET_MODEL_ENDPOINT, validModelPayload } from '../shared/model-setting-rpc.mjs';
|
|
9
10
|
|
|
10
11
|
export const WHATSAPP_RPC_CHANNEL = '/whatsapp';
|
|
11
12
|
export const WHATSAPP_ENDPOINTS = Object.freeze({
|
|
@@ -17,6 +18,7 @@ export const WHATSAPP_ENDPOINTS = Object.freeze({
|
|
|
17
18
|
deleteBot: 'bot.delete',
|
|
18
19
|
setAccessPolicy: SET_ACCESS_POLICY_ENDPOINT,
|
|
19
20
|
setWorkspace: SET_WORKSPACE_ENDPOINT,
|
|
21
|
+
setModel: SET_MODEL_ENDPOINT,
|
|
20
22
|
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
21
23
|
setContextEnhancement: SET_CONTEXT_ENHANCEMENT_ENDPOINT,
|
|
22
24
|
});
|
|
@@ -62,6 +64,9 @@ function payloadFailure(endpoint, payload) {
|
|
|
62
64
|
return validWorkspacePayload(payload)
|
|
63
65
|
? null : '请输入工作区绝对路径。';
|
|
64
66
|
}
|
|
67
|
+
if (endpoint === WHATSAPP_ENDPOINTS.setModel) {
|
|
68
|
+
return validModelPayload(payload) ? null : '请选择有效模型。';
|
|
69
|
+
}
|
|
65
70
|
if (endpoint === WHATSAPP_ENDPOINTS.setAgentPreset) {
|
|
66
71
|
return validAgentPresetPayload(payload)
|
|
67
72
|
? null : '请选择 Agent Preset。';
|
|
@@ -172,6 +177,12 @@ export function createWhatsappRpcHandler(controller, { encodeQr = qrDataUrl } =
|
|
|
172
177
|
await controller.updateWorkspace(payload.botId, payload.workspace),
|
|
173
178
|
cachedEncode,
|
|
174
179
|
);
|
|
180
|
+
} else if (endpoint === WHATSAPP_ENDPOINTS.setModel) {
|
|
181
|
+
if (typeof controller.updateModel !== 'function') throw new Error('Model update is unavailable');
|
|
182
|
+
value = await publicStatus(
|
|
183
|
+
await controller.updateModel(payload.botId, payload.model),
|
|
184
|
+
cachedEncode,
|
|
185
|
+
);
|
|
175
186
|
} else if (endpoint === WHATSAPP_ENDPOINTS.setContextEnhancement) {
|
|
176
187
|
if (typeof controller.updateContextEnhancement !== 'function') throw new Error('Context enhancement update is unavailable');
|
|
177
188
|
value = await controller.updateContextEnhancement(
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
deliverySuggestionsFromSessions,
|
|
3
|
+
privateConversationKeyMatchesTarget,
|
|
4
|
+
resolvePrivateConversationKey,
|
|
5
|
+
} from './delivery-suggestions.mjs';
|
|
2
6
|
|
|
3
7
|
const CHANNELS = new Set([
|
|
4
8
|
'weixin',
|
|
@@ -22,6 +26,12 @@ function invalidTarget(message) {
|
|
|
22
26
|
return error;
|
|
23
27
|
}
|
|
24
28
|
|
|
29
|
+
function sessionSyncUnavailable(message = 'Session sync is unavailable for this target') {
|
|
30
|
+
const error = new Error(message);
|
|
31
|
+
error.code = 'session-sync-unavailable';
|
|
32
|
+
return error;
|
|
33
|
+
}
|
|
34
|
+
|
|
25
35
|
function isRecord(value) {
|
|
26
36
|
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
27
37
|
}
|
|
@@ -129,6 +139,49 @@ export function normalizeDeliveryTarget(channel, value, { targetIdRequired = tru
|
|
|
129
139
|
return normalized;
|
|
130
140
|
}
|
|
131
141
|
|
|
142
|
+
function targetWithoutSessionSync(target) {
|
|
143
|
+
return {
|
|
144
|
+
targetId: target.targetId,
|
|
145
|
+
...(target.name === undefined ? {} : { name: target.name }),
|
|
146
|
+
kind: target.kind,
|
|
147
|
+
route: target.route,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function sessionSyncConfigs(workspaces, botId) {
|
|
152
|
+
if (typeof workspaces.listSessionSyncTargets !== 'function') return [];
|
|
153
|
+
const targets = workspaces.listSessionSyncTargets();
|
|
154
|
+
return botId === undefined ? targets : targets.filter((target) => target.botId === botId);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function stateSessions(state) {
|
|
158
|
+
if (!state || typeof state.snapshot !== 'function') return null;
|
|
159
|
+
const sessions = state.snapshot()?.sessions;
|
|
160
|
+
return sessions && typeof sessions === 'object' && !Array.isArray(sessions) ? sessions : null;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function sessionSyncView(channel, target, sessions, configured) {
|
|
164
|
+
if (configured) {
|
|
165
|
+
const valid = privateConversationKeyMatchesTarget(
|
|
166
|
+
channel,
|
|
167
|
+
configured.conversationKey,
|
|
168
|
+
target,
|
|
169
|
+
);
|
|
170
|
+
if (!valid || !sessions) return { enabled: true, state: 'unavailable' };
|
|
171
|
+
return {
|
|
172
|
+
enabled: true,
|
|
173
|
+
state: typeof sessions[configured.conversationKey] === 'string'
|
|
174
|
+
&& Boolean(sessions[configured.conversationKey])
|
|
175
|
+
? 'active'
|
|
176
|
+
: 'waiting',
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
const conversationKey = sessions
|
|
180
|
+
? resolvePrivateConversationKey(channel, sessions, target)
|
|
181
|
+
: null;
|
|
182
|
+
return { enabled: false, state: conversationKey ? 'off' : 'unavailable' };
|
|
183
|
+
}
|
|
184
|
+
|
|
132
185
|
/** Bind one channel's existing workspace store and unwrapped controller to DeliveryService. */
|
|
133
186
|
export function createDeliveryAdapter({ channel, workspaces, coreController, stateFor }) {
|
|
134
187
|
if (!supportsDeliveryChannel(channel)) throw new TypeError(`Unsupported delivery channel: ${channel}`);
|
|
@@ -145,7 +198,22 @@ export function createDeliveryAdapter({ channel, workspaces, coreController, sta
|
|
|
145
198
|
channel,
|
|
146
199
|
ownsBot: (botId) => workspaces.has(botId),
|
|
147
200
|
listBots: () => workspaces.listBotIds(),
|
|
148
|
-
listTargets
|
|
201
|
+
async listTargets(botId) {
|
|
202
|
+
const targets = workspaces.listDeliveryTargets(botId);
|
|
203
|
+
const configured = new Map(
|
|
204
|
+
sessionSyncConfigs(workspaces, botId).map((target) => [target.targetId, target]),
|
|
205
|
+
);
|
|
206
|
+
let sessions = null;
|
|
207
|
+
try {
|
|
208
|
+
sessions = stateSessions(await stateFor(botId));
|
|
209
|
+
} catch {
|
|
210
|
+
// Target CRUD remains usable when its persisted conversation state cannot be read.
|
|
211
|
+
}
|
|
212
|
+
return targets.map((target) => ({
|
|
213
|
+
...target,
|
|
214
|
+
sessionSync: sessionSyncView(channel, target, sessions, configured.get(target.targetId)),
|
|
215
|
+
}));
|
|
216
|
+
},
|
|
149
217
|
async listSuggestions(botId) {
|
|
150
218
|
const state = await stateFor(botId);
|
|
151
219
|
if (!state || typeof state.snapshot !== 'function') {
|
|
@@ -169,12 +237,82 @@ export function createDeliveryAdapter({ channel, workspaces, coreController, sta
|
|
|
169
237
|
),
|
|
170
238
|
deleteTarget: (botId, targetId) => workspaces.deleteDeliveryTarget(botId, targetId),
|
|
171
239
|
async sendText(botId, target, text, options = {}) {
|
|
172
|
-
const normalized = normalizeDeliveryTarget(channel, target);
|
|
240
|
+
const normalized = normalizeDeliveryTarget(channel, targetWithoutSessionSync(target));
|
|
173
241
|
if (typeof coreController.sendProactiveText !== 'function') {
|
|
174
242
|
throw new TypeError('delivery controller cannot send proactive text');
|
|
175
243
|
}
|
|
176
244
|
await coreController.sendProactiveText(botId, normalized, text, options);
|
|
177
245
|
return { sent: true };
|
|
178
246
|
},
|
|
247
|
+
async setSessionSync(botId, targetId, enabled) {
|
|
248
|
+
if (typeof workspaces.setDeliveryTargetSessionSync !== 'function') {
|
|
249
|
+
throw sessionSyncUnavailable();
|
|
250
|
+
}
|
|
251
|
+
const target = workspaces.deliveryTargetFor(botId, targetId);
|
|
252
|
+
if (!target) {
|
|
253
|
+
const error = new Error('Unknown target');
|
|
254
|
+
error.code = 'unknown-target';
|
|
255
|
+
throw error;
|
|
256
|
+
}
|
|
257
|
+
if (!enabled) {
|
|
258
|
+
await workspaces.setDeliveryTargetSessionSync(botId, targetId, null);
|
|
259
|
+
let sessions = null;
|
|
260
|
+
try {
|
|
261
|
+
sessions = stateSessions(await stateFor(botId));
|
|
262
|
+
} catch {
|
|
263
|
+
// The setting is already safely disabled; only its availability is unknown.
|
|
264
|
+
}
|
|
265
|
+
return sessionSyncView(channel, target, sessions, null);
|
|
266
|
+
}
|
|
267
|
+
const sessions = stateSessions(await stateFor(botId));
|
|
268
|
+
const conversationKey = resolvePrivateConversationKey(channel, sessions, target);
|
|
269
|
+
if (!conversationKey) throw sessionSyncUnavailable();
|
|
270
|
+
await workspaces.setDeliveryTargetSessionSync(botId, targetId, conversationKey);
|
|
271
|
+
return { enabled: true, state: 'active' };
|
|
272
|
+
},
|
|
273
|
+
async listSessionSyncTargets(sessionId) {
|
|
274
|
+
if (typeof sessionId !== 'string' || !sessionId) {
|
|
275
|
+
throw new TypeError('sessionId is required');
|
|
276
|
+
}
|
|
277
|
+
const matches = [];
|
|
278
|
+
for (const configured of sessionSyncConfigs(workspaces)) {
|
|
279
|
+
const target = workspaces.deliveryTargetFor(configured.botId, configured.targetId);
|
|
280
|
+
if (!target || !privateConversationKeyMatchesTarget(
|
|
281
|
+
channel,
|
|
282
|
+
configured.conversationKey,
|
|
283
|
+
target,
|
|
284
|
+
)) continue;
|
|
285
|
+
let sessions;
|
|
286
|
+
try {
|
|
287
|
+
sessions = stateSessions(await stateFor(configured.botId));
|
|
288
|
+
} catch {
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
if (sessions?.[configured.conversationKey] === sessionId) {
|
|
292
|
+
matches.push({ botId: configured.botId, targetId: configured.targetId });
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return matches;
|
|
296
|
+
},
|
|
297
|
+
async sendSessionSyncText(botId, targetId, sessionId, text, options = {}) {
|
|
298
|
+
if (typeof text !== 'string' || !text.trim()) throw new TypeError('text is required');
|
|
299
|
+
const configured = sessionSyncConfigs(workspaces, botId)
|
|
300
|
+
.find((target) => target.targetId === targetId);
|
|
301
|
+
const target = workspaces.deliveryTargetFor(botId, targetId);
|
|
302
|
+
if (!configured || !target || !privateConversationKeyMatchesTarget(
|
|
303
|
+
channel,
|
|
304
|
+
configured.conversationKey,
|
|
305
|
+
target,
|
|
306
|
+
)) throw sessionSyncUnavailable('Session sync target is no longer enabled');
|
|
307
|
+
const sessions = stateSessions(await stateFor(botId));
|
|
308
|
+
if (sessions?.[configured.conversationKey] !== sessionId) {
|
|
309
|
+
throw sessionSyncUnavailable('Session sync target is no longer bound to this Session');
|
|
310
|
+
}
|
|
311
|
+
if (typeof coreController.sendProactiveText !== 'function') {
|
|
312
|
+
throw new TypeError('delivery controller cannot send proactive text');
|
|
313
|
+
}
|
|
314
|
+
await coreController.sendProactiveText(botId, target, text, options);
|
|
315
|
+
return { sent: true };
|
|
316
|
+
},
|
|
179
317
|
});
|
|
180
318
|
}
|