Criar e personalizar catálogos de componentes

Na arquitetura A2UI, cada superfície é impulsionada por um catálogo de componentes. Um catálogo é um contrato formal que define os componentes da interface, os esquemas de propriedades e as funções de cliente locais disponíveis para um agente de IA. Em vez de gerar código arbitrário ou inventar elementos desconhecidos, o agente precisa construir interfaces do usuário usando exclusivamente os componentes declarados no catálogo.

Em outras palavras, o catálogo declara os componentes, e o agente os usa para criar a interface do app.

Ao criar um app Android com o renderizador A2UI do Jetpack Compose, você tem opções flexíveis de como fornecer catálogos:

  • O catálogo básico: o projeto A2UI define uma especificação padronizada e de uso geral chamada catálogo básico, que inclui elementos comuns, como botões, texto, campos de texto, cards e listas. A biblioteca AndroidX androidx.compose.material3:material3-a2ui oferece uma implementação pronta para uso dessa especificação do catálogo básico usando componentes nativos do Material Design 3. A biblioteca androidx.a2ui.compose:compose-ui também oferece uma definição de esquema genérico para o catálogo básico, que ajuda você a implementar o catálogo básico no seu próprio sistema de design.
  • Catálogos personalizados: para aplicativos de produção com sistemas de design distintos, é possível criar um catálogo personalizado do zero. Isso restringe o agente aos componentes exatos, tokens de estilo e linguagem visual do seu app.
  • Um subconjunto ou híbrido: é possível combinar implementações de componentes específicos do catálogo básico fornecido com seus próprios componentes personalizados ou substituir implementações de componentes individuais no pacote do catálogo básico.

Usar o catálogo básico fornecido

Para começar rapidamente sem criar um esquema de componente do zero, você pode usar a implementação fornecida da especificação do catálogo básico A2UI. A biblioteca androidx.compose.material3:material3-a2ui implementa o catálogo básico usando componentes do Material Design 3.

Ao instanciar materialA2uiBasicCatalogV1, forneça renderizadores e manipuladores para o seguinte:

  • Componentes de mídia, como imagens, vídeos e players de áudio
  • Abridor de URL
  • Formatação de mensagens localizadas

As bibliotecas A2UI não agrupam dependências de mídia e rede externas, como Coil, Glide ou Media3. Em vez disso, você fornece seus próprios renderizadores. Isso evita conflitos de dependência ao fornecer bibliotecas exclusivas. Por exemplo, se o app já usa o Coil para carregamento de imagens ou o Media3 para reprodução, você pode conectar essas bibliotecas diretamente ao catálogo.

O exemplo a seguir demonstra como instanciar o catálogo básico e conectar suas bibliotecas de mídia, abridor de URL e formatador de mensagens preferidos:

// Instantiate the provided Basic Catalog (implemented with Material 3)
val basicCatalog = materialA2uiBasicCatalogV1(
    // Example: Wire up Coil for image loading (via AsyncImage)
    image = MaterialA2uiBasicCatalogV1Defaults.image {
            url, description, scale, modifier, onError ->
        AsyncImage(
            model = url,
            contentDescription = description,
            contentScale = scale,
            modifier = modifier,
            onError = { state -> onError(state.result.throwable) },
        )
    },

    // Example: Use ExoPlayer/Media3 for video
    video = MaterialA2uiBasicCatalogV1Defaults.video { url, modifier, onError ->
        // Custom ExoPlayer video integration here
    },

    // Example: Use an audio player
    audioPlayer = MaterialA2uiBasicCatalogV1Defaults.audioPlayer {
            url, description, modifier, onError ->
        // Custom audio integration here
    },

    // Handle outbound URLs, such as using an app navigator or context intents.
    urlOpener = { url ->
        appNavigator.openUrl(url)
    },

    // Handle localized message formatting
    messageFormatter = { pattern, locale, args ->
        MessageFormat.format(context, locale, pattern, args)
    },
    localeProvider = A2uiLocaleProvider.Default,
)

Montar um catálogo de componentes personalizados do zero

Se o app usa um sistema de design personalizado, você pode definir seu próprio catálogo com suas próprias implementações A2uiComponent personalizadas. Essa abordagem dá a você controle total sobre os esquemas de componentes expostos ao agente e a interface do Compose nativa emitida:

// Define a custom catalog that mirrors your app's design system
val CustomDesignSystemCatalog = A2uiCatalog(
    catalogId = "https://example.com/catalogs/my-design-system/v1/catalog.json",
    components = listOf(
        CustomButtonComponent,
        CustomCardComponent,
        CustomTextFieldComponent,
    ),
    functions = listOf(MyCustomLocalFunction()),
)

