a2aproject / a2aproject/a2a-go

REST streaming stops at an unknown StreamResponse payload (v2.5.0)

Aperta
#435 1 commento 0 reazioni 0 assegnatari Vedi su GitHub
Lingua principale
Go
Stelle
460
Fork
93
Merge medio
2g 21h
PR unite (30g)
9

Descrizione

Following [the request for SDK investigations in A2A #2129](https://github.com/a2aproject/A2A/pull/2129#discussion_r3805450070), here is a reproducible Go case for the already-reported unknown-event compatibility problem.

With **a2a-go v2.5.0**, a REST/SSE stream containing:

`Task → working status → unfamiliar payload → working status → completed status`

stops at the unfamiliar payload with `unknown stream response type`. The caller receives the first two events but neither later known update. The request explicitly sends `A2A-Version: 1.0`.

The synthetic `futureEvent` is valid JSON but is **not a defined A2A 1.0 event**. This demonstrates a constraint on future event additions; it does not assume the current specification already mandates accepting that variant.

### Reproduction

With Go 1.25+, save this as `main.go` in a fresh directory:

Self-contained loopback reproduction

```go
package main

import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"time"

"github.com/a2aproject/a2a-go/v2/a2a"
"github.com/a2aproject/a2a-go/v2/a2aclient"
)

func main() {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/event-stream")
if _, err := fmt.Fprint(w, `data: {"task":{"id":"task-fixture","contextId":"context-fixture","status":{"state":"TASK_STATE_SUBMITTED"}}}

data: {"statusUpdate":{"taskId":"task-fixture","contextId":"context-fixture","status":{"state":"TASK_STATE_WORKING"}}}

data: {"futureEvent":{"taskId":"task-fixture","contextId":"context-fixture","text":"synthetic future event; not a defined A2A 1.0 variant"}}

data: {"statusUpdate":{"taskId":"task-fixture","contextId":"context-fixture","status":{"state":"TASK_STATE_WORKING"}}}

data: {"statusUpdate":{"taskId":"task-fixture","contextId":"context-fixture","status":{"state":"TASK_STATE_COMPLETED"}}}

`); err != nil {
panic(err)
}
}))
defer server.Close()
endpoint, err := url.Parse(server.URL)
if err != nil {
panic(err)
}
transport := a2aclient.NewRESTTransport(endpoint, &http.Client{Timeout: 5 * time.Second})
message := a2a.NewMessage(a2a.MessageRoleUser, a2a.NewTextPart("fixture request"))
message.ID = "message-fixture"
count := 0
for event, err := range transport.SendStreamingMessage(context.Background(), a2aclient.ServiceParams{"A2A-Version": {"1.0"}}, &a2a.SendMessageRequest{Message: message}) {
if err != nil {
fmt.Printf("after %d events: %v\n", count, err)
return
}
count++
fmt.Printf("event %d: %T\n", count, event)
}
}
```

```sh
go mod init example.com/a2a-unknown-event-repro
go get github.com/a2aproject/a2a-go/v2@v2.5.0
go mod tidy
go run .
```

Observed with the published module, without local SDK changes:

```text
event 1: *a2a.Task
event 2: *a2a.TaskStatusUpdateEvent
after 2 events: unknown stream response type
```

### Controls

Using the same public REST receive path and loopback fixture:

- Known events only, or an extra field inside a known status update: all four known events arrive, including completion.
- A malformed known update (`status: 42`) or two recognized payload members in one wrapper: parsing fails.
- An HTTP body shorter than its declared Content-Length: `SSE stream error: unexpected EOF`; no completion is delivered.
- An empty `{}` wrapper also produces `unknown stream response type`.

For comparison, Python a2a-sdk 1.1.3 stops at the same unfamiliar payload with a protobuf `ParseError`. Only HTTP+JSON/SSE was exercised; this report makes no claim about other bindings or high-level aggregation.

### Proposed next step

Would you prefer a narrow change that skips unfamiliar payloads with a diagnostic and continues to known events, an opaque-event representation, or keeping rejection with an explicit version-negotiation requirement? The handling should distinguish the intended future-event case from empty/malformed responses and keep real transport failures visible.

[Spec §5.7](https://github.com/a2aproject/A2A/blob/98853be376c88df25e1704771cd3ea9ef8823a96/docs/specification.md#57-field-presence-and-optionality) recommends ignoring unknown fields, but does not explicitly define the receive API behavior when no recognized payload remains. I can contribute the focused implementation and regression cases once that behavior is agreed.

Tested Go release: `9d95b95445f4208ba77f48a137a278067937adb7`. The relevant REST parser and transport are unchanged at inspected main `03b1f8483cc9cbdd3e95567100d95c5509687eb5` (static comparison). Existing `go test ./a2aclient ./internal/rest` checks pass.

Guida per i contributori

Apri la guida per i contributori

Valutazione

Questa issue non è ancora stata valutata.

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.