mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-09 03:03:24 +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 WEIXIN_RPC_CHANNEL = '/weixin';
|
||||
export const WEIXIN_ENDPOINTS = Object.freeze({
|
||||
status: 'connection.status',
|
||||
|
|
@ -8,6 +10,7 @@ export const WEIXIN_ENDPOINTS = Object.freeze({
|
|||
reconnectBot: 'bot.reconnect',
|
||||
deleteBot: 'bot.delete',
|
||||
setWorkspace: 'bot.workspace.set',
|
||||
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
||||
});
|
||||
|
||||
const ACCOUNT_STATES = new Set(['connected', 'connecting', 'offline', 'error']);
|
||||
|
|
@ -115,6 +118,7 @@ function normalizeBot(value) {
|
|||
connected,
|
||||
configured: value.configured === true,
|
||||
workspace: string(value.workspace).slice(0, 4_096),
|
||||
agentPreset: normalizeAgentPresetId(value.agentPreset),
|
||||
bot: {
|
||||
name: string(value.bot.name, '微信机器人'),
|
||||
accountIdMasked: string(value.bot.accountIdMasked, '已安全保存'),
|
||||
|
|
@ -153,6 +157,7 @@ export function normalizeSnapshot(value) {
|
|||
},
|
||||
provisioning: value.provisioning ? normalizeProvisioning(value.provisioning) : null,
|
||||
testMessage: normalizeTestMessage(value.testMessage),
|
||||
agentPresetCatalog: normalizeAgentPresetCatalog(value.agentPresetCatalog),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,11 @@ import {
|
|||
} from './api.js';
|
||||
import { createPollScheduler, useAnimationFrameScheduler } from '../../lifecycle.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 { installWeixinStyles } from './styles.js';
|
||||
|
||||
|
|
@ -202,6 +207,7 @@ export function AccountCard({
|
|||
removing,
|
||||
onReconnect,
|
||||
onWorkspaceSave,
|
||||
onAgentPresetSave,
|
||||
onRequestRemove,
|
||||
onConfirmRemove,
|
||||
onCancelRemove,
|
||||
|
|
@ -228,6 +234,11 @@ export function AccountCard({
|
|||
disabled: Boolean(busy),
|
||||
onSave: onWorkspaceSave,
|
||||
}),
|
||||
h(AgentPresetEditor, {
|
||||
agentPreset: account.agentPreset,
|
||||
disabled: Boolean(busy),
|
||||
onSave: onAgentPresetSave,
|
||||
}),
|
||||
h('div', { className: 'dxw-accountFooter dim-cardFooter' },
|
||||
summary ? h('div', { className: 'dxw-summary dim-cardSummary' }, summary) : null,
|
||||
feedback ? h('div', {
|
||||
|
|
@ -260,6 +271,7 @@ function AccountList(props) {
|
|||
removing: props.removeTarget === account.botId,
|
||||
onReconnect: () => props.onReconnect(account),
|
||||
onWorkspaceSave: (workspace) => props.onWorkspaceSave(account, workspace),
|
||||
onAgentPresetSave: (agentPreset) => props.onAgentPresetSave(account, agentPreset),
|
||||
onRequestRemove: () => props.onRequestRemove(account),
|
||||
onConfirmRemove: () => props.onConfirmRemove(account),
|
||||
onCancelRemove: props.onCancelRemove,
|
||||
|
|
@ -285,6 +297,7 @@ export function mergeWeixinProvisioningSnapshot(
|
|||
export function WeixinSettingsTab({ rpcCall }) {
|
||||
const [model, setModel] = React.useState({
|
||||
phase: 'loading', bots: [], totals: EMPTY_TOTALS, revision: 0, error: null,
|
||||
agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
|
||||
});
|
||||
const [provision, setProvision] = React.useState(null);
|
||||
const [busy, setBusy] = React.useState(false);
|
||||
|
|
@ -327,6 +340,7 @@ export function WeixinSettingsTab({ rpcCall }) {
|
|||
setModel({
|
||||
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals,
|
||||
revision: snapshot.revision, error: null,
|
||||
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
||||
});
|
||||
if (snapshot.provisioning) {
|
||||
setProvision((current) => mergeWeixinProvisioningSnapshot(
|
||||
|
|
@ -515,7 +529,10 @@ export function WeixinSettingsTab({ rpcCall }) {
|
|||
{ botId: account.botId, sendTest: true },
|
||||
));
|
||||
if (mountedRef.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
||||
setModel((current) => ({ ...current, bots: snapshot.bots, totals: snapshot.totals, revision: snapshot.revision }));
|
||||
setModel((current) => ({
|
||||
...current, bots: snapshot.bots, totals: snapshot.totals, revision: snapshot.revision,
|
||||
agentPresetCatalog: snapshot.agentPresetCatalog ?? current.agentPresetCatalog,
|
||||
}));
|
||||
}
|
||||
const refreshed = snapshot.bots.find((bot) => bot.botId === account.botId);
|
||||
let feedback;
|
||||
|
|
@ -559,6 +576,29 @@ export function WeixinSettingsTab({ rpcCall }) {
|
|||
setModel({
|
||||
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals,
|
||||
revision: snapshot.revision, error: null,
|
||||
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
const shouldRefresh = workspaceFence.endMutation();
|
||||
if (shouldRefresh && mountedRef.current) void loadStatus({ silent: true });
|
||||
if (mountedRef.current) setBotBusy(account.botId, null);
|
||||
}
|
||||
}, [invoke, loadStatus, setBotBusy, workspaceFence]);
|
||||
|
||||
const saveAgentPreset = React.useCallback(async (account, agentPreset) => {
|
||||
const snapshotVersion = workspaceFence.beginMutation();
|
||||
setBotBusy(account.botId, 'preset');
|
||||
try {
|
||||
const snapshot = normalizeSnapshot(await invoke(
|
||||
WEIXIN_ENDPOINTS.setAgentPreset,
|
||||
{ botId: account.botId, agentPreset },
|
||||
));
|
||||
if (mountedRef.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
||||
setModel({
|
||||
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals,
|
||||
revision: snapshot.revision, error: null,
|
||||
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
|
|
@ -577,7 +617,10 @@ export function WeixinSettingsTab({ rpcCall }) {
|
|||
confirm: true,
|
||||
}));
|
||||
if (mountedRef.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
||||
setModel((current) => ({ ...current, bots: snapshot.bots, totals: snapshot.totals, revision: snapshot.revision }));
|
||||
setModel((current) => ({
|
||||
...current, bots: snapshot.bots, totals: snapshot.totals, revision: snapshot.revision,
|
||||
agentPresetCatalog: snapshot.agentPresetCatalog ?? current.agentPresetCatalog,
|
||||
}));
|
||||
}
|
||||
setRemoveTarget(null);
|
||||
announce('微信账号及本机凭据已移除。');
|
||||
|
|
@ -617,7 +660,9 @@ export function WeixinSettingsTab({ rpcCall }) {
|
|||
});
|
||||
}
|
||||
|
||||
return h('section', { className: 'dxw-page dim-channelPage', 'aria-label': '微信设置' },
|
||||
return h(AgentPresetCatalogContext.Provider, {
|
||||
value: model.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
||||
}, h('section', { className: 'dxw-page dim-channelPage', 'aria-label': '微信设置' },
|
||||
h(Heading, {
|
||||
totals: model.totals,
|
||||
adding: Boolean(provision),
|
||||
|
|
@ -650,12 +695,13 @@ export function WeixinSettingsTab({ rpcCall }) {
|
|||
removeTarget,
|
||||
onReconnect: (account) => void reconnect(account),
|
||||
onWorkspaceSave: saveWorkspace,
|
||||
onAgentPresetSave: saveAgentPreset,
|
||||
onRequestRemove: (account) => setRemoveTarget(account.botId),
|
||||
onConfirmRemove: (account) => void remove(account),
|
||||
onCancelRemove: () => setRemoveTarget(null),
|
||||
})
|
||||
: null),
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
export function apply(ctx) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue