From 7041b3c82504b2aa534be9a93c08276d2237917b Mon Sep 17 00:00:00 2001 From: LIlGG <1103069291@qq.com> Date: Wed, 17 Jun 2026 00:13:27 +0800 Subject: [PATCH] fix: tolerate null legacy chat settings --- .../run/halo/live2d/agent/AgentSettings.java | 39 +++++++++++---- .../run/halo/live2d/chat/AiChatEndpoint.java | 4 +- .../live2d/agent/AgentToolNormalizerTest.java | 50 +++++++++++++++++++ .../halo/live2d/chat/AiChatEndpointTest.java | 47 +++++++++++++++++ 4 files changed, 128 insertions(+), 12 deletions(-) create mode 100644 src/test/java/run/halo/live2d/chat/AiChatEndpointTest.java diff --git a/src/main/java/run/halo/live2d/agent/AgentSettings.java b/src/main/java/run/halo/live2d/agent/AgentSettings.java index d372294..5e45081 100644 --- a/src/main/java/run/halo/live2d/agent/AgentSettings.java +++ b/src/main/java/run/halo/live2d/agent/AgentSettings.java @@ -53,13 +53,17 @@ public List normalizedAiTools() { @JsonIgnoreProperties(ignoreUnknown = true) public record AgentBuiltInCapabilities( - boolean pageContext, - boolean haloNavigation, - boolean haloContentSearch, - boolean networkAccess, + Boolean pageContext, + Boolean haloNavigation, + Boolean haloContentSearch, + Boolean networkAccess, AgentCommentCapability commentCapability ) { public AgentBuiltInCapabilities { + pageContext = pageContext == null ? true : pageContext; + haloNavigation = haloNavigation == null ? true : haloNavigation; + haloContentSearch = haloContentSearch == null ? true : haloContentSearch; + networkAccess = networkAccess == null ? false : networkAccess; commentCapability = commentCapability == null ? AgentCommentCapability.ASSIST : commentCapability; @@ -74,8 +78,12 @@ public static AgentBuiltInCapabilities defaults() { @JsonIgnoreProperties(ignoreUnknown = true) public record AgentToolSecurity( Object allowedExternalOrigins, - boolean allowNewTab + Boolean allowNewTab ) { + public AgentToolSecurity { + allowNewTab = allowNewTab == null ? false : allowNewTab; + } + public static AgentToolSecurity defaults() { return new AgentToolSecurity(List.of(), false); } @@ -88,8 +96,12 @@ public List normalizedAllowedExternalOrigins() { @JsonIgnoreProperties(ignoreUnknown = true) public record AgentHaloSearchSettings( List allowedTypes, - int defaultLimit + Integer defaultLimit ) { + public AgentHaloSearchSettings { + defaultLimit = defaultLimit == null ? 5 : defaultLimit; + } + public static AgentHaloSearchSettings defaults() { return new AgentHaloSearchSettings(List.of(), 5); } @@ -108,9 +120,10 @@ public int normalizedDefaultLimit() { @JsonIgnoreProperties(ignoreUnknown = true) public record AgentHaloResourceDetailSettings( - int maxContentChars + Integer maxContentChars ) { public AgentHaloResourceDetailSettings { + maxContentChars = maxContentChars == null ? 3000 : maxContentChars; if (maxContentChars < 500) { maxContentChars = 3000; } @@ -127,9 +140,14 @@ public static AgentHaloResourceDetailSettings defaults() { @JsonIgnoreProperties(ignoreUnknown = true) public record AgentNetworkAccessSettings( Object allowedOrigins, - int maxResponseChars, - int timeoutSeconds + Integer maxResponseChars, + Integer timeoutSeconds ) { + public AgentNetworkAccessSettings { + maxResponseChars = maxResponseChars == null ? 4000 : maxResponseChars; + timeoutSeconds = timeoutSeconds == null ? 5 : timeoutSeconds; + } + public static AgentNetworkAccessSettings defaults() { return new AgentNetworkAccessSettings(List.of(), 4000, 5); } @@ -152,7 +170,7 @@ public int normalizedTimeoutSeconds() { @JsonIgnoreProperties(ignoreUnknown = true) public record AgentToolConfig( String name, - boolean enabled, + Boolean enabled, String description, JsonNode inputSchema, AgentToolApproval approval, @@ -161,6 +179,7 @@ public record AgentToolConfig( JsonNode testInput ) { public AgentToolConfig { + enabled = enabled == null ? false : enabled; approval = approval == null ? AgentToolApproval.DEFAULT : approval; requiredAuth = requiredAuth == null ? AgentToolAuth.NONE : requiredAuth; } diff --git a/src/main/java/run/halo/live2d/chat/AiChatEndpoint.java b/src/main/java/run/halo/live2d/chat/AiChatEndpoint.java index 5d3c8c8..b731f8a 100644 --- a/src/main/java/run/halo/live2d/chat/AiChatEndpoint.java +++ b/src/main/java/run/halo/live2d/chat/AiChatEndpoint.java @@ -167,7 +167,7 @@ record AiChatConfig(boolean isAiChat, AiChatBaseSetting aiChatBaseSetting) { } } - record AiChatBaseSetting(boolean isAnonymous, String accessMode, String systemMessage, + record AiChatBaseSetting(Boolean isAnonymous, String accessMode, String systemMessage, String modelName) { AiChatBaseSetting { if (StringUtils.isBlank(systemMessage)) { @@ -179,7 +179,7 @@ record AiChatBaseSetting(boolean isAnonymous, String accessMode, String systemMe } AgentAccessMode resolvedAccessMode() { - return AgentAccessMode.from(accessMode, isAnonymous); + return AgentAccessMode.from(accessMode, Boolean.TRUE.equals(isAnonymous)); } } diff --git a/src/test/java/run/halo/live2d/agent/AgentToolNormalizerTest.java b/src/test/java/run/halo/live2d/agent/AgentToolNormalizerTest.java index 331dece..2d65bb3 100644 --- a/src/test/java/run/halo/live2d/agent/AgentToolNormalizerTest.java +++ b/src/test/java/run/halo/live2d/agent/AgentToolNormalizerTest.java @@ -49,6 +49,56 @@ void mapsFormValuesToAgentEnums() throws Exception { .contains("\"commentCapability\":\"assist\""); } + @Test + void mapsNullPrimitiveAgentSettingsToDefaults() throws Exception { + var settings = objectMapper.readValue( + """ + { + "builtIn": { + "pageContext": null, + "haloNavigation": null, + "haloContentSearch": null, + "networkAccess": null, + "commentCapability": null + }, + "toolSecurity": { + "allowNewTab": null + }, + "haloSearch": { + "defaultLimit": null + }, + "haloResourceDetail": { + "maxContentChars": null + }, + "networkAccess": { + "maxResponseChars": null, + "timeoutSeconds": null + }, + "aiTools": [{ + "name": "open_contact_form", + "enabled": null, + "description": "打开留言面板", + "action": { + "type": "registered" + } + }] + } + """, + AgentSettings.class); + + assertThat(settings.builtIn().pageContext()).isTrue(); + assertThat(settings.builtIn().haloNavigation()).isTrue(); + assertThat(settings.builtIn().haloContentSearch()).isTrue(); + assertThat(settings.builtIn().networkAccess()).isFalse(); + assertThat(settings.builtIn().commentCapability()).isEqualTo(AgentCommentCapability.ASSIST); + assertThat(settings.toolSecurity().allowNewTab()).isFalse(); + assertThat(settings.haloSearch().normalizedDefaultLimit()).isEqualTo(5); + assertThat(settings.haloResourceDetail().maxContentChars()).isEqualTo(3000); + assertThat(settings.networkAccess().normalizedMaxResponseChars()).isEqualTo(4000); + assertThat(settings.networkAccess().normalizedTimeoutSeconds()).isEqualTo(5); + assertThat(settings.normalizedAiTools().getFirst().enabled()).isFalse(); + } + @Test void normalizesValidCustomTool() throws Exception { var settings = new AgentSettings( diff --git a/src/test/java/run/halo/live2d/chat/AiChatEndpointTest.java b/src/test/java/run/halo/live2d/chat/AiChatEndpointTest.java new file mode 100644 index 0000000..f55a077 --- /dev/null +++ b/src/test/java/run/halo/live2d/chat/AiChatEndpointTest.java @@ -0,0 +1,47 @@ +package run.halo.live2d.chat; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import run.halo.live2d.agent.AgentAccessMode; + +class AiChatEndpointTest { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void mapsNullLegacyAnonymousSettingToAuthenticatedChat() throws Exception { + var config = objectMapper.readValue(""" + { + "isAiChat": true, + "aiChatBaseSetting": { + "isAnonymous": null, + "systemMessage": "system", + "modelName": "model" + } + } + """, AiChatEndpoint.AiChatConfig.class); + + assertThat(config.aiChatBaseSetting().resolvedAccessMode()) + .isEqualTo(AgentAccessMode.AUTHENTICATED_CHAT); + } + + @Test + void accessModeTakesPrecedenceOverNullLegacyAnonymousSetting() throws Exception { + var config = objectMapper.readValue(""" + { + "isAiChat": true, + "aiChatBaseSetting": { + "isAnonymous": null, + "accessMode": "anonymous_chat", + "systemMessage": "system", + "modelName": "model" + } + } + """, AiChatEndpoint.AiChatConfig.class); + + assertThat(config.aiChatBaseSetting().resolvedAccessMode()) + .isEqualTo(AgentAccessMode.ANONYMOUS_CHAT); + } +}