Public API and payload reference

The package's public names, custom events, input metadata, and terminal events.

Stream Protocol exposes seven package-root names. It converts public Harness observations into typed AG-UI events; transport, persistence, delivery acknowledgement, UI rendering, and Agent continuation remain outside this package.

Public names

Export from a13n_stream_protocolPurpose
HarnessAguiObserverBind one Thread/Run, observe source items, snapshot detached events, or resume from finite source history
AguiEventProcessorSynchronous (source, event) -> event or None Host projection callback
AguiObservationErrorInvalid correlation, observation, replay, or processor replacement
ContentMetadataPresentation conventions plus opaque extra metadata
fragment_custom_eventSplit an oversized CUSTOM event without losing its domain JSON
CustomEventAssemblerReassemble ordered frames within one bounded subscription
__version__Installed distribution version

HarnessAguiObserver(processor=None) exposes observe(item), snapshot(), async resume(history), and read-only thread_id / run_id. IDs are unbound until observation succeeds. Events and processors owns the live workflow; Replay and recovery owns atomic reconstruction, validation, and failure behavior.

Fragment a complete custom event

This complete example performs an in-memory round trip without network or an Agent:

from ag_ui.core.events import CustomEvent
from a13n_stream_protocol import CustomEventAssembler, fragment_custom_event

original = CustomEvent(name="example.document", value={"text": "x" * 60_000})
frames = fragment_custom_event(original, identity="document-1")
assembler = CustomEventAssembler()
complete = None
for frame in frames:
    complete = assembler.accept(frame.model_dump(mode="json", by_alias=False))
assert complete is not None
assert complete["name"] == "example.document"
assert complete["value"] == original.value
assert not assembler.gap

Pass the complete serialized CUSTOM envelope to accept(), not only its value. Events at or below 48 KiB encoded UTF-8 remain intact. Larger events become a13n.stream.fragment events with id, index, count, and string data. Choose identities unique enough for interleaved events in your subscription.

The assembler defaults to 64 MiB pending bytes and eight pending identities; both bounds must be positive. It returns None until an entire event is reconstructed, or on rejected fragments. Invalid, inconsistent, out-of-order, nested, or over-budget sequences set the sticky gap flag. It never publishes a partial domain event.

One assembler belongs to one live subscription. Reset it on reconnect. A missing tail with no subsequent frame cannot be detected from silence alone; the Host owns stream termination/timeouts and gap presentation. Fragment assembly is not durable replay.

Input metadata and media

ContentMetadata defaults to display=True, source_id=None, and media=False, and allows opaque extra metadata. from_native() reads a metadata dict or returns defaults for a non-dict input. Metadata is presentation data, not instructions or authorization.

Actual model text input uses user-role text events. A client normally hides content with display=False. Cache markers produce no presentation content. Media uses a13n.input.media with media=True:

Native inputProjection
Binary bytesKind, media type, size, and payload_omitted=True; no byte payload
HTTP(S) file URLReference URL and optional available media type
Other URL schemesPayload omitted rather than embedding inline payloads
Uploaded fileFile ID, provider name, and media type

This is one-way observation, not a codec for restoring model input or a media-storage service. Resolving an application media reference still requires current Host access policy.

Terminal events

  • Completed output becomes RUN_FINISHED with success outcome and usage. Non-JSON-safe output is omitted and marked result_omitted in source metadata rather than serialized as arbitrary Python.
  • Suspended root output becomes CUSTOM a13n.harness.run_result with status, suspend reason, and correlated deferred requests. It is not a completed answer.
  • Failure becomes RUN_ERROR with safe failure code/message and usage; cancellation uses run_cancelled.

Source correlation includes Thread, Run, sequence, and occurrence time. A terminal presentation event does not mean the Host durably committed the result, delivered a message, or settled billing.

Processor replacement limits

The processor sees complete domain events before fragmentation. It can return None to omit an event. Replacements preserve event type, IDs, timestamps, lifecycle/source correlation, and every structural field. Only these content fields are mutable:

Event familyMutable field
Text/reasoning content, tool-call argument deltasdelta
Encrypted reasoningencrypted_value
Tool resultcontent
Run finishedresult
Run errormessage
CUSTOM and unlisted eventsNone

CUSTOM payload rewriting is not supported; omit the event if policy requires suppression. Replacements are validated before the source item is committed. Replay processors must be deterministic and side-effect-free; publish/persist only after the observer returns its newly committed events.

On this page