From 9a23bcbf294ede84d5924d03b28710ba0e100874 Mon Sep 17 00:00:00 2001 From: JGoP-L <741047428@qq.com> Date: Wed, 4 Feb 2026 19:16:36 +0800 Subject: [PATCH] fix(model): auto-generate ChatResponse.id when LLM doesn't provide it (#708) Ollama API doesn't return an id field in its chat completion responses, unlike other LLM providers (OpenAI, Anthropic, DashScope). This causes the AGUI protocol and other components that depend on ChatResponse.getId() to fail with "messageId cannot be null". Solution: - Modified ChatResponse.Builder.build() to auto-generate a UUID when id is null, empty, or blank (whitespace-only) - Updated AnthropicResponseParserTest to verify auto-generated IDs Per review feedback: - Copilot: Added isEmpty() check for empty strings - gemini-code-assist: Added trim().isEmpty() for blank strings This ensures compatibility across all LLM providers while maintaining backward compatibility with providers that return an id. Co-Authored-By: Claude Opus 4.5 --- .../java/io/agentscope/core/model/ChatResponse.java | 12 +++++++++++- .../anthropic/AnthropicResponseParserTest.java | 4 +++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/agentscope-core/src/main/java/io/agentscope/core/model/ChatResponse.java b/agentscope-core/src/main/java/io/agentscope/core/model/ChatResponse.java index c385fb888..2e0165b61 100644 --- a/agentscope-core/src/main/java/io/agentscope/core/model/ChatResponse.java +++ b/agentscope-core/src/main/java/io/agentscope/core/model/ChatResponse.java @@ -18,6 +18,7 @@ import io.agentscope.core.message.ContentBlock; import java.util.List; import java.util.Map; +import java.util.UUID; /** * Represents a chat completion response from a language model. @@ -176,11 +177,20 @@ public Builder finishReason(String finishReason) { /** * Builds a new ChatResponse instance with the set values. + *

+ * If no id was set (or is empty/blank), a random UUID will be generated + * automatically. This ensures compatibility with LLM providers (like Ollama) + * that don't return an id field in their API responses. * * @return a new ChatResponse instance */ public ChatResponse build() { - return new ChatResponse(id, content, usage, metadata, finishReason); + // Auto-generate id if not set, empty, or blank (for providers like Ollama) + String responseId = this.id; + if (responseId == null || responseId.trim().isEmpty()) { + responseId = UUID.randomUUID().toString(); + } + return new ChatResponse(responseId, content, usage, metadata, finishReason); } } } diff --git a/agentscope-core/src/test/java/io/agentscope/core/formatter/anthropic/AnthropicResponseParserTest.java b/agentscope-core/src/test/java/io/agentscope/core/formatter/anthropic/AnthropicResponseParserTest.java index 6654b0659..cb311ba88 100644 --- a/agentscope-core/src/test/java/io/agentscope/core/formatter/anthropic/AnthropicResponseParserTest.java +++ b/agentscope-core/src/test/java/io/agentscope/core/formatter/anthropic/AnthropicResponseParserTest.java @@ -16,6 +16,7 @@ package io.agentscope.core.formatter.anthropic; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -324,7 +325,8 @@ void testParseStreamEventUnknownType() throws Exception { ChatResponse response = invokeParseStreamEvent(event, startTime); assertNotNull(response); - assertNull(response.getId()); + assertNotNull(response.getId()); // Builder auto-generates UUID when id is null + assertFalse(response.getId().isEmpty()); assertTrue(response.getContent().isEmpty()); assertNull(response.getUsage()); }