a2ui-project / a2ui-project/a2ui

Replace CRUD operations with JSON patch

Đang mở
#1,316 16 bình luận 0 reaction 0 người được giao Xem trên GitHub
component: specification P2 type: feature/enhancement
Ngôn ngữ chính
TypeScript
Star
16.4k
Fork
1.3k
Merge trung bình
2 ngày 13 giờ
Pull request đã merge (30 ngày)
134

Mô tả

# Background

Currently, A2UI has an underlying data structure which is basically a set of components and a data model. But our messages are for incrementally updating each of them, just imply defining them.

# Problems

- There is no well-defined format to serialize the current state of a surface
- Our CRUD operations are a little irregular. E.g. why `updateComponents` rather than `updateSurface`? Why not include initial components in `CreateSurface` etc (see https://github.com/google/A2UI/issues/1239). If we add more kinds of data, we need to invent new CRUD operations to represent them.
- In practice, most UIs are created and never updated, so it makes sense for the format to emphasize the surface state, rather than incremental updates. Right now, we have an incremental API makes it simple to represent changes to state (a single message) but complex to represent the current state (list of message which may overwrite each other and thus be redundant).
- There is no way to delete components currently, only replace them.

# Recent changes in direction

Since we defined A2UI v0.8 and v0.9, some things have changed about our direction which could motivate this design change.
- There is more emphasis on MCP, which is typically a "generate once" pattern, rather than a "generate and update" pattern. A2UI is kind of awkward for MCP, because they need to include a list of messages, and there is a question about which order they should be in etc (it doesn't matter).
- We are looking at separating transport and inference format - https://docs.google.com/document/d/1mH2DJ_jZZA2vZ9EQlWaU4v8_xCAcmqrox_LlElmJ3ws/edit?tab=t.0#heading=h.c0uts5ftkk58 . LLMs cannot write JSON patch well, and this motivated us to avoid it previously. But, if we are defining a separate LLM format anyway, let's go ahead and use it seeing as it entirely solves the issue of representing incremental data updates.

# Proposal

Let's focus on defining a JSON object which represents the state of a surface including data model and components. Then, when creating new surfaces, we just send the data. To update a surface, we send a JSON patch based on the previous data to apply.

# Pros and Cons

## Pros
- Simplify the transport format
- Simplify the mental model of a Surface snapshot and incremental updates
- Make it easy for us to expand the surface state representation (e.g. add something more than data model and components) without needing to rethink CRUD operations
- Simplify core library implementation. Currently, we have a message processor that understands how to apply our messages to a data model. Instead, we would just have some JSON and a JSON patch library that modifies it.
- Obvious way to represent surface snapshot state to LLMs. Currently, in the most simple a2ui implementations, the LLM would see the history of A2UI messages in its context. This is unnecessarily verbose. If there are many messages updating a surface, it should likely just see a snapshot of surface state. This new structure makes it obvious how to achieve this.
- Ability to represent arbitrarily small updates to state, e.g. update an individual property value

## Cons

- Creates more churn - this is relatively big change to the spec. Though, I believe we can make this update in the core library and renderers would be unaffected.
- Agents will really need full access to the accurate existing UI state in order to generate correct patches. They will probably have this anyway, though.
- JSON patch is hard for humans to read
- To incrementally update surfaces, developers will *need* an inference library to help. They won't be able to wing the JSON patch generation.

# Sketch

### Surface
```
{
"$defs": {
"Surface": {
"type": "object",
"description": "The complete state of an A2UI surface.",
"properties": {
"surfaceId": {
"type": "string",
"description": "Unique identifier for the surface."
},
"catalogId": {
"type": "string",
"description": "The URI of the catalog defining the components used."
},
"components": {
"type": "object",
"description": "A map of ComponentId to component definitions.",
"additionalProperties": {
"$ref": "catalog.json#/$defs/anyComponent"
}
},
"dataModel": {
"type": "object",
"description": "The initial data model for the surface.",
"default": {}
},
"theme": {
"$ref": "catalog.json#/$defs/theme"
},
"sendDataModel": {
"type": "boolean",
"default": false
}
},
"required": ["surfaceId", "catalogId", "components"]
}
}
}
```

### Server to client

```
{
"oneOf": [
{ "$ref": "#/$defs/CreateSurfaceMessage" },
{ "$ref": "#/$defs/UpdateSurfaceMessage" },
{ "$ref": "#/$defs/DeleteSurfaceMessage" }
],
"$defs": {
"CreateSurfaceMessage": {
"type": "object",
"properties": {
"version": { "const": "v0.10" },
"createSurface": {
"type": "object",
"properties": {
"surface": { "$ref": "common_types.json#/$defs/Surface" }
},
"required": ["surface"]
}
},
"required": ["createSurface", "version"]
},
"UpdateSurfaceMessage": {
"type": "object",
"properties": {
"version": { "const": "v0.10" },
"updateSurface": {
"type": "object",
"properties": {
"surfaceId": { "type": "string" },
"patch": {
"type": "array",
"items": { "$ref": "#/$defs/JsonPatchOperation" }
}
},
"required": ["surfaceId", "patch"]
}
},
"required": ["updateSurface", "version"]
},
"JsonPatchOperation": {
"type": "object",
"properties": {
"op": { "enum": ["add", "remove", "replace", "move", "copy", "test"] },
"path": { "type": "string", "description": "JSON Pointer to the surface property." },
"value": { "description": "The value to add or replace." },
"from": { "type": "string", "description": "Required for move/copy." }
},
"required": ["op", "path"]
}
}
}
```

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Hướng nghiên cứu

The issue proposes replacing the current CRUD message system with a JSON Patch-based API. Start by examining the existing message definitions and processor in the core library. Understand the current Surface state representation and how updates are applied. Review the linked issue #1239 for context on irregular CRUD operations. The goal is to design a new JSON schema for Surface state and patch operations, ensuring backward compatibility where possible. Focus on the core library changes first, as renderers should be unaffected.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
json, typescript
Lĩnh vực
api, backend-api-design
Loại issue
Tái cấu trúc
Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức độ hoạt động
Ít trao đổi
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
35/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.