输入与事件
GenUI 应用中如何处理输入与事件。
本指南说明 GenUI package 中如何处理用户交互,从最初 widget 交互到 AI 智能体接收事件。
概览
#在 GenUI 架构中,UI 由 AI 驱动,但用户交互(如点击按钮或提交表单)必须传回 AI 智能体,以便智能体根据用户输入更新 UI 或执行操作。
事件流程如下:
-
交互 (Interaction):用户与 widget 交互;例如点击按钮。
-
捕获 (Capture):widget 实现派发
UiEvent。 -
处理 (Processing):框架添加上下文(如
surfaceId或数据模型值)并转发事件。 -
传输 (Transmission):Flutter widget 生成事件、添加上下文,经
ContentGenerator路由到 AI,再转发给 AI 智能体。
定义事件
#协议层
#
A2UI 协议定义用于上报事件的 action 消息。
action 包含:
-
name:操作名称(由 AI 在生成 widget 时定义)。 -
surfaceId:事件发生所在 UI surface 的 ID。 -
sourceComponentId:触发事件的 widget ID。 -
context:包含与事件相关数据的 JSON 对象。 timestamp:事件发生时间。
Dart 实现
#
在 package:genui 中,用户事件由 UiEvent extension type 及其实现 UserActionEvent 表示。
以下结构定义在 lib/src/model/ui_models.dart:
/// A data object that represents a user interaction event in the UI.
extension type UiEvent.fromMap(JsonMap _json) { ... }
/// A UI event that represents a user action.
extension type UserActionEvent.fromMap(JsonMap _json) implements UiEvent {
UserActionEvent({
String? surfaceId,
required String name,
required String sourceComponentId,
JsonMap? context,
// ...
}) : ...
}
/// 表示 UI 中用户交互事件的数据对象。
extension type UiEvent.fromMap(JsonMap _json) { ... }
/// 表示用户操作的 UI 事件。
extension type UserActionEvent.fromMap(JsonMap _json) implements UiEvent {
UserActionEvent({
String? surfaceId,
required String name,
required String sourceComponentId,
JsonMap? context,
// ...
}) : ...
}
在 widget 中捕获事件
#
GenUI 中的 widget 在 Catalog 中定义,其中包含 widget 可向 AI 发送哪些事件的信息。
AI 随后可发送如何回传这些事件的说明。实现自定义 widget(或使用标准 widget)时,在 CatalogItemContext 中使用 dispatchEvent 派发事件。
示例:Button 实现
#
以下示例展示 Button widget 通常如何捕获点击并派发事件:从属性获取 AI 提供的 action 定义,解析上下文中的数据绑定,并发送事件。
// Inside a CatalogItem widgetBuilder:
widgetBuilder: (itemContext) {
// 1. Extract action data from the component properties.
final buttonData = _ButtonData.fromMap(itemContext.data as JsonMap);
final JsonMap actionData = buttonData.action;
final actionName = actionData['name'] as String;
// 2. Extract context definition (which data to send back).
final List<Object?> contextDefinition =
(actionData['context'] as List<Object?>?) ?? <Object?>[];
return ElevatedButton(
onPressed: () {
// 3. Resolve the context values from the data model.
final JsonMap resolvedContext = resolveContext(
itemContext.dataContext,
contextDefinition,
);
// 4. Dispatch the event.
itemContext.dispatchEvent(
UserActionEvent(
name: actionName,
sourceComponentId: itemContext.id,
context: resolvedContext,
),
);
},
child: /* ... */
);
},
事件处理流水线
#调用 dispatchEvent 后,事件流经 GenUI 核心层。
Surface
#
Surface widget(位于 lib/src/core/surface.dart)包装已渲染 widget,提供 dispatchEvent 回调实现。
调用 _dispatchEvent 时:
-
自动将
surfaceId注入事件,确保 AI 知道交互来自哪个 surface。 -
将处理委托给
SurfaceHost(由SurfaceController实现)。
// Surface implementation details
void _dispatchEvent(UiEvent event) {
// ...
final Map<String, Object?> eventMap = {
...event.toMap(),
surfaceIdKey: widget.surfaceId, // Inject surfaceId
};
final UiEvent newEvent = UserActionEvent.fromMap(eventMap);
widget.host.handleUiEvent(newEvent);
}
SurfaceController
#
SurfaceController(位于 lib/src/core/surface_controller.dart)是管理 UI 状态的中央枢纽。
调用 handleUiEvent 时,它会:
验证事件类型。
-
用协议要求的
actionJSON 信封包装事件。 -
在其
onSubmit流上发出UserUiInteractionMessage。
// SurfaceController implementation details
@override
void handleUiEvent(UiEvent event) {
if (event is! UserActionEvent) return;
// Wrap in protocol 'action' envelope
final String eventJsonString = jsonEncode({'action': event.toMap()});
// Emit for listeners (like Conversation)
_onSubmit.add(UserUiInteractionMessage.text(eventJsonString));
}
传输到 AI
#
最后一步将事件发送给 AI 智能体,通常由 Conversation(位于 lib/src/facade/conversation.dart)处理。
Conversation 监听消息处理器的 onSubmit 流。
// Conversation constructor
_userEventSubscription = surfaceController.onSubmit.listen(sendRequest);
收到事件时,sendRequest 方法会:
-
将
UserUiInteractionMessage包装回开发者客户端代码。 -
自定义集成或预定义传输适配器将消息转发到 LLM 智能体网络传输。
AI 智能体接收该 JSON 消息,处理用户操作,并可能流式返回新的 surfaceUpdate 或 dataModelUpdate 消息以修改 UI,或其他操作,完成完整交互循环。
除非另有说明,本文档之所提及适用于 Flutter 3.44.0 版本。本页面最后更新时间:2026-06-12。查看文档源码 或者 为本页面内容提出建议。