Skip to content

docs(python/agent): document per-request processors, RendererState and streaming - #3271

Open
nan-yu wants to merge 10 commits into
feat/python-agent-processor-statefrom
docs/python-agent-renderer-state
Open

nan-yu wants to merge 10 commits into
feat/python-agent-processor-statefrom
docs/python-agent-renderer-state

Conversation

@nan-yu

@nan-yu nan-yu commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Part of #3262 and #3263. Stacked on #3270.

Documentation for the changes in #3268, #3269 and #3270.

  1. agent_development.md explains creating a processor per request from the client's capabilities, the chat and canvas lifetimes of a RendererState, and reading a streamed response with open_stream, feed and close.
  2. The agent SDK README lists RendererState and ResponseStream and describes the stateless parser.
  3. The a2ui-a2a README describes to_a2a_parts and stream_response_to_parts with a ResponseStream.
  4. a2ui.constants gains A2UI_RENDERER_CAPABILITIES_KEY ("a2uiRendererCapabilities"), the message metadata key under which the v1.0 A2A extension sends the renderer capabilities; v0.8 and v0.9 use A2UI_CLIENT_CAPABILITIES_KEY. The sample PRs stacked on this one (refactor(samples): per-request processors in restaurant_finder and custom-components-example #3272, refactor(samples): per-request processors in the ADK toolset samples #3274) read it.
  5. The streaming section of agent_development.md says which messages the direct JSON stream emits while they grow (updateComponents and updateDataModel) and that every other message waits for its object to close, as feat(python/agent)!: make the Parser stateless; always validate; add ResponseStream #3269 now does, and that a v0.8 chat response that never sends beginRendering is rejected (feat(python/agent): add RendererState; build validate_payload on it #3268).

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request updates the documentation in python/a2ui_a2a/README.md, python/a2ui_agent/README.md, and python/a2ui_agent/agent_development.md to align with API changes around response parsing, streaming, and state management (such as to_a2a_parts, stream_response_to_parts, and RendererState). The review feedback points out two issues in the code examples within agent_development.md: invalid Python syntax in a placeholder and an undefined capabilities variable in the multi-version support example.

Comment thread python/a2ui_agent/agent_development.md Outdated
Comment thread python/a2ui_agent/agent_development.md
@nan-yu
nan-yu added this pull request to stack #3275 October 16, 2026 19:09
@nan-yu
nan-yu force-pushed the docs/python-agent-renderer-state branch from 0df8f19 to cf5db13 Compare October 16, 2026 19:34
@nan-yu
nan-yu force-pushed the docs/python-agent-renderer-state branch from cf5db13 to 6e471f6 Compare October 16, 2026 19:51
@nan-yu
nan-yu force-pushed the docs/python-agent-renderer-state branch from 6e471f6 to 74fb3d8 Compare October 16, 2026 19:53
@nan-yu
nan-yu force-pushed the docs/python-agent-renderer-state branch from 229788b to 7b4baed Compare October 16, 2026 22:57
…d streaming

1. `agent_development.md` explains the chat and canvas lifetimes of a
   `RendererState`, creating a processor per request from the client's
   capabilities, and reading a streamed response with `open_stream`,
   `feed` and `close`.
2. The agent SDK README lists `RendererState` and `ResponseStream`.
3. The `a2ui-a2a` README shows `stream_response_to_parts` with a
   `ResponseStream` and `to_a2a_parts`.

Part of #3262 and #3263.

Signed-off-by: Nan Yu <nanyu@google.com>
The LlmAgent example passes an empty tools list instead of a placeholder
that isn't Python, and the multi-version example reads the client's
capabilities before it creates the processor.

Signed-off-by: Nan Yu <nanyu@google.com>
agent_development.md still said the catalogs must be freestanding, and
linked to a section of the catalogs guide that no longer exists. Since
cross-catalog references are resolved against peer catalogs, it now says
which catalogs a reference resolves against and links to Catalog
Linking.

Signed-off-by: Nan Yu <nanyu@google.com>
…nt inference formats

1. Step 2 no longer loads examples into the prompt with load_examples:
   the generator's examples are checked against the request's catalogs
   and written into processor.prompt_snippet. It shows how to give the
   generator example turns instead.
2. Allowed messages are set on the format factory given to the
   generator, not by calling schema_to_prompt, and use the message
   names the formats read ("createSurface", "updateComponents").
3. A new "Choose an Inference Format" section: Direct JSON is the
   default and the only format that streams; Express needs fewer output
   tokens and is parsed whole.
4. Option B says it needs Direct JSON, and that the stream must be
   closed after the last chunk, which stream_response_to_parts does.

Signed-off-by: Nan Yu <nanyu@google.com>
@nan-yu
nan-yu force-pushed the docs/python-agent-renderer-state branch from 7b4baed to eebbda5 Compare October 16, 2026 23:07
Comment thread python/a2ui_agent/agent_development.md Outdated

@gspencergoog gspencergoog left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Docs-only change (stack #3275, 5 of 6) that rewrites agent_development.md and the a2ui_agent / a2ui_a2a READMEs around per-request processors, open_stream() / feed() / close(), to_a2a_parts / stream_response_to_parts, and the chat-versus-canvas RendererState model. I checked every symbol, import path, keyword argument, exception class, link, and behavioral claim on the changed lines against the source in the checkout (processor.py, generator.py, parser.py, response_stream.py, renderer_state.py, catalog_resolver.py, schema_pruning.py, parts.py, the v0.9 server_to_client.json schema, and the pinned ADK Runner signature), and parsed every Python block on a changed line. All of it matches; no findings.

Two notes for context rather than action. The sentence that custom-components-example starts a new state when the client's catalogs change describes #3272 (next in the stack), which adds that logic in _renderer_state(); the sample on disk at this commit still uses the removed create_parser() API. The allowed_messages=["createSurface", "updateComponents"] example works for v0.9 (prune_messages_schema also matches message keys, and the Express prompt generator accepts both spellings), but the prune_messages_schema docstring only names CreateSurfaceMessage-style names; that docstring is outside this diff.

🤖 Agent-generated

@ditman ditman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Optional, while you're in these files:

  1. agent_development.md L578: a2ui.a2a has no A2UI_EXTENSION_URI; use get_a2ui_extension_uri(version).
  2. agent_development.md L663: the v0.9 basic catalog id is https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json.
  3. agent_development.md L438: LlmAgent(instruction=instruction, ...) is a SyntaxError, like the placeholder you fixed.
  4. python/a2ui_agent/README.md L61: A2uiTargetNotFoundError doesn't exist; errors.py defines the A2uiCompilation*Error classes.

LGTM, these are a bunch of nits.

Comment thread python/a2ui_agent/agent_development.md Outdated
Comment thread python/a2ui_agent/agent_development.md Outdated
Comment thread python/a2ui_agent/agent_development.md Outdated
Comment thread python/a2ui_agent/agent_development.md Outdated
Comment thread python/a2ui_agent/agent_development.md Outdated
Comment thread python/a2ui_agent/agent_development.md
…e' into docs/python-agent-renderer-state

Signed-off-by: Nan Yu <nanyu@google.com>
- Fix code blocks that weren't valid Python or used undefined names:
  define catalogs in Step 1, name the 4b variable version, guard against
  message.metadata being None, and drop '...' arguments.
- Describe the stream as the code behaves: messages emit as soon as part
  of them reads and again as they grow, strings heal only for
  progressive_keys (none by default), change detection is per message.
- Read a streamed retry with open_stream(state=stream.state), and say what
  a failed stream leaves in the state.
- Use accepts_state to tell when a kept state no longer fits the request's
  catalogs, which follow the client's supportedCatalogIds order.
- Fix the orchestrator's extension URI, the v0.9 basic catalog id, the
  unresolved $ref note, v0.8 buffering, inline catalogs, to_message_dicts
  for create_a2ui_part, and the README notes on open_stream, errors.py and
  parse_content_to_parts.

Signed-off-by: Nan Yu <nanyu@google.com>

@nan-yu nan-yu left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Thanks @ditman, I also took the optional ones in 2f34d3a:

  1. The orchestrator compares against get_a2ui_extension_uri(ProtocolVersion.V0_9).
  2. The proxy uses the real v0.9 basic catalog id, https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json.
  3. LlmAgent(model=..., name="...", instruction=instruction). 4a had the same problem in def __init__(self, agent, ...) and MyAgentExecutor(agent=agent, ...), which are fixed too. Every Python block in the guide and both READMEs now parses.
  4. The README's errors.py line lists A2uiCompilationError, A2uiCompilationParseError and A2uiCompilationValidationError.

The v1.0 A2A extension sends the renderer capabilities under
a2uiRendererCapabilities; v0.8 and v0.9 use a2uiClientCapabilities. The
sample PRs stacked on this one (#3272, #3274) each added the constant, so
it lands here once.

Signed-off-by: Nan Yu <nanyu@google.com>
…nt-renderer-state

Describe the stream as it now emits: only updateComponents and updateDataModel while they grow, every other message once its object closes, each chunk read once. A v0.8 chat response that never sends beginRendering is rejected.

Signed-off-by: Nan Yu <nanyu@google.com>

This branch has not been deployed

No deployments
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.

3 participants