From 53c36ad1e8fe1ef373713c34515deba179316f6e Mon Sep 17 00:00:00 2001 From: fuzi1996 Date: Thu, 29 Jan 2026 21:11:34 +0800 Subject: [PATCH 1/2] Fix Windows permission mode issue with newline characters in system prompts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When systemPrompt or appendSystemPrompt contains newline characters on Windows, the PermissionMode was not being applied correctly. The issue was that command line arguments with newlines were not properly normalized for the Windows CLI. Changes: - Add normalizeNewline() method to convert newlines to platform-appropriate line continuation characters (Windows uses ^, Unix uses \) - Add platform detection static initialization for Windows - Apply normalization to both systemPrompt and appendSystemPrompt arguments - Add comprehensive integration tests for various newline scenarios This resolves Issue #7 where PermissionMode defaulted to 'default' instead of the configured 'bypassPermissions' when systemPrompt contained newlines. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../sdk/transport/StreamingTransport.java | 35 +- .../claude/agent/sdk/issues/Issues7.java | 389 ++++++++++++++++++ 2 files changed, 422 insertions(+), 2 deletions(-) create mode 100644 claude-code-sdk/src/test/java/org/springaicommunity/claude/agent/sdk/issues/Issues7.java diff --git a/claude-code-sdk/src/main/java/org/springaicommunity/claude/agent/sdk/transport/StreamingTransport.java b/claude-code-sdk/src/main/java/org/springaicommunity/claude/agent/sdk/transport/StreamingTransport.java index d2f13d8c..57d9141d 100644 --- a/claude-code-sdk/src/main/java/org/springaicommunity/claude/agent/sdk/transport/StreamingTransport.java +++ b/claude-code-sdk/src/main/java/org/springaicommunity/claude/agent/sdk/transport/StreamingTransport.java @@ -83,6 +83,12 @@ public class StreamingTransport implements AutoCloseable { // State Machine Constants // ============================================================ + // 缓存平台判断结果 + private static boolean isWindows; + static { + isWindows = System.getProperty("os.name").toLowerCase().contains("win"); + } + /** Transport is created but not connected */ public static final int STATE_DISCONNECTED = 0; @@ -418,7 +424,7 @@ List buildStreamingCommand(CLIOptions options) { // Note: --append-system-prompt adds to the default, --system-prompt replaces it if (options.getSystemPrompt() != null) { command.add("--system-prompt"); - command.add(options.getSystemPrompt()); + command.add(this.normalizeNewline(options.getSystemPrompt())); } // Handle --tools option (base set of tools) - added in Python SDK v0.1.10 @@ -539,7 +545,7 @@ List buildStreamingCommand(CLIOptions options) { // Add append system prompt (uses preset mode with append) if (options.getAppendSystemPrompt() != null && !options.getAppendSystemPrompt().isEmpty()) { command.add("--append-system-prompt"); - command.add(options.getAppendSystemPrompt()); + command.add(this.normalizeNewline(options.getAppendSystemPrompt())); } // ============================================================ @@ -608,6 +614,31 @@ List buildStreamingCommand(CLIOptions options) { return command; } + private String normalizeNewline(String command) { + if (command == null || command.isEmpty()) { + return ""; + } + + // 第一步:统一将 \r\n、\r 转换为 \n + String unifiedCommand = command.replaceAll("\r\n?", "\n"); + + // 第二步:去除每行首尾空白,避免 ^ 后带空格 + String[] lines = unifiedCommand.split("\n"); + StringBuilder sb = new StringBuilder(); + for (String line : lines) { + String trimmedLine = line.trim(); + if (!trimmedLine.isEmpty()) { + sb.append(trimmedLine); + // 第三步:根据平台添加命令行连接符(最后一行不加) + if (!line.equals(lines[lines.length - 1])) { + sb.append(isWindows ? "^" : "\\"); + } + } + } + + return sb.toString(); + } + /** * Builds the MCP config map for CLI serialization. SDK servers have their instances * stripped (not serializable); only type and name are passed. diff --git a/claude-code-sdk/src/test/java/org/springaicommunity/claude/agent/sdk/issues/Issues7.java b/claude-code-sdk/src/test/java/org/springaicommunity/claude/agent/sdk/issues/Issues7.java new file mode 100644 index 00000000..680ca64b --- /dev/null +++ b/claude-code-sdk/src/test/java/org/springaicommunity/claude/agent/sdk/issues/Issues7.java @@ -0,0 +1,389 @@ +/* + * Copyright 2025 Spring AI Community + * + * 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 + * + * https://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 org.springaicommunity.claude.agent.sdk.issues; + +import org.junit.jupiter.api.*; +import org.springaicommunity.claude.agent.sdk.ClaudeClient; +import org.springaicommunity.claude.agent.sdk.ClaudeSyncClient; +import org.springaicommunity.claude.agent.sdk.config.PermissionMode; +import org.springaicommunity.claude.agent.sdk.parsing.ParsedMessage; +import org.springaicommunity.claude.agent.sdk.types.SystemMessage; + +import java.nio.file.Path; +import java.util.Iterator; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +/** + * Issue #7: PermissionMode does not work correctly when systemPrompt contains newline character on Windows. + * + *

