עיבוד של ממשקי A2UI באפליקציה

כשמשתמשים במעבד התצוגה של Jetpack Compose מסוג סוכן לממשק משתמש (A2UI), סוכן AI שולח הודעות שמתארות מבנים של ממשק משתמש, מאפייני רכיבים ועדכוני נתונים. כדי להציג את הממשקים האלה באופן מקורי באפליקציה, צריך לארח ולהציג משטח A2UI בהיררכיית Jetpack Compose של האפליקציה.

רכיב ה-renderer של Compose A2UI מתאם בין ניתוח ההודעות, ניהול המצב של תמונת המצב הריאקטיבית ומעברים בין מצבי פני השטח של האנימציה. הכלי הבסיסי לעיבוד תמונות לא תלוי במערכת עיצוב ספציפית, אבל הוא מציע אינטגרציה מוכנה עם Material Design 3 באמצעות הקטלוג הבסיסי שסופק.

הפעלת שכבת הנתונים שמבוססת על Compose

רכיב ה-Renderer של A2UI תומך במצב שמתעדכן לפי תמונת מצב בשכבת הנתונים של האפליקציה, וכך מאפשר לממשק המשתמש של האפליקציה להגיב לעדכונים מצטברים מהסוכן. כדי להוסיף את התמיכה הזו, צריך להפעיל את האנליזר ואת המעבד באמצעות פונקציות היצירה A2uiMessageParser ו-A2uiMessageProcessor ב-ViewModel, כמו שמוצג בקטע הקוד הבא:

class AgenticUiViewModel : ViewModel() {
    // Create a parser that leverages the built-in JSON parser.
    private val parser = A2uiMessageParser()

    // Create an A2UI message processor with your catalog and optional
    // action interceptor (implementing A2uiActionInterceptor).
    private val processor = A2uiMessageProcessor(
        // You can also use the provided Material catalog instead of
        // a custom one.
        catalogs = listOf(CustomDesignSystemCatalog)
    )

    // Expose active surfaces to the UI as a StateFlow.
    val a2uiSurfaces: StateFlow<List<A2uiSurfaceModel>> =
        processor.activeSurfaces

    init {
        // Collect messages on a background thread tied to the ViewModel lifecycle.
        viewModelScope.launch(Dispatchers.Default) {
            processor.collectMessages()
        }

        // Add support for two-way communication with the agent.
        viewModelScope.launch(start = CoroutineStart.UNDISPATCHED) {
            processor.outboundEvents.collect(::handleOutboundA2uiEvent)
        }
    }

    // Called by your app's networking layer or business logic whenever
    // a new A2UI protocol message arrives from the AI agent.
    fun onNetworkMessage(json: String) {
        processor.processInput(parser, json)
    }
}

עיבוד משטחים באמצעות הקטלוג הבסיסי (Material 3)

כשמעבדים משטחים באמצעות ההטמעה של קטלוג בסיסי שסופקה (androidx.compose.material3:material3-a2ui), אפשר לעבד משטח Material 3 עם סגנון מלא, כולל תמיכה מובנית במחווני טעינה, בגבולות שגיאה ובמעברים מונפשים. כדי לעשות את זה, משתמשים בנקודת הכניסה הקומפוזבילית A2uiSurface:

@Composable
fun AgenticUiScreen(viewModel: AgenticUiViewModel) {
    // Observe active surfaces managed by the data layer.
    val surfaces by viewModel.a2uiSurfaces.collectAsStateWithLifecycle()

    Column(Modifier.fillMaxSize()) {
        surfaces.forEach { surface ->
            key(surface.id) {
                A2uiSurface(
                    surfaceModel = surface,
                    // Add your surface's custom modifiers here.
                )
            }
        }
    }
}

טיפול במצבי פני השטח ובמעברים מונפשים

A2uiSurface מתאם בין הפתרון של מצב רכיב השורש ומחיל מעברים של AnimatedContent בין מצבי הטעינה, השגיאה וההצלחה:

