@opentiny/next-sdk 0.2.7 → 0.2.9

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.
@@ -27762,6 +27762,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
27762
27762
  this.dropdownMenu.parentNode.removeChild(this.dropdownMenu);
27763
27763
  }
27764
27764
  }
27765
+ // 隐藏组件
27766
+ hide() {
27767
+ if (this.floatingBlock) {
27768
+ this.floatingBlock.style.display = "none";
27769
+ }
27770
+ this.closeDropdown();
27771
+ }
27772
+ // 显示组件
27773
+ show() {
27774
+ if (this.floatingBlock) {
27775
+ this.floatingBlock.style.display = "flex";
27776
+ }
27777
+ }
27765
27778
  }
27766
27779
  const createRemoter = (options = {}) => {
27767
27780
  return new FloatingBlock(options);
@@ -50165,15 +50178,24 @@ Thought: 用户想要获取今天的日期,我需要调用日期相关的工
50165
50178
  }
50166
50179
  this.onUpdatedTools?.();
50167
50180
  }
50168
- /** 创建临时允许调用的tools集合 */
50169
- _tempMergeTools(extraTool = {}) {
50170
- const toolsResult = Object.values(this.mcpTools).reduce((acc, curr) => ({ ...acc, ...curr }), {});
50181
+ /** 创建临时允许调用的 tools 集合,合并 mcpTools 与 extraTool */
50182
+ _tempMergeTools(extraTool = {}, deleteIgnored = true) {
50183
+ const toolsResult = Object.values(this.mcpTools).reduce(
50184
+ (acc, curr) => ({ ...acc, ...curr }),
50185
+ {}
50186
+ );
50171
50187
  Object.assign(toolsResult, extraTool);
50172
- this.ignoreToolnames.forEach((name16) => {
50173
- delete toolsResult[name16];
50174
- });
50188
+ if (deleteIgnored) {
50189
+ this.ignoreToolnames.forEach((name16) => {
50190
+ delete toolsResult[name16];
50191
+ });
50192
+ }
50175
50193
  return toolsResult;
50176
50194
  }
50195
+ /** 获取当前激活的 tools 名称列表(过滤 ignoreToolnames) */
50196
+ _getActiveToolNames(tools) {
50197
+ return Object.keys(tools).filter((name16) => !this.ignoreToolnames.includes(name16));
50198
+ }
50177
50199
  /** 生成 ReAct 模式的系统提示词(包含工具描述) */
50178
50200
  _generateReActSystemPrompt(tools, modelName, baseSystemPrompt) {
50179
50201
  const toolsPrompt = generateReActToolsPrompt(tools);
@@ -50517,12 +50539,14 @@ ${observationText}
50517
50539
  throw new Error("LLM is not initialized");
50518
50540
  }
50519
50541
  await this.initClientsAndTools();
50542
+ const allTools = this._tempMergeTools(options.tools, false);
50520
50543
  const chatOptions = {
50521
50544
  // @ts-ignore ProviderV2 是所有llm的父类, 在每一个具体的llm 类都有一个选择model的函数用法
50522
50545
  model: this.llm(model),
50523
50546
  stopWhen: stepCountIs(maxSteps),
50524
50547
  ...options,
50525
- tools: this._tempMergeTools(options.tools)
50548
+ tools: allTools,
50549
+ activeTools: this._getActiveToolNames(allTools)
50526
50550
  };
50527
50551
  let lastUserMessage = null;
50528
50552
  if (options.message && !options.messages) {
@@ -50552,6 +50576,282 @@ ${observationText}
50552
50576
  return this._chat(streamText, options);
50553
50577
  }
50554
50578
  }
