@webskill/sdk 0.12.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/agent.d.ts +3 -3
  2. package/dist/agent.js +3 -3
  3. package/dist/browser.d.ts +250 -9
  4. package/dist/browser.js +1257 -95
  5. package/dist/{catalogComponents-BgAJN0p8-C3K8klJd.js → catalogComponents-BgAJN0p8-Cr55ouOg.js} +348 -14
  6. package/dist/{dist-sdKFgERo.js → dist-Bfga1TmS.js} +368 -34
  7. package/dist/{dist-DU9KDAuR.js → dist-BnqAkSS6.js} +965 -49
  8. package/dist/{dist-DqcL6jKO.js → dist-CiaDIqkV.js} +2 -2
  9. package/dist/{dist-Bev6i6Ip.js → dist-D5YhlCdY.js} +59 -1
  10. package/dist/governance.d.ts +3 -3
  11. package/dist/governance.js +2 -2
  12. package/dist/{index-C9pzXLKy.d.ts → index-CWoKOFBP.d.ts} +86 -5
  13. package/dist/{index-DFhU1uks.d.ts → index-DQwGvHAI.d.ts} +447 -22
  14. package/dist/{index-3fCHc1mQ.d.ts → index-sd-gVKey.d.ts} +2 -2
  15. package/dist/index.d.ts +4 -4
  16. package/dist/index.js +5 -5
  17. package/dist/mcp.d.ts +77 -3
  18. package/dist/mcp.js +78 -4
  19. package/dist/{memoryArtifactStore-52Zn9npI-LbCQaqyx.js → memoryArtifactStore-52Zn9npI-BxtUkrgV.js} +1 -1
  20. package/dist/node.d.ts +3 -3
  21. package/dist/node.js +6 -6
  22. package/dist/{openUiLibrary-BKXW7Iwx-DaymVubt.js → openUiLibrary-BKXW7Iwx-DjvEnMlJ.js} +2 -2
  23. package/dist/{skillVersionStore-D-qHk9ZE-DheTIwAB.d.ts → skillVersionStore-D-qHk9ZE-C0OFDTQY.d.ts} +1 -1
  24. package/dist/{testing-WPTyXQYt.js → testing-Cm8MseLF.js} +2 -2
  25. package/dist/testing.d.ts +1 -1
  26. package/dist/testing.js +2 -2
  27. package/dist/{types-DLctJep_-B5G4uk2u.d.ts → types-C3V6lAeO-BgeOvc1Y.d.ts} +63 -4
  28. package/dist/ui-react.d.ts +2 -2
  29. package/dist/ui-react.js +13 -11
  30. package/dist/ui-vue.d.ts +1 -1
  31. package/dist/ui-vue.js +1 -1
  32. package/dist/ui.d.ts +3 -3
  33. package/dist/ui.js +2 -2
  34. package/dist/{webskillLitCatalog-D_zCqeQF-C9lrvvMr.js → webskillLitCatalog-D_zCqeQF-swXsWoAe.js} +1 -1
  35. package/package.json +2 -1
@@ -1,5 +1,5 @@
1
- import { K as validateSkills, M as messageOf, P as parseSkillMarkdown, R as renderAvailableSkillsXml, V as resolveInsideRoot, _ as assertSafePathSegment, g as assertRemoteUrlAllowed, h as WebSkillError, m as SkillReader, p as SkillDiscovery, v as atomicWriteText, y as buildCatalog } from "./dist-Bev6i6Ip.js";
2
- import { a as textParts, i as rejectUnsupportedPart, n as partsToText, o as validateLlmMessages, r as promptText, t as MemoryArtifactStore } from "./memoryArtifactStore-52Zn9npI-LbCQaqyx.js";
1
+ import { B as messageOf, C as assertSafePathSegment, H as parseSkillMarkdown, K as renderAvailableSkillsXml, S as assertRemoteUrlAllowed, T as buildCatalog, Y as resolveInsideRoot, _ as SkillDiscovery, b as WebSkillError, et as validateSkills, v as SkillReader, w as atomicWriteText } from "./dist-D5YhlCdY.js";
2
+ import { a as textParts, i as rejectUnsupportedPart, n as partsToText, o as validateLlmMessages, r as promptText, t as MemoryArtifactStore } from "./memoryArtifactStore-52Zn9npI-BxtUkrgV.js";
3
3
 
4
4
  //#region ../runtime/dist/index.js
5
5
  /** 与正常工具结果同构:模型读到的是「这次调用被中断了」,而不是一个凭空消失的调用 */
@@ -607,6 +607,76 @@ function createSseFrameReader() {
607
607
  }
608
608
  };
609
609
  }
610
+ /**
611
+ * 内联 `<think>` 段落切分器(内部模块,不进公开导出)。
612
+ *
613
+ * 本地部署的思考型模型(Qwen 等经 OpenAI 兼容端点)不下发 `reasoning_content`,
614
+ * 而是把推理直接写进 `content`,用 `<think>` … `</think>` 包起来。不切分的话
615
+ * 思考正文会当成回答正文流进界面、进消息历史、进落盘,既污染上下文也没法折叠。
616
+ */
617
+ const OPEN = "<think>";
618
+ const CLOSE = "</think>";
619
+ /** buffer 是否为 tag 的真前缀(还不能判定,得再等) */
620
+ const isPartialPrefix = (buffer, tag) => buffer.length < tag.length && tag.startsWith(buffer);
621
+ function createThinkTagSplitter() {
622
+ let buffer = "";
623
+ let inThink = false;
624
+ const consume = () => {
625
+ let text = "";
626
+ let thinking = "";
627
+ for (;;) {
628
+ const tag = inThink ? CLOSE : OPEN;
629
+ const hit = buffer.indexOf(tag);
630
+ if (hit >= 0) {
631
+ const before = buffer.slice(0, hit);
632
+ if (inThink) thinking += before;
633
+ else text += before;
634
+ buffer = buffer.slice(hit + tag.length);
635
+ inThink = !inThink;
636
+ continue;
637
+ }
638
+ const start = buffer.lastIndexOf("<");
639
+ const keep = start >= 0 && isPartialPrefix(buffer.slice(start), tag) ? start : buffer.length;
640
+ const emit = buffer.slice(0, keep);
641
+ if (inThink) thinking += emit;
642
+ else text += emit;
643
+ buffer = buffer.slice(keep);
644
+ return {
645
+ text,
646
+ thinking
647
+ };
648
+ }
649
+ };
650
+ return {
651
+ push(delta) {
652
+ buffer += delta;
653
+ return consume();
654
+ },
655
+ flush() {
656
+ const rest = buffer;
657
+ buffer = "";
658
+ return inThink ? {
659
+ text: "",
660
+ thinking: rest
661
+ } : {
662
+ text: rest,
663
+ thinking: ""
664
+ };
665
+ }
666
+ };
667
+ }
668
+ /** 非流式整段切分:返回正文与思考正文(无 `<think>` 时 thinking 为 undefined) */
669
+ function splitThinkTags(content) {
670
+ if (!content.includes(OPEN)) return { text: content };
671
+ const splitter = createThinkTagSplitter();
672
+ const first = splitter.push(content);
673
+ const last = splitter.flush();
674
+ const thinking = first.thinking + last.thinking;
675
+ return {
676
+ text: first.text + last.text,
677
+ ...thinking !== "" ? { thinking } : {}
678
+ };
679
+ }
610
680
  const dataUrl = (part) => `data:${part.mimeType};base64,${part.data}`;
