fix(chat): show only reply text to user, not raw JSON

The LLM returns a structured JSON object. Previously, raw tokens were
streamed directly to the user via msg.stream_token(), causing the full
JSON blob to appear in the chat.

Fix: collect all chunks silently, parse the JSON, then send only the
reply field with cl.Message(content=reply_text).send(). The JSON fields
(updates, next_step, registration_complete, language, intent) are still
processed in the background — parents never see them.

https://claude.ai/code/session_01SUWzMzFvSfWiHXA2p6rPg9
This commit is contained in:
Claude
2026-02-22 08:16:12 +00:00
parent e4b4cdd41e
commit 808be0185f
+7 -5
View File
@@ -100,17 +100,16 @@ async def on_message(message: cl.Message) -> None:
# --- Build system prompt --- # --- Build system prompt ---
system = build_system_prompt(_kb, state) system = build_system_prompt(_kb, state)
# --- Stream LLM response --- # --- Collect LLM response (JSON), then display only the reply field ---
msg = cl.Message(content="") # The LLM returns a structured JSON object; we must not stream raw tokens
# to the user because they would see the JSON wrapper, not the reply text.
full_content = "" full_content = ""
try: try:
for chunk in llm.stream_complete(_config.ai_model, system, state.messages): for chunk in llm.stream_complete(_config.ai_model, system, state.messages):
await msg.stream_token(chunk)
full_content += chunk full_content += chunk
await msg.send()
except Exception: except Exception:
logger.exception("LLM streaming failed for session %s", state.conversation_id) logger.exception("LLM call failed for session %s", state.conversation_id)
error_text = fallback_message(state.language) error_text = fallback_message(state.language)
await cl.Message(content=error_text).send() await cl.Message(content=error_text).send()
# Don't update state — let parent retry # Don't update state — let parent retry
@@ -134,6 +133,9 @@ async def on_message(message: cl.Message) -> None:
# Append assistant reply to history # Append assistant reply to history
state.messages.append(ChatMessage(role="assistant", content=reply_text)) state.messages.append(ChatMessage(role="assistant", content=reply_text))
# Send the reply text to the user (parsed from the LLM's JSON response)
await cl.Message(content=reply_text).send()
# --- Handle registration completion --- # --- Handle registration completion ---
if is_complete and not state.completed: if is_complete and not state.completed:
state.completed = True state.completed = True