mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
fix(models): restore disabled custom providers
This commit is contained in:
parent
aecc619bef
commit
281ea53551
@ -175,7 +175,11 @@ public class ModelProviderService {
|
||||
throw new MateClawException("err.llm.provider_id_invalid",
|
||||
"Provider id 仅允许字母/数字及 . _ -(不允许斜杠或空格),首字符必须是字母或数字,长度 1-64: " + request.getId());
|
||||
}
|
||||
if (modelProviderMapper.selectById(request.getId()) != null) {
|
||||
ModelProviderEntity existing = modelProviderMapper.selectById(request.getId());
|
||||
if (existing != null && canRestoreCustomProvider(existing)) {
|
||||
return restoreCustomProvider(existing, request);
|
||||
}
|
||||
if (existing != null) {
|
||||
throw new MateClawException("err.llm.provider_exists", "Provider 已存在: " + request.getId());
|
||||
}
|
||||
ModelProtocol protocol = ModelProtocol.resolve(request.getProtocol(), request.getChatModel());
|
||||
@ -211,6 +215,32 @@ public class ModelProviderService {
|
||||
return toProviderInfo(provider, modelConfigService.listModelsByProvider(request.getId()));
|
||||
}
|
||||
|
||||
private boolean canRestoreCustomProvider(ModelProviderEntity provider) {
|
||||
return Boolean.TRUE.equals(provider.getIsCustom()) && !Boolean.TRUE.equals(provider.getEnabled());
|
||||
}
|
||||
|
||||
private ProviderInfoDTO restoreCustomProvider(ModelProviderEntity provider, CreateCustomProviderRequest request) {
|
||||
ModelProtocol protocol = ModelProtocol.resolve(request.getProtocol(), request.getChatModel());
|
||||
provider.setName(request.getName());
|
||||
provider.setApiKeyPrefix(request.getApiKeyPrefix());
|
||||
provider.setChatModel(protocol.getChatModelClass());
|
||||
provider.setBaseUrl(request.getDefaultBaseUrl());
|
||||
provider.setIsCustom(true);
|
||||
provider.setIsLocal(false);
|
||||
provider.setEnabled(true);
|
||||
provider.setSupportModelDiscovery(protocol.supportsSelfConfiguredDiscovery());
|
||||
provider.setRequireApiKey(request.getRequireApiKey() == null || Boolean.TRUE.equals(request.getRequireApiKey()));
|
||||
modelProviderMapper.updateById(provider);
|
||||
if (request.getModels() != null) {
|
||||
for (ModelInfoDTO model : request.getModels()) {
|
||||
modelConfigService.addModelToProvider(request.getId(), model.getId(), model.getName(), false);
|
||||
}
|
||||
}
|
||||
tryAutoActivateModel(request.getId(), provider);
|
||||
eventPublisher.publishEvent(new ModelConfigChangedEvent("provider-enabled"));
|
||||
return toProviderInfo(provider, modelConfigService.listModelsByProvider(request.getId()));
|
||||
}
|
||||
|
||||
public void deleteCustomProvider(String providerId) {
|
||||
ModelProviderEntity provider = getProvider(providerId);
|
||||
if (!Boolean.TRUE.equals(provider.getIsCustom())) {
|
||||
|
||||
@ -14,6 +14,7 @@ import vip.mate.llm.failover.AvailableProviderPool;
|
||||
import vip.mate.llm.failover.ProviderHealthProperties;
|
||||
import vip.mate.llm.failover.ProviderHealthTracker;
|
||||
import vip.mate.llm.failover.ProviderInitProbe;
|
||||
import vip.mate.llm.model.CreateCustomProviderRequest;
|
||||
import vip.mate.llm.model.EnableResult;
|
||||
import vip.mate.llm.model.ModelConfigEntity;
|
||||
import vip.mate.llm.model.ModelProviderEntity;
|
||||
@ -112,6 +113,36 @@ class ModelProviderServiceEnableTest {
|
||||
verify(eventPublisher, never()).publishEvent(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("createCustomProvider with an existing disabled custom row re-enables and updates it")
|
||||
void createCustomProviderReEnablesDisabledCustomProvider() {
|
||||
ModelProviderEntity existing = providerEntity("custom-openai", false);
|
||||
existing.setIsCustom(true);
|
||||
existing.setName("Old name");
|
||||
when(providerMapper.selectById("custom-openai")).thenReturn(existing);
|
||||
when(modelConfigService.listModelsByProvider("custom-openai")).thenReturn(new ArrayList<>());
|
||||
|
||||
CreateCustomProviderRequest request = new CreateCustomProviderRequest();
|
||||
request.setId("custom-openai");
|
||||
request.setName("New name");
|
||||
request.setDefaultBaseUrl("https://new.example.com/v1");
|
||||
request.setApiKeyPrefix("mk-");
|
||||
request.setProtocol("openai-compatible");
|
||||
request.setRequireApiKey(true);
|
||||
|
||||
service.createCustomProvider(request);
|
||||
|
||||
assertTrue(existing.getEnabled(), "disabled custom provider should be visible again");
|
||||
assertEquals("New name", existing.getName());
|
||||
assertEquals("https://new.example.com/v1", existing.getBaseUrl());
|
||||
assertEquals("mk-", existing.getApiKeyPrefix());
|
||||
verify(providerMapper).updateById(existing);
|
||||
verify(providerMapper, never()).insert(any(ModelProviderEntity.class));
|
||||
ArgumentCaptor<ModelConfigChangedEvent> evtCap = ArgumentCaptor.forClass(ModelConfigChangedEvent.class);
|
||||
verify(eventPublisher).publishEvent(evtCap.capture());
|
||||
assertEquals("provider-enabled", evtCap.getValue().reason());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("setEnabled(false) when provider's model is current default: auto-switches and reports new")
|
||||
void disableSwitchesDefault() {
|
||||
|
||||
@ -1137,15 +1137,15 @@ export default {
|
||||
livenessUnprobedTooltip: 'Checking availability after startup; will refresh shortly',
|
||||
livenessUnconfigured: 'Needs setup',
|
||||
// RFC-074 PR-2: enable / disable / drawer
|
||||
enableProviderCta: '+ Enable Provider',
|
||||
enableProviderCta: '+ Enable / Restore Provider',
|
||||
addCustomProvider: '+ Custom',
|
||||
enable: 'Enable',
|
||||
disable: 'Disable',
|
||||
alreadyEnabled: 'Enabled',
|
||||
disableConfirm: 'Disable provider "{name}"? It will disappear from the dropdown but its config is kept — you can re-enable any time.',
|
||||
defaultSwitchedToast: 'Default model switched to {provider} / {model}',
|
||||
addProviderDrawerTitle: 'Add Provider',
|
||||
addProviderDrawerSubtitle: 'Once enabled the provider appears in the model dropdown. Cloud providers still need an API key after enabling.',
|
||||
addProviderDrawerTitle: 'Enable / Restore Provider',
|
||||
addProviderDrawerSubtitle: 'Disabled providers can be restored here. Once enabled, the provider appears in the model dropdown. Cloud providers may still need an API key.',
|
||||
catalogEmpty: 'Catalog is empty',
|
||||
catalogSearchPlaceholder: 'Search providers…',
|
||||
catalogSearchEmpty: 'No providers match “{query}”',
|
||||
|
||||
@ -982,15 +982,15 @@ export default {
|
||||
livenessUnprobedTooltip: '启动后正在检测可用性,稍候自动更新',
|
||||
livenessUnconfigured: '需要配置',
|
||||
// RFC-074 PR-2: enable / disable / drawer
|
||||
enableProviderCta: '+ 启用提供商',
|
||||
enableProviderCta: '+ 启用/恢复提供商',
|
||||
addCustomProvider: '+ 自定义提供商',
|
||||
enable: '启用',
|
||||
disable: '禁用',
|
||||
alreadyEnabled: '已启用',
|
||||
disableConfirm: '确定禁用提供商"{name}"?它将从下拉中消失,但配置保留,可随时再启用。',
|
||||
defaultSwitchedToast: '已将默认模型切换到 {provider} / {model}',
|
||||
addProviderDrawerTitle: '添加提供商',
|
||||
addProviderDrawerSubtitle: '启用后会出现在模型下拉中。如果是云端提供商,启用后还需要填 API Key。',
|
||||
addProviderDrawerTitle: '启用/恢复提供商',
|
||||
addProviderDrawerSubtitle: '禁用后的提供商可在这里恢复;启用后会出现在模型下拉中。云端提供商可能还需要填 API Key。',
|
||||
catalogEmpty: '目录为空',
|
||||
catalogSearchPlaceholder: '搜索提供商…',
|
||||
catalogSearchEmpty: '没有匹配“{query}”的提供商',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user