mirror of
https://github.com/block/buzz.git
synced 2026-11-04 08:21:48 +00:00
A printed Builderlab agent card's QR leads to its share page (app.builderlab.xyz/a/<id>), whose "Add to Buzz" button opens buzz://agent/new?card=<id>. Mobile now handles that link: it fetches the card's agent.json from the avatars CDN for this build's Builderlab environment and opens the Agents page with an editable, prefilled Create agent form. Opening a link never creates an agent. - shared/deeplink: strict parser for buzz://agent/new?card=<token>; any other shape is not this link. - HostedEnvironment.avatarsCdnOrigin maps each account environment to its CDN; the link can never name the host. - AgentCreationDraft.fetch reads name, avatarUrl, instructions, model and reasoningEffort. Every field is optional: published cards have only name and avatar today. snake_case and a few synonyms are also read so a later agent.json revision degrades to a partial draft instead of failing. The avatar is used only from the same CDN; the body is capped at 256 KiB. - AgentsPage waits for sign-in, the registry load and remote-agent support, drops the link with a message if a setup is unfinished or the card can't be loaded, and replaces an open Agents stack rather than stacking one. - CreateAgentPage takes an optional draft; model and effort apply only if the live catalog offers them. - Table tests for the link and agent.json, and a journey test from link to Create against a fake CDN (needs BUZZ_AUTH_DOMAINS, like the other hosted agent tests). Co-authored-by: studio <dc2fc481343672df31a689840c09299972e704dac592e0da6f18486646a7ee3e@buzz.block.builderlab.xyz> Signed-off-by: Tom Brow <tomb@squareup.com>
51 lines
1.7 KiB
Dart
51 lines
1.7 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
import 'app.dart';
|
|
import 'features/age_gate/age_signal_push_bootstrap.dart';
|
|
import 'features/agents/agents_page.dart';
|
|
import 'features/invites/invite_join_provider.dart';
|
|
import 'shared/agents/agents_surface.dart';
|
|
import 'shared/push/push_bridge.dart';
|
|
import 'shared/relay/relay_closed_policy.dart';
|
|
import 'shared/theme/theme_provider.dart';
|
|
|
|
void main() => runBuzzApp(const App());
|
|
|
|
Future<void> runBuzzApp(Widget app) async {
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
installBuzzPushMethodHandler();
|
|
|
|
// Pre-load preferences so the first frame uses the saved theme/accent.
|
|
final prefs = await SharedPreferences.getInstance();
|
|
|
|
runApp(buildRootProviderScope(prefs: prefs, child: app));
|
|
}
|
|
|
|
/// The app's root scope, shared with tests so its production wiring is
|
|
/// asserted rather than re-declared.
|
|
ProviderScope buildRootProviderScope({
|
|
required SharedPreferences prefs,
|
|
required Widget child,
|
|
}) => ProviderScope(
|
|
// A relay statement deadline cannot resolve on retry — the same expensive
|
|
// query would re-run and hit the same limit. Return null (no retry) for
|
|
// deadline errors and fall through to the default exponential backoff for
|
|
// everything else.
|
|
retry: relayProviderRetry,
|
|
overrides: [
|
|
agentCreationSurfaceProvider.overrideWithValue(
|
|
(context, link) async => unawaited(showAgents(context, draft: link)),
|
|
),
|
|
savedPrefsProvider.overrideWithValue(prefs),
|
|
inviteJoinRecoveryProvider.overrideWith(
|
|
(ref) =>
|
|
(scope) => buildMobileInviteJoinRecovery(ref, scope),
|
|
),
|
|
],
|
|
child: AgeSignalPushBootstrap(child: child),
|
|
);
|