Problem Description:

+ * When using {@code systemPrompt} with a newline character ({@code \n}) on Windows, + * the {@code PermissionMode} is not applied correctly and defaults to {@code default} + * instead of the configured {@code bypassPermissions}. + * + *

Test Scenarios:

+ *
    + *
  • System prompt without newline: works correctly
  • + *
  • System prompt with newline: fails on Windows (should return bypassPermissions but returns default)
  • + *
+ * + * @see Issue #7 + */ +@DisplayName("Issue #7: PermissionMode with newline in systemPrompt on Windows") +public class Issues7 { + +// public static final String MODEL_HAIKU = "claude-haiku-4-5-20251001"; + public static final String MODEL_HAIKU = "glm-4.7"; + private static final String SYSTEM_PROMPT_WITHOUT_NEWLINE = "You are an AI assistant."; + private static final String SYSTEM_PROMPT_WITH_NEWLINE = "You are an AI assistant.\n"; + private static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().contains("win"); + + @Nested + @DisplayName("On Windows system") + class WindowsTests { + + @BeforeEach + void assumeWindows() { + assumeTrue(IS_WINDOWS, + "These tests should only run on Windows. Current OS: " + System.getProperty("os.name")); + } + + @Test + @DisplayName("should apply bypassPermissions when systemPrompt contains single newline character") + void shouldApplyBypassPermissionsWhenSystemPromptContainsSingleNewline() { + try (ClaudeSyncClient client = ClaudeClient.sync() + .workingDirectory(Path.of(".")) + .model(MODEL_HAIKU) + .systemPrompt(SYSTEM_PROMPT_WITH_NEWLINE) + .permissionMode(PermissionMode.BYPASS_PERMISSIONS) + .build()) { + + client.connect("hi"); + Iterator response = client.receiveResponse(); + + boolean foundSystemMessage = false; + while (response.hasNext()) { + ParsedMessage msg = response.next(); + if (msg.isRegularMessage() && msg.asMessage() instanceof SystemMessage system) { + String permissionMode = (String) system.data().get("permissionMode"); + assertThat(permissionMode) + .as("PermissionMode should be 'bypassPermissions' even when systemPrompt contains single newline") + .isEqualTo("bypassPermissions"); + foundSystemMessage = true; + } + } + + assertThat(foundSystemMessage) + .as("Should have found a SystemMessage in the response") + .isTrue(); + } + } + + @Test + @DisplayName("should apply bypassPermissions when systemPrompt does not contain newline character") + void shouldApplyBypassPermissionsWhenSystemPromptDoesNotContainNewline() { + try (ClaudeSyncClient client = ClaudeClient.sync() + .workingDirectory(Path.of(".")) + .model(MODEL_HAIKU) + .systemPrompt(SYSTEM_PROMPT_WITHOUT_NEWLINE) + .permissionMode(PermissionMode.BYPASS_PERMISSIONS) + .build()) { + + client.connect("hi"); + Iterator response = client.receiveResponse(); + + boolean foundSystemMessage = false; + while (response.hasNext()) { + ParsedMessage msg = response.next(); + if (msg.isRegularMessage() && msg.asMessage() instanceof SystemMessage system) { + String permissionMode = (String) system.data().get("permissionMode"); + assertThat(permissionMode) + .as("PermissionMode should be 'bypassPermissions' when systemPrompt has no newline") + .isEqualTo("bypassPermissions"); + foundSystemMessage = true; + } + } + + assertThat(foundSystemMessage) + .as("Should have found a SystemMessage in the response") + .isTrue(); + } + } + + @Test + @DisplayName("should apply bypassPermissions when systemPrompt contains multiple newline characters") + void shouldApplyBypassPermissionsWhenSystemPromptContainsMultipleNewlines() { + String systemPromptWithMultipleNewlines = "You are an AI assistant.\n\nBehave helpfully.\n"; + + try (ClaudeSyncClient client = ClaudeClient.sync() + .workingDirectory(Path.of(".")) + .model(MODEL_HAIKU) + .systemPrompt(systemPromptWithMultipleNewlines) + .permissionMode(PermissionMode.BYPASS_PERMISSIONS) + .build()) { + + client.connect("hi"); + Iterator response = client.receiveResponse(); + + boolean foundSystemMessage = false; + while (response.hasNext()) { + ParsedMessage msg = response.next(); + if (msg.isRegularMessage() && msg.asMessage() instanceof SystemMessage system) { + String permissionMode = (String) system.data().get("permissionMode"); + assertThat(permissionMode) + .as("PermissionMode should be 'bypassPermissions' even when systemPrompt contains multiple newlines") + .isEqualTo("bypassPermissions"); + foundSystemMessage = true; + } + } + + assertThat(foundSystemMessage) + .as("Should have found a SystemMessage in the response") + .isTrue(); + } + } + + @Test + @DisplayName("should apply bypassPermissions when systemPrompt contains newline in the middle") + void shouldApplyBypassPermissionsWhenSystemPromptContainsNewlineInMiddle() { + String systemPromptWithNewlineInMiddle = "You are an\nAI assistant."; + + try (ClaudeSyncClient client = ClaudeClient.sync() + .workingDirectory(Path.of(".")) + .model(MODEL_HAIKU) + .systemPrompt(systemPromptWithNewlineInMiddle) + .permissionMode(PermissionMode.BYPASS_PERMISSIONS) + .build()) { + + client.connect("hi"); + Iterator response = client.receiveResponse(); + + boolean foundSystemMessage = false; + while (response.hasNext()) { + ParsedMessage msg = response.next(); + if (msg.isRegularMessage() && msg.asMessage() instanceof SystemMessage system) { + String permissionMode = (String) system.data().get("permissionMode"); + assertThat(permissionMode) + .as("PermissionMode should be 'bypassPermissions' when systemPrompt contains newline in the middle") + .isEqualTo("bypassPermissions"); + foundSystemMessage = true; + } + } + + assertThat(foundSystemMessage) + .as("Should have found a SystemMessage in the response") + .isTrue(); + } + } + + @Test + @DisplayName("should apply bypassPermissions when systemPrompt contains Windows line separator") + void shouldApplyBypassPermissionsWhenSystemPromptContainsWindowsLineSeparator() { + String systemPromptWithWindowsSeparator = "You are an AI assistant.\r\n"; + + try (ClaudeSyncClient client = ClaudeClient.sync() + .workingDirectory(Path.of(".")) + .model(MODEL_HAIKU) + .systemPrompt(systemPromptWithWindowsSeparator) + .permissionMode(PermissionMode.BYPASS_PERMISSIONS) + .build()) { + + client.connect("hi"); + Iterator response = client.receiveResponse(); + + boolean foundSystemMessage = false; + while (response.hasNext()) { + ParsedMessage msg = response.next(); + if (msg.isRegularMessage() && msg.asMessage() instanceof SystemMessage system) { + String permissionMode = (String) system.data().get("permissionMode"); + assertThat(permissionMode) + .as("PermissionMode should be 'bypassPermissions' when systemPrompt contains Windows line separator (\\r\\n)") + .isEqualTo("bypassPermissions"); + foundSystemMessage = true; + } + } + + assertThat(foundSystemMessage) + .as("Should have found a SystemMessage in the response") + .isTrue(); + } + } + + @Test + @DisplayName("should apply bypassPermissions without systemPrompt") + void shouldApplyBypassPermissionsWithoutSystemPrompt() { + try (ClaudeSyncClient client = ClaudeClient.sync() + .workingDirectory(Path.of(".")) + .model(MODEL_HAIKU) + .permissionMode(PermissionMode.BYPASS_PERMISSIONS) + .build()) { + + client.connect("hi"); + Iterator response = client.receiveResponse(); + + boolean foundSystemMessage = false; + while (response.hasNext()) { + ParsedMessage msg = response.next(); + if (msg.isRegularMessage() && msg.asMessage() instanceof SystemMessage system) { + String permissionMode = (String) system.data().get("permissionMode"); + assertThat(permissionMode) + .as("PermissionMode should be 'bypassPermissions' when no systemPrompt is set") + .isEqualTo("bypassPermissions"); + foundSystemMessage = true; + } + } + + assertThat(foundSystemMessage) + .as("Should have found a SystemMessage in the response") + .isTrue(); + } + } + + @Test + @DisplayName("should apply bypassPermissions when appendSystemPrompt contains newline character") + void shouldApplyBypassPermissionsWhenAppendSystemPromptContainsNewline() { + String appendSystemPromptWithNewline = "Be concise and helpful.\n"; + + try (ClaudeSyncClient client = ClaudeClient.sync() + .workingDirectory(Path.of(".")) + .model(MODEL_HAIKU) + .appendSystemPrompt(appendSystemPromptWithNewline) + .permissionMode(PermissionMode.BYPASS_PERMISSIONS) + .build()) { + + client.connect("hi"); + Iterator response = client.receiveResponse(); + + boolean foundSystemMessage = false; + while (response.hasNext()) { + ParsedMessage msg = response.next(); + if (msg.isRegularMessage() && msg.asMessage() instanceof SystemMessage system) { + String permissionMode = (String) system.data().get("permissionMode"); + assertThat(permissionMode) + .as("PermissionMode should be 'bypassPermissions' when appendSystemPrompt contains newline") + .isEqualTo("bypassPermissions"); + foundSystemMessage = true; + } + } + + assertThat(foundSystemMessage) + .as("Should have found a SystemMessage in the response") + .isTrue(); + } + } + + @Test + @DisplayName("should apply bypassPermissions when appendSystemPrompt does not contain newline character") + void shouldApplyBypassPermissionsWhenAppendSystemPromptDoesNotContainNewline() { + String appendSystemPromptWithoutNewline = "Be concise and helpful."; + + try (ClaudeSyncClient client = ClaudeClient.sync() + .workingDirectory(Path.of(".")) + .model(MODEL_HAIKU) + .appendSystemPrompt(appendSystemPromptWithoutNewline) + .permissionMode(PermissionMode.BYPASS_PERMISSIONS) + .build()) { + + client.connect("hi"); + Iterator response = client.receiveResponse(); + + boolean foundSystemMessage = false; + while (response.hasNext()) { + ParsedMessage msg = response.next(); + if (msg.isRegularMessage() && msg.asMessage() instanceof SystemMessage system) { + String permissionMode = (String) system.data().get("permissionMode"); + assertThat(permissionMode) + .as("PermissionMode should be 'bypassPermissions' when appendSystemPrompt has no newline") + .isEqualTo("bypassPermissions"); + foundSystemMessage = true; + } + } + + assertThat(foundSystemMessage) + .as("Should have found a SystemMessage in the response") + .isTrue(); + } + } + + @Test + @DisplayName("should apply bypassPermissions when both systemPrompt and appendSystemPrompt contain newlines") + void shouldApplyBypassPermissionsWhenBothSystemPromptAndAppendSystemPromptContainNewlines() { + try (ClaudeSyncClient client = ClaudeClient.sync() + .workingDirectory(Path.of(".")) + .model(MODEL_HAIKU) + .systemPrompt(SYSTEM_PROMPT_WITH_NEWLINE) + .appendSystemPrompt("Be concise.\n") + .permissionMode(PermissionMode.BYPASS_PERMISSIONS) + .build()) { + + client.connect("hi"); + Iterator response = client.receiveResponse(); + + boolean foundSystemMessage = false; + while (response.hasNext()) { + ParsedMessage msg = response.next(); + if (msg.isRegularMessage() && msg.asMessage() instanceof SystemMessage system) { + String permissionMode = (String) system.data().get("permissionMode"); + assertThat(permissionMode) + .as("PermissionMode should be 'bypassPermissions' when both systemPrompt and appendSystemPrompt contain newlines") + .isEqualTo("bypassPermissions"); + foundSystemMessage = true; + } + } + + assertThat(foundSystemMessage) + .as("Should have found a SystemMessage in the response") + .isTrue(); + } + } + + @Test + @DisplayName("should apply bypassPermissions when appendSystemPrompt contains Windows line separator") + void shouldApplyBypassPermissionsWhenAppendSystemPromptContainsWindowsLineSeparator() { + String appendSystemPromptWithWindowsSeparator = "Be concise and helpful.\r\n"; + + try (ClaudeSyncClient client = ClaudeClient.sync() + .workingDirectory(Path.of(".")) + .model(MODEL_HAIKU) + .appendSystemPrompt(appendSystemPromptWithWindowsSeparator) + .permissionMode(PermissionMode.BYPASS_PERMISSIONS) + .build()) { + + client.connect("hi"); + Iterator response = client.receiveResponse(); + + boolean foundSystemMessage = false; + while (response.hasNext()) { + ParsedMessage msg = response.next(); + if (msg.isRegularMessage() && msg.asMessage() instanceof SystemMessage system) { + String permissionMode = (String) system.data().get("permissionMode"); + assertThat(permissionMode) + .as("PermissionMode should be 'bypassPermissions' when appendSystemPrompt contains Windows line separator (\\r\\n)") + .isEqualTo("bypassPermissions"); + foundSystemMessage = true; + } + } + + assertThat(foundSystemMessage) + .as("Should have found a SystemMessage in the response") + .isTrue(); + } + } + } +} From 57473504360b6e13e1510691da2e6f90fa2eb8e5 Mon Sep 17 00:00:00 2001 From: fuzi1996 Date: Fri, 30 Jan 2026 21:27:18 +0800 Subject: [PATCH 2/2] Simplify Windows command normalization and add text block test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Simplify normalizeWindowsCommand to directly replace newlines with spaces on Windows - Add test case for systemPrompt with text blocks containing newlines - Remove complex multi-line command processing logic in favor of simpler approach 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../sdk/transport/StreamingTransport.java | 22 ++----- .../claude/agent/sdk/issues/Issues7.java | 58 ++++++++++++++++++- 2 files changed, 60 insertions(+), 20 deletions(-) diff --git a/claude-code-sdk/src/main/java/org/springaicommunity/claude/agent/sdk/transport/StreamingTransport.java b/claude-code-sdk/src/main/java/org/springaicommunity/claude/agent/sdk/transport/StreamingTransport.java index 57d9141d..5d68c609 100644 --- a/claude-code-sdk/src/main/java/org/springaicommunity/claude/agent/sdk/transport/StreamingTransport.java +++ b/claude-code-sdk/src/main/java/org/springaicommunity/claude/agent/sdk/transport/StreamingTransport.java @@ -83,7 +83,6 @@ public class StreamingTransport implements AutoCloseable { // State Machine Constants // ============================================================ - // 缓存平台判断结果 private static boolean isWindows; static { isWindows = System.getProperty("os.name").toLowerCase().contains("win"); @@ -619,24 +618,11 @@ private String normalizeNewline(String command) { return ""; } - // 第一步:统一将 \r\n、\r 转换为 \n - String unifiedCommand = command.replaceAll("\r\n?", "\n"); - - // 第二步:去除每行首尾空白,避免 ^ 后带空格 - String[] lines = unifiedCommand.split("\n"); - StringBuilder sb = new StringBuilder(); - for (String line : lines) { - String trimmedLine = line.trim(); - if (!trimmedLine.isEmpty()) { - sb.append(trimmedLine); - // 第三步:根据平台添加命令行连接符(最后一行不加) - if (!line.equals(lines[lines.length - 1])) { - sb.append(isWindows ? "^" : "\\"); - } - } + if(isWindows){ + return command.replaceAll("\r\n?", "\n").replaceAll("\n", " "); + }else{ + return command; } - - return sb.toString(); } /** diff --git a/claude-code-sdk/src/test/java/org/springaicommunity/claude/agent/sdk/issues/Issues7.java b/claude-code-sdk/src/test/java/org/springaicommunity/claude/agent/sdk/issues/Issues7.java index 680ca64b..9ecb37ed 100644 --- a/claude-code-sdk/src/test/java/org/springaicommunity/claude/agent/sdk/issues/Issues7.java +++ b/claude-code-sdk/src/test/java/org/springaicommunity/claude/agent/sdk/issues/Issues7.java @@ -21,6 +21,7 @@ import org.springaicommunity.claude.agent.sdk.ClaudeSyncClient; import org.springaicommunity.claude.agent.sdk.config.PermissionMode; import org.springaicommunity.claude.agent.sdk.parsing.ParsedMessage; +import org.springaicommunity.claude.agent.sdk.types.AssistantMessage; import org.springaicommunity.claude.agent.sdk.types.SystemMessage; import java.nio.file.Path; @@ -48,8 +49,7 @@ @DisplayName("Issue #7: PermissionMode with newline in systemPrompt on Windows") public class Issues7 { -// public static final String MODEL_HAIKU = "claude-haiku-4-5-20251001"; - public static final String MODEL_HAIKU = "glm-4.7"; + public static final String MODEL_HAIKU = "claude-haiku-4-5-20251001"; private static final String SYSTEM_PROMPT_WITHOUT_NEWLINE = "You are an AI assistant."; private static final String SYSTEM_PROMPT_WITH_NEWLINE = "You are an AI assistant.\n"; private static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().contains("win"); @@ -385,5 +385,59 @@ void shouldApplyBypassPermissionsWhenAppendSystemPromptContainsWindowsLineSepara .isTrue(); } } + + @Test + @DisplayName("should return correct JSON format when systemPrompt contains text block with newlines") + void shouldReturnCorrectJsonFormatWhenSystemPromptContainsTextBlockWithNewlines() { + String systemPromptTextBlock = """ + If you receive "hi", return a strict JSON string: + ```json + { + "result": "hi" + } + ``` + """; + + try (ClaudeSyncClient client = ClaudeClient.sync() + .workingDirectory(Path.of(".")) + .model(MODEL_HAIKU) + .systemPrompt(systemPromptTextBlock) + .permissionMode(PermissionMode.BYPASS_PERMISSIONS) + .build()) { + + client.connect("hi"); + Iterator response = client.receiveResponse(); + + boolean foundAssistantMessage = false; + boolean foundSystemMessage = false; + + while (response.hasNext()) { + ParsedMessage msg = response.next(); + + if (msg.isRegularMessage() && msg.asMessage() instanceof SystemMessage system) { + String permissionMode = (String) system.data().get("permissionMode"); + assertThat(permissionMode) + .as("PermissionMode should be 'bypassPermissions' even when systemPrompt contains text block with newlines") + .isEqualTo("bypassPermissions"); + foundSystemMessage = true; + } + + if (msg.isRegularMessage() && msg.asMessage() instanceof AssistantMessage assistantMessage) { + assertThat(assistantMessage.toString().replaceAll("\n|\r\n|\s+", "")) + .as("Should return the specified JSON format") + .isEqualTo("```json{\"result\":\"hi\"}```"); + foundAssistantMessage = true; + } + } + + assertThat(foundSystemMessage) + .as("Should have found a SystemMessage in the response") + .isTrue(); + + assertThat(foundAssistantMessage) + .as("Should have found an AssistantMessage in the response") + .isTrue(); + } + } } }