Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

[spring-ai] Streaming responses ending with CJK punctuation (。!?) are misclassified as partial and never persisted to the session

Abierto Apto para principiantes
#1,608 1 comentario 0 reacciones 1 asignado Ver en GitHub

Los mantenedores suelen responder en 1 día

@caps-xia ya está trabajando en esto.

Desde el 6/10/2026.

  • #1620 de @caps-xia — abierto

Evaluación

Dificultad
2/5
Tiempo estimado
1-3 horas
Aptitud para principiantes
84/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
java, spring
Área
backend

Línea de trabajo

Comienza en contrib/spring-ai/src/main/java/com/google/adk/models/springai/MessageConverter.java, método isPartialResponse, que solo comprueba ASCII . ! ? y salto de línea. La reproducción mínima del issue llama a MessageConverter#toLlmResponse directamente con una ChatResponse que termina en 。, así que convierte eso en una prueba unitaria bajo contrib/spring-ai/src/test y confirma que actualmente devuelve partial=true. Hecho significa que una respuesta que termina en 。!? produce partial=false, y tanto la nueva prueba como las pruebas existentes del módulo pasan.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

Describe the Bug

In the Spring AI bridge (contrib/spring-ai), MessageConverter#isPartialResponse
decides whether a streaming chunk is partial by checking only ASCII sentence-ending
punctuation: ., !, ?, \n. CJK terminal punctuation (。, !, ?) is not
included.

As a result, when a model's final streaming response ends with a Chinese sentence
mark (which is the normal case for Chinese users), it is classified as partial=true
and therefore never persisted to the session — the reply silently disappears from
conversation history, breaking multi-turn context and session replay.

Steps to Reproduce
  1. Use the official com.google.adk.models.springai.SpringAI model bridge with any
    OpenAI-compatible model, streaming mode (RunConfig SSE).
  2. Send a question that produces a Chinese answer, e.g. 根因是库存扣减为 0 未拦截。
  3. Observe the final LlmResponse: partial is true, and the session event store
    never receives this response.

A minimal unit-level repro (calling the converter directly) is provided below.
No exception/stacktrace is produced — the failure is silent, which is what makes it
hard to notice in production.

Expected Behavior

A response ending with 。 (or ! / ?) is a complete final response in Chinese
and should be partial=false, persisted to the session like its ASCII-. counterpart.

Observed Behavior

Verified against google-adk-spring-ai:1.9.0 on our classpath:

[PROBE] chinese-ending partial = true    <-- bug: final reply treated as partial
[PROBE] ascii-ending   partial = false

Downstream effect: Runner-driven sessions lose the assistant's final answer for
CJK conversations; Session.events() replay shows the question without the reply.
Live streaming looks fine (partials are forwarded to the client), so the loss only
shows up in history, multi-turn follow-ups and session replay.

Environment Details
  • ADK Library Version: verified on 1.9.0, and confirmed still present in
    1.11.0 (latest release) and on current main
    (contrib/spring-ai/src/main/java/com/google/adk/models/springai/MessageConverter.java#isPartialResponse)
  • OS: macOS (behavior is OS-independent — pure string logic)
  • TS Version: N/A (Java)
Model Information

Model-independent. Observed with GLM via an OpenAI-compatible gateway; the
classification happens in MessageConverter before any model-specific handling.

Regression

N/A — the heuristic has been present since we started using the bridge (1.9.0),
and is unchanged through 1.11.0.

Additional Context

Suggested fix, from minimal to better:

  1. Add CJK terminal punctuation to the check: 。!? (plus …, )).
  2. Better: don't infer completeness from punctuation at all. Text legitimately ends
    without sentence-ending characters (lists, code blocks, tables). Partial-ness
    could be derived from chunk position / stream state instead of the last character.

This affects every CJK-language user of the official SpringAI bridge — and because
partials are still forwarded live, the missing persistence only surfaces later
(history / follow-up turns), which makes it easy to misdiagnose as a session-store
problem.

Minimal Reproduction Code
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.adk.models.springai.MessageConverter;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.model.Generation;

import java.util.List;

MessageConverter converter = new MessageConverter(new ObjectMapper());

ChatResponse chineseEnding = new ChatResponse(List.of(new Generation(
        AssistantMessage.builder().content("根因是库存扣减为 0 未拦截。").build())));
ChatResponse asciiEnding = new ChatResponse(List.of(new Generation(
        AssistantMessage.builder().content("Root cause: zero-stock deduction is not blocked.").build())));

boolean chinesePartial = converter.toLlmResponse(chineseEnding, true).partial().orElse(false); // true  (bug)
boolean asciiPartial   = converter.toLlmResponse(asciiEnding, true).partial().orElse(false);   // false
How often has this issue occurred?

Always (100%) — every Chinese final response ending with 。, which is essentially
every conversation.

Lenguaje dominante
Java
Estrellas
1.7k
Forks
431
Merge medio
2 d 20 h
PR fusionados (30 d)
42

Preparar el entorno

Abrir en Codespaces

Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de google/adk-java

Todos los issues de google/adk-java

Issues similares

Más issues de Java

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.