Skip to content

docs: add wire-safe serialization section for TypeScript streaming events#693

Open
agent-of-mkmeral wants to merge 12 commits intostrands-agents:mainfrom
agent-of-mkmeral:docs/wire-safe-streaming-serialization
Open

docs: add wire-safe serialization section for TypeScript streaming events#693
agent-of-mkmeral wants to merge 12 commits intostrands-agents:mainfrom
agent-of-mkmeral:docs/wire-safe-streaming-serialization

Conversation

@agent-of-mkmeral
Copy link
Copy Markdown
Contributor

Description

Documents the toJSON() serialization behavior for all TypeScript streaming events. When events are sent over the wire (SSE, WebSockets, HTTP responses), the toJSON() method ensures compact output (~100-200 bytes) instead of serializing the entire Agent instance (~54KB+ per event).

Changes

  • Streaming Overview (index.mdx): Added new "Wire-Safe Serialization (TypeScript)" section with:

    • How toJSON() works with JSON.stringify()
    • Complete table of what each event serializes to
    • List of excluded fields (agent, tool, cancel, retry)
    • Error serialization format ({ error: { message?: string } })
    • Code example showing in-process vs wire access patterns
  • Express.js example (async-iterators.ts): Added comments explaining the automatic wire-safe serialization behavior

Related Issues

Type of Change

  • New content

Checklist

  • I have read the CONTRIBUTING document
  • My changes follow the project's documentation style
  • I have tested the documentation locally using npm run dev
  • Links in the documentation are valid and working

…ents

Document the toJSON() serialization behavior for all TypeScript streaming
events. This includes:

- New 'Wire-Safe Serialization' section in the streaming overview
- Table showing what each event serializes to
- Explanation of excluded fields (agent, tool, cancel, retry)
- Error handling format ({ error: { message?: string } })
- In-process vs wire access patterns
- Updated Express.js example with serialization comments

Related: strands-agents/sdk-typescript#708
- Remove verbose 'How It Works', 'Excluded Fields', 'Error Handling',
  and 'In-Process Access' subsections
- Keep single concise paragraph explaining serialization behavior
- Retain events table showing what each event serializes to
- Mention excluded fields (agent, tool, cancel, retry) inline

Co-authored-by: mkmeral <mkmeral@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 21, 2026

Documentation Preview Ready

Your documentation preview has been successfully deployed!

Preview URL: https://d3ehv1nix5p99z.cloudfront.net/pr-cms-693/docs/user-guide/quickstart/overview/

Updated at: 2026-04-01T14:10:52.004Z

Copy link
Copy Markdown
Contributor

@mkmeral mkmeral left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

…fields

Address review feedback:
- Rename 'Wire-Safe Serialization (TypeScript)' to 'Event Serialization'
- Wrap in <Tabs> with Python/TypeScript tabs
- Lead with what each event keeps during serialization
- Move excluded fields mention to secondary position after table
- Use 'serialization' language instead of 'wire-safe'
@mkmeral
Copy link
Copy Markdown
Contributor

mkmeral commented Mar 21, 2026

add this under streaming events tabs (that already exist) or something, I don't want a tab for python. also that python info is not correct anyway

@mkmeral
Copy link
Copy Markdown
Contributor

mkmeral commented Mar 21, 2026

@agent-of-mkmeral

…nt types

Address review feedback from @mkmeral:
- Remove Tabs wrapper and Python tab (info was not correct)
- Downgrade to ### subsection under Event Types (same level as
  Lifecycle Events, Model Stream Events, etc.)
- TypeScript serialization content stays as-is, directly under heading
@agent-of-mkmeral
Copy link
Copy Markdown
Contributor Author

Done in f01de2e — addressed both points:

  • Removed the Python tab (info was incorrect anyway)
  • Removed the <Tabs> wrapper entirely — the section is now ### Event Serialization (a subsection under Event Types, same level as Lifecycle Events, Model Stream Events, etc.) with just the TypeScript serialization content directly

Net change: -11 lines, +1 line.

@agent-of-mkmeral
Copy link
Copy Markdown
Contributor Author

Merged main into this branch to fix the CI failure.

Root cause: The typecheck:snippets step was failing with:

error TS2307: Cannot find module '@strands-agents/sdk/openai' or its corresponding type declarations.

in deploy_to_docker/imports.ts and deploy_to_docker/index.tscompletely unrelated to this PR's streaming docs changes. These files were updated on main (likely by a recent rename/refactor of the OpenAI provider module), and this branch was behind.

Fix: Merged upstream main (97aa679) → commit dd35581. No conflicts.

CI should be green now. @mkmeral

Updates Event Serialization section for sdk-typescript PR #741:

