@svadmin/surface 0.8.19 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/README.md +70 -38
  2. package/STYLING.md +31 -0
  3. package/compatibility.json +23 -2
  4. package/dist/agent-contract.d.ts +37 -0
  5. package/dist/agent-contract.js +203 -0
  6. package/dist/agent.d.ts +38 -7
  7. package/dist/agent.js +98 -59
  8. package/dist/binding.d.ts +2 -0
  9. package/dist/binding.js +7 -1
  10. package/dist/builtin-definitions.d.ts +6 -0
  11. package/dist/builtin-definitions.js +40 -0
  12. package/dist/builtin-schemas.d.ts +25 -0
  13. package/dist/builtin-schemas.js +13 -0
  14. package/dist/catalog.d.ts +4 -61
  15. package/dist/catalog.js +20 -44
  16. package/dist/components/MetricWidget.svelte +12 -8
  17. package/dist/components/ResourceFormBody.svelte +97 -0
  18. package/dist/components/ResourceFormBody.svelte.d.ts +13 -0
  19. package/dist/components/ResourceFormWidget.svelte +19 -0
  20. package/dist/components/ResourceFormWidget.svelte.d.ts +4 -0
  21. package/dist/components/ResourceTableWidget.svelte +14 -12
  22. package/dist/components/SurfaceEditPreview.svelte +107 -0
  23. package/dist/components/SurfaceEditPreview.svelte.d.ts +20 -0
  24. package/dist/components/SurfaceRenderer.svelte +120 -163
  25. package/dist/components/SurfaceRenderer.svelte.d.ts +4 -0
  26. package/dist/components/SurfaceWorkflowProvider.svelte +22 -0
  27. package/dist/components/SurfaceWorkflowProvider.svelte.d.ts +17 -0
  28. package/dist/components/SvarGridWidget.svelte +47 -0
  29. package/dist/components/SvarGridWidget.svelte.d.ts +4 -0
  30. package/dist/components/SvarSurfaceProvider.svelte +12 -0
  31. package/dist/components/SvarSurfaceProvider.svelte.d.ts +11 -0
  32. package/dist/edits.d.ts +57 -0
  33. package/dist/edits.js +166 -0
  34. package/dist/index.d.ts +8 -2
  35. package/dist/index.js +5 -1
  36. package/dist/interactive.d.ts +6 -0
  37. package/dist/interactive.js +15 -0
  38. package/dist/openui.d.ts +64 -0
  39. package/dist/openui.js +168 -0
  40. package/dist/schema.d.ts +108 -0
  41. package/dist/schema.js +73 -0
  42. package/dist/server-sqlite.d.ts +1 -0
  43. package/dist/server-sqlite.js +2 -0
  44. package/dist/server.d.ts +4 -0
  45. package/dist/server.js +4 -0
  46. package/dist/source-cache.d.ts +30 -0
  47. package/dist/source-cache.js +135 -0
  48. package/dist/styled-system/css/conditions.js +36 -0
  49. package/dist/styled-system/css/css.d.ts +22 -0
  50. package/dist/styled-system/css/css.js +45 -0
  51. package/dist/styled-system/css/cva.d.ts +6 -0
  52. package/dist/styled-system/css/cva.js +87 -0
  53. package/dist/styled-system/css/cx.d.ts +5 -0
  54. package/dist/styled-system/css/cx.js +15 -0
  55. package/dist/styled-system/css/index.d.ts +5 -0
  56. package/dist/styled-system/css/index.js +4 -0
  57. package/dist/styled-system/css/sva.d.ts +4 -0
  58. package/dist/styled-system/css/sva.js +46 -0
  59. package/dist/styled-system/design-contract.d.ts +13 -0
  60. package/dist/styled-system/design-contract.js +11 -0
  61. package/dist/styled-system/helpers.js +316 -0
  62. package/dist/styled-system/patterns/aspect-ratio.d.ts +20 -0
  63. package/dist/styled-system/patterns/aspect-ratio.js +38 -0
  64. package/dist/styled-system/patterns/bleed.d.ts +21 -0
  65. package/dist/styled-system/patterns/bleed.js +24 -0
  66. package/dist/styled-system/patterns/box.d.ts +20 -0
  67. package/dist/styled-system/patterns/box.js +15 -0
  68. package/dist/styled-system/patterns/center.d.ts +20 -0
  69. package/dist/styled-system/patterns/center.js +21 -0
  70. package/dist/styled-system/patterns/circle.d.ts +20 -0
  71. package/dist/styled-system/patterns/circle.js +25 -0
  72. package/dist/styled-system/patterns/container.d.ts +20 -0
  73. package/dist/styled-system/patterns/container.js +21 -0
  74. package/dist/styled-system/patterns/cq.d.ts +21 -0
  75. package/dist/styled-system/patterns/cq.js +21 -0
  76. package/dist/styled-system/patterns/divider.d.ts +22 -0
  77. package/dist/styled-system/patterns/divider.js +25 -0
  78. package/dist/styled-system/patterns/flex.d.ts +26 -0
  79. package/dist/styled-system/patterns/flex.js +26 -0
  80. package/dist/styled-system/patterns/float.d.ts +23 -0
  81. package/dist/styled-system/patterns/float.js +52 -0
  82. package/dist/styled-system/patterns/grid-item.d.ts +25 -0
  83. package/dist/styled-system/patterns/grid-item.js +25 -0
  84. package/dist/styled-system/patterns/grid.d.ts +24 -0
  85. package/dist/styled-system/patterns/grid.js +27 -0
  86. package/dist/styled-system/patterns/hstack.d.ts +21 -0
  87. package/dist/styled-system/patterns/hstack.js +24 -0
  88. package/dist/styled-system/patterns/index.d.ts +21 -0
  89. package/dist/styled-system/patterns/index.js +20 -0
  90. package/dist/styled-system/patterns/link-overlay.d.ts +20 -0
  91. package/dist/styled-system/patterns/link-overlay.js +24 -0
  92. package/dist/styled-system/patterns/spacer.d.ts +20 -0
  93. package/dist/styled-system/patterns/spacer.js +25 -0
  94. package/dist/styled-system/patterns/square.d.ts +20 -0
  95. package/dist/styled-system/patterns/square.js +24 -0
  96. package/dist/styled-system/patterns/stack.d.ts +23 -0
  97. package/dist/styled-system/patterns/stack.js +24 -0
  98. package/dist/styled-system/patterns/visually-hidden.d.ts +20 -0
  99. package/dist/styled-system/patterns/visually-hidden.js +18 -0
  100. package/dist/styled-system/patterns/vstack.d.ts +21 -0
  101. package/dist/styled-system/patterns/vstack.js +24 -0
  102. package/dist/styled-system/patterns/wrap.d.ts +24 -0
  103. package/dist/styled-system/patterns/wrap.js +25 -0
  104. package/dist/styled-system/recipes/content-header.d.ts +31 -0
  105. package/dist/styled-system/recipes/content-header.js +65 -0
  106. package/dist/styled-system/recipes/content-page.d.ts +34 -0
  107. package/dist/styled-system/recipes/content-page.js +43 -0
  108. package/dist/styled-system/recipes/create-recipe.js +82 -0
  109. package/dist/styled-system/recipes/index.d.ts +17 -0
  110. package/dist/styled-system/recipes/index.js +16 -0
  111. package/dist/styled-system/recipes/metric-block.d.ts +34 -0
  112. package/dist/styled-system/recipes/metric-block.js +76 -0
  113. package/dist/styled-system/recipes/product-list.d.ts +31 -0
  114. package/dist/styled-system/recipes/product-list.js +73 -0
  115. package/dist/styled-system/recipes/product-section.d.ts +31 -0
  116. package/dist/styled-system/recipes/product-section.js +49 -0
  117. package/dist/styled-system/recipes/product-settings-row.d.ts +34 -0
  118. package/dist/styled-system/recipes/product-settings-row.js +58 -0
  119. package/dist/styled-system/recipes/product-settings.d.ts +31 -0
  120. package/dist/styled-system/recipes/product-settings.js +57 -0
  121. package/dist/styled-system/recipes/product-status.d.ts +34 -0
  122. package/dist/styled-system/recipes/product-status.js +45 -0
  123. package/dist/styled-system/recipes/product-toolbar.d.ts +31 -0
  124. package/dist/styled-system/recipes/product-toolbar.js +41 -0
  125. package/dist/styled-system/recipes/product-workspace.d.ts +34 -0
  126. package/dist/styled-system/recipes/product-workspace.js +58 -0
  127. package/dist/styled-system/recipes/surface-metric.d.ts +38 -0
  128. package/dist/styled-system/recipes/surface-metric.js +63 -0
  129. package/dist/styled-system/recipes/surface-table.d.ts +34 -0
  130. package/dist/styled-system/recipes/surface-table.js +62 -0
  131. package/dist/styled-system/recipes/ui-badge.d.ts +31 -0
  132. package/dist/styled-system/recipes/ui-badge.js +38 -0
  133. package/dist/styled-system/recipes/ui-button.d.ts +32 -0
  134. package/dist/styled-system/recipes/ui-button.js +43 -0
  135. package/dist/styled-system/recipes/ui-input.d.ts +31 -0
  136. package/dist/styled-system/recipes/ui-input.js +49 -0
  137. package/dist/styled-system/recipes/ui-textarea.d.ts +31 -0
  138. package/dist/styled-system/recipes/ui-textarea.js +24 -0
  139. package/dist/styled-system/styles.css +1257 -0
  140. package/dist/styled-system/tokens/index.d.ts +9 -0
  141. package/dist/styled-system/tokens/index.js +268 -0
  142. package/dist/styled-system/tokens/tokens.d.ts +36 -0
  143. package/dist/styled-system/types/composition.d.ts +227 -0
  144. package/dist/styled-system/types/conditions.d.ts +236 -0
  145. package/dist/styled-system/types/csstype.d.ts +22570 -0
  146. package/dist/styled-system/types/index.d.ts +6 -0
  147. package/dist/styled-system/types/parts.d.ts +8 -0
  148. package/dist/styled-system/types/pattern.d.ts +78 -0
  149. package/dist/styled-system/types/prop-type.d.ts +223 -0
  150. package/dist/styled-system/types/recipe.d.ts +181 -0
  151. package/dist/styled-system/types/selectors.d.ts +59 -0
  152. package/dist/styled-system/types/static-css.d.ts +56 -0
  153. package/dist/styled-system/types/style-props.d.ts +8088 -0
  154. package/dist/styled-system/types/system-types.d.ts +151 -0
  155. package/dist/styles/editor.css +124 -0
  156. package/dist/styles/editor.generated.d.ts +8 -0
  157. package/dist/styles/editor.generated.js +9 -0
  158. package/dist/styles.css +1262 -0
  159. package/dist/svar-catalog.d.ts +3 -0
  160. package/dist/svar-catalog.js +7 -0
  161. package/dist/svar-context.d.ts +9 -0
  162. package/dist/svar-context.js +1 -0
  163. package/dist/svar-schema.d.ts +21 -0
  164. package/dist/svar-schema.js +36 -0
  165. package/dist/svar.d.ts +4 -0
  166. package/dist/svar.js +3 -0
  167. package/dist/svelte.d.ts +4 -2
  168. package/dist/svelte.js +2 -1
  169. package/dist/types.d.ts +4 -0
  170. package/dist/validation.js +2 -102
  171. package/dist/wire.d.ts +13 -0
  172. package/dist/wire.js +30 -0
  173. package/dist/workflows/action-contracts.d.ts +7 -0
  174. package/dist/workflows/action-contracts.js +54 -0
  175. package/dist/workflows/catalog.d.ts +20 -0
  176. package/dist/workflows/catalog.js +50 -0
  177. package/dist/workflows/client.d.ts +45 -0
  178. package/dist/workflows/client.js +125 -0
  179. package/dist/workflows/context.d.ts +9 -0
  180. package/dist/workflows/context.js +5 -0
  181. package/dist/workflows/openui-guard.d.ts +19 -0
  182. package/dist/workflows/openui-guard.js +209 -0
  183. package/dist/workflows/service.d.ts +58 -0
  184. package/dist/workflows/service.js +296 -0
  185. package/dist/workflows/sqlite-store.d.ts +20 -0
  186. package/dist/workflows/sqlite-store.js +91 -0
  187. package/dist/workflows/types.d.ts +103 -0
  188. package/dist/workflows/types.js +8 -0
  189. package/dist/workflows.d.ts +5 -0
  190. package/dist/workflows.js +4 -0
  191. package/package.json +52 -8
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # @svadmin/surface
2
2
 