50579
+ let overlayElement = null;
50580
+ let labelElement = null;
50581
+ let styleElement = null;
50582
+ let activeCount = 0;
50583
+ const BODY_GLOW_CLASS = "next-sdk-tool-body-glow";
50584
+ function ensureDomReady() {
50585
+ return typeof window !== "undefined" && typeof document !== "undefined";
50586
+ }
50587
+ function ensureStyleElement() {
50588
+ if (!ensureDomReady()) return;
50589
+ if (styleElement) return;
50590
+ const style = document.createElement("style");
50591
+ style.textContent = `
50592
+ .${BODY_GLOW_CLASS} {
50593
+ position: relative;
50594
+ }
50595
+
50596
+ .next-sdk-tool-overlay {
50597
+ position: fixed;
50598
+ inset: 0;
50599
+ z-index: 999999;
50600
+ pointer-events: none;
50601
+ display: flex;
50602
+ align-items: flex-end;
50603
+ justify-content: flex-start;
50604
+ padding: 0 0 18px 18px;
50605
+ background: transparent;
50606
+ animation: next-sdk-overlay-fade-in 260ms ease-out;
50607
+ }
50608
+
50609
+ .next-sdk-tool-overlay--exit {
50610
+ animation: next-sdk-overlay-fade-out 220ms ease-in forwards;
50611
+ }
50612
+
50613
+ .next-sdk-tool-overlay__glow-ring {
50614
+ display: none;
50615
+ }
50616
+
50617
+ .next-sdk-tool-overlay__panel {
50618
+ position: relative;
50619
+ min-width: min(320px, 78vw);
50620
+ max-width: min(420px, 82vw);
50621
+ padding: 10px 14px;
50622
+ border-radius: 999px;
50623
+ background:
50624
+ linear-gradient(135deg, rgba(15, 23, 42, 0.9), rgba(17, 24, 39, 0.9)),
50625
+ radial-gradient(circle at top left, rgba(96, 165, 250, 0.25), transparent 55%),
50626
+ radial-gradient(circle at bottom right, rgba(45, 212, 191, 0.22), transparent 60%);
50627
+ box-shadow:
50628
+ 0 12px 28px rgba(15, 23, 42, 0.78),
50629
+ 0 0 0 1px rgba(148, 163, 184, 0.26);
50630
+ display: flex;
50631
+ align-items: center;
50632
+ gap: 10px;
50633
+ pointer-events: none;
50634
+ transform-origin: center;
50635
+ animation: next-sdk-panel-pop-in 260ms cubic-bezier(0.18, 0.89, 0.32, 1.28);
50636
+ color: #e5e7eb;
50637
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
50638
+ }
50639
+
50640
+ .next-sdk-tool-overlay__indicator {
50641
+ width: 26px;
50642
+ height: 26px;
50643
+ border-radius: 999px;
50644
+ background: radial-gradient(circle at 30% 10%, #f9fafb, #93c5fd);
50645
+ box-shadow:
50646
+ 0 0 0 1px rgba(191, 219, 254, 0.6),
50647
+ 0 8px 18px rgba(37, 99, 235, 0.8),
50648
+ 0 0 28px rgba(56, 189, 248, 0.9);
50649
+ position: relative;
50650
+ flex-shrink: 0;
50651
+ display: flex;
50652
+ align-items: center;
50653
+ justify-content: center;
50654
+ overflow: hidden;
50655
+ }
50656
+
50657
+ .next-sdk-tool-overlay__indicator-orbit {
50658
+ position: absolute;
50659
+ inset: 2px;
50660
+ border-radius: inherit;
50661
+ border: 1px solid rgba(248, 250, 252, 0.6);
50662
+ box-sizing: border-box;
50663
+ opacity: 0.9;
50664
+ }
50665
+
50666
+ .next-sdk-tool-overlay__indicator-orbit::before {
50667
+ content: '';
50668
+ position: absolute;
50669
+ width: 6px;
50670
+ height: 6px;
50671
+ border-radius: 999px;
50672
+ background: #f9fafb;
50673
+ box-shadow:
50674
+ 0 0 12px rgba(248, 250, 252, 0.9),
50675
+ 0 0 24px rgba(250, 249, 246, 0.9);
50676
+ top: 0;
50677
+ left: 50%;
50678
+ transform: translate(-50%, -50%);
50679
+ transform-origin: 50% 18px;
50680
+ animation: next-sdk-indicator-orbit 1.4s linear infinite;
50681
+ }
50682
+
50683
+ .next-sdk-tool-overlay__indicator-core {
50684
+ width: 14px;
50685
+ height: 14px;
50686
+ border-radius: inherit;
50687
+ background: radial-gradient(circle at 30% 20%, #f9fafb, #bfdbfe);
50688
+ box-shadow:
50689
+ 0 0 12px rgba(248, 250, 252, 0.9),
50690
+ 0 0 32px rgba(191, 219, 254, 0.8);
50691
+ opacity: 0.96;
50692
+ }
50693
+
50694
+ .next-sdk-tool-overlay__content {
50695
+ display: flex;
50696
+ flex-direction: column;
50697
+ gap: 1px;
50698
+ min-width: 0;
50699
+ }
50700
+
50701
+ .next-sdk-tool-overlay__title {
50702
+ font-size: 11px;
50703
+ letter-spacing: 0.08em;
50704
+ text-transform: uppercase;
50705
+ color: rgba(156, 163, 175, 0.96);
50706
+ display: flex;
50707
+ align-items: center;
50708
+ gap: 6px;
50709
+ }
50710
+
50711
+ .next-sdk-tool-overlay__title-dot {
50712
+ width: 6px;
50713
+ height: 6px;
50714
+ border-radius: 999px;
50715
+ background: #22c55e;
50716
+ box-shadow:
50717
+ 0 0 8px rgba(34, 197, 94, 0.9),
50718
+ 0 0 14px rgba(22, 163, 74, 0.9);
50719
+ }
50720
+
50721
+ .next-sdk-tool-overlay__label {
50722
+ font-size: 12px;
50723
+ font-weight: 500;
50724
+ color: #e5e7eb;
50725
+ white-space: nowrap;
50726
+ text-overflow: ellipsis;
50727
+ overflow: hidden;
50728
+ }
50729
+
50730
+ @keyframes next-sdk-overlay-fade-in {
50731
+ from { opacity: 0; }
50732
+ to { opacity: 1; }
50733
+ }
50734
+
50735
+ @keyframes next-sdk-overlay-fade-out {
50736
+ from { opacity: 1; }
50737
+ to { opacity: 0; }
50738
+ }
50739
+
50740
+ @keyframes next-sdk-indicator-orbit {
50741
+ from {
50742
+ transform: translate(-50%, -50%) rotate(0deg) translateY(0);
50743
+ }
50744
+ to {
50745
+ transform: translate(-50%, -50%) rotate(360deg) translateY(0);
50746
+ }
50747
+ }
50748
+
50749
+ @keyframes next-sdk-panel-pop-in {
50750
+ 0% {
50751
+ opacity: 0;
50752
+ transform: scale(0.92) translateY(10px);
50753
+ }
50754
+ 100% {
50755
+ opacity: 1;
50756
+ transform: scale(1) translateY(0);
50757
+ }
50758
+ }
50759
+ `;
50760
+ document.head.appendChild(style);
50761
+ styleElement = style;
50762
+ }
50763
+ function ensureOverlayElement() {
50764
+ if (!ensureDomReady()) return;
50765
+ if (overlayElement) return;
50766
+ ensureStyleElement();
50767
+ const overlay = document.createElement("div");
50768
+ overlay.className = "next-sdk-tool-overlay";
50769
+ const glowRing = document.createElement("div");
50770
+ glowRing.className = "next-sdk-tool-overlay__glow-ring";
50771
+ const panel = document.createElement("div");
50772
+ panel.className = "next-sdk-tool-overlay__panel";
50773
+ const indicator = document.createElement("div");
50774
+ indicator.className = "next-sdk-tool-overlay__indicator";
50775
+ const indicatorOrbit = document.createElement("div");
50776
+ indicatorOrbit.className = "next-sdk-tool-overlay__indicator-orbit";
50777
+ const indicatorCore = document.createElement("div");
50778
+ indicatorCore.className = "next-sdk-tool-overlay__indicator-core";
50779
+ const content = document.createElement("div");
50780
+ content.className = "next-sdk-tool-overlay__content";
50781
+ const titleRow = document.createElement("div");
50782
+ titleRow.className = "next-sdk-tool-overlay__title";
50783
+ titleRow.textContent = "AI 正在调用页面工具";
50784
+ const titleDot = document.createElement("span");
50785
+ titleDot.className = "next-sdk-tool-overlay__title-dot";
50786
+ const label = document.createElement("div");
50787
+ label.className = "next-sdk-tool-overlay__label";
50788
+ titleRow.prepend(titleDot);
50789
+ content.appendChild(titleRow);
50790
+ content.appendChild(label);
50791
+ indicator.appendChild(indicatorOrbit);
50792
+ indicator.appendChild(indicatorCore);
50793
+ panel.appendChild(indicator);
50794
+ panel.appendChild(content);
50795
+ overlay.appendChild(glowRing);
50796
+ overlay.appendChild(panel);
50797
+ document.body.appendChild(overlay);
50798
+ overlayElement = overlay;
50799
+ labelElement = label;
50800
+ }
50801
+ function updateOverlay(config2) {
50802
+ if (!ensureDomReady()) return;
50803
+ ensureOverlayElement();
50804
+ if (!overlayElement || !labelElement) return;
50805
+ overlayElement.classList.remove("next-sdk-tool-overlay--exit");
50806
+ labelElement.textContent = config2.label;
50807
+ }
50808
+ function removeOverlayWithAnimation() {
50809
+ if (!overlayElement) return;
50810
+ overlayElement.classList.add("next-sdk-tool-overlay--exit");
50811
+ const localOverlay = overlayElement;
50812
+ let handled = false;
50813
+ let timerId;
50814
+ const handle = () => {
50815
+ if (handled) return;
50816
+ handled = true;
50817
+ if (timerId !== void 0) {
50818
+ clearTimeout(timerId);
50819
+ timerId = void 0;
50820
+ }
50821
+ if (localOverlay.parentNode) {
50822
+ localOverlay.parentNode.removeChild(localOverlay);
50823
+ }
50824
+ if (overlayElement === localOverlay) {
50825
+ overlayElement = null;
50826
+ labelElement = null;
50827
+ }
50828
+ localOverlay.removeEventListener("animationend", handle);
50829
+ };
50830
+ localOverlay.addEventListener("animationend", handle);
50831
+ timerId = setTimeout(handle, 500);
50832
+ }
50833
+ function showToolInvokeEffect(config2) {
50834
+ if (!ensureDomReady()) return;
50835
+ activeCount += 1;
50836
+ updateOverlay(config2);
50837
+ }
50838
+ function hideToolInvokeEffect() {
50839
+ if (!ensureDomReady() || activeCount <= 0) return;
50840
+ activeCount -= 1;
50841
+ if (activeCount === 0) {
50842
+ removeOverlayWithAnimation();
50843
+ }
50844
+ }
50845
+ function resolveRuntimeEffectConfig(toolName, toolTitle, value) {
50846
+ if (!value) return void 0;
50847
+ const baseLabel = toolTitle || toolName;
50848
+ if (typeof value === "boolean") {
50849
+ return value ? { label: baseLabel } : void 0;
50850
+ }
50851
+ return {
50852
+ label: value.label || baseLabel
50853
+ };
50854
+ }
50555
50855
  const MSG_TOOL_CALL = "next-sdk:tool-call";
