Skip to content

feat(examples-chat): replace sub-LLM dispatch with parent-emits-envelopes#259

Merged
blove merged 3 commits into
mainfrom
claude/genui-streaming-envelope-tool
May 12, 2026
Merged

feat(examples-chat): replace sub-LLM dispatch with parent-emits-envelopes#259
blove merged 3 commits into
mainfrom
claude/genui-streaming-envelope-tool

Conversation

@blove
Copy link
Copy Markdown
Contributor

@blove blove commented May 12, 2026

Summary

Replaces the two-LLM GenUI flow (parent calls generate_a2ui_schema tool → sub-LLM produces envelopes → ToolMessage) with a single parent LLM that emits A2UI v1 envelopes directly as structured tool arguments under OpenAI strict mode.

The spike (committed earlier on claude/spec-genui-streaming-parent-llm) validated this approach against 15 representative prompts: 93% valid on gpt-5-mini, 80% on gpt-5 after argument-shape normalization. Strict-mode binding eliminates most non-canonical shapes; the normalizer (src/streaming/envelope_normalizer.py + parity TS in libs/chat/src/lib/a2ui/envelope-normalizer.ts) is the safety net for what slips through.

emit_generated_surface keeps its #255 job (static reorder + in-place AIMessage replacement). Wire shape unchanged for non-streaming consumers. PR 3 turns on live streaming via a callback handler that sidebands the parent LLM's tool_call_chunks as a2ui-partial custom events.

Spec: docs/superpowers/specs/2026-05-12-genui-streaming-sub-llm-design.md.

Test plan

  • pytest tests/test_envelope_tool.py — 7 tests
  • pytest tests/test_envelope_normalizer.py — 6 tests
  • pytest tests/test_graph_smoke.py — existing + 2 new tests
  • CI green

blove added 3 commits May 12, 2026 14:47
Parent-LLM-bound tool render_a2ui_surface accepts envelopes as typed
structured arguments. OpenAI strict-mode bind_tools will validate against
the Pydantic schema. Body serializes via model_dump(exclude_none=True)
so optional fields don't leak as null into the wire JSON.
Parity with libs/chat envelope-normalizer.ts. Accepts envelopes/envelope/
positional/flat shapes the parent LLM may emit under non-strict tool
binding. Returns a canonical envelope list or None.
Replaces the two-LLM hop (parent → tool body's sub-LLM) with a single
parent LLM bound to render_a2ui_surface(envelopes: list[A2uiEnvelope])
under OpenAI strict mode. The A2UI v1 schema prompt is appended to the
parent's system prompt with explicit envelope-emission ordering so the
surface mounts as soon as surfaceUpdate parses.

emit_generated_surface keeps its PR #255 job: read the validated envelope
list from ToolMessage, apply the static reorder for defence-in-depth,
wrap with A2UI_PREFIX, replace upstream AI message in place (single-bubble
invariant). The new envelope-emission flow already streams natively via
the parent LLM's tool_call_chunks; PR 3 attaches a callback handler that
sidebands the chunks as a2ui-partial custom events for the live UX.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 12, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cacheplane Ready Ready Preview, Comment May 12, 2026 9:52pm

Request Review

@blove blove merged commit 5df9fcb into main May 12, 2026
14 checks passed
blove added a commit that referenced this pull request May 12, 2026
…rk (#271)

Brings the canonical smoke checklist current with 29 PRs that landed
between Phase 7 (#239) and today without checklist updates. Specifically:

Updated sections:
- chat-debug devtools — replaced bottom-drawer model with floating
  launcher + status pill + switch (PRs #249, #251)
- Control palette — palette v2 (status pill, shadcn-styled panel, PR #244)
- Generative UI / A2UI surfaces — single-bubble invariant (PR #255),
  parent-emits-envelopes architecture (PR #259), wrapped-content +
  tool_calls coexistence (PR #255), envelope reorder
- Server-side wire format — tool_calls preserved on the final AI
- Replaced 'Multi-thread' section with 'Sidenav (thread management)'
  reflecting the permanent semantic <nav> + Active/Archived sections
  (PR #253) and removing the old palette-toggled drawer model

Added sections:
- Cmd+K history search — palette open/search/select/close, archived
  result subtitle, keyboard navigation (PR #253)
- Per-row thread actions — kebab menu order per state (active, pinned,
  archived), rename + pin/unpin + archive/unarchive + delete flows
  (PRs #258, #260, #267)
- Thread titles — first-user-message derivation, idempotent writes,
  manual rename precedence (PR #242)
- Progressive A2UI streaming — per-component fallback transition
  observable during streaming window (PRs #252, #261, #262, #268, #269)
- Inline checkpoint markers — render between messages during multi-step
  runs (PR #243)
- Responsive sidenav — viewport breakpoints, auto-collapse behavior (PR #240)

Total: ~58 new check items across 6 new sections, plus rewrites to 5
existing sections. Original 333-line checklist → 391 lines / 237 check
items.
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.

1 participant