3
- `@svadmin/surface` renders a small, versioned JSON contract as a trusted Svelte dashboard. It is an optional browser package and does not change the public contract of `@svadmin/core`.
3
+ `@svadmin/surface` renders a versioned JSON contract as a trusted Svelte dashboard. It is an optional package and does not change the public contract of `@svadmin/core`.
4
4
 
5
- The MVP supports Svelte 5 + Vite, a fixed 12-column grid, four built-in widgets, read-only `DataProvider` queries, explicit access checks, field projection, and manual host refresh.
5
+ `surface/v1` supports Svelte 5 + Vite, a fixed 12-column grid, four built-in widgets, read-only `DataProvider` queries, explicit access checks, field projection, and manual host refresh. Optional AI helpers derive generation contracts from the component catalog and support revision-checked edit proposals.
6
6
 
7
7
  ## Install
8
8
 
@@ -10,7 +10,7 @@ The MVP supports Svelte 5 + Vite, a fixed 12-column grid, four built-in widgets,
10
10
  bun add @svadmin/surface @svadmin/core @svadmin/ui @tanstack/svelte-query svelte @sinclair/typebox
11
11
  ```
12
12
 
13
- Import protocol types and validation from the DOM-free root entry. Import rendering code from the Svelte subpath.
13
+ Import protocol types and validation from the DOM-free root entry. Import rendering code from the Svelte subpath. Hosts do not need Panda or Tailwind compiler plugins to consume precompiled component styles.
14
14
 
15
15
  ```ts