611
681
  /** parts → OpenAI content;纯文本折叠成字符串(兼容端点对数组形态支持不一) */
612
682
  const toOpenAiContent = (parts, where) => {
@@ -712,6 +782,7 @@ var OpenAiCompatibleClient = class {
712
782
  const decoder = new TextDecoder();
713
783
  const reader = res.body.getReader();
714
784
  const frames = createSseFrameReader();
785
+ const think = createThinkTagSplitter();
715
786
  let done = false;
716
787
  let usage;
717
788
  const handleFrame = function* (data) {
@@ -736,10 +807,17 @@ var OpenAiCompatibleClient = class {
736
807
  type: "thinking-delta",
737
808
  delta: delta["reasoning_content"]
738
809
  };
739
- if (typeof delta["content"] === "string" && delta["content"] !== "") yield {
740
- type: "text-delta",
741
- delta: delta["content"]
742
- };
810
+ if (typeof delta["content"] === "string" && delta["content"] !== "") {
811
+ const split = think.push(delta["content"]);
812
+ if (split.thinking !== "") yield {
813
+ type: "thinking-delta",
814
+ delta: split.thinking
815
+ };
816
+ if (split.text !== "") yield {
817
+ type: "text-delta",
818
+ delta: split.text
819
+ };
820
+ }
743
821
  const toolDeltas = delta["tool_calls"];
744
822
  for (const td of toolDeltas ?? []) {
745
823
  const index = td.index ?? 0;
@@ -767,6 +845,15 @@ var OpenAiCompatibleClient = class {
767
845
  } finally {
768
846
  reader.releaseLock();
769
847
  }
848
+ const tail = think.flush();
849
+ if (tail.thinking !== "") yield {
850
+ type: "thinking-delta",
851
+ delta: tail.thinking
852
+ };
853
+ if (tail.text !== "") yield {
854
+ type: "text-delta",
855
+ delta: tail.text
856
+ };
770
857
  if (toolCallsByIndex.size > 0) yield {
771
858
  type: "tool-calls",
772
859
  toolCalls: [...toolCallsByIndex.entries()].sort(([a], [b]) => a - b).map(([index, acc]) => {
@@ -822,7 +909,7 @@ var OpenAiCompatibleClient = class {
822
909
  }
823
910
  if (!res.ok) {
824
911
  const detail = await res.text().catch(() => "");
825
- throw new WebSkillError("LLM_REQUEST_FAILED", `LLM request failed with HTTP ${res.status}${detail ? `: ${detail.slice(0, 500)}` : ""}`);
912
+ throw new WebSkillError("LLM_REQUEST_FAILED", `LLM request failed with HTTP ${res.status}${detail ? `: ${detail.slice(0, 500)}` : ""}`, { status: res.status });
826
913
  }
827
914
  return res;
828
915
  }
@@ -854,15 +941,21 @@ var OpenAiCompatibleClient = class {
854
941
  ...parseError ? { argumentsParseError: parseError } : {}
855
942
  };
856
943
  });
857
- const content = choice["content"];
858
- const thinking = choice["reasoning_content"];
944
+ const raw = choice["content"];
945
+ const split = typeof raw === "string" ? splitThinkTags(raw) : {
946
+ text: "",
947
+ thinking: void 0
948
+ };
949
+ const content = split.text;
950
+ const declared = choice["reasoning_content"];
951
+ const thinking = typeof declared === "string" && declared !== "" ? declared : split.thinking;
859
952
  const usageRaw = data.usage;
860
953
  const usage = usageRaw && (typeof usageRaw["prompt_tokens"] === "number" || typeof usageRaw["completion_tokens"] === "number") ? {
861
954
  inputTokens: typeof usageRaw["prompt_tokens"] === "number" ? usageRaw["prompt_tokens"] : 0,
862
955
  outputTokens: typeof usageRaw["completion_tokens"] === "number" ? usageRaw["completion_tokens"] : 0
863
956
  } : void 0;
864
957
  return {
865
- content: typeof content === "string" && content !== "" ? textParts(content) : void 0,
958
+ content: content !== "" ? textParts(content) : void 0,
866
959
  toolCalls: toolCalls?.length ? toolCalls : void 0,
867
960
  ...typeof thinking === "string" && thinking !== "" ? { thinking } : {},
868
961
  ...usage ? { usage } : {},
@@ -1123,7 +1216,7 @@ var AnthropicClient = class {
1123
1216
  }
1124
1217
  if (!res.ok) {
1125
1218
  const detail = await res.text().catch(() => "");
1126
- throw new WebSkillError("LLM_REQUEST_FAILED", `LLM request failed with HTTP ${res.status}${detail ? `: ${detail.slice(0, 500)}` : ""}`);
1219
+ throw new WebSkillError("LLM_REQUEST_FAILED", `LLM request failed with HTTP ${res.status}${detail ? `: ${detail.slice(0, 500)}` : ""}`, { status: res.status });
1127
1220
  }
1128
1221
  return res;
1129
1222
  }
@@ -1388,7 +1481,7 @@ var GoogleGenAiClient = class {
1388
1481
  }
1389
1482
  if (!res.ok) {
1390
1483
  const detail = await res.text().catch(() => "");
1391
- throw new WebSkillError("LLM_REQUEST_FAILED", `LLM request failed with HTTP ${res.status}${detail ? `: ${detail.slice(0, 500)}` : ""}`);
1484
+ throw new WebSkillError("LLM_REQUEST_FAILED", `LLM request failed with HTTP ${res.status}${detail ? `: ${detail.slice(0, 500)}` : ""}`, { status: res.status });
1392
1485
  }
1393
1486
  return res;
1394
1487
  }
@@ -2469,6 +2562,12 @@ function sampleBehaviorRecords(records, limits = DEFAULT_USER_PROFILE_LIMITS) {
2469
2562
  * 最后一句是重点:不明说「没有工具」,模型会凭训练记忆自己编造 tool_call 标记。
2470
2563
  */
2471
2564
  const PLAIN_CHAT_SYSTEM_PROMPT = "You are a helpful assistant. Answer the user's question directly and concisely. You have no tools available; do not describe or simulate tool calls.";
2565
+ /**
2566
+ * 按需披露的系统提示(分册 19 / FR-19.7)。
2567
+ * 只在本 run 确实存在按需工具时追加——没有按需工具却说「有些工具没列出来」,
2568
+ * 是在教模型怀疑一个完整的工具表。
2569
+ */
2570
+ const ON_DEMAND_TOOLS_HINT = "Some tools are disclosed on demand and are not listed above. If a capability you need seems missing, look for a related skill in the catalog and read its SKILL.md first — activating it may reveal additional tools. Do not conclude the capability does not exist.";
2472
2571
  const READ_LINKED_DOCUMENT_TOOL_NAME = "read_linked_document";
2473
2572
  /**
2474
2573
  * 能直接给模型用的 MIME。其余一律拒绝并列出这份清单——
@@ -2476,14 +2575,15 @@ const READ_LINKED_DOCUMENT_TOOL_NAME = "read_linked_document";
2476
2575
  */
2477
2576
  const SUPPORTED_DOCUMENT_MIME = {
2478
2577
  pdf: "application/pdf",
2479
- docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
2578
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
2579
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
2480
2580
  };
2481
2581
  /** 引擎侧固定流程(§2.3)用到的错误文案,集中一处便于判据引用 */
2482
- const UNSUPPORTED_DOCUMENT_MESSAGE = `Only PDF (${SUPPORTED_DOCUMENT_MIME.pdf}), Word (${SUPPORTED_DOCUMENT_MIME.docx}) and plain text documents can be read.`;
2582
+ const UNSUPPORTED_DOCUMENT_MESSAGE = `Only PDF (${SUPPORTED_DOCUMENT_MIME.pdf}), Word (${SUPPORTED_DOCUMENT_MIME.docx}), Excel (${SUPPORTED_DOCUMENT_MIME.xlsx}) and plain text documents can be read.`;
2483
2583
  /**
2484
2584
  * 内建工具:读页面链接指向的文档。
2485
2585
  *
2486
- * **始终注册**(只要宿主装配了 reader):docx 与纯文本这条路对所有模型成立。
2586
+ * **始终注册**(只要宿主装配了 reader):docx / xlsx 与纯文本这条路对所有模型成立。
2487
2587
  * PDF 目标在模型不支持文档时**取数后拒绝**,而不是入口就拦 ——
2488
2588
  * 入口拦会误伤 docx,它抽成文本后根本不需要文档能力。
2489
2589
  */
@@ -2506,6 +2606,10 @@ function toBase64(bytes) {
2506
2606
  for (const byte of bytes) binary += String.fromCharCode(byte);
2507
2607
  return btoa(binary);
2508
2608
  }
2609
+ /** `toBase64` 的逆;分片里的文档要交回抽取器时用(0.13.0 FR-22.3) */
2610
+ function fromBase64(data) {
2611
+ return Uint8Array.from(atob(data), (char) => char.charCodeAt(0));
2612
+ }
2509
2613
  /** 结构化 trace 记录器;时钟与 id 工厂可注入(golden trace 用固定值保证确定性) */
2510
2614
  var TraceRecorder = class {
2511
2615
  #runId;
@@ -2745,6 +2849,30 @@ function evaluateToolAccess(state, llmToolName) {
2745
2849
  };
2746
2850
  }
2747
2851
  /**
2852
+ * 分册 19 诊断(FR-19.6):某条模式在给定工具名集合里有没有命中过。
2853
+ * 与点名判定分开,是因为这里问的是「作者写的这条规则有没有意义」,不是「某个工具能不能进上下文」。
2854
+ */
2855
+ function patternMatchesAnyTool(pattern, declaringSkill, llmToolNames, activated) {
2856
+ for (const name of llmToolNames) if (matchesPattern(pattern, declaringSkill, name, canonicalToolName(name, activated))) return true;
2857
+ return false;
2858
+ }
2859
+ /**
2860
+ * 分册 19 的点名判定:**有没有某个已激活技能显式声明了这个工具**。
2861
+ *
2862
+ * 与 `evaluateToolAccess` 回答的不是同一个问题(那个回答「允不允许调用」,
2863
+ * 这个回答「要不要写进上下文」),因此故意不复用它,两处关键差异:
2864
+ * 1. 无人声明 ⇒ 这里返回 **false**(没人点名),那里返回 true(不受限);
2865
+ * 2. 不含一票否决——某个技能没写清单,不影响另一个技能点名成功。
2866
+ */
2867
+ function isNamedByActivatedSkill(state, llmToolName) {
2868
+ const canonical = canonicalToolName(llmToolName, state.activated);
2869
+ for (const [skill, patterns] of state.skillAllowedTools) {
2870
+ if (!state.activated.has(skill)) continue;
2871
+ for (const pattern of patterns) if (matchesPattern(pattern, skill, llmToolName, canonical)) return true;
2872
+ }
2873
+ return false;
2874
+ }
2875
+ /**
2748
2876
  * 参数敏感标注关键字(分册 30 / FR-30.3)。
2749
2877
  *
2750
2878
  * 不用 `format: 'password'`:`format` 是 JSON Schema 的规范关键字,provider 侧
@@ -2818,6 +2946,41 @@ const LLM_TURN_CODES = /* @__PURE__ */ new Set([
2818
2946
  "LLM_REQUEST_FAILED",
2819
2947
  "TOOL_SCHEMA_UNAVAILABLE"
2820
2948
  ]);
2949
+ /**
2950
+ * 模型侧图片通道收得下的位图格式(三家 provider 的交集)。
2951
+ * SVG 是文本、`application/octet-stream` 是未知字节——两者编成 data URL 发出去,
2952
+ * 端点当场 400(LM Studio:`'url' field must be a base64 encoded image.`),
2953
+ * 页面里一个内联图标就能把整次 run 打死。这不是「预判模型能不能读」,
2954
+ * 是这些字节根本进不了图片分片。
2955
+ */
2956
+ const MODEL_IMAGE_MIME_TYPES = /* @__PURE__ */ new Set([
2957
+ "image/png",
2958
+ "image/jpeg",
2959
+ "image/webp",
2960
+ "image/gif"
2961
+ ]);
2962
+ /**
2963
+ * 数据源清单里的出处标注(0.14.0 分册 21,FR-21.6)。
2964
+ *
2965
+ * 措辞必须说出「这段说明来自页面、可能不准确」:`description` 已在候选层剥掉换行与控制字符,
2966
+ * 它无法把自己伪装成上下文里的新一行指令——**剥换行与这句标注是一对,只做一件都不够**。
2967
+ */
2968
+ const DATA_SOURCE_PROVENANCE_NOTE = {
2969
+ "": "",
2970
+ "page-declared": " [declared by the current site; this description comes from the page and may be inaccurate]",
2971
+ "tool-projection": " [projected from a tool the current site registered; this description comes from the page and may be inaccurate]"
2972
+ };
2973
+ /** 分片是不是 PDF;mime 允许带参数与大小写差异,与 FR-11.1 的判定同口径 */
2974
+ const isPdfPart = (part) => part.type === "file" && part.mimeType.split(";")[0]?.trim().toLowerCase() === SUPPORTED_DOCUMENT_MIME.pdf;
2975
+ /**
2976
+ * LLM 客户端在 HTTP 失败时放进 `details` 的状态码(FR-22.2)。
2977
+ * 判不出来返回 undefined——网络层异常没有状态码,回退对它没有意义。
2978
+ */
2979
+ const httpStatusOf = (e) => {
2980
+ if (!(e instanceof WebSkillError) || typeof e.details !== "object" || e.details === null) return void 0;
2981
+ const status = e.details.status;
2982
+ return typeof status === "number" ? status : void 0;
2983
+ };
2821
2984
  /** 交互终态(取消/超时):从工具执行深处直接终止 run */
2822
2985
  var RunTerminated = class extends Error {
2823
2986
  outcome;
@@ -2842,6 +3005,16 @@ const summarizeArgs = (args) => {
2842
3005
  const json = JSON.stringify(args);
2843
3006
  return json.length > 100 ? `${json.slice(0, 100)}…` : json;
2844
3007
  };
3008
+ /**
3009
+ * 图片分片投不出去时换成一条说明(与超预算文档同一处置),多张合并成一条——
3010
+ * 一个页面上十几个内联图标各报一遍会把工具结果淹掉。
3011
+ * 静默丢掉会让模型以为自己看过了;直接发出去则整次请求 400,一张图连累全程。
3012
+ */
3013
+ const undeliverableImageNote = (parts, toolName) => {
3014
+ const formats = [...new Set(parts.map((p) => p.type === "image" ? p.mimeType : ""))].join(", ");
3015
+ return `${parts.length === 1 ? "1 image" : `${parts.length} images`} from "${toolName}" ${parts.length === 1 ? "was" : "were"} not attached: ${formats} cannot be sent as model image input, which accepts only ${[...MODEL_IMAGE_MIME_TYPES].join(", ")}. Rely on the surrounding text, or ask for a raster version.`;
3016
+ };
3017
+ const isDeliverableImage = (part) => part.type !== "image" || MODEL_IMAGE_MIME_TYPES.has(part.mimeType.split(";")[0]?.trim().toLowerCase() ?? "");
2845
3018
  /** 外部工具的 inputSchema 索引(分册 30);run 开始与 resume 各重建一次 */
2846
3019
  function indexExternalToolSchemas(state, specs) {
2847
3020
  state.externalToolSchemas.clear();
@@ -2972,6 +3145,9 @@ var AgentLoop = class {
2972
3145
  activatedTools: /* @__PURE__ */ new Map(),
2973
3146
  skillAllowedTools: /* @__PURE__ */ new Map(),
2974
3147
  warnedDeniedTools: /* @__PURE__ */ new Set(),
3148
+ externalToolSources: /* @__PURE__ */ new Map(),
3149
+ withheldTools: /* @__PURE__ */ new Set(),
3150
+ pdfFallbackDone: false,
2975
3151
  integrityVerdicts: /* @__PURE__ */ new Map(),
2976
3152
  toolTimeoutMs: this.#config.toolTimeoutMs,
2977
3153
  now,
@@ -3024,7 +3200,19 @@ var AgentLoop = class {
3024
3200
  trace.record("run.warning", { message: `External tool source "${source.kind}" failed to build a system prompt: ${messageOf(e)}` });
3025
3201
  }
3026
3202
  }
3027
- const systemPrompt = this.#config.toolCallingDisabled ? PLAIN_CHAT_SYSTEM_PROMPT : [route.systemPrompt, ...externalSystemPrompts].join("\n\n");
3203
+ const hasOnDemand = !this.#config.toolCallingDisabled && externalSpecs.some((spec) => {
3204
+ const source = state.externalToolSources.get(spec.name);
3205
+ try {
3206
+ return source?.disclosure?.(spec.name) === "on-demand";
3207
+ } catch {
3208
+ return false;
3209
+ }
3210
+ });
3211
+ const systemPrompt = this.#config.toolCallingDisabled ? PLAIN_CHAT_SYSTEM_PROMPT : [
3212
+ route.systemPrompt,
3213
+ ...externalSystemPrompts,
3214
+ ...hasOnDemand ? [ON_DEMAND_TOOLS_HINT] : []
3215
+ ].join("\n\n");
3028
3216
  const profileMessage = await this.#userProfileMessage(state);
3029
3217
  state.messages = [
3030
3218
  {
@@ -3083,6 +3271,44 @@ var AgentLoop = class {
3083
3271
  }
3084
3272
  return false;
3085
3273
  }
3274
+ /**
3275
+ * 分册 19 暴露点:外部工具本轮是否披露。
3276
+ *
3277
+ * 与 `#checkToolAccess` 是两个问题:那个回答「允不允许调用」,这个只回答「要不要写进上下文」。
3278
+ * 未披露**不影响可执行性**——分发点不看它,模型硬调照样执行(FR-19.5)。
3279
+ */
3280
+ #disclosed(state, llmToolName) {
3281
+ const source = state.externalToolSources.get(llmToolName);
3282
+ if (source?.disclosure === void 0) return true;
3283
+ let level;
3284
+ try {
3285
+ level = source.disclosure(llmToolName);
3286
+ } catch (e) {
3287
+ state.trace.record("run.warning", { message: `External tool source "${source.kind}" failed to report a disclosure level for "${llmToolName}"; treating it as always disclosed: ${messageOf(e)}` });
3288
+ return true;
3289
+ }
3290
+ if (level !== "on-demand") return true;
3291
+ if (isNamedByActivatedSkill(state, llmToolName)) return true;
3292
+ if (!state.withheldTools.has(llmToolName)) {
3293
+ state.withheldTools.add(llmToolName);
3294
+ state.trace.record("tool.withheld", {
3295
+ message: `Tool "${llmToolName}" is disclosed on demand and was not requested by any activated skill`,
3296
+ data: { name: llmToolName }
3297
+ });
3298
+ }
3299
+ return false;
3300
+ }
3301
+ /**
3302
+ * FR-19.6:技能声明的外部工具模式一个已知工具都没命中时告警。
3303
+ * 端点名拼错是最常见的失误,而它的表现是「工具静静地不出现」——不告警就无从排查。
3304
+ */
3305
+ #warnUnmatchedToolPatterns(state, skillName, patterns) {
3306
+ for (const pattern of patterns) {
3307
+ if (!pattern.includes(":") && !pattern.includes("#")) continue;
3308
+ if (patternMatchesAnyTool(pattern, skillName, state.externalToolSources.keys(), state.activated)) continue;
3309
+ state.trace.record("run.warning", { message: `Skill "${skillName}" declares allowed-tools pattern "${pattern}", but it matches no known tool.` });
3310
+ }
3311
+ }
3086
3312
  /** 分发点被拒时回喂给模型的结构化错误(不抛异常:模型造名字是常态,抛异常会终止整个 run) */
3087
3313
  #deniedToolError(state, toolName) {
3088
3314
  return toolError("TOOL_NOT_ALLOWED", evaluateToolAccess(state, toolName).reason ?? `Tool "${toolName}" is not allowed`);
@@ -3098,7 +3324,9 @@ var AgentLoop = class {
3098
3324
  state.turn = turn;
3099
3325
  if (turn > state.maxTurns) return finish("failed", "max-turns", `Agent loop exceeded the maximum of ${state.maxTurns} turns`, "RUN_MAX_TURNS_EXCEEDED");
3100
3326
  if (this.#elapsed(state) > state.totalTimeoutMs) return finish("failed", "timeout", `Agent loop exceeded the total timeout of ${state.totalTimeoutMs}ms`, "RUN_TIMEOUT");
3101
- const skillToolSpecs = [...[...state.activatedTools.values()].map(toLlmToolSpec), ...externalSpecs].filter((spec) => this.#checkToolAccess(state, spec.name));
3327
+ const scriptToolSpecs = [...state.activatedTools.values()].map(toLlmToolSpec).filter((spec) => this.#checkToolAccess(state, spec.name));
3328
+ const externalToolSpecs = externalSpecs.filter((spec) => this.#disclosed(state, spec.name));
3329
+ const skillToolSpecs = [...scriptToolSpecs, ...externalToolSpecs];
3102
3330
  const toolSpecs = this.#config.toolCallingDisabled ? [] : [
3103
3331
  toLlmToolSpec(READ_SKILL_FILE_TOOL),
3104
3332
  ...this.#deps.uiBridge ? [toLlmToolSpec(ASK_USER_TOOL)] : [],
@@ -3130,8 +3358,12 @@ var AgentLoop = class {
3130
3358
  if (this.#cancelled.has(state.runId)) return finish("cancelled", "user-cancelled", "Run cancelled by user", "RUN_CANCELLED");
3131
3359
  return finish("failed", "timeout", `Agent loop exceeded the total timeout of ${state.totalTimeoutMs}ms`, "RUN_TIMEOUT");
3132
3360
  }
3361
+ if (await this.#fallbackPdfToText(state, e)) {
3362
+ turn--;
3363
+ continue;
3364
+ }
3133
3365
  const code = e instanceof WebSkillError && LLM_TURN_CODES.has(e.code) ? e.code : "LLM_REQUEST_FAILED";
3134
- const hint = messages.some((message) => Array.isArray(message.content) && message.content.some((part) => part.type === "file")) ? " This turn attached a document; the selected model may not accept document input. Try another model, or link a Word or text file instead." : "";
3366
+ const hint = state.pdfFallbackDone ? " The attached PDF was re-sent as extracted text after the endpoint rejected the original file, and that attempt failed as well." : messages.some((message) => message.content.some(isPdfPart)) ? " This turn attached a document; the selected model may not accept document input. Try another model, or link a Word or text file instead." : "";
3135
3367
  return finish("failed", "llm-error", `${messageOf(e)}${hint}`, code);
3136
3368
  }
3137
3369
  if (response.thinking !== void 0 && response.thinking !== "") {
@@ -3364,6 +3596,9 @@ var AgentLoop = class {
3364
3596
  activatedTools: new Map(snapshot.activatedTools.map((d) => [d.name, d])),
3365
3597
  skillAllowedTools: new Map(Object.entries(snapshot.skillAllowedTools ?? {})),
3366
3598
  warnedDeniedTools: /* @__PURE__ */ new Set(),
3599
+ externalToolSources: /* @__PURE__ */ new Map(),
3600
+ withheldTools: /* @__PURE__ */ new Set(),
3601
+ pdfFallbackDone: false,
3367
3602
  integrityVerdicts: /* @__PURE__ */ new Map(),
3368
3603
  toolTimeoutMs: snapshot.config.toolTimeoutMs,
3369
3604
  now,
@@ -3686,9 +3921,12 @@ var AgentLoop = class {
3686
3921
  }
3687
3922
  /** 外部工具 specs:单个来源失败跳过并记 warning(run 开始与 resume 共用) */
3688
3923
  async #collectExternalSpecs(state) {
3924
+ state.externalToolSources.clear();
3689
3925
  return (await Promise.all((this.#deps.externalTools ?? []).map(async (source) => {
3690
3926
  try {
3691
- return await source.listToolSpecs();
3927
+ const specs = await source.listToolSpecs();
3928
+ for (const spec of specs) state.externalToolSources.set(spec.name, source);
3929
+ return specs;
3692
3930
  } catch (e) {
3693
3931
  state.trace.record("run.warning", { message: `External tool source "${source.kind}" failed to list specs: ${messageOf(e)}` });
3694
3932
  return [];
@@ -3776,17 +4014,15 @@ var AgentLoop = class {
3776
4014
  else if (call.name === "read_skill_file") result = await this.#handleReadSkillFile(call, state);
3777
4015
  else if (call.name === "ask_user") result = await this.#handleAskUser(call, state);
3778
4016
  else if (call.name === "read_linked_document" && this.#deps.linkedDocuments !== void 0) result = await this.#handleReadLinkedDocument(call, state);
3779
- else if (!this.#checkToolAccess(state, call.name)) result = this.#deniedToolError(state, call.name);
3780
4017
  else {
3781
4018
  const resolution = resolveToolName(call.name, state.activated, state.activatedTools.keys());
3782
- if (resolution.kind === "script") result = await this.#handleScriptTool(call, resolution.skillName, resolution.scriptName, state);
4019
+ const source = resolution.kind === "script" ? void 0 : (this.#deps.externalTools ?? []).find((s) => s.canHandle(call.name));
4020
+ if (source === void 0 && !this.#checkToolAccess(state, call.name)) result = this.#deniedToolError(state, call.name);
4021
+ else if (resolution.kind === "script") result = await this.#handleScriptTool(call, resolution.skillName, resolution.scriptName, state);
4022
+ else if (source) result = await source.call(call.name, call.arguments, { runId: state.runId });
3783
4023
  else {
3784
- const source = (this.#deps.externalTools ?? []).find((s) => s.canHandle(call.name));
3785
- if (source) result = await source.call(call.name, call.arguments);
3786
- else {
3787
- if (resolution.kind === "not-found") state.unknownToolCalls += 1;
3788
- result = toolError(resolution.code, resolution.message, resolution.kind === "not-found" ? resolution.data : void 0);
3789
- }
4024
+ if (resolution.kind === "not-found") state.unknownToolCalls += 1;
4025
+ result = toolError(resolution.code, resolution.message, resolution.kind === "not-found" ? resolution.data : void 0);
3790
4026
  }
3791
4027
  }
3792
4028
  const durationMs = Date.parse(state.now()) - callStartMs;
@@ -4177,17 +4413,20 @@ var AgentLoop = class {
4177
4413
  };
4178
4414
  }
4179
4415
  let text;
4180
- if (mime === SUPPORTED_DOCUMENT_MIME.docx) {
4181
- if (this.#deps.docxExtractor === void 0) {
4416
+ if (mime === SUPPORTED_DOCUMENT_MIME.docx || mime === SUPPORTED_DOCUMENT_MIME.xlsx) {
4417
+ const docx = mime === SUPPORTED_DOCUMENT_MIME.docx;
4418
+ const kind = docx ? "docx" : "xlsx";
4419
+ const extractor = docx ? this.#deps.docxExtractor : this.#deps.xlsxExtractor;
4420
+ if (extractor === void 0) {
4182
4421
  await audit({
4183
4422
  ...record,
4184
4423
  ok: false,
4185
- reason: "no docx extractor"
4424
+ reason: `no ${kind} extractor`
4186
4425
  });
4187
- return toolError("TOOL_UNSUPPORTED", "Word documents cannot be read in this environment: no docx text extractor is configured.");
4426
+ return toolError("TOOL_UNSUPPORTED", `${docx ? "Word documents" : "Excel workbooks"} cannot be read in this environment: no ${kind} text extractor is configured.`);
4188
4427
  }
4189
4428
  try {
4190
- text = await this.#deps.docxExtractor(fetched.bytes);
4429
+ text = await extractor(fetched.bytes);
4191
4430
  } catch (e) {
4192
4431
  const message = messageOf(e);
4193
4432
  await audit({
@@ -4398,6 +4637,57 @@ var AgentLoop = class {
4398
4637
  return toolError("SKILL_NOT_FOUND", `Skill not found via external providers: ${skillKey}${detail}`);
4399
4638
  }
4400
4639
  /**
4640
+ * 端点拒收 PDF 后,把消息里的 PDF 分片换成抽取文本,让本轮可以重发(FR-22.2 / FR-22.3)。
4641
+ * 返回 true 表示已改写、调用方应重试本轮;返回 false 表示走原有失败路径。
4642
+ */
4643
+ async #fallbackPdfToText(state, cause) {
4644
+ const extract = this.#deps.pdfExtractor;
4645
+ if (extract === void 0 || state.pdfFallbackDone) return false;
4646
+ const status = httpStatusOf(cause);
4647
+ if (status === void 0 || status < 400 || status >= 500) return false;
4648
+ if (!state.messages.some((message) => message.content.some(isPdfPart))) return false;
4649
+ state.pdfFallbackDone = true;
4650
+ let converted = 0;
4651
+ for (const message of state.messages) for (let i = 0; i < message.content.length; i++) {
4652
+ const part = message.content[i];
4653
+ if (part === void 0 || !isPdfPart(part)) continue;
4654
+ message.content[i] = {
4655
+ type: "text",
4656
+ text: await this.#pdfAsText(state, part, extract)
4657
+ };
4658
+ converted++;
4659
+ }
4660
+ state.trace.record("run.warning", {
4661
+ message: `The endpoint rejected ${converted} attached PDF file(s) with HTTP ${status}; they were replaced with extracted text and the turn was retried. Original error: ${messageOf(cause)}`,
4662
+ data: {
4663
+ converted,
4664
+ status
4665
+ }
4666
+ });
4667
+ return converted > 0;
4668
+ }
4669
+ /** 单个 PDF 分片 → 文本;包装形态与 chatEngine 的附件标签同口径(FR-22.3 / FR-22.4) */
4670
+ async #pdfAsText(state, part, extract) {
4671
+ const name = part.name ?? "document.pdf";
4672
+ const label = (note) => `--- Attachment: ${name} (${SUPPORTED_DOCUMENT_MIME.pdf}, ${note}) ---\n`;
4673
+ let text;
4674
+ try {
4675
+ text = await extract(fromBase64(part.data));
4676
+ } catch (e) {
4677
+ return `${label("text extraction failed")}${messageOf(e)}`;
4678
+ }
4679
+ if (text.trim() === "") return `${label("no extractable text")}This PDF has no text layer, so its contents could not be extracted. It is most likely a scan or an image-only export. Tell the user this instead of guessing what it contains.`;
4680
+ const id = `doc-${state.runId}-${++state.documentSeq}`;
4681
+ const tooLarge = this.#documentTooLarge({
4682
+ type: "document-text",
4683
+ text,
4684
+ name,
4685
+ id
4686
+ });
4687
+ if (tooLarge !== void 0) return `${label("not attached")}${tooLarge}`;
4688
+ return `${label("extracted text")}${text}`;
4689
+ }
4690
+ /**
4401
4691
  * 超预算的文档分片换成一条说明(FR-23.4)。**不截断**:
4402
4692
  * 半份 PDF 是坏文件,半份抽取文本会让模型以为自己读全了。
4403
4693
  */
@@ -4441,6 +4731,7 @@ var AgentLoop = class {
4441
4731
  };
4442
4732
  const notes = [];
4443
4733
  const carried = [];
4734
+ const undeliverable = [];
4444
4735
  for (const part of passthrough) {
4445
4736
  const tooLarge = this.#documentTooLarge(part);
4446
4737
  if (tooLarge) {
@@ -4448,6 +4739,10 @@ var AgentLoop = class {
4448
4739
  notes.push(tooLarge);
4449
4740
  continue;
4450
4741
  }
4742
+ if (!isDeliverableImage(part)) {
4743
+ undeliverable.push(part);
4744
+ continue;
4745
+ }
4451
4746
  if (part.type === "image") carried.push({
4452
4747
  type: "image",
4453
4748
  mimeType: part.mimeType,
@@ -4461,6 +4756,11 @@ var AgentLoop = class {
4461
4756
  });
4462
4757
  else if (part.type === "document-text") notes.push(part.text);
4463
4758
  }
4759
+ if (undeliverable.length > 0) {
4760
+ const note = undeliverableImageNote(undeliverable, call.name);
4761
+ state.trace.record("run.warning", { message: note });
4762
+ notes.push(note);
4763
+ }
4464
4764
  return {
4465
4765
  tool: [
4466
4766
  {
@@ -4500,7 +4800,9 @@ var AgentLoop = class {
4500
4800
  }
4501
4801
  const head = text.slice(0, Math.floor(max * .6));
4502
4802
  const tail = text.slice(-Math.floor(max * .3));
4503
- return `${head}\n...[truncated ${text.length - head.length - tail.length} chars; ${note}]...\n${tail}`;
4803
+ const omitted = text.length - head.length - tail.length;
4804
+ state.trace.record("run.warning", { message: `Tool result for "${call.name}" exceeded ${String(max)} chars and was truncated in the middle; ${String(omitted)} chars omitted (${note}).` });
4805
+ return `${head}\n...[truncated ${omitted} chars; ${note}]...\n${tail}`;
4504
4806
  }
4505
4807
  /** SkillStateGuard 判定(无注入默认全放行;仅显式 false 拦截) */
4506
4808
  async #guardDenied(kind, skillName) {
@@ -4569,6 +4871,7 @@ var AgentLoop = class {
4569
4871
  if (!root) return "";
4570
4872
  let allowedTools;
4571
4873
  let dependencies = [];
4874
+ let declaredSources = [];
4572
4875
  try {
4573
4876
  const { metadata } = parseSkillMarkdown(skillMdText ?? await this.#deps.fs.readText(`${root}/SKILL.md`));
4574
4877
  const rawDeps = metadata["dependencies"];
@@ -4577,7 +4880,11 @@ var AgentLoop = class {
4577
4880
  if (rawAllowed !== void 0) if (Array.isArray(rawAllowed)) {
4578
4881
  allowedTools = rawAllowed.filter((e) => typeof e === "string");
4579
4882
  state.skillAllowedTools.set(skillName, allowedTools);
4883
+ this.#warnUnmatchedToolPatterns(state, skillName, allowedTools);
4580
4884
  } else state.trace.record("run.warning", { message: `Skill "${skillName}" has a non-array "allowed-tools" metadata entry; ignored` });
4885
+ const rawSources = metadata["data-sources"];
4886
+ if (rawSources !== void 0) if (Array.isArray(rawSources)) declaredSources = rawSources.filter((e) => typeof e === "string");
4887
+ else state.trace.record("run.warning", { message: `Skill "${skillName}" has a non-array "data-sources" metadata entry; ignored` });
4581
4888
  } catch (e) {
4582
4889
  state.trace.record("run.warning", { message: `Failed to read or parse SKILL.md of skill "${skillName}": ${messageOf(e)}` });
4583
4890
  }
@@ -4613,6 +4920,7 @@ var AgentLoop = class {
4613
4920
  }
4614
4921
  }
4615
4922
  let note = (loaded.length ? `\n\nActivated tools: ${loaded.join(", ")}` : "") + formatSkillScriptManifest(scripts);
4923
+ note += this.#dataSourceNotice(skillName, declaredSources, state);
4616
4924
  for (const dep of dependencies) {
4617
4925
  if (state.activated.has(dep)) continue;
4618
4926
  if (!this.#deps.skillIndex.has(dep)) {
@@ -4624,6 +4932,26 @@ var AgentLoop = class {
4624
4932
  return note;
4625
4933
  }
4626
4934
  /**
4935
+ * 0.14.0 分册 19:技能声明的源在本宿主缺失时,把「缺哪些 / 有哪些」写进激活回执与 trace。
4936
+ * 宿主没注入清单时一个字不说——那是「未知」,不是「没有」。
4937
+ *
4938
+ * 0.14.0 分册 21(DV-7):「有哪些」由 id 列表升级为 `<id> — <description>`,
4939
+ * 并对非宿主声明的条目附出处标注。`description` 可能来自页面,
4940
+ * 因此标注必须与它同时出现——只写说明不写出处,等于让站点以宿主口吻讲话。
4941
+ */
4942
+ #dataSourceNotice(skillName, declared, state) {
4943
+ const declaredSources = this.#deps.dataSources;
4944
+ const available = typeof declaredSources === "function" ? declaredSources() : declaredSources;
4945
+ if (declared.length === 0 || available === void 0) return "";
4946
+ const have = new Set(available.map((source) => source.id));
4947
+ const missing = declared.filter((id) => !have.has(id));
4948
+ if (missing.length === 0) return "";
4949
+ const listed = available.map((source) => `\n- ${source.id} — ${source.description}${DATA_SOURCE_PROVENANCE_NOTE[source.provenance ?? ""] ?? ""}`).join("");
4950
+ const message = `Skill "${skillName}" declares data source(s) this host does not provide: ${missing.join(", ")}. Available here:${listed || " (none)"}\nDo not retry them or invent their values; tell the user which data source is missing.`;
4951
+ state.trace.record("run.warning", { message });
4952
+ return `\n\n${message}`;
4953
+ }
4954
+ /**
4627
4955
  * D2 Schema 兜底链(同一 run 内激活时只算一次):
4628
4956
  * 显式 inputSchema > sidecar scripts/<name>.schema.json > schemaInferer 推导 > schemaUnavailable
4629
4957
  * 返回值即最终来源,进技能清单告诉模型该信谁(FR-18.1)。
@@ -5138,8 +5466,11 @@ var WebSkillRuntime = class {
5138
5466
  skillIntegrityGuard: this.#deps.skillIntegrityGuard,
5139
5467
  skillOutcomeReporter: this.#deps.skillOutcomeReporter,
5140
5468
  fetchData: this.#deps.fetchData,
5469
+ dataSources: this.#deps.dataSources,
5141
5470
  linkedDocuments: this.#deps.linkedDocuments,
5142
5471
  docxExtractor: this.#deps.docxExtractor,
5472
+ xlsxExtractor: this.#deps.xlsxExtractor,
5473
+ pdfExtractor: this.#deps.pdfExtractor,
5143
5474
  documentAudit: this.#deps.documentAudit
5144
5475
  }, this.#deps.config);
5145
5476
  const runId = `run-${Math.random().toString(36).slice(2, 10)}`;
@@ -5264,8 +5595,11 @@ var WebSkillRuntime = class {
5264
5595
  skillIntegrityGuard: this.#deps.skillIntegrityGuard,
5265
5596
  skillOutcomeReporter: this.#deps.skillOutcomeReporter,
5266
5597
  fetchData: this.#deps.fetchData,
5598
+ dataSources: this.#deps.dataSources,
5267
5599
  linkedDocuments: this.#deps.linkedDocuments,
5268
5600
  docxExtractor: this.#deps.docxExtractor,
5601
+ xlsxExtractor: this.#deps.xlsxExtractor,
5602
+ pdfExtractor: this.#deps.pdfExtractor,
5269
5603
  documentAudit: this.#deps.documentAudit
5270
5604
  }, this.#deps.config);
5271
5605
  this.#loops.set(runId, loop);
@@ -6544,4 +6878,4 @@ var FsToolStepStore = class {
6544
6878
  };
6545
6879
 
6546
6880
  //#endregion
6547
- export { bridgeError as $, ProgressiveRouter as A, refineUserProfile as At, SUPPORTED_DOCUMENT_MIME as B, toLlmToolSpec as Bt, FsSessionStore as C, normalizeToolError as Ct, HookRunner as D, readProfileEntries as Dt, GoogleGenAiClient as E, readBehaviorRecords as Et, READ_SKILL_FILE_TOOL_NAME as F, schemaToForm as Ft, USER_PROFILE_EXPORT_VERSION as G, TEXT_BUDGETED_CONTENT_TYPES as H, toVercelToolSpecs as Ht, RUN_SNAPSHOT_SCHEMA_VERSION as I, scriptToolName as It, USER_PROFILE_PROMPT_HEADER as J, USER_PROFILE_KEY as K, RUN_TRACE_SCHEMA_VERSION as L, sealToolCallPairs as Lt, READ_LINKED_DOCUMENT_TOOL_NAME as M, resolveToolName as Mt, READ_SKILL_FILE_INPUT_SCHEMA as N, sampleBehaviorRecords as Nt, MAX_TOOL_STEP_ARG_BYTES as O, readUserProfile as Ot, READ_SKILL_FILE_TOOL as P, schemaSourceLabel as Pt, applyUserProfileImport as Q, SENSITIVE_ANNOTATION as R, summarizeRunUsage as Rt, FsRunTraceStore as S, normalizeToolContent as St, FullDisclosureRouter as T, parseUserProfileExport as Tt, TraceRecorder as U, validateUiSpecEvent as Ut, SerializingMemoryStore as V, toRecordDigests as Vt, UNSUPPORTED_DOCUMENT_MESSAGE as W, validateUiSpecNode as Wt, WebSkillRuntime as X, USER_PROFILE_REFINE_PROMPT as Y, appendBehaviorRecords as Z, EventBus as _, mergeCatalogEntries as _t, ASK_USER_TOOL as a, extractChartSpec as at, FsMemoryStore as b, networkUrlHost as bt, AnthropicClient as c, extractUiSpecEvents as ct, DEFAULT_LOOP_LIMITS as d, fromVercelResult as dt, buildRenderResult as et, DEFAULT_MAX_DATA_SOURCE_BYTES as f, fromVercelStreamPart as ft, EMPTY_USER_PROFILE as g, listSkillScripts as gt, DEFAULT_USER_PROFILE_LIMITS as h, isUnsupportedRunSnapshot as ht, ASK_USER_MAX_FIELDS as i, exportUserProfile as it, READ_LINKED_DOCUMENT_TOOL as j, renderUserProfileContext as jt, OpenAiCompatibleClient as k, redactToolStepArgs as kt, BEHAVIOR_RECORDS_KEY as l, findUnpairedToolCalls as lt, DEFAULT_MAX_DOCUMENT_TEXT_BYTES as m, isNetworkAllowed as mt, ASK_USER_FIELD_TYPES as n, createWebSkillApi as nt, ASK_USER_TOOL_NAME as o, extractSkillCandidate as ot, DEFAULT_MAX_DOCUMENT_BYTES as p, interruptedToolResult as pt, USER_PROFILE_NO_INVENTION_RULE as q, ASK_USER_INPUT_SCHEMA as r, diffUserProfile as rt, AgentLoop as s, extractTodoTraceEvents as st, ALLOWED_TOOLS_EXCLUSION_REASON as t, createScriptContext as tt, CapabilityApproval as u, formatSkillScriptManifest as ut, FS_SESSION_PAGE_SIZE as v, mergeProfileEntries as vt, FsToolStepStore as w, parseBridgeRequest as wt, FsRunSnapshotStore as x, normalizeErrorCode as xt, FsArtifactStore as y, networkPolicyLibSource as yt, SESSION_SCHEMA_VERSION as z, summarizeToolCalls as zt };
6881
+ export { bridgeError as $, ProgressiveRouter as A, refineUserProfile as At, SUPPORTED_DOCUMENT_MIME as B, toBase64 as Bt, FsSessionStore as C, normalizeToolError as Ct, HookRunner as D, readProfileEntries as Dt, GoogleGenAiClient as E, readBehaviorRecords as Et, READ_SKILL_FILE_TOOL_NAME as F, schemaToForm as Ft, USER_PROFILE_EXPORT_VERSION as G, validateUiSpecNode as Gt, TEXT_BUDGETED_CONTENT_TYPES as H, toRecordDigests as Ht, RUN_SNAPSHOT_SCHEMA_VERSION as I, scriptToolName as It, USER_PROFILE_PROMPT_HEADER as J, USER_PROFILE_KEY as K, RUN_TRACE_SCHEMA_VERSION as L, sealToolCallPairs as Lt, READ_LINKED_DOCUMENT_TOOL_NAME as M, resolveToolName as Mt, READ_SKILL_FILE_INPUT_SCHEMA as N, sampleBehaviorRecords as Nt, MAX_TOOL_STEP_ARG_BYTES as O, readUserProfile as Ot, READ_SKILL_FILE_TOOL as P, schemaSourceLabel as Pt, applyUserProfileImport as Q, SENSITIVE_ANNOTATION as R, summarizeRunUsage as Rt, FsRunTraceStore as S, normalizeToolContent as St, FullDisclosureRouter as T, parseUserProfileExport as Tt, TraceRecorder as U, toVercelToolSpecs as Ut, SerializingMemoryStore as V, toLlmToolSpec as Vt, UNSUPPORTED_DOCUMENT_MESSAGE as W, validateUiSpecEvent as Wt, WebSkillRuntime as X, USER_PROFILE_REFINE_PROMPT as Y, appendBehaviorRecords as Z, EventBus as _, mergeCatalogEntries as _t, ASK_USER_TOOL as a, extractChartSpec as at, FsMemoryStore as b, networkUrlHost as bt, AnthropicClient as c, extractUiSpecEvents as ct, DEFAULT_LOOP_LIMITS as d, fromVercelResult as dt, buildRenderResult as et, DEFAULT_MAX_DATA_SOURCE_BYTES as f, fromVercelStreamPart as ft, EMPTY_USER_PROFILE as g, listSkillScripts as gt, DEFAULT_USER_PROFILE_LIMITS as h, isUnsupportedRunSnapshot as ht, ASK_USER_MAX_FIELDS as i, exportUserProfile as it, READ_LINKED_DOCUMENT_TOOL as j, renderUserProfileContext as jt, OpenAiCompatibleClient as k, redactToolStepArgs as kt, BEHAVIOR_RECORDS_KEY as l, findUnpairedToolCalls as lt, DEFAULT_MAX_DOCUMENT_TEXT_BYTES as m, isNetworkAllowed as mt, ASK_USER_FIELD_TYPES as n, createWebSkillApi as nt, ASK_USER_TOOL_NAME as o, extractSkillCandidate as ot, DEFAULT_MAX_DOCUMENT_BYTES as p, interruptedToolResult as pt, USER_PROFILE_NO_INVENTION_RULE as q, ASK_USER_INPUT_SCHEMA as r, diffUserProfile as rt, AgentLoop as s, extractTodoTraceEvents as st, ALLOWED_TOOLS_EXCLUSION_REASON as t, createScriptContext as tt, CapabilityApproval as u, formatSkillScriptManifest as ut, FS_SESSION_PAGE_SIZE as v, mergeProfileEntries as vt, FsToolStepStore as w, parseBridgeRequest as wt, FsRunSnapshotStore as x, normalizeErrorCode as xt, FsArtifactStore as y, networkPolicyLibSource as yt, SESSION_SCHEMA_VERSION as z, summarizeToolCalls as zt };