- Add SSE keepalive middleware (15s comment heartbeat) to prevent Cloud Run
LB from closing idle SSE connections during long tool executions
- Increase A2A server request timeout from 300s to 3600s (1 hour)
- Cache loaded tasks in NoOpTaskStore to prevent redundant GCS workspace
restores on every SDK event cycle (was restoring 5+ times per request)
- Add undici dispatcher with 10-min timeouts for bridge SSE connections
- Install gh CLI and gcloud CLI in Docker image for agent GitHub/GCP access
- 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
Separate the Google Chat bridge from the A2A agent server so each can
scale independently on Cloud Run. The bridge is a lightweight proxy
(concurrency=80) while the agent needs concurrency=1.
- Add standalone entry point (src/chat-bridge/server.ts)
- Add Dockerfile.chat-bridge and cloudbuild-chat-bridge.yaml
- Remove chat bridge setup from app.ts
- Inline A2UI constants in a2a-bridge-client.ts (no agent deps)
- Update README for two-service architecture
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
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.
Verifies Bearer tokens from Google Chat using google-auth-library.
Checks issuer (chat@system.gserviceaccount.com) and audience
(CHAT_PROJECT_NUMBER). Verification is skipped when project number
is not configured, allowing local testing without tokens.
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