ag-ui-protocol / ag-ui-protocol/ag-ui

[Feature]: Add AGUIStreamOptions.IncludeRawEvents to make rawEvent attachment opt-out (.NET)

Abierto
#2,297 1 comentario 1 reacción 0 asignados Ver en GitHub
enhancement
Lenguaje dominante
Python
Estrellas
15.9k
Forks
1.4k
Merge medio
1 d 17 h
PR fusionados (30 d)
163

Descripción

### Pre-flight Checklist

- [x] I have searched existing issues and this hasn't been requested yet.

### Problem or Motivation

`AsAGUIEventStreamAsync` serializes every `ChatResponseUpdate` and attaches it as `rawEvent` to each event derived from it (`TEXT_MESSAGE_*`, `TOOL_CALL_*`, `REASONING_ENCRYPTED_VALUE`). There is no way to turn it off.

Measured on this repo's own `Step*` server baselines: `rawEvent` is **66% of the wire** (425,009 → 145,716 bytes when stripped; `TEXT_MESSAGE_CONTENT` +213%, `TOOL_CALL_END` +648%). It rides protobuf as well as SSE.

Nothing reads it. The .NET client's only `RawEvent` reference is the *event type* (`EventStreamConverter.cs:341`); the TS client only writes the field on its own error events (`transform/http.ts:72`).

It is also a .NET-only divergence: no TS or Python server populates `rawEvent` (Python declares `raw_event: Optional[Any] = None` and never sets it), and `agui-cross-sdk-parity/SKILL.md:27` makes TypeScript canonical for wire format.

### Proposed Solution

An init-only `bool IncludeRawEvents` on `AGUIStreamOptions`, default `true` so nothing changes. Guard the serialization, not the assignment, so opting out also recovers the per-update CPU and allocations (`ChatResponseUpdateAGUIExtensions.cs:200`):

```csharp
JsonElement? raw = options.IncludeRawEvents
? JsonSerializer.SerializeToElement(chatResponse, jsonSerializerOptions.GetTypeInfo(typeof(ChatResponseUpdate)))
: null;
```

Every `Create` already takes `JsonElement?`, so this widens one internal signature (`ReasoningMessageTracker.EmitEncryptedValue`). Events the caller supplies — via `RawRepresentation` or a `Map*` callback — keep their own `RawEvent`. Event sequence is unchanged, so this is not a protocol change.

### Alternatives Considered

**A host-side stream filter** that nulls `RawEvent` before the formatter. Works (verified, −61% on a short stream) but still pays the serialization, must be reimplemented per host, and can't tell an SDK-attached payload from a deliberate one.

**Defaulting to `false`.** Arguably correct long-term — it is what puts .NET in parity — but flipping it breaks anyone reading the field and moves every baseline. Better as a separate, deliberate change.

**Emitting `BaseEvent`s via `RawRepresentation`** to hit the short-circuit above line 200. Avoids the serialization entirely, but means reimplementing text/tool/reasoning tracking.

### Additional Context

_No response_

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.