Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Update AI console function. #360

Merged
merged 2 commits into from
Oct 21, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat: Update AI console function.
1. Update the data models of Consumer, LlmProvider and AiRoute.
2. Return the original tokens instead of masked ones in ConsumersController and LlmProviderController.
3. Fix auth functions in AI route.
CH3CHO committed Oct 18, 2024
commit 64e476894d1bec6ac8a2c3c64122307f4ab07ea4
Original file line number Diff line number Diff line change
@@ -16,7 +16,6 @@
import javax.validation.ValidationException;
import javax.validation.constraints.NotBlank;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
@@ -35,7 +34,6 @@
import com.alibaba.higress.sdk.model.CommonPageQuery;
import com.alibaba.higress.sdk.model.PaginatedResult;
import com.alibaba.higress.sdk.model.consumer.Consumer;
import com.alibaba.higress.sdk.model.consumer.Credential;
import com.alibaba.higress.sdk.service.consumer.ConsumerService;

@RestController("ConsumersController")
@@ -53,17 +51,13 @@ public void setConsumerService(ConsumerService consumerService) {
@GetMapping
public ResponseEntity<PaginatedResponse<Consumer>> list(CommonPageQuery query) {
PaginatedResult<Consumer> consumers = consumerService.list(query);
if (CollectionUtils.isNotEmpty(consumers.getData())) {
consumers.getData().forEach(ConsumersController::maskSensitiveData);
}
return ControllerUtil.buildResponseEntity(consumers);
}

@PostMapping
public ResponseEntity<Response<Consumer>> add(@RequestBody Consumer consumer) {
consumer.validate(false);
Consumer newConsumer = consumerService.addOrUpdate(consumer);
maskSensitiveData(newConsumer);
return ControllerUtil.buildResponseEntity(newConsumer);
}

@@ -83,7 +77,6 @@ public ResponseEntity<Response<Consumer>> put(@PathVariable("name") @NotBlank St
}
consumer.validate(true);
Consumer updatedConsumer = consumerService.addOrUpdate(consumer);
maskSensitiveData(updatedConsumer);
return ControllerUtil.buildResponseEntity(updatedConsumer);
}

@@ -92,10 +85,4 @@ public ResponseEntity<Response<Consumer>> delete(@PathVariable("name") @NotBlank
consumerService.delete(name);
return ResponseEntity.noContent().build();
}

private static void maskSensitiveData(Consumer consumer) {
if (consumer != null && CollectionUtils.isNotEmpty(consumer.getCredentials())) {
consumer.getCredentials().forEach(Credential::maskSensitiveData);
}
}
}
Original file line number Diff line number Diff line change
@@ -16,7 +16,6 @@
import javax.validation.ValidationException;
import javax.validation.constraints.NotBlank;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
@@ -52,25 +51,18 @@ public void setLlmProviderService(LlmProviderService llmProviderService) {
@GetMapping
public ResponseEntity<PaginatedResponse<LlmProvider>> list(CommonPageQuery query) {
PaginatedResult<LlmProvider> providers = llmProviderService.list(query);
if (CollectionUtils.isNotEmpty(providers.getData())) {
providers.getData().forEach(LlmProvider::maskSensitiveData);
}
return ControllerUtil.buildResponseEntity(providers);
}

@PostMapping
public ResponseEntity<Response<LlmProvider>> add(@RequestBody LlmProvider certificate) {
LlmProvider newProvider = llmProviderService.addOrUpdate(certificate);
newProvider.maskSensitiveData();
return ControllerUtil.buildResponseEntity(newProvider);
}

@GetMapping(value = "/{name}")
public ResponseEntity<Response<LlmProvider>> query(@PathVariable("name") @NotBlank String name) {
LlmProvider provider = llmProviderService.query(name);
if (provider != null){
provider.maskSensitiveData();
}
return ControllerUtil.buildResponseEntity(provider);
}

@@ -83,7 +75,6 @@ public ResponseEntity<Response<LlmProvider>> put(@PathVariable("name") @NotBlank
throw new ValidationException("Provider name in the URL doesn't match the one in the body.");
}
LlmProvider updatedProvider = llmProviderService.addOrUpdate(provider);
updatedProvider.maskSensitiveData();
return ControllerUtil.buildResponseEntity(updatedProvider);
}