16
16
  import { validateSurfaceSpec, type SurfacePolicy, type SurfaceSpec } from '@svadmin/surface';
@@ -27,10 +27,7 @@ import {
27
27
  ```svelte
28
28
  <script lang="ts">
29
29
  import type { SurfacePolicy, SurfaceSpec } from '@svadmin/surface';
30
- import {
31
- DEFAULT_SURFACE_CATALOG_VERSION,
32
- SurfaceRenderer,
33
- } from '@svadmin/surface/svelte';
30
+ import { DEFAULT_SURFACE_CATALOG_VERSION, SurfaceRenderer } from '@svadmin/surface/svelte';
34
31
 
35
32
  const policy = {
36
33
  resources: {
@@ -78,35 +75,69 @@ import {
78
75
 
79
76
  When rendered inside `AdminApp`, the renderer resolves the configured provider for each resource. A trusted host may instead pass `dataProvider`, which is still narrowed to `getList` and `getOne`.
80
77
 
81
- The renderer also follows the active `AdminApp` i18n locale. Built-in loading, empty, error, boolean, number, currency, percent, and date presentation updates automatically. A standalone host can pass `locale`, and can override individual built-in strings with `messages`. Business copy such as the surface title, widget titles, labels, and column headers remains part of the JSON spec; build or select a localized spec when the host locale changes.
78
+ The renderer follows the active `AdminApp` i18n locale. Built-in loading, empty, error, boolean, number, currency, percent, and date presentation updates automatically. A standalone host can pass `locale` and override built-in strings with `messages`. Business copy such as titles, labels, and column headers remains part of the JSON spec.
82
79
 
83
80
  ```svelte
84
- <SurfaceRenderer
85
- {spec}
86
- {policy}
87
- locale="zh-CN"
88
- messages={{ tableNoRecords: '没有符合条件的记录' }}
89
- />
81
+ <SurfaceRenderer {spec} {policy} locale="zh-CN"
82
+ messages={{ tableNoRecords: '没有符合条件的记录' }} />
90
83
  ```
91
84
 
92
- ## AI proposals
85
+ ## Incremental loading and session boundaries
86
+
87
+ Title, layout, widget ordering, equivalent JSON and locale-only changes reuse unchanged source results and in-flight reads. Query, projection-policy or provider changes reload only affected sources. `refresh(sourceId)` forces one source and `refresh()` forces all sources. Stale replies and errors are ignored after replacement, removal or destruction; this is logical cancellation, not a transport `AbortSignal` guarantee.
88
+
89
+ Stable widget IDs and component types preserve local input state during visual edits. Removed/retyped widgets can remount. A changed trusted `scopeKey` or `dataScopeKey` clears source identity and remounts local widget state; observable logout, tenant, authentication and access-control identities are also tracked. Hosts must update a non-secret scope token when opaque credentials/session state changes, and discard pending AI proposals on account or tenant changes. These properties are not model-controlled fields. Presentation changes are no longer implicit data refresh or reauthorization signals.
90
+
91
+ ## AI generation contracts
93
92
 
94
- The DOM-free root entry also exposes an opt-in Agent protocol. `buildSurfaceAgentPrompt()` constrains a model to return a proposal envelope and includes the host's widget/resource/field allowlists. `parseSurfaceAgentProposal()` parses and validates the complete `SurfaceSpec` against the same catalog and policy without querying a provider:
93
+ Catalog definitions can include `description` and schema-validated `examples`. The root exports `createSurfaceCatalogManifest()` and `createSurfaceAgentResponseSchema()` for model adapters. Inline, closed TypeBox object schemas are supported; transforms and schema references fail explicitly rather than silently weakening the generated contract.
95
94
 
96
95
  ```ts
97
96
  import {
98
- buildSurfaceAgentPrompt,
99
- parseSurfaceAgentProposal,
97
+ buildSurfaceAgentMessages,
98
+ parseSurfaceAgentResponse,
99
+ selectSurfaceCatalog,
100
100
  } from '@svadmin/surface';
101
-
102
- const prompt = buildSurfaceAgentPrompt('Generate an inventory dashboard', catalog, policy);
103
- const proposal = parseSurfaceAgentProposal(modelText, catalog, policy);
104
- if (proposal.ok) {
105
- // Preview proposal.value.spec, then require explicit user approval before rendering.
101
+ import { defaultSurfaceCatalog } from '@svadmin/surface/svelte';
102
+
103
+ const catalog = selectSurfaceCatalog(defaultSurfaceCatalog, ['metric', 'resource-table']);
104
+ const messages = buildSurfaceAgentMessages('Generate an inventory dashboard', catalog, policy);
105
+ // Send messages through a trusted model adapter. Never expose model credentials.
106
+ const response = parseSurfaceAgentResponse(modelText, catalog, policy);
107
+ if (response.ok && response.value.action === 'propose') {
108
+ // Preview response.value.spec and require explicit approval before applying it.
109
+ } else if (response.ok) {
110
+ // Render response.value.message as text: this is a cannot-fulfill response.
106
111
  }
107
112
  ```
108
113
 
109
- The adapter is deliberately proposal-only. Persistence, revision history, audit records, and the final apply decision belong to the host application. It never executes generated code or mutation actions.
114
+ Use the same task-scoped catalog for generation, validation and rendering. JSON Schema narrows generation but does not replace cross-source binding checks, field policy or server authorization. The schema is not claimed to match every vendor's restricted structured-output subset.
115
+
116
+ `buildSurfaceAgentPrompt()` and `parseSurfaceAgentProposal()` remain compatible with the legacy proposal-only `surface-agent/v1` envelope. The new message API uses `surface-agent/v2` with a structured `cannot-fulfill` alternative. `createSurfaceAgentStream()` buffers bounded text and validates at `finish()`; it does **not** render partial JSON or implement OpenUI Lang streaming.
117
+
118
+ ## Revisioned edits and explicit preview
119
+
120
+ `createSurfaceRevision()` creates a validated immutable snapshot. `buildSurfaceEditMessages()` describes the current revision, catalog and allowed operations. `applySurfaceEditProposal()` validates a complete `surface-edit/v1` transaction and returns a new candidate revision without mutating the old one. Operations cover title/layout, widget/source upsert/removal and complete widget reordering by stable ID. Stale `baseRevision`, unknown IDs, invalid props, denied fields and broken final references reject the whole transaction.
121
+
122
+ The Svelte `SurfaceEditPreview` component accepts a controlled revision and untrusted proposal:
123
+
124
+ ```svelte
125
+ <SurfaceEditPreview
126
+ {revision}
127
+ {proposal}
128
+ {streaming}
129
+ {policy}
130
+ {catalog}
131
+ {dataProvider}
132
+ scopeKey={trustedSessionRevision}
133
+ density="comfortable"
134
+ onApply={applyApprovedRevision}
135
+ />
136
+ ```
137
+
138
+ It leaves the current surface intact during streaming, offers a separate preview/back action, and revalidates at the explicit apply click. It calls `onApply(candidate)` only for a valid proposal. The host performs any persistence with server authorization and atomic revision compare-and-swap, then updates `revision` and clears `proposal`. Missing handlers, invalid proposals and pending callbacks disable application. A rejected callback reports an error without changing the controlled revision. Changing scope does not authorize an old proposal: the host must discard old proposals as described above.
139
+
140
+ The new preview controls use Panda build-time tokens/recipes and import their compiled CSS. `@svadmin/surface/editor.css` is also available for explicit CSS collection. Only finite density/button variants are emitted; host styles can override the existing complete-color semantic CSS variables. The integrated main already uses the compiler-free native/Panda build from PR #430; this preview adds its own scoped recipes without restoring Tailwind dependencies. The separate `@svadmin/surface/styles.css` entry for `styledSurfaceCatalog` remains available; see `STYLING.md`.
110
141
 
111
142
  ## Built-in catalog
112
143
 
@@ -117,18 +148,21 @@ The adapter is deliberately proposal-only. Persistence, revision history, audit
117
148
  | `bar-chart` | `/items` | Zero-dependency SVG bar chart |
118
149
  | `line-chart` | `/items` | Zero-dependency SVG line chart |
119
150
 
120
- The catalog version is `svadmin/v1`. `catalogVersion` must match exactly.
121
-
122
- Custom catalogs are trusted runtime configuration. Every registration must use a strict TypeBox object schema and a trusted Svelte component. Item widgets that read record fields must expose those fields through `getReferencedFields`; validation then checks them against `SurfacePolicy.readFields`.
151
+ The catalog version is `svadmin/v1`. `catalogVersion` must match exactly. Custom registrations use strict TypeBox props schemas and trusted Svelte components. Item widgets reading record fields must expose them through `getReferencedFields` so runtime validation checks `SurfacePolicy.readFields`.
123
152
 
124
153
  ```ts
154
+ import { Type } from '@sinclair/typebox';
155
+ import { Value } from '@sinclair/typebox/value';
156
+
157
+ const statusProps = Type.Object({ statusField: Type.String() }, { additionalProperties: false });
125
158
  const catalog = defineSurfaceCatalog({
126
159
  version: 'acme/v1',
127
160
  widgets: [{
128
161
  type: 'status-list',
162
+ description: 'Display a policy-authorized status field from resource items.',
129
163
  dataKind: 'items',
130
- propsSchema: z.object({ statusField: z.string() }).strict(),
131
- getReferencedFields: (props) => [props.statusField as string],
164
+ propsSchema: statusProps,
165
+ getReferencedFields: (props) => [Value.Decode(statusProps, props).statusField],
132
166
  component: StatusList,
133
167
  }],
134
168
  });
@@ -136,18 +170,16 @@ const catalog = defineSurfaceCatalog({
136
170
 
137
171
  ## Security boundary
138
172
 
139
- Surface specs are untrusted data. The renderer validates the whole document before sending any query. It rejects unknown components and sources, duplicate or overlong IDs, invalid props, dangerous pointers, mismatched versions, policy violations, and configured limits.
140
-
141
- Specs cannot contain HTML, Svelte, JavaScript, event handlers, Tailwind classes, style declarations, colors, URLs, SQL, provider selection, `meta`, arbitrary requests, or mutation actions. Provider records are projected to `readFields`, and selected values containing `Date`, `File`, `BigInt`, functions, cycles, `NaN`, or infinities fail instead of being converted.
173
+ Surface specs are untrusted data. The renderer validates the whole document before sending any query. It rejects unknown components/sources, duplicate or overlong IDs, invalid props, dangerous pointers, mismatched versions, policy violations, and configured limits.
142
174
 
143
- The browser access-control check is display gating only. The backend must independently authorize every request and must not trust the spec, policy, or projected fields received from a browser.
175
+ Specs cannot contain executable HTML, Svelte, JavaScript, event handlers, class names, style declarations, colors, URLs, SQL, provider selection, `meta`, arbitrary requests, or mutation actions. Provider records are projected to `readFields`. Selected values containing `Date`, `File`, `BigInt`, functions, cycles, `NaN`, or infinities fail instead of being converted.
144
176
 
145
- MVP limits are eight data sources, 24 widgets, 100 rows per page, eight filters, three sorters, 64-character IDs, 64 levels of JSON nesting, and 10,000 JSON nodes. A source is loaded once and shared. Generation checks discard stale responses.
177
+ The browser access-control check is display gating only. The backend must independently authorize every request and must not trust a spec, client policy or projected fields as proof of authority. AI and edit helpers neither contact a model nor execute business writes. Persistence, audit records, model transport and approval policy belong to the host.
146
178
 
147
- Supported Core/UI ranges and the minimum packed-consumer matrix are published in `compatibility.json`.
179
+ Limits are eight data sources, 24 widgets, 100 rows per page, eight filters, three sorters, 64-character IDs, 64 levels of JSON nesting, and 10,000 JSON nodes. AI text/request/contract sizes and edit operation counts are separately bounded by their exported limit constants. Supported Core/UI ranges and packed-consumer requirements are published in `compatibility.json`.
148
180
 
149
- ## Out of scope for v1
181
+ ## Current boundaries
150
182
 
151
- SSR/Lite, Agent generation, storage, revisions, JSON Patch, actions, mutations, automatic refresh, arbitrary URLs, client aggregation, Canvas, and iframe rendering are intentionally absent. Aggregated metrics should come from a backend summary resource and bind through `resource-one`.
183
+ Actual OpenUI Lang parsing, nested interactive forms, registered business actions, server persistence, SSR/Lite rendering, arbitrary URLs, client aggregation, Canvas and iframe execution are not implemented. Aggregated metrics should come from a policy-authorized backend summary resource and bind through `resource-one`. The current UI contract remains read-only even though its definition can be edited.
152
184
 
153
- 中文指南见文档站的“声明式 Surface”。
185
+ See `docs/architecture/openui-surface-phase2.md` for the original feature scope and `docs/architecture/surface-integration-provenance.md` for its integration with the current native/Panda main. 中文指南见文档站的“声明式 Surface”。
package/STYLING.md ADDED
@@ -0,0 +1,31 @@
1
+ # Surface semantic styles
2
+
3
+ 默认 `svadmin/v1` 的校验规则和未指定变体时的组件样式保持兼容。新语义变体必须显式选择 `styledSurfaceCatalog`,不能只把 tone/density 添加到旧版 spec。
4
+
5
+ ```ts
6
+ import '@svadmin/ui/app.css';
7
+ import '@svadmin/surface/styles.css';
8
+ import { styledSurfaceCatalog, STYLED_SURFACE_CATALOG_VERSION } from '@svadmin/surface/svelte';
9
+ ```
10
+
11
+ 将 spec.catalogVersion 设置为 STYLED_SURFACE_CATALOG_VERSION,并把同一 styledSurfaceCatalog 传给提示生成器、校验器和 SurfaceRenderer 的 catalog 属性。这样三个环节使用同一组件契约。`metric` 支持 tone(neutral/success/warning/danger/info)及 density(comfortable/compact),`resource-table` 支持 density。
12
+
13
+ ```json
14
+ {
15
+ "type": "metric",
16
+ "props": {
17
+ "label": "待处理订单",
18
+ "format": "number",
19
+ "tone": "warning",
20
+ "density": "compact"
21
+ }
22
+ }
23
+ ```
24
+
25
+ 以上只是 widget 片段;完整 spec 仍需要 schemaVersion、catalogVersion、数据源、绑定及布局等必要字段。
26
+
27
+ Surface 自行打包预生成的 recipe 助手与 styles.css,避免让旧 UI peer 安装必须提供新增的 JS 导出入口。构建本仓库时先构建 UI 样式,再构建 Surface;消费发布包时不需要安装 Panda 或 Tailwind。配合尚未包含新 recipe CSS 的 UI 版本时必须加载 Surface 的 styles.css。
28
+
29
+ AI 只能选择公开枚举,不能指定 class/style、任意颜色、recipe 定义或可执行代码。字段权限、只读查询、版本匹配和宿主确认要求不因样式变体而改变。
30
+
31
+ 本次是两类 Surface 组件的 recipes 试点;其他 UI 继续使用保留的原生兼容样式。OpenUI Lang 的解析、流式渲染适配、全量 UI recipe 重写以及 DTCG 文件转换器不在本次已实现范围。不能把 CSS 编译器移除等同于以上功能已经完成。
@@ -1,5 +1,5 @@
1
1
  {
2
- "surface": "0.8.x",
2
+ "surface": "0.9.x",
3
3
  "minimumSupported": {
4
4
  "@svadmin/core": "0.34.2",
5
5
  "@svadmin/ui": "0.40.6",
@@ -18,5 +18,26 @@
18
18
  "ui": "workspace tarball",
19
19
  "svelte": "workspace override"
20
20
  }
21
- ]
21
+ ],
22
+ "minimumSupportedAppliesTo": [
23
+ ".",
24
+ "./svelte"
25
+ ],
26
+ "entrypointCompatibility": {
27
+ "./interactive": {
28
+ "status": "experimental",
29
+ "requiredUiCapabilities": [
30
+ "JsonSchemaForm.idPrefix",
31
+ "proxy-safe nested field updates",
32
+ "required boolean and decimal input support"
33
+ ],
34
+ "minimumPublishedUi": null,
35
+ "verification": "same-checkout tarballs via scripts/surface-workflows/packed-consumer.mjs; inspect the current run result",
36
+ "releaseGate": "Coordinate a tested UI release and narrow the package peer floor before publishing this entry."
37
+ },
38
+ "./server/sqlite": {
39
+ "runtime": "Node.js",
40
+ "verification": "Current CI Node version with real node:sqlite; no browser or distributed-store support implied."
41
+ }
42
+ }
22
43
  }
@@ -0,0 +1,37 @@
1
+ import { type TSchema } from '@sinclair/typebox';
2
+ import { type JsonObject, type SurfaceCatalog, type SurfacePolicy } from './types.js';
3
+ export declare const SURFACE_CATALOG_SCHEMA_VERSION: "surface-catalog/v1";
4
+ export declare const SURFACE_AGENT_SCHEMA_VERSION: "surface-agent/v1";
5
+ export declare const SURFACE_AGENT_RESPONSE_SCHEMA_VERSION: "surface-agent/v2";
6
+ export declare const SURFACE_AGENT_LIMITS: {
7
+ readonly maxInputCharacters: 262144;
8
+ readonly maxRequestCharacters: 16384;
9
+ readonly maxContractCharacters: 131072;
10
+ };
11
+ export interface SurfaceCatalogManifest {
12
+ readonly schemaVersion: typeof SURFACE_CATALOG_SCHEMA_VERSION;
13
+ readonly catalogVersion: string;
14
+ readonly widgets: readonly {
15
+ readonly type: string;
16
+ readonly dataKind: 'none' | 'scalar' | 'items';
17
+ readonly description?: string;
18
+ readonly propsSchema: JsonObject;
19
+ readonly examples?: readonly JsonObject[];
20
+ }[];
21
+ }
22
+ /** 不把 Transform、函数或引用 schema 静默降级为宽松的 JSON schema。 */
23
+ export declare function surfaceSchemaToJson(schema: TSchema): JsonObject;
24
+ /** 同一目录可用于提示、运行时校验及渲染;任务筛选不会仅在提示词中生效。 */
25
+ export declare function selectSurfaceCatalog<T extends SurfaceCatalog>(catalog: T, widgetTypes: readonly string[]): Omit<T, 'widgets'> & {
26
+ readonly widgets: readonly T['widgets'][number][];
27
+ };
28
+ export declare function createSurfaceCatalogManifest(catalog: SurfaceCatalog): SurfaceCatalogManifest;
29
+ /** 生成约束缩小候选空间,不能代替绑定/字段关联校验,更不能代替后端授权。 */
30
+ export declare function createSurfaceGenerationSpecSchema(catalog: SurfaceCatalog, policy: SurfacePolicy): TSchema;
31
+ export declare function createSurfaceAgentResponseSchema(catalog: SurfaceCatalog, policy: SurfacePolicy): JsonObject;
32
+ export declare const surfaceCannotFulfillSchema: import("@sinclair/typebox").TObject<{
33
+ schemaVersion: import("@sinclair/typebox").TLiteral<"surface-agent/v2">;
34
+ action: import("@sinclair/typebox").TLiteral<"cannot-fulfill">;
35
+ reason: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"unsupported_request">, import("@sinclair/typebox").TLiteral<"insufficient_permissions">, import("@sinclair/typebox").TLiteral<"insufficient_context">]>;
36
+ message: import("@sinclair/typebox").TString;
37
+ }>;
@@ -0,0 +1,203 @@
1
+ import { Kind, OptionalKind, ReadonlyKind, Type } from '@sinclair/typebox';
2
+ import { Value } from '@sinclair/typebox/value';
3
+ import { escapedJsonPointerToken, jsonValueIssue } from './json.js';
4
+ import { surfaceFilterSchema, surfaceIdSchema, surfaceListSourceSchema, surfaceOneSourceSchema, surfaceSpecSchema, surfaceWidgetSchema, } from './schema.js';
5
+ import { SURFACE_LIMITS, SURFACE_SCHEMA_VERSION, } from './types.js';
6
+ export const SURFACE_CATALOG_SCHEMA_VERSION = 'surface-catalog/v1';
7
+ export const SURFACE_AGENT_SCHEMA_VERSION = 'surface-agent/v1';
8
+ export const SURFACE_AGENT_RESPONSE_SCHEMA_VERSION = 'surface-agent/v2';
9
+ export const SURFACE_AGENT_LIMITS = {
10
+ maxInputCharacters: 262_144,
11
+ maxRequestCharacters: 16_384,
12
+ maxContractCharacters: 131_072,
13
+ };
14
+ /** 不把 Transform、函数或引用 schema 静默降级为宽松的 JSON schema。 */
15
+ export function surfaceSchemaToJson(schema) {
16
+ const ancestors = new Set();
17
+ let nodes = 0;
18
+ function visit(value, depth) {
19
+ nodes += 1;
20
+ if (nodes > SURFACE_LIMITS.maxJsonNodes || depth > SURFACE_LIMITS.maxJsonDepth) {
21
+ throw new Error('Surface schema exceeds the supported size');
22
+ }
23
+ if (value === null || typeof value === 'string' || typeof value === 'boolean')
24
+ return value;
25
+ if (typeof value === 'number' && Number.isFinite(value))
26
+ return value;
27
+ if (typeof value !== 'object' || ancestors.has(value)) {
28
+ throw new Error('Surface schema must be serializable without transforms or cycles');
29
+ }
30
+ const prototype = Object.getPrototypeOf(value);
31
+ if (!Array.isArray(value) && prototype !== Object.prototype && prototype !== null) {
32
+ throw new Error('Surface schema must contain only plain objects');
33
+ }
34
+ ancestors.add(value);
35
+ const result = Object.create(null);
36
+ for (const key of Reflect.ownKeys(value)) {
37
+ if (Array.isArray(value) && key === 'length')
38
+ continue;
39
+ if (typeof key === 'symbol') {
40
+ if (key === Kind || key === OptionalKind || key === ReadonlyKind)
41
+ continue;
42
+ throw new Error('Surface schema contains unsupported symbol metadata or a transform');
43
+ }
44
+ if (['__proto__', 'constructor', 'prototype', '$ref', '$dynamicRef', '$recursiveRef'].includes(key)) {
45
+ throw new Error(`Surface schema key "${key}" is not supported; use an inline schema`);
46
+ }
47
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
48
+ if (!descriptor?.enumerable || !('value' in descriptor)) {
49
+ throw new Error('Surface schema accessors and hidden properties are not supported');
50
+ }
51
+ result[key] = visit(descriptor.value, depth + 1);
52
+ }
53
+ ancestors.delete(value);
54
+ if (Array.isArray(value)) {
55
+ if (Object.keys(result).length !== value.length || Object.keys(result).some((key) => !/^(0|[1-9][0-9]*)$/u.test(key) || Number(key) >= value.length)) {
56
+ throw new Error('Surface schema arrays must be dense JSON arrays');
57
+ }
58
+ return Array.from({ length: value.length }, (_, index) => {
59
+ const item = result[String(index)];
60
+ if (item === undefined)
61
+ throw new Error('Surface schema arrays must be dense JSON arrays');
62
+ return item;
63
+ });
64
+ }
65
+ return result;
66
+ }
67
+ const result = visit(schema, 0);
68
+ if (result === null || typeof result !== 'object' || Array.isArray(result)) {
69
+ throw new Error('Expected an object JSON schema');
70
+ }
71
+ if (JSON.stringify(result).length > SURFACE_AGENT_LIMITS.maxContractCharacters) {
72
+ throw new Error('Surface schema exceeds the supported character count');
73
+ }
74
+ return result;
75
+ }
76
+ function isClosedObject(schema) {
77
+ if (schema['type'] === 'object' && schema['additionalProperties'] === false)
78
+ return true;
79
+ const branches = schema['anyOf'] ?? schema['oneOf'] ?? schema['allOf'];
80
+ return Array.isArray(branches) && branches.length > 0 && branches.every((branch) => (branch !== null && typeof branch === 'object' && !Array.isArray(branch) && isClosedObject(branch)));
81
+ }
82
+ /** 同一目录可用于提示、运行时校验及渲染;任务筛选不会仅在提示词中生效。 */
83
+ export function selectSurfaceCatalog(catalog, widgetTypes) {
84
+ const requested = new Set(widgetTypes);
85
+ if (requested.size !== widgetTypes.length)
86
+ throw new Error('Duplicate requested surface widget type');
87
+ const known = new Set(catalog.widgets.map((widget) => widget.type));
88
+ for (const type of requested) {
89
+ if (!known.has(type))
90
+ throw new Error(`Unknown surface widget type "${type}"`);
91
+ }
92
+ return { ...catalog, widgets: catalog.widgets.filter((widget) => requested.has(widget.type)) };
93
+ }
94
+ export function createSurfaceCatalogManifest(catalog) {
95
+ if (!catalog.version)
96
+ throw new Error('Surface catalog version must not be empty');
97
+ const known = new Set();
98
+ const widgets = catalog.widgets.map((widget) => {
99
+ if (!/^[A-Za-z][A-Za-z0-9_-]*$/u.test(widget.type) || widget.type.length > SURFACE_LIMITS.maxIdLength || known.has(widget.type)) {
100
+ throw new Error(`Invalid or duplicate surface widget type "${widget.type}"`);
101
+ }
102
+ known.add(widget.type);
103
+ if (!['none', 'scalar', 'items'].includes(widget.dataKind))
104
+ throw new Error('Invalid surface widget data kind');
105
+ const propsSchema = surfaceSchemaToJson(widget.propsSchema);
106
+ if (!isClosedObject(propsSchema))
107
+ throw new Error(`Widget "${widget.type}" must use a closed object props schema`);
108
+ const examples = widget.examples?.map((props) => {
109
+ if (jsonValueIssue(props) || !Value.Check(widget.propsSchema, props)) {
110
+ throw new Error(`Invalid props example for widget "${widget.type}"`);
111
+ }
112
+ return JSON.parse(JSON.stringify(props));
113
+ });
114
+ return {
115
+ type: widget.type,
116
+ dataKind: widget.dataKind,
117
+ ...(widget.description === undefined ? {} : { description: widget.description }),
118
+ propsSchema,
119
+ ...(examples === undefined ? {} : { examples }),
120
+ };
121
+ });
122
+ const manifest = {
123
+ schemaVersion: SURFACE_CATALOG_SCHEMA_VERSION,
124
+ catalogVersion: catalog.version,
125
+ widgets,
126
+ };
127
+ if (jsonValueIssue(manifest) || JSON.stringify(manifest).length > SURFACE_AGENT_LIMITS.maxContractCharacters) {
128
+ throw new Error('Surface catalog manifest exceeds the JSON contract limits');
129
+ }
130
+ return manifest;
131
+ }
132
+ function literals(values) {
133
+ return values.length === 0 ? Type.Never() : Type.Union([...new Set(values)].map((value) => Type.Literal(value)));
134
+ }
135
+ /** 生成约束缩小候选空间,不能代替绑定/字段关联校验,更不能代替后端授权。 */
136
+ export function createSurfaceGenerationSpecSchema(catalog, policy) {
137
+ createSurfaceCatalogManifest(catalog);
138
+ const sources = [];
139
+ const scalarPointers = new Set(['/total']);
140
+ for (const [resource, rule] of Object.entries(policy.resources)) {
141
+ const limit = Math.min(rule.maxPageSize ?? SURFACE_LIMITS.maxPageSize, SURFACE_LIMITS.maxPageSize);
142
+ if (!Number.isSafeInteger(limit) || limit < 1)
143
+ throw new Error(`Invalid page limit for resource "${resource}"`);
144
+ const filters = Type.Union(surfaceFilterSchema.anyOf.map((branch) => Type.Object({
145
+ ...branch.properties,
146
+ field: literals(rule.filterFields ?? []),
147
+ }, { additionalProperties: false })));
148
+ sources.push(Type.Object({
149
+ ...surfaceListSourceSchema.properties,
150
+ resource: Type.Literal(resource),
151
+ // 显式页大小避免宿主默认值 10 超过小于 10 的策略上限。
152
+ pageSize: Type.Integer({ minimum: 1, maximum: limit }),
153
+ sorters: Type.Optional(Type.Array(Type.Object({
154
+ field: literals(rule.sortFields ?? []),
155
+ order: Type.Union([Type.Literal('asc'), Type.Literal('desc')]),
156
+ }, { additionalProperties: false }), { maxItems: (rule.sortFields?.length ?? 0) > 0 ? SURFACE_LIMITS.maxSorters : 0 })),
157
+ filters: Type.Optional(Type.Array(filters, { maxItems: (rule.filterFields?.length ?? 0) > 0 ? SURFACE_LIMITS.maxFilters : 0 })),
158
+ }, { additionalProperties: false }));
159
+ if (rule.allowGetOne === true) {
160
+ sources.push(Type.Object({ ...surfaceOneSourceSchema.properties, resource: Type.Literal(resource) }, { additionalProperties: false }));
161
+ for (const field of rule.readFields)
162
+ scalarPointers.add(`/${escapedJsonPointerToken(field)}`);
163
+ }
164
+ }
165
+ const widgets = catalog.widgets.map((widget) => {
166
+ const { binding: _binding, ...properties } = surfaceWidgetSchema.properties;
167
+ return Type.Object({
168
+ ...properties,
169
+ type: Type.Literal(widget.type),
170
+ props: widget.propsSchema,
171
+ ...(widget.dataKind === 'none' ? {} : {
172
+ binding: Type.Object({
173
+ sourceId: surfaceIdSchema,
174
+ pointer: widget.dataKind === 'items' ? Type.Literal('/items') : literals([...scalarPointers]),
175
+ }, { additionalProperties: false }),
176
+ }),
177
+ }, { additionalProperties: false, ...(widget.description ? { description: widget.description } : {}) });
178
+ });
179
+ return Type.Object({
180
+ ...surfaceSpecSchema.properties,
181
+ schemaVersion: Type.Literal(SURFACE_SCHEMA_VERSION),
182
+ catalogVersion: Type.Literal(catalog.version),
183
+ dataSources: Type.Array(sources.length ? Type.Union(sources) : Type.Never(), { maxItems: sources.length ? SURFACE_LIMITS.maxDataSources : 0 }),
184
+ widgets: Type.Array(widgets.length ? Type.Union(widgets) : Type.Never(), { maxItems: widgets.length ? SURFACE_LIMITS.maxWidgets : 0 }),
185
+ }, { additionalProperties: false });
186
+ }
187
+ export function createSurfaceAgentResponseSchema(catalog, policy) {
188
+ const proposal = Type.Object({
189
+ schemaVersion: Type.Literal(SURFACE_AGENT_RESPONSE_SCHEMA_VERSION),
190
+ action: Type.Literal('propose'),
191
+ summary: Type.Optional(Type.String({ minLength: 1, maxLength: 240 })),
192
+ spec: createSurfaceGenerationSpecSchema(catalog, policy),
193
+ }, { additionalProperties: false });
194
+ return surfaceSchemaToJson(Type.Union([proposal, surfaceCannotFulfillSchema]));
195
+ }
196
+ export const surfaceCannotFulfillSchema = Type.Object({
197
+ schemaVersion: Type.Literal(SURFACE_AGENT_RESPONSE_SCHEMA_VERSION),
198
+ action: Type.Literal('cannot-fulfill'),
199
+ reason: Type.Union([
200
+ Type.Literal('unsupported_request'), Type.Literal('insufficient_permissions'), Type.Literal('insufficient_context'),
201
+ ]),
202
+ message: Type.String({ minLength: 1, maxLength: 480 }),
203
+ }, { additionalProperties: false });
package/dist/agent.d.ts CHANGED
@@ -1,12 +1,18 @@
1
+ import { type Static } from '@sinclair/typebox';
2
+ import { SURFACE_AGENT_RESPONSE_SCHEMA_VERSION, SURFACE_AGENT_SCHEMA_VERSION, surfaceCannotFulfillSchema } from './agent-contract.js';
1
3
  import type { SurfaceCatalog, SurfacePolicy, SurfaceSpec, SurfaceValidationIssue } from './types.js';
2
- /** Wire version for model-produced, human-reviewable Surface proposals. */
3
- export declare const SURFACE_AGENT_SCHEMA_VERSION: "surface-agent/v1";
4
+ export { SURFACE_AGENT_SCHEMA_VERSION } from './agent-contract.js';
4
5
  export interface SurfaceAgentProposal {
5
6
  readonly schemaVersion: typeof SURFACE_AGENT_SCHEMA_VERSION;
6
7
  readonly action: 'propose';
7
8
  readonly summary?: string;
8
9
  readonly spec: SurfaceSpec;
9
10
  }
11
+ export interface SurfaceAgentProposalV2 extends Omit<SurfaceAgentProposal, 'schemaVersion'> {
12
+ readonly schemaVersion: typeof SURFACE_AGENT_RESPONSE_SCHEMA_VERSION;
13
+ }
14
+ export type SurfaceAgentCannotFulfill = Static<typeof surfaceCannotFulfillSchema>;
15
+ export type SurfaceAgentResponse = SurfaceAgentProposal | SurfaceAgentProposalV2 | SurfaceAgentCannotFulfill;
10
16
  export type SurfaceAgentValidationResult = {
11
17
  readonly ok: true;
12
18
  readonly value: SurfaceAgentProposal;
@@ -14,10 +20,35 @@ export type SurfaceAgentValidationResult = {
14
20
  readonly ok: false;
15
21
  readonly issues: readonly SurfaceValidationIssue[];
16
22
  };
17
- /**
18
- * Parse and fully validate an AI-generated proposal before a host previews it.
19
- * This function has no side effects and never queries a provider.
20
- */
23
+ export type SurfaceAgentResponseResult = {
24
+ readonly ok: true;
25
+ readonly value: SurfaceAgentResponse;
26
+ } | {
27
+ readonly ok: false;
28
+ readonly issues: readonly SurfaceValidationIssue[];
29
+ };
30
+ export interface SurfaceAgentMessage {
31
+ readonly role: 'system' | 'user';
32
+ readonly content: string;
33
+ }
34
+ /** 保留 v1 的函数签名、返回类型以及带说明文字的 fenced JSON 兼容行为。 */
21
35
  export declare function parseSurfaceAgentProposal(input: unknown, catalog: SurfaceCatalog, policy: SurfacePolicy): SurfaceAgentValidationResult;
22
- /** Build a model instruction that keeps generation inside the Surface contract. */
36
+ /** 结构化“无法完成”也是有效响应,但永远不是可渲染/可执行的提案。 */
37
+ export declare function parseSurfaceAgentResponse(input: unknown, catalog: SurfaceCatalog, policy: SurfacePolicy): SurfaceAgentResponseResult;
38
+ /** 兼容旧 v1 输出,同时补齐从组件契约派生的完整参数/结构 schema。 */
23
39
  export declare function buildSurfaceAgentPrompt(request: string, catalog: SurfaceCatalog, policy: SurfacePolicy): string;
40
+ /** 系统契约与用户需求分开传递;不绑定某个模型厂商或 CSS 编译器。 */
41
+ export declare function buildSurfaceAgentMessages(request: string, catalog: SurfaceCatalog, policy: SurfacePolicy): readonly SurfaceAgentMessage[];
42
+ export interface SurfaceAgentStream {
43
+ /** 接收文本,不解析、不渲染、不查询数据。 */
44
+ push(chunk: string): {
45
+ readonly ok: true;
46
+ readonly characters: number;
47
+ } | Extract<SurfaceAgentResponseResult, {
48
+ ok: false;
49
+ }>;
50
+ /** 仅结束后返回整体校验结果。重复调用返回同一终态。 */
51
+ finish(): SurfaceAgentResponseResult;
52
+ }
53
+ /** 有界传输缓冲,不冒充 OpenUI 增量渲染;半成品不进入运行时。 */
54
+ export declare function createSurfaceAgentStream(catalog: SurfaceCatalog, policy: SurfacePolicy): SurfaceAgentStream;