From 9716334a209c90e6a124bf06365ff3644bc07ca2 Mon Sep 17 00:00:00 2001 From: rUv Date: Wed, 25 Mar 2026 20:27:59 +0000 Subject: [PATCH] fix(brain): wrap Google Chat responses in Add-ons DataActions envelope Google Workspace Add-ons expect responses wrapped in: { "hostAppDataAction": { "chatDataActionMarkup": { "createMessageAction": { "message": {...} } } } } Returning a raw Message object causes Google Chat to show "not responding" even though the HTTP status is 200. The endpoint was receiving requests correctly (confirmed via Cloud Run logs) but responses were being silently dropped by the Add-ons framework. Ref: https://developers.google.com/workspace/add-ons/chat/build Co-Authored-By: claude-flow --- crates/mcp-brain-server/src/routes.rs | 31 +++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/crates/mcp-brain-server/src/routes.rs b/crates/mcp-brain-server/src/routes.rs index ba44e85a5..aab7e9547 100644 --- a/crates/mcp-brain-server/src/routes.rs +++ b/crates/mcp-brain-server/src/routes.rs @@ -6069,9 +6069,17 @@ struct GoogleChatUser { email: Option, } -/// Google Chat card response — always includes `text` fallback for HTTP endpoint mode +/// Google Chat response wrapped in the Add-ons DataActions format. +/// +/// Google Workspace Add-ons expect responses wrapped in: +/// { "hostAppDataAction": { "chatDataActionMarkup": { "createMessageAction": { "message": {...} } } } } +/// +/// NOT the raw Message object. Returning a raw Message causes Google Chat +/// to show "not responding" even though the HTTP status is 200. +/// +/// See: https://developers.google.com/workspace/add-ons/chat/build fn chat_card(title: &str, subtitle: &str, sections: Vec) -> serde_json::Value { - serde_json::json!({ + let message = serde_json::json!({ "text": format!("{} — {}", title, subtitle), "cardsV2": [{ "cardId": "brain-response", @@ -6085,6 +6093,21 @@ fn chat_card(title: &str, subtitle: &str, sections: Vec) -> s "sections": sections } }] + }); + + wrap_chat_response(message) +} + +/// Wrap a Chat Message in the Add-ons DataActions envelope. +fn wrap_chat_response(message: serde_json::Value) -> serde_json::Value { + serde_json::json!({ + "hostAppDataAction": { + "chatDataActionMarkup": { + "createMessageAction": { + "message": message + } + } + } }) } @@ -6118,9 +6141,9 @@ async fn google_chat_handler( Err(err) => { let raw = String::from_utf8_lossy(&body); tracing::warn!("Failed to parse Chat event: {}. Raw: {}", err, &raw[..raw.len().min(500)]); - return Json(serde_json::json!({ + return Json(wrap_chat_response(serde_json::json!({ "text": "Pi Brain received your message but couldn't parse it. Try: help" - })); + }))); } };