-
Notifications
You must be signed in to change notification settings - Fork 244
feat(a2a-bridge): add gRPC and REST transport support #363
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
zeroasterisk
wants to merge
6
commits into
GoogleCloudPlatform:main
Choose a base branch
from
zeroasterisk:a2a/sdk-grpc-rest
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
8018d55
feat(a2a-bridge): adopt a2a-go SDK for protocol handling
zeroasterisk fc6ac23
feat(a2a-bridge): add gRPC and REST transport support
zeroasterisk 268346f
fix(a2a-bridge): review fixes for SDK migration
zeroasterisk f65f5d1
fix(a2a-bridge): address review comments — nil checks, channel safety
zeroasterisk f3df7a5
fix(a2a-bridge): address review findings for gRPC/REST transports (#363)
zeroasterisk 3c65df4
fix(a2a-bridge): fix build errors from SendStructuredMessage signatur…
zeroasterisk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| # A2A Go SDK Migration | ||
|
|
||
| ## Status: In Progress | ||
| ## Date: 2026-06-08 | ||
|
|
||
| ## Summary | ||
|
|
||
| Migrate the scion-a2a-bridge from a hand-rolled A2A protocol implementation to | ||
| the official `a2a-go` SDK (`github.com/a2aproject/a2a-go/v2`). This replaces | ||
| our custom JSON-RPC handling, task lifecycle management, and streaming | ||
| infrastructure with the SDK's spec-compliant implementations while preserving | ||
| our Scion Hub routing core. | ||
|
|
||
| ## Motivation | ||
|
|
||
| - **Spec compliance**: The SDK tracks the A2A spec automatically. Our hand-rolled | ||
| implementation required manual updates for each spec revision. | ||
| - **Reduced maintenance**: ~500 lines of JSON-RPC, SSE streaming, and task store | ||
| code replaced by SDK. | ||
| - **Multi-transport**: SDK provides JSON-RPC, REST, and gRPC transports from a | ||
| single `RequestHandler` — we get gRPC and REST nearly for free. | ||
| - **Correctness**: SDK handles edge cases (OCC, concurrent cancellation, event | ||
| ordering) that our MVP implementation simplified or deferred. | ||
|
|
||
| ## Architecture | ||
|
|
||
| ### Before (hand-rolled) | ||
|
|
||
| ``` | ||
| HTTP Request → server.go (JSON-RPC dispatch) → bridge.go (task management) | ||
| → Hub API → Broker → bridge.go (response correlation) → JSON-RPC response | ||
| ``` | ||
|
|
||
| ### After (SDK-based) | ||
|
|
||
| ``` | ||
| HTTP Request → auth middleware → route extraction → SDK JSONRPC Handler | ||
| → SDK RequestHandler → SDK task lifecycle → ScionExecutor.Execute() | ||
| → bridge.go (Hub routing) → Broker → waiter channel → SDK events | ||
| → SDK response serialization → HTTP response | ||
| ``` | ||
|
|
||
| ### Key Components | ||
|
|
||
| **ScionExecutor** (`executor.go`): Implements `a2asrv.AgentExecutor`. The bridge | ||
| between the SDK's event-driven model and our Scion Hub message routing. | ||
|
|
||
| - `Execute()`: Translates SDK message → Scion StructuredMessage, sends to Hub, | ||
| waits for broker response, yields SDK events. | ||
| - `Cancel()`: Sends interrupt to Scion agent, yields canceled status event. | ||
|
|
||
| **Server** (`server.go`): Simplified HTTP routing layer. Handles: | ||
| - Multi-project/agent URL routing (`/projects/{p}/agents/{a}/jsonrpc`) | ||
| - Agent card serving (kept custom — SDK's card handler is single-agent) | ||
| - Auth middleware, rate limiting, metrics (unchanged) | ||
| - Delegates JSON-RPC to SDK's `NewJSONRPCHandler` | ||
|
|
||
| **Bridge** (`bridge.go`): Core Hub routing preserved. Changes: | ||
| - Added `sdkRequestHandler` field for multi-transport access | ||
| - Task lifecycle now managed by SDK's in-memory task store | ||
| - SQLite store retained for context mapping and broker correlation | ||
|
|
||
| **Translate** (`translate.go`): Added SDK-compatible translation functions: | ||
| - `TranslateA2APartsToScion()`: SDK `a2a.ContentParts` → Scion message | ||
| - `TranslateScionToA2AParts()`: Scion message → SDK `a2a.Message` + `a2a.Artifact` | ||
| - `MapActivityToSDKTaskState()`: Scion activity → SDK `a2a.TaskState` | ||
| - Original functions retained for backward compatibility | ||
|
|
||
| ## What Changed | ||
|
|
||
| | Component | Before | After | | ||
| |-----------|--------|-------| | ||
| | JSON-RPC parsing | `server.go` hand-rolled | SDK `a2asrv.NewJSONRPCHandler` | | ||
| | Task lifecycle | `bridge.go` + SQLite | SDK in-memory task store | | ||
| | SSE streaming | `stream.go` custom | SDK built-in | | ||
| | Push notifications | `push.go` custom | SDK `push.Sender` (future) | | ||
| | A2A types | `translate.go` custom structs | SDK `a2a` package | | ||
| | Error codes | Custom constants | SDK `a2a.Err*` sentinel errors | | ||
|
|
||
| ## What's Preserved | ||
|
|
||
| - **Bridge core**: Hub client routing, broker plugin, agent lookup, context | ||
| resolution, auto-provisioning — all unchanged. | ||
| - **Config**: Same YAML format, same fields. | ||
| - **Auth**: Same API key / Bearer middleware. | ||
| - **Metrics**: Same Prometheus metrics. | ||
| - **Rate limiting**: Same per-IP/key token bucket. | ||
| - **Broker plugin**: Same go-plugin RPC server. | ||
| - **SQLite store**: Retained for context mapping. Task state now also in SDK | ||
| in-memory store. | ||
|
|
||
| ## PR Structure | ||
|
|
||
| ### PR A: SDK Adoption (`a2a/sdk-migration`) | ||
| - Add `a2a-go/v2` dependency | ||
| - New `executor.go` (AgentExecutor implementation) | ||
| - Rewritten `server.go` (SDK handler delegation) | ||
| - Updated `translate.go` (SDK type translations) | ||
| - Updated `bridge.go` (sdkRequestHandler field) | ||
| - Updated `main.go` (SDK wiring) | ||
| - Updated tests | ||
|
|
||
| ### PR B: gRPC + REST Transports (`a2a/sdk-grpc-rest`) | ||
| - `a2agrpc.NewHandler` for gRPC transport | ||
| - `a2asrv.NewRESTHandler` for REST transport | ||
| - Config fields: `grpc_listen_address`, `rest_listen_address` | ||
| - Startup wiring in `main.go` | ||
|
|
||
| ## Migration Risks | ||
|
|
||
| 1. **Task store divergence**: SDK uses in-memory store; our SQLite store tracks | ||
| context mappings separately. Tasks visible via A2A protocol come from SDK | ||
| store; context lookups use SQLite. | ||
|
|
||
| 2. **Broker correlation**: The SDK doesn't know about our broker. Response | ||
| correlation happens inside `ScionExecutor.Execute()` using the same waiter | ||
| channel pattern. | ||
|
|
||
| 3. **Push notification gap**: SDK has `push.Sender` interface but we haven't | ||
| wired our SSRF-safe push dispatcher yet. Push is disabled in capabilities. | ||
|
|
||
| ## Future Work | ||
|
|
||
| - Wire SDK push notification support with our SSRF-safe dispatcher | ||
| - Implement SDK `taskstore.Store` interface backed by SQLite for persistence | ||
| - Add multi-turn conversation support (SDK handles it; our executor needs updates) | ||
| - Evaluate SDK's work queue for distributed deployment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.