- All bot responses now pushed via Chat API instead of synchronous webhook
response — Add-ons createMessageAction ignores thread info in Spaces,
causing messages to appear as top-level instead of in-thread
- Webhook returns bare {} for empty responses to prevent Google Chat
from retrying (wrapped empty createMessageAction caused retry storm)
- Add retryStream() with exponential backoff (3 retries, 5s/10s/20s)
for transient A2A server 500/503 errors
- Add GEMINI_MODEL env var override in config (was hardcoded to
gemini-3-pro-preview which hit capacity limits)
- Extract pushAndReturn() helper for fire-and-forget Chat API sends
- Add session cancellation on /reset to stop in-flight async streams
- Implement per-session YOLO auto-approval with batch tool confirmations
(sendBatchToolConfirmations sends all approvals in one A2A message to
avoid hangs when agent needs ALL tools approved before proceeding)
- Fix threading: include thread info in Add-ons response wrapper so
replies appear in the user's thread instead of top-level
- Make tool approval async: return immediate ack, process confirmation
in background, push result via Chat API (fixes "Agent is processing..."
empty response after approve)
- Replace text-based approval with clickable Approve/Always Allow/Reject
buttons on compact Cards V2
- Wire CARD_CLICKED handler to async approval flow (fire-and-forget
with UPDATE_MESSAGE ack)
Tested via Cloud Run proxy curl suite:
/reset, simple messages, async guard, /yolo, /safe, CARD_CLICKED
(approve + reject), ADDED_TO_SPACE, empty message, cancellation.
- Add identity token auth in A2ABridgeClient for Cloud Run (K_SERVICE)
- Support CODER_AGENT_PUBLIC_URL env var for agent card URL on Cloud Run
- Strip @Bot mention prefix before slash command detection (Add-ons)
- Grant bridge SA roles/run.invoker on A2A server via IAM
Replace blocking A2A calls with streaming: webhook returns
immediate "Processing..." response, then streams results from
A2A agent and pushes them to Google Chat via REST API.
- Add ChatApiClient for proactive messaging via Chat REST API
- Add sendMessageStream() to A2ABridgeClient for SSE streaming
- Add extractFromStreamEvent() for parsing individual stream events
- Refactor handler to fire-and-forget async processing
- Fix isTerminal logic to use stream state instead of taskId presence
- Add asyncProcessing guard to prevent overlapping requests
- Add comprehensive README with deployment and setup guide
Pass thread name through Add-ons response wrapper so bot replies stay
in the user's thread instead of posting top-level messages. Add
GIT_TERMINAL_PROMPT=0 to Dockerfile to prevent git from hanging on
credential prompts, which was blocking all requests under concurrency=1.
Enable session resumability across Cloud Run restarts:
- executor.ts: Save conversation history in task metadata during
toSDKTask(), restore via setHistory() in reconstruct()
- gcs.ts: Persist conversation history as separate GCS object
(conversation.tar.gz) alongside metadata and workspace
- session-store.ts: Add optional GCS-backed persistence with periodic
flush and restore-on-startup for thread→session mappings
- handler.ts: Restore persisted sessions on initialize()
- types.ts: Add gcsBucket to ChatBridgeConfig
- app.ts: Pass GCS_BUCKET_NAME to chat bridge config
Validated end-to-end: message persists, Cloud Run restarts, follow-up
message in same thread correctly recalls prior context. Different
threads maintain isolation.
Implements a Google Chat HTTP webhook bridge that connects Google Chat
to the A2A server. Each Chat thread maps to an A2A contextId/taskId
pair. The bridge converts A2UI tool approval surfaces to Google Chat
Cards V2 with Approve/Always Allow/Reject buttons, and handles
CARD_CLICKED events to forward tool confirmations back to the A2A server.
Components:
- chat-bridge/types.ts: Google Chat event/response types
- chat-bridge/session-store.ts: Thread -> A2A session mapping
- chat-bridge/a2a-bridge-client.ts: A2A SDK client wrapper
- chat-bridge/response-renderer.ts: A2UI -> Google Chat Cards V2
- chat-bridge/handler.ts: Event handler (MESSAGE, CARD_CLICKED)
- chat-bridge/routes.ts: Express routes mounted at /chat/webhook