@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.
- package/PROACTIVE_DELIVERY.en.md +23 -1
- package/PROACTIVE_DELIVERY.md +23 -1
- package/README.en.md +5 -1
- package/README.md +6 -2
- package/lib/client.js +2077 -673
- package/lib/index.js +277 -272
- package/package.json +13 -1
- 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 +25 -2
- package/plugin-src/client/channels/feishu/api.js +6 -0
- package/plugin-src/client/channels/feishu/group-settings.js +581 -0
- package/plugin-src/client/channels/feishu/index.js +26 -150
- package/plugin-src/client/channels/qq/api.js +4 -0
- package/plugin-src/client/channels/qq/index.js +25 -2
- package/plugin-src/client/channels/shared/token-api.js +4 -0
- package/plugin-src/client/channels/shared/token-channel.js +25 -3
- package/plugin-src/client/channels/wecom/api.js +4 -0
- package/plugin-src/client/channels/wecom/index.js +25 -2
- package/plugin-src/client/channels/weixin/api.js +4 -0
- package/plugin-src/client/channels/weixin/index.js +25 -2
- package/plugin-src/client/channels/whatsapp/api.js +4 -0
- package/plugin-src/client/channels/whatsapp/index.js +24 -2
- package/plugin-src/client/delivery-settings.js +73 -5
- package/plugin-src/client/global-settings.js +341 -0
- package/plugin-src/client/i18n.js +49 -0
- package/plugin-src/client/index.js +47 -6
- package/plugin-src/client/model-setting.js +104 -0
- package/plugin-src/client/styles.js +99 -0
- package/plugin-src/host/channels/dingtalk/production.mjs +15 -0
- package/plugin-src/host/channels/dingtalk/rpc.mjs +11 -0
- package/plugin-src/host/channels/feishu/production.mjs +17 -0
- package/plugin-src/host/channels/feishu/rpc.mjs +32 -0
- package/plugin-src/host/channels/qq/production.mjs +15 -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 +15 -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 +15 -0
- package/plugin-src/host/channels/slack/rpc.mjs +9 -0
- package/plugin-src/host/channels/wecom/production.mjs +15 -0
- package/plugin-src/host/channels/wecom/rpc.mjs +11 -0
- package/plugin-src/host/channels/weixin/production.mjs +15 -0
- package/plugin-src/host/channels/weixin/rpc.mjs +11 -0
- package/plugin-src/host/channels/whatsapp/production.mjs +15 -0
- package/plugin-src/host/channels/whatsapp/rpc.mjs +11 -0
- package/plugin-src/host/delivery-adapter.mjs +142 -3
- package/plugin-src/host/delivery-rpc.mjs +12 -0
- package/plugin-src/host/delivery-service.mjs +125 -3
- package/plugin-src/host/delivery-suggestions.mjs +46 -0
- package/plugin-src/host/harness-session-coordinator.mjs +32 -10
- package/plugin-src/host/inbound-ttl-rpc.mjs +83 -0
- package/plugin-src/host/inbound-ttl-runtime.mjs +85 -0
- package/plugin-src/host/inbound-ttl-service.mjs +179 -0
- package/plugin-src/host/index.mjs +26 -1
- package/plugin-src/host/modern-harness-api.mjs +58 -2
- package/plugin-src/host/session-sync-coordinator.mjs +217 -0
- package/scripts/verify-package.mjs +12 -6
- package/src/channels/feishu/bridge.mjs +164 -4
- package/src/channels/feishu/feishu-channel.mjs +45 -10
- package/src/channels/feishu/feishu-runtime.mjs +9 -0
- package/src/channels/feishu/message-utils.mjs +13 -0
- package/src/channels/feishu/multi-bot-controller.mjs +16 -0
- package/src/channels/feishu/plugin-config-store.mjs +1 -0
- package/src/channels/feishu/state-store.mjs +25 -0
- package/src/channels/shared/bot-workspace-store.mjs +291 -38
- package/src/channels/shared/harness-client.mjs +124 -43
- package/src/channels/shared/inbound-file.mjs +117 -2
- package/src/channels/shared/inbound-ttl-store.mjs +110 -0
- package/src/channels/shared/inbound-ttl.mjs +22 -0
- package/src/channels/shared/model-setting.mjs +110 -0
|
@@ -61,6 +61,15 @@ const CSS = String.raw`
|
|
|
61
61
|
.dim-githubArrow { font-size: 13px; line-height: 1; }
|
|
62
62
|
.dim-githubTooltip { position: absolute; top: calc(100% + 8px); right: 0; z-index: 20; width: max-content; max-width: min(220px, 80vw); padding: 6px 9px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 8px 24px rgb(31 35 41 / 14%); font-size: 11px; line-height: 16px; font-weight: 500; white-space: nowrap; opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
|
|
63
63
|
.dim-githubAction:hover .dim-githubTooltip, .dim-githubAction:focus-within .dim-githubTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
|
|
64
|
+
.dim-generalSettingsAction { position: relative; display: inline-flex; flex: none; }
|
|
65
|
+
.dim-generalSettingsButton { width: 30px; height: 30px; display: grid; place-items: center; flex: none; padding: 0; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-layer-1, #fff); cursor: pointer; transition: border-color .15s ease, color .15s ease, background .15s ease, box-shadow .15s ease; }
|
|
66
|
+
.dim-generalSettingsButton svg { display: block; }
|
|
67
|
+
.dim-generalSettingsButton:hover { border-color: #aeb3bb; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
|
|
68
|
+
.dim-generalSettingsButton[aria-current="page"] { border-color: color-mix(in srgb, var(--dim-blue) 42%, var(--dsw-alias-border-l2, #dfe1e5)); color: var(--dim-blue); background: var(--dim-blue-soft); }
|
|
69
|
+
.dim-generalSettingsButton:focus-visible { outline: 2px solid color-mix(in srgb, var(--dim-blue) 70%, white); outline-offset: 2px; }
|
|
70
|
+
.dim-generalSettingsTooltip { position: absolute; top: calc(100% + 8px); right: 0; z-index: 20; width: max-content; padding: 6px 9px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 8px 24px rgb(31 35 41 / 14%); font-size: 11px; line-height: 16px; font-weight: 500; white-space: nowrap; opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
|
|
71
|
+
.dim-generalSettingsAction:hover .dim-generalSettingsTooltip, .dim-generalSettingsButton:focus-visible + .dim-generalSettingsTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
|
|
72
|
+
.dim-generalSettingsButton[aria-current="page"] + .dim-generalSettingsTooltip { opacity: 0; visibility: hidden; transform: translateY(-3px); }
|
|
64
73
|
.dim-layout { display: grid; grid-template-columns: 174px 1px minmax(0, 1fr); gap: 24px; align-items: start; }
|
|
65
74
|
.dim-rail { max-height: 520px; display: grid; align-content: start; gap: 8px; overflow-y: auto; padding: 0 4px 1px 1px; scrollbar-width: thin; scrollbar-color: var(--dsw-alias-border-l2, #dfe1e5) transparent; }
|
|
66
75
|
.dim-rail::-webkit-scrollbar { width: 4px; }
|
|
@@ -382,6 +391,45 @@ const CSS = String.raw`
|
|
|
382
391
|
.dim-botSettingsTab[aria-selected="true"]::after { background: var(--dsw-alias-state-business-primary, #3370ff); transform: scaleX(1); }
|
|
383
392
|
.dim-botSettingsTab:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: -2px; border-radius: 5px; }
|
|
384
393
|
.dim-botSettingsTabPanel { min-width: 0; display: grid; gap: 14px; padding-top: 14px; }
|
|
394
|
+
.dim-feishuGroupSettings { min-width: 0; display: grid; gap: 14px; }
|
|
395
|
+
.dim-feishuGroupControls { min-width: 0; display: grid; gap: 12px; }
|
|
396
|
+
.dim-feishuGroupControl { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; padding: 16px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 12px; background: var(--dsw-alias-bg-layer-3, #fff); }
|
|
397
|
+
.dim-feishuGroupControlHeader { min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 12px; }
|
|
398
|
+
.dim-feishuGroupControlHeader h3 { min-width: 0; margin: 0; color: var(--dsw-alias-label-primary, #1f2329); font-size: 14px; line-height: 21px; font-weight: 650; }
|
|
399
|
+
.dim-feishuGroupControlStatus { flex: none; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; line-height: 17px; }
|
|
400
|
+
.dim-feishuGroupSelect { min-width: 0; width: 100%; height: 38px; padding: 0 34px 0 11px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 13px; line-height: 38px; cursor: pointer; transition: border-color .15s ease, box-shadow .15s ease; }
|
|
401
|
+
.dim-feishuGroupSelect:hover:not(:disabled) { border-color: color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 42%, var(--dsw-alias-border-l2, #dfe1e5)); }
|
|
402
|
+
.dim-feishuGroupSelect:focus-visible { outline: none; border-color: var(--dsw-alias-state-business-primary, #3370ff); box-shadow: 0 0 0 2px color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 15%, transparent); }
|
|
403
|
+
.dim-feishuGroupSelect:disabled { cursor: not-allowed; opacity: .55; }
|
|
404
|
+
.dim-feishuGroupHelp { margin: -2px 0 0; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 12px; line-height: 19px; }
|
|
405
|
+
.dim-feishuGroupPermissionAction { display: flex; justify-content: flex-start; }
|
|
406
|
+
.dim-feishuGroupPermissionAction .dim-deliveryButton { color: var(--dsw-alias-state-business-primary, #3370ff); border-color: color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 30%, var(--dsw-alias-border-l2, #dfe1e5)); }
|
|
407
|
+
.dim-feishuGroupError, .dim-feishuGroupRefreshError { margin: 0; padding: 9px 11px; border-radius: 8px; font-size: 12px; line-height: 18px; }
|
|
408
|
+
.dim-feishuGroupError, .dim-feishuGroupRefreshError { color: var(--dsw-alias-state-error-primary, #d54941); background: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d54941) 7%, var(--dsw-alias-bg-layer-1, #fff)); }
|
|
409
|
+
.dim-feishuGroupAuthorization { min-width: 0; display: grid; grid-template-columns: 184px minmax(0, 1fr); align-items: start; gap: 24px; padding: 18px; border: 1px solid color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 30%, var(--dsw-alias-border-l2, #dfe1e5)); border-radius: 12px; background: color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 2.5%, var(--dsw-alias-bg-layer-3, #fff)); }
|
|
410
|
+
.dim-feishuGroupAuthorizationState { min-height: 126px; grid-template-columns: 32px minmax(0, 1fr); align-items: center; }
|
|
411
|
+
.dim-feishuGroupAuthorizationState h3, .dim-feishuGroupAuthorizationError h3, .dim-feishuGroupAuthorizationCopy h3 { margin: 0; color: var(--dsw-alias-label-primary, #1f2329); font-size: 16px; line-height: 24px; font-weight: 650; }
|
|
412
|
+
.dim-feishuGroupAuthorizationState p, .dim-feishuGroupAuthorizationError p, .dim-feishuGroupAuthorizationCopy > p { margin: 5px 0 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 19px; }
|
|
413
|
+
.dim-feishuGroupSpinner { width: 24px; height: 24px; border: 3px solid var(--dsw-alias-border-l2, #dfe1e5); border-top-color: var(--dsw-alias-state-business-primary, #3370ff); border-radius: 50%; animation: dim-spin .8s linear infinite; }
|
|
414
|
+
.dim-feishuGroupAuthorizationError { grid-template-columns: minmax(0, 1fr) max-content; align-items: center; border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d54941) 28%, var(--dsw-alias-border-l2, #dfe1e5)); background: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d54941) 4%, var(--dsw-alias-bg-layer-3, #fff)); }
|
|
415
|
+
.dim-feishuGroupAuthorizationError code { display: inline-block; margin-top: 6px; color: var(--dsw-alias-label-tertiary, #8f959e); font: 11px/17px ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
416
|
+
.dim-feishuGroupQrColumn { min-width: 0; }
|
|
417
|
+
.dim-feishuGroupQrFrame { position: relative; width: 176px; height: 176px; display: grid; place-items: center; padding: 10px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 11px; background: #fff; box-shadow: 0 6px 18px rgb(31 35 41 / 7%); }
|
|
418
|
+
.dim-feishuGroupQrFrame img { width: 100%; height: 100%; display: block; object-fit: contain; }
|
|
419
|
+
.dim-feishuGroupQrFallback { width: 100%; height: 100%; display: grid; place-content: center; justify-items: center; gap: 7px; border-radius: 7px; color: var(--dsw-alias-state-business-primary, #3370ff); background: #f7f9ff; text-align: center; }
|
|
420
|
+
.dim-feishuGroupQrFallback span { color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 17px; }
|
|
421
|
+
.dim-feishuGroupQrExpired { position: absolute; inset: 10px; display: grid; place-content: center; gap: 2px; border-radius: 8px; color: var(--dsw-alias-label-primary, #1f2329); background: rgb(255 255 255 / 94%); backdrop-filter: blur(3px); text-align: center; }
|
|
422
|
+
.dim-feishuGroupQrExpired span { font-size: 13px; line-height: 20px; font-weight: 650; }
|
|
423
|
+
.dim-feishuGroupQrExpired small { color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 17px; }
|
|
424
|
+
.dim-feishuGroupCountdown { width: 176px; display: grid; grid-template-columns: minmax(0, 1fr) max-content; gap: 5px 10px; margin-top: 9px; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; line-height: 17px; font-variant-numeric: tabular-nums; }
|
|
425
|
+
.dim-feishuGroupCountdown strong { color: var(--dsw-alias-label-secondary, #646a73); font-weight: 600; }
|
|
426
|
+
.dim-feishuGroupProgress { grid-column: 1 / -1; height: 3px; overflow: hidden; border-radius: 99px; background: var(--dsw-alias-bg-module-platform, #f2f3f5); }
|
|
427
|
+
.dim-feishuGroupProgress > span { display: block; height: 100%; border-radius: inherit; background: var(--dsw-alias-state-business-primary, #3370ff); transition: width 1s linear; }
|
|
428
|
+
.dim-feishuGroupAuthorizationCopy { min-width: 0; }
|
|
429
|
+
.dim-feishuGroupAuthorizationEyebrow { display: block; margin-bottom: 7px; color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 17px; font-weight: 600; }
|
|
430
|
+
.dim-feishuGroupAuthorizationCopy ol { display: grid; gap: 6px; margin: 13px 0 0; padding-left: 18px; color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 18px; }
|
|
431
|
+
.dim-feishuGroupAuthorizationActions { display: flex; align-items: center; justify-content: flex-start; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
|
|
432
|
+
.dim-feishuGroupAuthorizationLink { text-decoration: none; }
|
|
385
433
|
.dim-deliveryDocsLink { min-height: 30px; flex: none; display: inline-flex; align-items: center; gap: 4px; padding: 5px 8px; border-radius: 7px; color: var(--dsw-alias-state-business-primary, #3370ff); font-size: 12px; line-height: 18px; text-decoration: none; white-space: nowrap; }
|
|
386
434
|
.dim-deliveryDocsLink:hover { background: color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 8%, transparent); }
|
|
387
435
|
.dim-deliveryDocsLink:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: 2px; }
|
|
@@ -411,6 +459,12 @@ const CSS = String.raw`
|
|
|
411
459
|
.dim-targetTitle span { flex: none; padding: 1px 6px; border-radius: 5px; color: var(--dsw-alias-state-business-primary, #3370ff); background: color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 9%, transparent); font-size: 10px; line-height: 16px; }
|
|
412
460
|
.dim-targetSummary code { display: block; overflow: hidden; margin-top: 3px; color: var(--dsw-alias-label-secondary, #646a73); font: 11px/17px ui-monospace, SFMono-Regular, Menlo, monospace; text-overflow: ellipsis; white-space: nowrap; }
|
|
413
461
|
.dim-targetActions { display: flex; align-items: center; justify-content: flex-end; gap: 6px; flex-wrap: wrap; }
|
|
462
|
+
.dim-targetSessionSync { grid-column: 1 / -1; min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 12px; padding-top: 9px; border-top: 1px solid var(--dsw-alias-border-l1, #eef0f3); cursor: pointer; }
|
|
463
|
+
.dim-targetSessionSyncCopy { min-width: 0; display: grid; gap: 1px; }
|
|
464
|
+
.dim-targetSessionSyncCopy strong { color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; line-height: 18px; font-weight: 600; }
|
|
465
|
+
.dim-targetSessionSyncCopy small { color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 17px; }
|
|
466
|
+
.dim-targetSessionSync input { width: 16px; height: 16px; flex: none; margin: 0; accent-color: var(--dsw-alias-state-business-primary, #3370ff); }
|
|
467
|
+
.dim-targetSessionSync:has(input:disabled) { cursor: default; }
|
|
414
468
|
.dim-targetFeedback { grid-column: 1 / -1; margin: 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 17px; }
|
|
415
469
|
.dim-targetFeedback[data-tone="success"] { color: var(--dsw-alias-state-success-primary, #20a162); }
|
|
416
470
|
.dim-targetFeedback[data-tone="error"], .dim-targetFormError { color: var(--dsw-alias-state-error-primary, #d54941); }
|
|
@@ -468,6 +522,46 @@ const CSS = String.raw`
|
|
|
468
522
|
.dim-accessFeedback[data-tone="success"] { color: var(--dsw-alias-state-success-primary, #20a162); }
|
|
469
523
|
.dim-accessFeedback[data-tone="error"] { color: var(--dsw-alias-state-error-primary, #d54941); }
|
|
470
524
|
.dim-accessActions { display: flex; justify-content: flex-end; }
|
|
525
|
+
.dim-generalSettingsPage { min-width: 0; display: grid; }
|
|
526
|
+
.dim-generalSettingsHeader { min-width: 0; margin: 0 0 8px; }
|
|
527
|
+
.dim-generalSettingsHeader h2 { margin: 0; color: var(--dsw-alias-label-primary, #1f2329); font-size: 18px; line-height: 25px; font-weight: 680; }
|
|
528
|
+
.dim-generalSettingsTabsBar { min-width: 0; border-bottom: 1px solid var(--dsw-alias-border-l2, #dfe1e5); }
|
|
529
|
+
.dim-generalSettingsTabs { min-width: 0; display: flex; align-items: flex-end; gap: 24px; overflow-x: auto; scrollbar-width: none; }
|
|
530
|
+
.dim-generalSettingsTabs::-webkit-scrollbar { display: none; }
|
|
531
|
+
.dim-generalSettingsTab { position: relative; min-height: 38px; flex: none; display: inline-flex; align-items: center; justify-content: center; padding: 6px 2px 9px; border: 0; color: var(--dsw-alias-label-secondary, #646a73); background: transparent; font: inherit; font-size: 13px; line-height: 20px; font-weight: 560; white-space: nowrap; cursor: pointer; transition: color .15s ease; }
|
|
532
|
+
.dim-generalSettingsTab::after { content: ''; position: absolute; right: 0; bottom: -1px; left: 0; height: 2px; border-radius: 2px 2px 0 0; background: transparent; transform: scaleX(.45); transition: background .15s ease, transform .15s ease; }
|
|
533
|
+
.dim-generalSettingsTab:hover:not([aria-selected="true"]) { color: var(--dsw-alias-label-primary, #1f2329); }
|
|
534
|
+
.dim-generalSettingsTab[aria-selected="true"] { color: var(--dim-blue); font-weight: 650; }
|
|
535
|
+
.dim-generalSettingsTab[aria-selected="true"]::after { background: var(--dim-blue); transform: scaleX(1); }
|
|
536
|
+
.dim-generalSettingsTab:focus-visible { outline: 2px solid var(--dim-blue); outline-offset: -2px; border-radius: 5px; }
|
|
537
|
+
.dim-generalSettingsTabPanel { min-width: 0; padding-top: 14px; }
|
|
538
|
+
.dim-globalSection { min-width: 0; padding: 14px 16px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 12px; background: var(--dsw-alias-bg-layer-3, #fff); }
|
|
539
|
+
.dim-globalHead { min-width: 0; display: flex; align-items: center; }
|
|
540
|
+
.dim-globalHeadTitle { min-width: 0; display: inline-flex; align-items: center; gap: 6px; }
|
|
541
|
+
.dim-globalHead h3 { min-width: 0; overflow: hidden; margin: 0; color: var(--dsw-alias-label-primary, #1f2329); font-size: 15px; line-height: 22px; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
|
|
542
|
+
.dim-globalTtlHelp { position: relative; display: inline-flex; flex: none; }
|
|
543
|
+
.dim-globalTtlTooltip { position: absolute; top: calc(100% + 7px); left: 0; z-index: 30; width: max-content; max-width: min(280px, calc(100vw - 48px)); padding: 9px 10px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 10px 28px rgb(31 35 41 / 16%); opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
|
|
544
|
+
.dim-globalTtlHelp:hover .dim-globalTtlTooltip, .dim-globalTtlHelpButton:focus-visible + .dim-globalTtlTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
|
|
545
|
+
.dim-globalTtlHints { display: grid; gap: 4px; margin: 0; padding: 0; list-style: none; }
|
|
546
|
+
.dim-globalTtlHints li { min-width: 0; display: flex; align-items: baseline; gap: 8px; }
|
|
547
|
+
.dim-globalTtlHints code { flex: none; min-width: 44px; padding: 0 6px; border-radius: 5px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-module-platform, #f7f8fa); font: 10px/16px ui-monospace, SFMono-Regular, Menlo, monospace; text-align: center; }
|
|
548
|
+
.dim-globalTtlHints span { min-width: 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 16px; }
|
|
549
|
+
.dim-globalTtlRow { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 10px; margin-top: 12px; }
|
|
550
|
+
.dim-globalTtlInput { width: min(160px, 100%); min-width: 110px; max-width: 160px; flex: 1 1 130px; height: 34px; padding: 0 11px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-1, #fff); font: 13px ui-monospace, SFMono-Regular, Menlo, monospace; transition: border-color .16s ease, box-shadow .16s ease; }
|
|
551
|
+
.dim-globalTtlInput:hover:not(:disabled) { border-color: var(--dsw-alias-border-l3, #bbbfc4); }
|
|
552
|
+
.dim-globalTtlInput:focus { outline: none; border-color: var(--dim-blue); box-shadow: 0 0 0 3px color-mix(in srgb, var(--dim-blue) 14%, transparent); }
|
|
553
|
+
.dim-globalTtlInput[aria-invalid="true"] { border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d54941) 62%, var(--dsw-alias-border-l2, #dfe1e5)); }
|
|
554
|
+
.dim-globalTtlInput:disabled { cursor: not-allowed; opacity: .55; }
|
|
555
|
+
.dim-globalSaveButton { min-width: 58px; min-height: 34px; }
|
|
556
|
+
.dim-globalSweepAction { position: relative; display: inline-flex; flex: none; margin-left: auto; }
|
|
557
|
+
.dim-globalSweepButton { flex: none; }
|
|
558
|
+
.dim-globalSweepConfirm { position: absolute; top: calc(100% + 8px); right: 0; z-index: 35; width: 218px; padding: 11px 12px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 9px; background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 12px 30px rgb(31 35 41 / 18%); }
|
|
559
|
+
.dim-globalSweepConfirm p { margin: 0; color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; line-height: 18px; }
|
|
560
|
+
.dim-globalSweepConfirmActions { display: flex; justify-content: flex-end; gap: 7px; margin-top: 10px; }
|
|
561
|
+
.dim-deliveryButton.dim-globalSweepConfirmButton { border-color: var(--dsw-alias-state-error-primary, #d54941); color: #fff; background: var(--dsw-alias-state-error-primary, #d54941); }
|
|
562
|
+
.dim-deliveryButton.dim-globalSweepConfirmButton:hover:not(:disabled) { border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d54941) 82%, #000); background: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d54941) 88%, #000); }
|
|
563
|
+
.dim-globalInline { flex: 1 0 100%; min-width: 0; margin: 2px 0 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 16px; overflow-wrap: anywhere; }
|
|
564
|
+
.dim-globalInline[data-tone="error"] { color: var(--dsw-alias-state-error-primary, #d54941); }
|
|
471
565
|
.dim-panel .dim-botCard .dim-cardFooter { margin-top: 0; }
|
|
472
566
|
.dim-panel .ddt-headingCopy { display: none; }
|
|
473
567
|
.dim-panel .ddt-qrFrame, .dim-panel .ddt-countdown { width: min(270px, 100%); }
|
|
@@ -494,6 +588,10 @@ const CSS = String.raw`
|
|
|
494
588
|
.dim-accessControls { grid-template-columns: minmax(0, 1fr); }
|
|
495
589
|
.dim-accessUserRow { grid-template-columns: minmax(0, 1fr); }
|
|
496
590
|
.dim-accessDeleteUser { justify-self: start; }
|
|
591
|
+
.dim-feishuGroupAuthorization { grid-template-columns: minmax(0, 1fr); justify-items: center; }
|
|
592
|
+
.dim-feishuGroupAuthorizationCopy { width: 100%; }
|
|
593
|
+
.dim-feishuGroupAuthorizationState { grid-template-columns: 32px minmax(0, 1fr); justify-items: stretch; }
|
|
594
|
+
.dim-feishuGroupAuthorizationError { justify-items: stretch; }
|
|
497
595
|
}
|
|
498
596
|
@media (max-width: 840px) {
|
|
499
597
|
.dim-title { align-items: flex-start; }
|
|
@@ -523,6 +621,7 @@ const CSS = String.raw`
|
|
|
523
621
|
.dim-deliveryBotId > span { grid-column: 1 / -1; }
|
|
524
622
|
.dim-targetActions .dim-deliveryButton { flex: 1 1 auto; }
|
|
525
623
|
.dim-accessActions .dim-deliveryButton { width: 100%; }
|
|
624
|
+
.dim-feishuGroupAuthorizationActions .dim-deliveryButton { flex: 1 1 auto; }
|
|
526
625
|
.dim-directoryPickerBackdrop { padding: 10px; }
|
|
527
626
|
.dim-directoryPicker { height: calc(100vh - 20px); min-height: 0; border-radius: 14px; }
|
|
528
627
|
.dim-directoryPickerHeader { padding: 18px 17px 14px; }
|
|
@@ -15,11 +15,16 @@ 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';
|
|
21
22
|
import { harnessConnection } from '../../harness-connection.mjs';
|
|
22
23
|
import { createHarnessSessionExecutors } from '../../harness-session-coordinator.mjs';
|
|
24
|
+
import {
|
|
25
|
+
getInboundTtlRuntime,
|
|
26
|
+
registerInboundTtlWorkspaces,
|
|
27
|
+
} from '../../inbound-ttl-runtime.mjs';
|
|
23
28
|
import {
|
|
24
29
|
accessPolicyProvider,
|
|
25
30
|
initialAccessPolicyFor,
|
|
@@ -84,10 +89,18 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
84
89
|
return state;
|
|
85
90
|
};
|
|
86
91
|
const commandExecutor = createHarnessCommandExecutor(ctx, internals.commandExecutor);
|
|
92
|
+
const inboundTtl = internals.inboundTtl ?? getInboundTtlRuntime(ctx, config);
|
|
93
|
+
const inboundTtlService = inboundTtl?.service ?? inboundTtl;
|
|
94
|
+
registerInboundTtlWorkspaces(ctx, inboundTtlService, {
|
|
95
|
+
workspaces,
|
|
96
|
+
configStore: observedConfigStore,
|
|
97
|
+
defaultWorkspace,
|
|
98
|
+
});
|
|
87
99
|
const { controlExecutor, sessionMaintenanceExecutor, fileIngressExecutor } = createHarnessSessionExecutors(ctx, {
|
|
88
100
|
controlExecutor: internals.controlExecutor,
|
|
89
101
|
sessionMaintenanceExecutor: internals.sessionMaintenanceExecutor,
|
|
90
102
|
fileIngressExecutor: internals.fileIngressExecutor,
|
|
103
|
+
inboundTtlService,
|
|
91
104
|
});
|
|
92
105
|
const harness = new Harness({
|
|
93
106
|
...connection,
|
|
@@ -99,6 +112,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
99
112
|
...(sessionMaintenanceExecutor ? { sessionMaintenanceExecutor } : {}),
|
|
100
113
|
...(fileIngressExecutor ? { fileIngressExecutor } : {}),
|
|
101
114
|
});
|
|
115
|
+
const modelCatalog = () => listModelCatalog(harness);
|
|
102
116
|
const coreController = new Controller({
|
|
103
117
|
deviceAuth,
|
|
104
118
|
credentials: ctx.credentials,
|
|
@@ -151,6 +165,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
151
165
|
workspaces,
|
|
152
166
|
stateFor,
|
|
153
167
|
agentPresetCatalog,
|
|
168
|
+
modelCatalog,
|
|
154
169
|
});
|
|
155
170
|
const supervisor = createSupervisor({
|
|
156
171
|
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 DINGTALK_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,
|
|
@@ -94,6 +96,9 @@ function payloadFailure(endpoint, payload) {
|
|
|
94
96
|
return validWorkspacePayload(payload)
|
|
95
97
|
? null : '请输入工作区绝对路径。';
|
|
96
98
|
}
|
|
99
|
+
if (endpoint === DINGTALK_ENDPOINTS.setModel) {
|
|
100
|
+
return validModelPayload(payload) ? null : '请选择有效模型。';
|
|
101
|
+
}
|
|
97
102
|
if (endpoint === DINGTALK_ENDPOINTS.setAgentPreset) {
|
|
98
103
|
return validAgentPresetPayload(payload)
|
|
99
104
|
? null : '请选择 Agent Preset。';
|
|
@@ -284,6 +289,12 @@ export function createDingtalkRpcHandler(controller, { encodeQr = qrDataUrl } =
|
|
|
284
289
|
await controller.updateWorkspace(payload.botId, payload.workspace),
|
|
285
290
|
cachedEncode,
|
|
286
291
|
);
|
|
292
|
+
} else if (endpoint === DINGTALK_ENDPOINTS.setModel) {
|
|
293
|
+
if (typeof controller.updateModel !== 'function') throw new Error('Model update is unavailable');
|
|
294
|
+
value = await publicStatus(
|
|
295
|
+
await controller.updateModel(payload.botId, payload.model),
|
|
296
|
+
cachedEncode,
|
|
297
|
+
);
|
|
287
298
|
} else if (endpoint === DINGTALK_ENDPOINTS.setContextEnhancement) {
|
|
288
299
|
if (typeof controller.updateContextEnhancement !== 'function') throw new Error('Context enhancement update is unavailable');
|
|
289
300
|
value = await controller.updateContextEnhancement(
|
|
@@ -7,6 +7,10 @@ import { createConnectionSupervisor } from './connection-supervisor.mjs';
|
|
|
7
7
|
import { createHarnessCommandExecutor } from '../../harness-command-executor.mjs';
|
|
8
8
|
import { harnessConnection } from '../../harness-connection.mjs';
|
|
9
9
|
import { createHarnessSessionExecutors } from '../../harness-session-coordinator.mjs';
|
|
10
|
+
import {
|
|
11
|
+
getInboundTtlRuntime,
|
|
12
|
+
registerInboundTtlWorkspaces,
|
|
13
|
+
} from '../../inbound-ttl-runtime.mjs';
|
|
10
14
|
import { verifyFeishuApp } from '../../../../src/channels/feishu/feishu-app.mjs';
|
|
11
15
|
import { FeishuRuntime } from '../../../../src/channels/feishu/feishu-runtime.mjs';
|
|
12
16
|
import { HarnessClient } from '../../../../src/channels/feishu/harness-client.mjs';
|
|
@@ -23,6 +27,7 @@ import {
|
|
|
23
27
|
observeBotWorkspaceRemovals,
|
|
24
28
|
} from '../../../../src/channels/shared/bot-workspace-store.mjs';
|
|
25
29
|
import { listAgentPresetCatalog } from '../../../../src/channels/shared/agent-preset.mjs';
|
|
30
|
+
import { listModelCatalog } from '../../../../src/channels/shared/model-setting.mjs';
|
|
26
31
|
import { createDeliveryAdapter } from '../../delivery-adapter.mjs';
|
|
27
32
|
import {
|
|
28
33
|
accessPolicyProvider,
|
|
@@ -158,10 +163,19 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
158
163
|
return stateFor(botConfig);
|
|
159
164
|
};
|
|
160
165
|
const commandExecutor = createHarnessCommandExecutor(ctx, internals.commandExecutor);
|
|
166
|
+
const inboundTtl = internals.inboundTtl ?? getInboundTtlRuntime(ctx, config);
|
|
167
|
+
const inboundTtlService = inboundTtl?.service ?? inboundTtl;
|
|
168
|
+
registerInboundTtlWorkspaces(ctx, inboundTtlService, {
|
|
169
|
+
workspaces,
|
|
170
|
+
configStore: observedConfigStore,
|
|
171
|
+
defaultWorkspace,
|
|
172
|
+
botIdFrom: (bot) => bot?.id,
|
|
173
|
+
});
|
|
161
174
|
const { controlExecutor, sessionMaintenanceExecutor, fileIngressExecutor } = createHarnessSessionExecutors(ctx, {
|
|
162
175
|
controlExecutor: internals.controlExecutor,
|
|
163
176
|
sessionMaintenanceExecutor: internals.sessionMaintenanceExecutor,
|
|
164
177
|
fileIngressExecutor: internals.fileIngressExecutor,
|
|
178
|
+
inboundTtlService,
|
|
165
179
|
});
|
|
166
180
|
const harness = new Harness({
|
|
167
181
|
...connection,
|
|
@@ -178,6 +192,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
178
192
|
const proxyEnv = internals.proxyEnv ?? process.env;
|
|
179
193
|
const wsAgent = createFeishuWebSocketAgent(proxyEnv, internals.createProxyAgent);
|
|
180
194
|
|
|
195
|
+
const modelCatalog = () => listModelCatalog(harness);
|
|
181
196
|
const coreController = new Controller({
|
|
182
197
|
registerApp: (options) => lark.registerApp(options),
|
|
183
198
|
verifyApp,
|
|
@@ -202,6 +217,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
202
217
|
domain: botConfig.domain,
|
|
203
218
|
botOpenId: botConfig.botOpenId,
|
|
204
219
|
groupResponseMode: botConfig.groupResponseMode,
|
|
220
|
+
groupTopicReply: botConfig.groupTopicReply,
|
|
205
221
|
ownerOpenIds: botConfig.ownerOpenIds ?? [botConfig.ownerOpenId],
|
|
206
222
|
harness: workspaceScope.harness,
|
|
207
223
|
state: workspaceScope.state,
|
|
@@ -233,6 +249,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
233
249
|
workspaces,
|
|
234
250
|
stateFor: stateForBotId,
|
|
235
251
|
agentPresetCatalog,
|
|
252
|
+
modelCatalog,
|
|
236
253
|
});
|
|
237
254
|
|
|
238
255
|
const supervisor = createSupervisor({
|
|
@@ -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,10 +288,12 @@ 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),
|
|
289
295
|
groupResponseMode: normalizeFeishuGroupResponseMode(source.groupResponseMode),
|
|
296
|
+
groupTopicReply: source.groupTopicReply === true,
|
|
290
297
|
groupMessagePermissionGranted: source.groupMessagePermissionGranted === true,
|
|
291
298
|
bot: publicBot(source.bot),
|
|
292
299
|
health: publicHealth(source, connected),
|
|
@@ -332,6 +339,7 @@ export async function toPublicFeishuStatus(status, { encodeQr = qrCodeDataUrl }
|
|
|
332
339
|
health: publicHealth(source, connected),
|
|
333
340
|
bots,
|
|
334
341
|
agentPresetCatalog: normalizeAgentPresetCatalog(source.agentPresetCatalog),
|
|
342
|
+
modelCatalog: normalizeModelCatalog(source.modelCatalog),
|
|
335
343
|
totals: {
|
|
336
344
|
configured: bots.length || (source.configured === true ? 1 : 0),
|
|
337
345
|
connected: bots.length ? bots.filter((bot) => bot.connected).length : (connected ? 1 : 0),
|
|
@@ -421,6 +429,9 @@ function validPayload(endpoint, payload) {
|
|
|
421
429
|
return validWorkspacePayload(payload)
|
|
422
430
|
? null : '请输入工作区绝对路径。';
|
|
423
431
|
}
|
|
432
|
+
if (endpoint === FEISHU_ENDPOINTS.setModel) {
|
|
433
|
+
return validModelPayload(payload) ? null : '请选择有效模型。';
|
|
434
|
+
}
|
|
424
435
|
if (endpoint === FEISHU_ENDPOINTS.setAgentPreset) {
|
|
425
436
|
return validAgentPresetPayload(payload)
|
|
426
437
|
? null : '请选择 Agent Preset。';
|
|
@@ -440,6 +451,13 @@ function validPayload(endpoint, payload) {
|
|
|
440
451
|
? null
|
|
441
452
|
: '请选择群聊响应方式。';
|
|
442
453
|
}
|
|
454
|
+
if (endpoint === FEISHU_ENDPOINTS.setGroupTopicReply) {
|
|
455
|
+
return hasOnlyKeys(payload, new Set(['botId', 'groupTopicReply']))
|
|
456
|
+
&& safeOpaqueId(payload.botId)
|
|
457
|
+
&& typeof payload.groupTopicReply === 'boolean'
|
|
458
|
+
? null
|
|
459
|
+
: '请选择是否以话题方式回复。';
|
|
460
|
+
}
|
|
443
461
|
return 'Unknown Feishu endpoint.';
|
|
444
462
|
}
|
|
445
463
|
|
|
@@ -684,6 +702,12 @@ export function createFeishuRpcHandler(controller, { encodeQr = qrCodeDataUrl }
|
|
|
684
702
|
await controller.updateWorkspace(payload.botId, payload.workspace),
|
|
685
703
|
{ encodeQr: cachedEncodeQr },
|
|
686
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
|
+
);
|
|
687
711
|
} else if (endpoint === FEISHU_ENDPOINTS.setContextEnhancement) {
|
|
688
712
|
if (typeof controller.updateContextEnhancement !== 'function') throw new Error('Context enhancement update is unavailable');
|
|
689
713
|
value = await controller.updateContextEnhancement(
|
|
@@ -710,6 +734,14 @@ export function createFeishuRpcHandler(controller, { encodeQr = qrCodeDataUrl }
|
|
|
710
734
|
await controller.updateGroupResponseMode(payload.botId, payload.groupResponseMode),
|
|
711
735
|
{ encodeQr: cachedEncodeQr },
|
|
712
736
|
);
|
|
737
|
+
} else if (endpoint === FEISHU_ENDPOINTS.setGroupTopicReply) {
|
|
738
|
+
if (typeof controller.updateGroupTopicReply !== 'function') {
|
|
739
|
+
throw new Error('Group topic reply update is unavailable');
|
|
740
|
+
}
|
|
741
|
+
value = await toPublicFeishuStatus(
|
|
742
|
+
await controller.updateGroupTopicReply(payload.botId, payload.groupTopicReply),
|
|
743
|
+
{ encodeQr: cachedEncodeQr },
|
|
744
|
+
);
|
|
713
745
|
} else {
|
|
714
746
|
if (typeof controller.deleteBot !== 'function') throw new Error('Multi-bot delete is unavailable');
|
|
715
747
|
value = await toPublicFeishuStatus(await controller.deleteBot(payload.botId), { encodeQr: cachedEncodeQr });
|
|
@@ -15,11 +15,16 @@ 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';
|
|
21
22
|
import { harnessConnection } from '../../harness-connection.mjs';
|
|
22
23
|
import { createHarnessSessionExecutors } from '../../harness-session-coordinator.mjs';
|
|
24
|
+
import {
|
|
25
|
+
getInboundTtlRuntime,
|
|
26
|
+
registerInboundTtlWorkspaces,
|
|
27
|
+
} from '../../inbound-ttl-runtime.mjs';
|
|
23
28
|
import {
|
|
24
29
|
accessPolicyProvider,
|
|
25
30
|
initialAccessPolicyFor,
|
|
@@ -75,10 +80,18 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
75
80
|
return state;
|
|
76
81
|
};
|
|
77
82
|
const commandExecutor = createHarnessCommandExecutor(ctx, internals.commandExecutor);
|
|
83
|
+
const inboundTtl = internals.inboundTtl ?? getInboundTtlRuntime(ctx, config);
|
|
84
|
+
const inboundTtlService = inboundTtl?.service ?? inboundTtl;
|
|
85
|
+
registerInboundTtlWorkspaces(ctx, inboundTtlService, {
|
|
86
|
+
workspaces,
|
|
87
|
+
configStore: observedConfigStore,
|
|
88
|
+
defaultWorkspace,
|
|
89
|
+
});
|
|
78
90
|
const { controlExecutor, sessionMaintenanceExecutor, fileIngressExecutor } = createHarnessSessionExecutors(ctx, {
|
|
79
91
|
controlExecutor: internals.controlExecutor,
|
|
80
92
|
sessionMaintenanceExecutor: internals.sessionMaintenanceExecutor,
|
|
81
93
|
fileIngressExecutor: internals.fileIngressExecutor,
|
|
94
|
+
inboundTtlService,
|
|
82
95
|
});
|
|
83
96
|
const harness = new Harness({
|
|
84
97
|
...connection,
|
|
@@ -90,6 +103,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
90
103
|
...(sessionMaintenanceExecutor ? { sessionMaintenanceExecutor } : {}),
|
|
91
104
|
...(fileIngressExecutor ? { fileIngressExecutor } : {}),
|
|
92
105
|
});
|
|
106
|
+
const modelCatalog = () => listModelCatalog(harness);
|
|
93
107
|
const coreController = new Controller({
|
|
94
108
|
qrAuth,
|
|
95
109
|
credentials: ctx.credentials,
|
|
@@ -141,6 +155,7 @@ export async function createProductionController(ctx, config = {}, internals = {
|
|
|
141
155
|
workspaces,
|
|
142
156
|
stateFor,
|
|
143
157
|
agentPresetCatalog,
|
|
158
|
+
modelCatalog,
|
|
144
159
|
});
|
|
145
160
|
const supervisor = createSupervisor({
|
|
146
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
|
+
}
|
|
@@ -6,6 +6,10 @@ import { createTokenConnectionSupervisor } from './connection-supervisor.mjs';
|
|
|
6
6
|
import { createHarnessCommandExecutor } from '../../harness-command-executor.mjs';
|
|
7
7
|
import { harnessConnection } from '../../harness-connection.mjs';
|
|
8
8
|
import { createHarnessSessionExecutors } from '../../harness-session-coordinator.mjs';
|
|
9
|
+
import {
|
|
10
|
+
getInboundTtlRuntime,
|
|
11
|
+
registerInboundTtlWorkspaces,
|
|
12
|
+
} from '../../inbound-ttl-runtime.mjs';
|
|
9
13
|
import {
|
|
10
14
|
BotWorkspaceStore,
|
|
11
15
|
createBotWorkspaceScope,
|
|
@@ -13,6 +17,7 @@ import {
|
|
|
13
17
|
observeBotWorkspaceRemovals,
|
|
14
18
|
} from '../../../../src/channels/shared/bot-workspace-store.mjs';
|
|
15
19
|
import { listAgentPresetCatalog } from '../../../../src/channels/shared/agent-preset.mjs';
|
|
20
|
+
import { listModelCatalog } from '../../../../src/channels/shared/model-setting.mjs';
|
|
16
21
|
import {
|
|
17
22
|
createDeliveryAdapter,
|
|
18
23
|
supportsDeliveryChannel,
|
|
@@ -84,10 +89,18 @@ export async function createTokenProductionController(ctx, config, internals, de
|
|
|
84
89
|
return state;
|
|
85
90
|
};
|
|
86
91
|
const commandExecutor = createHarnessCommandExecutor(ctx, internals.commandExecutor);
|
|
92
|
+
const inboundTtl = internals.inboundTtl ?? getInboundTtlRuntime(ctx, config);
|
|
93
|
+
const inboundTtlService = inboundTtl?.service ?? inboundTtl;
|
|
94
|
+
registerInboundTtlWorkspaces(ctx, inboundTtlService, {
|
|
95
|
+
workspaces,
|
|
96
|
+
configStore: observedConfigStore,
|
|
97
|
+
defaultWorkspace,
|
|
98
|
+
});
|
|
87
99
|
const { controlExecutor, sessionMaintenanceExecutor, fileIngressExecutor } = createHarnessSessionExecutors(ctx, {
|
|
88
100
|
controlExecutor: internals.controlExecutor,
|
|
89
101
|
sessionMaintenanceExecutor: internals.sessionMaintenanceExecutor,
|
|
90
102
|
fileIngressExecutor: internals.fileIngressExecutor,
|
|
103
|
+
inboundTtlService,
|
|
91
104
|
});
|
|
92
105
|
const harness = new ResolvedHarness({
|
|
93
106
|
...connection,
|
|
@@ -99,6 +112,7 @@ export async function createTokenProductionController(ctx, config, internals, de
|
|
|
99
112
|
...(sessionMaintenanceExecutor ? { sessionMaintenanceExecutor } : {}),
|
|
100
113
|
...(fileIngressExecutor ? { fileIngressExecutor } : {}),
|
|
101
114
|
});
|
|
115
|
+
const modelCatalog = () => listModelCatalog(harness);
|
|
102
116
|
const coreController = new ResolvedController({
|
|
103
117
|
credentials: ctx.credentials,
|
|
104
118
|
configStore: observedConfigStore,
|
|
@@ -149,6 +163,7 @@ export async function createTokenProductionController(ctx, config, internals, de
|
|
|
149
163
|
workspaces,
|
|
150
164
|
stateFor,
|
|
151
165
|
agentPresetCatalog,
|
|
166
|
+
modelCatalog,
|
|
152
167
|
});
|
|
153
168
|
const supervisor = createSupervisor({
|
|
154
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 };
|