Skip to content

feat: v0.3.0 — v0.9 wire format migration#3

Merged
23min merged 8 commits intomainfrom
feat/v0.3.0-spec-v0.9
Feb 12, 2026
Merged

feat: v0.3.0 — v0.9 wire format migration#3
23min merged 8 commits intomainfrom
feat/v0.3.0-spec-v0.9

Conversation

@23min
Copy link
Owner

@23min 23min commented Feb 12, 2026

Summary

  • Migrate encoder/decoder to A2UI spec v0.9 wire format (breaking change)
  • Messages renamed: surfaceUpdateupdateComponents, dataModelUpdateupdateDataModel, beginRenderingcreateSurface, userActionaction (with event envelope)
  • Component properties moved to top level (flat format), literal values are plain (no wrapper objects), component type is a string discriminator
  • All messages include "version": "v0.9" and are wrapped in JSON arrays
  • Added :audio_player type, renamed :multiple_choice:choice_picker (18 standard types)
  • encode_surface/1 now returns single String.t() (JSON array) instead of [String.t()]
  • Decoder returns {:ok, [{:action, action, metadata}]} with extracted envelope metadata
  • 100 tests, all passing

Breaking Changes

Before (v0.8) After (v0.9)
Encoder.surface_update/1 Encoder.update_components/1
Encoder.data_model_update/2 Encoder.update_data_model/2
Encoder.begin_rendering/2,3 Encoder.create_surface/1
encode_surface/1[String.t()] encode_surface/1String.t()
{:ok, {:user_action, action}} {:ok, [{:action, action, metadata}]}
{"literalString": "hi"} "hi"
{"component": {"Text": {...}}} {"component": "Text", ...}
:multiple_choice :choice_picker

Test plan

  • mix ci passes (format + compile + 100 tests)
  • Manual test with mix run demo_server.exs — verify debug renderer at localhost:4000
  • Review CHANGELOG.md for completeness

🤖 Generated with Claude Code

23min and others added 8 commits February 11, 2026 10:50
Update devcontainer image and CI matrix to include latest
Elixir 1.19 / OTP 28, replacing the 1.16 / OTP 27 row.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add push_data/3, push_surface/2, broadcast/3, broadcast_all/2 to
A2UI.Server for broadcasting updates to connected clients from
external processes (timers, PubSub, GenServer casts).

- A2UI.Supervisor: OTP Supervisor (Registry + Bandit, rest_for_one)
- A2UI.SurfaceProvider: optional handle_info/2 callback
- A2UI.Socket: Registry registration, handle_info delegation
- Demo server: timer-based uptime push example
- 95 tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Research gap analysis of ex_a2ui (v0.8) vs A2UI spec (v0.9).
Roadmap updated with migration plan through v0.6.0.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Migrate encoder/decoder to A2UI spec v0.9 wire format. This is a
breaking change to the JSON output and decoder return types.

Wire format: messages renamed (updateComponents, updateDataModel,
createSurface, action), all messages versioned and array-wrapped,
component properties at top level, literal values plain (no wrapper),
action uses event envelope with metadata.

Types: added :audio_player, renamed :multiple_choice → :choice_picker
(18 standard types). Surface gained catalog_id field.

100 tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@23min 23min merged commit 741b8b0 into main Feb 12, 2026
3 checks passed
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