关于 lynx-a2ui
帮助 Agent 将自然语言需求转换为 A2UI v0.9 消息数据的技能,供支持该协议的渲染器生成界面。它要求获取最新组件目录并按其模式输出 JSON,不生成可执行代码。
主要功能
- 01将需求转换为 A2UI 消息
- 02生成界面组件图与数据模型
- 03获取并遵循最新组件目录
- 04支持界面增量更新与操作补丁
- 05限制输出为受信任组件数据
适用场景
- 01为自然语言界面需求生成 A2UI 数据
- 02依据最新目录构建表单或视图
- 03为现有界面交互生成数据补丁
MCP 相关
A2UI 消息可通过 MCP 或其他传输方式传递;此技能负责生成协议数据,不实现 MCP 传输。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ lynx-community/ skills --skill lynx-a2ui安装后在 Claude Code 中输入/lynx-a2ui确认已加载。
附带文件package.json
详细介绍
A2UI 生成器
当 Agent 必须将自然语言请求转换为用于渲染的 A2UI 协议数据时,使用此技能。 输出仅包含数据:A2UI v0.9 消息的 JSON 数组。
生成工作流
- 从目录来源部分中的 URL 获取最新目录。
- 如果获取的目录提供了相关信息,请阅读
catalogId、组件架构、函数架构、必填字段、枚举值和示例。 - 根据协议规则、目录架构、硬性规则以及此技能中嵌入的示例模式构建 UI。
- 将用户意图转换为数据模型和平铺的组件图,并确保其符合最新获取的目录。
- 仅输出最终的 A2UI 消息 JSON 数组。
此技能适用于第三方 Agent 平台,可独立使用。请勿依赖仓库本地文件。
协议参考
A2UI 是一种基于 JSON 的流式 UI 协议。Agent 通过输出声明式 JSON 消息来描述界面。渲染器只会实例化当前目录中的受信任组件。协议不支持任意代码:切勿输出 JavaScript、HTML、CSS、事件处理程序、脚本或可执行代码片段。
设计原则:
- 提示词优先:严格遵循上下文中的架构和示例。
- 兼具数据的安全性与代码的表现力:仅输出受信任的组件数据。
- 结构与数据分离:组件消息定义平铺的 UI 图;数据模型消息填充或更新动态绑定使用的值。
- 渐进式渲染:每条有效消息到达时都可以渲染。优先先提供实用的最小 UI,再添加数据或完善内容。
- 与传输方式无关:A2UI 消息可以通过 SSE、REST、WebSocket、A2A、AG UI、MCP 或其他宿主传输方式传递。
信封语义:
createSurface创建一个画布。创建后,其surfaceId和catalogId将固定不变。若要更改目录或主题,请删除并重新创建画布。updateDataModel设置画布数据模型中的值。其形状为{ "surfaceId": string, "path"?: string, "value"?: any }。path默认为/,value可以是任意 JSON 值。updateComponents为画布添加或替换组件定义。它可以引用数据路径,但这些路径应已由同一响应中更早的updateDataModel消息填充。deleteSurface移除一个画布。
输出约定
仅返回经过美化格式化的 JSON 数组。不要返回 Markdown、散文、XML、HTML、JavaScript、CSS、代码围栏、注释或尾随逗号。
数组中的每一项都必须是顶层对象,包含 "version": "v0.9",并且只能包含以下消息键之一:
"createSurface":创建新的渲染画布。"updateDataModel":设置绑定使用的 JSON 值。"updateComponents":添加或替换组件定义。"deleteSurface":移除现有画布。
对于全新的 UI 响应,请按以下顺序输出消息:
createSurface- 为通过
{ "path": ... }读取的任何初始值输出updateDataModel - 输出包含 id 为
"root"的组件的updateComponents - 可选的其他
updateDataModel或updateComponents消息
第一条全新的 updateComponents 消息必须恰好包含一个 root 组件。后续的 updateComponents 消息可按需替换或添加更多组件。每个消息对象和组件对象都应各占单独一行,以便 JSON 易于解析和验证。
完成前,请检查括号是否配对:每个组件对象都只闭合一次,每个 components 数组都只闭合一次,每个消息对象都只闭合一次,外层数组也恰好闭合一次。
目录源
除非调用方提供其他 ID,否则使用 surface ID "main"。生成 A2UI JSON 之前,请获取最新的 Lynx GenUI A2UI 目录:
"https://unpkg.com/@lynx-js/genui/a2ui/dist/catalog.json"
将获取的目录视为生成 UI 的权威动态类型定义。不要依赖对此技能中旧版组件列表的记忆。该目录的顶层结构如下:
{
"catalogId": "https://unpkg.com/@lynx-js/genui/a2ui/dist/catalog.json",
"components": {},
"functions": {}
}
在 createSurface.catalogId 中使用获取的 catalogId 值。只能使用 components 下列出的组件、functions 下列出的函数,以及该最新目录允许的 props、必填字段、枚举值、动态值结构和操作 schema。如果无法获取目录,请先索要目录内容或可访问的目录 URL,再生成复杂 UI。
如果用户提供了不同的目录 URL 或目录 JSON,请改用该目录,并确保 createSurface.catalogId 与当前使用的目录一致。
示例策略
示例有助于提高准确性,但必须结合目录使用。请按以下方式使用示例:
- 如果获取的目录中包含示例,请优先使用这些示例。
- 将下方内嵌示例用作可复用模式,适用于带操作的表单、数据绑定的重复视图、类似图表的数据视图,以及操作响应补丁。
- 借用内嵌示例前,请根据最新目录进行验证。对于引用了缺失组件或 props、必填字段或枚举值已更改,或使用了当前目录中不存在的函数的示例,请予以舍弃或调整。
- 除非示例 JSON 完全符合用户请求和最新目录,否则不要将其粘贴到最终回答中。
- 如果没有适用的示例,请直接根据获取的 schema 生成。
硬性规则
- 输出必须是 A2UI 消息的 JSON 数组。不得包含散文、Markdown、XML、代码围栏、注释或尾随逗号。
- 每个元素都必须包含
"version": "v0.9"。 - 输出使用 2 个空格缩进的美化 JSON。不得输出压缩成单行的 JSON。
- 对于全新的非操作响应,第一条消息必须是
createSurface。使用获取到的catalogId,并使用界面 ID"main",除非用户另有指定。 - 对于
{ "path": ... }绑定,必须在第一条读取这些路径的updateComponents消息之前发送updateDataModel。 - 第一条全新的
updateComponents消息必须恰好包含一个 ID 为"root"的组件。 - 使用基于属性的组件判别符:
"component": "SomeComponent",不得使用{ "SomeComponent": { ... } }之类的包装对象。 - 子组件只能通过 ID 引用。不得内联子组件。
- 子组件引用必须指向同一响应中包含的组件,或指向补丁应用时已存在于同一界面上的组件。
- ID 必须采用 kebab-case,且在每个界面内唯一,例如
"root"、"title-text"和"submit-button"。 - 不得使用最新获取的目录之外的组件、属性、函数、枚举值或操作形状。
- 如果组件具有布局
weight属性,应将其视为子布局比例,而不是 CSS 字体粗细。除非最新目录明确规定了该含义,否则不得使用400、500、600或700等排版值。 - 如果用户要求的 UI 不可能实现、不安全或不受支持,应使用目录中支持的组件返回简洁的说明性 A2UI 界面,而不是散文。
- 如果最新用户消息以
A2UI_USER_ACTION:开头,必须为现有界面返回非空补丁。除非操作明确要求替换整个 UI,否则不得创建新界面。 - 对于操作响应,优先使用最小有效补丁:针对已更改的数据发送一条
updateDataModel,仅在需要更改可见结构时发送updateComponents。 - 对于交互后应发生变化的 UI,初始响应应保持操作前的状态。确认、成功、错误或结果详情应放在操作响应中。
组件规则
- 组件是
updateComponents.components中的扁平对象;子组件只能通过 ID 字符串引用,绝不能内联嵌套。 - 每个组件都必须有唯一的 kebab-case
"id",并且其目录判别符的值必须是已获取目录components对象中的键之一。 - 全新 UI 的第一个可见组件树必须包含
"id": "root"。 - 如果组件架构包含
children,应按该架构允许的形状提供内容。如果它包含单个子组件引用,则必须恰好提供一个组件 ID。如果需要多个可视子组件,应使用架构支持多个子组件的目录组件。 - 如果组件架构要求操作,应按已获取的架构允许的形状生成操作,并提供允许的事件载荷,或调用
functions中存在的函数。 - 不得使用当前目录中未定义的组件、属性、函数、枚举值或布局字段。
- 对于媒体类组件,应遵循已获取架构中的 URL/来源字段要求。如果宿主会解析图片查询,应使用简短的英文搜索词,而不是编造 CDN URL。
- 如果用户要求不受支持或不安全的 UI,仍须返回 A2UI JSON:使用最新目录中可用的组件呈现简洁的说明性界面,而不是返回散文。
数据绑定
固定文本和简单静态 UI 使用字面值。需要共享、编辑、重复显示或在操作后更新的值,则使用数据模型绑定。
{ "someProp": "literal value" }
{ "someProp": { "path": "/data/path" } }
如果组件读取 { "path": "/..." },请先发送 updateDataModel 消息来创建该值。
对于重复子项,使用获取到的组件架构中的模板结构。
当架构支持 { "path": "...", "componentId": "..." } 时,容器指向绝对数组路径,而模板组件使用相对项路径。
对应的数据必须是对象数组:
[
{ "label": "Alpha" },
{ "label": "Beta" }
]
在模板组件树内部,使用 { "path": "label" } 进行绑定。不要使用诸如 "/items/*/label" 这样的通配符路径,也不要使用 { "path": "." }。
选择获取到的架构和描述最符合所需布局及滚动行为的重复内容组件。
操作响应
如果最新的用户输入以 A2UI_USER_ACTION: 开头,请更新现有界面,而不是创建新界面。返回一个非空 JSON 数组,并使用最小有效补丁:
- 仅数据发生变化时,使用
updateDataModel。 - 仅在可见结构发生变化时,添加
updateComponents。 - 除非该操作明确替换 UI,否则保留相同的
surfaceId。
在用户执行操作之前,不要在初始响应中显示成功、确认或操作后的结果状态。将这些状态放在操作响应中。 对于交互后会发生变化的 UI,初始响应应保持操作前的状态,并通过操作响应补丁显示确认、成功、错误或结果详情。
嵌入式示例模式
以下示例是在上下文中说明模式的示例。复用前,请先获取最新目录,并确认所有组件、属性、枚举值和操作结构仍然有效。如果当前目录已发生变化,请调整组件名称和属性。
带操作的表单
用户:Generate a login card with email, password, and a submit button.
[
{
"version": "v0.9",
"createSurface": {
"surfaceId": "main",
"catalogId": "https://unpkg.com/@lynx-js/genui/a2ui/dist/catalog.json"
}
},
{
"version": "v0.9",
"updateDataModel": {
"surfaceId": "main",
"value": {
"form": {
"email": "",
"password": ""
}
}
}
},
{
"version": "v0.9",
"updateComponents": {
"surfaceId": "main",
"components": [
{
"id": "root",
"component": "Card",
"child": "form-column"
},
{
"id": "form-column",
"component": "Column",
"children": [
"title",
"email",
"password",
"submit"
]
},
{
"id": "title",
"component": "Text",
"text": "Sign in",
"variant": "h2"
},
{
"id": "email",
"component": "TextField",
"label": "Email",
"value": {
"path": "/form/email"
}
},
{
"id": "password",
"component": "TextField",
"label": "Password",
"variant": "obscured",
"value": {
"path": "/form/password"
}
},
{
"id": "submit",
"component": "Button",
"variant": "primary",
"child": "submit-label",
"action": {
"event": {
"name": "submit_login",
"context": {
"email": {
"path": "/form/email"
},
"password": {
"path": "/form/password"
}
}
}
}
},
{
"id": "submit-label",
"component": "Text",
"text": "Sign in"
}
]
}
}
]
数据绑定的重复视图
用户:Show three trip ideas as a compact vertical group.
[
{
"version": "v0.9",
"createSurface": {
"surfaceId": "main",
"catalogId": "https://unpkg.com/@lynx-js/genui/a2ui/dist/catalog.json"
}
},
{
"version": "v0.9",
"updateDataModel": {
"surfaceId": "main",
"path": "/items",
"value": [
{
"name": "Canal walk",
"detail": "Morning coffee and quiet bridges"
},
{
"name": "Museum loop",
"detail": "Design exhibits plus lunch nearby"
},
{
"name": "Sunset hill",
"detail": "Short climb with skyline views"
}
]
}
},
{
"version": "v0.9",
"updateComponents": {
"surfaceId": "main",
"components": [
{
"id": "root",
"component": "Column",
"children": [
"title",
"trip-items"
]
},
{
"id": "title",
"component": "Text",
"text": "Trip ideas",
"variant": "h2"
},
{
"id": "trip-items",
"component": "Column",
"children": {
"path": "/items",
"componentId": "trip-row"
}
},
{
"id": "trip-row",
"component": "Row",
"children": [
"trip-icon",
"trip-copy"
],
"align": "center"
},
{
"id": "trip-icon",
"component": "Icon",
"name": "location_on"
},
{
"id": "trip-copy",
"component": "Column",
"children": [
"trip-name",
"trip-detail"
]
},
{
"id": "trip-name",
"component": "Text",
"text": {
"path": "name"
},
"variant": "h3"
},
{
"id": "trip-detail",
"component": "Text",
"text": {
"path": "detail"
},
"variant": "body"
}
]
}
}
]
图表式数据视图
用户:Show weekly active users as a line chart.
[
{
"version": "v0.9",
"createSurface": {
"surfaceId": "main",
"catalogId": "https://unpkg.com/@lynx-js/genui/a2ui/dist/catalog.json"
}
},
{
"version": "v0.9",
"updateDataModel": {
"surfaceId": "main",
"value": {
"chart": {
"labels": [
"Mon",
"Tue",
"Wed",
"Thu",
"Fri"
],
"series": [
{
"name": "Users",
"values": [
120,
148,
132,
171,
190
]
}
]
}
}
}
},
{
"version": "v0.9",
"updateComponents": {
"surfaceId": "main",
"components": [
{
"id": "root",
"component": "Card",
"child": "chart-column"
},
{
"id": "chart-column",
"component": "Column",
"children": [
"title",
"chart"
]
},
{
"id": "title",
"component": "Text",
"text": "Weekly active users",
"variant": "h2"
},
{
"id": "chart",
"component": "LineChart",
"labels": {
"path": "/chart/labels"
},
"series": {
"path": "/chart/series"
},
"xLabel": "Day",
"yLabel": "Users",
"showGrid": true,
"showLegend": true
}
]
}
}
]
操作响应补丁
用户:
A2UI_USER_ACTION: {"surfaceId":"main","action":{"name":"submit_login","context":{"email":"[email protected]"}}}
[
{
"version": "v0.9",
"updateDataModel": {
"surfaceId": "main",
"path": "/status",
"value": {
"kind": "success",
"message": "Signed in as [email protected]"
}
}
},
{
"version": "v0.9",
"updateComponents": {
"surfaceId": "main",
"components": [
{
"id": "root",
"component": "Card",
"child": "status-column"
},
{
"id": "status-column",
"component": "Column",
"children": [
"status-title",
"status-message"
]
},
{
"id": "status-title",
"component": "Text",
"text": "Success",
"variant": "h2"
},
{
"id": "status-message",
"component": "Text",
"text": {
"path": "/status/message"
}
}
]
}
}
]
验证清单
最终输出前,请确认:
- 第一个字符是
[,最后一个字符是]。 - 每条消息都包含
"version": "v0.9"。 - 新响应以
createSurface开头。 - 第一条新建的
updateComponents消息包含root。 - 每个子项 ID 引用都在同一响应中存在。
- 绑定路径都有对应的、此前已创建的数据模型值。
- 重复模板使用对象项和相对项字段。
- 所有组件、属性、枚举值、函数和操作结构均来自最新获取的目录。
- JSON 可解析,且不含注释或尾随逗号。