@svadmin/surface 0.8.19 → 0.10.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.
- package/README.md +76 -38
- package/STYLING.md +33 -0
- package/compatibility.json +40 -8
- package/dist/agent-contract.d.ts +37 -0
- package/dist/agent-contract.js +206 -0
- package/dist/agent.d.ts +38 -7
- package/dist/agent.js +98 -59
- package/dist/binding.d.ts +2 -0
- package/dist/binding.js +7 -1
- package/dist/builtin-definitions.d.ts +6 -0
- package/dist/builtin-definitions.js +40 -0
- package/dist/builtin-schemas.d.ts +25 -0
- package/dist/builtin-schemas.js +13 -0
- package/dist/business-data.d.ts +16 -0
- package/dist/business-data.js +42 -0
- package/dist/business-definitions.d.ts +28 -0
- package/dist/business-definitions.js +53 -0
- package/dist/business.d.ts +3 -0
- package/dist/business.js +17 -0
- package/dist/catalog.d.ts +4 -61
- package/dist/catalog.js +20 -44
- package/dist/components/ActivityFeedWidget.svelte +34 -0
- package/dist/components/ActivityFeedWidget.svelte.d.ts +4 -0
- package/dist/components/MetricWidget.svelte +13 -8
- package/dist/components/MetricWidget.svelte.d.ts +1 -0
- package/dist/components/ResourceDetailWidget.svelte +56 -0
- package/dist/components/ResourceDetailWidget.svelte.d.ts +4 -0
- package/dist/components/ResourceFormBody.svelte +97 -0
- package/dist/components/ResourceFormBody.svelte.d.ts +13 -0
- package/dist/components/ResourceFormWidget.svelte +19 -0
- package/dist/components/ResourceFormWidget.svelte.d.ts +4 -0
- package/dist/components/ResourceTableWidget.svelte +15 -12
- package/dist/components/ResourceTableWidget.svelte.d.ts +1 -0
- package/dist/components/SurfaceEditPreview.svelte +107 -0
- package/dist/components/SurfaceEditPreview.svelte.d.ts +20 -0
- package/dist/components/SurfaceRenderer.svelte +121 -163
- package/dist/components/SurfaceRenderer.svelte.d.ts +5 -0
- package/dist/components/SurfaceWorkflowProvider.svelte +22 -0
- package/dist/components/SurfaceWorkflowProvider.svelte.d.ts +17 -0
- package/dist/components/SvarGridWidget.svelte +47 -0
- package/dist/components/SvarGridWidget.svelte.d.ts +4 -0
- package/dist/components/SvarSurfaceProvider.svelte +12 -0
- package/dist/components/SvarSurfaceProvider.svelte.d.ts +11 -0
- package/dist/design-contract.d.ts +2 -0
- package/dist/design-contract.js +2 -0
- package/dist/edits.d.ts +57 -0
- package/dist/edits.js +166 -0
- package/dist/index.d.ts +8 -2
- package/dist/index.js +5 -1
- package/dist/interactive.d.ts +6 -0
- package/dist/interactive.js +15 -0
- package/dist/localization.d.ts +11 -1
- package/dist/localization.js +20 -0
- package/dist/openui.d.ts +64 -0
- package/dist/openui.js +168 -0
- package/dist/recipes.d.ts +20 -0
- package/dist/recipes.js +20 -0
- package/dist/schema.d.ts +108 -0
- package/dist/schema.js +73 -0
- package/dist/server-sqlite.d.ts +1 -0
- package/dist/server-sqlite.js +2 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.js +4 -0
- package/dist/source-cache.d.ts +30 -0
- package/dist/source-cache.js +135 -0
- package/dist/styles/editor.css +124 -0
- package/dist/styles/editor.d.ts +8 -0
- package/dist/styles/editor.js +9 -0
- package/dist/styles.css +43 -0
- package/dist/svar-catalog.d.ts +3 -0
- package/dist/svar-catalog.js +7 -0
- package/dist/svar-context.d.ts +9 -0
- package/dist/svar-context.js +1 -0
- package/dist/svar-schema.d.ts +21 -0
- package/dist/svar-schema.js +36 -0
- package/dist/svar.d.ts +4 -0
- package/dist/svar.js +3 -0
- package/dist/svelte.d.ts +4 -2
- package/dist/svelte.js +2 -1
- package/dist/types.d.ts +5 -1
- package/dist/validation.js +14 -108
- package/dist/wire.d.ts +13 -0
- package/dist/wire.js +30 -0
- package/dist/workflows/action-contracts.d.ts +7 -0
- package/dist/workflows/action-contracts.js +54 -0
- package/dist/workflows/catalog.d.ts +20 -0
- package/dist/workflows/catalog.js +50 -0
- package/dist/workflows/client.d.ts +45 -0
- package/dist/workflows/client.js +125 -0
- package/dist/workflows/context.d.ts +9 -0
- package/dist/workflows/context.js +5 -0
- package/dist/workflows/openui-guard.d.ts +19 -0
- package/dist/workflows/openui-guard.js +209 -0
- package/dist/workflows/service.d.ts +58 -0
- package/dist/workflows/service.js +296 -0
- package/dist/workflows/sqlite-store.d.ts +20 -0
- package/dist/workflows/sqlite-store.js +91 -0
- package/dist/workflows/types.d.ts +103 -0
- package/dist/workflows/types.js +8 -0
- package/dist/workflows.d.ts +5 -0
- package/dist/workflows.js +4 -0
- package/package.json +59 -8
package/README.md
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
# @svadmin/surface
|
|
2
2
|
|
|
3
|
-
`@svadmin/surface` renders a
|
|
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
|
-
|
|
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
|
|
|
9
|
+
The declared minimum combination is Core 0.53.0, UI 0.73.0, and Svelte
|
|
10
|
+
5.56.10, matching the published UI peer requirements. `compatibility.json`
|
|
11
|
+
lists verification targets, not proof of a successful run. Acceptance requires
|
|
12
|
+
the `minimum-supported` strict install and consumer checks in `pack:check` to
|
|
13
|
+
pass against registry artifacts; workspace tarballs do not replace that check.
|
|
14
|
+
|
|
9
15
|
```bash
|
|
10
16
|
bun add @svadmin/surface @svadmin/core @svadmin/ui @tanstack/svelte-query svelte @sinclair/typebox
|
|
11
17
|
```
|
|
12
18
|
|
|
13
|
-
Import protocol types and validation from the DOM-free root entry. Import rendering code from the Svelte subpath.
|
|
19
|
+
Import protocol types and validation from the DOM-free root entry. Import rendering code from the Svelte subpath. Hosts do not need CSS compiler plugins to consume the package's static component styles.
|
|
14
20
|
|
|
15
21
|
```ts
|
|
16
22
|
import { validateSurfaceSpec, type SurfacePolicy, type SurfaceSpec } from '@svadmin/surface';
|
|
@@ -27,10 +33,7 @@ import {
|
|
|
27
33
|
```svelte
|
|
28
34
|
<script lang="ts">
|
|
29
35
|
import type { SurfacePolicy, SurfaceSpec } from '@svadmin/surface';
|
|
30
|
-
import {
|
|
31
|
-
DEFAULT_SURFACE_CATALOG_VERSION,
|
|
32
|
-
SurfaceRenderer,
|
|
33
|
-
} from '@svadmin/surface/svelte';
|
|
36
|
+
import { DEFAULT_SURFACE_CATALOG_VERSION, SurfaceRenderer } from '@svadmin/surface/svelte';
|
|
34
37
|
|
|
35
38
|
const policy = {
|
|
36
39
|
resources: {
|
|
@@ -78,35 +81,69 @@ import {
|
|
|
78
81
|
|
|
79
82
|
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
83
|
|
|
81
|
-
The renderer
|
|
84
|
+
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
85
|
|
|
83
86
|
```svelte
|
|
84
|
-
<SurfaceRenderer
|
|
85
|
-
{
|
|
86
|
-
{policy}
|
|
87
|
-
locale="zh-CN"
|
|
88
|
-
messages={{ tableNoRecords: '没有符合条件的记录' }}
|
|
89
|
-
/>
|
|
87
|
+
<SurfaceRenderer {spec} {policy} locale="zh-CN"
|
|
88
|
+
messages={{ tableNoRecords: '没有符合条件的记录' }} />
|
|
90
89
|
```
|
|
91
90
|
|
|
92
|
-
##
|
|
91
|
+
## Incremental loading and session boundaries
|
|
92
|
+
|
|
93
|
+
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.
|
|
94
|
+
|
|
95
|
+
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.
|
|
96
|
+
|
|
97
|
+
## AI generation contracts
|
|
93
98
|
|
|
94
|
-
|
|
99
|
+
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
100
|
|
|
96
101
|
```ts
|
|
97
102
|
import {
|
|
98
|
-
|
|
99
|
-
|
|
103
|
+
buildSurfaceAgentMessages,
|
|
104
|
+
parseSurfaceAgentResponse,
|
|
105
|
+
selectSurfaceCatalog,
|
|
100
106
|
} from '@svadmin/surface';
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
107
|
+
import { defaultSurfaceCatalog } from '@svadmin/surface/svelte';
|
|
108
|
+
|
|
109
|
+
const catalog = selectSurfaceCatalog(defaultSurfaceCatalog, ['metric', 'resource-table']);
|
|
110
|
+
const messages = buildSurfaceAgentMessages('Generate an inventory dashboard', catalog, policy);
|
|
111
|
+
// Send messages through a trusted model adapter. Never expose model credentials.
|
|
112
|
+
const response = parseSurfaceAgentResponse(modelText, catalog, policy);
|
|
113
|
+
if (response.ok && response.value.action === 'propose') {
|
|
114
|
+
// Preview response.value.spec and require explicit approval before applying it.
|
|
115
|
+
} else if (response.ok) {
|
|
116
|
+
// Render response.value.message as text: this is a cannot-fulfill response.
|
|
106
117
|
}
|
|
107
118
|
```
|
|
108
119
|
|
|
109
|
-
|
|
120
|
+
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.
|
|
121
|
+
|
|
122
|
+
`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.
|
|
123
|
+
|
|
124
|
+
## Revisioned edits and explicit preview
|
|
125
|
+
|
|
126
|
+
`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.
|
|
127
|
+
|
|
128
|
+
The Svelte `SurfaceEditPreview` component accepts a controlled revision and untrusted proposal:
|
|
129
|
+
|
|
130
|
+
```svelte
|
|
131
|
+
<SurfaceEditPreview
|
|
132
|
+
{revision}
|
|
133
|
+
{proposal}
|
|
134
|
+
{streaming}
|
|
135
|
+
{policy}
|
|
136
|
+
{catalog}
|
|
137
|
+
{dataProvider}
|
|
138
|
+
scopeKey={trustedSessionRevision}
|
|
139
|
+
density="comfortable"
|
|
140
|
+
onApply={applyApprovedRevision}
|
|
141
|
+
/>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
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.
|
|
145
|
+
|
|
146
|
+
Preview controls use local finite class helpers and maintained static CSS. `@svadmin/surface/editor.css` remains available for explicit CSS collection. Density/button variants and complete-color semantic CSS variable overrides are preserved. Widgets use local semantic recipes to retain compatibility with older UI peers; no UI-generated helpers are copied during build. The separate `@svadmin/surface/styles.css` entry remains available and rendering components also import it automatically; see `STYLING.md`.
|
|
110
147
|
|
|
111
148
|
## Built-in catalog
|
|
112
149
|
|
|
@@ -117,18 +154,21 @@ The adapter is deliberately proposal-only. Persistence, revision history, audit
|
|
|
117
154
|
| `bar-chart` | `/items` | Zero-dependency SVG bar chart |
|
|
118
155
|
| `line-chart` | `/items` | Zero-dependency SVG line chart |
|
|
119
156
|
|
|
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`.
|
|
157
|
+
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
158
|
|
|
124
159
|
```ts
|
|
160
|
+
import { Type } from '@sinclair/typebox';
|
|
161
|
+
import { Value } from '@sinclair/typebox/value';
|
|
162
|
+
|
|
163
|
+
const statusProps = Type.Object({ statusField: Type.String() }, { additionalProperties: false });
|
|
125
164
|
const catalog = defineSurfaceCatalog({
|
|
126
165
|
version: 'acme/v1',
|
|
127
166
|
widgets: [{
|
|
128
167
|
type: 'status-list',
|
|
168
|
+
description: 'Display a policy-authorized status field from resource items.',
|
|
129
169
|
dataKind: 'items',
|
|
130
|
-
propsSchema:
|
|
131
|
-
getReferencedFields: (props) => [props.statusField
|
|
170
|
+
propsSchema: statusProps,
|
|
171
|
+
getReferencedFields: (props) => [Value.Decode(statusProps, props).statusField],
|
|
132
172
|
component: StatusList,
|
|
133
173
|
}],
|
|
134
174
|
});
|
|
@@ -136,18 +176,16 @@ const catalog = defineSurfaceCatalog({
|
|
|
136
176
|
|
|
137
177
|
## Security boundary
|
|
138
178
|
|
|
139
|
-
Surface specs are untrusted data. The renderer validates the whole document before sending any query. It rejects unknown components
|
|
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.
|
|
179
|
+
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
180
|
|
|
143
|
-
|
|
181
|
+
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
182
|
|
|
145
|
-
|
|
183
|
+
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
184
|
|
|
147
|
-
Supported Core/UI ranges and
|
|
185
|
+
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
186
|
|
|
149
|
-
##
|
|
187
|
+
## Current boundaries
|
|
150
188
|
|
|
151
|
-
|
|
189
|
+
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
190
|
|
|
153
|
-
中文指南见文档站的“声明式 Surface”。
|
|
191
|
+
See `docs/architecture/openui-surface-phase2.md` for the original feature scope and `docs/architecture/surface-integration-provenance.md` for historical integration evidence. 中文指南见文档站的“声明式 Surface”。
|
package/STYLING.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
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 helper 和静态 styles.css;design-contract 统一从 @svadmin/ui/design-contract 导入,要求 UI >=0.73.0 <0.74.0。不复制 UI 生成物,也不依赖样式编译器。渲染组件自动导入语义样式;原有 styles.css 子路径仍可显式导入。UI 基础样式仍由宿主通过 @svadmin/ui/app.css 加载。构建仅执行 svelte-package;styles:check 检查全部有限变体及静态 CSS 边界。
|
|
28
|
+
|
|
29
|
+
editor.css 与本地 styles/editor.ts 一起维护,保留 density、button variant、禁用/焦点状态和语义变量覆盖;editor.css 子路径不变。宿主升级时应同时升级 UI 与 Surface,并重新执行消费侧构建。
|
|
30
|
+
|
|
31
|
+
AI 只能选择公开枚举,不能指定 class/style、任意颜色、recipe 定义或可执行代码。字段权限、只读查询、版本匹配和宿主确认要求不因样式变体而改变。
|
|
32
|
+
|
|
33
|
+
此次仅替换样式基础设施。OpenUI 入口、catalog/schema 校验、workflow 授权与执行、提案预览及宿主确认逻辑保持不变;去除样式编译器不代表增加新的协议能力。
|
package/compatibility.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
|
-
"surface": "0.
|
|
2
|
+
"surface": "0.10.x",
|
|
3
3
|
"minimumSupported": {
|
|
4
|
-
"@svadmin/core": "0.
|
|
5
|
-
"@svadmin/ui": "0.
|
|
6
|
-
"svelte": "5.56.
|
|
4
|
+
"@svadmin/core": "0.53.0",
|
|
5
|
+
"@svadmin/ui": "0.73.0",
|
|
6
|
+
"svelte": "5.56.10"
|
|
7
7
|
},
|
|
8
8
|
"testedCombinations": [
|
|
9
9
|
{
|
|
10
10
|
"name": "minimum-supported",
|
|
11
|
-
"core": "0.
|
|
12
|
-
"ui": "0.
|
|
13
|
-
"svelte": "5.56.
|
|
11
|
+
"core": "0.53.0",
|
|
12
|
+
"ui": "0.73.0",
|
|
13
|
+
"svelte": "5.56.10"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
"name": "workspace-packed",
|
|
@@ -18,5 +18,37 @@
|
|
|
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
|
+
"./business": {
|
|
43
|
+
"status": "experimental",
|
|
44
|
+
"requiredUiCapabilities": [
|
|
45
|
+
"ActivityFeed.title",
|
|
46
|
+
"ActivityFeed.emptyLabel",
|
|
47
|
+
"ActivityFeed.countLabel"
|
|
48
|
+
],
|
|
49
|
+
"minimumPublishedUi": null,
|
|
50
|
+
"verification": "same-checkout business + interactive packed consumer; current Surface workflow reports",
|
|
51
|
+
"releaseGate": "Coordinate a tested UI release and verify the peer floor before publishing this new entry."
|
|
52
|
+
}
|
|
53
|
+
}
|
|
22
54
|
}
|
|
@@ -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' | 'record';
|
|
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,206 @@
|
|
|
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', 'record'].includes(widget.dataKind))
|
|
104
|
+
throw new Error('Invalid surface widget data kind');
|
|
105
|
+
if (widget.dataKind === 'record' && !widget.getReferencedFields)
|
|
106
|
+
throw new Error('Record widgets require an explicit field selector');
|
|
107
|
+
const propsSchema = surfaceSchemaToJson(widget.propsSchema);
|
|
108
|
+
if (!isClosedObject(propsSchema))
|
|
109
|
+
throw new Error(`Widget "${widget.type}" must use a closed object props schema`);
|
|
110
|
+
const examples = widget.examples?.map((props) => {
|
|
111
|
+
if (jsonValueIssue(props) || !Value.Check(widget.propsSchema, props)) {
|
|
112
|
+
throw new Error(`Invalid props example for widget "${widget.type}"`);
|
|
113
|
+
}
|
|
114
|
+
return JSON.parse(JSON.stringify(props));
|
|
115
|
+
});
|
|
116
|
+
return {
|
|
117
|
+
type: widget.type,
|
|
118
|
+
dataKind: widget.dataKind,
|
|
119
|
+
...(widget.description === undefined ? {} : { description: widget.description }),
|
|
120
|
+
propsSchema,
|
|
121
|
+
...(examples === undefined ? {} : { examples }),
|
|
122
|
+
};
|
|
123
|
+
});
|
|
124
|
+
const manifest = {
|
|
125
|
+
schemaVersion: SURFACE_CATALOG_SCHEMA_VERSION,
|
|
126
|
+
catalogVersion: catalog.version,
|
|
127
|
+
widgets,
|
|
128
|
+
};
|
|
129
|
+
if (jsonValueIssue(manifest) || JSON.stringify(manifest).length > SURFACE_AGENT_LIMITS.maxContractCharacters) {
|
|
130
|
+
throw new Error('Surface catalog manifest exceeds the JSON contract limits');
|
|
131
|
+
}
|
|
132
|
+
return manifest;
|
|
133
|
+
}
|
|
134
|
+
function literals(values) {
|
|
135
|
+
return values.length === 0 ? Type.Never() : Type.Union([...new Set(values)].map((value) => Type.Literal(value)));
|
|
136
|
+
}
|
|
137
|
+
/** 生成约束缩小候选空间,不能代替绑定/字段关联校验,更不能代替后端授权。 */
|
|
138
|
+
export function createSurfaceGenerationSpecSchema(catalog, policy) {
|
|
139
|
+
createSurfaceCatalogManifest(catalog);
|
|
140
|
+
const sources = [];
|
|
141
|
+
const scalarPointers = new Set(['/total']);
|
|
142
|
+
for (const [resource, rule] of Object.entries(policy.resources)) {
|
|
143
|
+
const limit = Math.min(rule.maxPageSize ?? SURFACE_LIMITS.maxPageSize, SURFACE_LIMITS.maxPageSize);
|
|
144
|
+
if (!Number.isSafeInteger(limit) || limit < 1)
|
|
145
|
+
throw new Error(`Invalid page limit for resource "${resource}"`);
|
|
146
|
+
const filters = Type.Union(surfaceFilterSchema.anyOf.map((branch) => Type.Object({
|
|
147
|
+
...branch.properties,
|
|
148
|
+
field: literals(rule.filterFields ?? []),
|
|
149
|
+
}, { additionalProperties: false })));
|
|
150
|
+
sources.push(Type.Object({
|
|
151
|
+
...surfaceListSourceSchema.properties,
|
|
152
|
+
resource: Type.Literal(resource),
|
|
153
|
+
// 显式页大小避免宿主默认值 10 超过小于 10 的策略上限。
|
|
154
|
+
pageSize: Type.Integer({ minimum: 1, maximum: limit }),
|
|
155
|
+
sorters: Type.Optional(Type.Array(Type.Object({
|
|
156
|
+
field: literals(rule.sortFields ?? []),
|
|
157
|
+
order: Type.Union([Type.Literal('asc'), Type.Literal('desc')]),
|
|
158
|
+
}, { additionalProperties: false }), { maxItems: (rule.sortFields?.length ?? 0) > 0 ? SURFACE_LIMITS.maxSorters : 0 })),
|
|
159
|
+
filters: Type.Optional(Type.Array(filters, { maxItems: (rule.filterFields?.length ?? 0) > 0 ? SURFACE_LIMITS.maxFilters : 0 })),
|
|
160
|
+
}, { additionalProperties: false }));
|
|
161
|
+
if (rule.allowGetOne === true) {
|
|
162
|
+
sources.push(Type.Object({ ...surfaceOneSourceSchema.properties, resource: Type.Literal(resource) }, { additionalProperties: false }));
|
|
163
|
+
for (const field of rule.readFields)
|
|
164
|
+
scalarPointers.add(`/${escapedJsonPointerToken(field)}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const widgets = catalog.widgets.map((widget) => {
|
|
168
|
+
const { binding: _binding, ...properties } = surfaceWidgetSchema.properties;
|
|
169
|
+
return Type.Object({
|
|
170
|
+
...properties,
|
|
171
|
+
type: Type.Literal(widget.type),
|
|
172
|
+
props: widget.propsSchema,
|
|
173
|
+
...(widget.dataKind === 'none' ? {} : {
|
|
174
|
+
binding: Type.Object({
|
|
175
|
+
sourceId: surfaceIdSchema,
|
|
176
|
+
pointer: widget.dataKind === 'items' ? Type.Literal('/items')
|
|
177
|
+
: widget.dataKind === 'record' ? Type.Literal('') : literals([...scalarPointers]),
|
|
178
|
+
}, { additionalProperties: false }),
|
|
179
|
+
}),
|
|
180
|
+
}, { additionalProperties: false, ...(widget.description ? { description: widget.description } : {}) });
|
|
181
|
+
});
|
|
182
|
+
return Type.Object({
|
|
183
|
+
...surfaceSpecSchema.properties,
|
|
184
|
+
schemaVersion: Type.Literal(SURFACE_SCHEMA_VERSION),
|
|
185
|
+
catalogVersion: Type.Literal(catalog.version),
|
|
186
|
+
dataSources: Type.Array(sources.length ? Type.Union(sources) : Type.Never(), { maxItems: sources.length ? SURFACE_LIMITS.maxDataSources : 0 }),
|
|
187
|
+
widgets: Type.Array(widgets.length ? Type.Union(widgets) : Type.Never(), { maxItems: widgets.length ? SURFACE_LIMITS.maxWidgets : 0 }),
|
|
188
|
+
}, { additionalProperties: false });
|
|
189
|
+
}
|
|
190
|
+
export function createSurfaceAgentResponseSchema(catalog, policy) {
|
|
191
|
+
const proposal = Type.Object({
|
|
192
|
+
schemaVersion: Type.Literal(SURFACE_AGENT_RESPONSE_SCHEMA_VERSION),
|
|
193
|
+
action: Type.Literal('propose'),
|
|
194
|
+
summary: Type.Optional(Type.String({ minLength: 1, maxLength: 240 })),
|
|
195
|
+
spec: createSurfaceGenerationSpecSchema(catalog, policy),
|
|
196
|
+
}, { additionalProperties: false });
|
|
197
|
+
return surfaceSchemaToJson(Type.Union([proposal, surfaceCannotFulfillSchema]));
|
|
198
|
+
}
|
|
199
|
+
export const surfaceCannotFulfillSchema = Type.Object({
|
|
200
|
+
schemaVersion: Type.Literal(SURFACE_AGENT_RESPONSE_SCHEMA_VERSION),
|
|
201
|
+
action: Type.Literal('cannot-fulfill'),
|
|
202
|
+
reason: Type.Union([
|
|
203
|
+
Type.Literal('unsupported_request'), Type.Literal('insufficient_permissions'), Type.Literal('insufficient_context'),
|
|
204
|
+
]),
|
|
205
|
+
message: Type.String({ minLength: 1, maxLength: 480 }),
|
|
206
|
+
}, { 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
|
-
|
|
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
|
-
|
|
19
|
-
|
|
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
|
-
/**
|
|
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;
|