@webskill/sdk 0.14.0 → 0.15.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/dist/agent.d.ts +3 -3
- package/dist/agent.js +2442 -3
- package/dist/{dist-Bfga1TmS.js → approval-BnLLCOG0.js} +235 -2932
- package/dist/browser.d.ts +106 -5
- package/dist/browser.js +364 -10
- package/dist/{openUiLibrary-BKXW7Iwx-DjvEnMlJ.js → dist-CTsxblSD.js} +496 -28
- package/dist/{echarts-De78wXqV.js → echarts-BE7oV_Dl.js} +1 -1
- package/dist/{env-8cY40DXB-CGnEVZby.js → env-Bj1MI2Ww.js} +1 -1
- package/dist/errors-BDZNpC13.js +22 -0
- package/dist/{eventTypes-FllCrX-Z-DNDeHWoG.js → eventTypes-Y07N8IAC.js} +14 -2
- package/dist/external-_ZRQe-V9.js +53 -0
- package/dist/governance.d.ts +15 -3
- package/dist/governance.js +86 -4
- package/dist/{index-DQwGvHAI.d.ts → index-CQYo4tcT.d.ts} +85 -6
- package/dist/{index-sd-gVKey.d.ts → index-CU2md8R1.d.ts} +26 -18
- package/dist/{index-CWoKOFBP.d.ts → index-Oc3H89TJ.d.ts} +159 -3
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1001 -5
- package/dist/kind-DxgS8LM-.js +77 -0
- package/dist/linkedDocument-xNXF-z8n.js +94 -0
- package/dist/llm-B7lLH0ZI.js +1767 -0
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +41 -4
- package/dist/memoryArtifactStore-D6dLeY55.js +48 -0
- package/dist/miniChart-owdCdaw-.js +533 -0
- package/dist/node.d.ts +3 -3
- package/dist/node.js +106 -9
- package/dist/openUiLibrary-CY_ADoe0.js +30 -0
- package/dist/openUiSpecLang-DuOCdw9G.js +1849 -0
- package/dist/pathSecurity-B1owvJAF.js +65 -0
- package/dist/processSandboxEntry.js +5 -1
- package/dist/renderResult-D9Q-Vu2x.js +143 -0
- package/dist/{rolldown-runtime-BOF7iYI8.js → rolldown-runtime-BHkdefai.js} +1 -2
- package/dist/sandboxWorkerEntry.js +5 -1
- package/dist/{dist-D5YhlCdY.js → skill-CAJMsLod.js} +44 -372
- package/dist/{skillVersionStore-D-qHk9ZE-C0OFDTQY.d.ts → skillVersionStore-B24Jjjry-C4zomhMZ.d.ts} +14 -2
- package/dist/surface-DVGiCmwq.js +145 -0
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +64 -3
- package/dist/{types-C3V6lAeO-BgeOvc1Y.d.ts → types-C3V6lAeO-BIf7UB2e.d.ts} +17 -1
- package/dist/types-TUydnxaj.js +78 -0
- package/dist/ui-react.d.ts +12 -5
- package/dist/ui-react.js +128548 -4729
- package/dist/ui-vue.d.ts +1 -1
- package/dist/ui-vue.js +11 -2
- package/dist/ui.d.ts +3 -3
- package/dist/ui.js +1254 -3
- package/dist/urlSafety-CiSuCJvX.js +65 -0
- package/dist/webSkillApi-DOOyz2G5.js +106 -0
- package/dist/{webskillLitCatalog-D_zCqeQF-swXsWoAe.js → webskillLitCatalog-DSqVFQjK.js} +11 -3
- package/package.json +1 -1
- package/dist/catalogComponents-BgAJN0p8-Cr55ouOg.js +0 -124384
- package/dist/client-BCM6Z3yq-qUQNkKrK.js +0 -7787
- package/dist/dist-BnqAkSS6.js +0 -2384
- package/dist/dist-CiaDIqkV.js +0 -3509
- package/dist/dist-DxyxmXPU-DGC-dpXf.js +0 -5621
- package/dist/memoryArtifactStore-52Zn9npI-BxtUkrgV.js +0 -86
- package/dist/stdio-CFMoANJJ-BxrTeXh7.js +0 -31
- package/dist/testing-Cm8MseLF.js +0 -142
- package/dist/types-WovEf4ED-CZSDiiBU.js +0 -6215
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
//#region ../runtime/src/tools/normalizeContent.ts
|
|
2
|
+
const MCP_CONTENT_RE = /^(text|json|image|resource|audio)$/;
|
|
3
|
+
/**
|
|
4
|
+
* 脚本返回值归一到 MCP content 格式:数组沿用(逐项归一),
|
|
5
|
+
* 字符串包装为 text,其他值序列化包装。Node/浏览器执行器共享。
|
|
6
|
+
* 产出只有文本型分片:脚本侧没有下发图像的通道(图像只来自页面取像)。
|
|
7
|
+
*/
|
|
8
|
+
function normalizeToolContent(value) {
|
|
9
|
+
if (Array.isArray(value)) return value.map((item) => {
|
|
10
|
+
if (typeof item === "object" && item !== null && typeof item.type === "string" && MCP_CONTENT_RE.test(item.type)) {
|
|
11
|
+
const { type, ...rest } = item;
|
|
12
|
+
if (type === "json") return {
|
|
13
|
+
type: "json",
|
|
14
|
+
data: rest["data"] ?? rest
|
|
15
|
+
};
|
|
16
|
+
return {
|
|
17
|
+
type: "text",
|
|
18
|
+
text: typeof rest["text"] === "string" ? rest["text"] : JSON.stringify(rest)
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
type: "text",
|
|
23
|
+
text: typeof item === "string" ? item : JSON.stringify(item)
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
if (typeof value === "string") return [{
|
|
27
|
+
type: "text",
|
|
28
|
+
text: value
|
|
29
|
+
}];
|
|
30
|
+
if (value === void 0 || value === null) return [{
|
|
31
|
+
type: "text",
|
|
32
|
+
text: ""
|
|
33
|
+
}];
|
|
34
|
+
return [{
|
|
35
|
+
type: "text",
|
|
36
|
+
text: typeof value === "object" ? JSON.stringify(value) : String(value)
|
|
37
|
+
}];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region ../runtime/src/engine/external.ts
|
|
42
|
+
/**
|
|
43
|
+
* Catalog 合并:同名本地优先;外部条目的 mcp:// 根 URI 保留,
|
|
44
|
+
* 调用方可凭 URI 强制选择外部技能(绕过本地优先)。
|
|
45
|
+
*/
|
|
46
|
+
function mergeCatalogEntries(localEntries, providerEntries) {
|
|
47
|
+
const byName = new Map(localEntries.map((e) => [e.name, e]));
|
|
48
|
+
for (const entry of providerEntries) if (!byName.has(entry.name)) byName.set(entry.name, entry);
|
|
49
|
+
return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
//#endregion
|
|
53
|
+
export { normalizeToolContent as n, mergeCatalogEntries as t };
|
package/dist/governance.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { S as UiBridge, U as FileSystemProvider, X as PageQuery, Y as Page, f as LlmMessage, ft as SkillDocument, gt as SkillManagerPort, l as LlmClient, ut as SkillCatalogEntry } from "./types-C3V6lAeO-
|
|
2
|
-
import { $
|
|
3
|
-
import { _ as SkillState, a as AuditLog, b as SkillVersionStore, c as CandidateFile, d as CandidateSkill, f as CandidateSource, g as SKILL_VERSION_PAGE_SIZE, h as CompositeApprovalPolicy, i as AuditEvent, l as CandidatePage, m as CandidateStore, n as ApprovalDecision, o as AuditQueryFilter, p as CandidateStatus, r as ApprovalPolicy, s as CANDIDATE_PAGE_SIZE, t as AlwaysHumanApprovalPolicy, u as CandidateRisk, v as SkillVersion, x as candidateToCatalogEntry, y as SkillVersionPage } from "./skillVersionStore-
|
|
1
|
+
import { S as UiBridge, U as FileSystemProvider, X as PageQuery, Y as Page, f as LlmMessage, ft as SkillDocument, gt as SkillManagerPort, l as LlmClient, ut as SkillCatalogEntry } from "./types-C3V6lAeO-BIf7UB2e.js";
|
|
2
|
+
import { $ as IntegrityVerdict, Wn as WebSkillRuntime, cn as SkillStateGuard, in as SkillOutcomeReporter, rn as SkillIntegrityGuard, zt as RuntimeRun } from "./index-Oc3H89TJ.js";
|
|
3
|
+
import { _ as SkillState, a as AuditLog, b as SkillVersionStore, c as CandidateFile, d as CandidateSkill, f as CandidateSource, g as SKILL_VERSION_PAGE_SIZE, h as CompositeApprovalPolicy, i as AuditEvent, l as CandidatePage, m as CandidateStore, n as ApprovalDecision, o as AuditQueryFilter, p as CandidateStatus, r as ApprovalPolicy, s as CANDIDATE_PAGE_SIZE, t as AlwaysHumanApprovalPolicy, u as CandidateRisk, v as SkillVersion, x as candidateToCatalogEntry, y as SkillVersionPage } from "./skillVersionStore-B24Jjjry-C4zomhMZ.js";
|
|
4
4
|
//#region ../governance/dist/index.d.ts
|
|
5
5
|
//#region src/candidate/candidateNormalizer.d.ts
|
|
6
6
|
/** 剥 markdown fence 与 <think> 块、截取首尾 {};非对象 → CANDIDATE_INVALID */
|
|
@@ -205,12 +205,24 @@ declare const AUDIT_EVENT_TYPES: {
|
|
|
205
205
|
readonly candidateSubmitted: "candidate.submitted";
|
|
206
206
|
readonly candidateApproved: "candidate.approved";
|
|
207
207
|
readonly candidateRejected: "candidate.rejected";
|
|
208
|
+
/** 候选记录被从审批队列里删除(仅 draft / pending-review / rejected 可删) */
|
|
209
|
+
readonly candidateRemoved: "candidate.removed";
|
|
208
210
|
readonly pagePerceived: "page.perceived";
|
|
209
211
|
readonly pageAction: "page.action";
|
|
212
|
+
/**
|
|
213
|
+
* 一次页面操作引发了下载,但 `sandbox.downloadedFiles` 关着,模型因此一无所知
|
|
214
|
+
* (0.15.0 分册 15 · FR-15.7)。载荷只有计数与原因,不含文件名 / 大小 / 类型。
|
|
215
|
+
*/
|
|
216
|
+
readonly pageDownloadUnreported: "page.download.unreported";
|
|
210
217
|
readonly documentRead: "document.read";
|
|
211
218
|
readonly documentSurfaceOpen: "document.surface.open";
|
|
212
219
|
/** 脚本按宿主声明的数据源取数(分册 16);被拒也记,否则反复试探看不见 */
|
|
213
220
|
readonly dataFetched: "data.fetch";
|
|
221
|
+
/**
|
|
222
|
+
* 技能脚本读用户本轮上传的文件(0.15.0 分册 17 · FR-17.7)。
|
|
223
|
+
* 载荷记文件名 / 类型 / 字节数与是否被拒,**不含文件内容**。
|
|
224
|
+
*/
|
|
225
|
+
readonly uploadFileRead: "upload.file.read";
|
|
214
226
|
};
|
|
215
227
|
type AuditEventType = (typeof AUDIT_EVENT_TYPES)[keyof typeof AUDIT_EVENT_TYPES];
|
|
216
228
|
/** 稳定展示序:筛选下拉与文档表格都从这里取,不各自维护一份顺序 */
|
package/dist/governance.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { n as messageOf, t as WebSkillError } from "./errors-BDZNpC13.js";
|
|
2
|
+
import { y as isValidSkillName } from "./skill-CAJMsLod.js";
|
|
3
|
+
import { a as atomicWriteText, t as assertSafePathSegment } from "./pathSecurity-B1owvJAF.js";
|
|
4
|
+
import { d as partsToText, p as textParts } from "./llm-B7lLH0ZI.js";
|
|
5
|
+
import { n as AUDIT_EVENT_TYPE_LIST, t as AUDIT_EVENT_TYPES } from "./eventTypes-Y07N8IAC.js";
|
|
4
6
|
|
|
5
|
-
//#region ../governance/
|
|
7
|
+
//#region ../governance/src/candidate/candidateNormalizer.ts
|
|
6
8
|
const invalid = (message, details) => {
|
|
7
9
|
throw new WebSkillError("CANDIDATE_INVALID", message, details);
|
|
8
10
|
};
|
|
@@ -96,11 +98,17 @@ function normalizeCandidate(input) {
|
|
|
96
98
|
updatedAt: now
|
|
97
99
|
};
|
|
98
100
|
}
|
|
101
|
+
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region ../governance/src/candidate/candidateValidator.ts
|
|
99
104
|
/** 候选校验:缺 SKILL.md / 非法扩展名 → CANDIDATE_INVALID */
|
|
100
105
|
function validateCandidate(candidate) {
|
|
101
106
|
if (!candidate.files.some((f) => f.kind === "skill-md")) throw new WebSkillError("CANDIDATE_INVALID", `Candidate "${candidate.name}" is missing SKILL.md`);
|
|
102
107
|
for (const file of candidate.files) if (file.kind === "script" && !/\.(ts|js)$/.test(file.path)) throw new WebSkillError("CANDIDATE_INVALID", `Candidate "${candidate.name}" has an unsupported script file: ${file.path}`);
|
|
103
108
|
}
|
|
109
|
+
|
|
110
|
+
//#endregion
|
|
111
|
+
//#region ../governance/src/pagination.ts
|
|
104
112
|
/**
|
|
105
113
|
* 治理侧各列表共用的游标切片,形状与会话消息(C1)完全一致:
|
|
106
114
|
* 无游标给**最新**一页,`nextCursor` 指向更早的历史,页内按时间升序。
|
|
@@ -125,6 +133,9 @@ function takeTailPage(all, options, defaultLimit, what) {
|
|
|
125
133
|
...start > 0 ? { nextCursor: String(start) } : {}
|
|
126
134
|
};
|
|
127
135
|
}
|
|
136
|
+
|
|
137
|
+
//#endregion
|
|
138
|
+
//#region ../governance/src/candidate/candidateStore.ts
|
|
128
139
|
const dirOf$1 = (root) => `${root}/.webskill/candidates`;
|
|
129
140
|
/** 候选列表的缺省页长。缺省属于实现,不属于调用方 */
|
|
130
141
|
const CANDIDATE_PAGE_SIZE = 50;
|
|
@@ -132,9 +143,11 @@ const CANDIDATE_PAGE_SIZE = 50;
|
|
|
132
143
|
var CandidateStore = class {
|
|
133
144
|
#root;
|
|
134
145
|
#fs;
|
|
146
|
+
#isSkillInstalled;
|
|
135
147
|
constructor(deps) {
|
|
136
148
|
this.#root = deps.root.replace(/\/+$/, "");
|
|
137
149
|
this.#fs = deps.fs;
|
|
150
|
+
this.#isSkillInstalled = deps.isSkillInstalled;
|
|
138
151
|
}
|
|
139
152
|
async save(candidate) {
|
|
140
153
|
validateCandidate(candidate);
|
|
@@ -175,6 +188,24 @@ var CandidateStore = class {
|
|
|
175
188
|
await this.save(candidate);
|
|
176
189
|
return candidate;
|
|
177
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* 把候选记录从队列里删掉。
|
|
193
|
+
*
|
|
194
|
+
* `approved` 恒拒删:它是「已批准但还没发布」,删掉等于让批准过的东西凭空消失;
|
|
195
|
+
* 要清理先 `reject`(留下理由)再删。
|
|
196
|
+
* `published` 是已安装技能的来源凭证,技能还装着时同样拒删;技能卸载后它只剩堆在队列里,
|
|
197
|
+
* 此时可删(0.15.0 分册 16 D-16-2)。未注入 `isSkillInstalled` 时判断不了装没装,
|
|
198
|
+
* 退化为「published 一律拒删」——宁可留着清不掉,也不能把还装着的技能的来源凭证删了。
|
|
199
|
+
*/
|
|
200
|
+
async remove(id) {
|
|
201
|
+
const candidate = await this.get(id);
|
|
202
|
+
if (candidate.status === "approved") throw new WebSkillError("GOVERNANCE_FAILED", `Candidate "${candidate.name}" cannot be removed from status "${candidate.status}"`);
|
|
203
|
+
if (candidate.status === "published" && await this.#skillStillInstalled(candidate.name)) throw new WebSkillError("GOVERNANCE_FAILED", `Candidate "${candidate.name}" is the provenance record of an installed skill and cannot be removed; uninstall the skill first`);
|
|
204
|
+
await this.#fs.remove(`${dirOf$1(this.#root)}/${id}.json`);
|
|
205
|
+
}
|
|
206
|
+
async #skillStillInstalled(name) {
|
|
207
|
+
return this.#isSkillInstalled === void 0 ? true : await this.#isSkillInstalled(name);
|
|
208
|
+
}
|
|
178
209
|
};
|
|
179
210
|
/** 硬门禁:仅 published 可转换为 Catalog 条目,否则 APPROVAL_REQUIRED */
|
|
180
211
|
function candidateToCatalogEntry(candidate) {
|
|
@@ -189,6 +220,9 @@ function candidateToCatalogEntry(candidate) {
|
|
|
189
220
|
hasAssets: candidate.files.some((f) => f.kind === "asset")
|
|
190
221
|
};
|
|
191
222
|
}
|
|
223
|
+
|
|
224
|
+
//#endregion
|
|
225
|
+
//#region ../governance/src/candidate/candidateSink.ts
|
|
192
226
|
/**
|
|
193
227
|
* 把 agent 生成的技能草稿接进既有的候选管线(设计 02 §5)。
|
|
194
228
|
*
|
|
@@ -232,6 +266,9 @@ function createCandidateSink(options) {
|
|
|
232
266
|
return { id: candidate.id };
|
|
233
267
|
} };
|
|
234
268
|
}
|
|
269
|
+
|
|
270
|
+
//#endregion
|
|
271
|
+
//#region ../governance/src/llmText.ts
|
|
235
272
|
/**
|
|
236
273
|
* 文本补全:优先走流式(慢速本地模型下非流式整响应缓冲会触发 fetch 头超时,
|
|
237
274
|
* SSE 首包秒到不受此限);无 stream 的客户端回退 complete。
|
|
@@ -246,6 +283,9 @@ async function completeText(llm, messages) {
|
|
|
246
283
|
}
|
|
247
284
|
return partsToText((await llm.complete({ messages })).content);
|
|
248
285
|
}
|
|
286
|
+
|
|
287
|
+
//#endregion
|
|
288
|
+
//#region ../governance/src/candidate/llmCandidateGenerator.ts
|
|
249
289
|
const GENERATION_PROMPT = (task, context) => [
|
|
250
290
|
"You generate a skill candidate as STRICT JSON only (no markdown, no explanation).",
|
|
251
291
|
"Schema: {\"name\": string, \"description\": string, \"risk\": \"low\"|\"medium\"|\"high\",",
|
|
@@ -293,6 +333,9 @@ var LlmCandidateGenerator = class {
|
|
|
293
333
|
return candidate;
|
|
294
334
|
}
|
|
295
335
|
};
|
|
336
|
+
|
|
337
|
+
//#endregion
|
|
338
|
+
//#region ../governance/src/approval/policies.ts
|
|
296
339
|
/** 默认策略:任何候选都必须人工审批 */
|
|
297
340
|
var AlwaysHumanApprovalPolicy = class {
|
|
298
341
|
evaluate(candidate) {
|
|
@@ -318,6 +361,9 @@ var CompositeApprovalPolicy = class {
|
|
|
318
361
|
return this.#fallback.evaluate(candidate);
|
|
319
362
|
}
|
|
320
363
|
};
|
|
364
|
+
|
|
365
|
+
//#endregion
|
|
366
|
+
//#region ../governance/src/audit/fsAuditLog.ts
|
|
321
367
|
const fileOf$1 = (root) => `${root}/.webskill/audit.jsonl`;
|
|
322
368
|
/** 审计查询的缺省页长。缺省属于实现,不属于调用方 */
|
|
323
369
|
const AUDIT_PAGE_SIZE = 100;
|
|
@@ -572,6 +618,9 @@ var FsAuditLog = class {
|
|
|
572
618
|
};
|
|
573
619
|
}
|
|
574
620
|
};
|
|
621
|
+
|
|
622
|
+
//#endregion
|
|
623
|
+
//#region ../governance/src/versioning/skillVersionStore.ts
|
|
575
624
|
const dirOf = (root, skillName) => {
|
|
576
625
|
assertSafePathSegment(skillName, "skill name");
|
|
577
626
|
return `${root}/.webskill/versions/${skillName}`;
|
|
@@ -669,6 +718,9 @@ var SkillVersionStore = class {
|
|
|
669
718
|
});
|
|
670
719
|
}
|
|
671
720
|
};
|
|
721
|
+
|
|
722
|
+
//#endregion
|
|
723
|
+
//#region ../governance/src/repair/failureAnalyzer.ts
|
|
672
724
|
const ERROR_CAUSES = {
|
|
673
725
|
TOOL_NOT_FOUND: "The skill script or tool is missing",
|
|
674
726
|
TOOL_EXECUTION_FAILED: "The script failed at runtime",
|
|
@@ -720,6 +772,9 @@ var FailureAnalyzer = class {
|
|
|
720
772
|
};
|
|
721
773
|
}
|
|
722
774
|
};
|
|
775
|
+
|
|
776
|
+
//#endregion
|
|
777
|
+
//#region ../governance/src/repair/repairPlanner.ts
|
|
723
778
|
/**
|
|
724
779
|
* 修订选项规划:patch(按诊断给具体文件变更)/ rollback(有旧版本时)/ quarantine。
|
|
725
780
|
* 注意:任何 option 的 apply 都必须经 ApprovalWorkflow 审批后执行;rollback 选项(targetVersionId)经 ApprovalWorkflow.applyRollback 真实恢复文件。
|
|
@@ -748,6 +803,9 @@ var RepairPlanner = class {
|
|
|
748
803
|
return options;
|
|
749
804
|
}
|
|
750
805
|
};
|
|
806
|
+
|
|
807
|
+
//#endregion
|
|
808
|
+
//#region ../governance/src/state/skillStatePolicy.ts
|
|
751
809
|
const fileOf = (root) => `${root}/.webskill/states.json`;
|
|
752
810
|
/**
|
|
753
811
|
* 用户策略主动拒绝的错误码(FR-12.4):这是配置生效的证据,不是技能有问题,不计入隔离阈值。
|
|
@@ -1013,6 +1071,9 @@ var SkillStatePolicy = class {
|
|
|
1013
1071
|
});
|
|
1014
1072
|
}
|
|
1015
1073
|
};
|
|
1074
|
+
|
|
1075
|
+
//#endregion
|
|
1076
|
+
//#region ../governance/src/evaluation/evaluationRunner.ts
|
|
1016
1077
|
function matchExpected(expected, output, run) {
|
|
1017
1078
|
if (expected === void 0) return run.status === "completed";
|
|
1018
1079
|
if (typeof expected === "string") return output.includes(expected);
|
|
@@ -1067,6 +1128,9 @@ var EvaluationRunner = class {
|
|
|
1067
1128
|
};
|
|
1068
1129
|
}
|
|
1069
1130
|
};
|
|
1131
|
+
|
|
1132
|
+
//#endregion
|
|
1133
|
+
//#region ../governance/src/evaluation/testSuggestion.ts
|
|
1070
1134
|
/** 失败 trace → 回归评估任务建议(prompt 复现 + expected 错误模式) */
|
|
1071
1135
|
function suggestFromFailedRun(run) {
|
|
1072
1136
|
const errorPatterns = run.trace.filter((e) => e.type === "tool.failed" || e.type === "run.failed").map((e) => String(e.data?.["code"] ?? e.message ?? "")).filter(Boolean);
|
|
@@ -1084,6 +1148,9 @@ function suggestFromFailedRun(run) {
|
|
|
1084
1148
|
}
|
|
1085
1149
|
};
|
|
1086
1150
|
}
|
|
1151
|
+
|
|
1152
|
+
//#endregion
|
|
1153
|
+
//#region ../governance/src/scoring/skillScorer.ts
|
|
1087
1154
|
const SCORING_WEIGHTS = {
|
|
1088
1155
|
success: .5,
|
|
1089
1156
|
usage: .2,
|
|
@@ -1116,6 +1183,9 @@ var SkillScorer = class {
|
|
|
1116
1183
|
};
|
|
1117
1184
|
}
|
|
1118
1185
|
};
|
|
1186
|
+
|
|
1187
|
+
//#endregion
|
|
1188
|
+
//#region ../governance/src/scoring/similarity.ts
|
|
1119
1189
|
const tokenize = (text) => new Set(text.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length > 1));
|
|
1120
1190
|
function jaccardSimilarity(a, b) {
|
|
1121
1191
|
const sa = tokenize(a);
|
|
@@ -1136,6 +1206,9 @@ var SimilarityDetector = class {
|
|
|
1136
1206
|
for (const skill of existing) if (jaccardSimilarity(description, skill.description) >= this.#threshold) return skill.name;
|
|
1137
1207
|
}
|
|
1138
1208
|
};
|
|
1209
|
+
|
|
1210
|
+
//#endregion
|
|
1211
|
+
//#region ../governance/src/scoring/dependencyGraph.ts
|
|
1139
1212
|
var DependencyGraph = class DependencyGraph {
|
|
1140
1213
|
#edges = /* @__PURE__ */ new Map();
|
|
1141
1214
|
addDependency(from, to) {
|
|
@@ -1163,6 +1236,9 @@ var DependencyGraph = class DependencyGraph {
|
|
|
1163
1236
|
return out.sort();
|
|
1164
1237
|
}
|
|
1165
1238
|
};
|
|
1239
|
+
|
|
1240
|
+
//#endregion
|
|
1241
|
+
//#region ../governance/src/documents/documentSource.ts
|
|
1166
1242
|
/** 环境无关 sha256(WebCrypto;Node ≥17 与浏览器均有 globalThis.crypto.subtle) */
|
|
1167
1243
|
async function sha256Hex(text) {
|
|
1168
1244
|
const digest = await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(text));
|
|
@@ -1177,6 +1253,9 @@ async function readDocument(fs, path) {
|
|
|
1177
1253
|
hash: await sha256Hex(content)
|
|
1178
1254
|
};
|
|
1179
1255
|
}
|
|
1256
|
+
|
|
1257
|
+
//#endregion
|
|
1258
|
+
//#region ../governance/src/documents/documentSkillExtractor.ts
|
|
1180
1259
|
const EXTRACT_PROMPT = (doc, nameHint) => [
|
|
1181
1260
|
"Extract an executable skill from the following document as STRICT JSON only.",
|
|
1182
1261
|
"Schema: {\"name\": string, \"description\": string, \"risk\": \"low\"|\"medium\"|\"high\",",
|
|
@@ -1245,6 +1324,9 @@ var DocumentSkillExtractor = class {
|
|
|
1245
1324
|
};
|
|
1246
1325
|
}
|
|
1247
1326
|
};
|
|
1327
|
+
|
|
1328
|
+
//#endregion
|
|
1329
|
+
//#region ../governance/src/missHook.ts
|
|
1248
1330
|
/**
|
|
1249
1331
|
* runtime-miss 现成适配(opt-in):run 未激活技能时生成 draft 候选入库待审。
|
|
1250
1332
|
* 返回的 hook 失败会向上抛(由 runtime 降级为 warning)。
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { I as ChatAttachmentKind,
|
|
2
|
-
import {
|
|
1
|
+
import { I as ChatAttachmentKind, Nt as WebSkillErrorCode, S as UiBridge, Z as RemoteUrlPolicy, a as InteractionOrigin, c as InteractionResponse, s as InteractionRequest } from "./types-C3V6lAeO-BIf7UB2e.js";
|
|
2
|
+
import { Kn as XlsxTextExtractor, P as DocxTextExtractor, bn as ToolStepReader, j as DataSourceInfo, z as ExternalToolSource } from "./index-Oc3H89TJ.js";
|
|
3
3
|
//#region ../agent/dist/index.d.ts
|
|
4
4
|
//#region src/todo/types.d.ts
|
|
5
5
|
/** 待办条目状态:未开始 / 进行中 / 已完成(FR-3.1) */
|
|
@@ -523,10 +523,12 @@ interface PerceptionRecord {
|
|
|
523
523
|
/** 读到的顶层节点数;用于「它读的比我预期的多」这类判断 */
|
|
524
524
|
nodeCount: number;
|
|
525
525
|
/**
|
|
526
|
-
*
|
|
526
|
+
* 整份快照的节点总数(含各层);**每次感知都在**(0.15.0 分册 14 · D-14-2)。
|
|
527
|
+
* 早先它只在分段时出现,于是「没分段」的那些次感知无法回答「模型到底看到了多少」。
|
|
528
|
+
* 与 `segmentPerception()` 的 `nodesTotal` 同源同值(FR-14.2)。
|
|
527
529
|
* `nodeCount` 的语义不动——改它会让所有既有断言与 console 展示静默变义。
|
|
528
530
|
*/
|
|
529
|
-
nodesTotal
|
|
531
|
+
nodesTotal: number;
|
|
530
532
|
/** 切成了几段;只在分段发生时存在 */
|
|
531
533
|
segments?: number;
|
|
532
534
|
/** 本次直接回喂给模型的那一段承载了多少个节点;只在分段发生时存在 */
|
|
@@ -923,6 +925,61 @@ declare class DataSourceCandidatePolicy {
|
|
|
923
925
|
restore(scope: string): Promise<void>;
|
|
924
926
|
}
|
|
925
927
|
//#endregion
|
|
928
|
+
//#region src/pageAction/downloadSignal.d.ts
|
|
929
|
+
/**
|
|
930
|
+
* 操作触发的下载:完成信号(0.15.0 分册 15)。
|
|
931
|
+
*
|
|
932
|
+
* 这一层不含任何浏览器概念。SDK 只定义「窗口什么时候开、什么时候关、结果长什么样」,
|
|
933
|
+
* 「怎么知道下载起来了」全在端口之后——与分册 20 的分工一致。
|
|
934
|
+
*/
|
|
935
|
+
/**
|
|
936
|
+
* 一次页面操作的下载观察窗口。**只在 `act()` 的一次调用里存在**:
|
|
937
|
+
* 返回之后这个对象就不可达,因此窗口之外没有任何代码路径能问到下载(FR-15.2)。
|
|
938
|
+
* @experimental
|
|
939
|
+
*/
|
|
940
|
+
interface ActionDownloadWindow {
|
|
941
|
+
/**
|
|
942
|
+
* 结算并**关闭**窗口,返回窗口内完成的下载次数(没有即 0)。
|
|
943
|
+
*
|
|
944
|
+
* 到预算上限就返回当时已经数到的次数,不丢弃、不抛错——
|
|
945
|
+
* 等待超时不是失败,操作本身的结果照常返回(FR-15.3)。
|
|
946
|
+
*/
|
|
947
|
+
settle(budget: {
|
|
948
|
+
timeoutMs: number;
|
|
949
|
+
}): Promise<number>;
|
|
950
|
+
}
|
|
951
|
+
/**
|
|
952
|
+
* 下载观察窗口的宿主实现(FR-15.2)。**不注入即整条通路不存在**:
|
|
953
|
+
* 不开窗、不留痕,页面操作的结果与本版前逐字一致。
|
|
954
|
+
*
|
|
955
|
+
* 之所以是 `open` / `settle` 一对而不是一个 `waitForDownloads(ms)`:
|
|
956
|
+
* 后者只说了「等多久」,没说「从什么时候开始算」,宿主可以实现成
|
|
957
|
+
* 「返回最近 N 秒内的下载」——那就把用户在别处的下载也算了进来(D-15-4 否掉的 (a))。
|
|
958
|
+
* 窗口的两端由 SDK 说了算,宿主实现里没有自己决定起点的余地。
|
|
959
|
+
* @experimental
|
|
960
|
+
*/
|
|
961
|
+
interface ActionDownloadWatcher {
|
|
962
|
+
/**
|
|
963
|
+
* 在页面操作**执行前**打开窗口。
|
|
964
|
+
* 下载可能在点击返回之前就已经落盘,先执行再开窗会漏掉最快的那一类。
|
|
965
|
+
*/
|
|
966
|
+
open(context: {
|
|
967
|
+
runId?: string;
|
|
968
|
+
}): ActionDownloadWindow | Promise<ActionDownloadWindow>;
|
|
969
|
+
}
|
|
970
|
+
/** 宿主不注入等待上限时的缺省;够覆盖「点击 → 浏览器起下载」的常见延迟 */
|
|
971
|
+
declare const DOWNLOAD_WAIT_DEFAULT_MS = 1500;
|
|
972
|
+
/** 地板:注入 0 会把本能力静默变成永不触发,那是更坏的失败形态 */
|
|
973
|
+
declare const DOWNLOAD_WAIT_MIN_MS = 250;
|
|
974
|
+
/** 天花板:宿主写错一个 0 不该让一轮对话挂十分钟 */
|
|
975
|
+
declare const DOWNLOAD_WAIT_MAX_MS = 10000;
|
|
976
|
+
/**
|
|
977
|
+
* 把宿主注入的等待上限夹进地板与天花板(FR-15.3)。
|
|
978
|
+
* 不注入或注入了非有限数即取缺省——不信任宿主传进来的数是这里存在的全部理由。
|
|
979
|
+
* @experimental
|
|
980
|
+
*/
|
|
981
|
+
declare function clampDownloadWaitMs(ms: number | undefined): number;
|
|
982
|
+
//#endregion
|
|
926
983
|
//#region src/pageAction/types.d.ts
|
|
927
984
|
/**
|
|
928
985
|
* 页面操作的策略层类型(需求 23)。
|
|
@@ -1023,6 +1080,14 @@ interface PageActionOutcome {
|
|
|
1023
1080
|
navigated?: boolean;
|
|
1024
1081
|
/** 变更后的地址;仅 `navigated` 时带 */
|
|
1025
1082
|
documentUrl?: string;
|
|
1083
|
+
/**
|
|
1084
|
+
* 本次操作引发的下载**完成**次数(0.15.0 分册 15 · FR-15.1)。
|
|
1085
|
+
* 没有下载时**不带**该字段,与 `navigated` 同口径。
|
|
1086
|
+
*
|
|
1087
|
+
* 只有次数:文件名、大小、类型一律不在这里(D-15-3)——带上就等于开了一条
|
|
1088
|
+
* 绕过 `list_downloaded_files` 确认卡的披露路径。要读内容仍得逐次点头。
|
|
1089
|
+
*/
|
|
1090
|
+
downloadCount?: number;
|
|
1026
1091
|
/** 失败原因(英文) */
|
|
1027
1092
|
reason?: string;
|
|
1028
1093
|
}
|
|
@@ -1118,6 +1183,18 @@ interface PageActionPolicyOptions {
|
|
|
1118
1183
|
* 前者是宿主装配时写死的静态配置,后者是用户运行期一次一次攒出来的。
|
|
1119
1184
|
*/
|
|
1120
1185
|
consent?: PageActionConsent;
|
|
1186
|
+
/**
|
|
1187
|
+
* 操作触发的下载观察窗口(0.15.0 分册 15)。**不注入即整条通路不存在**:
|
|
1188
|
+
* 不开窗、不留痕,页面操作的结果与本版前逐字一致(AC-15.5 / AC-15.12)。
|
|
1189
|
+
*/
|
|
1190
|
+
downloadWatcher?: ActionDownloadWatcher;
|
|
1191
|
+
/**
|
|
1192
|
+
* 下载信号的能力开关(`sandbox.downloadedFiles`,D-15-5)。缺省即**关闭**:
|
|
1193
|
+
* `downloadCount` 永不出现。关着时窗口照开,结果只进留痕(D-15-6 / FR-15.7)。
|
|
1194
|
+
*/
|
|
1195
|
+
downloadSignalEnabled?(): boolean;
|
|
1196
|
+
/** 宿主注入的等待上限(毫秒);SDK 夹在地板与天花板之间(FR-15.3)。模型无法影响它 */
|
|
1197
|
+
downloadWaitMs?(): number | undefined;
|
|
1121
1198
|
now?(): string;
|
|
1122
1199
|
}
|
|
1123
1200
|
/**
|
|
@@ -1149,7 +1226,9 @@ declare class PageActionPolicy {
|
|
|
1149
1226
|
* 只留句柄等于留了一个换次运行就失效的引用;角色与可访问名才是可重放的那部分。
|
|
1150
1227
|
*/
|
|
1151
1228
|
rememberedTarget(ref: string): PageActionTarget | undefined;
|
|
1152
|
-
act(request: PageActionRequest
|
|
1229
|
+
act(request: PageActionRequest, context?: {
|
|
1230
|
+
runId?: string;
|
|
1231
|
+
}): Promise<PageActionOutcome>;
|
|
1153
1232
|
}
|
|
1154
1233
|
//#endregion
|
|
1155
1234
|
//#region src/pageAction/toolSource.d.ts
|
|
@@ -1321,4 +1400,4 @@ interface DownloadedFileToolSourceOptions {
|
|
|
1321
1400
|
*/
|
|
1322
1401
|
declare function createDownloadedFileToolSource(options: DownloadedFileToolSourceOptions): ExternalToolSource;
|
|
1323
1402
|
//#endregion
|
|
1324
|
-
export {
|
|
1403
|
+
export { PERCEPTION_PAGING_DEFAULTS as $, createHttpDataSourceTransport as $t, DownloadedFileAction as A, SKILL_GENERATION_SYSTEM_PROMPT as At, FrameNote as B, SubAgentRunInput as Bt, DataSourceTransport as C, PerceptionCaptureOptions as Ct, DelegationRequest as D, PerceptionScope as Dt, DelegationOrchestratorOptions as E, PerceptionResult as Et, DownloadedFilePolicyOptions as F, SkillGenerationToolSourceOptions as Ft, ImageCaptureBudget as G, TodoList as Gt, GENERATE_SKILL_TOOL as H, TODO_SYSTEM_PROMPT as Ht, DownloadedFileReadResult as I, SkillGenerator as It, NestedFrameRef as J, TodoStore as Jt, LIST_DOWNLOADED_FILES_TOOL as K, TodoListener as Kt, DownloadedFileReader as L, SkillGeneratorOptions as Lt, DownloadedFileEntry as M, SkillGenerationMessages as Mt, DownloadedFileListing as N, SkillGenerationOutcome as Nt, DelegationResult as O, PerceptionScopeInput as Ot, DownloadedFilePolicy as P, SkillGenerationPolicy as Pt, PERCEIVE_PAGE_TOOL as Q, createDownloadedFileToolSource as Qt, DownloadedFileRecord as R, SkillTraceEvidence as Rt, DataSourceRecord as S, PerceptionAuditSink as St, DelegationOrchestrator as T, PerceptionRecord as Tt, GeneratedSkillDraft as U, TodoEvent as Ut, FrameScope as V, SubAgentRunner as Vt, HttpDataSourceOptions as W, TodoItem as Wt, PAGE_ACTION_SYSTEM_PROMPT as X, clampDownloadWaitMs as Xt, PAGE_ACTION_KINDS as Y, TodoToolSourceOptions as Yt, PAGE_ACTION_TOOL as Z, createDelegationToolSource as Zt, DataSourceDef as _, PagePerceptionReader as _t, DELEGATE_TASK_TOOL as a, frameSteps as an, PageActionPolicy as at, DataSourcePolicyOptions as b, PerceivedImage as bt, DOWNLOAD_WAIT_MAX_MS as c, withDelegationOrigin as cn, PageActionRequest as ct, DataSourceCandidate as d, PageActionTarget as dt, createPageActionToolSource as en, PERCEPTION_SYSTEM_PROMPT as et, DataSourceCandidateAuditSink as f, PageActionToolSourceOptions as ft, DataSourceCandidateStore as g, PagePerceptionPolicyOptions as gt, DataSourceCandidateRecord as h, PagePerceptionPolicy as ht, ConsentUi as i, frameLabel as in, PageActionOutcome as it, DownloadedFileConsent as j, SkillCandidateSink as jt, DelegationToolSourceOptions as k, READ_DOWNLOADED_FILE_TOOL as kt, DOWNLOAD_WAIT_MIN_MS as l, PageActionScope as lt, DataSourceCandidatePolicyOptions as m, PageAuditSink as mt, ActionDownloadWindow as n, createSkillGenerationToolSource as nn, PageActionExecutor as nt, DELEGATION_SYSTEM_PROMPT as o, toActionFrameScopes as on, PageActionPolicyOptions as ot, DataSourceCandidatePolicy as p, PageActionUi as pt, MANAGE_TODO_TOOL as q, TodoStatus as qt, ActionFrameScope as r, createTodoToolSource as rn, PageActionKind as rt, DOWNLOAD_WAIT_DEFAULT_MS as s, toFrameScopes as sn, PageActionRecord as st, ActionDownloadWatcher as t, createPagePerceptionToolSource as tn, PageActionConsent as tt, DataSourceAuditSink as u, PageActionScopeInput as ut, DataSourceKind as v, PagePerceptionToolSourceOptions as vt, DelegationBudget as w, PerceptionPagingBudget as wt, DataSourceProvenance as x, PerceivedNode as xt, DataSourcePolicy as y, ParentBudget as yt, DownloadedFileToolSourceOptions as z, SkillTraceEvidenceStep as zt };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as UiSpecActionCapability, D as UiSpecSnapshot,
|
|
2
|
-
import {
|
|
1
|
+
import { C as UiSpecActionCapability, D as UiSpecSnapshot, K as JsonSchema, Ot as UiSpecNode, S as UiBridge, b as RenderResultRequest, c as InteractionResponse, r as ChartSpec, s as InteractionRequest, y as RenderBlock } from "./types-C3V6lAeO-BIf7UB2e.js";
|
|
2
|
+
import { z as ExternalToolSource } from "./index-Oc3H89TJ.js";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { ComponentType, ReactNode } from "react";
|
|
5
5
|
//#region ../ui/dist/index.d.ts
|
|
@@ -80,6 +80,8 @@ interface SurfaceFormTexts {
|
|
|
80
80
|
suggested: string;
|
|
81
81
|
/** 采纳建议值的按钮 */
|
|
82
82
|
useSuggestion: string;
|
|
83
|
+
/** `OpenDocument` 按钮的缺省文案(0.15.0 分册 13;技能的 `props.label` 优先) */
|
|
84
|
+
openDocument: string;
|
|
83
85
|
}
|
|
84
86
|
/** 可复用的部分取自 DEFAULT_INTERACTION_TEXTS,不另抄一份(AC-G10) */
|
|
85
87
|
declare const DEFAULT_SURFACE_FORM_TEXTS: SurfaceFormTexts;
|
|
@@ -447,39 +449,45 @@ declare const UI_CATALOG_PROMPT_BUDGET_BYTES: number;
|
|
|
447
449
|
* **超阈值的处置是砍组件或收窄枚举取值,不是抬高这里的数字。**
|
|
448
450
|
*/
|
|
449
451
|
/**
|
|
450
|
-
*
|
|
451
|
-
* 已有的 `Field.type`,分册 23 不碰 catalog),故在此切到 `'final'`:
|
|
452
|
+
* 预算阶段。0.11.0 分册 12 是那一版最后一处 catalog 增量,故切到 `'final'`:
|
|
452
453
|
* 阈值收紧到实测终态 + 余量,且余量小于一个平均组件的成本
|
|
453
454
|
* ——余量大于一个组件,等于默许下一版无声塞进一个。
|
|
455
|
+
* 0.15.0 分册 13 新增 `OpenDocument` 后仍是 `'final'`,只是实测基线换了一份。
|
|
454
456
|
*/
|
|
455
457
|
declare const CATALOG_BUDGET_STAGE: 'entry' | 'final';
|
|
456
458
|
/**
|
|
457
459
|
* 阈值 = **已落地实测** + 余量,余量须小于一个平均组件的成本。
|
|
458
460
|
*
|
|
459
|
-
* 2026-08-
|
|
460
|
-
* 平均组件成本 prompt
|
|
461
|
-
* 当前余量 prompt
|
|
461
|
+
* 2026-08-26 实测终态(0.15.0 分册 13 落地后):prompt 13 372 / schema 22 184,31 个组件。
|
|
462
|
+
* 平均组件成本 prompt 431 / schema 715。
|
|
463
|
+
* 当前余量 prompt 278 / schema 316,均小于一个平均组件——再加一个组件必红。
|
|
462
464
|
*
|
|
463
|
-
* ⚠️
|
|
464
|
-
*
|
|
465
|
+
* ⚠️ **这两个数字被上调过三次**,三次都由需求方裁决并改写了需求文档,
|
|
466
|
+
* 不是实现阶段自行放宽:
|
|
465
467
|
*
|
|
466
|
-
* 1. 11 200 → 12 200 / 20 500 → 21 200
|
|
468
|
+
* 1. 11 200 → 12 200 / 20 500 → 21 200(0.11.0 分册 29 §2 第 7 条):分册 13 组件描述由短改长。
|
|
467
469
|
* `example` 是既有护栏的硬要求(`catalog.test.ts` 与 `catalogMatrix.test.tsx`
|
|
468
470
|
* 逐个组件校验并四档渲染),靠省掉示例腾出的空间收不回来。
|
|
469
|
-
* 2. 12 200 → 13 000 / 21 200 → 21 800
|
|
471
|
+
* 2. 12 200 → 13 000 / 21 200 → 21 800(0.11.0 分册 29 §2.2):分册 12 的 `Split` 实测 490 + 694,
|
|
470
472
|
* 超出计划增量(403 + 1 047)的 prompt 侧。需求方裁定
|
|
471
473
|
* 「描述要长,可用性大于预算阈值」——收紧措辞可省回 158 字节,
|
|
472
474
|
* 但砍的正是各组件「何时改用 X」的辨析句,即选型准确率本身。
|
|
475
|
+
* 3. 13 000 → 13 650 / 21 800 → 22 500(0.15.0 分册 13 §3,2026-08-26 裁决):
|
|
476
|
+
* 新增内置组件 `OpenDocument`,实测 prompt +372 / schema +384。
|
|
477
|
+
* 该组件是本册消灭「站点技能在扩展里必然落到红框」的唯一手段,
|
|
478
|
+
* 砍它等于砍掉整册需求;改用「catalog 里有些组件不广告」则引入一个新概念,
|
|
479
|
+
* 模型看不见的组件与不存在的组件在它眼里没区别。需求方裁定取组件可用性、上调阈值,
|
|
480
|
+
* 幅度以落地后实测为准、不得预留宽裕。
|
|
473
481
|
*
|
|
474
|
-
*
|
|
475
|
-
* **AC-G20
|
|
476
|
-
*
|
|
482
|
+
* 三次上调合计把单请求成本从 21.7 KB 抬到约 35.3 KB。
|
|
483
|
+
* **AC-G20 原文「超了砍组件、不抬阈值」在这三处被推翻,每次都限于当版;
|
|
484
|
+
* 后续再撞顶仍须回到需求方,本版同样不得成为第四次上调的先例。**
|
|
477
485
|
*/
|
|
478
|
-
declare const CATALOG_PROMPT_MAX =
|
|
479
|
-
declare const CATALOG_SCHEMA_MAX =
|
|
486
|
+
declare const CATALOG_PROMPT_MAX = 13650;
|
|
487
|
+
declare const CATALOG_SCHEMA_MAX = 22500;
|
|
480
488
|
/**
|
|
481
|
-
*
|
|
482
|
-
* `CATALOG_BUDGET_STAGE`
|
|
489
|
+
* **尚未落地**的计划增量。0.15.0 分册 13 已落地,故仍归零;
|
|
490
|
+
* `CATALOG_BUDGET_STAGE` 保持 `'final'`,余量改由「小于一个平均组件」判定。
|
|
483
491
|
*/
|
|
484
492
|
declare const PLANNED_INCREMENT: {
|
|
485
493
|
readonly prompt: 0;
|