Skip to content

Commit 79883ee

Browse files
committed
Merge S1: stub auto-load via PartialLoader
2 parents 720cbee + 6c9cd15 commit 79883ee

36 files changed

Lines changed: 1321 additions & 505 deletions

docs/content/docs/integrations/a2a/generative-ui/declarative-a2ui.mdx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ Build an A2A agent, configure it to use A2UI, use the A2UI composer to generate
5858
...
5959
---BEGIN SINGLE_COLUMN_LIST_EXAMPLE---
6060
[
61-
{{ "beginRendering": {{ "surfaceId": "default", "root": "root-column", "styles": {{ "primaryColor": "#FF0000", "font": "Roboto" }} }} }},
62-
{{ "surfaceUpdate": {{
61+
{{ "createSurface": {{ "surfaceId": "default", "catalogId": "https://a2ui.org/specification/v0_9/basic_catalog.json", "styles": {{ "primaryColor": "#FF0000", "font": "Roboto" }} }} }},
62+
{{ "updateComponents": {{
6363
"surfaceId": "default",
6464
"components": [
65-
{{ "id": "root-column", "component": {{ "Column": {{ "children": {{ "explicitList": ["title-heading", "item-list"] }} }} }} }},
65+
{{ "id": "root", "component": {{ "Column": {{ "children": {{ "explicitList": ["title-heading", "item-list"] }} }} }} }},
6666
{{ "id": "title-heading", "component": {{ "Text": {{ "usageHint": "h1", "text": {{ "literalString": "Top Restaurants" }} }} }} }},
6767
{{ "id": "item-list", "component": {{ "List": {{ "direction": "vertical", "children": {{ "template": {{ "componentId": "item-card-template", "dataBinding": "/items" }} }} }} }} }},
6868
{{ "id": "item-card-template", "component": {{ "Card": {{ "child": "card-layout" }} }} }},
@@ -77,7 +77,7 @@ Build an A2A agent, configure it to use A2UI, use the A2UI composer to generate
7777
{{ "id": "book-now-text", "component": {{ "Text": {{ "text": {{ "literalString": "Book Now" }} }} }} }}
7878
]
7979
}} }},
80-
{{ "dataModelUpdate": {{
80+
{{ "updateDataModel": {{
8181
"surfaceId": "default",
8282
"path": "/",
8383
"contents": [
@@ -109,9 +109,9 @@ Build an A2A agent, configure it to use A2UI, use the A2UI composer to generate
109109
The widgets are injected into the agent's prompt, in this case using the `RESTAURANT_UI_EXAMPLES` variable.
110110
Widgets are defined for the agent using examples of the json arrays they should output, wrapped in a comment block.
111111
- A comment indicating the start of the example
112-
- beginRendering: The start of the widget's rendering
113-
- surfaceUpdate: An example of the json structure for the widget
114-
- dataModelUpdate: an example of the data that will be used to populate the widget
112+
- createSurface: Initializes the surface with its catalog (and optional styles/theme). Must come first.
113+
- updateComponents: The component tree for the widget. Exactly one component must have `id: "root"`.
114+
- updateDataModel: The data used to populate the widget
115115
- A comment indicating the end of the example
116116
117117
In the example repo, all of the widgets are defined in a single variable int the prompt_builder.py file, but you can structure them however you like,

docs/content/docs/integrations/deepagents/generative-ui/a2ui/advanced.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,8 @@ useA2UIActionHandler((action, declaredOps) => {
174174
if (action.name === "book_flight") {
175175
// Return custom operations
176176
return [
177-
{ surfaceUpdate: { surfaceId: action.surfaceId, components: mySchema } },
178-
{ beginRendering: { surfaceId: action.surfaceId, root: "root" } },
177+
{ createSurface: { surfaceId: action.surfaceId, catalogId: "https://a2ui.org/specification/v0_9/basic_catalog.json" } },
178+
{ updateComponents: { surfaceId: action.surfaceId, components: mySchema } },
179179
];
180180
}
181181
return null; // skip — let other handlers or fallback try

docs/content/docs/integrations/deepagents/generative-ui/a2ui/dynamic-schema.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ The secondary LLM's `render_a2ui` tool call streams through LangGraph as `TOOL_C
116116

117117
1. Extracts the `components` array as it streams — waits for the full schema before rendering
118118
2. Extracts `surfaceId` and `root` from the partial JSON
119-
3. Once the schema is complete, emits `surfaceUpdate` + `beginRendering`
120-
4. Extracts complete `items` objects progressively and emits `dataModelUpdate` for each
119+
3. Once the schema is complete, emits `createSurface` + `updateComponents`
120+
4. Extracts complete `items` objects progressively and emits `updateDataModel` for each
121121
5. Cards appear one by one as data streams in
122122

123123
## Built-in progress indicator

docs/content/docs/integrations/deepagents/generative-ui/a2ui/fixed-schema.mdx

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ In the fixed-schema approach, you design the UI schema once (in a JSON file or u
1212

1313
1. Schema is loaded from a JSON file at startup
1414
2. Agent tool receives data from the LLM (e.g., flight search results)
15-
3. Tool returns `a2ui.render()` with surfaceUpdate + dataModelUpdate + beginRendering
15+
3. Tool returns `a2ui.render()` with createSurface + updateComponents + updateDataModel
1616
4. The A2UI middleware intercepts the tool result and renders the surface
1717

1818
## Implementation
@@ -65,23 +65,22 @@ def search_flights(flights: list[Flight]) -> str:
6565
"""Search for flights and display results as rich cards."""
6666
return a2ui.render(
6767
operations=[
68-
a2ui.surface_update(SURFACE_ID, FLIGHT_SCHEMA),
69-
a2ui.data_model_update(SURFACE_ID, {"flights": flights}),
70-
a2ui.begin_rendering(SURFACE_ID, "root"),
68+
a2ui.create_surface(SURFACE_ID),
69+
a2ui.update_components(SURFACE_ID, FLIGHT_SCHEMA),
70+
a2ui.update_data_model(SURFACE_ID, {"flights": flights}),
7171
],
7272
action_handlers={
7373
# Exact match: fires when a button with action.name="book_flight" is clicked
7474
"book_flight": [
75-
a2ui.surface_update(SURFACE_ID, BOOKED_SCHEMA),
76-
a2ui.data_model_update(SURFACE_ID, {
75+
a2ui.update_components(SURFACE_ID, BOOKED_SCHEMA),
76+
a2ui.update_data_model(SURFACE_ID, {
7777
"title": "Booking Confirmed",
7878
"detail": "Your flight has been booked.",
7979
}),
80-
a2ui.begin_rendering(SURFACE_ID, "root"),
8180
],
8281
# Catch-all: fires for any button action without a specific match
8382
"*": [
84-
a2ui.data_model_update(SURFACE_ID, {
83+
a2ui.update_data_model(SURFACE_ID, {
8584
"status": "Action received",
8685
}),
8786
],

docs/content/docs/integrations/deepagents/generative-ui/a2ui/index.mdx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,21 +60,21 @@ All three approaches use the same A2UI protocol and renderer. The difference is
6060

6161
## How it works
6262

63-
Every A2UI surface is built from three operations:
63+
Every A2UI v0.9 surface is built from three operations:
6464

65-
1. **`surfaceUpdate`**defines the component tree (the schema)
66-
2. **`dataModelUpdate`**provides the data that populates the components
67-
3. **`beginRendering`**tells the client to start rendering
65+
1. **`createSurface`**initializes the surface with its catalog (must come first)
66+
2. **`updateComponents`**defines the component tree (the schema)
67+
3. **`updateDataModel`**provides the data that populates the components
6868

6969
The CopilotKit Python SDK provides helpers to build these operations:
7070

7171
```python
7272
from copilotkit import a2ui
7373

74-
a2ui.surface_update(surface_id, components)
75-
a2ui.data_model_update(surface_id, {"items": data})
76-
a2ui.begin_rendering(surface_id, root_id)
77-
a2ui.render(operations) # wraps and serializes
74+
a2ui.create_surface(surface_id)
75+
a2ui.update_components(surface_id, components)
76+
a2ui.update_data_model(surface_id, {"items": data})
77+
a2ui.render(operations) # wraps in a2ui_operations and serializes
7878
```
7979

8080
Continue to one of the approach guides above to see the full implementation.

docs/content/docs/integrations/langgraph/generative-ui/a2ui/advanced.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,8 @@ useA2UIActionHandler((action, declaredOps) => {
174174
if (action.name === "book_flight") {
175175
// Return custom operations
176176
return [
177-
{ surfaceUpdate: { surfaceId: action.surfaceId, components: mySchema } },
178-
{ beginRendering: { surfaceId: action.surfaceId, root: "root" } },
177+
{ createSurface: { surfaceId: action.surfaceId, catalogId: "https://a2ui.org/specification/v0_9/basic_catalog.json" } },
178+
{ updateComponents: { surfaceId: action.surfaceId, components: mySchema } },
179179
];
180180
}
181181
return null; // skip — let other handlers or fallback try

docs/content/docs/integrations/langgraph/generative-ui/a2ui/dynamic-schema.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ The secondary LLM's `render_a2ui` tool call streams through LangGraph as `TOOL_C
115115

116116
1. Extracts the `components` array as it streams — waits for the full schema before rendering
117117
2. Extracts `surfaceId` and `root` from the partial JSON
118-
3. Once the schema is complete, emits `surfaceUpdate` + `beginRendering`
119-
4. Extracts complete `items` objects progressively and emits `dataModelUpdate` for each
118+
3. Once the schema is complete, emits `createSurface` + `updateComponents`
119+
4. Extracts complete `items` objects progressively and emits `updateDataModel` for each
120120
5. Cards appear one by one as data streams in
121121

122122
## Built-in progress indicator

docs/content/docs/integrations/langgraph/generative-ui/a2ui/fixed-schema.mdx

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ In the fixed-schema approach, you design the UI schema once (in a JSON file or u
1212

1313
1. Schema is loaded from a JSON file at startup
1414
2. Agent tool receives data from the LLM (e.g., flight search results)
15-
3. Tool returns `a2ui.render()` with surfaceUpdate + dataModelUpdate + beginRendering
15+
3. Tool returns `a2ui.render()` with createSurface + updateComponents + updateDataModel
1616
4. The A2UI middleware intercepts the tool result and renders the surface
1717

1818
## Implementation
@@ -65,23 +65,22 @@ def search_flights(flights: list[Flight]) -> str:
6565
"""Search for flights and display results as rich cards."""
6666
return a2ui.render(
6767
operations=[
68-
a2ui.surface_update(SURFACE_ID, FLIGHT_SCHEMA),
69-
a2ui.data_model_update(SURFACE_ID, {"flights": flights}),
70-
a2ui.begin_rendering(SURFACE_ID, "root"),
68+
a2ui.create_surface(SURFACE_ID),
69+
a2ui.update_components(SURFACE_ID, FLIGHT_SCHEMA),
70+
a2ui.update_data_model(SURFACE_ID, {"flights": flights}),
7171
],
7272
action_handlers={
7373
# Exact match: fires when a button with action.name="book_flight" is clicked
7474
"book_flight": [
75-
a2ui.surface_update(SURFACE_ID, BOOKED_SCHEMA),
76-
a2ui.data_model_update(SURFACE_ID, {
75+
a2ui.update_components(SURFACE_ID, BOOKED_SCHEMA),
76+
a2ui.update_data_model(SURFACE_ID, {
7777
"title": "Booking Confirmed",
7878
"detail": "Your flight has been booked.",
7979
}),
80-
a2ui.begin_rendering(SURFACE_ID, "root"),
8180
],
8281
# Catch-all: fires for any button action without a specific match
8382
"*": [
84-
a2ui.data_model_update(SURFACE_ID, {
83+
a2ui.update_data_model(SURFACE_ID, {
8584
"status": "Action received",
8685
}),
8786
],

docs/content/docs/integrations/langgraph/generative-ui/a2ui/index.mdx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,21 +60,21 @@ All three approaches use the same A2UI protocol and renderer. The difference is
6060

6161
## How it works
6262

63-
Every A2UI surface is built from three operations:
63+
Every A2UI v0.9 surface is built from three operations:
6464

65-
1. **`surfaceUpdate`**defines the component tree (the schema)
66-
2. **`dataModelUpdate`**provides the data that populates the components
67-
3. **`beginRendering`**tells the client to start rendering
65+
1. **`createSurface`**initializes the surface with its catalog (must come first)
66+
2. **`updateComponents`**defines the component tree (the schema)
67+
3. **`updateDataModel`**provides the data that populates the components
6868

6969
The CopilotKit Python SDK provides helpers to build these operations:
7070

7171
```python
7272
from copilotkit import a2ui
7373

74-
a2ui.surface_update(surface_id, components)
75-
a2ui.data_model_update(surface_id, {"items": data})
76-
a2ui.begin_rendering(surface_id, root_id)
77-
a2ui.render(operations) # wraps and serializes
74+
a2ui.create_surface(surface_id)
75+
a2ui.update_components(surface_id, components)
76+
a2ui.update_data_model(surface_id, {"items": data})
77+
a2ui.render(operations) # wraps in a2ui_operations and serializes
7878
```
7979

8080
Continue to one of the approach guides above to see the full implementation.

showcase/harness/src/probes/drivers/e2e-deep.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,16 @@ export interface E2eDeepPage extends Page {
220220
* gracefully when a renderer crash closes the page underneath them.
221221
*/
222222
isClosed?(): boolean;
223+
/**
224+
* Resolve a Playwright Locator for the given CSS selector. The probe
225+
* scripts use it for count-based assertions
226+
* (`page.locator(sel).count()`) when polling for an expected number of
227+
* elements to appear; the harness `Page.evaluate` path only supports
228+
* zero-arg functions, so dynamic selectors need a Locator. Optional so
229+
* test fakes can omit it; the only production probe that needs it is
230+
* `d5-tool-rendering-reasoning-chain`.
231+
*/
232+
locator?(selector: string): { count(): Promise<number> };
223233
/**
224234
* Install a request interceptor on the underlying Playwright page.
225235
* Optional — only the d5-readonly-state-context probe currently uses
@@ -426,6 +436,7 @@ const defaultLauncher: E2eDeepBrowserLauncher =
426436
requestFailures: requestFailures.slice(-10),
427437
}),
428438
isClosed: () => page.isClosed(),
439+
locator: (s) => page.locator(s),
429440
route: (url, handler) =>
430441
page.route(url, handler as Parameters<typeof page.route>[1]),
431442
unroute: (url) => page.unroute(url),
@@ -547,6 +558,7 @@ export function createPooledE2eDeepLauncher(
547558
requestFailures: requestFailures.slice(-10),
548559
}),
549560
isClosed: () => page.isClosed(),
561+
locator: (s) => page.locator(s),
550562
route: (url, handler) =>
551563
page.route(url, handler as Parameters<typeof page.route>[1]),
552564
unroute: (url) => page.unroute(url),

0 commit comments

Comments
 (0)