@webskill/sdk 0.2.3 → 0.2.5
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/browser.d.ts +3 -2
- package/dist/browser.js +47 -15
- package/dist/{dist-NM4Mylx4.js → dist-B77plHjw.js} +230 -105
- package/dist/{dist-D0saNPi_.js → dist-BQzncxXg.js} +98 -5
- package/dist/{dist-CvIMVwr3.js → dist-Chk8iB-E.js} +101 -38
- package/dist/{dist-BJobG0i-.js → dist-DNSG9FqC.js} +108 -69
- package/dist/governance.d.ts +13 -5
- package/dist/governance.js +50 -20
- package/dist/{index-iqcz3_NS.d.ts → index-CsDJvYGV.d.ts} +8 -3
- package/dist/{index-gjFuBevI.d.ts → index-DfINBEOy.d.ts} +29 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/mcp.d.ts +7 -3
- package/dist/mcp.js +35 -18
- package/dist/node.d.ts +3 -3
- package/dist/node.js +3 -3
- package/dist/processSandboxEntry.js +11 -0
- package/dist/sandboxWorkerEntry.js +11 -0
- package/dist/{testing-B4pq6JYa.js → testing-BUoXvm1u.js} +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/dist/{types-CKm5G_eQ-8W8FnP4u.d.ts → types-CKm5G_eQ-krKWW8WV.d.ts} +40 -7
- package/dist/ui-react.d.ts +3 -1
- package/dist/ui-react.js +8 -1
- package/dist/ui-vue.d.ts +3 -1
- package/dist/ui-vue.js +8 -1
- package/dist/ui.d.ts +20 -6
- package/dist/ui.js +3 -3
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as
|
|
1
|
+
import { C as messageOf, N as validateSkills, O as renderAvailableSkillsXml, T as parseSkillMarkdown, c as SkillDiscovery, f as assertSafePathSegment, j as resolveInsideRoot, l as SkillReader, m as buildCatalog, u as WebSkillError } from "./dist-BQzncxXg.js";
|
|
2
2
|
import { t as MemoryArtifactStore } from "./memoryArtifactStore-C9lFVqPF-yFz6yJj0.js";
|
|
3
3
|
|
|
4
4
|
//#region ../runtime/dist/index.js
|
|
@@ -272,7 +272,7 @@ var AnthropicClient = class {
|
|
|
272
272
|
"content-type": "application/json",
|
|
273
273
|
"x-api-key": this.#config.apiKey,
|
|
274
274
|
"anthropic-version": ANTHROPIC_VERSION,
|
|
275
|
-
"anthropic-dangerous-direct-browser-access": "true"
|
|
275
|
+
...this.#config.dangerouslyAllowDirectBrowserAccess ? { "anthropic-dangerous-direct-browser-access": "true" } : {}
|
|
276
276
|
};
|
|
277
277
|
}
|
|
278
278
|
async complete(input) {
|
|
@@ -571,7 +571,7 @@ var GoogleGenAiClient = class {
|
|
|
571
571
|
}
|
|
572
572
|
async #post(input, stream) {
|
|
573
573
|
const model = input.model ?? this.#config.model;
|
|
574
|
-
const action = stream ?
|
|
574
|
+
const action = stream ? ":streamGenerateContent?alt=sse" : ":generateContent";
|
|
575
575
|
const { systemInstruction, contents } = toGenAiContents(input.messages);
|
|
576
576
|
const body = { contents };
|
|
577
577
|
if (systemInstruction) body["systemInstruction"] = systemInstruction;
|
|
@@ -581,7 +581,10 @@ var GoogleGenAiClient = class {
|
|
|
581
581
|
try {
|
|
582
582
|
res = await this.#fetch(`${this.#baseUrl()}/v1beta/models/${encodeURIComponent(model)}${action}`, {
|
|
583
583
|
method: "POST",
|
|
584
|
-
headers: {
|
|
584
|
+
headers: {
|
|
585
|
+
"content-type": "application/json",
|
|
586
|
+
"x-goog-api-key": this.#config.apiKey
|
|
587
|
+
},
|
|
585
588
|
body: JSON.stringify(body),
|
|
586
589
|
signal: input.signal ?? (this.#config.requestTimeoutMs ? AbortSignal.timeout(this.#config.requestTimeoutMs) : null)
|
|
587
590
|
});
|
|
@@ -597,7 +600,7 @@ var GoogleGenAiClient = class {
|
|
|
597
600
|
/** 轻量探测(GET /v1beta/models),集成测试据此决定 skip */
|
|
598
601
|
async checkAvailability() {
|
|
599
602
|
try {
|
|
600
|
-
return (await this.#fetch(`${this.#baseUrl()}/v1beta/models
|
|
603
|
+
return (await this.#fetch(`${this.#baseUrl()}/v1beta/models`, { headers: { "x-goog-api-key": this.#config.apiKey } })).ok;
|
|
601
604
|
} catch {
|
|
602
605
|
return false;
|
|
603
606
|
}
|
|
@@ -846,11 +849,12 @@ const ASK_USER_TOOL = {
|
|
|
846
849
|
*/
|
|
847
850
|
function createScriptContext(deps) {
|
|
848
851
|
const { fs, artifactStore, skillName, skillRoot, runId, confirm, onWarning, onArtifactCreated } = deps;
|
|
852
|
+
const readFs = fs.withRoot?.(skillRoot) ?? fs;
|
|
849
853
|
return {
|
|
850
854
|
skillName,
|
|
851
855
|
runId,
|
|
852
856
|
async readReference(relativePath) {
|
|
853
|
-
return
|
|
857
|
+
return readFs.readText(resolveInsideRoot(skillRoot, `references/${relativePath}`));
|
|
854
858
|
},
|
|
855
859
|
async writeArtifact(path, content, options) {
|
|
856
860
|
const artifact = typeof content === "string" ? await artifactStore.createTextArtifact({
|
|
@@ -963,6 +967,13 @@ function mapFieldType(prop) {
|
|
|
963
967
|
/** 生命周期事件总线:只读观测,支持按阶段或通配订阅 */
|
|
964
968
|
var EventBus = class {
|
|
965
969
|
#listeners = /* @__PURE__ */ new Map();
|
|
970
|
+
/** 监听器异常出口(默认 console.warn;单个监听器抛错不影响其他监听器与 emit 调用方) */
|
|
971
|
+
#onListenerError;
|
|
972
|
+
constructor(onListenerError) {
|
|
973
|
+
this.#onListenerError = onListenerError ?? ((error, event) => {
|
|
974
|
+
console.warn(`EventBus listener threw on phase "${event.phase}": ${error instanceof Error ? error.message : String(error)}`);
|
|
975
|
+
});
|
|
976
|
+
}
|
|
966
977
|
/** 返回取消订阅函数 */
|
|
967
978
|
on(phase, listener) {
|
|
968
979
|
const key = phase;
|
|
@@ -982,8 +993,15 @@ var EventBus = class {
|
|
|
982
993
|
}
|
|
983
994
|
emit(event) {
|
|
984
995
|
const frozen = Object.freeze(event);
|
|
985
|
-
for (const listener of this.#listeners.get(event.phase) ?? []) listener
|
|
986
|
-
for (const listener of this.#listeners.get("*") ?? []) listener
|
|
996
|
+
for (const listener of this.#listeners.get(event.phase) ?? []) this.#dispatch(listener, frozen);
|
|
997
|
+
for (const listener of this.#listeners.get("*") ?? []) this.#dispatch(listener, frozen);
|
|
998
|
+
}
|
|
999
|
+
#dispatch(listener, event) {
|
|
1000
|
+
try {
|
|
1001
|
+
listener(event);
|
|
1002
|
+
} catch (e) {
|
|
1003
|
+
this.#onListenerError(e, event);
|
|
1004
|
+
}
|
|
987
1005
|
}
|
|
988
1006
|
};
|
|
989
1007
|
/**
|
|
@@ -996,9 +1014,17 @@ var SerializingMemoryStore = class {
|
|
|
996
1014
|
constructor(inner) {
|
|
997
1015
|
this.#inner = inner;
|
|
998
1016
|
}
|
|
1017
|
+
/** 当前链上的 scope 数(监控/测试用;空闲时应回落到 0) */
|
|
1018
|
+
get trackedScopeCount() {
|
|
1019
|
+
return this.#chains.size;
|
|
1020
|
+
}
|
|
999
1021
|
#serialize(scope, fn) {
|
|
1000
1022
|
const next = (this.#chains.get(scope) ?? Promise.resolve()).then(fn, fn);
|
|
1001
|
-
|
|
1023
|
+
const guarded = next.catch(() => void 0);
|
|
1024
|
+
this.#chains.set(scope, guarded);
|
|
1025
|
+
guarded.then(() => {
|
|
1026
|
+
if (this.#chains.get(scope) === guarded) this.#chains.delete(scope);
|
|
1027
|
+
});
|
|
1002
1028
|
return next;
|
|
1003
1029
|
}
|
|
1004
1030
|
get(scope, key) {
|
|
@@ -1058,7 +1084,6 @@ var RunTerminated = class extends Error {
|
|
|
1058
1084
|
/** bridge.request 自身异常(非超时):恢复 running 后转为工具错误回喂 */
|
|
1059
1085
|
var BridgeRequestError = class extends Error {};
|
|
1060
1086
|
const baseName = (p) => p.split("/").pop() ?? p;
|
|
1061
|
-
const messageOf$1 = (e) => e instanceof Error ? e.message : String(e);
|
|
1062
1087
|
const toolError = (code, message) => ({
|
|
1063
1088
|
ok: false,
|
|
1064
1089
|
content: [],
|
|
@@ -1086,6 +1111,7 @@ var AgentLoop = class {
|
|
|
1086
1111
|
totalTimeoutMs: config.totalTimeoutMs ?? 12e4,
|
|
1087
1112
|
toolTimeoutMs: config.toolTimeoutMs ?? 3e4,
|
|
1088
1113
|
toolResultMaxBytes: config.toolResultMaxBytes ?? 1e5,
|
|
1114
|
+
paramHistoryLimit: config.paramHistoryLimit ?? 50,
|
|
1089
1115
|
temperature: config.temperature,
|
|
1090
1116
|
renderResult: config.renderResult
|
|
1091
1117
|
};
|
|
@@ -1144,7 +1170,7 @@ var AgentLoop = class {
|
|
|
1144
1170
|
try {
|
|
1145
1171
|
return await source.listToolSpecs();
|
|
1146
1172
|
} catch (e) {
|
|
1147
|
-
trace.record("run.warning", { message: `External tool source "${source.kind}" failed to list specs: ${messageOf
|
|
1173
|
+
trace.record("run.warning", { message: `External tool source "${source.kind}" failed to list specs: ${messageOf(e)}` });
|
|
1148
1174
|
return [];
|
|
1149
1175
|
}
|
|
1150
1176
|
}))).flat();
|
|
@@ -1162,7 +1188,7 @@ var AgentLoop = class {
|
|
|
1162
1188
|
try {
|
|
1163
1189
|
return await this.#turnLoop(state, 1, externalSpecs);
|
|
1164
1190
|
} catch (e) {
|
|
1165
|
-
if (e instanceof WebSkillError && e.code === "RUN_FAILED") return this.#finish(state, "failed", "hook-error", messageOf
|
|
1191
|
+
if (e instanceof WebSkillError && e.code === "RUN_FAILED") return this.#finish(state, "failed", "hook-error", messageOf(e), "RUN_FAILED");
|
|
1166
1192
|
throw e;
|
|
1167
1193
|
}
|
|
1168
1194
|
}
|
|
@@ -1192,73 +1218,77 @@ var AgentLoop = class {
|
|
|
1192
1218
|
const { llm } = this.#deps;
|
|
1193
1219
|
const { trace, messages } = state;
|
|
1194
1220
|
this.#armDeadline(state);
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
response = llm.stream ? await this.#completeStreaming(llm, state, {
|
|
1213
|
-
model: this.#deps.model,
|
|
1214
|
-
messages,
|
|
1215
|
-
tools: toolSpecs,
|
|
1216
|
-
temperature: this.#config.temperature,
|
|
1217
|
-
signal: state.controller.signal
|
|
1218
|
-
}) : await llm.complete({
|
|
1219
|
-
model: this.#deps.model,
|
|
1220
|
-
messages,
|
|
1221
|
-
tools: toolSpecs,
|
|
1222
|
-
temperature: this.#config.temperature,
|
|
1223
|
-
signal: state.controller.signal
|
|
1224
|
-
});
|
|
1225
|
-
} catch (e) {
|
|
1226
|
-
if (state.controller.signal.aborted) return finish("failed", "timeout", `Agent loop exceeded the total timeout of ${state.totalTimeoutMs}ms`, "RUN_TIMEOUT");
|
|
1227
|
-
const code = e instanceof WebSkillError && (e.code === "LLM_UNAVAILABLE" || e.code === "LLM_REQUEST_FAILED") ? e.code : "LLM_REQUEST_FAILED";
|
|
1228
|
-
return finish("failed", "llm-error", messageOf$1(e), code);
|
|
1229
|
-
}
|
|
1230
|
-
trace.record("llm.response", { data: {
|
|
1231
|
-
turn,
|
|
1232
|
-
hasToolCalls: Boolean(response.toolCalls?.length),
|
|
1233
|
-
contentLength: response.content?.length ?? 0
|
|
1234
|
-
} });
|
|
1235
|
-
if (!response.toolCalls?.length) {
|
|
1236
|
-
messages.push({
|
|
1237
|
-
role: "assistant",
|
|
1238
|
-
content: response.content ?? ""
|
|
1239
|
-
});
|
|
1240
|
-
return finish("completed", "final-answer", response.content ?? "");
|
|
1241
|
-
}
|
|
1242
|
-
await this.#lifecycle("execute", state, { turn });
|
|
1243
|
-
messages.push({
|
|
1244
|
-
role: "assistant",
|
|
1245
|
-
content: response.content ?? "",
|
|
1246
|
-
toolCalls: response.toolCalls
|
|
1247
|
-
});
|
|
1248
|
-
for (const call of response.toolCalls) {
|
|
1249
|
-
let result;
|
|
1221
|
+
try {
|
|
1222
|
+
for (let turn = startTurn;; turn++) {
|
|
1223
|
+
state.turn = turn;
|
|
1224
|
+
if (turn > state.maxTurns) return finish("failed", "max-turns", `Agent loop exceeded the maximum of ${state.maxTurns} turns`, "RUN_MAX_TURNS_EXCEEDED");
|
|
1225
|
+
if (this.#elapsed(state) > state.totalTimeoutMs) return finish("failed", "timeout", `Agent loop exceeded the total timeout of ${state.totalTimeoutMs}ms`, "RUN_TIMEOUT");
|
|
1226
|
+
const toolSpecs = [
|
|
1227
|
+
toLlmToolSpec(READ_SKILL_FILE_TOOL),
|
|
1228
|
+
...this.#deps.uiBridge ? [toLlmToolSpec(ASK_USER_TOOL)] : [],
|
|
1229
|
+
...[...state.activatedTools.values()].map(toLlmToolSpec),
|
|
1230
|
+
...externalSpecs
|
|
1231
|
+
];
|
|
1232
|
+
trace.record("llm.request", { data: {
|
|
1233
|
+
turn,
|
|
1234
|
+
messageCount: messages.length,
|
|
1235
|
+
toolCount: toolSpecs.length
|
|
1236
|
+
} });
|
|
1237
|
+
let response;
|
|
1250
1238
|
try {
|
|
1251
|
-
|
|
1239
|
+
response = llm.stream ? await this.#completeStreaming(llm, state, {
|
|
1240
|
+
model: this.#deps.model,
|
|
1241
|
+
messages,
|
|
1242
|
+
tools: toolSpecs,
|
|
1243
|
+
temperature: this.#config.temperature,
|
|
1244
|
+
signal: state.controller.signal
|
|
1245
|
+
}) : await llm.complete({
|
|
1246
|
+
model: this.#deps.model,
|
|
1247
|
+
messages,
|
|
1248
|
+
tools: toolSpecs,
|
|
1249
|
+
temperature: this.#config.temperature,
|
|
1250
|
+
signal: state.controller.signal
|
|
1251
|
+
});
|
|
1252
1252
|
} catch (e) {
|
|
1253
|
-
if (
|
|
1254
|
-
|
|
1253
|
+
if (state.controller.signal.aborted) return finish("failed", "timeout", `Agent loop exceeded the total timeout of ${state.totalTimeoutMs}ms`, "RUN_TIMEOUT");
|
|
1254
|
+
const code = e instanceof WebSkillError && (e.code === "LLM_UNAVAILABLE" || e.code === "LLM_REQUEST_FAILED") ? e.code : "LLM_REQUEST_FAILED";
|
|
1255
|
+
return finish("failed", "llm-error", messageOf(e), code);
|
|
1255
1256
|
}
|
|
1257
|
+
trace.record("llm.response", { data: {
|
|
1258
|
+
turn,
|
|
1259
|
+
hasToolCalls: Boolean(response.toolCalls?.length),
|
|
1260
|
+
contentLength: response.content?.length ?? 0
|
|
1261
|
+
} });
|
|
1262
|
+
if (!response.toolCalls?.length) {
|
|
1263
|
+
messages.push({
|
|
1264
|
+
role: "assistant",
|
|
1265
|
+
content: response.content ?? ""
|
|
1266
|
+
});
|
|
1267
|
+
return finish("completed", "final-answer", response.content ?? "");
|
|
1268
|
+
}
|
|
1269
|
+
await this.#lifecycle("execute", state, { turn });
|
|
1256
1270
|
messages.push({
|
|
1257
|
-
role: "
|
|
1258
|
-
|
|
1259
|
-
|
|
1271
|
+
role: "assistant",
|
|
1272
|
+
content: response.content ?? "",
|
|
1273
|
+
toolCalls: response.toolCalls
|
|
1260
1274
|
});
|
|
1275
|
+
for (const call of response.toolCalls) {
|
|
1276
|
+
let result;
|
|
1277
|
+
try {
|
|
1278
|
+
result = await this.#executeCall(call, state);
|
|
1279
|
+
} catch (e) {
|
|
1280
|
+
if (e instanceof RunTerminated) return finish(e.outcome.status, e.outcome.reason, e.outcome.message, e.outcome.code);
|
|
1281
|
+
throw e;
|
|
1282
|
+
}
|
|
1283
|
+
messages.push({
|
|
1284
|
+
role: "tool",
|
|
1285
|
+
toolCallId: call.id,
|
|
1286
|
+
content: await this.#serializeToolResult(call, result, state)
|
|
1287
|
+
});
|
|
1288
|
+
}
|
|
1261
1289
|
}
|
|
1290
|
+
} finally {
|
|
1291
|
+
this.#disarmDeadline(state);
|
|
1262
1292
|
}
|
|
1263
1293
|
}
|
|
1264
1294
|
/** 统一终态处理:completed/failed/cancelled;终态即删快照(快照是续命机制,审计归治理) */
|
|
@@ -1288,17 +1318,17 @@ var AgentLoop = class {
|
|
|
1288
1318
|
await bridge.renderResult(request);
|
|
1289
1319
|
trace.record("ui.rendered", { data: { blockCount: request.blocks.length } });
|
|
1290
1320
|
} catch (e) {
|
|
1291
|
-
trace.record("run.warning", { message: `renderResult failed: ${messageOf
|
|
1321
|
+
trace.record("run.warning", { message: `renderResult failed: ${messageOf(e)}` });
|
|
1292
1322
|
}
|
|
1293
1323
|
if (this.#deps.snapshotStore) try {
|
|
1294
1324
|
await this.#deps.snapshotStore.delete(state.runId);
|
|
1295
1325
|
} catch (e) {
|
|
1296
|
-
trace.record("run.warning", { message: `Failed to delete run snapshot: ${messageOf
|
|
1326
|
+
trace.record("run.warning", { message: `Failed to delete run snapshot: ${messageOf(e)}` });
|
|
1297
1327
|
}
|
|
1298
1328
|
try {
|
|
1299
1329
|
await this.#lifecycle(status === "completed" ? "complete" : "fail", state, { reason });
|
|
1300
1330
|
} catch (e) {
|
|
1301
|
-
trace.record("run.warning", { message: `Terminal lifecycle hook failed: ${messageOf
|
|
1331
|
+
trace.record("run.warning", { message: `Terminal lifecycle hook failed: ${messageOf(e)}` });
|
|
1302
1332
|
}
|
|
1303
1333
|
run.trace = trace.list();
|
|
1304
1334
|
return {
|
|
@@ -1325,6 +1355,7 @@ var AgentLoop = class {
|
|
|
1325
1355
|
interactionExpiresAt: state.run.interruptExpiresAt,
|
|
1326
1356
|
renderBlocks: [...state.renderBlocks],
|
|
1327
1357
|
interactionSeq: state.interactionSeq,
|
|
1358
|
+
pausedMs: state.pausedMs,
|
|
1328
1359
|
config: {
|
|
1329
1360
|
maxTurns: state.maxTurns,
|
|
1330
1361
|
totalTimeoutMs: state.totalTimeoutMs,
|
|
@@ -1336,7 +1367,7 @@ var AgentLoop = class {
|
|
|
1336
1367
|
try {
|
|
1337
1368
|
await store.save(snapshot);
|
|
1338
1369
|
} catch (e) {
|
|
1339
|
-
state.trace.record("run.warning", { message: `Failed to save run snapshot: ${messageOf
|
|
1370
|
+
state.trace.record("run.warning", { message: `Failed to save run snapshot: ${messageOf(e)}` });
|
|
1340
1371
|
}
|
|
1341
1372
|
}
|
|
1342
1373
|
/**
|
|
@@ -1372,7 +1403,7 @@ var AgentLoop = class {
|
|
|
1372
1403
|
turn: snapshot.turn,
|
|
1373
1404
|
renderBlocks: (snapshot.renderBlocks ?? []).map((b) => ({ ...b })),
|
|
1374
1405
|
startMs,
|
|
1375
|
-
pausedMs: 0,
|
|
1406
|
+
pausedMs: snapshot.pausedMs ?? 0,
|
|
1376
1407
|
maxTurns: snapshot.config.maxTurns,
|
|
1377
1408
|
totalTimeoutMs: snapshot.config.totalTimeoutMs,
|
|
1378
1409
|
controller: new AbortController()
|
|
@@ -1451,14 +1482,14 @@ var AgentLoop = class {
|
|
|
1451
1482
|
try {
|
|
1452
1483
|
return await source.listToolSpecs();
|
|
1453
1484
|
} catch (e) {
|
|
1454
|
-
trace.record("run.warning", { message: `External tool source "${source.kind}" failed to list specs: ${messageOf
|
|
1485
|
+
trace.record("run.warning", { message: `External tool source "${source.kind}" failed to list specs: ${messageOf(e)}` });
|
|
1455
1486
|
return [];
|
|
1456
1487
|
}
|
|
1457
1488
|
}))).flat();
|
|
1458
1489
|
try {
|
|
1459
1490
|
return await this.#turnLoop(state, snapshot.turn + 1, externalSpecs);
|
|
1460
1491
|
} catch (e) {
|
|
1461
|
-
if (e instanceof WebSkillError && e.code === "RUN_FAILED") return this.#finish(state, "failed", "hook-error", messageOf
|
|
1492
|
+
if (e instanceof WebSkillError && e.code === "RUN_FAILED") return this.#finish(state, "failed", "hook-error", messageOf(e), "RUN_FAILED");
|
|
1462
1493
|
throw e;
|
|
1463
1494
|
}
|
|
1464
1495
|
}
|
|
@@ -1560,8 +1591,8 @@ var AgentLoop = class {
|
|
|
1560
1591
|
message: e.message,
|
|
1561
1592
|
code: "RUN_INTERACTION_TIMEOUT"
|
|
1562
1593
|
});
|
|
1563
|
-
state.trace.record("run.warning", { message: `UiBridge request failed: ${messageOf
|
|
1564
|
-
throw new BridgeRequestError(messageOf
|
|
1594
|
+
state.trace.record("run.warning", { message: `UiBridge request failed: ${messageOf(e)}` });
|
|
1595
|
+
throw new BridgeRequestError(messageOf(e));
|
|
1565
1596
|
}
|
|
1566
1597
|
if (response.cancelled) throw new RunTerminated({
|
|
1567
1598
|
status: "cancelled",
|
|
@@ -1680,7 +1711,7 @@ var AgentLoop = class {
|
|
|
1680
1711
|
};
|
|
1681
1712
|
} catch (e) {
|
|
1682
1713
|
if (e instanceof WebSkillError && e.code === "SKILL_NOT_FOUND" && (this.#deps.skillProviders?.length ?? 0) > 0) return this.#handleReadExternalSkill(skillName, pathArg, state);
|
|
1683
|
-
return toolError(e instanceof WebSkillError ? e.code : "TOOL_EXECUTION_FAILED", `read_skill_file failed: ${messageOf
|
|
1714
|
+
return toolError(e instanceof WebSkillError ? e.code : "TOOL_EXECUTION_FAILED", `read_skill_file failed: ${messageOf(e)}`);
|
|
1684
1715
|
}
|
|
1685
1716
|
}
|
|
1686
1717
|
/** 经外部技能提供者读取技能文档/资源;skillKey 为技能名或 mcp:// URI */
|
|
@@ -1720,7 +1751,7 @@ var AgentLoop = class {
|
|
|
1720
1751
|
}]
|
|
1721
1752
|
};
|
|
1722
1753
|
} catch (e) {
|
|
1723
|
-
failures.push(messageOf
|
|
1754
|
+
failures.push(messageOf(e));
|
|
1724
1755
|
continue;
|
|
1725
1756
|
}
|
|
1726
1757
|
const detail = failures.length > 0 ? ` (provider errors: ${failures.join("; ")})` : "";
|
|
@@ -1734,14 +1765,20 @@ var AgentLoop = class {
|
|
|
1734
1765
|
const text = JSON.stringify(result);
|
|
1735
1766
|
const max = this.#config.toolResultMaxBytes;
|
|
1736
1767
|
if (text.length <= max) return text;
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1768
|
+
let note;
|
|
1769
|
+
try {
|
|
1770
|
+
note = `full tool result saved as artifact "${(await this.#deps.artifactStore.createTextArtifact({
|
|
1771
|
+
runId: state.runId,
|
|
1772
|
+
path: `tool-results/${call.id}.json`,
|
|
1773
|
+
content: text
|
|
1774
|
+
})).id}"`;
|
|
1775
|
+
} catch (e) {
|
|
1776
|
+
state.trace.record("run.warning", { message: `Failed to persist oversized tool result artifact for "${call.name}": ${messageOf(e)}` });
|
|
1777
|
+
note = "full result discarded (artifact store unavailable)";
|
|
1778
|
+
}
|
|
1742
1779
|
const head = text.slice(0, Math.floor(max * .6));
|
|
1743
1780
|
const tail = text.slice(-Math.floor(max * .3));
|
|
1744
|
-
return `${head}\n...[truncated ${text.length - head.length - tail.length} chars;
|
|
1781
|
+
return `${head}\n...[truncated ${text.length - head.length - tail.length} chars; ${note}]...\n${tail}`;
|
|
1745
1782
|
}
|
|
1746
1783
|
/** SkillStateGuard 判定(无注入默认全放行;仅显式 false 拦截) */
|
|
1747
1784
|
async #guardDenied(kind, skillName) {
|
|
@@ -1774,7 +1811,7 @@ var AgentLoop = class {
|
|
|
1774
1811
|
if (rawAllowed !== void 0) if (Array.isArray(rawAllowed)) allowedTools = rawAllowed.filter((e) => typeof e === "string");
|
|
1775
1812
|
else state.trace.record("run.warning", { message: `Skill "${skillName}" has a non-array "allowed-tools" metadata entry; ignored` });
|
|
1776
1813
|
} catch (e) {
|
|
1777
|
-
state.trace.record("run.warning", { message: `Failed to read or parse SKILL.md of skill "${skillName}": ${messageOf
|
|
1814
|
+
state.trace.record("run.warning", { message: `Failed to read or parse SKILL.md of skill "${skillName}": ${messageOf(e)}` });
|
|
1778
1815
|
}
|
|
1779
1816
|
const executor = this.#deps.executor;
|
|
1780
1817
|
const loaded = [];
|
|
@@ -1795,7 +1832,7 @@ var AgentLoop = class {
|
|
|
1795
1832
|
state.activatedTools.set(def.name, def);
|
|
1796
1833
|
loaded.push(def.name);
|
|
1797
1834
|
} catch (e) {
|
|
1798
|
-
state.trace.record("run.warning", { message: `Failed to load definition of script "${match[1]}" for skill "${skillName}": ${messageOf
|
|
1835
|
+
state.trace.record("run.warning", { message: `Failed to load definition of script "${match[1]}" for skill "${skillName}": ${messageOf(e)}` });
|
|
1799
1836
|
}
|
|
1800
1837
|
}
|
|
1801
1838
|
}
|
|
@@ -1821,7 +1858,7 @@ var AgentLoop = class {
|
|
|
1821
1858
|
def.inputSchema = JSON.parse(await this.#deps.fs.readText(sidecar));
|
|
1822
1859
|
return;
|
|
1823
1860
|
} catch (e) {
|
|
1824
|
-
state.trace.record("run.warning", { message: `Failed to parse schema sidecar ${sidecar}: ${messageOf
|
|
1861
|
+
state.trace.record("run.warning", { message: `Failed to parse schema sidecar ${sidecar}: ${messageOf(e)}` });
|
|
1825
1862
|
}
|
|
1826
1863
|
if (!this.#deps.schemaInferer) return;
|
|
1827
1864
|
for (const ext of ["ts", "js"]) {
|
|
@@ -1831,7 +1868,7 @@ var AgentLoop = class {
|
|
|
1831
1868
|
const inferred = this.#deps.schemaInferer.inferSchemaFromSource(await this.#deps.fs.readText(scriptPath), { fileName: `${scriptName}.${ext}` });
|
|
1832
1869
|
if (inferred) def.inputSchema = inferred;
|
|
1833
1870
|
} catch (e) {
|
|
1834
|
-
state.trace.record("run.warning", { message: `Schema inference failed for ${scriptPath}: ${messageOf
|
|
1871
|
+
state.trace.record("run.warning", { message: `Schema inference failed for ${scriptPath}: ${messageOf(e)}` });
|
|
1835
1872
|
}
|
|
1836
1873
|
return;
|
|
1837
1874
|
}
|
|
@@ -1892,7 +1929,7 @@ var AgentLoop = class {
|
|
|
1892
1929
|
} catch (e) {
|
|
1893
1930
|
if (e instanceof RunTerminated) throw e;
|
|
1894
1931
|
await this.#bumpSkillStat(skillName, "failures", state);
|
|
1895
|
-
return toolError(e instanceof WebSkillError ? e.code : "TOOL_EXECUTION_FAILED", `Tool "${call.name}" failed: ${messageOf
|
|
1932
|
+
return toolError(e instanceof WebSkillError ? e.code : "TOOL_EXECUTION_FAILED", `Tool "${call.name}" failed: ${messageOf(e)}`);
|
|
1896
1933
|
}
|
|
1897
1934
|
}
|
|
1898
1935
|
/** context.confirm 触发点:默认真实询问;auto-approve 直通;无 bridge 降级直通 + warning */
|
|
@@ -1931,7 +1968,7 @@ var AgentLoop = class {
|
|
|
1931
1968
|
try {
|
|
1932
1969
|
await this.#deps.memory?.set(scope, key, value);
|
|
1933
1970
|
} catch (e) {
|
|
1934
|
-
state.trace.record("run.warning", { message: `Memory write failed: ${messageOf
|
|
1971
|
+
state.trace.record("run.warning", { message: `Memory write failed: ${messageOf(e)}` });
|
|
1935
1972
|
}
|
|
1936
1973
|
}
|
|
1937
1974
|
/** read-modify-write:有 transaction 实现在 scope 原子段内执行(并发不丢计数),否则顺序执行 */
|
|
@@ -1944,7 +1981,7 @@ var AgentLoop = class {
|
|
|
1944
1981
|
await inner.set(scope, key, mutate(await inner.get(scope, key)));
|
|
1945
1982
|
});
|
|
1946
1983
|
} catch (e) {
|
|
1947
|
-
state.trace.record("run.warning", { message: `Memory write failed: ${messageOf
|
|
1984
|
+
state.trace.record("run.warning", { message: `Memory write failed: ${messageOf(e)}` });
|
|
1948
1985
|
}
|
|
1949
1986
|
return;
|
|
1950
1987
|
}
|
|
@@ -1979,6 +2016,7 @@ var AgentLoop = class {
|
|
|
1979
2016
|
async #appendParamHistory(state, request, value) {
|
|
1980
2017
|
if (!this.#deps.memory) return;
|
|
1981
2018
|
const scope = `session:${state.run.sessionId}`;
|
|
2019
|
+
const limit = this.#config.paramHistoryLimit;
|
|
1982
2020
|
await this.#memoryMutate(scope, "paramHistory", state, (current) => {
|
|
1983
2021
|
const history = current ?? [];
|
|
1984
2022
|
history.push({
|
|
@@ -1987,7 +2025,7 @@ var AgentLoop = class {
|
|
|
1987
2025
|
type: request.type,
|
|
1988
2026
|
value
|
|
1989
2027
|
});
|
|
1990
|
-
return history;
|
|
2028
|
+
return history.slice(-limit);
|
|
1991
2029
|
});
|
|
1992
2030
|
}
|
|
1993
2031
|
};
|
|
@@ -2074,6 +2112,24 @@ var FsRunSnapshotStore = class {
|
|
|
2074
2112
|
}
|
|
2075
2113
|
};
|
|
2076
2114
|
/**
|
|
2115
|
+
* session history 滚动裁剪:超出预算时裁掉中段,保留首尾。
|
|
2116
|
+
* 边界对齐 LLM tool 契约:head 不以未应答的 assistant toolCalls 结尾,
|
|
2117
|
+
* tail 不以孤儿 tool 消息开头(其 assistant 调用已随中段裁掉)。
|
|
2118
|
+
*/
|
|
2119
|
+
function trimSessionHistory(messages, max) {
|
|
2120
|
+
if (max < 2 || messages.length <= max) return messages;
|
|
2121
|
+
let head = Math.ceil(max / 2);
|
|
2122
|
+
while (head > 0) {
|
|
2123
|
+
const last = messages[head - 1];
|
|
2124
|
+
if (last.role === "assistant" && last.toolCalls?.length) head -= 1;
|
|
2125
|
+
else break;
|
|
2126
|
+
}
|
|
2127
|
+
let tailStart = Math.max(head, messages.length - (max - head));
|
|
2128
|
+
while (tailStart < messages.length && messages[tailStart].role === "tool") tailStart += 1;
|
|
2129
|
+
if (tailStart >= messages.length) return messages.slice(-max);
|
|
2130
|
+
return [...messages.slice(0, head), ...messages.slice(tailStart)];
|
|
2131
|
+
}
|
|
2132
|
+
/**
|
|
2077
2133
|
* runtime 门面:组合 discovery / router / agent loop / lifecycle
|
|
2078
2134
|
* @stable
|
|
2079
2135
|
*/
|
|
@@ -2118,20 +2174,28 @@ var WebSkillRuntime = class {
|
|
|
2118
2174
|
/**
|
|
2119
2175
|
* 多会话:session 对象的 run(prompt) 跨 run 延续消息历史(同一 session 对话上下文连续)。
|
|
2120
2176
|
* 既有 runtime.run(prompt) 保持无状态单次语义不变。
|
|
2177
|
+
* 同 handle 并发 run 经 per-handle 队列串行化(防历史 last-writer-wins 丢轮次);
|
|
2178
|
+
* maxHistoryMessages(默认 100)超出时滚动裁剪中段(保留首尾;边界对齐 tool 契约)。
|
|
2121
2179
|
*/
|
|
2122
2180
|
createSession(options = {}) {
|
|
2123
2181
|
const sessionId = options.sessionId ?? `session-${Math.random().toString(36).slice(2, 10)}`;
|
|
2124
2182
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2183
|
+
const maxHistory = options.maxHistoryMessages ?? 100;
|
|
2125
2184
|
let history = [];
|
|
2185
|
+
let queue = Promise.resolve();
|
|
2126
2186
|
return {
|
|
2127
2187
|
id: sessionId,
|
|
2128
2188
|
createdAt,
|
|
2129
|
-
run:
|
|
2130
|
-
const result =
|
|
2131
|
-
|
|
2132
|
-
|
|
2189
|
+
run: (prompt) => {
|
|
2190
|
+
const result = queue.then(async () => {
|
|
2191
|
+
const r = await this.run(prompt, {
|
|
2192
|
+
sessionId,
|
|
2193
|
+
history
|
|
2194
|
+
});
|
|
2195
|
+
history = trimSessionHistory(r.messages.slice(1), maxHistory);
|
|
2196
|
+
return r;
|
|
2133
2197
|
});
|
|
2134
|
-
|
|
2198
|
+
queue = result.then(() => void 0, () => void 0);
|
|
2135
2199
|
return result;
|
|
2136
2200
|
}
|
|
2137
2201
|
};
|
|
@@ -2379,7 +2443,6 @@ function sourceFromUrl(url) {
|
|
|
2379
2443
|
path: url
|
|
2380
2444
|
};
|
|
2381
2445
|
}
|
|
2382
|
-
const messageOf = (e) => e instanceof Error ? e.message : String(e);
|
|
2383
2446
|
/** 受控钩子执行器:逐个执行,超时/异常默认降级为 warning,可切严格模式 */
|
|
2384
2447
|
var HookRunner = class {
|
|
2385
2448
|
#hooks = /* @__PURE__ */ new Map();
|
|
@@ -2637,6 +2700,67 @@ function networkUrlHost(url) {
|
|
|
2637
2700
|
return "(unparseable-url)";
|
|
2638
2701
|
}
|
|
2639
2702
|
}
|
|
2703
|
+
/** WebSkillErrorCode 全量白名单(错误码归一用;与 core errors.ts 保持同步) */
|
|
2704
|
+
const WHITELIST = /* @__PURE__ */ new Set([
|
|
2705
|
+
"FS_NOT_FOUND",
|
|
2706
|
+
"FS_PATH_OUTSIDE_ROOT",
|
|
2707
|
+
"SKILL_NOT_FOUND",
|
|
2708
|
+
"SKILL_INVALID_METADATA",
|
|
2709
|
+
"SKILL_INVALID_NAME",
|
|
2710
|
+
"SKILL_DUPLICATE_NAME",
|
|
2711
|
+
"SKILL_UNSUPPORTED_SCRIPT",
|
|
2712
|
+
"VALIDATION_FAILED",
|
|
2713
|
+
"TOOL_NOT_FOUND",
|
|
2714
|
+
"TOOL_EXECUTION_FAILED",
|
|
2715
|
+
"NETWORK_BLOCKED",
|
|
2716
|
+
"TOOL_UNSUPPORTED",
|
|
2717
|
+
"TOOL_SCHEMA_UNAVAILABLE",
|
|
2718
|
+
"RUN_TIMEOUT",
|
|
2719
|
+
"RUN_MAX_TURNS_EXCEEDED",
|
|
2720
|
+
"RUN_FAILED",
|
|
2721
|
+
"RUN_CANCELLED",
|
|
2722
|
+
"RUN_INTERACTION_TIMEOUT",
|
|
2723
|
+
"UI_UNAVAILABLE",
|
|
2724
|
+
"LLM_UNAVAILABLE",
|
|
2725
|
+
"LLM_REQUEST_FAILED",
|
|
2726
|
+
"INSTALL_FAILED",
|
|
2727
|
+
"UNINSTALL_FAILED",
|
|
2728
|
+
"EXPORT_FAILED",
|
|
2729
|
+
"INTEGRITY_FAILED",
|
|
2730
|
+
"FS_PERMISSION_DENIED",
|
|
2731
|
+
"MCP_ENDPOINT_UNAVAILABLE",
|
|
2732
|
+
"MCP_TOOL_NOT_FOUND",
|
|
2733
|
+
"CANDIDATE_INVALID",
|
|
2734
|
+
"APPROVAL_REQUIRED",
|
|
2735
|
+
"SKILL_QUARANTINED",
|
|
2736
|
+
"SKILL_DISABLED",
|
|
2737
|
+
"SKILL_UNKNOWN_ALLOWED_TOOL",
|
|
2738
|
+
"SKILL_UNKNOWN_DEPENDENCY",
|
|
2739
|
+
"SKILL_CIRCULAR_DEPENDENCY",
|
|
2740
|
+
"GOVERNANCE_FAILED",
|
|
2741
|
+
"RUN_SNAPSHOT_NOT_FOUND",
|
|
2742
|
+
"RUN_SNAPSHOT_EXPIRED",
|
|
2743
|
+
"RUN_SNAPSHOT_INCOMPATIBLE"
|
|
2744
|
+
]);
|
|
2745
|
+
/**
|
|
2746
|
+
* 错误码白名单归一:沙箱/桥消息里出现的非白名单码(DOMException 数值码、
|
|
2747
|
+
* Node 任意 ERR_* 码等)一律归为 TOOL_EXECUTION_FAILED。
|
|
2748
|
+
*/
|
|
2749
|
+
function normalizeErrorCode(code) {
|
|
2750
|
+
return typeof code === "string" && WHITELIST.has(code) ? code : "TOOL_EXECUTION_FAILED";
|
|
2751
|
+
}
|
|
2752
|
+
/** 归一化后的 (code, message):非白名单码保留在 message 尾部([original code: X]) */
|
|
2753
|
+
function normalizeToolError(code, message) {
|
|
2754
|
+
const normalized = normalizeErrorCode(code);
|
|
2755
|
+
if (typeof code === "string" && normalized === code) return {
|
|
2756
|
+
code: normalized,
|
|
2757
|
+
message
|
|
2758
|
+
};
|
|
2759
|
+
return {
|
|
2760
|
+
code: normalized,
|
|
2761
|
+
message: `${message} [original code: ${String(code)}]`
|
|
2762
|
+
};
|
|
2763
|
+
}
|
|
2640
2764
|
/**
|
|
2641
2765
|
* Per-capability 强制授权判定(宿主侧,browser/node 执行器共用单一来源)。
|
|
2642
2766
|
* 'require-approval' 模式下经注入的 UiBridge 发 authorize 交互;
|
|
@@ -2661,6 +2785,7 @@ var CapabilityApproval = class CapabilityApproval {
|
|
|
2661
2785
|
async authorize(input) {
|
|
2662
2786
|
const { runId, capability, mode } = input;
|
|
2663
2787
|
if (mode === false) return "disabled";
|
|
2788
|
+
if (mode !== true && mode !== "require-approval") return "disabled";
|
|
2664
2789
|
if (mode !== "require-approval") return "allowed";
|
|
2665
2790
|
if (this.#scope === "once-per-run" && this.#approved.get(runId)?.has(capability)) return "allowed";
|
|
2666
2791
|
if (!this.#uiBridge) return "denied";
|
|
@@ -2688,4 +2813,4 @@ var CapabilityApproval = class CapabilityApproval {
|
|
|
2688
2813
|
};
|
|
2689
2814
|
|
|
2690
2815
|
//#endregion
|
|
2691
|
-
export { isNetworkAllowed as A, bridgeError as C, extractChartSpec as D, createWebSkillApi as E,
|
|
2816
|
+
export { isNetworkAllowed as A, toVercelToolSpecs as B, bridgeError as C, extractChartSpec as D, createWebSkillApi as E, normalizeToolError as F, parseBridgeRequest as I, resolveToolName as L, networkUrlHost as M, normalizeErrorCode as N, fromVercelResult as O, normalizeToolContent as P, schemaToForm as R, WebSkillRuntime as S, createScriptContext as T, READ_SKILL_FILE_TOOL as _, AnthropicClient as a, SerializingMemoryStore as b, FsArtifactStore as c, FullDisclosureRouter as d, GoogleGenAiClient as f, READ_SKILL_FILE_INPUT_SCHEMA as g, ProgressiveRouter as h, AgentLoop as i, mergeCatalogEntries as j, fromVercelStreamPart as k, FsMemoryStore as l, OpenAiCompatibleClient as m, ASK_USER_TOOL as n, CapabilityApproval as o, HookRunner as p, ASK_USER_TOOL_NAME as r, EventBus as s, ASK_USER_INPUT_SCHEMA as t, FsRunSnapshotStore as u, READ_SKILL_FILE_TOOL_NAME as v, buildRenderResult as w, TraceRecorder as x, RUN_SNAPSHOT_SCHEMA_VERSION as y, toLlmToolSpec as z };
|