Commit Graph

8 Commits

Author SHA1 Message Date
Adam Weidman a9eb2ee5e3 fix: push all messages via Chat API for threading, add retry and model override
- 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
2026-02-19 14:00:26 -05:00
Adam Weidman fc9623248d fix: session cancellation, YOLO auto-approval, threading, and approval UX
- 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.
2026-02-19 11:42:06 -05:00
Adam Weidman 45c9545f78 fix: Cloud Run service-to-service auth and agent card URL
- 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
2026-02-15 00:22:08 -07:00
Adam Weidman 4f3ffc8959 feat: async streaming chat bridge with Chat API push
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
2026-02-14 19:54:47 -07:00
Adam Weidman 03ef280120 fix: reply in user's thread and prevent git credential hangs
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.
2026-02-12 17:36:58 -05:00
Adam Weidman 60b01761b8 feat: add GCS-backed session and conversation persistence
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.
2026-02-12 17:17:08 -05:00
Adam Weidman df81bfe1f2 feat: Google Chat bridge with YOLO mode, text-based approvals, and Add-ons support
- Add normalizeEvent() to convert Workspace Add-ons event format to legacy ChatEvent
- Add wrapAddOnsResponse() for Add-ons response wrapping
- Mount chat bridge routes BEFORE A2A SDK catch-all handler
- Replace card button approvals with text-based approve/reject/always allow
- Add /reset, /yolo, /safe slash commands for session control
- Add YOLO mode tool approval dedup (filter auto-approved surfaces)
- Add extractCommandSummary() for concise tool card display
- Delegate auth to Cloud Run IAM when K_SERVICE env var detected
- Add JWT debug logging for token claim inspection
2026-02-12 16:12:18 -05:00
Adam Weidman 57f3c9ca1a feat: add Google Chat bridge for A2UI integration
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
2026-02-12 10:11:58 -05:00