mirror of
https://github.com/block/buzz.git
synced 2026-11-03 07:51:22 +00:00
Builderlab agent cards (printed for the event, and generated at the kiosk) carry a QR to a share page, `app.builderlab.xyz/a/<id>`. Its **Add to Buzz** button opens `buzz://agent/new?card=<id>`, which no Buzz client handled until now. This PR makes mobile handle it. ### Behavior - Opening the link shows the Agents page, then a Create agent form prefilled from the card. Everything stays editable, and nothing is created until the user taps Create. - The app fetches the card's `agent.json` from the avatars CDN for this build's Builderlab environment (production or staging). The link carries only the card id, never a host, so the QR stays small no matter how long a card's instructions get. - `agent.json` is validated against the card schema. `id` (matching the link), `name` and `avatarUrl` (an https URL) are required. `instructions`, `model` and `reasoningEffort` are optional (published cards don't have them yet) and left for the user when absent. A missing required field or a wrongly typed known field rejects the card; any other key is ignored whatever its type, including `v` and `description` (Buzz agents have no description to prefill), so Builderlab can add fields without breaking released apps. The model and effort are preselected only if the live catalog offers them. The card id is opaque: any non-empty id is accepted and percent-encoded into the URL. - The fetch uses the same limits as image downloads, now shared in `bounded_fetch.dart`: aborted after 20 s without a byte or 5 min overall, and rejected over 2 MB. `MediaImageProvider` now calls the same helper, with no behavior change. - The link waits for sign-in, then reloads the registry for the signed-in account before anything else. It's dropped with a message if the card is unavailable (403/404), invalid, can't be loaded (any other response), or an agent setup is unfinished, including a setup saved before a sign-in the link triggered. - A link that arrives while Agents shows only its list replaces that page instead of stacking a second one. If a form or sheet is open there, the link is dropped with "Finish or close what’s open in Agents, then reopen the link." and the open work is kept. ### Demo Simulator (iPhone 17 Pro, debug build of this branch plus the sign-in fix from [#8914](https://github.com/block/buzz/pull/8914) and the hidden debug banner from [#8915](https://github.com/block/buzz/pull/8915), signed in to Builderlab, remote-agent-pilot), recorded in one take with idle time trimmed: the card's share page in Safari, Add to Buzz, the prefilled Create agent form, a model, thinking level and instructions, Create, then a message and the agent's reply. https://github.com/user-attachments/assets/e66aae17-884a-4e68-a1b8-ecb40562be1d ### Validation Added tests: - Table tests for the link shape (only `?card=<id>` with an opaque id; the inline `#` form, extra parameters and dot segments are rejected) and for reading `agent.json` (a published card, a card with instructions and model defaults, unknown keys of any type ignored, including `v`, `description`, arrays, objects and null, and invalid cards: missing or mismatched required fields, wrong types, and non-https or relative avatars). - Table tests for fetching: the request goes to this build's CDN without following redirects, with the id percent-encoded as one path segment; 403/404, a redirect, a 500, a network error, declared and streamed oversize bodies, non-JSON and a JSON array each give a specific message. The image loader's existing stall, deadline, cap and cancel tests now cover the shared helper. - A journey test from link to Create against a fake CDN: prefill and edit, then submit; an unavailable card; a failed model catalog whose Retry then preselects the card's model; a Builderlab account change while the card loads, which drops the draft; a v1 card with no instructions and an unknown model; an unfinished setup; a link arriving while a Create form with edits is open, which keeps the form and its edits; and a link arriving while Agents is open. Disabling the https or id check makes the table test fail, and removing either the account recheck or the loaded-catalog check fails the journey. The journey runs through the production root scope (removing its link handler fails it) and runs in CI's configured-authentication-domains step. Full mobile check and test suite pass locally. Live data: a real staging card's `agent.json` (`av_MioTAG6dm7q3Zcm0UV2j8A`) has the v1 shape the table test uses, and an unknown id returns 403 from the CDN. Live run on an iPhone SE (build of 63ed54c749, Builderlab sign-in enabled, remote-agent-pilot, signed in as builderlab@tombrow.com) with a real production card, [ToastyMacbeth](https://app.builderlab.xyz/a/av_lrmRlJR6ylrQKvJkoLWCOQ) (a v1 card with no instructions and an extra `description` key): - Opening `buzz://agent/new?card=av_lrmRlJR6ylrQKvJkoLWCOQ` from a cold start opens Create agent prefilled with the card's name and avatar. - After choosing a model and adding instructions, Create adds the agent with the card avatar, and it replies in a DM. - An unknown card id shows "This agent card isn’t available." | Prefilled | Created | Reply | Unknown card | | --- | --- | --- | --- | | <img src="https://raw.githubusercontent.com/block/buzz/b9222db494758c3e536b8e2011032ba7cec86daa/pr-8912--01-prefilled.png" width="200"> | <img src="https://raw.githubusercontent.com/block/buzz/b9222db494758c3e536b8e2011032ba7cec86daa/pr-8912--02-created.png" width="200"> | <img src="https://raw.githubusercontent.com/block/buzz/b9222db494758c3e536b8e2011032ba7cec86daa/pr-8912--03-reply.png" width="200"> | <img src="https://raw.githubusercontent.com/block/buzz/b9222db494758c3e536b8e2011032ba7cec86daa/pr-8912--04-unavailable.png" width="200"> | Before this PR, the app had no handler for `buzz://agent/new`, so the link did nothing. A separate widget test covers a link that needs Builderlab sign-in first: once sign-in lands, a setup saved for that account blocks the card, which is never fetched. Removing the registry reload fails it, as does removing the busy-Agents guard for the journey step above. ### Before merge - [x] Human live check waived under the repository owner's standing testing exception. In its place, agent-driven full-app runs exercised the flow end to end: the iPhone SE device run and the simulator demo above (a real card's share page, **Add to Buzz**, the prefilled form, Create and a reply from the agent). Limitation: those runs predate [638f5ecac7](638f5ecac7), whose two guards are covered by the widget tests above rather than a live run. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: Tom Brow <tomb@squareup.com> Co-authored-by: Tom Brow <tomb@squareup.com> Co-authored-by: studio <dc2fc481343672df31a689840c09299972e704dac592e0da6f18486646a7ee3e@buzz.block.builderlab.xyz> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>