mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-12 05:40:45 +08:00
feat: 按机器人选择 Agent Preset
在九个渠道的设置页卡片上选择 Host 已有预设;未选则跟随默认,只影响之后新建的会话。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
c3b3a29f27
commit
3161816cc4
51 changed files with 2227 additions and 740 deletions
|
|
@ -1,3 +1,5 @@
|
|||
import { normalizeAgentPresetCatalog, normalizeAgentPresetId, SET_AGENT_PRESET_ENDPOINT } from '../../agent-preset.js';
|
||||
|
||||
export const WECOM_RPC_CHANNEL = '/wecom';
|
||||
|
||||
export const WECOM_ENDPOINTS = Object.freeze({
|
||||
|
|
@ -9,6 +11,7 @@ export const WECOM_ENDPOINTS = Object.freeze({
|
|||
reconnectBot: 'bot.reconnect',
|
||||
deleteBot: 'bot.delete',
|
||||
setWorkspace: 'bot.workspace.set',
|
||||
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
||||
});
|
||||
|
||||
const PROVISION_STATES = new Set(['starting', 'pending', 'refreshing', 'connecting', 'connected', 'failed', 'cancelled']);
|
||||
|
|
@ -91,6 +94,7 @@ function normalizeBot(value) {
|
|||
connected,
|
||||
state: connected ? 'connected' : state,
|
||||
workspace: text(value.workspace, '', 4_096),
|
||||
agentPreset: normalizeAgentPresetId(value.agentPreset),
|
||||
bot: {
|
||||
name: text(value.bot?.name, '企业微信机器人', 100),
|
||||
appIdMasked: text(value.bot?.appIdMasked, '应用标识已安全保存', 140),
|
||||
|
|
@ -116,6 +120,7 @@ export function normalizeSnapshot(value) {
|
|||
totals: { configured: bots.length, connected: bots.filter((bot) => bot.connected).length },
|
||||
provisioning: source.provisioning ? normalizeProvisioning(source.provisioning) : null,
|
||||
testMessage: normalizeTestMessage(source.testMessage),
|
||||
agentPresetCatalog: normalizeAgentPresetCatalog(source.agentPresetCatalog),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@ import { WecomLogoGlyph } from '../../channel-logos.js';
|
|||
import { CredentialActionIcon, CredentialBindingPanel, QrActionIcon } from '../../credential-binding.js';
|
||||
import { h } from '../../i18n.js';
|
||||
import { WorkspaceEditor } from '../../workspace-editor.js';
|
||||
import {
|
||||
AgentPresetCatalogContext,
|
||||
AgentPresetEditor,
|
||||
EMPTY_AGENT_PRESET_CATALOG,
|
||||
} from '../../agent-preset.js';
|
||||
import { useWorkspaceSnapshotFence } from '../../workspace-snapshot-fence.js';
|
||||
import { installDingtalkStyles } from '../dingtalk/styles.js';
|
||||
import {
|
||||
|
|
@ -155,6 +160,7 @@ export function AccountCard({
|
|||
removing,
|
||||
onReconnect,
|
||||
onWorkspaceSave,
|
||||
onAgentPresetSave,
|
||||
onRequestRemove,
|
||||
onConfirmRemove,
|
||||
onCancelRemove,
|
||||
|
|
@ -179,6 +185,11 @@ export function AccountCard({
|
|||
disabled: Boolean(busy),
|
||||
onSave: onWorkspaceSave,
|
||||
}),
|
||||
h(AgentPresetEditor, {
|
||||
agentPreset: account.agentPreset,
|
||||
disabled: Boolean(busy),
|
||||
onSave: onAgentPresetSave,
|
||||
}),
|
||||
h('div', { className: 'ddt-accountFooter dim-cardFooter' },
|
||||
summary ? h('div', { className: 'ddt-summary dim-cardSummary' }, summary) : null,
|
||||
feedback ? h('div', {
|
||||
|
|
@ -195,7 +206,10 @@ export function AccountCard({
|
|||
}
|
||||
|
||||
export function WecomSettingsTab({ rpcCall }) {
|
||||
const [model, setModel] = React.useState({ phase: 'loading', bots: [], totals: { configured: 0, connected: 0 }, error: null });
|
||||
const [model, setModel] = React.useState({
|
||||
phase: 'loading', bots: [], totals: { configured: 0, connected: 0 }, error: null,
|
||||
agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
|
||||
});
|
||||
const [provision, setProvision] = React.useState(null);
|
||||
const [busy, setBusy] = React.useState(false);
|
||||
const [busyByBot, setBusyByBot] = React.useState({});
|
||||
|
|
@ -253,7 +267,10 @@ export function WecomSettingsTab({ rpcCall }) {
|
|||
const snapshot = normalizeSnapshot(await invoke(WECOM_ENDPOINTS.status, {}, signal));
|
||||
if (!mounted.current || signal?.aborted
|
||||
|| !workspaceFence.canCommitStatus(workspaceVersion)) return undefined;
|
||||
setModel({ phase: 'ready', bots: snapshot.bots, totals: snapshot.totals, error: null });
|
||||
setModel({
|
||||
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals, error: null,
|
||||
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
||||
});
|
||||
if (restore && snapshot.provisioning) setProvision({
|
||||
...snapshot.provisioning,
|
||||
durationMs: Math.max(1, snapshot.provisioning.expiresAt - Date.now()),
|
||||
|
|
@ -317,7 +334,10 @@ export function WecomSettingsTab({ rpcCall }) {
|
|||
));
|
||||
if (!mounted.current) return;
|
||||
if (workspaceFence.canCommitMutation(snapshotVersion)) {
|
||||
setModel({ phase: 'ready', bots: snapshot.bots, totals: snapshot.totals, error: null });
|
||||
setModel({
|
||||
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals, error: null,
|
||||
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
||||
});
|
||||
}
|
||||
setCredentialOpen(false);
|
||||
} catch (error) {
|
||||
|
|
@ -377,7 +397,10 @@ export function WecomSettingsTab({ rpcCall }) {
|
|||
try {
|
||||
const snapshot = normalizeSnapshot(await invoke(endpoint, payload));
|
||||
if (mounted.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
||||
setModel({ phase: 'ready', bots: snapshot.bots, totals: snapshot.totals, error: null });
|
||||
setModel({
|
||||
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals, error: null,
|
||||
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
||||
});
|
||||
}
|
||||
return snapshot;
|
||||
} finally {
|
||||
|
|
@ -455,6 +478,12 @@ export function WecomSettingsTab({ rpcCall }) {
|
|||
WECOM_ENDPOINTS.setWorkspace,
|
||||
{ botId: account.botId, workspace },
|
||||
),
|
||||
onAgentPresetSave: (agentPreset) => botAction(
|
||||
account,
|
||||
'preset',
|
||||
WECOM_ENDPOINTS.setAgentPreset,
|
||||
{ botId: account.botId, agentPreset },
|
||||
),
|
||||
onRequestRemove: () => setRemoveTarget(account.botId),
|
||||
onCancelRemove: () => setRemoveTarget(null),
|
||||
onConfirmRemove: async () => {
|
||||
|
|
@ -478,7 +507,9 @@ export function WecomSettingsTab({ rpcCall }) {
|
|||
})
|
||||
: null;
|
||||
|
||||
return h('section', { className: 'ddt-page dwecom-page dim-channelPage', 'aria-label': '企业微信设置' },
|
||||
return h(AgentPresetCatalogContext.Provider, {
|
||||
value: model.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
||||
}, h('section', { className: 'ddt-page dwecom-page dim-channelPage', 'aria-label': '企业微信设置' },
|
||||
h(Heading, {
|
||||
totals: model.totals,
|
||||
adding: Boolean(provision),
|
||||
|
|
@ -497,7 +528,7 @@ export function WecomSettingsTab({ rpcCall }) {
|
|||
provisionView,
|
||||
model.bots.length === 0 && !provision && !credentialOpen
|
||||
? h(EmptyView, { busy, onStart: () => void startProvisioning() }) : null,
|
||||
botList));
|
||||
botList)));
|
||||
}
|
||||
|
||||
export function apply(ctx) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue