@opentiny/next-sdk 0.2.7 → 0.2.8
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/agent/AgentModelProvider.ts +22 -10
- package/dist/agent/AgentModelProvider.d.ts +3 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.es.dev.js +389 -20
- package/dist/index.es.js +11135 -10850
- package/dist/index.js +1998 -1713
- package/dist/index.umd.dev.js +389 -20
- package/dist/index.umd.js +217 -49
- package/dist/{page-tool-bridge.d.ts → page-tools/bridge.d.ts} +11 -42
- package/dist/page-tools/effects.d.ts +36 -0
- package/dist/remoter/createRemoter.d.ts +2 -0
- package/dist/skills/index.d.ts +2 -1
- package/dist/webagent.dev.js +31 -7
- package/dist/webagent.es.dev.js +31 -7
- package/dist/webagent.es.js +33 -17
- package/dist/webagent.js +3 -3
- package/index.ts +1 -1
- package/package.json +1 -1
- package/{page-tool-bridge.ts → page-tools/bridge.ts} +36 -95
- package/page-tools/effects.ts +343 -0
- package/remoter/createRemoter.ts +25 -11
- package/skills/index.ts +109 -12
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { streamText, stepCountIs, generateText
|
|
1
|
+
import { streamText, stepCountIs, generateText } from 'ai'
|
|
2
2
|
import { MCPClientConfig, createMCPClient } from '@ai-sdk/mcp'
|
|
3
3
|
import type { ToolSet } from 'ai'
|
|
4
4
|
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'
|
|
@@ -281,18 +281,27 @@ export class AgentModelProvider {
|
|
|
281
281
|
this.onUpdatedTools?.()
|
|
282
282
|
}
|
|
283
283
|
|
|
284
|
-
/** 创建临时允许调用的tools
|
|
285
|
-
private _tempMergeTools(extraTool = {}) {
|
|
286
|
-
|
|
287
|
-
|
|
284
|
+
/** 创建临时允许调用的 tools 集合,合并 mcpTools 与 extraTool */
|
|
285
|
+
private _tempMergeTools(extraTool: ToolSet = {} as ToolSet, deleteIgnored = true): ToolSet {
|
|
286
|
+
const toolsResult: ToolSet = Object.values(this.mcpTools).reduce(
|
|
287
|
+
(acc, curr) => ({ ...acc, ...curr } as ToolSet),
|
|
288
|
+
{} as ToolSet
|
|
289
|
+
)
|
|
288
290
|
Object.assign(toolsResult, extraTool)
|
|
289
291
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
292
|
+
if (deleteIgnored) {
|
|
293
|
+
this.ignoreToolnames.forEach((name) => {
|
|
294
|
+
delete toolsResult[name]
|
|
295
|
+
})
|
|
296
|
+
}
|
|
293
297
|
return toolsResult
|
|
294
298
|
}
|
|
295
299
|
|
|
300
|
+
/** 获取当前激活的 tools 名称列表(过滤 ignoreToolnames) */
|
|
301
|
+
private _getActiveToolNames(tools: ToolSet): string[] {
|
|
302
|
+
return Object.keys(tools).filter((name) => !this.ignoreToolnames.includes(name))
|
|
303
|
+
}
|
|
304
|
+
|
|
296
305
|
/** 生成 ReAct 模式的系统提示词(包含工具描述) */
|
|
297
306
|
private _generateReActSystemPrompt(tools: ToolSet, modelName: string, baseSystemPrompt?: string): string {
|
|
298
307
|
// 统一使用 XML 格式的 ReAct 提示词(所有 ReAct 模式都使用相同格式)
|
|
@@ -342,7 +351,7 @@ export class AgentModelProvider {
|
|
|
342
351
|
await this.initClientsAndTools()
|
|
343
352
|
|
|
344
353
|
// 合并所有可用工具
|
|
345
|
-
const allTools = this._tempMergeTools(options.tools)
|
|
354
|
+
const allTools = this._tempMergeTools(options.tools)
|
|
346
355
|
const toolNames = Object.keys(allTools)
|
|
347
356
|
|
|
348
357
|
// 如果没有工具,回退到普通模式
|
|
@@ -810,12 +819,15 @@ export class AgentModelProvider {
|
|
|
810
819
|
|
|
811
820
|
await this.initClientsAndTools()
|
|
812
821
|
|
|
822
|
+
const allTools = this._tempMergeTools(options.tools, false)
|
|
823
|
+
|
|
813
824
|
const chatOptions = {
|
|
814
825
|
// @ts-ignore ProviderV2 是所有llm的父类, 在每一个具体的llm 类都有一个选择model的函数用法
|
|
815
826
|
model: this.llm(model),
|
|
816
827
|
stopWhen: stepCountIs(maxSteps),
|
|
817
828
|
...options,
|
|
818
|
-
tools:
|
|
829
|
+
tools: allTools,
|
|
830
|
+
activeTools: this._getActiveToolNames(allTools),
|
|
819
831
|
}
|
|
820
832
|
|
|
821
833
|
// 保存最后一条 user 消息,用于后续缓存
|
|
@@ -53,8 +53,10 @@ export declare class AgentModelProvider {
|
|
|
53
53
|
insertMcpServer(serverName: string, mcpServer: McpServerConfig): Promise<false | WebMcpClient | import('@ai-sdk/mcp').MCPClient | null>;
|
|
54
54
|
/** 通过服务器名称删除mcpServer: mcpServers mcpClients mcpTools ignoreToolnames */
|
|
55
55
|
removeMcpServer(serverName: string): Promise<void>;
|
|
56
|
-
/** 创建临时允许调用的tools
|
|
56
|
+
/** 创建临时允许调用的 tools 集合,合并 mcpTools 与 extraTool */
|
|
57
57
|
private _tempMergeTools;
|
|
58
|
+
/** 获取当前激活的 tools 名称列表(过滤 ignoreToolnames) */
|
|
59
|
+
private _getActiveToolNames;
|
|
58
60
|
/** 生成 ReAct 模式的系统提示词(包含工具描述) */
|
|
59
61
|
private _generateReActSystemPrompt;
|
|
60
62
|
/** 执行 ReAct 模式下的工具调用 */
|
package/dist/index.d.ts
CHANGED
|
@@ -26,5 +26,5 @@ export { AgentModelProvider } from './agent/AgentModelProvider';
|
|
|
26
26
|
export { getAISDKTools } from './agent/utils/getAISDKTools';
|
|
27
27
|
export { QrCode, type QrCodeOption } from './remoter/QrCode';
|
|
28
28
|
export type * from './agent/type';
|
|
29
|
-
export * from './page-
|
|
29
|
+
export * from './page-tools/bridge';
|
|
30
30
|
export { getSkillOverviews, formatSkillsForSystemPrompt, getSkillMdPaths, getSkillMdContent, getMainSkillPaths, getMainSkillPathByName, parseSkillFrontMatter, createSkillTools, type SkillMeta, type SkillToolsSet } from './skills/index';
|
package/dist/index.es.dev.js
CHANGED
|
@@ -27758,6 +27758,19 @@ class FloatingBlock {
|
|
|
27758
27758
|
this.dropdownMenu.parentNode.removeChild(this.dropdownMenu);
|
|
27759
27759
|
}
|
|
27760
27760
|
}
|
|
27761
|
+
// 隐藏组件
|
|
27762
|
+
hide() {
|
|
27763
|
+
if (this.floatingBlock) {
|
|
27764
|
+
this.floatingBlock.style.display = "none";
|
|
27765
|
+
}
|
|
27766
|
+
this.closeDropdown();
|
|
27767
|
+
}
|
|
27768
|
+
// 显示组件
|
|
27769
|
+
show() {
|
|
27770
|
+
if (this.floatingBlock) {
|
|
27771
|
+
this.floatingBlock.style.display = "flex";
|
|
27772
|
+
}
|
|
27773
|
+
}
|
|
27761
27774
|
}
|
|
27762
27775
|
const createRemoter = (options = {}) => {
|
|
27763
27776
|
return new FloatingBlock(options);
|
|
@@ -49772,15 +49785,24 @@ class AgentModelProvider {
|
|
|
49772
49785
|
}
|
|
49773
49786
|
this.onUpdatedTools?.();
|
|
49774
49787
|
}
|
|
49775
|
-
/** 创建临时允许调用的tools
|
|
49776
|
-
_tempMergeTools(extraTool = {}) {
|
|
49777
|
-
const toolsResult = Object.values(this.mcpTools).reduce(
|
|
49788
|
+
/** 创建临时允许调用的 tools 集合,合并 mcpTools 与 extraTool */
|
|
49789
|
+
_tempMergeTools(extraTool = {}, deleteIgnored = true) {
|
|
49790
|
+
const toolsResult = Object.values(this.mcpTools).reduce(
|
|
49791
|
+
(acc, curr) => ({ ...acc, ...curr }),
|
|
49792
|
+
{}
|
|
49793
|
+
);
|
|
49778
49794
|
Object.assign(toolsResult, extraTool);
|
|
49779
|
-
|
|
49780
|
-
|
|
49781
|
-
|
|
49795
|
+
if (deleteIgnored) {
|
|
49796
|
+
this.ignoreToolnames.forEach((name16) => {
|
|
49797
|
+
delete toolsResult[name16];
|
|
49798
|
+
});
|
|
49799
|
+
}
|
|
49782
49800
|
return toolsResult;
|
|
49783
49801
|
}
|
|
49802
|
+
/** 获取当前激活的 tools 名称列表(过滤 ignoreToolnames) */
|
|
49803
|
+
_getActiveToolNames(tools) {
|
|
49804
|
+
return Object.keys(tools).filter((name16) => !this.ignoreToolnames.includes(name16));
|
|
49805
|
+
}
|
|
49784
49806
|
/** 生成 ReAct 模式的系统提示词(包含工具描述) */
|
|
49785
49807
|
_generateReActSystemPrompt(tools, modelName, baseSystemPrompt) {
|
|
49786
49808
|
const toolsPrompt = generateReActToolsPrompt(tools);
|
|
@@ -50124,12 +50146,14 @@ ${observationText}
|
|
|
50124
50146
|
throw new Error("LLM is not initialized");
|
|
50125
50147
|
}
|
|
50126
50148
|
await this.initClientsAndTools();
|
|
50149
|
+
const allTools = this._tempMergeTools(options.tools, false);
|
|
50127
50150
|
const chatOptions = {
|
|
50128
50151
|
// @ts-ignore ProviderV2 是所有llm的父类, 在每一个具体的llm 类都有一个选择model的函数用法
|
|
50129
50152
|
model: this.llm(model),
|
|
50130
50153
|
stopWhen: stepCountIs(maxSteps),
|
|
50131
50154
|
...options,
|
|
50132
|
-
tools:
|
|
50155
|
+
tools: allTools,
|
|
50156
|
+
activeTools: this._getActiveToolNames(allTools)
|
|
50133
50157
|
};
|
|
50134
50158
|
let lastUserMessage = null;
|
|
50135
50159
|
if (options.message && !options.messages) {
|
|
@@ -50159,6 +50183,282 @@ ${observationText}
|
|
|
50159
50183
|
return this._chat(streamText, options);
|
|
50160
50184
|
}
|
|
50161
50185
|
}
|
|
50186
|
+
let overlayElement = null;
|
|
50187
|
+
let labelElement = null;
|
|
50188
|
+
let styleElement = null;
|
|
50189
|
+
let activeCount = 0;
|
|
50190
|
+
const BODY_GLOW_CLASS = "next-sdk-tool-body-glow";
|
|
50191
|
+
function ensureDomReady() {
|
|
50192
|
+
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
50193
|
+
}
|
|
50194
|
+
function ensureStyleElement() {
|
|
50195
|
+
if (!ensureDomReady()) return;
|
|
50196
|
+
if (styleElement) return;
|
|
50197
|
+
const style = document.createElement("style");
|
|
50198
|
+
style.textContent = `
|
|
50199
|
+
.${BODY_GLOW_CLASS} {
|
|
50200
|
+
position: relative;
|
|
50201
|
+
}
|
|
50202
|
+
|
|
50203
|
+
.next-sdk-tool-overlay {
|
|
50204
|
+
position: fixed;
|
|
50205
|
+
inset: 0;
|
|
50206
|
+
z-index: 999999;
|
|
50207
|
+
pointer-events: none;
|
|
50208
|
+
display: flex;
|
|
50209
|
+
align-items: flex-end;
|
|
50210
|
+
justify-content: flex-start;
|
|
50211
|
+
padding: 0 0 18px 18px;
|
|
50212
|
+
background: transparent;
|
|
50213
|
+
animation: next-sdk-overlay-fade-in 260ms ease-out;
|
|
50214
|
+
}
|
|
50215
|
+
|
|
50216
|
+
.next-sdk-tool-overlay--exit {
|
|
50217
|
+
animation: next-sdk-overlay-fade-out 220ms ease-in forwards;
|
|
50218
|
+
}
|
|
50219
|
+
|
|
50220
|
+
.next-sdk-tool-overlay__glow-ring {
|
|
50221
|
+
display: none;
|
|
50222
|
+
}
|
|
50223
|
+
|
|
50224
|
+
.next-sdk-tool-overlay__panel {
|
|
50225
|
+
position: relative;
|
|
50226
|
+
min-width: min(320px, 78vw);
|
|
50227
|
+
max-width: min(420px, 82vw);
|
|
50228
|
+
padding: 10px 14px;
|
|
50229
|
+
border-radius: 999px;
|
|
50230
|
+
background:
|
|
50231
|
+
linear-gradient(135deg, rgba(15, 23, 42, 0.9), rgba(17, 24, 39, 0.9)),
|
|
50232
|
+
radial-gradient(circle at top left, rgba(96, 165, 250, 0.25), transparent 55%),
|
|
50233
|
+
radial-gradient(circle at bottom right, rgba(45, 212, 191, 0.22), transparent 60%);
|
|
50234
|
+
box-shadow:
|
|
50235
|
+
0 12px 28px rgba(15, 23, 42, 0.78),
|
|
50236
|
+
0 0 0 1px rgba(148, 163, 184, 0.26);
|
|
50237
|
+
display: flex;
|
|
50238
|
+
align-items: center;
|
|
50239
|
+
gap: 10px;
|
|
50240
|
+
pointer-events: none;
|
|
50241
|
+
transform-origin: center;
|
|
50242
|
+
animation: next-sdk-panel-pop-in 260ms cubic-bezier(0.18, 0.89, 0.32, 1.28);
|
|
50243
|
+
color: #e5e7eb;
|
|
50244
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
|
|
50245
|
+
}
|
|
50246
|
+
|
|
50247
|
+
.next-sdk-tool-overlay__indicator {
|
|
50248
|
+
width: 26px;
|
|
50249
|
+
height: 26px;
|
|
50250
|
+
border-radius: 999px;
|
|
50251
|
+
background: radial-gradient(circle at 30% 10%, #f9fafb, #93c5fd);
|
|
50252
|
+
box-shadow:
|
|
50253
|
+
0 0 0 1px rgba(191, 219, 254, 0.6),
|
|
50254
|
+
0 8px 18px rgba(37, 99, 235, 0.8),
|
|
50255
|
+
0 0 28px rgba(56, 189, 248, 0.9);
|
|
50256
|
+
position: relative;
|
|
50257
|
+
flex-shrink: 0;
|
|
50258
|
+
display: flex;
|
|
50259
|
+
align-items: center;
|
|
50260
|
+
justify-content: center;
|
|
50261
|
+
overflow: hidden;
|
|
50262
|
+
}
|
|
50263
|
+
|
|
50264
|
+
.next-sdk-tool-overlay__indicator-orbit {
|
|
50265
|
+
position: absolute;
|
|
50266
|
+
inset: 2px;
|
|
50267
|
+
border-radius: inherit;
|
|
50268
|
+
border: 1px solid rgba(248, 250, 252, 0.6);
|
|
50269
|
+
box-sizing: border-box;
|
|
50270
|
+
opacity: 0.9;
|
|
50271
|
+
}
|
|
50272
|
+
|
|
50273
|
+
.next-sdk-tool-overlay__indicator-orbit::before {
|
|
50274
|
+
content: '';
|
|
50275
|
+
position: absolute;
|
|
50276
|
+
width: 6px;
|
|
50277
|
+
height: 6px;
|
|
50278
|
+
border-radius: 999px;
|
|
50279
|
+
background: #f9fafb;
|
|
50280
|
+
box-shadow:
|
|
50281
|
+
0 0 12px rgba(248, 250, 252, 0.9),
|
|
50282
|
+
0 0 24px rgba(250, 249, 246, 0.9);
|
|
50283
|
+
top: 0;
|
|
50284
|
+
left: 50%;
|
|
50285
|
+
transform: translate(-50%, -50%);
|
|
50286
|
+
transform-origin: 50% 18px;
|
|
50287
|
+
animation: next-sdk-indicator-orbit 1.4s linear infinite;
|
|
50288
|
+
}
|
|
50289
|
+
|
|
50290
|
+
.next-sdk-tool-overlay__indicator-core {
|
|
50291
|
+
width: 14px;
|
|
50292
|
+
height: 14px;
|
|
50293
|
+
border-radius: inherit;
|
|
50294
|
+
background: radial-gradient(circle at 30% 20%, #f9fafb, #bfdbfe);
|
|
50295
|
+
box-shadow:
|
|
50296
|
+
0 0 12px rgba(248, 250, 252, 0.9),
|
|
50297
|
+
0 0 32px rgba(191, 219, 254, 0.8);
|
|
50298
|
+
opacity: 0.96;
|
|
50299
|
+
}
|
|
50300
|
+
|
|
50301
|
+
.next-sdk-tool-overlay__content {
|
|
50302
|
+
display: flex;
|
|
50303
|
+
flex-direction: column;
|
|
50304
|
+
gap: 1px;
|
|
50305
|
+
min-width: 0;
|
|
50306
|
+
}
|
|
50307
|
+
|
|
50308
|
+
.next-sdk-tool-overlay__title {
|
|
50309
|
+
font-size: 11px;
|
|
50310
|
+
letter-spacing: 0.08em;
|
|
50311
|
+
text-transform: uppercase;
|
|
50312
|
+
color: rgba(156, 163, 175, 0.96);
|
|
50313
|
+
display: flex;
|
|
50314
|
+
align-items: center;
|
|
50315
|
+
gap: 6px;
|
|
50316
|
+
}
|
|
50317
|
+
|
|
50318
|
+
.next-sdk-tool-overlay__title-dot {
|
|
50319
|
+
width: 6px;
|
|
50320
|
+
height: 6px;
|
|
50321
|
+
border-radius: 999px;
|
|
50322
|
+
background: #22c55e;
|
|
50323
|
+
box-shadow:
|
|
50324
|
+
0 0 8px rgba(34, 197, 94, 0.9),
|
|
50325
|
+
0 0 14px rgba(22, 163, 74, 0.9);
|
|
50326
|
+
}
|
|
50327
|
+
|
|
50328
|
+
.next-sdk-tool-overlay__label {
|
|
50329
|
+
font-size: 12px;
|
|
50330
|
+
font-weight: 500;
|
|
50331
|
+
color: #e5e7eb;
|
|
50332
|
+
white-space: nowrap;
|
|
50333
|
+
text-overflow: ellipsis;
|
|
50334
|
+
overflow: hidden;
|
|
50335
|
+
}
|
|
50336
|
+
|
|
50337
|
+
@keyframes next-sdk-overlay-fade-in {
|
|
50338
|
+
from { opacity: 0; }
|
|
50339
|
+
to { opacity: 1; }
|
|
50340
|
+
}
|
|
50341
|
+
|
|
50342
|
+
@keyframes next-sdk-overlay-fade-out {
|
|
50343
|
+
from { opacity: 1; }
|
|
50344
|
+
to { opacity: 0; }
|
|
50345
|
+
}
|
|
50346
|
+
|
|
50347
|
+
@keyframes next-sdk-indicator-orbit {
|
|
50348
|
+
from {
|
|
50349
|
+
transform: translate(-50%, -50%) rotate(0deg) translateY(0);
|
|
50350
|
+
}
|
|
50351
|
+
to {
|
|
50352
|
+
transform: translate(-50%, -50%) rotate(360deg) translateY(0);
|
|
50353
|
+
}
|
|
50354
|
+
}
|
|
50355
|
+
|
|
50356
|
+
@keyframes next-sdk-panel-pop-in {
|
|
50357
|
+
0% {
|
|
50358
|
+
opacity: 0;
|
|
50359
|
+
transform: scale(0.92) translateY(10px);
|
|
50360
|
+
}
|
|
50361
|
+
100% {
|
|
50362
|
+
opacity: 1;
|
|
50363
|
+
transform: scale(1) translateY(0);
|
|
50364
|
+
}
|
|
50365
|
+
}
|
|
50366
|
+
`;
|
|
50367
|
+
document.head.appendChild(style);
|
|
50368
|
+
styleElement = style;
|
|
50369
|
+
}
|
|
50370
|
+
function ensureOverlayElement() {
|
|
50371
|
+
if (!ensureDomReady()) return;
|
|
50372
|
+
if (overlayElement) return;
|
|
50373
|
+
ensureStyleElement();
|
|
50374
|
+
const overlay = document.createElement("div");
|
|
50375
|
+
overlay.className = "next-sdk-tool-overlay";
|
|
50376
|
+
const glowRing = document.createElement("div");
|
|
50377
|
+
glowRing.className = "next-sdk-tool-overlay__glow-ring";
|
|
50378
|
+
const panel = document.createElement("div");
|
|
50379
|
+
panel.className = "next-sdk-tool-overlay__panel";
|
|
50380
|
+
const indicator = document.createElement("div");
|
|
50381
|
+
indicator.className = "next-sdk-tool-overlay__indicator";
|
|
50382
|
+
const indicatorOrbit = document.createElement("div");
|
|
50383
|
+
indicatorOrbit.className = "next-sdk-tool-overlay__indicator-orbit";
|
|
50384
|
+
const indicatorCore = document.createElement("div");
|
|
50385
|
+
indicatorCore.className = "next-sdk-tool-overlay__indicator-core";
|
|
50386
|
+
const content = document.createElement("div");
|
|
50387
|
+
content.className = "next-sdk-tool-overlay__content";
|
|
50388
|
+
const titleRow = document.createElement("div");
|
|
50389
|
+
titleRow.className = "next-sdk-tool-overlay__title";
|
|
50390
|
+
titleRow.textContent = "AI 正在调用页面工具";
|
|
50391
|
+
const titleDot = document.createElement("span");
|
|
50392
|
+
titleDot.className = "next-sdk-tool-overlay__title-dot";
|
|
50393
|
+
const label = document.createElement("div");
|
|
50394
|
+
label.className = "next-sdk-tool-overlay__label";
|
|
50395
|
+
titleRow.prepend(titleDot);
|
|
50396
|
+
content.appendChild(titleRow);
|
|
50397
|
+
content.appendChild(label);
|
|
50398
|
+
indicator.appendChild(indicatorOrbit);
|
|
50399
|
+
indicator.appendChild(indicatorCore);
|
|
50400
|
+
panel.appendChild(indicator);
|
|
50401
|
+
panel.appendChild(content);
|
|
50402
|
+
overlay.appendChild(glowRing);
|
|
50403
|
+
overlay.appendChild(panel);
|
|
50404
|
+
document.body.appendChild(overlay);
|
|
50405
|
+
overlayElement = overlay;
|
|
50406
|
+
labelElement = label;
|
|
50407
|
+
}
|
|
50408
|
+
function updateOverlay(config2) {
|
|
50409
|
+
if (!ensureDomReady()) return;
|
|
50410
|
+
ensureOverlayElement();
|
|
50411
|
+
if (!overlayElement || !labelElement) return;
|
|
50412
|
+
overlayElement.classList.remove("next-sdk-tool-overlay--exit");
|
|
50413
|
+
labelElement.textContent = config2.label;
|
|
50414
|
+
}
|
|
50415
|
+
function removeOverlayWithAnimation() {
|
|
50416
|
+
if (!overlayElement) return;
|
|
50417
|
+
overlayElement.classList.add("next-sdk-tool-overlay--exit");
|
|
50418
|
+
const localOverlay = overlayElement;
|
|
50419
|
+
let handled = false;
|
|
50420
|
+
let timerId;
|
|
50421
|
+
const handle = () => {
|
|
50422
|
+
if (handled) return;
|
|
50423
|
+
handled = true;
|
|
50424
|
+
if (timerId !== void 0) {
|
|
50425
|
+
clearTimeout(timerId);
|
|
50426
|
+
timerId = void 0;
|
|
50427
|
+
}
|
|
50428
|
+
if (localOverlay.parentNode) {
|
|
50429
|
+
localOverlay.parentNode.removeChild(localOverlay);
|
|
50430
|
+
}
|
|
50431
|
+
if (overlayElement === localOverlay) {
|
|
50432
|
+
overlayElement = null;
|
|
50433
|
+
labelElement = null;
|
|
50434
|
+
}
|
|
50435
|
+
localOverlay.removeEventListener("animationend", handle);
|
|
50436
|
+
};
|
|
50437
|
+
localOverlay.addEventListener("animationend", handle);
|
|
50438
|
+
timerId = setTimeout(handle, 500);
|
|
50439
|
+
}
|
|
50440
|
+
function showToolInvokeEffect(config2) {
|
|
50441
|
+
if (!ensureDomReady()) return;
|
|
50442
|
+
activeCount += 1;
|
|
50443
|
+
updateOverlay(config2);
|
|
50444
|
+
}
|
|
50445
|
+
function hideToolInvokeEffect() {
|
|
50446
|
+
if (!ensureDomReady() || activeCount <= 0) return;
|
|
50447
|
+
activeCount -= 1;
|
|
50448
|
+
if (activeCount === 0) {
|
|
50449
|
+
removeOverlayWithAnimation();
|
|
50450
|
+
}
|
|
50451
|
+
}
|
|
50452
|
+
function resolveRuntimeEffectConfig(toolName, toolTitle, value) {
|
|
50453
|
+
if (!value) return void 0;
|
|
50454
|
+
const baseLabel = toolTitle || toolName;
|
|
50455
|
+
if (typeof value === "boolean") {
|
|
50456
|
+
return value ? { label: baseLabel } : void 0;
|
|
50457
|
+
}
|
|
50458
|
+
return {
|
|
50459
|
+
label: value.label || baseLabel
|
|
50460
|
+
};
|
|
50461
|
+
}
|
|
50162
50462
|
const MSG_TOOL_CALL = "next-sdk:tool-call";
|
|
50163
50463
|
const MSG_TOOL_RESPONSE = "next-sdk:tool-response";
|
|
50164
50464
|
const MSG_PAGE_READY = "next-sdk:page-ready";
|
|
@@ -50212,7 +50512,7 @@ let _navigator = null;
|
|
|
50212
50512
|
function setNavigator(fn) {
|
|
50213
50513
|
_navigator = fn;
|
|
50214
50514
|
}
|
|
50215
|
-
function buildPageHandler(name16, route, timeout = 3e4) {
|
|
50515
|
+
function buildPageHandler(name16, route, timeout = 3e4, effectConfig) {
|
|
50216
50516
|
return (input) => {
|
|
50217
50517
|
const callId = randomUUID();
|
|
50218
50518
|
return new Promise((resolve2, reject) => {
|
|
@@ -50224,6 +50524,9 @@ function buildPageHandler(name16, route, timeout = 3e4) {
|
|
|
50224
50524
|
if (readyHandler) {
|
|
50225
50525
|
window.removeEventListener("message", readyHandler);
|
|
50226
50526
|
}
|
|
50527
|
+
if (effectConfig) {
|
|
50528
|
+
hideToolInvokeEffect();
|
|
50529
|
+
}
|
|
50227
50530
|
};
|
|
50228
50531
|
timer = setTimeout(() => {
|
|
50229
50532
|
cleanup();
|
|
@@ -50247,6 +50550,9 @@ function buildPageHandler(name16, route, timeout = 3e4) {
|
|
|
50247
50550
|
};
|
|
50248
50551
|
const run = async () => {
|
|
50249
50552
|
try {
|
|
50553
|
+
if (effectConfig) {
|
|
50554
|
+
showToolInvokeEffect(effectConfig);
|
|
50555
|
+
}
|
|
50250
50556
|
if (activePages.get(route)) {
|
|
50251
50557
|
sendCallOnce();
|
|
50252
50558
|
return;
|
|
@@ -50283,9 +50589,10 @@ function withPageTools(server) {
|
|
|
50283
50589
|
if (typeof handlerOrRoute === "function") {
|
|
50284
50590
|
return rawRegister(name16, config2, handlerOrRoute);
|
|
50285
50591
|
}
|
|
50286
|
-
const { route, timeout } = handlerOrRoute;
|
|
50592
|
+
const { route, timeout, invokeEffect } = handlerOrRoute;
|
|
50287
50593
|
toolRouteMap.set(name16, route);
|
|
50288
|
-
|
|
50594
|
+
const effectConfig = resolveRuntimeEffectConfig(name16, config2?.title, invokeEffect);
|
|
50595
|
+
return rawRegister(name16, config2, buildPageHandler(name16, route, timeout, effectConfig));
|
|
50289
50596
|
};
|
|
50290
50597
|
}
|
|
50291
50598
|
return Reflect.get(target, prop, receiver);
|
|
@@ -50383,33 +50690,95 @@ function getSkillMdPaths(modules) {
|
|
|
50383
50690
|
}
|
|
50384
50691
|
function getSkillMdContent(modules, path) {
|
|
50385
50692
|
const normalized = normalizeSkillModuleKeys(modules);
|
|
50386
|
-
|
|
50693
|
+
const exactMatch = normalized[path];
|
|
50694
|
+
if (exactMatch) return exactMatch;
|
|
50695
|
+
const suffix = path.replace(/^\.?\//, "/");
|
|
50696
|
+
const matchingKey = Object.keys(normalized).find((key) => key.endsWith(suffix));
|
|
50697
|
+
return matchingKey ? normalized[matchingKey] : void 0;
|
|
50387
50698
|
}
|
|
50388
50699
|
function getMainSkillPathByName(modules, name16) {
|
|
50389
|
-
|
|
50700
|
+
const normalizedModules = normalizeSkillModuleKeys(modules);
|
|
50701
|
+
const paths = getMainSkillPaths(normalizedModules);
|
|
50702
|
+
const dirMatch = paths.find((p) => p.startsWith(`./${name16}/SKILL.md`));
|
|
50703
|
+
if (dirMatch) return dirMatch;
|
|
50704
|
+
for (const p of paths) {
|
|
50705
|
+
const content = normalizedModules[p];
|
|
50706
|
+
if (content) {
|
|
50707
|
+
const parsed = parseSkillFrontMatter(content);
|
|
50708
|
+
if (parsed && parsed.name === name16) {
|
|
50709
|
+
return p;
|
|
50710
|
+
}
|
|
50711
|
+
}
|
|
50712
|
+
}
|
|
50713
|
+
return void 0;
|
|
50390
50714
|
}
|
|
50391
50715
|
const SKILL_INPUT_SCHEMA = objectType({
|
|
50392
|
-
skillName: stringType().optional().describe(
|
|
50393
|
-
|
|
50716
|
+
skillName: stringType().optional().describe(
|
|
50717
|
+
'进入某个技能的主入口名称。优先匹配技能的目录名(如 ecommerce),或者技能的中文名称(如"客户价保单创建及审核")。'
|
|
50718
|
+
),
|
|
50719
|
+
path: stringType().optional().describe("你想查阅的文档的路径。如 ./calculator/SKILL.md 或从其他文档里看到的相对路径 ./reference/inventory.md。"),
|
|
50720
|
+
currentPath: stringType().optional().describe(
|
|
50721
|
+
"你当前正在阅读的文档路径(如果有)。比如你刚刚读取了 ./ecommerce/SKILL.md,请把这个路径原样传回来,这样系统才能根据你的相对路径准确找到下一份文件。"
|
|
50722
|
+
)
|
|
50394
50723
|
});
|
|
50395
50724
|
function createSkillTools(modules) {
|
|
50396
50725
|
const normalizedModules = normalizeSkillModuleKeys(modules);
|
|
50397
50726
|
const getSkillContent = tool({
|
|
50398
|
-
description: "
|
|
50727
|
+
description: "根据技能名称或文档路径获取该技能的完整文档内容。如果你想根据相对路径查阅文件,请务必同时提供你当前所在的文件路径 currentPath。",
|
|
50399
50728
|
inputSchema: SKILL_INPUT_SCHEMA,
|
|
50400
50729
|
execute: (args) => {
|
|
50401
|
-
const { skillName, path: pathArg } = args;
|
|
50730
|
+
const { skillName, path: pathArg, currentPath: currentPathArg } = args;
|
|
50402
50731
|
let content;
|
|
50732
|
+
let resolvedPath = "";
|
|
50403
50733
|
if (pathArg) {
|
|
50404
|
-
|
|
50734
|
+
let basePathContext = ".";
|
|
50735
|
+
if (currentPathArg) {
|
|
50736
|
+
const lastSlashIndex = currentPathArg.lastIndexOf("/");
|
|
50737
|
+
if (lastSlashIndex >= 0) {
|
|
50738
|
+
basePathContext = currentPathArg.slice(0, lastSlashIndex);
|
|
50739
|
+
}
|
|
50740
|
+
}
|
|
50741
|
+
const dummyBase = `http://localhost/${basePathContext}/`;
|
|
50742
|
+
const url2 = new URL(pathArg, dummyBase);
|
|
50743
|
+
resolvedPath = "." + url2.pathname;
|
|
50744
|
+
content = getSkillMdContent(normalizedModules, resolvedPath);
|
|
50745
|
+
if (content === void 0 && (pathArg.startsWith("./") || pathArg.startsWith("../")) && currentPathArg) {
|
|
50746
|
+
const baseParts = currentPathArg.split("/");
|
|
50747
|
+
if (baseParts.length >= 2) {
|
|
50748
|
+
const skillRoot = baseParts[1];
|
|
50749
|
+
const fallbackDummyBase = `http://localhost/${skillRoot}/`;
|
|
50750
|
+
const fallbackUrl = new URL(pathArg, fallbackDummyBase);
|
|
50751
|
+
const fallbackPath = "." + fallbackUrl.pathname;
|
|
50752
|
+
content = getSkillMdContent(normalizedModules, fallbackPath);
|
|
50753
|
+
if (content) {
|
|
50754
|
+
resolvedPath = fallbackPath;
|
|
50755
|
+
}
|
|
50756
|
+
}
|
|
50757
|
+
}
|
|
50758
|
+
if (content && !normalizedModules[resolvedPath]) {
|
|
50759
|
+
const suffix = resolvedPath.replace(/^\.?\//, "/");
|
|
50760
|
+
const matchingKey = Object.keys(normalizedModules).find((key) => key.endsWith(suffix));
|
|
50761
|
+
if (matchingKey) {
|
|
50762
|
+
resolvedPath = matchingKey;
|
|
50763
|
+
}
|
|
50764
|
+
}
|
|
50405
50765
|
} else if (skillName) {
|
|
50406
50766
|
const mainPath = getMainSkillPathByName(normalizedModules, skillName);
|
|
50407
|
-
|
|
50767
|
+
if (mainPath) {
|
|
50768
|
+
resolvedPath = mainPath;
|
|
50769
|
+
content = getSkillMdContent(normalizedModules, mainPath);
|
|
50770
|
+
}
|
|
50408
50771
|
}
|
|
50409
50772
|
if (content === void 0) {
|
|
50410
|
-
return {
|
|
50773
|
+
return {
|
|
50774
|
+
error: "未找到对应技能文档",
|
|
50775
|
+
skillName,
|
|
50776
|
+
path: pathArg,
|
|
50777
|
+
providedCurrentPath: currentPathArg,
|
|
50778
|
+
attemptedPath: resolvedPath
|
|
50779
|
+
};
|
|
50411
50780
|
}
|
|
50412
|
-
return { content, path:
|
|
50781
|
+
return { content, path: resolvedPath };
|
|
50413
50782
|
}
|
|
50414
50783
|
});
|
|
50415
50784
|
return {
|