优化页面交互并增强 Provider 配置能力
- 表单下拉框不再用 label 包裹,改为 div + aria-label,避免点击后 下拉面板瞬间关闭 - Provider 卡片新增「从上游获取模型」和「修改」入口,支持编辑 base URL、API Key 与 api_mode,凭据写入对应的环境变量 - 服务端抽出 provider-model-discovery 统一不同 api_mode 的模型发现, 旧的 custom_providers 与新的 providers 字典结构都能正确更新 - Agent Bridge 改为后台启动,HTTP 接口在 Python 运行时就绪前即可用; worker 连接被拒时按类型重试,不重放可能已产生副作用的请求 - 断线重连后恢复 profiles、models 与会话列表,健康检查改为自调度 的 setTimeout,离线时 2 秒后重试 - 批量删除确认文案改用 Popconfirm content,避免变成侧栏触发器文本
This commit is contained in:
@@ -6,6 +6,8 @@ import type { AvailableModelGroup } from '@/api/hermes/system'
|
||||
import { useModelsStore } from '@/stores/hermes/models'
|
||||
import { useAppStore } from '@/stores/hermes/app'
|
||||
import { useChatStore } from '@/stores/hermes/chat'
|
||||
import ProviderEditModal from './ProviderEditModal.vue'
|
||||
import { fetchProviderModels } from '@/api/hermes/system'
|
||||
import { checkCopilotToken, disableCopilot } from '@/api/hermes/copilot-auth'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
@@ -24,6 +26,32 @@ const isConfigBackedProvider = computed(() => isCustomProviderKey.value || (!pro
|
||||
const isCopilot = computed(() => props.provider.provider === 'copilot')
|
||||
const displayName = computed(() => props.provider.label)
|
||||
const deleting = ref(false)
|
||||
const showEditModal = ref(false)
|
||||
const fetchingUpstream = ref(false)
|
||||
const canEditProvider = computed(() => isConfigBackedProvider.value || props.provider.credentials_editable || !!props.provider.base_url_env)
|
||||
|
||||
async function handleFetchUpstream() {
|
||||
if (fetchingUpstream.value) return
|
||||
fetchingUpstream.value = true
|
||||
try {
|
||||
const result = await fetchProviderModels({
|
||||
provider: props.provider.provider,
|
||||
label: props.provider.label,
|
||||
base_url: props.provider.base_url,
|
||||
api_key: props.provider.api_key,
|
||||
update_cache: true,
|
||||
api_mode: props.provider.api_mode,
|
||||
freeOnly: props.provider.provider === 'openrouter',
|
||||
})
|
||||
await modelsStore.fetchProviders()
|
||||
await appStore.reloadModels()
|
||||
message.success(t('models.upstreamModelsFetched', { count: result.models.length }))
|
||||
} catch (e: any) {
|
||||
message.error(e?.message || t('models.upstreamModelsFailed'))
|
||||
} finally {
|
||||
fetchingUpstream.value = false
|
||||
}
|
||||
}
|
||||
const destructiveActionLabel = computed(() => {
|
||||
if (isConfigBackedProvider.value) return t('common.delete')
|
||||
if (isCopilot.value) return t('models.disableProvider')
|
||||
@@ -302,11 +330,15 @@ async function handleDelete() {
|
||||
</div>
|
||||
|
||||
<div class="cy-panel-b card-actions">
|
||||
<a-button size="mini" type="text" :loading="fetchingUpstream" :disabled="!provider.base_url || showEditModal" @click="handleFetchUpstream">{{ t('models.fetchUpstreamModels') }}</a-button>
|
||||
<a-button v-if="canEditProvider" size="mini" type="text" :disabled="fetchingUpstream || deleting" @click="showEditModal = true">{{ t('common.edit') }}</a-button>
|
||||
<a-button size="mini" type="text" @click="showAliasListModal = true">{{ t('models.aliasManage') }}</a-button>
|
||||
<a-button size="mini" type="text" @click="openVisibilityModal">{{ t('models.manageVisibleModels') }}</a-button>
|
||||
<a-button size="mini" type="text" status="danger" :loading="deleting" @click="handleDelete">{{ destructiveActionLabel }}</a-button>
|
||||
</div>
|
||||
|
||||
<ProviderEditModal v-if="showEditModal" :provider="provider" @close="showEditModal = false" />
|
||||
|
||||
<a-modal
|
||||
v-model:visible="showAliasListModal"
|
||||
:footer="false"
|
||||
|
||||
Reference in New Issue
Block a user