diff --git a/apps/android/app/src/main/java/ai/openclaw/android/chat/ChatController.kt b/apps/android/app/src/main/java/ai/openclaw/android/chat/ChatController.kt index 3ed69ee5b24..b72357983d5 100644 --- a/apps/android/app/src/main/java/ai/openclaw/android/chat/ChatController.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/chat/ChatController.kt @@ -325,6 +325,12 @@ class ChatController( val state = payload["state"].asStringOrNull() when (state) { + "delta" -> { + val text = parseAssistantDeltaText(payload) + if (!text.isNullOrEmpty()) { + _streamingAssistantText.value = text + } + } "final", "aborted", "error" -> { if (state == "error") { _errorText.value = payload["errorMessage"].asStringOrNull() ?: "Chat failed" @@ -351,9 +357,8 @@ class ChatController( private fun handleAgentEvent(payloadJson: String) { val payload = json.parseToJsonElement(payloadJson).asObjectOrNull() ?: return - val runId = payload["runId"].asStringOrNull() - val sessionId = _sessionId.value - if (sessionId != null && runId != sessionId) return + val sessionKey = payload["sessionKey"].asStringOrNull()?.trim() + if (!sessionKey.isNullOrEmpty() && sessionKey != _sessionKey.value) return val stream = payload["stream"].asStringOrNull() val data = payload["data"].asObjectOrNull() @@ -398,6 +403,21 @@ class ChatController( } } + private fun parseAssistantDeltaText(payload: JsonObject): String? { + val message = payload["message"].asObjectOrNull() ?: return null + if (message["role"].asStringOrNull() != "assistant") return null + val content = message["content"].asArrayOrNull() ?: return null + for (item in content) { + val obj = item.asObjectOrNull() ?: continue + if (obj["type"].asStringOrNull() != "text") continue + val text = obj["text"].asStringOrNull() + if (!text.isNullOrEmpty()) { + return text + } + } + return null + } + private fun publishPendingToolCalls() { _pendingToolCalls.value = pendingToolCallsById.values.sortedBy { it.startedAtMs }