Crea y personaliza catálogos de componentes

En la arquitectura de A2UI, cada superficie se basa en un catálogo de componentes. Un catálogo es un contrato formal que define los componentes de la IU, los esquemas de propiedades y las funciones del cliente local disponibles para un agente de IA. En lugar de generar código arbitrario o inventar elementos desconocidos, el agente debe construir interfaces de usuario usando exclusivamente los componentes declarados en el catálogo.

En otras palabras, el catálogo declara los componentes y el agente los usa para compilar la IU de tu app.

Cuando compilas una app para Android con el renderizador de A2UI de Jetpack Compose, tienes opciones flexibles para proporcionar catálogos:

  • El catálogo básico: El proyecto de A2UI define una especificación estandarizada y de uso general llamada catálogo básico, que incluye elementos comunes como botones, texto, campos de texto, tarjetas y listas. La biblioteca de AndroidX androidx.compose.material3:material3-a2ui proporciona una implementación lista para usar de esta especificación de catálogo básico con componentes nativos de Material Design 3. La biblioteca androidx.a2ui.compose:compose-ui también proporciona una definición de esquema genérico para el catálogo básico, lo que te ayuda a implementar el catálogo básico para tu propio sistema de diseño.
  • Catálogos personalizados: Para las aplicaciones de producción con sus propios sistemas de diseño distintos, puedes crear un catálogo personalizado desde cero. Esto restringe el agente a los componentes, los tokens de diseño y el lenguaje visual exactos de tu app.
  • Un subconjunto o híbrido: Puedes combinar implementaciones de componentes específicos del catálogo básico proporcionado con tus propios componentes personalizados o anular implementaciones de componentes individuales dentro del conjunto del catálogo básico.

Usa el catálogo básico proporcionado

Para comenzar rápidamente sin crear un esquema de componente desde cero, puedes usar la implementación proporcionada de la especificación del catálogo básico de A2UI. La biblioteca de androidx.compose.material3:material3-a2ui implementa el catálogo básico con componentes de Material Design 3.

Cuando crees una instancia de materialA2uiBasicCatalogV1, proporciona renderizadores y controladores para lo siguiente:

  • Componentes multimedia, como reproductores de imágenes, video y audio
  • Abre URLs
  • Formato de mensajes localizados

Las bibliotecas de A2UI no incluyen intencionalmente dependencias externas de redes y medios, como Coil, Glide o Media3. En cambio, proporcionas tus propios renderizadores. Esto evita conflictos de dependencias, ya que proporciona bibliotecas únicas. Por ejemplo, si tu app ya usa Coil para cargar imágenes o Media3 para la reproducción, puedes conectar esas bibliotecas existentes directamente al catálogo.

En el siguiente ejemplo, se muestra cómo crear una instancia del catálogo básico y conectar tus bibliotecas de medios, el abridor de URLs y el formateador de mensajes 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,
)

Cómo ensamblar un catálogo de componentes personalizados desde cero

Si tu app usa un sistema de diseño personalizado, puedes definir tu propio catálogo que contenga tus propias implementaciones de A2uiComponent personalizadas. Este enfoque te brinda control total sobre los esquemas de componentes expuestos al agente y la IU de 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()),
)

Si quieres obtener instrucciones para definir esquemas de componentes individuales y su lógica de renderización de la IU de Compose, consulta Implementa componentes personalizados de A2UI.

Usa un subconjunto de componentes de Basic Catalog con componentes personalizados

No tienes que elegir estrictamente entre crear todo desde cero o adoptar todo el catálogo básico. Puedes ensamblar un catálogo que combine componentes seleccionados de la implementación del catálogo básico proporcionado con tus propios 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, puedes personalizar el paquete de catálogo básico proporcionado reemplazando ranuras 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,
    
)

Administra el control de versiones del catálogo y la evolución del esquema

Los catálogos de A2UI tienen versiones explícitas basadas en su contrato de esquema JSON. Se requiere un aumento de versión cuando se introducen cambios rotundos en el 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 habilitar migraciones fluidas sin tiempo de inactividad, tu cliente puede registrar varias versiones del catálogo admitidas con el procesador de mensajes de forma simultánea:

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

Durante la negociación del catálogo, el agente descubre todos los IDs de catálogo admitidos y segmenta la versión adecuada para cada plataforma.

Detalles de la implementación

En las siguientes secciones, se explican la validación del catálogo interno y la negociación del esquema.

Los recorridos del usuario de administración del catálogo presentan las siguientes APIs clave:

  • A2uiCatalog: Es la interfaz y la función de fábrica de nivel superior para definir catálogos de componentes.
  • materialA2uiBasicCatalogVX: Son funciones de fábrica versionadas (como materialA2uiBasicCatalogV1) que proporcionan la implementación de Material 3 de la especificación estándar del catálogo básico de A2UI.
  • A2uiReadinessEvaluator y asReadinessEvaluator(): A2uiReadinessEvaluator es la interfaz para evaluar la preparación de los componentes. La función de extensión asReadinessEvaluator() resuelve los estados de preparación con los componentes registrados en un catálogo.

Catálogo de versiones y esquemas de componentes de A2UI

Una definición de esquema de catálogo se asocia con una versión de protocolo específica. Cuando el protocolo evoluciona, la definición del catálogo avanza su versión. Las implementaciones de componentes para esta próxima versión pueden usar APIs de renderizador actualizadas, mientras que las versiones anteriores siguen funcionando en paralelo.