- Put Event Serialization under Python/TypeScript tabs
- Add multi-agent event serialization table (10 events from PR #741)
- Add A2A event serialization table (2 events from PR #741)
- Add Python tab explaining event filtering approach
- Update excluded fields list to include orchestrator and state
- Note Error object serialization format
Replace the three comprehensive tables (agent events, multi-agent events,
A2A events) in the TypeScript serialization tab with prose that explains
the behavior, the key differences during serialization, and mentions a
few examples of filtered/included fields without an exhaustive listing.

Python tab remains unchanged.
Show what an event looks like in-process (with agent reference)
versus what JSON.stringify produces (compact wire-safe output).
Covers text deltas, lifecycle events, and result events.
@mkmeral mkmeral temporarily deployed to manual-approval March 25, 2026 19:22 — with GitHub Actions Inactive
@mkmeral mkmeral temporarily deployed to manual-approval March 25, 2026 19:22 — with GitHub Actions Inactive
@mkmeral
Copy link
Copy Markdown
Contributor

mkmeral commented Mar 27, 2026

/strands review

Copy link
Copy Markdown
Contributor Author

@agent-of-mkmeral agent-of-mkmeral left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — /strands review

Overall: Looks good to me ✅ — clean addition, well-structured, all previous feedback addressed.

Summary

Aspect Status
CI ✅ Green
All 3 review threads ✅ Resolved
Placement ### Event Serialization under Event Types, before Quick Examples
Consistency ✅ Uses <Tabs> pattern matching rest of page
Files changed 2 files, +81/-2 lines

What's Good

  1. TypeScript tab — Clear explanation of toJSON() mechanics. The code example with inline comments showing in-process vs serialized output is really instructive. Leads with what each event keeps (per earlier feedback).

  2. Python tab — The filter_event() helper is practical and actionable. Since Python events are plain dicts with no built-in serialization filter, showing a concrete pattern users can adapt is the right call.

  3. async-iterators.ts — The 3-line comment on the JSON.stringify(event) call adds context without being noisy.

Minor Nits (non-blocking)

  1. "wire-safe" in async-iterators.ts comment — The code comment says "Events automatically serialize to compact, wire-safe JSON via toJSON()". Earlier feedback asked to prefer "serialization" language over "wire" language. Consider:

    // Events automatically serialize to compact JSON via toJSON().
    

    (Drop "wire-safe" to stay consistent with the main docs section title "Event Serialization".)

  2. Python tab existence — Previous feedback said "I don't want a tab for python". The content is completely rewritten now (the incorrect info is gone, replaced with a useful filter_event pattern), so this is likely fine — but flagging in case @mkmeral still prefers no Python tab here.

Neither nit is blocking. PR is ready for maintainer approval.

The same behavior applies to multi-agent and A2A events. Multi-agent events include identifying context like `nodeId` and `nodeType` alongside their data, while the `orchestrator` and `state` references are filtered out. This means you can serialize any event from `agent.stream()` or a multi-agent orchestrator's stream without additional processing:

```typescript
for await (const event of agent.stream('Hello')) {
Copy link
Copy Markdown
Member

@pgrayy pgrayy Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Consider defining in ts file for type checking/linting.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in the previous commit (26b0635) — moved the snippet into overview.ts with --8<-- [start/end:event_serialization] markers for type checking. This latest commit (d506871) also rewrites the snippet contents to be real executable code.

pgrayy
pgrayy previously approved these changes Mar 31, 2026
Address @pgrayy's review nit: extract the inline TypeScript code block
from index.mdx into overview.ts with --8<-- markers, matching the
existing pattern used by all other code snippets on this page.

Also drops 'wire-safe' from the async-iterators.ts comment per
earlier review feedback to use 'serialization' language consistently.
@agent-of-mkmeral
Copy link
Copy Markdown
Contributor Author

Addressed @pgrayy's nit in 26b0635:

  • Moved the inline TypeScript code block from index.mdx into overview.ts with --8<-- [start:event_serialization] / [end:event_serialization] markers — matching the pattern used by all other snippets on this page. This gives us type checking/linting on the snippet.
  • Dropped "wire-safe" from the async-iterators.ts comment to stay consistent with "serialization" language.

CI should pick it up. PR is ready to merge once it goes green. 🚀

for await (const event of agent.stream('Hello')) {
// Every event is a class instance. In-process, it carries the full agent reference:
//
// event.type → "modelStreamUpdateEvent"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is sort of a weird example as it's mostly entirely commented out code:

Image

Can we output the information and/or add filtering behavior like the python implementation. A chunk of commented out code doesn't make for a good example IMHO

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call — pushed d506871 to fix this.

Replaced the commented-out block with a real switch/case that mirrors the Python tab's filter_event pattern:

  • Forwards text deltas for real-time display
  • Forwards tool names for progress indicators
  • Forwards the final agentResultEvent
  • Skips everything else (lifecycle, metadata, etc.)

All executable code, no comments pretending to be output.


Every event class implements a `toJSON()` method that controls what `JSON.stringify()` produces. This keeps serialized payloads compact for SSE, WebSockets, or HTTP responses — without changing the in-process API.

Each serialized event always includes its `type` discriminator alongside the data fields relevant to that event. For example, a `ModelStreamUpdateEvent` serializes to `{ type, event }` with just the streaming delta, and an `AgentResultEvent` includes `{ type, result }` with the final output. Lifecycle events like `BeforeInvocationEvent` and `AfterInvocationEvent` serialize to just `{ type }`, since they signal state transitions without carrying additional data.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be much more concise; we spend 4 paragraphs explaining that toJSON() excludes object references and properties that are settable; I think we can state that and indicate that it matches the general shape and data of the class but exclude settable properties and object references specific to in-memory (like agent/graph etc.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Condensed in the same commit (d506871).

4 paragraphs → 1 paragraph. Now reads:

Every event class implements a toJSON() method that JSON.stringify() calls automatically. Each serialized event retains its type discriminator and the relevant data fields — matching the general shape of the class — while excluding in-memory runtime references (agent, orchestrator, state, tool) and mutable hook properties (cancel, retry). Error objects are converted to { message: string }. This applies to single-agent, multi-agent, and A2A events alike.

- Condensed 4 paragraphs about toJSON() into 1 concise paragraph (index.mdx)
- Replaced commented-out code with a real event-filtering example that
  mirrors the Python tab's filter_event pattern (overview.ts)
- The TS snippet now shows a switch/case that forwards text deltas,
  tool names, and the final result — all real executable code
@agent-of-mkmeral
Copy link
Copy Markdown
Contributor Author

Addressed @zastrowm's review in d506871:

Thread Feedback Fix
overview.ts Code example is mostly comments Replaced with real switch/case filtering pattern (text deltas, tool names, final result) — mirrors the Python tab
index.mdx 4 paragraphs is too verbose Condensed to 1 concise paragraph
index.mdx (@pgrayy) Move to .ts file for type checking Already done in 26b0635, this commit also rewrites the snippet

CI should pick it up. Ready for re-review. 🚀

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 1, 2026

Assessment: Approve

Good documentation addition for TypeScript event serialization. Previous review feedback from @pgrayy and @zastrowm has been addressed.

Review Summary
  • Content Quality: Clear, concise explanation of toJSON() behavior — condensed from 4 paragraphs to 1 as requested
  • Code Examples: Real filtering pattern with switch/case replaces the commented-out code
  • Project Patterns: Snippet markers and function wrappers used correctly per guidelines

The open review threads can be resolved since all feedback has been implemented. 🚀

@strands-agents strands-agents deleted a comment from github-actions bot Apr 1, 2026
@strands-agents strands-agents deleted a comment from github-actions bot Apr 1, 2026
@strands-agents strands-agents deleted a comment from github-actions bot Apr 1, 2026
@strands-agents strands-agents deleted a comment from github-actions bot Apr 1, 2026
@strands-agents strands-agents deleted a comment from github-actions bot Apr 1, 2026
@strands-agents strands-agents deleted a comment from github-actions bot Apr 1, 2026

Every event class implements a `toJSON()` method that `JSON.stringify()` calls automatically. Each serialized event retains its `type` discriminator and the relevant data fields — matching the general shape of the class — while excluding in-memory runtime references (`agent`, `orchestrator`, `state`, `tool`) and mutable hook properties (`cancel`, `retry`). `Error` objects are converted to `{ message: string }`. This applies to single-agent, multi-agent, and A2A events alike.

Like the Python example, you can filter which events to forward:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't reference Python here! People aren't looking at both

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 8fc5a3a — changed:

Like the Python example, you can filter which events to forward:

You can filter which events to forward to the client:

Good catch — users viewing the TS tab haven't seen the Python tab.

Address @zastrowm review — users viewing the TypeScript tab haven't
seen the Python tab, so 'Like the Python example' is a broken reference.
Changed to standalone phrasing.
@agent-of-mkmeral
Copy link
Copy Markdown
Contributor Author

Addressed @zastrowm's latest feedback in 8fc5a3a:

Thread Feedback Fix
index.mdx:224 Don't reference Python in TS tab Removed cross-reference — now says "You can filter which events to forward to the client:"

All previous threads were already addressed. Ready for re-review. 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants