Creare e personalizzare cataloghi di componenti

Nell'architettura A2UI, ogni superficie è gestita da un catalogo di componenti. Un catalogo è un contratto formale che definisce i componenti della UI, gli schemi delle proprietà e le funzioni client locali disponibili per un agente AI. Anziché generare codice arbitrario o inventare elementi sconosciuti, l'agente deve costruire interfacce utente utilizzando esclusivamente i componenti dichiarati nel catalogo.

In altre parole, il catalogo dichiara i componenti e l'agente li utilizza per creare l'interfaccia utente della tua app.

Quando crei un'app per Android con il renderer A2UI di Jetpack Compose, hai opzioni flessibili per la modalità di fornitura dei cataloghi:

  • Catalogo di base: il progetto A2UI definisce una specifica standardizzata e per uso generico chiamata Catalogo di base, che include elementi comuni come pulsanti, testo, campi di testo, schede ed elenchi. La libreria AndroidX androidx.compose.material3:material3-a2ui fornisce un'implementazione immediata di questa specifica di catalogo di base utilizzando componenti Material Design 3 nativi. La libreria androidx.a2ui.compose:compose-ui fornisce anche una definizione di schema generica per il catalogo di base, che ti aiuta a implementare il catalogo di base per il tuo sistema di progettazione.
  • Cataloghi personalizzati: per le applicazioni di produzione con sistemi di progettazione distinti, puoi creare un catalogo personalizzato da zero. In questo modo, l'agente è limitato ai componenti esatti, ai token di stile e al linguaggio visivo della tua app.
  • Un sottoinsieme o un ibrido: puoi combinare implementazioni di componenti specifici del catalogo di base fornito con i tuoi componenti personalizzati oppure sostituire le implementazioni di singoli componenti all'interno della suite del catalogo di base.

Utilizzare il catalogo di base fornito

Per iniziare rapidamente senza creare uno schema di componenti da zero, puoi utilizzare l'implementazione fornita della specifica A2UI Basic Catalog. La libreria androidx.compose.material3:material3-a2ui implementa il catalogo di base utilizzando i componenti Material Design 3.

Quando crei un'istanza di materialA2uiBasicCatalogV1, fornisci i renderer e i gestori per quanto segue:

  • Componenti multimediali, come immagini, video e lettori audio
  • Apertura URL
  • Formattazione dei messaggi localizzati

Le librerie A2UI non includono intenzionalmente dipendenze di rete e multimediali esterne, come Coil, Glide o Media3. Invece, fornisci i tuoi renderer. In questo modo si evitano conflitti di dipendenze fornendo librerie uniche. Ad esempio, se la tua app utilizza già Coil per il caricamento delle immagini o Media3 per la riproduzione, puoi collegare queste librerie esistenti direttamente al catalogo.

Il seguente esempio mostra come creare un'istanza del catalogo di base e collegare le librerie multimediali, l'apertura URL e il formattatore di messaggi che preferisci:

// 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,
)

Assemblare un catalogo di componenti personalizzati da zero

Se la tua app utilizza un sistema di progettazione personalizzato, puoi definire un catalogo contenente le tue implementazioni A2uiComponent personalizzate. Questo approccio ti offre il controllo completo degli schemi dei componenti esposti all'agente e dell'interfaccia utente Compose nativa emessa:

// 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()),
)

Per istruzioni sulla definizione degli schemi dei singoli componenti e della logica di rendering dell'interfaccia utente Compose, consulta Implementare componenti A2UI personalizzati.

Utilizzare un sottoinsieme di componenti del catalogo di base con componenti personalizzati

Non devi scegliere rigorosamente tra la creazione di tutto da zero o l'adozione dell'intero catalogo di base. Puoi assemblare un catalogo che combini componenti selezionati dell'implementazione del catalogo di base fornita con i tuoi componenti personalizzati:

// 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(...),
)

In alternativa, puoi personalizzare la suite Basic Catalog fornita eseguendo l'override di slot di componenti specifici:

// 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,
    
)

Gestisci il controllo delle versioni del catalogo e l'evoluzione dello schema

I cataloghi A2UI sono versionati in modo esplicito in base al contratto dello schema JSON. È necessario un incremento della versione quando vengono introdotte modifiche allo schema che provocano errori:

// 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),
)

Per consentire migrazioni senza interruzioni e senza tempi di inattività, il tuo client può registrare più versioni del catalogo supportate con il processore di messaggi contemporaneamente:

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

Durante la negoziazione del catalogo, l'agente rileva tutti gli ID catalogo supportati e sceglie la versione appropriata per ogni piattaforma.

Dettagli di implementazione

Le sezioni seguenti spiegano la convalida del catalogo interno e la negoziazione dello schema.

I percorsi utente di gestione del catalogo introducono le seguenti API chiave:

  • A2uiCatalog: Interfaccia e funzione di fabbrica di primo livello per definire i cataloghi dei componenti.
  • materialA2uiBasicCatalogVX: Funzioni di fabbrica con controllo delle versioni (ad esempio materialA2uiBasicCatalogV1) che forniscono l'implementazione di Material 3 della specifica standard del catalogo di base A2UI.
  • A2uiReadinessEvaluator e asReadinessEvaluator(): A2uiReadinessEvaluator è l'interfaccia per valutare la preparazione dei componenti. La funzione di estensione asReadinessEvaluator() risolve gli stati di preparazione utilizzando i componenti registrati in un catalogo.

Catalogo delle versioni di A2UI e schemi dei componenti

Una definizione dello schema del catalogo è associata a una versione specifica del protocollo. Quando il protocollo si evolve, la definizione del catalogo avanza di versione. Le implementazioni dei componenti per questa versione successiva possono utilizzare API di rendering aggiornate, mentre le versioni precedenti rimangono operative affiancate.