Para instruções sobre como definir esquemas de componentes individuais e a lógica de renderização da interface do Compose, consulte Implementar componentes personalizados da A2UI.

Usar um subconjunto de componentes do catálogo básico com componentes personalizados

Você não precisa escolher entre criar tudo do zero ou adotar todo o catálogo básico. Você pode montar um catálogo que combine componentes selecionados da implementação do catálogo básico fornecida com seus próprios componentes personalizados:

// Assemble a catalog using select Basic Catalog components alongside custom components
val hybridCatalog = A2uiCatalog(
    catalogId = "https://example.com/catalogs/my-app/v1/catalog.json",
    components = listOf(
        // Use provided Basic Catalog components (built with Material 3)
        MaterialA2uiBasicCatalogV1Defaults.text,
        MaterialA2uiBasicCatalogV1Defaults.card,

        // Add proprietary components from your app's design system
        CustomChartComponent,
        CustomProductCardComponent,
    ),
    functions = createBasicCatalogFunctions(...),
)

Como alternativa, é possível personalizar o pacote do catálogo básico fornecido substituindo slots de componentes específicos:

// Override specific components within the Basic Catalog suite
val customizedBasicCatalog = materialA2uiBasicCatalogV1(
    // Supply required renderers (such as Coil or ExoPlayer) as shown earlier
    image = MaterialA2uiBasicCatalogV1Defaults.image(myImageRenderer),
    video = MaterialA2uiBasicCatalogV1Defaults.video(myVideoRenderer),
    audioPlayer = MaterialA2uiBasicCatalogV1Defaults
        .audioPlayer(myAudioRenderer),
    urlOpener = { url -> /* Open URL */ },
    messageFormatter = { pattern, _, _ -> pattern },
    localeProvider = A2uiLocaleProvider.Default,
    // Replaces the default button. If you use this, implement the
    // A2uiBasicCatalogV1.Button interface.
    button = MyCustomBrandButtonComponent,
    
)

Gerenciar o controle de versões do catálogo e a evolução do esquema

Os catálogos da A2UI são versionados explicitamente com base no contrato de esquema JSON. Um aumento de versão é necessário ao introduzir mudanças interruptivas no esquema:

// Original component (v1 catalog)
object CustomButtonComponent : A2uiComponent { ... }

// Unchanged component across versions
object CustomTextComponent : A2uiComponent { ... }

// Future breaking schema change (v2 catalog)
object CustomButtonComponentV2 : A2uiComponent { ... }

// Assembles the v1 catalog
fun customCatalogV1(
    button: A2uiComponent = CustomButtonComponent,
    text: A2uiComponent = CustomTextComponent,
): A2uiCatalog = A2uiCatalog(
    catalogId = "https://example.com/catalogs/my-app/v1/catalog.json",
    components = listOf(button, text),
)

// Assembles the v2 catalog
fun customCatalogV2(
    button: A2uiComponent = CustomButtonComponentV2,
    text: A2uiComponent = CustomTextComponent,
): A2uiCatalog = A2uiCatalog(
    catalogId = "https://example.com/catalogs/my-app/v2/catalog.json",
    components = listOf(button, text),
)

Para permitir migrações sem interrupções e sem inatividade, seu cliente pode registrar várias versões compatíveis do catálogo com o processador de mensagens simultaneamente:

private val processor = A2uiMessageProcessor(
    catalogs = listOf(
        customCatalogV1(),
        customCatalogV2(),
    ),
)

Durante a negociação de catálogo, o agente descobre todos os IDs de catálogo compatíveis e segmenta a versão adequada para cada plataforma.

Detalhes de implementação

As seções a seguir explicam a validação interna do catálogo e a negociação de esquema.

As jornadas do usuário de gerenciamento de catálogo apresentam as seguintes APIs principais:

  • A2uiCatalog: interface e função de fábrica de nível superior para definir catálogos de componentes.
  • materialA2uiBasicCatalogVX: funções de fábrica com controle de versão (como materialA2uiBasicCatalogV1) que fornecem a implementação do Material 3 da especificação padrão do catálogo básico da A2UI.
  • A2uiReadinessEvaluator e asReadinessEvaluator(): A2uiReadinessEvaluator é a interface para avaliar a prontidão do componente. A função de extensão asReadinessEvaluator() resolve estados de prontidão usando os componentes registrados em um catálogo.

Catálogo de versões e esquemas de componentes da A2UI

Uma definição de esquema de catálogo está associada a uma versão específica do protocolo. Quando o protocolo evolui, a definição do catálogo avança na versão. As implementações de componentes para essa próxima versão podem usar APIs de renderização atualizadas enquanto as versões mais antigas permanecem operacionais lado a lado.