Original file line number Diff line number Diff line change
@@ -36,9 +36,8 @@ public class AiRoute {
private String version;
private List<String> domains;
private List<AiUpstream> upstreams;
private Boolean authEnabled;
private List<String> consumers;
private AiUpstream fallbackUpstream;
private AiRouteAuthConfig authConfig;
private AiRouteFallbackConfig fallbackConfig;

public void validate() {
if (StringUtils.isBlank(name)) {
@@ -47,8 +46,12 @@ public void validate() {
if (CollectionUtils.isEmpty(upstreams)){
throw new ValidationException("upstreams cannot be empty.");
}
if (Boolean.TRUE.equals(authEnabled) && CollectionUtils.isEmpty(consumers)){
throw new ValidationException("consumers cannot be empty when authEnabled is true.");
upstreams.forEach(AiUpstream::validate);
if (authConfig != null){
authConfig.validate();
}
if (fallbackConfig != null){
fallbackConfig.validate();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2022-2023 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.alibaba.higress.sdk.model.ai;

import java.util.List;

import org.apache.commons.collections4.CollectionUtils;

import com.alibaba.higress.sdk.exception.ValidationException;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AiRouteAuthConfig {

private Boolean enabled;
private List<String> allowedConsumers;

public void validate() {
if (Boolean.TRUE.equals(enabled) && CollectionUtils.isEmpty(allowedConsumers)) {
throw new ValidationException("allowedConsumers cannot be empty when auth is enabled.");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2022-2023 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.alibaba.higress.sdk.model.ai;

import java.util.List;

import org.apache.commons.collections4.CollectionUtils;

import com.alibaba.higress.sdk.exception.ValidationException;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AiRouteFallbackConfig {

private Boolean enabled;
private List<AiUpstream> upstreams;
private String fallbackStrategy;

public void validate() {
if (!Boolean.TRUE.equals(enabled)) {
return;
}
if (StringUtils.isNotEmpty(fallbackStrategy)) {
switch (fallbackStrategy) {
case AiRouteFallbackStrategy.RANDOM:
case AiRouteFallbackStrategy.SEQUENCE:
break;
default:
throw new ValidationException("unknown fallback strategy: " + fallbackStrategy);
}
}
if (CollectionUtils.isEmpty(upstreams)) {
throw new ValidationException("upstreams cannot be empty when fallback is enabled.");
}
upstreams.forEach(AiUpstream::validate);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright (c) 2022-2023 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.alibaba.higress.sdk.model.ai;

public final class AiRouteFallbackStrategy {

private AiRouteFallbackStrategy() {
}

public static final String RANDOM = "RAND";

public static final String SEQUENCE = "SEQ";
}
Original file line number Diff line number Diff line change
@@ -12,6 +12,10 @@
*/
package com.alibaba.higress.sdk.model.ai;

import org.apache.commons.lang3.StringUtils;

import com.alibaba.higress.sdk.exception.ValidationException;

import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -27,4 +31,10 @@ public class AiUpstream {

private String provider;
private Integer weight;

public void validate() {
if (StringUtils.isEmpty(provider)) {
throw new ValidationException("provider cannot be null or empty.");
}
}
}
Original file line number Diff line number Diff line change
@@ -15,11 +15,8 @@
import java.util.List;
import java.util.Map;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import com.alibaba.higress.sdk.util.StringUtil;

import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -53,13 +50,4 @@ public void validate(boolean forUpdate) {
throw new IllegalArgumentException("Unknown protocol: " + protocol);
}
}

public void maskSensitiveData() {
if (CollectionUtils.isEmpty(tokens)) {
return;
}
for (int i = 0; i < tokens.size(); ++i) {
tokens.set(i, StringUtil.mask(tokens.get(i)));
}
}
}
Original file line number Diff line number Diff line change
@@ -55,6 +55,4 @@ public void setProperty(String name, Object value) {
}

public void validate(boolean forUpdate) {}

public void maskSensitiveData() {}
}
Original file line number Diff line number Diff line change
@@ -17,7 +17,6 @@
import org.apache.commons.lang3.StringUtils;

import com.alibaba.higress.sdk.exception.ValidationException;
import com.alibaba.higress.sdk.util.StringUtil;

import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
@@ -78,10 +77,4 @@ public void validate(boolean forUpdate) {
throw new ValidationException("value cannot be blank.");
}
}

@Override
public void maskSensitiveData() {
super.maskSensitiveData();
this.value = StringUtil.mask(this.value);
}
}
Original file line number Diff line number Diff line change
@@ -58,8 +58,8 @@ class HigressServiceProviderImpl implements HigressServiceProvider {
consumerService = new ConsumerServiceImpl(wasmPluginService, wasmPluginInstanceService);
llmProviderService =
new LlmProviderServiceImpl(serviceSourceService, wasmPluginService, wasmPluginInstanceService);
aiRouteService =
new AiRouteServiceImpl(kubernetesModelConverter, kubernetesClientService, routeService, llmProviderService);
aiRouteService = new AiRouteServiceImpl(kubernetesModelConverter, kubernetesClientService, routeService,
llmProviderService, consumerService);
}

@Override
Original file line number Diff line number Diff line change
@@ -111,6 +111,8 @@ public void saveConfig(LlmProvider provider, Map<String, Object> configurations)
List<String> tokens = provider.getTokens();
if (CollectionUtils.isNotEmpty(tokens)) {
configurations.put(PROVIDER_API_TOKENS_KEY, tokens);
} else {
configurations.remove(PROVIDER_API_TOKENS_KEY);
}

TokenFailoverConfig failoverConfig = provider.getTokenFailoverConfig();
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@
import java.util.Map;
import java.util.Optional;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

@@ -30,13 +31,18 @@
import com.alibaba.higress.sdk.model.CommonPageQuery;
import com.alibaba.higress.sdk.model.PaginatedResult;
import com.alibaba.higress.sdk.model.Route;
import com.alibaba.higress.sdk.model.WasmPluginInstanceScope;
import com.alibaba.higress.sdk.model.ai.AiRoute;
import com.alibaba.higress.sdk.model.ai.AiRouteAuthConfig;
import com.alibaba.higress.sdk.model.ai.AiRouteFallbackConfig;
import com.alibaba.higress.sdk.model.ai.AiRouteFallbackStrategy;
import com.alibaba.higress.sdk.model.ai.AiUpstream;
import com.alibaba.higress.sdk.model.route.KeyedRoutePredicate;
import com.alibaba.higress.sdk.model.route.RoutePredicate;
import com.alibaba.higress.sdk.model.route.RoutePredicateTypeEnum;
import com.alibaba.higress.sdk.model.route.UpstreamService;
import com.alibaba.higress.sdk.service.RouteService;
import com.alibaba.higress.sdk.service.consumer.ConsumerService;
import com.alibaba.higress.sdk.service.kubernetes.KubernetesClientService;
import com.alibaba.higress.sdk.service.kubernetes.KubernetesModelConverter;
import com.alibaba.higress.sdk.service.kubernetes.crd.istio.V1alpha3EnvoyFilter;
@@ -62,15 +68,18 @@ public class AiRouteServiceImpl implements AiRouteService {

private final LlmProviderService llmProviderService;

private final ConsumerService consumerService;

private final String routeFallbackEnvoyFilterConfig;

public AiRouteServiceImpl(KubernetesModelConverter kubernetesModelConverter,
KubernetesClientService kubernetesClientService, RouteService routeService,
LlmProviderService llmProviderService) {
LlmProviderService llmProviderService, ConsumerService consumerService) {
this.kubernetesModelConverter = kubernetesModelConverter;
this.kubernetesClientService = kubernetesClientService;
this.routeService = routeService;
this.llmProviderService = llmProviderService;
this.consumerService = consumerService;

try {
this.routeFallbackEnvoyFilterConfig =
@@ -151,20 +160,23 @@ public AiRoute update(AiRoute route) {
}

writeAiRouteResources(route);
writeAiRouteFallbackResources(route);

return kubernetesModelConverter.configMap2AiRoute(updatedConfigMap);
}

private void writeAiRouteResources(AiRoute aiRoute) {
String routeName = aiRoute.getName() + HigressConstants.INTERNAL_RESOURCE_NAME_SUFFIX;
Route route = buildRoute(routeName, aiRoute);
setUpstreams(route, aiRoute.getUpstreams());
saveRoute(route);

writeAiRouteFallbackResources(aiRoute);
writeAuthConfigResources(routeName, aiRoute.getAuthConfig());
}

private void writeAiRouteFallbackResources(AiRoute aiRoute) {
if (aiRoute.getFallbackUpstream() == null || StringUtils.isEmpty(aiRoute.getFallbackUpstream().getProvider())) {
AiRouteFallbackConfig fallbackConfig = aiRoute.getFallbackConfig();
if (fallbackConfig == null || !Boolean.TRUE.equals(fallbackConfig.getEnabled())
|| CollectionUtils.isEmpty(fallbackConfig.getUpstreams())) {
return;
}

@@ -178,6 +190,17 @@ private void writeAiRouteFallbackResources(AiRoute aiRoute) {
fallbackHeaderPredicate.setMatchValue(originalRouteName);
fallbackHeaderPredicate.setCaseSensitive(true);
route.setHeaders(List.of(fallbackHeaderPredicate));
String fallbackStrategy = fallbackConfig.getFallbackStrategy();
List<AiUpstream> fallbackUpStreams;
if (StringUtils.isEmpty(fallbackStrategy) || AiRouteFallbackStrategy.RANDOM.equals(fallbackStrategy)) {
fallbackUpStreams = fallbackConfig.getUpstreams();
fallbackUpStreams.forEach(upstream -> upstream.setWeight(1));
} else if (AiRouteFallbackStrategy.SEQUENCE.equals(fallbackStrategy)) {
fallbackUpStreams = List.of(fallbackConfig.getUpstreams().get(0));
} else {
throw new BusinessException("Unknown fallback strategy: " + fallbackStrategy);
}
setUpstreams(route, fallbackUpStreams);
saveRoute(route);

StringBuilder envoyFilterBuilder = new StringBuilder(routeFallbackEnvoyFilterConfig);
@@ -199,26 +222,40 @@ private void writeAiRouteFallbackResources(AiRoute aiRoute) {
throw new BusinessException(
"Error occurs when writing the fallback EnvoyFilter for AI route: " + aiRoute.getName(), e);
}

writeAuthConfigResources(fallbackRouteName, aiRoute.getAuthConfig());
}

private void writeAuthConfigResources(String routeName, AiRouteAuthConfig authConfig) {
List<String> allowedConsumers = authConfig != null && Boolean.TRUE.equals(authConfig.getEnabled())
? authConfig.getAllowedConsumers() : List.of();
consumerService.updateAllowList(WasmPluginInstanceScope.ROUTE, routeName, allowedConsumers);
}

private Route buildRoute(String routeName, AiRoute aiRoute) {
Route route = new Route();
route.setName(routeName);
route.setPath(new RoutePredicate(RoutePredicateTypeEnum.PRE.name(), "/", true));
route.setDomains(aiRoute.getDomains());
if (aiRoute.getUpstreams() != null) {
List<UpstreamService> services = new ArrayList<>(aiRoute.getUpstreams().size());
for (AiUpstream upstream : aiRoute.getUpstreams()) {
UpstreamService service = llmProviderService.buildUpstreamService(upstream.getProvider());
service.setVersion(null);
service.setWeight(upstream.getWeight());
services.add(service);
}
route.setServices(services);
}
return route;
}

private void setUpstreams(Route route, List<AiUpstream> upstreams) {
if (CollectionUtils.isEmpty(upstreams)) {
route.setServices(List.of());
return;
}

List<UpstreamService> services = new ArrayList<>(upstreams.size());
for (AiUpstream upstream : upstreams) {
UpstreamService service = llmProviderService.buildUpstreamService(upstream.getProvider());
service.setVersion(null);
service.setWeight(upstream.getWeight());
services.add(service);
}
route.setServices(services);
}

private void deleteAiRouteResources(String aiRouteName) {
String routeName = aiRouteName + HigressConstants.INTERNAL_RESOURCE_NAME_SUFFIX;
routeService.delete(routeName);
Original file line number Diff line number Diff line change
@@ -12,8 +12,11 @@
*/
package com.alibaba.higress.sdk.service.consumer;

import java.util.List;

import com.alibaba.higress.sdk.model.CommonPageQuery;
import com.alibaba.higress.sdk.model.PaginatedResult;
import com.alibaba.higress.sdk.model.WasmPluginInstanceScope;
import com.alibaba.higress.sdk.model.consumer.Consumer;

public interface ConsumerService {
@@ -25,4 +28,6 @@ public interface ConsumerService {
Consumer query(String consumerName);

void delete(String consumerName);

void updateAllowList(WasmPluginInstanceScope scope, String target, List<String> consumerNames);
}
Original file line number Diff line number Diff line change
@@ -63,11 +63,7 @@ public Consumer addOrUpdate(Consumer consumer) {
if (plugin == null) {
throw new BusinessException("Plugin " + config.getPluginName() + " not found");
}
instance = new WasmPluginInstance();
instance.setPluginName(plugin.getName());
instance.setPluginVersion(plugin.getPluginVersion());
instance.setInternal(true);
instance.setScope(WasmPluginInstanceScope.GLOBAL);
instance = createInstance(WasmPluginInstanceScope.GLOBAL, null, config.getPluginName());
}
if (config.saveConsumer(instance, consumer)) {
instancesToUpdate.add(instance);
@@ -112,6 +108,18 @@ public void delete(String consumerName) {
}
}

@Override
public void updateAllowList(WasmPluginInstanceScope scope, String target, List<String> consumerNames) {
for (CredentialHandler config : CREDENTIAL_HANDLERS.values()) {
WasmPluginInstance instance = wasmPluginInstanceService.query(scope, target, config.getPluginName(), true);
if (instance == null) {
instance = createInstance(scope, target, config.getPluginName());
}
config.updateAllowList(instance, consumerNames);
wasmPluginInstanceService.addOrUpdate(instance);
}
}

private SortedMap<String, Consumer> getConsumers() {
SortedMap<String, Consumer> consumers = new TreeMap<>();
for (CredentialHandler config : CREDENTIAL_HANDLERS.values()) {
@@ -130,4 +138,18 @@ private SortedMap<String, Consumer> getConsumers() {
}
return consumers;
}

private WasmPluginInstance createInstance(WasmPluginInstanceScope scope, String target, String pluginName) {
WasmPlugin plugin = wasmPluginService.query(pluginName, null);
if (plugin == null) {
throw new BusinessException("Plugin " + pluginName + " not found");
}
WasmPluginInstance instance = new WasmPluginInstance();
instance.setPluginName(plugin.getName());
instance.setPluginVersion(plugin.getPluginVersion());
instance.setInternal(true);
instance.setScope(scope);
instance.setTarget(target);
return instance;
}
}
Original file line number Diff line number Diff line change
@@ -12,11 +12,11 @@
*/
package com.alibaba.higress.sdk.service.consumer;

import java.util.List;

import com.alibaba.higress.sdk.model.WasmPluginInstance;
import com.alibaba.higress.sdk.model.consumer.Consumer;

import java.util.List;

interface CredentialHandler {

String getType();
@@ -30,4 +30,6 @@ interface CredentialHandler {
boolean saveConsumer(WasmPluginInstance instance, Consumer consumer);

boolean deleteConsumer(WasmPluginInstance globalInstance, String consumerName);

void updateAllowList(WasmPluginInstance instance, List<String> consumerNames);
}
Original file line number Diff line number Diff line change
@@ -35,7 +35,7 @@ class KeyAuthCredentialHandler implements CredentialHandler {
private static final String NAME_KEY = "name";
private static final String IN_HEADER_KEY = "in_header";
private static final String IN_QUERY_KEY = "in_query";
private static final String KEY_KEY = "key";
private static final String KEYS_KEY = "keys";
private static final String CREDENTIAL_KEY = "credential";
private static final String ALLOW_KEY = "allow";

@@ -124,6 +124,10 @@ public boolean saveConsumer(WasmPluginInstance instance, Consumer consumer) {
instance.setConfigurations(configurations);
}

// TODO: Remove this after plugin upgrade.
// Add a dummy key to the global keys list because the plugin requires at least one global key.
configurations.put(KEYS_KEY, List.of("x-higress-dummy-key"));

Object consumersObj = configurations.computeIfAbsent(CONSUMERS_KEY, k -> new ArrayList<>());
List<Object> consumers;
if (consumersObj instanceof List) {
@@ -177,7 +181,7 @@ public boolean saveConsumer(WasmPluginInstance instance, Consumer consumer) {
throw new IllegalArgumentException(
"Unsupported key auth credential source: " + keyAuthCredential.getSource());
}
consumerConfig.put(KEY_KEY, List.of(key));
consumerConfig.put(KEYS_KEY, List.of(key));
consumerConfig.put(CREDENTIAL_KEY, credential);

configurations.put(CONSUMERS_KEY, consumers);
@@ -211,6 +215,21 @@ public boolean deleteConsumer(WasmPluginInstance globalInstance, String consumer
return deleted;
}

@Override
public void updateAllowList(WasmPluginInstance instance, List<String> consumerNames) {
Map<String, Object> configurations = instance.getConfigurations();
if (MapUtils.isEmpty(configurations)) {
configurations = new HashMap<>();
instance.setConfigurations(configurations);
}

if (CollectionUtils.isEmpty(consumerNames)) {
configurations.remove(ALLOW_KEY);
} else {
configurations.put(ALLOW_KEY, new ArrayList<>(consumerNames));
}
}

private KeyAuthCredential mergeExistedConfig(KeyAuthCredential keyAuthCredential,
Map<String, Object> consumerConfig) {
KeyAuthCredential existedCredential = parseCredential(consumerConfig);
@@ -230,7 +249,7 @@ private static KeyAuthCredential parseCredential(Map<String, Object> consumerMap
return null;
}

Object keyObj = MapUtils.getObject(consumerMap, KEY_KEY);
Object keyObj = MapUtils.getObject(consumerMap, KEYS_KEY);
if (!(keyObj instanceof List<?> keyList) || keyList.isEmpty()) {
return null;
}

Unchanged files with check annotations Beta

formRef.current && formRef.current.reset();
refresh();
} catch (errInfo) {
console.log('Save failed: ', errInfo);

Check warning on line 110 in frontend/src/pages/ai/provider.tsx

GitHub Actions / build (16.x)

Unexpected console statement
}
};
formRef.current && formRef.current.reset();
refresh();
} catch (errInfo) {
console.log('Save failed: ', errInfo);

Check warning on line 139 in frontend/src/pages/ai/route.tsx

GitHub Actions / build (16.x)

Unexpected console statement
}
};