50556
50856
  const MSG_TOOL_RESPONSE = "next-sdk:tool-response";
50557
50857
  const MSG_PAGE_READY = "next-sdk:page-ready";
@@ -50559,6 +50859,7 @@ ${observationText}
50559
50859
  const MSG_REMOTER_READY = "next-sdk:remoter-ready";
50560
50860
  const MSG_ROUTE_STATE_INITIAL = "next-sdk:route-state-initial";
50561
50861
  const activePages = /* @__PURE__ */ new Map();
50862
+ const normalizeRoute = (value) => value.replace(/\/+$/, "") || "/";
50562
50863
  const broadcastTargets = /* @__PURE__ */ new Set();
50563
50864
  function initBroadcastTargets() {
50564
50865
  if (typeof window !== "undefined") {
@@ -50605,7 +50906,89 @@ ${observationText}
50605
50906
  function setNavigator(fn) {
50606
50907
  _navigator = fn;
50607
50908
  }
50608
- function buildPageHandler(name16, route, timeout = 3e4) {
50909
+ function waitForPageReady(path, timeoutMs = 1500) {
50910
+ if (typeof window === "undefined") {
50911
+ return Promise.resolve();
50912
+ }
50913
+ const target = normalizeRoute(path);
50914
+ return new Promise((resolve2) => {
50915
+ let done = false;
50916
+ const cleanup = () => {
50917
+ if (done) return;
50918
+ done = true;
50919
+ window.removeEventListener("message", handleMessage);
50920
+ resolve2();
50921
+ };
50922
+ const handleMessage = (event) => {
50923
+ if (event.source !== window || event.data?.type !== MSG_PAGE_READY) return;
50924
+ const route = normalizeRoute(String(event.data.route ?? ""));
50925
+ if (route === target) {
50926
+ cleanup();
50927
+ }
50928
+ };
50929
+ window.addEventListener("message", handleMessage);
50930
+ setTimeout(cleanup, timeoutMs);
50931
+ });
50932
+ }
50933
+ function registerNavigateTool(server, options) {
50934
+ const name16 = options?.name ?? "navigate_to_page";
50935
+ const title2 = options?.title ?? "页面跳转";
50936
+ const description2 = options?.description ?? '当需要的工具在当前页面不可用时,使用此工具跳转到特定页面。例如:要查询订单时跳转到 "/orders",要创建价保时跳转到 "/price-protection"。';
50937
+ const timeoutMs = options?.timeoutMs ?? 1500;
50938
+ return server.registerTool(
50939
+ name16,
50940
+ {
50941
+ title: title2,
50942
+ description: description2,
50943
+ inputSchema: {
50944
+ path: stringType().describe('目标页面的路由地址,例如 "/orders"、"/inventory"、"/price-protection" 等。')
50945
+ }
50946
+ },
50947
+ async ({ path }) => {
50948
+ if (typeof window === "undefined") {
50949
+ return {
50950
+ content: [{ type: "text", text: "当前环境不支持页面跳转(window 不存在)。" }]
50951
+ };
50952
+ }
50953
+ if (!_navigator) {
50954
+ return {
50955
+ content: [
50956
+ {
50957
+ type: "text",
50958
+ text: "页面跳转失败:尚未在应用入口调用 setNavigator 注册导航函数,无法执行路由跳转。"
50959
+ }
50960
+ ]
50961
+ };
50962
+ }
50963
+ try {
50964
+ const target = normalizeRoute(path);
50965
+ const current = normalizeRoute(window.location.pathname);
50966
+ const isAlreadyOnTarget = current === target || current.endsWith(target) && (current.length === target.length || current[current.lastIndexOf(target) - 1] === "/");
50967
+ if (isAlreadyOnTarget) {
50968
+ return {
50969
+ content: [{ type: "text", text: `当前已在页面:${path}。请继续你的下一步操作。` }]
50970
+ };
50971
+ }
50972
+ const readyPromise = waitForPageReady(path, timeoutMs);
50973
+ await _navigator(path);
50974
+ await readyPromise;
50975
+ return {
50976
+ content: [{ type: "text", text: `已成功跳转至页面:${path}。请继续你的下一步操作。` }]
50977
+ };
50978
+ } catch (err) {
50979
+ return {
50980
+ content: [
50981
+ {
50982
+ type: "text",
50983
+ text: `页面跳转失败:${err instanceof Error ? err.message : String(err)}。`
50984
+ }
50985
+ ]
50986
+ };
50987
+ }
50988
+ }
50989
+ );
50990
+ }
50991
+ function buildPageHandler(name16, route, timeout = 3e4, effectConfig) {
50609
50992
  return (input) => {
50610
50993
  const callId = randomUUID();
50611
50994
  return new Promise((resolve2, reject) => {
@@ -50617,6 +51000,9 @@ ${observationText}
50617
51000
  if (readyHandler) {
50618
51001
  window.removeEventListener("message", readyHandler);
50619
51002
  }
51003
+ if (effectConfig) {
51004
+ hideToolInvokeEffect();
51005
+ }
50620
51006
  };
50621
51007
  timer = setTimeout(() => {
50622
51008
  cleanup();
@@ -50640,6 +51026,9 @@ ${observationText}
50640
51026
  };
50641
51027
  const run = async () => {
50642
51028
  try {
51029
+ if (effectConfig) {
51030
+ showToolInvokeEffect(effectConfig);
51031
+ }
50643
51032
  if (activePages.get(route)) {
50644
51033
  sendCallOnce();
50645
51034
  return;
@@ -50676,9 +51065,10 @@ ${observationText}
50676
51065
  if (typeof handlerOrRoute === "function") {
50677
51066
  return rawRegister(name16, config2, handlerOrRoute);
50678
51067
  }
50679
- const { route, timeout } = handlerOrRoute;
51068
+ const { route, timeout, invokeEffect } = handlerOrRoute;
50680
51069
  toolRouteMap.set(name16, route);
50681
- return rawRegister(name16, config2, buildPageHandler(name16, route, timeout));
51070
+ const effectConfig = resolveRuntimeEffectConfig(name16, config2?.title, invokeEffect);
51071
+ return rawRegister(name16, config2, buildPageHandler(name16, route, timeout, effectConfig));
50682
51072
  };
50683
51073
  }
50684
51074
  return Reflect.get(target, prop, receiver);
@@ -50687,10 +51077,10 @@ ${observationText}
50687
51077
  }
50688
51078
  function registerPageTool(options) {
50689
51079
  const { route: routeOption, handlers } = options;
50690
- const normalizeRoute = (value) => value.replace(/\/+$/, "") || "/";
50691
- const route = normalizeRoute(routeOption ?? window.location.pathname);
51080
+ const normalizeRoute2 = (value) => value.replace(/\/+$/, "") || "/";
51081
+ const route = normalizeRoute2(routeOption ?? window.location.pathname);
50692
51082
  const handleMessage = async (event) => {
50693
- if (event.source !== window || event.data?.type !== MSG_TOOL_CALL || normalizeRoute(String(event.data?.route ?? "")) !== route || !(event.data.toolName in handlers)) {
51083
+ if (event.source !== window || event.data?.type !== MSG_TOOL_CALL || normalizeRoute2(String(event.data?.route ?? "")) !== route || !(event.data.toolName in handlers)) {
50694
51084
  return;
50695
51085
  }
50696
51086
  const { callId, toolName, input } = event.data;
@@ -50776,33 +51166,95 @@ ${lines.join("\n")}
50776
51166
  }
50777
51167
  function getSkillMdContent(modules, path) {
50778
51168
  const normalized = normalizeSkillModuleKeys(modules);
50779
- return normalized[path];
51169
+ const exactMatch = normalized[path];
51170
+ if (exactMatch) return exactMatch;
51171
+ const suffix = path.replace(/^\.?\//, "/");
51172
+ const matchingKey = Object.keys(normalized).find((key) => key.endsWith(suffix));
51173
+ return matchingKey ? normalized[matchingKey] : void 0;
50780
51174
  }
50781
51175
  function getMainSkillPathByName(modules, name16) {
50782
- return getMainSkillPaths(modules).find((p) => p.startsWith(`./${name16}/SKILL.md`));
51176
+ const normalizedModules = normalizeSkillModuleKeys(modules);
51177
+ const paths = getMainSkillPaths(normalizedModules);
51178
+ const dirMatch = paths.find((p) => p.startsWith(`./${name16}/SKILL.md`));
51179
+ if (dirMatch) return dirMatch;
51180
+ for (const p of paths) {
51181
+ const content = normalizedModules[p];
51182
+ if (content) {
51183
+ const parsed = parseSkillFrontMatter(content);
51184
+ if (parsed && parsed.name === name16) {
51185
+ return p;
51186
+ }
51187
+ }
51188
+ }
51189
+ return void 0;
50783
51190
  }
50784
51191
  const SKILL_INPUT_SCHEMA = objectType({
50785
- skillName: stringType().optional().describe("技能名称,与目录名一致,如 calculator"),
50786
- path: stringType().optional().describe("文档相对路径,如 ./calculator/SKILL.md 或 ./product-guide/reference/xxx.json")
51192
+ skillName: stringType().optional().describe(
51193
+ '进入某个技能的主入口名称。优先匹配技能的目录名(如 ecommerce),或者技能的中文名称(如"客户价保单创建及审核")。'
51194
+ ),
51195
+ path: stringType().optional().describe("你想查阅的文档的路径。如 ./calculator/SKILL.md 或从其他文档里看到的相对路径 ./reference/inventory.md。"),
51196
+ currentPath: stringType().optional().describe(
51197
+ "你当前正在阅读的文档路径(如果有)。比如你刚刚读取了 ./ecommerce/SKILL.md,请把这个路径原样传回来,这样系统才能根据你的相对路径准确找到下一份文件。"
51198
+ )
50787
51199
  });
50788
51200
  function createSkillTools(modules) {
50789
51201
  const normalizedModules = normalizeSkillModuleKeys(modules);
50790
51202
  const getSkillContent = tool({
50791
- description: "根据技能名称或文档路径获取该技能的完整文档内容。传入 skillName(如 calculator)或 path(如 ./calculator/SKILL.md)。支持 .md、.json、.xml 等各类文本格式文件。",
51203
+ description: "根据技能名称或文档路径获取该技能的完整文档内容。如果你想根据相对路径查阅文件,请务必同时提供你当前所在的文件路径 currentPath。",
50792
51204
  inputSchema: SKILL_INPUT_SCHEMA,
50793
51205
  execute: (args) => {
50794
- const { skillName, path: pathArg } = args;
51206
+ const { skillName, path: pathArg, currentPath: currentPathArg } = args;
50795
51207
  let content;
51208
+ let resolvedPath = "";
50796
51209
  if (pathArg) {
50797
- content = getSkillMdContent(normalizedModules, pathArg);
51210
+ let basePathContext = ".";
51211
+ if (currentPathArg) {
51212
+ const lastSlashIndex = currentPathArg.lastIndexOf("/");
51213
+ if (lastSlashIndex >= 0) {
51214
+ basePathContext = currentPathArg.slice(0, lastSlashIndex);
51215
+ }
51216
+ }
51217
+ const dummyBase = `http://localhost/${basePathContext}/`;
51218
+ const url2 = new URL(pathArg, dummyBase);
51219
+ resolvedPath = "." + url2.pathname;
51220
+ content = getSkillMdContent(normalizedModules, resolvedPath);
51221
+ if (content === void 0 && (pathArg.startsWith("./") || pathArg.startsWith("../")) && currentPathArg) {
51222
+ const baseParts = currentPathArg.split("/");
51223
+ if (baseParts.length >= 2) {
51224
+ const skillRoot = baseParts[1];
51225
+ const fallbackDummyBase = `http://localhost/${skillRoot}/`;
51226
+ const fallbackUrl = new URL(pathArg, fallbackDummyBase);
51227
+ const fallbackPath = "." + fallbackUrl.pathname;
51228
+ content = getSkillMdContent(normalizedModules, fallbackPath);
51229
+ if (content) {
51230
+ resolvedPath = fallbackPath;
51231
+ }
51232
+ }
51233
+ }
51234
+ if (content && !normalizedModules[resolvedPath]) {
51235
+ const suffix = resolvedPath.replace(/^\.?\//, "/");
51236
+ const matchingKey = Object.keys(normalizedModules).find((key) => key.endsWith(suffix));
51237
+ if (matchingKey) {
51238
+ resolvedPath = matchingKey;
51239
+ }
51240
+ }
50798
51241
  } else if (skillName) {
50799
51242
  const mainPath = getMainSkillPathByName(normalizedModules, skillName);
50800
- content = mainPath ? getSkillMdContent(normalizedModules, mainPath) : void 0;
51243
+ if (mainPath) {
51244
+ resolvedPath = mainPath;
51245
+ content = getSkillMdContent(normalizedModules, mainPath);
51246
+ }
50801
51247
  }
50802
51248
  if (content === void 0) {
50803
- return { error: "未找到对应技能文档", skillName: skillName ?? pathArg };
51249
+ return {
51250
+ error: "未找到对应技能文档",
51251
+ skillName,
51252
+ path: pathArg,
51253
+ providedCurrentPath: currentPathArg,
51254
+ attemptedPath: resolvedPath
51255
+ };
50804
51256
  }
50805
- return { content, path: pathArg ?? getMainSkillPathByName(normalizedModules, skillName) };
51257
+ return { content, path: resolvedPath };
50806
51258
  }
50807
51259
  });
50808
51260
  return {
@@ -50849,6 +51301,7 @@ ${lines.join("\n")}
50849
51301
  exports2.isSSEClientTransport = isSSEClientTransport;
50850
51302
  exports2.isStreamableHTTPClientTransport = isStreamableHTTPClientTransport;
50851
51303
  exports2.parseSkillFrontMatter = parseSkillFrontMatter;
51304
+ exports2.registerNavigateTool = registerNavigateTool;
50852
51305
  exports2.registerPageTool = registerPageTool;
50853
51306
  exports2.setNavigator = setNavigator;
50854
51307
  exports2.withPageTools = withPageTools;