@xmanrui/dsh-im 4.9.1 → 4.11.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.
Files changed (72) hide show
  1. package/PROACTIVE_DELIVERY.en.md +23 -1
  2. package/PROACTIVE_DELIVERY.md +23 -1
  3. package/README.en.md +5 -1
  4. package/README.md +6 -2
  5. package/lib/client.js +2077 -673
  6. package/lib/index.js +277 -272
  7. package/package.json +13 -1
  8. package/plugin-src/client/channel-card-meta.js +9 -1
  9. package/plugin-src/client/channels/dingtalk/api.js +4 -0
  10. package/plugin-src/client/channels/dingtalk/index.js +25 -2
  11. package/plugin-src/client/channels/feishu/api.js +6 -0
  12. package/plugin-src/client/channels/feishu/group-settings.js +581 -0
  13. package/plugin-src/client/channels/feishu/index.js +26 -150
  14. package/plugin-src/client/channels/qq/api.js +4 -0
  15. package/plugin-src/client/channels/qq/index.js +25 -2
  16. package/plugin-src/client/channels/shared/token-api.js +4 -0
  17. package/plugin-src/client/channels/shared/token-channel.js +25 -3
  18. package/plugin-src/client/channels/wecom/api.js +4 -0
  19. package/plugin-src/client/channels/wecom/index.js +25 -2
  20. package/plugin-src/client/channels/weixin/api.js +4 -0
  21. package/plugin-src/client/channels/weixin/index.js +25 -2
  22. package/plugin-src/client/channels/whatsapp/api.js +4 -0
  23. package/plugin-src/client/channels/whatsapp/index.js +24 -2
  24. package/plugin-src/client/delivery-settings.js +73 -5
  25. package/plugin-src/client/global-settings.js +341 -0
  26. package/plugin-src/client/i18n.js +49 -0
  27. package/plugin-src/client/index.js +47 -6
  28. package/plugin-src/client/model-setting.js +104 -0
  29. package/plugin-src/client/styles.js +99 -0
  30. package/plugin-src/host/channels/dingtalk/production.mjs +15 -0
  31. package/plugin-src/host/channels/dingtalk/rpc.mjs +11 -0
  32. package/plugin-src/host/channels/feishu/production.mjs +17 -0
  33. package/plugin-src/host/channels/feishu/rpc.mjs +32 -0
  34. package/plugin-src/host/channels/qq/production.mjs +15 -0
  35. package/plugin-src/host/channels/qq/rpc.mjs +11 -0
  36. package/plugin-src/host/channels/shared/model-setting-rpc.mjs +19 -0
  37. package/plugin-src/host/channels/shared/production.mjs +15 -0
  38. package/plugin-src/host/channels/shared/rpc.mjs +9 -0
  39. package/plugin-src/host/channels/shared/workspace-rpc.mjs +2 -0
  40. package/plugin-src/host/channels/slack/production.mjs +15 -0
  41. package/plugin-src/host/channels/slack/rpc.mjs +9 -0
  42. package/plugin-src/host/channels/wecom/production.mjs +15 -0
  43. package/plugin-src/host/channels/wecom/rpc.mjs +11 -0
  44. package/plugin-src/host/channels/weixin/production.mjs +15 -0
  45. package/plugin-src/host/channels/weixin/rpc.mjs +11 -0
  46. package/plugin-src/host/channels/whatsapp/production.mjs +15 -0
  47. package/plugin-src/host/channels/whatsapp/rpc.mjs +11 -0
  48. package/plugin-src/host/delivery-adapter.mjs +142 -3
  49. package/plugin-src/host/delivery-rpc.mjs +12 -0
  50. package/plugin-src/host/delivery-service.mjs +125 -3
  51. package/plugin-src/host/delivery-suggestions.mjs +46 -0
  52. package/plugin-src/host/harness-session-coordinator.mjs +32 -10
  53. package/plugin-src/host/inbound-ttl-rpc.mjs +83 -0
  54. package/plugin-src/host/inbound-ttl-runtime.mjs +85 -0
  55. package/plugin-src/host/inbound-ttl-service.mjs +179 -0
  56. package/plugin-src/host/index.mjs +26 -1
  57. package/plugin-src/host/modern-harness-api.mjs +58 -2
  58. package/plugin-src/host/session-sync-coordinator.mjs +217 -0
  59. package/scripts/verify-package.mjs +12 -6
  60. package/src/channels/feishu/bridge.mjs +164 -4
  61. package/src/channels/feishu/feishu-channel.mjs +45 -10
  62. package/src/channels/feishu/feishu-runtime.mjs +9 -0
  63. package/src/channels/feishu/message-utils.mjs +13 -0
  64. package/src/channels/feishu/multi-bot-controller.mjs +16 -0
  65. package/src/channels/feishu/plugin-config-store.mjs +1 -0
  66. package/src/channels/feishu/state-store.mjs +25 -0
  67. package/src/channels/shared/bot-workspace-store.mjs +291 -38
  68. package/src/channels/shared/harness-client.mjs +124 -43
  69. package/src/channels/shared/inbound-file.mjs +117 -2
  70. package/src/channels/shared/inbound-ttl-store.mjs +110 -0
  71. package/src/channels/shared/inbound-ttl.mjs +22 -0
  72. package/src/channels/shared/model-setting.mjs +110 -0
