From 72ea38b306345abc1607319321f1f11591e2bbb6 Mon Sep 17 00:00:00 2001 From: Adam Weidman Date: Thu, 12 Feb 2026 10:23:47 -0500 Subject: [PATCH] fix: resolve agent card URL for A2A client initialization ClientFactory.createFromUrl expects the full agent card URL (/.well-known/agent-card.json), not just the base server URL. Also adds CHAT_BRIDGE_A2A_URL to k8s deployment and test script. --- packages/a2a-server/k8s/deployment.yaml | 2 + .../src/chat-bridge/a2a-bridge-client.ts | 12 +++-- packages/a2a-server/test-chat-bridge.sh | 48 +++++++++++++++++++ 3 files changed, 58 insertions(+), 4 deletions(-) create mode 100755 packages/a2a-server/test-chat-bridge.sh diff --git a/packages/a2a-server/k8s/deployment.yaml b/packages/a2a-server/k8s/deployment.yaml index bda37203d3..a3d5573d5b 100644 --- a/packages/a2a-server/k8s/deployment.yaml +++ b/packages/a2a-server/k8s/deployment.yaml @@ -34,6 +34,8 @@ spec: key: api-key - name: GEMINI_YOLO_MODE value: "true" + - name: CHAT_BRIDGE_A2A_URL + value: "http://localhost:8080" - name: NODE_ENV value: "production" resources: diff --git a/packages/a2a-server/src/chat-bridge/a2a-bridge-client.ts b/packages/a2a-server/src/chat-bridge/a2a-bridge-client.ts index 649d83e873..5a33874f3d 100644 --- a/packages/a2a-server/src/chat-bridge/a2a-bridge-client.ts +++ b/packages/a2a-server/src/chat-bridge/a2a-bridge-client.ts @@ -87,9 +87,10 @@ export function extractAllParts(result: A2AResponse): Part[] { export function extractTextFromParts(parts: Part[]): string { return parts .filter((p) => p.kind === 'text') - .map((p) => - // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion - (p as unknown as { text: string }).text + .map( + (p) => + // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion + (p as unknown as { text: string }).text, ) .filter(Boolean) .join('\n'); @@ -151,7 +152,10 @@ export class A2ABridgeClient { ); const factory = new ClientFactory(options); - this.client = await factory.createFromUrl(this.agentUrl, ''); + // createFromUrl expects the agent card URL, not just the base URL + const agentCardUrl = + this.agentUrl.replace(/\/$/, '') + '/.well-known/agent-card.json'; + this.client = await factory.createFromUrl(agentCardUrl, ''); const card = await this.client.getAgentCard(); logger.info( diff --git a/packages/a2a-server/test-chat-bridge.sh b/packages/a2a-server/test-chat-bridge.sh new file mode 100755 index 0000000000..0ceaca3921 --- /dev/null +++ b/packages/a2a-server/test-chat-bridge.sh @@ -0,0 +1,48 @@ +#!/bin/bash +# Test script for the Google Chat bridge webhook endpoint. +# Simulates Google Chat events to verify the bridge works. +# +# Usage: ./test-chat-bridge.sh [PORT] +# Default port: 9090 (for kubectl port-forward) + +PORT=${1:-9090} +BASE_URL="http://localhost:${PORT}" + +echo "Testing chat bridge at ${BASE_URL}..." + +# 1. Test health endpoint +echo -e "\n--- Health Check ---" +curl -s "${BASE_URL}/chat/health" | jq . + +# 2. Test ADDED_TO_SPACE event +echo -e "\n--- ADDED_TO_SPACE ---" +curl -s -X POST "${BASE_URL}/chat/webhook" \ + -H "Content-Type: application/json" \ + -d '{ + "type": "ADDED_TO_SPACE", + "eventTime": "2026-01-01T00:00:00Z", + "space": { "name": "spaces/test123", "type": "DM" }, + "user": { "name": "users/123", "displayName": "Test User" } + }' | jq . + +# 3. Test MESSAGE event +echo -e "\n--- MESSAGE (Hello) ---" +curl -s -X POST "${BASE_URL}/chat/webhook" \ + -H "Content-Type: application/json" \ + -d '{ + "type": "MESSAGE", + "eventTime": "2026-01-01T00:01:00Z", + "message": { + "name": "spaces/test123/messages/msg1", + "sender": { "name": "users/123", "displayName": "Test User" }, + "createTime": "2026-01-01T00:01:00Z", + "text": "Hello, write me a python hello world", + "argumentText": "Hello, write me a python hello world", + "thread": { "name": "spaces/test123/threads/thread1" }, + "space": { "name": "spaces/test123", "type": "DM" } + }, + "space": { "name": "spaces/test123", "type": "DM" }, + "user": { "name": "users/123", "displayName": "Test User" } + }' | jq . + +echo -e "\nDone."