@Composable
fun CustomStyledSurface(surface: A2uiSurfaceModel) {
    A2uiSurface(
        surfaceModel = surface,
        modifier = Modifier.fillMaxSize(),
        loadingContent = {
            Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
                CircularProgressIndicator()
            }
        },
        errorContent = { exception ->
            Text(
                text = "Failed to load: ${exception.message}",
                color = MaterialTheme.colorScheme.error,
                // Add your custom error styling, such as modifiers, here.
            )
        },
        transitionSpec = {
            (fadeIn(animationSpec = tween(600)) togetherWith
                    fadeOut(animationSpec = tween(600)))
                .using(SizeTransform(clip = false))
        },
    )
}

הצגת משטחים ברמה נמוכה עם נתבים בהתאמה אישית

אפשר לצפות במצב של רכיב הבסיס של הממשק ישירות באמצעות observeA2uiComponentState ולהעביר את העיבוד אל A2uiComponent:

@Composable
fun RawSurfaceCoordinator(surface: A2uiSurfaceModel) {
    // Extract the catalog to provide its readiness evaluator to the
    // composition. This lets components wait for their dynamic data bindings
    // before they're rendered.
    val coreSurface = surface as? A2uiCoreSurfaceModel
        ?: throw IllegalArgumentException(
            "Surface must implement A2uiCoreSurfaceModel")
    val composeCatalog = coreSurface.catalog as? A2uiCatalog
        ?: throw IllegalArgumentException("Catalog must implement A2uiCatalog")
    val readinessEvaluator = remember(composeCatalog) {
        composeCatalog.asReadinessEvaluator() }

    CompositionLocalProvider(
        LocalA2uiReadinessEvaluator provides readinessEvaluator
    ) {
        val rootState = observeA2uiComponentState(surface = surface)
        when (rootState) {
            is A2uiComponentState.Loading -> {
                LoadingSpinner()
            }
            is A2uiComponentState.Error -> {
                ErrorBanner(rootState.exception)
            }
            is A2uiComponentState.Success -> {
                // Delegate component routing to the Compose A2UI router.
                A2uiComponent(
                    component = rootState.component,
                    // Add your custom modifiers here.
                )
            }
        }
    }
}

פרטי ההטמעה

הכלי לעיבוד סוכן לממשק משתמש מטפל בפתרון מצב הממשק ובגבולות של שגיאות הגנה.

גבולות שגיאה מגננתיים וטיפול בהזיות של סוכנים

ממשקי המשתמש של A2UI מבוססים על סוכני LLM גנרטיביים, ולכן יכול להיות שהמטען הייעודי (payload) שמגיע יהיה פגום או יפנה לסוגי רכיבים לא ידועים.

כדי לצמצם את הסיכוי לקריסות, מנגנון הרינדור יוצר את גבולות ההגנה הבאים:

  • שליחת שגיאות לתיקון עצמי של הסוכן: השגיאות נשלחות כהודעות לקוח יוצאות, וכך הסוכן יכול לתקן את עצמו בתורות הבאות של האינטראקציה. יש גם API שמאפשר להטמעות של רכיבים לשלוח שגיאות לסוכן במקרים שבהם ה-API מזהה שגיאות ספציפיות לרכיב בזמן רינדור.
  • רכיבים לא ידועים: כשנתקלים בסוג רכיב לא מוכר, הוא נחסם לפני שהוא מגיע לעץ ממשק המשתמש, מסומן כמצב שגיאה ומדווח בחזרה לסוכן לצורך תיקון עצמי.
  • כשלים באימות סכימה: המטענים הייעודיים (payloads) מאומתים מול סכימות של רכיבים (A2uiSchema). מאפיינים עם מבנה לא תקין לא אמורים להגיע לפריסות של Compose UI.
  • הגנה על מערך דליל: כשמתקבלים אינדקסים גדולים מאוד של רשימות, מודל הנתונים עובר מרשימה צפופה למפה דלילה אדפטיבית, וכך נמנעות שגיאות של חוסר זיכרון.