@@ -21,6 +21,11 @@ import {
21
21
  AgentPresetEditor,
22
22
  EMPTY_AGENT_PRESET_CATALOG,
23
23
  } from '../../agent-preset.js';
24
+ import {
25
+ EMPTY_MODEL_CATALOG,
26
+ ModelCatalogContext,
27
+ ModelEditor,
28
+ } from '../../model-setting.js';
24
29
  import { useWorkspaceSnapshotFence } from '../../workspace-snapshot-fence.js';
25
30
  import {
26
31
  BotSettingsButton,
@@ -208,6 +213,7 @@ export function AccountCard({
208
213
  removing,
209
214
  onReconnect,
210
215
  onWorkspaceSave,
216
+ onModelSave,
211
217
  onAgentPresetSave,
212
218
  onContextEnhancementSave,
213
219
  onRequestRemove,
@@ -244,6 +250,11 @@ export function AccountCard({
244
250
  disabled: Boolean(busy),
245
251
  onSave: onWorkspaceSave,
246
252
  }),
253
+ h(ModelEditor, {
254
+ model: account.model,
255
+ disabled: Boolean(busy),
256
+ onSave: onModelSave,
257
+ }),
247
258
  h(AgentPresetEditor, {
248
259
  agentPreset: account.agentPreset,
249
260
  disabled: Boolean(busy),
@@ -296,6 +307,7 @@ function AccountList(props) {
296
307
  removing: props.removeTarget === account.botId,
297
308
  onReconnect: () => props.onReconnect(account),
298
309
  onWorkspaceSave: (workspace) => props.onWorkspaceSave(account, workspace),
310
+ onModelSave: (model) => props.onModelSave(account, model),
299
311
  onAgentPresetSave: (agentPreset) => props.onAgentPresetSave(account, agentPreset),
300
312
  onContextEnhancementSave: (config) => props.onContextEnhancementSave(account, config),
301
313
  onRequestRemove: () => props.onRequestRemove(account),
@@ -324,6 +336,7 @@ export function WeixinSettingsTab({ rpcCall }) {
324
336
  const [model, setModel] = React.useState({
325
337
  phase: 'loading', bots: [], totals: EMPTY_TOTALS, revision: 0, error: null,
326
338
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
339
+ modelCatalog: EMPTY_MODEL_CATALOG,
327
340
  });
328
341
  const [provision, setProvision] = React.useState(null);
329
342
  const [busy, setBusy] = React.useState(false);
@@ -367,6 +380,7 @@ export function WeixinSettingsTab({ rpcCall }) {
367
380
  phase: 'ready', bots: snapshot.bots, totals: snapshot.totals,
368
381
  revision: snapshot.revision, error: null,
369
382
  agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
383
+ modelCatalog: snapshot.modelCatalog ?? EMPTY_MODEL_CATALOG,
370
384
  });
371
385
  if (snapshot.provisioning) {
372
386
  setProvision((current) => mergeWeixinProvisioningSnapshot(
@@ -558,6 +572,7 @@ export function WeixinSettingsTab({ rpcCall }) {
558
572
  setModel((current) => ({
559
573
  ...current, bots: snapshot.bots, totals: snapshot.totals, revision: snapshot.revision,
560
574
  agentPresetCatalog: snapshot.agentPresetCatalog ?? current.agentPresetCatalog,
575
+ modelCatalog: snapshot.modelCatalog ?? current.modelCatalog,
561
576
  }));
562
577
  }
563
578
  const refreshed = snapshot.bots.find((bot) => bot.botId === account.botId);
@@ -603,6 +618,7 @@ export function WeixinSettingsTab({ rpcCall }) {
603
618
  phase: 'ready', bots: snapshot.bots, totals: snapshot.totals,
604
619
  revision: snapshot.revision, error: null,
605
620
  agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
621
+ modelCatalog: snapshot.modelCatalog ?? EMPTY_MODEL_CATALOG,
606
622
  });
607
623
  }
608
624
  } finally {
@@ -625,6 +641,7 @@ export function WeixinSettingsTab({ rpcCall }) {
625
641
  phase: 'ready', bots: snapshot.bots, totals: snapshot.totals,
626
642
  revision: snapshot.revision, error: null,
627
643
  agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
644
+ modelCatalog: snapshot.modelCatalog ?? EMPTY_MODEL_CATALOG,
628
645
  });
629
646
  }
630
647
  } finally {
@@ -646,6 +663,7 @@ export function WeixinSettingsTab({ rpcCall }) {
646
663
  setModel((current) => ({
647
664
  ...current, bots: snapshot.bots, totals: snapshot.totals, revision: snapshot.revision,
648
665
  agentPresetCatalog: snapshot.agentPresetCatalog ?? current.agentPresetCatalog,
666
+ modelCatalog: snapshot.modelCatalog ?? current.modelCatalog,
649
667
  }));
650
668
  }
651
669
  setRemoveTarget(null);
@@ -686,7 +704,9 @@ export function WeixinSettingsTab({ rpcCall }) {
686
704
  });
687
705
  }
688
706
 
689
- return h(AgentPresetCatalogContext.Provider, {
707
+ return h(ModelCatalogContext.Provider, {
708
+ value: model.modelCatalog ?? EMPTY_MODEL_CATALOG,
709
+ }, h(AgentPresetCatalogContext.Provider, {
690
710
  value: model.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
691
711
  }, h('section', { className: 'dxw-page dim-channelPage', 'aria-label': '微信设置' },
692
712
  h(Heading, {
@@ -721,6 +741,9 @@ export function WeixinSettingsTab({ rpcCall }) {
721
741
  removeTarget,
722
742
  onReconnect: (account) => void reconnect(account),
723
743
  onWorkspaceSave: saveWorkspace,
744
+ onModelSave: (account, selectedModel) => saveBotSetting(
745
+ account, 'model', WEIXIN_ENDPOINTS.setModel, { model: selectedModel },
746
+ ),
724
747
  onAgentPresetSave: (account, agentPreset) => saveBotSetting(
725
748
  account, 'preset', WEIXIN_ENDPOINTS.setAgentPreset, { agentPreset },
726
749
  ),
@@ -732,5 +755,5 @@ export function WeixinSettingsTab({ rpcCall }) {
732
755
  onCancelRemove: () => setRemoveTarget(null),
733
756
  })
734
757
  : null),
735
- ));
758
+ )));
736
759
  }
@@ -1,4 +1,5 @@
1
1
  import { normalizeAgentPresetCatalog, normalizeAgentPresetId, SET_AGENT_PRESET_ENDPOINT } from '../../agent-preset.js';
2
+ import { normalizeModelCatalog, normalizeModelSelection, SET_MODEL_ENDPOINT } from '../../model-setting.js';
2
3
  import { normalizeLastMessageError } from '../../last-message-error.js';
3
4
  import { normalizeAccessPolicy } from '../../../../src/channels/shared/access-policy.mjs';
4
5
  import { normalizeContextEnhancementConfig } from '../../../../src/channels/shared/context-enhancement.mjs';
@@ -14,6 +15,7 @@ export const WHATSAPP_ENDPOINTS = Object.freeze({
14
15
  deleteBot: 'bot.delete',
15
16
  setAccessPolicy: 'bot.access-policy.set',
16
17
  setWorkspace: 'bot.workspace.set',
18
+ setModel: SET_MODEL_ENDPOINT,
17
19
  setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
18
20
  setContextEnhancement: 'bot.context-enhancement.set',
19
21
  });
@@ -90,6 +92,7 @@ function normalizeBot(value) {
90
92
  connected,
91
93
  state: connected ? 'connected' : state,
92
94
  workspace: text(value.workspace, '', 4_096),
95
+ model: normalizeModelSelection(value.model),
93
96
  agentPreset: normalizeAgentPresetId(value.agentPreset),
94
97
  contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
95
98
  ...(Object.hasOwn(value, 'accessPolicy')
@@ -124,6 +127,7 @@ export function normalizeSnapshot(value) {
124
127
  totals: { configured: bots.length, connected: bots.filter((bot) => bot.connected).length },
125
128
  provisioning: source.provisioning ? normalizeProvisioning(source.provisioning) : null,
126
129
  agentPresetCatalog: normalizeAgentPresetCatalog(source.agentPresetCatalog),
130
+ modelCatalog: normalizeModelCatalog(source.modelCatalog),
127
131
  };
128
132
  }
129
133
 
@@ -10,6 +10,11 @@ import {
10
10
  AgentPresetEditor,
11
11
  EMPTY_AGENT_PRESET_CATALOG,
12
12
  } from '../../agent-preset.js';
13
+ import {
14
+ EMPTY_MODEL_CATALOG,
15
+ ModelCatalogContext,
16
+ ModelEditor,
17
+ } from '../../model-setting.js';
13
18
  import { useWorkspaceSnapshotFence } from '../../workspace-snapshot-fence.js';
14
19
  import {
15
20
  BotSettingsButton,
@@ -185,6 +190,7 @@ export function WhatsappAccountCard({
185
190
  removing,
186
191
  onReconnect,
187
192
  onWorkspaceSave,
193
+ onModelSave,
188
194
  onAgentPresetSave,
189
195
  onContextEnhancementSave,
190
196
  onRequestRemove,
@@ -226,6 +232,11 @@ export function WhatsappAccountCard({
226
232
  disabled: Boolean(busy),
227
233
  onSave: onWorkspaceSave,
228
234
  }),
235
+ h(ModelEditor, {
236
+ model: account.model,
237
+ disabled: Boolean(busy),
238
+ onSave: onModelSave,
239
+ }),
229
240
  h(AgentPresetEditor, {
230
241
  agentPreset: account.agentPreset,
231
242
  disabled: Boolean(busy),
@@ -266,6 +277,7 @@ export function WhatsappSettingsTab({ rpcCall }) {
266
277
  const [model, setModel] = React.useState({
267
278
  phase: 'loading', bots: [], totals: { configured: 0, connected: 0 }, error: null,
268
279
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
280
+ modelCatalog: EMPTY_MODEL_CATALOG,
269
281
  });
270
282
  const [provision, setProvision] = React.useState(null);
271
283
  const [busy, setBusy] = React.useState(false);
@@ -304,6 +316,7 @@ export function WhatsappSettingsTab({ rpcCall }) {
304
316
  setModel({
305
317
  phase: 'ready', bots: snapshot.bots, totals: snapshot.totals, error: null,
306
318
  agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
319
+ modelCatalog: snapshot.modelCatalog ?? EMPTY_MODEL_CATALOG,
307
320
  });
308
321
  if (restore && snapshot.provisioning) setProvision({
309
322
  ...snapshot.provisioning,
@@ -435,6 +448,7 @@ export function WhatsappSettingsTab({ rpcCall }) {
435
448
  setModel({
436
449
  phase: 'ready', bots: snapshot.bots, totals: snapshot.totals, error: null,
437
450
  agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
451
+ modelCatalog: snapshot.modelCatalog ?? EMPTY_MODEL_CATALOG,
438
452
  });
439
453
  if (operation === 'reconnect') {
440
454
  setTestNoticeByBot((current) => ({
@@ -487,6 +501,12 @@ export function WhatsappSettingsTab({ rpcCall }) {
487
501
  WHATSAPP_ENDPOINTS.setWorkspace,
488
502
  { botId: account.botId, workspace },
489
503
  ),
504
+ onModelSave: (selectedModel) => botAction(
505
+ account,
506
+ 'model',
507
+ WHATSAPP_ENDPOINTS.setModel,
508
+ { botId: account.botId, model: selectedModel },
509
+ ),
490
510
  onAgentPresetSave: (agentPreset) => botAction(
491
511
  account,
492
512
  'preset',
@@ -511,7 +531,9 @@ export function WhatsappSettingsTab({ rpcCall }) {
511
531
  })))))
512
532
  : null;
513
533
 
514
- return h(AgentPresetCatalogContext.Provider, {
534
+ return h(ModelCatalogContext.Provider, {
535
+ value: model.modelCatalog ?? EMPTY_MODEL_CATALOG,
536
+ }, h(AgentPresetCatalogContext.Provider, {
515
537
  value: model.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
516
538
  }, h('section', {
517
539
  className: 'ddt-page dwa-page dim-channelPage',
@@ -550,5 +572,5 @@ export function WhatsappSettingsTab({ rpcCall }) {
550
572
  : model.bots.length === 0
551
573
  ? h(EmptyView, { busy, onStart: () => void startProvisioning(false) })
552
574
  : null,
553
- botList)));
575
+ botList))));
554
576
  }
@@ -1,6 +1,7 @@
1
1
  import * as React from 'react';
2
2
 
3
3
  import { AccessPolicySettingsPage } from './access-policy-settings.js';
4
+ import { FeishuGroupSettingsPage } from './channels/feishu/group-settings.js';
4
5
  import { h, isEnglish, localizeText } from './i18n.js';
5
6
 
6
7
  export const DELIVERY_RPC_CHANNEL = '/dsh-im-delivery';
@@ -16,6 +17,7 @@ export const DELIVERY_ENDPOINTS = Object.freeze({
16
17
  create: 'target.create',
17
18
  update: 'target.update',
18
19
  delete: 'target.delete',
20
+ sessionSync: 'target.session-sync.set',
19
21
  test: 'target.test',
20
22
  });
21
23
 
@@ -24,6 +26,15 @@ export const BOT_SETTINGS_TABS = Object.freeze([
24
26
  Object.freeze({ id: 'access', label: '访问设置' }),
25
27
  ]);
26
28
 
29
+ export const FEISHU_BOT_SETTINGS_TABS = Object.freeze([
30
+ ...BOT_SETTINGS_TABS,
31
+ Object.freeze({ id: 'group', label: '群聊' }),
32
+ ]);
33
+
34
+ export function botSettingsTabsForChannel(channel) {
35
+ return channel === 'feishu' ? FEISHU_BOT_SETTINGS_TABS : BOT_SETTINGS_TABS;
36
+ }
37
+
27
38
  const CHANNEL_DEFINITIONS = Object.freeze({
28
39
  weixin: {
29
40
  label: '微信',
@@ -296,7 +307,9 @@ function TargetForm({
296
307
  h('div', { className: 'dim-targetFormHeading' },
297
308
  h('h3', null, editing ? '编辑投递目标' : '新建投递目标'),
298
309
  editing
299
- ? null
310
+ ? initialValue?.sessionSync?.enabled
311
+ ? h('p', null, '修改接收位置会关闭会话双向同步。')
312
+ : null
300
313
  : h('p', null, source === 'suggestion'
301
314
  ? '已从会话自动填入目标信息;确认后再保存。'
302
315
  : '请手动填写从对应平台取得的原生标识。')),
@@ -457,8 +470,17 @@ function TargetSuggestionPicker({
457
470
  function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, onEdit }) {
458
471
  const [action, setAction] = React.useState(null);
459
472
  const [testState, setTestState] = React.useState(null);
473
+ const [syncFeedback, setSyncFeedback] = React.useState(null);
460
474
  const [copyState, setCopyState] = React.useState(null);
461
475
  const [confirmDelete, setConfirmDelete] = React.useState(false);
476
+ const sessionSync = target.sessionSync ?? { enabled: false, state: 'unavailable' };
477
+ const syncDescription = sessionSync.state === 'active'
478
+ ? '自动跟随该私聊的当前会话'
479
+ : sessionSync.state === 'waiting'
480
+ ? '等待该私聊建立新会话'
481
+ : sessionSync.state === 'unavailable'
482
+ ? '仅支持已经聊过、已建立当前会话且使用当前 Host Harness 的私聊目标'
483
+ : '关闭时不发送 DSH 会话消息';
462
484
  const testTarget = async () => {
463
485
  setAction('test');
464
486
  setTestState(null);
@@ -494,6 +516,28 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
494
516
  }
495
517
  };
496
518
 
519
+ const setSessionSync = async (enabled) => {
520
+ setAction('sync');
521
+ setSyncFeedback(null);
522
+ try {
523
+ await rpcCall(DELIVERY_ENDPOINTS.sessionSync, {
524
+ botId,
525
+ targetId: target.targetId,
526
+ enabled,
527
+ });
528
+ await onChanged();
529
+ } catch (error) {
530
+ setSyncFeedback({
531
+ tone: 'error',
532
+ message: error?.code === 'session-sync-unavailable'
533
+ ? '会话同步仅支持已经聊过、已建立当前会话且使用当前 Host Harness 的私聊目标。'
534
+ : presentError(error, '会话同步设置失败,请稍后重试。'),
535
+ });
536
+ } finally {
537
+ setAction(null);
538
+ }
539
+ };
540
+
497
541
  return h('li', { className: 'dim-targetRow', 'data-target-id': target.targetId },
498
542
  h('div', { className: 'dim-targetSummary' },
499
543
  h('div', { className: 'dim-targetTitle' },
@@ -514,7 +558,24 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
514
558
  onClick: () => setConfirmDelete(true),
515
559
  disabled: Boolean(action),
516
560
  }, '删除')),
561
+ h('label', { className: 'dim-targetSessionSync' },
562
+ h('span', { className: 'dim-targetSessionSyncCopy' },
563
+ h('strong', null, '会话双向同步'),
564
+ h('small', null, syncDescription)),
565
+ h('input', {
566
+ type: 'checkbox',
567
+ checked: sessionSync.enabled === true,
568
+ disabled: Boolean(action)
569
+ || (sessionSync.enabled !== true && sessionSync.state === 'unavailable'),
570
+ onChange: (event) => void setSessionSync(event.target.checked),
571
+ 'aria-label': '会话双向同步',
572
+ })),
517
573
  copyState ? h('p', { className: 'dim-targetFeedback', role: 'status' }, copyState) : null,
574
+ syncFeedback ? h('p', {
575
+ className: 'dim-targetFeedback',
576
+ 'data-tone': syncFeedback.tone,
577
+ role: 'alert',
578
+ }, syncFeedback.message) : null,
518
579
  testState ? h('p', {
519
580
  className: 'dim-targetFeedback',
520
581
  'data-tone': testState.tone,
@@ -524,7 +585,8 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
524
585
  confirmDelete ? h('div', { className: 'dim-targetDeleteConfirm', role: 'alertdialog' },
525
586
  h('p', null,
526
587
  '删除 ', h('code', null, target.targetId),
527
- '?使用这个 targetId 的外部调用将返回 unknown-target。'),
588
+ '?使用这个 targetId 的外部调用将返回 unknown-target。',
589
+ sessionSync.enabled ? ' 会话同步设置也会一并删除。' : null),
528
590
  h('div', { className: 'dim-targetFormActions' },
529
591
  h(DeliveryButton, {
530
592
  onClick: () => setConfirmDelete(false),
@@ -672,8 +734,9 @@ export function DeliveryTargetSettingsPage({
672
734
  }
673
735
  };
674
736
 
675
- const activeTab = BOT_SETTINGS_TABS.find((tab) => tab.id === activeTabId)
676
- ?? BOT_SETTINGS_TABS[0];
737
+ const settingsTabs = botSettingsTabsForChannel(channel);
738
+ const activeTab = settingsTabs.find((tab) => tab.id === activeTabId)
739
+ ?? settingsTabs[0];
677
740
  const activeTabDomId = `dim-bot-settings-${activeTab.id}-tab`;
678
741
  const activePanelId = `dim-bot-settings-${activeTab.id}-panel`;
679
742
 
@@ -688,7 +751,7 @@ export function DeliveryTargetSettingsPage({
688
751
  className: 'dim-botSettingsTabs',
689
752
  role: 'tablist',
690
753
  'aria-label': '机器人设置页签',
691
- }, BOT_SETTINGS_TABS.map((tab) => h('button', {
754
+ }, settingsTabs.map((tab) => h('button', {
692
755
  key: tab.id,
693
756
  id: `dim-bot-settings-${tab.id}-tab`,
694
757
  type: 'button',
@@ -712,6 +775,11 @@ export function DeliveryTargetSettingsPage({
712
775
  rpcCall: accessRpcCall,
713
776
  onSaved: setAccessPolicy,
714
777
  })
778
+ : activeTab.id === 'group' && channel === 'feishu'
779
+ ? h(FeishuGroupSettingsPage, {
780
+ account,
781
+ rpcCall: accessRpcCall,
782
+ })
715
783
  : h(React.Fragment, null,
716
784
  h('section', { className: 'dim-deliveryIdentity', 'aria-labelledby': 'dim-delivery-bot-title' },
717
785
  h('div', { className: 'dim-deliveryIdentityHeading' },