mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-09-22 16:00:51 +00:00
fix: Fixed issue with openclaw config telegram failed (#13114)
This commit is contained in:
@@ -811,9 +811,7 @@ func extractTelegramConfig(conf map[string]interface{}) dto.AgentTelegramConfig
|
||||
result.RequireMention = result.GroupPolicy == "allowlist"
|
||||
result.GroupAllowFrom = extractStringList(telegram["groupAllowFrom"])
|
||||
result.Proxy = extractStringValue(telegram["proxy"])
|
||||
if streaming := extractStringValue(telegram["streaming"]); streaming != "" {
|
||||
result.Streaming = streaming
|
||||
}
|
||||
result.Streaming = normalizeTelegramStreamingMode(telegram["streaming"], result.Streaming)
|
||||
accounts := childMap(telegram, "accounts")
|
||||
if len(accounts) == 0 {
|
||||
botToken := extractStringValue(telegram["botToken"])
|
||||
@@ -839,7 +837,7 @@ func extractTelegramConfig(conf map[string]interface{}) dto.AgentTelegramConfig
|
||||
BotToken: extractStringValue(account["botToken"]),
|
||||
DmPolicy: extractStringValue(account["dmPolicy"]),
|
||||
GroupPolicy: extractStringValue(account["groupPolicy"]),
|
||||
Streaming: extractStringValue(account["streaming"]),
|
||||
Streaming: normalizeTelegramStreamingMode(account["streaming"], result.Streaming),
|
||||
})
|
||||
}
|
||||
result.DefaultAccount = normalizeDefaultAccount(extractStringValue(telegram["defaultAccount"]), getTelegramBotAccountIDs(bots))
|
||||
@@ -879,7 +877,7 @@ func setTelegramConfig(conf map[string]interface{}, config dto.AgentTelegramConf
|
||||
} else {
|
||||
delete(telegram, "proxy")
|
||||
}
|
||||
telegram["streaming"] = config.Streaming
|
||||
telegram["streaming"] = buildTelegramStreamingConfig(config.Streaming)
|
||||
accounts := make(map[string]interface{}, len(config.Bots))
|
||||
for _, bot := range config.Bots {
|
||||
account := map[string]interface{}{
|
||||
@@ -888,7 +886,7 @@ func setTelegramConfig(conf map[string]interface{}, config dto.AgentTelegramConf
|
||||
"botToken": bot.BotToken,
|
||||
"dmPolicy": bot.DmPolicy,
|
||||
"groupPolicy": bot.GroupPolicy,
|
||||
"streaming": bot.Streaming,
|
||||
"streaming": buildTelegramStreamingConfig(bot.Streaming),
|
||||
}
|
||||
if bot.DmPolicy == "open" {
|
||||
account["allowFrom"] = []string{"*"}
|
||||
@@ -899,6 +897,29 @@ func setTelegramConfig(conf map[string]interface{}, config dto.AgentTelegramConf
|
||||
delete(telegram, "botToken")
|
||||
}
|
||||
|
||||
func normalizeTelegramStreamingMode(value interface{}, defaultMode string) string {
|
||||
mode := defaultMode
|
||||
switch typed := value.(type) {
|
||||
case string:
|
||||
mode = typed
|
||||
case map[string]interface{}:
|
||||
mode = extractStringValue(typed["mode"])
|
||||
}
|
||||
mode = strings.ToLower(strings.TrimSpace(mode))
|
||||
switch mode {
|
||||
case "off", "partial", "block", "progress":
|
||||
return mode
|
||||
default:
|
||||
return "partial"
|
||||
}
|
||||
}
|
||||
|
||||
func buildTelegramStreamingConfig(mode string) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"mode": normalizeTelegramStreamingMode(mode, "partial"),
|
||||
}
|
||||
}
|
||||
|
||||
func extractDiscordConfig(conf map[string]interface{}) dto.AgentDiscordConfig {
|
||||
result := dto.AgentDiscordConfig{Enabled: true, DmPolicy: "pairing", AllowFrom: []string{}, RequireMention: false, GroupPolicy: "open"}
|
||||
discord := getChannelConfig(conf, "discord")
|
||||
|
||||
@@ -12,6 +12,7 @@ const (
|
||||
vllmImageEnvKey = "IMAGE"
|
||||
vllmImageTypeNvidia = "nvidia"
|
||||
vllmImageTypeIntel = "intel"
|
||||
vllmImageTypeAscend = "ascend"
|
||||
)
|
||||
|
||||
func resolveVllmVersionFamily(version, image string) string {
|
||||
@@ -19,6 +20,9 @@ func resolveVllmVersionFamily(version, image string) string {
|
||||
if strings.HasPrefix(normalizedVersion, vllmImageTypeIntel+"-") {
|
||||
return vllmImageTypeIntel
|
||||
}
|
||||
if strings.HasPrefix(normalizedVersion, vllmImageTypeAscend+"-") {
|
||||
return vllmImageTypeAscend
|
||||
}
|
||||
if strings.HasPrefix(normalizedVersion, vllmImageTypeNvidia+"-") {
|
||||
return vllmImageTypeNvidia
|
||||
}
|
||||
@@ -26,13 +30,16 @@ func resolveVllmVersionFamily(version, image string) string {
|
||||
if strings.Contains(normalizedImage, "intel/") || strings.Contains(normalizedImage, "llm-scaler-vllm") {
|
||||
return vllmImageTypeIntel
|
||||
}
|
||||
if strings.Contains(normalizedImage, "ascend/") || strings.Contains(normalizedImage, "vllm-ascend") {
|
||||
return vllmImageTypeAscend
|
||||
}
|
||||
return vllmImageTypeNvidia
|
||||
}
|
||||
|
||||
func trimVllmVersionFamily(version string) string {
|
||||
trimmed := strings.TrimSpace(version)
|
||||
normalized := strings.ToLower(trimmed)
|
||||
for _, family := range []string{vllmImageTypeNvidia, vllmImageTypeIntel} {
|
||||
for _, family := range []string{vllmImageTypeNvidia, vllmImageTypeIntel, vllmImageTypeAscend} {
|
||||
prefix := family + "-"
|
||||
if strings.HasPrefix(normalized, prefix) {
|
||||
return strings.TrimSpace(trimmed[len(prefix):])
|
||||
@@ -43,12 +50,16 @@ func trimVllmVersionFamily(version string) string {
|
||||
|
||||
func buildDefaultVllmImageByVersion(version string) string {
|
||||
tag := trimVllmVersionFamily(version)
|
||||
if resolveVllmVersionFamily(version, "") == vllmImageTypeIntel {
|
||||
family := resolveVllmVersionFamily(version, "")
|
||||
if family == vllmImageTypeIntel {
|
||||
return "intel/llm-scaler-vllm:" + tag
|
||||
}
|
||||
if tag != "" && !strings.HasPrefix(strings.ToLower(tag), "v") {
|
||||
tag = "v" + tag
|
||||
}
|
||||
if family == vllmImageTypeAscend {
|
||||
return "quay.io/ascend/vllm-ascend:" + tag
|
||||
}
|
||||
return "vllm/vllm-openai:" + tag
|
||||
}
|
||||
|
||||
@@ -60,7 +71,9 @@ func isVllmUpgradeVersionAllowed(currentVersion, targetVersion, currentImage str
|
||||
|
||||
func hasVllmVersionFamilyPrefix(version string) bool {
|
||||
normalized := strings.ToLower(strings.TrimSpace(version))
|
||||
return strings.HasPrefix(normalized, vllmImageTypeNvidia+"-") || strings.HasPrefix(normalized, vllmImageTypeIntel+"-")
|
||||
return strings.HasPrefix(normalized, vllmImageTypeNvidia+"-") ||
|
||||
strings.HasPrefix(normalized, vllmImageTypeIntel+"-") ||
|
||||
strings.HasPrefix(normalized, vllmImageTypeAscend+"-")
|
||||
}
|
||||
|
||||
func isVllmUpgradeCandidate(currentVersion, targetVersion, currentImage string) bool {
|
||||
|
||||
@@ -855,6 +855,9 @@ const message = {
|
||||
channelAutoRestartHelper: 'Saving will automatically restart the container so the changes take effect.',
|
||||
channelDeleteConfirm: 'Delete the {0} channel configuration?',
|
||||
customProviderHelper: 'Custom model providers do not validate whether the account is available.',
|
||||
apiTypeBaseURLHelper: 'This type sends requests to {0}. Recommended Base URL: {1}',
|
||||
apiTypeBaseURLMismatch:
|
||||
'The current Base URL looks like a {0} path, but {1} is selected. Recommended URL: {2}',
|
||||
},
|
||||
model: {
|
||||
model: 'Models',
|
||||
@@ -1025,6 +1028,8 @@ const message = {
|
||||
healthUnknown: 'Unknown',
|
||||
validationModelMapEmpty: 'Model mapping names cannot be empty',
|
||||
validationModelMapDuplicate: 'Request model {0} is duplicated',
|
||||
validateAvailability: 'Validate Account Availability',
|
||||
validateAvailabilityHelper: 'Send a minimal message before saving to validate API availability',
|
||||
modelGroup: 'Model Group',
|
||||
availableModels: 'Available Models',
|
||||
modelGroupModels: 'Request Models',
|
||||
|
||||
@@ -866,6 +866,9 @@ const message = {
|
||||
'Al guardar, el contenedor se reiniciará automáticamente para que la configuración surta efecto.',
|
||||
channelDeleteConfirm: '¿Eliminar la configuración del canal {0}?',
|
||||
customProviderHelper: 'En el proveedor de modelo personalizado no se valida si la cuenta está disponible',
|
||||
apiTypeBaseURLHelper: 'Este tipo envía solicitudes a {0}. Base URL recomendada: {1}',
|
||||
apiTypeBaseURLMismatch:
|
||||
'La Base URL actual parece una ruta {0}, pero está seleccionado {1}. URL recomendada: {2}',
|
||||
},
|
||||
model: {
|
||||
model: 'Modelo',
|
||||
@@ -1040,6 +1043,9 @@ const message = {
|
||||
healthUnknown: 'Desconocido',
|
||||
validationModelMapEmpty: 'Los nombres del mapeo de modelos no pueden estar vacíos',
|
||||
validationModelMapDuplicate: 'El modelo solicitado {0} está duplicado',
|
||||
validateAvailability: 'Validar disponibilidad de la cuenta',
|
||||
validateAvailabilityHelper:
|
||||
'Enviar un mensaje mínimo antes de guardar para validar la disponibilidad de la API',
|
||||
modelGroup: 'Grupo de modelos',
|
||||
availableModels: 'Modelos disponibles',
|
||||
modelGroupModels: 'Modelos solicitados',
|
||||
|
||||
@@ -858,6 +858,8 @@ const message = {
|
||||
channelAutoRestartHelper: '保存後、設定を反映するためにコンテナが自動で再起動されます。',
|
||||
channelDeleteConfirm: '{0} チャンネルの設定を削除しますか?',
|
||||
customProviderHelper: 'カスタムモデルプロバイダーでは、アカウントの有効性を検証しません',
|
||||
apiTypeBaseURLHelper: 'このタイプは最終的に {0} にリクエストします。推奨 Base URL: {1}',
|
||||
apiTypeBaseURLMismatch: '現在の Base URL は {0} のパスに見えますが、{1} が選択されています。推奨 URL: {2}',
|
||||
},
|
||||
model: {
|
||||
model: 'モデル',
|
||||
@@ -1030,6 +1032,8 @@ const message = {
|
||||
healthUnknown: '不明',
|
||||
validationModelMapEmpty: 'モデルマッピングのモデル名は空にできません',
|
||||
validationModelMapDuplicate: 'リクエストモデル {0} が重複しています',
|
||||
validateAvailability: 'アカウントの可用性を検証',
|
||||
validateAvailabilityHelper: '保存前に最小メッセージを送信して API の可用性を検証します',
|
||||
modelGroup: 'モデルグループ',
|
||||
availableModels: '利用可能なモデル',
|
||||
modelGroupModels: 'リクエストモデル',
|
||||
|
||||
@@ -843,6 +843,8 @@ const message = {
|
||||
channelAutoRestartHelper: '저장하면 설정 적용을 위해 컨테이너가 자동으로 재시작됩니다.',
|
||||
channelDeleteConfirm: '{0} 채널 구성을 삭제하시겠습니까?',
|
||||
customProviderHelper: '사용자 정의 모델 공급자는 계정 사용 가능 여부를 검증하지 않습니다',
|
||||
apiTypeBaseURLHelper: '이 유형은 최종적으로 {0}에 요청합니다. 권장 Base URL: {1}',
|
||||
apiTypeBaseURLMismatch: '현재 Base URL은 {0} 경로처럼 보이지만 {1}이 선택되었습니다. 권장 URL: {2}',
|
||||
},
|
||||
model: {
|
||||
model: '모델',
|
||||
@@ -1015,6 +1017,8 @@ const message = {
|
||||
healthUnknown: '알 수 없음',
|
||||
validationModelMapEmpty: '모델 매핑의 모델 이름은 비워 둘 수 없습니다',
|
||||
validationModelMapDuplicate: '요청 모델 {0}이(가) 중복되었습니다',
|
||||
validateAvailability: '계정 사용 가능 여부 검증',
|
||||
validateAvailabilityHelper: '저장 전에 최소 메시지를 보내 API 사용 가능 여부를 검증합니다',
|
||||
modelGroup: '모델 그룹',
|
||||
availableModels: '사용 가능한 모델',
|
||||
modelGroupModels: '요청 모델',
|
||||
|
||||
@@ -865,6 +865,9 @@ const message = {
|
||||
'Menyimpan akan memulakan semula bekas secara automatik supaya konfigurasi berkuat kuasa.',
|
||||
channelDeleteConfirm: 'Padam konfigurasi saluran {0}?',
|
||||
customProviderHelper: 'Penyedia model tersuai tidak mengesahkan sama ada akaun boleh digunakan',
|
||||
apiTypeBaseURLHelper: 'Jenis ini menghantar permintaan ke {0}. Base URL yang disyorkan: {1}',
|
||||
apiTypeBaseURLMismatch:
|
||||
'Base URL semasa kelihatan seperti laluan {0}, tetapi {1} dipilih. URL yang disyorkan: {2}',
|
||||
},
|
||||
model: {
|
||||
model: 'Model',
|
||||
@@ -1038,6 +1041,8 @@ const message = {
|
||||
healthUnknown: 'Tidak diketahui',
|
||||
validationModelMapEmpty: 'Nama model dalam pemetaan model tidak boleh kosong',
|
||||
validationModelMapDuplicate: 'Model permintaan {0} berulang',
|
||||
validateAvailability: 'Sahkan Ketersediaan Akaun',
|
||||
validateAvailabilityHelper: 'Hantar mesej minimum sebelum menyimpan untuk mengesahkan ketersediaan API',
|
||||
modelGroup: 'Kumpulan Model',
|
||||
availableModels: 'Model Tersedia',
|
||||
modelGroupModels: 'Model Permintaan',
|
||||
|
||||
@@ -861,6 +861,9 @@ const message = {
|
||||
'Ao salvar, o contêiner será reiniciado automaticamente para que a configuração entre em vigor.',
|
||||
channelDeleteConfirm: 'Excluir a configuração do canal {0}?',
|
||||
customProviderHelper: 'Provedores de modelo personalizados não validam se a conta está disponível',
|
||||
apiTypeBaseURLHelper: 'Este tipo envia requisições para {0}. Base URL recomendada: {1}',
|
||||
apiTypeBaseURLMismatch:
|
||||
'A Base URL atual parece um caminho {0}, mas {1} está selecionado. URL recomendada: {2}',
|
||||
},
|
||||
model: {
|
||||
model: 'Modelo',
|
||||
@@ -1034,6 +1037,9 @@ const message = {
|
||||
healthUnknown: 'Desconhecido',
|
||||
validationModelMapEmpty: 'Os nomes no mapeamento de modelos não podem ficar vazios',
|
||||
validationModelMapDuplicate: 'O modelo solicitado {0} está duplicado',
|
||||
validateAvailability: 'Validar disponibilidade da conta',
|
||||
validateAvailabilityHelper:
|
||||
'Envie uma mensagem mínima antes de salvar para validar a disponibilidade da API',
|
||||
modelGroup: 'Grupo de modelos',
|
||||
availableModels: 'Modelos disponíveis',
|
||||
modelGroupModels: 'Modelos solicitados',
|
||||
|
||||
@@ -856,6 +856,8 @@ const message = {
|
||||
'После сохранения контейнер будет автоматически перезапущен, чтобы настройки вступили в силу.',
|
||||
channelDeleteConfirm: 'Удалить конфигурацию канала {0}?',
|
||||
customProviderHelper: 'Для пользовательского провайдера модели доступность учетной записи не проверяется',
|
||||
apiTypeBaseURLHelper: 'Этот тип отправляет запросы в {0}. Рекомендуемый Base URL: {1}',
|
||||
apiTypeBaseURLMismatch: 'Текущий Base URL похож на путь {0}, но выбран {1}. Рекомендуемый URL: {2}',
|
||||
},
|
||||
model: {
|
||||
model: 'Модель',
|
||||
@@ -1029,6 +1031,9 @@ const message = {
|
||||
healthUnknown: 'Неизвестно',
|
||||
validationModelMapEmpty: 'Имена моделей в сопоставлении не могут быть пустыми',
|
||||
validationModelMapDuplicate: 'Запрошенная модель {0} дублируется',
|
||||
validateAvailability: 'Проверить доступность аккаунта',
|
||||
validateAvailabilityHelper:
|
||||
'Отправить минимальное сообщение перед сохранением для проверки доступности API',
|
||||
modelGroup: 'Группа моделей',
|
||||
availableModels: 'Доступные модели',
|
||||
modelGroupModels: 'Запрошенные модели',
|
||||
|
||||
@@ -864,6 +864,9 @@ const message = {
|
||||
'Kaydettiğinizde ayarların etkili olması için konteyner otomatik olarak yeniden başlatılır.',
|
||||
channelDeleteConfirm: '{0} kanal yapılandırması silinsin mi?',
|
||||
customProviderHelper: 'Özel model sağlayıcısında hesabın kullanılabilirliği doğrulanmaz',
|
||||
apiTypeBaseURLHelper: 'Bu tür istekleri {0} yoluna gönderir. Önerilen Base URL: {1}',
|
||||
apiTypeBaseURLMismatch:
|
||||
'Geçerli Base URL bir {0} yolu gibi görünüyor, ancak {1} seçildi. Önerilen URL: {2}',
|
||||
},
|
||||
model: {
|
||||
model: 'Model',
|
||||
@@ -1037,6 +1040,9 @@ const message = {
|
||||
healthUnknown: 'Bilinmiyor',
|
||||
validationModelMapEmpty: 'Model eşlemesindeki model adları boş olamaz',
|
||||
validationModelMapDuplicate: 'İstek modeli {0} yineleniyor',
|
||||
validateAvailability: 'Hesap Kullanılabilirliğini Doğrula',
|
||||
validateAvailabilityHelper:
|
||||
'Kaydetmeden önce API kullanılabilirliğini doğrulamak için en küçük iletiyi gönder',
|
||||
modelGroup: 'Model Grubu',
|
||||
availableModels: 'Kullanılabilir Modeller',
|
||||
modelGroupModels: 'İstek Modelleri',
|
||||
|
||||
@@ -809,6 +809,8 @@ const message = {
|
||||
channelAutoRestartHelper: '保存後將自動重新啟動容器以使設定生效。',
|
||||
channelDeleteConfirm: '確認刪除 {0} 頻道設定?',
|
||||
customProviderHelper: '自訂模型供應商不驗證帳號是否可用',
|
||||
apiTypeBaseURLHelper: '目前類型最終請求 {0},Base URL 建議填寫 {1}',
|
||||
apiTypeBaseURLMismatch: '目前 Base URL 看起來是 {0} 路徑,和已選擇的 {1} 不一致,建議改為 {2}',
|
||||
},
|
||||
model: {
|
||||
model: '模型',
|
||||
@@ -977,6 +979,8 @@ const message = {
|
||||
healthUnknown: '未知',
|
||||
validationModelMapEmpty: '模型映射的模型名稱不能為空',
|
||||
validationModelMapDuplicate: '請求模型 {0} 重複',
|
||||
validateAvailability: '驗證帳號可用性',
|
||||
validateAvailabilityHelper: '儲存前發送最小訊息驗證介面可用性',
|
||||
modelGroup: '模型組',
|
||||
availableModels: '可用模型',
|
||||
modelGroupModels: '請求模型',
|
||||
|
||||
@@ -802,6 +802,8 @@ const message = {
|
||||
channelAutoRestartHelper: '保存后将自动重启容器以使配置生效。',
|
||||
channelDeleteConfirm: '确认删除 {0} 频道配置?',
|
||||
customProviderHelper: '自定义模型供应商不验证账号是否可用',
|
||||
apiTypeBaseURLHelper: '当前类型最终请求 {0},Base URL 建议填写 {1}',
|
||||
apiTypeBaseURLMismatch: '当前 Base URL 看起来是 {0} 路径,和已选择的 {1} 不一致,建议改为 {2}',
|
||||
},
|
||||
model: {
|
||||
model: '模型',
|
||||
@@ -968,6 +970,8 @@ const message = {
|
||||
healthUnknown: '未知',
|
||||
validationModelMapEmpty: '模型映射的模型名不能为空',
|
||||
validationModelMapDuplicate: '请求模型 {0} 重复',
|
||||
validateAvailability: '验证账号可用性',
|
||||
validateAvailabilityHelper: '保存前发送最小消息验证接口可用性',
|
||||
modelGroup: '模型组',
|
||||
availableModels: '可用模型',
|
||||
modelGroupModels: '请求模型',
|
||||
|
||||
@@ -30,6 +30,18 @@
|
||||
</el-form-item>
|
||||
<el-form-item label="Base URL" prop="baseURL">
|
||||
<el-input v-model="form.baseURL" :disabled="!editableBaseURLProviders.includes(form.provider)" />
|
||||
<span v-if="apiTypeBaseURLHelper" class="input-help">
|
||||
{{ apiTypeBaseURLHelper }}
|
||||
</span>
|
||||
<el-alert
|
||||
v-if="baseURLAPITypeMismatchTip"
|
||||
class="base-url-warning"
|
||||
type="warning"
|
||||
:closable="false"
|
||||
show-icon
|
||||
>
|
||||
{{ baseURLAPITypeMismatchTip }}
|
||||
</el-alert>
|
||||
</el-form-item>
|
||||
<el-form-item :label="'API ' + $t('commons.table.type')" prop="apiType">
|
||||
<el-select v-model="form.apiType" :disabled="apiTypeOptions.length === 1">
|
||||
@@ -133,6 +145,67 @@ const apiTypeOptions = computed(() => {
|
||||
}
|
||||
return ['openai-completions', 'openai-responses'];
|
||||
});
|
||||
const apiTypeURLHints: Record<string, { requestPath: string; example: string; endpointSuffixes: string[] }> = {
|
||||
'openai-completions': {
|
||||
requestPath: '/v1/chat/completions',
|
||||
example: 'http://127.0.0.1:8000/v1',
|
||||
endpointSuffixes: ['/v1/chat/completions', '/v1beta/chat/completions', '/chat/completions'],
|
||||
},
|
||||
'openai-responses': {
|
||||
requestPath: '/v1/responses',
|
||||
example: 'http://127.0.0.1:8000/v1',
|
||||
endpointSuffixes: ['/v1/responses', '/responses'],
|
||||
},
|
||||
'anthropic-messages': {
|
||||
requestPath: '/v1/messages',
|
||||
example: 'http://127.0.0.1:8000',
|
||||
endpointSuffixes: ['/v1/messages', '/messages'],
|
||||
},
|
||||
};
|
||||
const showAPITypeBaseURLTips = computed(() => form.provider === 'vllm');
|
||||
const apiTypeBaseURLHelper = computed(() => {
|
||||
const hint = apiTypeURLHints[form.apiType];
|
||||
if (!showAPITypeBaseURLTips.value || !hint) {
|
||||
return '';
|
||||
}
|
||||
return i18n.global.t('aiTools.agents.apiTypeBaseURLHelper', [hint.requestPath, hint.example]);
|
||||
});
|
||||
|
||||
const normalizeBaseURLPath = (baseURL: string) => {
|
||||
const value = baseURL.trim().replace(/\/+$/, '');
|
||||
if (!value) {
|
||||
return '';
|
||||
}
|
||||
try {
|
||||
return (new URL(value).pathname || '/').replace(/\/+$/, '').toLowerCase();
|
||||
} catch {
|
||||
return value.split(/[?#]/)[0].replace(/\/+$/, '').toLowerCase();
|
||||
}
|
||||
};
|
||||
|
||||
const detectAPITypeFromBaseURL = (baseURL: string) => {
|
||||
const path = normalizeBaseURLPath(baseURL);
|
||||
if (!path) {
|
||||
return '';
|
||||
}
|
||||
for (const [apiType, hint] of Object.entries(apiTypeURLHints)) {
|
||||
if (hint.endpointSuffixes.some((suffix) => path.endsWith(suffix))) {
|
||||
return apiType;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
};
|
||||
const baseURLAPITypeMismatchTip = computed(() => {
|
||||
if (!showAPITypeBaseURLTips.value || !form.baseURL) {
|
||||
return '';
|
||||
}
|
||||
const detectedAPIType = detectAPITypeFromBaseURL(form.baseURL);
|
||||
const expected = apiTypeURLHints[form.apiType];
|
||||
if (!detectedAPIType || detectedAPIType === form.apiType || !expected) {
|
||||
return '';
|
||||
}
|
||||
return i18n.global.t('aiTools.agents.apiTypeBaseURLMismatch', [detectedAPIType, form.apiType, expected.example]);
|
||||
});
|
||||
|
||||
const rules = reactive({
|
||||
provider: [Rules.requiredSelect],
|
||||
@@ -376,4 +449,8 @@ defineExpose({
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.base-url-warning {
|
||||
margin-top: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user