diff --git a/package.json b/package.json index cec0cdd..4cb5391 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hermes-web-ui", - "version": "0.3.1", + "version": "0.3.2", "description": "Web dashboard for Hermes Agent — multi-platform AI chat, session management, scheduled jobs, usage analytics & channel configuration (Telegram, Discord, Slack, WhatsApp)", "repository": { "type": "git", @@ -8,6 +8,9 @@ }, "homepage": "https://github.com/EKKOLearnAI/hermes-web-ui", "license": "MIT", + "engines": { + "node": ">=20.0.0" + }, "keywords": [ "hermes", "ai-agent", diff --git a/packages/client/src/api/hermes/jobs.ts b/packages/client/src/api/hermes/jobs.ts index 6aafc07..5873bb4 100644 --- a/packages/client/src/api/hermes/jobs.ts +++ b/packages/client/src/api/hermes/jobs.ts @@ -45,7 +45,7 @@ export interface CreateJobRequest { export interface UpdateJobRequest { name?: string - schedule?: string + schedule?: string | { kind: string; expr: string; display: string } prompt?: string deliver?: string skills?: string[] diff --git a/packages/client/src/components/hermes/jobs/JobFormModal.vue b/packages/client/src/components/hermes/jobs/JobFormModal.vue index 52040ed..0f57b5e 100644 --- a/packages/client/src/components/hermes/jobs/JobFormModal.vue +++ b/packages/client/src/components/hermes/jobs/JobFormModal.vue @@ -48,6 +48,8 @@ const targetOptions = computed(() => [ { label: t('jobs.local'), value: 'local' }, ]) +const originalSchedule = ref<{ kind: string; expr: string; display: string } | null>(null) + onMounted(async () => { if (props.jobId) { try { @@ -60,6 +62,9 @@ onMounted(async () => { deliver: job.deliver || 'origin', repeat_times: typeof job.repeat === 'number' ? job.repeat : (typeof job.repeat === 'object' ? job.repeat.times : null), } + if (typeof job.schedule === 'object' && job.schedule) { + originalSchedule.value = job.schedule + } } catch (e: any) { message.error(t('jobs.loadFailed') + ': ' + e.message) } @@ -86,6 +91,14 @@ async function handleSave() { repeat: formData.value.repeat_times ?? undefined, } + if (isEdit.value && originalSchedule.value) { + (payload as any).schedule = { + kind: originalSchedule.value.kind, + expr: formData.value.schedule, + display: formData.value.schedule, + } + } + if (isEdit.value) { await jobsStore.updateJob(props.jobId!, payload) message.success(t('jobs.jobUpdated')) diff --git a/packages/client/src/components/hermes/settings/PlatformSettings.vue b/packages/client/src/components/hermes/settings/PlatformSettings.vue index 7bc4996..b1761cc 100644 --- a/packages/client/src/components/hermes/settings/PlatformSettings.vue +++ b/packages/client/src/components/hermes/settings/PlatformSettings.vue @@ -22,25 +22,6 @@ function isSaving(platform: string, field: string) { return !!saving[savingKey(platform, field)] } -// Debounce timers -const debounceTimers: Record> = {} - -function debounceSave(platform: string, field: string, saveFn: () => Promise, delay = 600) { - const key = savingKey(platform, field) - if (debounceTimers[key]) clearTimeout(debounceTimers[key]) - debounceTimers[key] = setTimeout(async () => { - saving[key] = true - try { - await saveFn() - message.success(t('settings.saved')) - } catch (err: any) { - message.error(t('settings.saveFailed')) - } finally { - saving[key] = false - } - }, delay) -} - // Immediate save for switches async function immediateSave(platform: string, field: string, saveFn: () => Promise) { const key = savingKey(platform, field) @@ -59,10 +40,6 @@ async function saveChannel(platform: string, field: string, values: Record settingsStore.saveSection(platform, values)) } -function debouncedSaveChannel(platform: string, field: string, values: Record) { - debounceSave(platform, field, () => settingsStore.saveSection(platform, values)) -} - // Save credentials to .env (matching hermes gateway setup behavior) async function saveCredentials(platform: string, field: string, values: Record) { immediateSave(platform, field, async () => { @@ -71,13 +48,6 @@ async function saveCredentials(platform: string, field: string, values: Record) { - debounceSave(platform, field, async () => { - await saveCredsApi(platform, values) - await settingsStore.fetchSettings() - }) -} - function getCreds(key: string) { return (settingsStore.platforms[key] || {}) as Record } @@ -121,7 +91,6 @@ function pollWeixinStatus() { wxQrStatus.value = 'expired' } else if (data.status === 'confirmed') { wxQrStatus.value = 'confirmed' - // Save credentials to .env await saveWeixinCredentials({ account_id: data.account_id!, token: data.token!, @@ -131,7 +100,6 @@ function pollWeixinStatus() { message.success(t('settings.saved')) } } catch { - // Retry poll on network error pollWeixinStatus() } }, 3000) @@ -146,7 +114,6 @@ function stopWeixinPoll() { onUnmounted(() => { stopWeixinPoll() - Object.values(debounceTimers).forEach(t => clearTimeout(t)) }) const platforms = [ @@ -180,11 +147,6 @@ const platforms = [ name: 'Feishu', icon: '', }, - // { - // key: 'dingtalk', - // name: 'DingTalk', - // icon: '', - // }, { key: 'weixin', name: 'Weixin', @@ -211,7 +173,7 @@ const platforms = [ @@ -280,20 +242,20 @@ const platforms = [ - + - + @@ -361,20 +323,20 @@ const platforms = [ - + - + diff --git a/packages/client/src/shared/providers.ts b/packages/client/src/shared/providers.ts index cce6eb1..f8a757c 100644 --- a/packages/client/src/shared/providers.ts +++ b/packages/client/src/shared/providers.ts @@ -86,13 +86,13 @@ export const PROVIDER_PRESETS: ProviderPreset[] = [ label: 'MiniMax', value: 'minimax', base_url: 'https://api.minimax.io/anthropic/v1', - models: ['MiniMax-M2.7', 'MiniMax-M2.5', 'MiniMax-M2.1', 'MiniMax-M2'], + models: ['MiniMax-M2.7', 'MiniMax-M2.7-highspeed', 'MiniMax-M2.5', 'MiniMax-M2.5-highspeed', 'MiniMax-M2.1', 'MiniMax-M2.1-highspeed', 'MiniMax-M2', 'MiniMax-M2-highspeed'], }, { label: 'MiniMax (China)', value: 'minimax-cn', base_url: 'https://api.minimaxi.com/v1', - models: ['MiniMax-M2.7', 'MiniMax-M2.5', 'MiniMax-M2.1', 'MiniMax-M2'], + models: ['MiniMax-M2.7', 'MiniMax-M2.7-highspeed', 'MiniMax-M2.5', 'MiniMax-M2.5-highspeed', 'MiniMax-M2.1', 'MiniMax-M2.1-highspeed', 'MiniMax-M2', 'MiniMax-M2-highspeed'], }, { label: 'Alibaba Cloud', diff --git a/packages/client/src/views/hermes/SettingsView.vue b/packages/client/src/views/hermes/SettingsView.vue index fad91ef..4ee4236 100644 --- a/packages/client/src/views/hermes/SettingsView.vue +++ b/packages/client/src/views/hermes/SettingsView.vue @@ -1,29 +1,36 @@ @@ -31,11 +38,15 @@ async function saveApiServer(values: Record) {