@webskill/sdk 0.7.0 → 0.8.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 +1 -1
- package/dist/agent.js +1 -1
- package/dist/browser.d.ts +151 -4
- package/dist/browser.js +250 -25
- package/dist/{catalogComponents-Dr5dFMAb-DKH_7VPI.js → catalogComponents-DfxxfUvn-D55Gbb2l.js} +3435 -437
- package/dist/{dist-8oQRa8Xz.js → dist-59XlqDuv.js} +93 -6
- package/dist/{dist-DnYG2-eY.js → dist-CJqQsIm9.js} +498 -118
- package/dist/{dist-D0qW6e40.js → dist-DmI5SBBF.js} +192 -17
- package/dist/{eventTypes-DjIQpt8Y-Bj3vghj4.js → eventTypes-g1BXL6x5-CibcOftR.js} +7 -2
- package/dist/governance.d.ts +16 -3
- package/dist/governance.js +24 -5
- package/dist/{index-DkbABR43.d.ts → index-K-eewlGL.d.ts} +138 -75
- package/dist/{index-BwsK9lGk.d.ts → index-P9J2LTfU.d.ts} +163 -6
- package/dist/{index-Ba3xFtfz.d.ts → index-fLskQfAS.d.ts} +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -4
- package/dist/mcp.d.ts +8 -2
- package/dist/mcp.js +12 -2
- package/dist/{memoryArtifactStore-52Zn9npI-BMPYwvoy.js → memoryArtifactStore-52Zn9npI-upv5OWYf.js} +1 -1
- package/dist/node.d.ts +3 -3
- package/dist/node.js +3 -3
- package/dist/{openUiLibrary-Bdrji9qK-D2LxmM-a.js → openUiLibrary-DURlAxjk-CU6AzfSW.js} +3 -3
- package/dist/{skillVersionStore-Bl-ElD45-CWPvGvoq.d.ts → skillVersionStore-Bl-ElD45-gRfSaAby.d.ts} +1 -1
- package/dist/{testing-CYTFqkDm.js → testing-BCUO5gZR.js} +2 -2
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +2 -2
- package/dist/{types-CcxRLdJG-DCXyw1US.d.ts → types-B3n0cMZu-BdcqQ35O.d.ts} +46 -6
- package/dist/ui-react.d.ts +13 -6
- package/dist/ui-react.js +153 -84
- package/dist/ui-vue.d.ts +1 -1
- package/dist/ui-vue.js +2 -2
- package/dist/ui.d.ts +4 -4
- package/dist/ui.js +3 -3
- package/dist/{webskillLitCatalog-_mugzRHx-B_54vxum.js → webskillLitCatalog-DwTwSBFt-DiXXpNZA.js} +22 -3
- package/package.json +2 -2
|
@@ -1,7 +1,69 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
import { a as textParts, i as rejectUnsupportedPart, n as partsToText, o as validateLlmMessages, r as promptText, t as MemoryArtifactStore } from "./memoryArtifactStore-52Zn9npI-
|
|
1
|
+
import { A as messageOf, I as renderAvailableSkillsXml, M as parseSkillMarkdown, W as validateSkills, f as SkillDiscovery, g as assertSafePathSegment, m as WebSkillError, p as SkillReader, v as buildCatalog, z as resolveInsideRoot } from "./dist-59XlqDuv.js";
|
|
2
|
+
import { a as textParts, i as rejectUnsupportedPart, n as partsToText, o as validateLlmMessages, r as promptText, t as MemoryArtifactStore } from "./memoryArtifactStore-52Zn9npI-upv5OWYf.js";
|
|
3
3
|
|
|
4
4
|
//#region ../runtime/dist/index.js
|
|
5
|
+
/** 与正常工具结果同构:模型读到的是「这次调用被中断了」,而不是一个凭空消失的调用 */
|
|
6
|
+
function interruptedToolResult(call, options = {}) {
|
|
7
|
+
const code = options.code ?? "RUN_INTERRUPTED";
|
|
8
|
+
const because = options.reason === void 0 ? "" : ` (${options.reason})`;
|
|
9
|
+
return {
|
|
10
|
+
ok: false,
|
|
11
|
+
content: [],
|
|
12
|
+
error: {
|
|
13
|
+
code,
|
|
14
|
+
message: `Tool call "${call.name}" produced no result: the run ended before it finished${because}.`
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/** 尚无 `role:'tool'` 应答的工具调用,按消息顺序 */
|
|
19
|
+
function findUnpairedToolCalls(messages) {
|
|
20
|
+
const answered = new Set(messages.filter((m) => m.role === "tool").map((m) => m.toolCallId));
|
|
21
|
+
return messages.filter((m) => m.role === "assistant" && m.toolCalls?.length).flatMap((m) => m.toolCalls ?? []).filter((call) => !answered.has(call.id));
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 为每个未应答的工具调用补一条结构化的中断说明。
|
|
25
|
+
*
|
|
26
|
+
* 补齐消息紧跟在该 assistant 已有的 tool 兄弟之后——供应商装配按相邻块分组,
|
|
27
|
+
* 插到序列末尾会让它归属到别的 assistant 消息上。
|
|
28
|
+
* 本函数**不改写入参**,也不写盘(AC-11.8)。
|
|
29
|
+
*/
|
|
30
|
+
function sealToolCallPairs(messages, options = {}) {
|
|
31
|
+
const answered = new Set(messages.filter((m) => m.role === "tool").map((m) => m.toolCallId));
|
|
32
|
+
const code = options.code ?? "RUN_INTERRUPTED";
|
|
33
|
+
const sealed = [];
|
|
34
|
+
const out = [];
|
|
35
|
+
for (let i = 0; i < messages.length; i += 1) {
|
|
36
|
+
const message = messages[i];
|
|
37
|
+
out.push(message);
|
|
38
|
+
if (message.role !== "assistant" || !message.toolCalls?.length) continue;
|
|
39
|
+
const missing = message.toolCalls.filter((call) => !answered.has(call.id));
|
|
40
|
+
if (missing.length === 0) continue;
|
|
41
|
+
while (i + 1 < messages.length && messages[i + 1].role === "tool") {
|
|
42
|
+
out.push(messages[i + 1]);
|
|
43
|
+
i += 1;
|
|
44
|
+
}
|
|
45
|
+
for (const call of missing) {
|
|
46
|
+
out.push({
|
|
47
|
+
role: "tool",
|
|
48
|
+
toolCallId: call.id,
|
|
49
|
+
content: textParts(JSON.stringify(interruptedToolResult(call, {
|
|
50
|
+
...options,
|
|
51
|
+
code
|
|
52
|
+
})))
|
|
53
|
+
});
|
|
54
|
+
answered.add(call.id);
|
|
55
|
+
sealed.push({
|
|
56
|
+
callId: call.id,
|
|
57
|
+
toolName: call.name,
|
|
58
|
+
code
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
messages: sealed.length === 0 ? [...messages] : out,
|
|
64
|
+
sealed
|
|
65
|
+
};
|
|
66
|
+
}
|
|
5
67
|
/**
|
|
6
68
|
* $defs 必须与 type / properties 同级,位于每个工具 inputSchema 的根。
|
|
7
69
|
* 已验证:放进 properties.spec 内层会得到同样的 "Unsupported ref: #" ——
|
|
@@ -1617,7 +1679,9 @@ function schemaToForm(schema, providedArgs) {
|
|
|
1617
1679
|
function mapFieldType(prop) {
|
|
1618
1680
|
if (Array.isArray(prop.enum)) return "select";
|
|
1619
1681
|
switch (prop.type) {
|
|
1620
|
-
case "string":
|
|
1682
|
+
case "string":
|
|
1683
|
+
if (prop["format"] === "binary" || prop["contentEncoding"] === "base64") return "file";
|
|
1684
|
+
return prop["format"] === "password" || prop["writeOnly"] === true ? "password" : "text";
|
|
1621
1685
|
case "number":
|
|
1622
1686
|
case "integer": return "number";
|
|
1623
1687
|
case "boolean": return "boolean";
|
|
@@ -1965,7 +2029,7 @@ const DEFAULT_LOOP_LIMITS = {
|
|
|
1965
2029
|
totalTimeoutMs: 12e4,
|
|
1966
2030
|
toolTimeoutMs: 3e4
|
|
1967
2031
|
};
|
|
1968
|
-
const RUN_SNAPSHOT_SCHEMA_VERSION =
|
|
2032
|
+
const RUN_SNAPSHOT_SCHEMA_VERSION = 3;
|
|
1969
2033
|
/** @experimental */
|
|
1970
2034
|
function isUnsupportedRunSnapshot(entry) {
|
|
1971
2035
|
return entry.unsupported === true;
|
|
@@ -2010,7 +2074,7 @@ var FsRunSnapshotStore = class {
|
|
|
2010
2074
|
throw new WebSkillError("RUN_SNAPSHOT_INCOMPATIBLE", `Snapshot for run "${runId}" has an unexpected shape and was deleted`);
|
|
2011
2075
|
}
|
|
2012
2076
|
const schemaVersion = typeof snapshot.schemaVersion === "number" ? snapshot.schemaVersion : 0;
|
|
2013
|
-
if (schemaVersion !==
|
|
2077
|
+
if (schemaVersion !== 3) throw new WebSkillError("RUN_SNAPSHOT_SCHEMA_UNSUPPORTED", `Snapshot for run "${runId}" uses schema version ${schemaVersion}; this runtime reads version 3. The file was kept for read-only inspection.`);
|
|
2014
2078
|
if (snapshot.runId !== runId) {
|
|
2015
2079
|
await this.#fs.remove(path).catch(() => void 0);
|
|
2016
2080
|
throw new WebSkillError("RUN_SNAPSHOT_INCOMPATIBLE", `Snapshot for run "${runId}" has an unexpected shape and was deleted`);
|
|
@@ -2030,7 +2094,7 @@ var FsRunSnapshotStore = class {
|
|
|
2030
2094
|
try {
|
|
2031
2095
|
const parsed = JSON.parse(await this.#fs.readText(entry.path));
|
|
2032
2096
|
const schemaVersion = typeof parsed.schemaVersion === "number" ? parsed.schemaVersion : 0;
|
|
2033
|
-
if (schemaVersion ===
|
|
2097
|
+
if (schemaVersion === 3) {
|
|
2034
2098
|
out.push(parsed);
|
|
2035
2099
|
continue;
|
|
2036
2100
|
}
|
|
@@ -2143,6 +2207,21 @@ const redactFileValue = (value) => {
|
|
|
2143
2207
|
return rest;
|
|
2144
2208
|
};
|
|
2145
2209
|
/**
|
|
2210
|
+
* 密码字段名集合(FR-23.7)。
|
|
2211
|
+
*
|
|
2212
|
+
* 既有的三处脱敏各有各的判别口径(看 request.type、看值是否标量、看值里有没有 data/mimeType),
|
|
2213
|
+
* 没有一处按**字段类型**判。行为记录那处尤其危险:它的安全假设是「标量是安全的」,
|
|
2214
|
+
* 而密码恰好是字符串标量——假设失效了。
|
|
2215
|
+
*/
|
|
2216
|
+
const passwordFieldNames = (request) => new Set(request.type === "form" ? request.fields.filter((f) => f.type === "password").map((f) => f.name) : []);
|
|
2217
|
+
/** 去掉密码字段的值;不是掩码而是**不存**,掩码存下来仍然泄露长度与存在性 */
|
|
2218
|
+
const withoutPasswords = (value, passwords) => {
|
|
2219
|
+
if (passwords.size === 0 || typeof value !== "object" || value === null || Array.isArray(value)) return value;
|
|
2220
|
+
const out = {};
|
|
2221
|
+
for (const [key, entry] of Object.entries(value)) if (!passwords.has(key)) out[key] = entry;
|
|
2222
|
+
return out;
|
|
2223
|
+
};
|
|
2224
|
+
/**
|
|
2146
2225
|
* 触顶失败的结构化细节(FR-21.2)。由终止原因推出上限字段,而不是在每个终止点各写一遍——
|
|
2147
2226
|
* 终止点有四个,写四遍就迟早有一处对不上。
|
|
2148
2227
|
*/
|
|
@@ -2156,6 +2235,16 @@ const limitDetails = (state, reason) => {
|
|
|
2156
2235
|
value: state.maxTurns
|
|
2157
2236
|
};
|
|
2158
2237
|
};
|
|
2238
|
+
/** 补齐消息里带的错误码:能说清「为什么没结果」的,就不要退化成 RUN_INTERRUPTED(设计 11 §2.5) */
|
|
2239
|
+
const sealCodeFor = (reason, errorCode) => {
|
|
2240
|
+
switch (reason) {
|
|
2241
|
+
case "interaction-timeout": return "RUN_INTERACTION_TIMEOUT";
|
|
2242
|
+
case "user-cancelled": return "RUN_CANCELLED";
|
|
2243
|
+
case "timeout": return "RUN_TIMEOUT";
|
|
2244
|
+
case "tool-resolution-exhausted": return "TOOL_RESOLUTION_EXHAUSTED";
|
|
2245
|
+
default: return errorCode ?? "RUN_INTERRUPTED";
|
|
2246
|
+
}
|
|
2247
|
+
};
|
|
2159
2248
|
/**
|
|
2160
2249
|
* 多轮 Agent 循环。
|
|
2161
2250
|
* 工具失败一律转为 ToolResult{ok:false} 回喂 LLM 继续循环;
|
|
@@ -2487,6 +2576,7 @@ var AgentLoop = class {
|
|
|
2487
2576
|
} catch (e) {
|
|
2488
2577
|
trace.record("run.warning", { message: `Terminal lifecycle hook failed: ${messageOf(e)}` });
|
|
2489
2578
|
}
|
|
2579
|
+
await this.#sealToolCalls(state, reason, errorCode);
|
|
2490
2580
|
run.trace = trace.list();
|
|
2491
2581
|
return {
|
|
2492
2582
|
output,
|
|
@@ -2494,12 +2584,45 @@ var AgentLoop = class {
|
|
|
2494
2584
|
messages: state.messages.map((m) => ({ ...m }))
|
|
2495
2585
|
};
|
|
2496
2586
|
}
|
|
2587
|
+
/**
|
|
2588
|
+
* S1 出口守卫(FR-11.1):中断留下的未应答工具调用在这里补齐。
|
|
2589
|
+
*
|
|
2590
|
+
* 放在 `#finish` 而不是四个早退点:它是唯一的汇流出口,写四遍就迟早漏一处。
|
|
2591
|
+
* 补齐产物只进 `LlmMessage[]`(下一轮请求装配用),不进 chatbot 的消息流(AC-11.2)。
|
|
2592
|
+
*/
|
|
2593
|
+
async #sealToolCalls(state, reason, errorCode) {
|
|
2594
|
+
const pending = findUnpairedToolCalls(state.messages);
|
|
2595
|
+
if (pending.length === 0) return;
|
|
2596
|
+
const code = sealCodeFor(reason, errorCode);
|
|
2597
|
+
for (const call of pending) {
|
|
2598
|
+
const result = interruptedToolResult(call, {
|
|
2599
|
+
code,
|
|
2600
|
+
reason
|
|
2601
|
+
});
|
|
2602
|
+
state.messages.push({
|
|
2603
|
+
role: "tool",
|
|
2604
|
+
toolCallId: call.id,
|
|
2605
|
+
content: await this.#toolResultParts(call, result, state)
|
|
2606
|
+
});
|
|
2607
|
+
state.trace.record("run.warning", {
|
|
2608
|
+
message: `Sealed unanswered tool call "${call.name}": the run ended before it produced a result.`,
|
|
2609
|
+
data: {
|
|
2610
|
+
kind: "tool-call-sealed",
|
|
2611
|
+
callId: call.id,
|
|
2612
|
+
toolName: call.name,
|
|
2613
|
+
side: "write",
|
|
2614
|
+
reason,
|
|
2615
|
+
code
|
|
2616
|
+
}
|
|
2617
|
+
});
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2497
2620
|
/** D3 快照写入(含 pendingInteraction 与过期时间;写失败降级 run.warning) */
|
|
2498
2621
|
async #saveSnapshot(state, pending) {
|
|
2499
2622
|
const store = this.#deps.snapshotStore;
|
|
2500
2623
|
if (!store) return;
|
|
2501
2624
|
const snapshot = {
|
|
2502
|
-
schemaVersion:
|
|
2625
|
+
schemaVersion: 3,
|
|
2503
2626
|
runId: state.runId,
|
|
2504
2627
|
sessionId: state.run.sessionId,
|
|
2505
2628
|
userPrompt: state.run.userPrompt,
|
|
@@ -2674,6 +2797,15 @@ var AgentLoop = class {
|
|
|
2674
2797
|
throw e;
|
|
2675
2798
|
}
|
|
2676
2799
|
}
|
|
2800
|
+
/**
|
|
2801
|
+
* 工具的技能归属。内置工具与外部工具没有归属,返回 `undefined`——
|
|
2802
|
+
* 拿 `activated[0]` 顶替会把内置工具的失败栽给一个无关技能,比不归因更糟(设计 26 §2.3)。
|
|
2803
|
+
*/
|
|
2804
|
+
#skillOf(call, state) {
|
|
2805
|
+
if (call.name === "read_skill_file" || call.name === "ask_user") return void 0;
|
|
2806
|
+
const resolution = resolveToolName(call.name, state.activated, state.activatedTools.keys());
|
|
2807
|
+
return resolution.kind === "script" ? resolution.skillName : void 0;
|
|
2808
|
+
}
|
|
2677
2809
|
/** 最后一条 assistant 消息里第一个尚无 tool 响应的工具调用(即中断时正在处理的那个) */
|
|
2678
2810
|
#findPendingToolCall(messages) {
|
|
2679
2811
|
const lastAssistant = [...messages].reverse().find((m) => m.role === "assistant" && m.toolCalls?.length);
|
|
@@ -2864,11 +2996,14 @@ var AgentLoop = class {
|
|
|
2864
2996
|
}
|
|
2865
2997
|
async #executeCall(call, state) {
|
|
2866
2998
|
const argsSummary = summarizeArgs(call.arguments);
|
|
2999
|
+
const owner = this.#skillOf(call, state);
|
|
3000
|
+
const attribution = owner === void 0 ? {} : { skillName: owner };
|
|
2867
3001
|
const callStartMs = Date.parse(state.now());
|
|
2868
3002
|
state.trace.record("tool.started", { data: {
|
|
2869
3003
|
name: call.name,
|
|
2870
3004
|
callId: call.id,
|
|
2871
|
-
args: argsSummary
|
|
3005
|
+
args: argsSummary,
|
|
3006
|
+
...attribution
|
|
2872
3007
|
} });
|
|
2873
3008
|
this.#emitTool(state, "started", call);
|
|
2874
3009
|
let result;
|
|
@@ -2894,7 +3029,8 @@ var AgentLoop = class {
|
|
|
2894
3029
|
name: call.name,
|
|
2895
3030
|
callId: call.id,
|
|
2896
3031
|
args: argsSummary,
|
|
2897
|
-
durationMs
|
|
3032
|
+
durationMs,
|
|
3033
|
+
...attribution
|
|
2898
3034
|
} });
|
|
2899
3035
|
this.#emitTool(state, "completed", call);
|
|
2900
3036
|
for (const item of result.content) {
|
|
@@ -2928,7 +3064,8 @@ var AgentLoop = class {
|
|
|
2928
3064
|
callId: call.id,
|
|
2929
3065
|
code: result.error?.code,
|
|
2930
3066
|
args: argsSummary,
|
|
2931
|
-
durationMs
|
|
3067
|
+
durationMs,
|
|
3068
|
+
...attribution
|
|
2932
3069
|
}
|
|
2933
3070
|
});
|
|
2934
3071
|
this.#emitTool(state, "failed", call, result.error?.code);
|
|
@@ -3095,10 +3232,17 @@ var AgentLoop = class {
|
|
|
3095
3232
|
async #replaySurfaceEvents(state) {
|
|
3096
3233
|
const bridge = this.#deps.uiBridge;
|
|
3097
3234
|
if (!bridge?.renderSurface || state.surfaceEvents.length === 0) return;
|
|
3098
|
-
try {
|
|
3099
|
-
|
|
3235
|
+
for (const event of state.surfaceEvents) try {
|
|
3236
|
+
await bridge.renderSurface(structuredClone(event));
|
|
3100
3237
|
} catch (e) {
|
|
3101
|
-
state.trace.record("
|
|
3238
|
+
state.trace.record("ui.degraded", {
|
|
3239
|
+
message: `Failed to replay UI surface "${event.id}": ${messageOf(e)}`,
|
|
3240
|
+
data: {
|
|
3241
|
+
kind: "replay-failed",
|
|
3242
|
+
surfaceId: event.id,
|
|
3243
|
+
eventType: event.type
|
|
3244
|
+
}
|
|
3245
|
+
});
|
|
3102
3246
|
}
|
|
3103
3247
|
}
|
|
3104
3248
|
/**
|
|
@@ -3662,7 +3806,8 @@ var AgentLoop = class {
|
|
|
3662
3806
|
if (!this.#deps.memory) return;
|
|
3663
3807
|
const scope = `session:${state.run.sessionId}`;
|
|
3664
3808
|
const limit = this.#config.paramHistoryLimit;
|
|
3665
|
-
const
|
|
3809
|
+
const passwords = passwordFieldNames(request);
|
|
3810
|
+
const recorded = request.type === "file-pick" ? redactFileValue(value) : withoutPasswords(value, passwords);
|
|
3666
3811
|
await this.#memoryMutate(scope, "paramHistory", state, (current) => {
|
|
3667
3812
|
const history = current ?? [];
|
|
3668
3813
|
history.push({
|
|
@@ -3729,6 +3874,7 @@ var AgentLoop = class {
|
|
|
3729
3874
|
else if (request.type === "form" && typeof value === "object" && value !== null) {
|
|
3730
3875
|
const submitted = value;
|
|
3731
3876
|
for (const field of request.fields) {
|
|
3877
|
+
if (field.type === "password") continue;
|
|
3732
3878
|
const next = submitted[field.name];
|
|
3733
3879
|
if (typeof next !== "string" && typeof next !== "number" && typeof next !== "boolean") continue;
|
|
3734
3880
|
if (next === "") continue;
|
|
@@ -3882,6 +4028,7 @@ var WebSkillRuntime = class {
|
|
|
3882
4028
|
if (!this.#catalogCache) await this.discover();
|
|
3883
4029
|
const cache = this.#catalogCache;
|
|
3884
4030
|
if (!cache) throw new Error("discover() did not populate the catalog cache");
|
|
4031
|
+
const sealedHistory = options.history ? sealToolCallPairs(options.history) : void 0;
|
|
3885
4032
|
const providerFailures = [];
|
|
3886
4033
|
const providerEntries = (await Promise.all((this.#deps.skillProviders ?? []).map(async (p) => {
|
|
3887
4034
|
try {
|
|
@@ -3928,11 +4075,25 @@ var WebSkillRuntime = class {
|
|
|
3928
4075
|
userPrompt,
|
|
3929
4076
|
route,
|
|
3930
4077
|
runId,
|
|
3931
|
-
...
|
|
4078
|
+
...sealedHistory ? { history: sealedHistory.messages } : {}
|
|
3932
4079
|
});
|
|
3933
4080
|
} finally {
|
|
3934
4081
|
this.#loops.delete(runId);
|
|
3935
4082
|
}
|
|
4083
|
+
for (const record of sealedHistory?.sealed ?? []) result.run.trace.push({
|
|
4084
|
+
id: `evt-seal-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
4085
|
+
runId: result.run.id,
|
|
4086
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4087
|
+
type: "run.warning",
|
|
4088
|
+
message: `Sealed unanswered tool call "${record.toolName}" carried over from an earlier interrupted run.`,
|
|
4089
|
+
data: {
|
|
4090
|
+
kind: "tool-call-sealed",
|
|
4091
|
+
callId: record.callId,
|
|
4092
|
+
toolName: record.toolName,
|
|
4093
|
+
side: "read",
|
|
4094
|
+
code: record.code
|
|
4095
|
+
}
|
|
4096
|
+
});
|
|
3936
4097
|
for (const failure of providerFailures) result.run.trace.push({
|
|
3937
4098
|
id: `evt-provider-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
3938
4099
|
runId: result.run.id,
|
|
@@ -4428,7 +4589,6 @@ function parseUserProfileExport(raw) {
|
|
|
4428
4589
|
entries
|
|
4429
4590
|
};
|
|
4430
4591
|
}
|
|
4431
|
-
/** 导入前给用户看的差异(FR-19.7):新增哪些、覆盖哪些 @experimental */
|
|
4432
4592
|
function diffUserProfile(current, incoming) {
|
|
4433
4593
|
const byId = new Map(current.entries.map((entry) => [entry.id, entry]));
|
|
4434
4594
|
const added = [];
|
|
@@ -4990,6 +5150,7 @@ const toMeta = (record) => ({
|
|
|
4990
5150
|
...record.title !== void 0 ? { title: record.title } : {},
|
|
4991
5151
|
...record.titleLocked === true ? { titleLocked: true } : {},
|
|
4992
5152
|
...record.archived === true ? { archived: true } : {},
|
|
5153
|
+
...record.modelId !== void 0 ? { modelId: record.modelId } : {},
|
|
4993
5154
|
messageCount: record.messages.length
|
|
4994
5155
|
});
|
|
4995
5156
|
const newSessionId = () => `session-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -5036,6 +5197,7 @@ function parseSessionFile(raw, path) {
|
|
|
5036
5197
|
...typeof file.title === "string" ? { title: file.title } : {},
|
|
5037
5198
|
...file.titleLocked === true ? { titleLocked: true } : {},
|
|
5038
5199
|
...file.archived === true ? { archived: true } : {},
|
|
5200
|
+
...typeof file.modelId === "string" ? { modelId: file.modelId } : {},
|
|
5039
5201
|
messages: Array.isArray(file.messages) ? file.messages : [],
|
|
5040
5202
|
messageCount: Array.isArray(file.messages) ? file.messages.length : 0
|
|
5041
5203
|
};
|
|
@@ -5077,6 +5239,7 @@ var FsSessionStore = class {
|
|
|
5077
5239
|
...record.title !== void 0 ? { title: record.title } : {},
|
|
5078
5240
|
...record.titleLocked === true ? { titleLocked: true } : {},
|
|
5079
5241
|
...record.archived === true ? { archived: true } : {},
|
|
5242
|
+
...record.modelId !== void 0 ? { modelId: record.modelId } : {},
|
|
5080
5243
|
messages: record.messages
|
|
5081
5244
|
};
|
|
5082
5245
|
await this.#fs.writeText(this.#path(record.id), JSON.stringify(file, null, 2));
|
|
@@ -5170,6 +5333,18 @@ var FsSessionStore = class {
|
|
|
5170
5333
|
await this.#write(record);
|
|
5171
5334
|
});
|
|
5172
5335
|
}
|
|
5336
|
+
async setModel(id, modelId) {
|
|
5337
|
+
await this.#serialize(id, async () => {
|
|
5338
|
+
const record = await this.#require(id);
|
|
5339
|
+
if (modelId === void 0) delete record.modelId;
|
|
5340
|
+
else record.modelId = modelId;
|
|
5341
|
+
await this.#write(record);
|
|
5342
|
+
});
|
|
5343
|
+
}
|
|
5344
|
+
async getMeta(id) {
|
|
5345
|
+
const record = await this.get(id);
|
|
5346
|
+
return record === void 0 ? void 0 : toMeta(record);
|
|
5347
|
+
}
|
|
5173
5348
|
async delete(id) {
|
|
5174
5349
|
await this.#serialize(id, async () => {
|
|
5175
5350
|
const path = this.#path(id);
|
|
@@ -5179,4 +5354,4 @@ var FsSessionStore = class {
|
|
|
5179
5354
|
};
|
|
5180
5355
|
|
|
5181
5356
|
//#endregion
|
|
5182
|
-
export {
|
|
5357
|
+
export { fromVercelStreamPart as $, SerializingMemoryStore as A, bridgeError as B, ProgressiveRouter as C, sealToolCallPairs as Ct, RUN_SNAPSHOT_SCHEMA_VERSION as D, toVercelToolSpecs as Dt, READ_SKILL_FILE_TOOL_NAME as E, toRecordDigests as Et, USER_PROFILE_PROMPT_HEADER as F, exportUserProfile as G, createScriptContext as H, USER_PROFILE_REFINE_PROMPT as I, extractTodoTraceEvents as J, extractChartSpec as K, WebSkillRuntime as L, USER_PROFILE_EXPORT_VERSION as M, USER_PROFILE_KEY as N, RUN_TRACE_SCHEMA_VERSION as O, validateUiSpecEvent as Ot, USER_PROFILE_NO_INVENTION_RULE as P, fromVercelResult as Q, appendBehaviorRecords as R, OpenAiCompatibleClient as S, scriptToolName as St, READ_SKILL_FILE_TOOL as T, toLlmToolSpec as Tt, createWebSkillApi as U, buildRenderResult as V, diffUserProfile as W, findUnpairedToolCalls as X, extractUiSpecEvents as Y, formatSkillScriptManifest as Z, FsRunTraceStore as _, renderUserProfileContext as _t, AgentLoop as a, mergeProfileEntries as at, GoogleGenAiClient as b, schemaSourceLabel as bt, CapabilityApproval as c, normalizeErrorCode as ct, EMPTY_USER_PROFILE as d, parseBridgeRequest as dt, interruptedToolResult as et, EventBus as f, parseUserProfileExport as ft, FsRunSnapshotStore as g, refineUserProfile as gt, FsMemoryStore as h, readUserProfile as ht, ASK_USER_TOOL_NAME as i, mergeCatalogEntries as it, TraceRecorder as j, SESSION_SCHEMA_VERSION as k, validateUiSpecNode as kt, DEFAULT_LOOP_LIMITS as l, normalizeToolContent as lt, FsArtifactStore as m, readProfileEntries as mt, ASK_USER_INPUT_SCHEMA as n, isUnsupportedRunSnapshot as nt, AnthropicClient as o, networkPolicyLibSource as ot, FS_SESSION_PAGE_SIZE as p, readBehaviorRecords as pt, extractSkillCandidate as q, ASK_USER_TOOL as r, listSkillScripts as rt, BEHAVIOR_RECORDS_KEY as s, networkUrlHost as st, ALLOWED_TOOLS_EXCLUSION_REASON as t, isNetworkAllowed as tt, DEFAULT_USER_PROFILE_LIMITS as u, normalizeToolError as ut, FsSessionStore as v, resolveToolName as vt, READ_SKILL_FILE_INPUT_SCHEMA as w, summarizeToolCalls as wt, HookRunner as x, schemaToForm as xt, FullDisclosureRouter as y, sampleBehaviorRecords as yt, applyUserProfileImport as z };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region ../governance/dist/eventTypes-
|
|
1
|
+
//#region ../governance/dist/eventTypes-g1BXL6x5.js
|
|
2
2
|
/**
|
|
3
3
|
* 审计事件类型常量(FR-13.4)。
|
|
4
4
|
*
|
|
@@ -21,9 +21,14 @@ const AUDIT_EVENT_TYPES = {
|
|
|
21
21
|
trustKeyRemoved: "trust.key_removed",
|
|
22
22
|
policyNetworkChanged: "policy.network_changed",
|
|
23
23
|
policyPrivacyChanged: "policy.privacy_changed",
|
|
24
|
+
policySecurityChanged: "policy.security_changed",
|
|
25
|
+
policySandboxChanged: "policy.sandbox_changed",
|
|
26
|
+
policyAgentCapabilitiesChanged: "policy.agent_capabilities_changed",
|
|
27
|
+
profileChanged: "profile.changed",
|
|
24
28
|
mcpEndpointChanged: "mcp.endpoint_changed",
|
|
25
29
|
mcpPolicyRelaxed: "mcp.policy_relaxed",
|
|
26
|
-
providerChanged: "provider.changed"
|
|
30
|
+
providerChanged: "provider.changed",
|
|
31
|
+
candidateGenerated: "candidate.generated"
|
|
27
32
|
};
|
|
28
33
|
/** 稳定展示序:筛选下拉与文档表格都从这里取,不各自维护一份顺序 */
|
|
29
34
|
const AUDIT_EVENT_TYPE_LIST = Object.values(AUDIT_EVENT_TYPES);
|
package/dist/governance.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { H as PageQuery, I as FileSystemProvider, V as Page,
|
|
2
|
-
import { H as IntegrityVerdict,
|
|
3
|
-
import { _ as SkillVersion, a as AuditLog, c as CandidateFile, d as CandidateSource, f as CandidateStatus, g as SkillState, h as SKILL_VERSION_PAGE_SIZE, i as AuditEvent, l as CandidateRisk, m as CompositeApprovalPolicy, n as ApprovalDecision, o as AuditQueryFilter, p as CandidateStore, r as ApprovalPolicy, s as CANDIDATE_PAGE_SIZE, t as AlwaysHumanApprovalPolicy, u as CandidateSkill, v as SkillVersionStore, y as candidateToCatalogEntry } from "./skillVersionStore-Bl-ElD45-
|
|
1
|
+
import { H as PageQuery, I as FileSystemProvider, V as Page, ct as SkillManagerPort, f as LlmMessage, it as SkillDocument, l as LlmClient, nt as SkillCatalogEntry, x as UiBridge } from "./types-B3n0cMZu-BdcqQ35O.js";
|
|
2
|
+
import { H as IntegrityVerdict, It as SkillIntegrityGuard, Lt as SkillOutcomeReporter, Vt as SkillStateGuard, bt as RuntimeRun, pn as WebSkillRuntime } from "./index-K-eewlGL.js";
|
|
3
|
+
import { _ as SkillVersion, a as AuditLog, c as CandidateFile, d as CandidateSource, f as CandidateStatus, g as SkillState, h as SKILL_VERSION_PAGE_SIZE, i as AuditEvent, l as CandidateRisk, m as CompositeApprovalPolicy, n as ApprovalDecision, o as AuditQueryFilter, p as CandidateStore, r as ApprovalPolicy, s as CANDIDATE_PAGE_SIZE, t as AlwaysHumanApprovalPolicy, u as CandidateSkill, v as SkillVersionStore, y as candidateToCatalogEntry } from "./skillVersionStore-Bl-ElD45-gRfSaAby.js";
|
|
4
4
|
//#region ../governance/dist/index.d.ts
|
|
5
5
|
//#region src/candidate/candidateNormalizer.d.ts
|
|
6
6
|
/** 剥 markdown fence 与 <think> 块、截取首尾 {};非对象 → CANDIDATE_INVALID */
|
|
@@ -110,6 +110,14 @@ interface AuditChainVerification {
|
|
|
110
110
|
interface AuditPage extends Page<AuditEvent> {
|
|
111
111
|
chainBrokenAt?: number;
|
|
112
112
|
chainReason?: string;
|
|
113
|
+
/**
|
|
114
|
+
* 解析失败的行。长度 > 0 即「读不动」,但已解析的记录仍在 `items` 里——
|
|
115
|
+
* 不给这个字段的话,坏行被吞掉后的返回值与「真的没有事件」完全一样(FR-18.3)。
|
|
116
|
+
*/
|
|
117
|
+
malformed?: {
|
|
118
|
+
count: number;
|
|
119
|
+
firstLine: number;
|
|
120
|
+
};
|
|
113
121
|
}
|
|
114
122
|
/**
|
|
115
123
|
* JSONL 追加式审计日志(<managedRoot>/.webskill/audit.jsonl):
|
|
@@ -171,9 +179,14 @@ declare const AUDIT_EVENT_TYPES: {
|
|
|
171
179
|
readonly trustKeyRemoved: "trust.key_removed";
|
|
172
180
|
readonly policyNetworkChanged: "policy.network_changed";
|
|
173
181
|
readonly policyPrivacyChanged: "policy.privacy_changed";
|
|
182
|
+
readonly policySecurityChanged: "policy.security_changed";
|
|
183
|
+
readonly policySandboxChanged: "policy.sandbox_changed";
|
|
184
|
+
readonly policyAgentCapabilitiesChanged: "policy.agent_capabilities_changed";
|
|
185
|
+
readonly profileChanged: "profile.changed";
|
|
174
186
|
readonly mcpEndpointChanged: "mcp.endpoint_changed";
|
|
175
187
|
readonly mcpPolicyRelaxed: "mcp.policy_relaxed";
|
|
176
188
|
readonly providerChanged: "provider.changed";
|
|
189
|
+
readonly candidateGenerated: "candidate.generated";
|
|
177
190
|
};
|
|
178
191
|
type AuditEventType = (typeof AUDIT_EVENT_TYPES)[keyof typeof AUDIT_EVENT_TYPES];
|
|
179
192
|
/** 稳定展示序:筛选下拉与文档表格都从这里取,不各自维护一份顺序 */
|
package/dist/governance.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as textParts, n as partsToText } from "./memoryArtifactStore-52Zn9npI-
|
|
3
|
-
import { n as AUDIT_EVENT_TYPE_LIST, t as AUDIT_EVENT_TYPES } from "./eventTypes-
|
|
1
|
+
import { A as messageOf, D as isValidSkillName, g as assertSafePathSegment, m as WebSkillError } from "./dist-59XlqDuv.js";
|
|
2
|
+
import { a as textParts, n as partsToText } from "./memoryArtifactStore-52Zn9npI-upv5OWYf.js";
|
|
3
|
+
import { n as AUDIT_EVENT_TYPE_LIST, t as AUDIT_EVENT_TYPES } from "./eventTypes-g1BXL6x5-CibcOftR.js";
|
|
4
4
|
|
|
5
5
|
//#region ../governance/dist/index.js
|
|
6
6
|
const invalid = (message, details) => {
|
|
@@ -443,15 +443,21 @@ var FsAuditLog = class {
|
|
|
443
443
|
/** 按文件行序保留(含解析失败的洞):链校验必须在文件行序上做,不能在筛选结果上做 */
|
|
444
444
|
const records = [];
|
|
445
445
|
let skippedLines = 0;
|
|
446
|
+
let firstMalformedLine = -1;
|
|
446
447
|
for (const line of raw.split("\n")) {
|
|
447
448
|
if (line.trim() === "") continue;
|
|
448
449
|
try {
|
|
449
450
|
records.push(JSON.parse(line));
|
|
450
451
|
} catch {
|
|
452
|
+
if (firstMalformedLine < 0) firstMalformedLine = records.length;
|
|
451
453
|
skippedLines += 1;
|
|
452
454
|
records.push(void 0);
|
|
453
455
|
}
|
|
454
456
|
}
|
|
457
|
+
const malformed = skippedLines > 0 ? {
|
|
458
|
+
count: skippedLines,
|
|
459
|
+
firstLine: firstMalformedLine
|
|
460
|
+
} : void 0;
|
|
455
461
|
if (skippedLines > 0) console.warn(`[webskill] Audit log at ${path} contains ${skippedLines} unparsable line(s) skipped by query; run verifyChain() to check integrity`);
|
|
456
462
|
const matched = [];
|
|
457
463
|
for (let i = 0; i < records.length; i++) {
|
|
@@ -493,7 +499,8 @@ var FsAuditLog = class {
|
|
|
493
499
|
...broken !== void 0 ? {
|
|
494
500
|
chainBrokenAt: broken.at,
|
|
495
501
|
chainReason: broken.reason
|
|
496
|
-
} : {}
|
|
502
|
+
} : {},
|
|
503
|
+
...malformed !== void 0 ? { malformed } : {}
|
|
497
504
|
};
|
|
498
505
|
}
|
|
499
506
|
/** 单行的链自洽:本行 hash 重算相符,且 prevHash 指向前一行的 hash。自洽时返回 undefined */
|
|
@@ -1025,14 +1032,17 @@ var EvaluationRunner = class {
|
|
|
1025
1032
|
/** 失败 trace → 回归评估任务建议(prompt 复现 + expected 错误模式) */
|
|
1026
1033
|
function suggestFromFailedRun(run) {
|
|
1027
1034
|
const errorPatterns = run.trace.filter((e) => e.type === "tool.failed" || e.type === "run.failed").map((e) => String(e.data?.["code"] ?? e.message ?? "")).filter(Boolean);
|
|
1035
|
+
const failedSkills = [...new Set(run.trace.filter((e) => e.type === "tool.failed").map((e) => e.data?.["skillName"]).filter((name) => typeof name === "string" && name !== ""))];
|
|
1028
1036
|
return {
|
|
1029
1037
|
id: `regression-${run.id}`,
|
|
1030
1038
|
prompt: run.userPrompt,
|
|
1039
|
+
...run.activeSkillNames.length > 0 ? { skillNames: [...run.activeSkillNames] } : {},
|
|
1031
1040
|
expected: (output, rerun) => rerun.status === "completed" && !rerun.trace.some((e) => (e.type === "tool.failed" || e.type === "run.failed") && errorPatterns.includes(String(e.data?.["code"] ?? ""))),
|
|
1032
1041
|
metadata: {
|
|
1033
1042
|
source: "test-suggestion",
|
|
1034
1043
|
failureReason: run.terminationReason ?? "unknown",
|
|
1035
|
-
errorPatterns
|
|
1044
|
+
errorPatterns,
|
|
1045
|
+
failedSkills
|
|
1036
1046
|
}
|
|
1037
1047
|
};
|
|
1038
1048
|
}
|
|
@@ -1208,6 +1218,15 @@ function createMissHook(deps) {
|
|
|
1208
1218
|
source: "runtime-miss"
|
|
1209
1219
|
});
|
|
1210
1220
|
await deps.store.save(candidate);
|
|
1221
|
+
await deps.audit?.append({
|
|
1222
|
+
type: AUDIT_EVENT_TYPES.candidateGenerated,
|
|
1223
|
+
actor: "system",
|
|
1224
|
+
target: candidate.name,
|
|
1225
|
+
data: {
|
|
1226
|
+
source: "runtime-miss",
|
|
1227
|
+
candidateId: candidate.id
|
|
1228
|
+
}
|
|
1229
|
+
});
|
|
1211
1230
|
};
|
|
1212
1231
|
}
|
|
1213
1232
|
|