@opentiny/next-sdk 0.2.8 → 0.2.10
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 +10 -3
- package/agent/type.ts +3 -3
- package/dist/agent/type.d.ts +3 -0
- package/dist/index.es.dev.js +123 -25
- package/dist/index.es.js +10161 -10085
- package/dist/index.js +897 -821
- package/dist/index.umd.dev.js +123 -25
- package/dist/index.umd.js +41 -41
- package/dist/page-tools/bridge.d.ts +23 -0
- package/dist/remoter/createRemoter.d.ts +3 -2
- package/dist/webagent.dev.js +15891 -15877
- package/dist/webagent.es.dev.js +15891 -15877
- package/dist/webagent.es.js +3154 -3142
- package/dist/webagent.js +35 -35
- package/package.json +1 -1
- package/page-tools/bridge.ts +134 -0
- package/remoter/createRemoter.ts +44 -23
|
@@ -2,6 +2,7 @@ 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'
|
|
5
|
+
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'
|
|
5
6
|
import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js'
|
|
6
7
|
import type { IAgentModelProviderOption, McpServerConfig } from './type'
|
|
7
8
|
import { ProviderV2 } from '@ai-sdk/provider'
|
|
@@ -81,15 +82,21 @@ export class AgentModelProvider {
|
|
|
81
82
|
private async _createOneClient(serverConfig: McpServerConfig) {
|
|
82
83
|
try {
|
|
83
84
|
let transport: MCPClientConfig['transport']
|
|
84
|
-
// transport 一定是 streamableHttp 或者就是: ai-sdk允许的 transport
|
|
85
|
+
// transport 一定是 streamableHttp/sse 或者就是: ai-sdk允许的 transport
|
|
85
86
|
if ('type' in serverConfig && serverConfig.type.toLocaleLowerCase() === 'streamablehttp') {
|
|
86
|
-
|
|
87
|
+
const configWithHeaders = serverConfig as { url: string; headers?: Record<string, string> }
|
|
88
|
+
const requestInit = configWithHeaders.headers ? { headers: configWithHeaders.headers } : undefined
|
|
89
|
+
transport = new StreamableHTTPClientTransport(new URL(configWithHeaders.url), { requestInit })
|
|
90
|
+
} else if ('type' in serverConfig && serverConfig.type === 'sse') {
|
|
91
|
+
const configWithHeaders = serverConfig as { url: string; headers?: Record<string, string> }
|
|
92
|
+
const requestInit = configWithHeaders.headers ? { headers: configWithHeaders.headers } : undefined
|
|
93
|
+
transport = new SSEClientTransport(new URL(configWithHeaders.url), { requestInit })
|
|
87
94
|
} else if ('type' in serverConfig && serverConfig.type === 'extension') {
|
|
88
95
|
transport = new ExtensionClientTransport(serverConfig.sessionId)
|
|
89
96
|
} else if ('transport' in serverConfig) {
|
|
90
97
|
transport = serverConfig.transport
|
|
91
98
|
} else {
|
|
92
|
-
transport = serverConfig as MCPClientConfig['transport']
|
|
99
|
+
transport = serverConfig as unknown as MCPClientConfig['transport']
|
|
93
100
|
}
|
|
94
101
|
|
|
95
102
|
// 根据 useAISdkClient 配置决定使用哪种 client 创建方式
|
package/agent/type.ts
CHANGED
|
@@ -35,9 +35,9 @@ export type IAgentModelProviderLlmConfig = LlmFactoryConfig | LlmInstanceConfig
|
|
|
35
35
|
|
|
36
36
|
/** Mcp Server的配置对象 */
|
|
37
37
|
export type McpServerConfig =
|
|
38
|
-
| { type: 'streamableHttp'; url: string; useAISdkClient?: boolean }
|
|
39
|
-
| { type: 'sse'; url: string; useAISdkClient?: boolean }
|
|
40
|
-
| { type: 'extension'; url: string; sessionId: string; useAISdkClient?: boolean }
|
|
38
|
+
| { type: 'streamableHttp'; url: string; useAISdkClient?: boolean; headers?: Record<string, string> }
|
|
39
|
+
| { type: 'sse'; url: string; useAISdkClient?: boolean; headers?: Record<string, string> }
|
|
40
|
+
| { type: 'extension'; url: string; sessionId: string; useAISdkClient?: boolean; headers?: Record<string, string> }
|
|
41
41
|
| { type: 'local'; transport: MCPTransport; useAISdkClient?: boolean }
|
|
42
42
|
|
|
43
43
|
/** */
|
package/dist/agent/type.d.ts
CHANGED
|
@@ -32,15 +32,18 @@ export type McpServerConfig = {
|
|
|
32
32
|
type: 'streamableHttp';
|
|
33
33
|
url: string;
|
|
34
34
|
useAISdkClient?: boolean;
|
|
35
|
+
headers?: Record<string, string>;
|
|
35
36
|
} | {
|
|
36
37
|
type: 'sse';
|
|
37
38
|
url: string;
|
|
38
39
|
useAISdkClient?: boolean;
|
|
40
|
+
headers?: Record<string, string>;
|
|
39
41
|
} | {
|
|
40
42
|
type: 'extension';
|
|
41
43
|
url: string;
|
|
42
44
|
sessionId: string;
|
|
43
45
|
useAISdkClient?: boolean;
|
|
46
|
+
headers?: Record<string, string>;
|
|
44
47
|
} | {
|
|
45
48
|
type: 'local';
|
|
46
49
|
transport: MCPTransport;
|
package/dist/index.es.dev.js
CHANGED
|
@@ -27069,27 +27069,27 @@ class FloatingBlock {
|
|
|
27069
27069
|
}
|
|
27070
27070
|
/**
|
|
27071
27071
|
* 合并菜单项配置。
|
|
27072
|
-
* -
|
|
27073
|
-
* -
|
|
27072
|
+
* - 用户明确传入 menuItems:直接使用用户配置,不受 sessionId 限制;未传 icon 时自动补充默认图标
|
|
27073
|
+
* - 有 sessionId 且未传 menuItems:使用默认菜单
|
|
27074
|
+
* - 无 sessionId 且未传 menuItems:不渲染任何下拉菜单,仅保留点击浮标打开对话框的能力
|
|
27074
27075
|
*/
|
|
27075
27076
|
mergeMenuItems(userMenuItems) {
|
|
27077
|
+
const defaultIcons = {
|
|
27078
|
+
"qr-code": qrCode,
|
|
27079
|
+
"ai-chat": chat,
|
|
27080
|
+
"remote-url": link,
|
|
27081
|
+
"remote-control": scan
|
|
27082
|
+
};
|
|
27083
|
+
if (userMenuItems) {
|
|
27084
|
+
return userMenuItems.map((item) => ({
|
|
27085
|
+
...item,
|
|
27086
|
+
icon: item.icon ?? defaultIcons[item.action]
|
|
27087
|
+
}));
|
|
27088
|
+
}
|
|
27076
27089
|
if (!this.options.sessionId) {
|
|
27077
27090
|
return [];
|
|
27078
27091
|
}
|
|
27079
|
-
|
|
27080
|
-
return getDefaultMenuItems(this.options);
|
|
27081
|
-
}
|
|
27082
|
-
return getDefaultMenuItems(this.options).map((defaultItem) => {
|
|
27083
|
-
const userItem = userMenuItems.find((item) => item.action === defaultItem.action);
|
|
27084
|
-
if (userItem) {
|
|
27085
|
-
return {
|
|
27086
|
-
...defaultItem,
|
|
27087
|
-
...userItem,
|
|
27088
|
-
show: userItem.show !== void 0 ? userItem.show : defaultItem.show
|
|
27089
|
-
};
|
|
27090
|
-
}
|
|
27091
|
-
return defaultItem;
|
|
27092
|
-
});
|
|
27092
|
+
return getDefaultMenuItems(this.options);
|
|
27093
27093
|
}
|
|
27094
27094
|
init() {
|
|
27095
27095
|
this.createFloatingBlock();
|
|
@@ -27120,7 +27120,7 @@ class FloatingBlock {
|
|
|
27120
27120
|
<div class="tiny-remoter-dropdown-item__content">
|
|
27121
27121
|
<div title="${item.tip}">${item.text}</div>
|
|
27122
27122
|
<div class="tiny-remoter-dropdown-item__desc-wrapper">
|
|
27123
|
-
<div class="tiny-remoter-dropdown-item__desc ${item.active ? "tiny-remoter-dropdown-item__desc--active" : ""} ${item.know ? "tiny-remoter-dropdown-item__desc--know" : ""}">${item.desc}</div>
|
|
27123
|
+
<div class="tiny-remoter-dropdown-item__desc ${item.active ? "tiny-remoter-dropdown-item__desc--active" : ""} ${item.know ? "tiny-remoter-dropdown-item__desc--know" : ""}">${item.desc ?? ""}</div>
|
|
27124
27124
|
<div>
|
|
27125
27125
|
${item.showCopyIcon ? `
|
|
27126
27126
|
<div class="tiny-remoter-copy-icon" id="${item.action}" data-action="${item.action}">
|
|
@@ -27228,12 +27228,20 @@ class FloatingBlock {
|
|
|
27228
27228
|
this.closeDropdown();
|
|
27229
27229
|
}
|
|
27230
27230
|
copyRemoteControl() {
|
|
27231
|
-
|
|
27232
|
-
this.
|
|
27231
|
+
const menuItem = this.menuItems.find((item) => item.action === "remote-control");
|
|
27232
|
+
const codeToCopy = menuItem?.desc || menuItem?.text || (this.options.sessionId ? this.options.sessionId.slice(-6) : "");
|
|
27233
|
+
if (codeToCopy) {
|
|
27234
|
+
this.copyToClipboard(codeToCopy);
|
|
27235
|
+
}
|
|
27233
27236
|
}
|
|
27234
27237
|
copyRemoteURL() {
|
|
27235
|
-
|
|
27236
|
-
this.
|
|
27238
|
+
const menuItem = this.menuItems.find((item) => item.action === "remote-url");
|
|
27239
|
+
const sessionUrl = this.options.sessionId ? this.options.remoteUrl + this.sessionPrefix + this.options.sessionId : "";
|
|
27240
|
+
const customDesc = menuItem?.desc && menuItem.desc !== this.options.remoteUrl ? menuItem.desc : void 0;
|
|
27241
|
+
const urlToCopy = customDesc || sessionUrl || menuItem?.text || "";
|
|
27242
|
+
if (urlToCopy) {
|
|
27243
|
+
this.copyToClipboard(urlToCopy);
|
|
27244
|
+
}
|
|
27237
27245
|
}
|
|
27238
27246
|
// 实现复制到剪贴板功能
|
|
27239
27247
|
async copyToClipboard(text2) {
|
|
@@ -49629,7 +49637,13 @@ class AgentModelProvider {
|
|
|
49629
49637
|
try {
|
|
49630
49638
|
let transport;
|
|
49631
49639
|
if ("type" in serverConfig && serverConfig.type.toLocaleLowerCase() === "streamablehttp") {
|
|
49632
|
-
|
|
49640
|
+
const configWithHeaders = serverConfig;
|
|
49641
|
+
const requestInit = configWithHeaders.headers ? { headers: configWithHeaders.headers } : void 0;
|
|
49642
|
+
transport = new StreamableHTTPClientTransport(new URL(configWithHeaders.url), { requestInit });
|
|
49643
|
+
} else if ("type" in serverConfig && serverConfig.type === "sse") {
|
|
49644
|
+
const configWithHeaders = serverConfig;
|
|
49645
|
+
const requestInit = configWithHeaders.headers ? { headers: configWithHeaders.headers } : void 0;
|
|
49646
|
+
transport = new SSEClientTransport(new URL(configWithHeaders.url), { requestInit });
|
|
49633
49647
|
} else if ("type" in serverConfig && serverConfig.type === "extension") {
|
|
49634
49648
|
transport = new ExtensionClientTransport(serverConfig.sessionId);
|
|
49635
49649
|
} else if ("transport" in serverConfig) {
|
|
@@ -50466,6 +50480,7 @@ const MSG_PAGE_LEAVE = "next-sdk:page-leave";
|
|
|
50466
50480
|
const MSG_REMOTER_READY = "next-sdk:remoter-ready";
|
|
50467
50481
|
const MSG_ROUTE_STATE_INITIAL = "next-sdk:route-state-initial";
|
|
50468
50482
|
const activePages = /* @__PURE__ */ new Map();
|
|
50483
|
+
const normalizeRoute = (value) => value.replace(/\/+$/, "") || "/";
|
|
50469
50484
|
const broadcastTargets = /* @__PURE__ */ new Set();
|
|
50470
50485
|
function initBroadcastTargets() {
|
|
50471
50486
|
if (typeof window !== "undefined") {
|
|
@@ -50512,6 +50527,88 @@ let _navigator = null;
|
|
|
50512
50527
|
function setNavigator(fn) {
|
|
50513
50528
|
_navigator = fn;
|
|
50514
50529
|
}
|
|
50530
|
+
function waitForPageReady(path, timeoutMs = 1500) {
|
|
50531
|
+
if (typeof window === "undefined") {
|
|
50532
|
+
return Promise.resolve();
|
|
50533
|
+
}
|
|
50534
|
+
const target = normalizeRoute(path);
|
|
50535
|
+
return new Promise((resolve2) => {
|
|
50536
|
+
let done = false;
|
|
50537
|
+
const cleanup = () => {
|
|
50538
|
+
if (done) return;
|
|
50539
|
+
done = true;
|
|
50540
|
+
window.removeEventListener("message", handleMessage);
|
|
50541
|
+
resolve2();
|
|
50542
|
+
};
|
|
50543
|
+
const handleMessage = (event) => {
|
|
50544
|
+
if (event.source !== window || event.data?.type !== MSG_PAGE_READY) return;
|
|
50545
|
+
const route = normalizeRoute(String(event.data.route ?? ""));
|
|
50546
|
+
if (route === target) {
|
|
50547
|
+
cleanup();
|
|
50548
|
+
}
|
|
50549
|
+
};
|
|
50550
|
+
window.addEventListener("message", handleMessage);
|
|
50551
|
+
setTimeout(cleanup, timeoutMs);
|
|
50552
|
+
});
|
|
50553
|
+
}
|
|
50554
|
+
function registerNavigateTool(server, options) {
|
|
50555
|
+
const name16 = options?.name ?? "navigate_to_page";
|
|
50556
|
+
const title2 = options?.title ?? "页面跳转";
|
|
50557
|
+
const description2 = options?.description ?? '当需要的工具在当前页面不可用时,使用此工具跳转到特定页面。例如:要查询订单时跳转到 "/orders",要创建价保时跳转到 "/price-protection"。';
|
|
50558
|
+
const timeoutMs = options?.timeoutMs ?? 1500;
|
|
50559
|
+
return server.registerTool(
|
|
50560
|
+
name16,
|
|
50561
|
+
{
|
|
50562
|
+
title: title2,
|
|
50563
|
+
description: description2,
|
|
50564
|
+
inputSchema: {
|
|
50565
|
+
path: stringType().describe('目标页面的路由地址,例如 "/orders"、"/inventory"、"/price-protection" 等。')
|
|
50566
|
+
}
|
|
50567
|
+
},
|
|
50568
|
+
async ({ path }) => {
|
|
50569
|
+
if (typeof window === "undefined") {
|
|
50570
|
+
return {
|
|
50571
|
+
content: [{ type: "text", text: "当前环境不支持页面跳转(window 不存在)。" }]
|
|
50572
|
+
};
|
|
50573
|
+
}
|
|
50574
|
+
if (!_navigator) {
|
|
50575
|
+
return {
|
|
50576
|
+
content: [
|
|
50577
|
+
{
|
|
50578
|
+
type: "text",
|
|
50579
|
+
text: "页面跳转失败:尚未在应用入口调用 setNavigator 注册导航函数,无法执行路由跳转。"
|
|
50580
|
+
}
|
|
50581
|
+
]
|
|
50582
|
+
};
|
|
50583
|
+
}
|
|
50584
|
+
try {
|
|
50585
|
+
const target = normalizeRoute(path);
|
|
50586
|
+
const current = normalizeRoute(window.location.pathname);
|
|
50587
|
+
const isAlreadyOnTarget = current === target || current.endsWith(target) && (current.length === target.length || current[current.lastIndexOf(target) - 1] === "/");
|
|
50588
|
+
if (isAlreadyOnTarget) {
|
|
50589
|
+
return {
|
|
50590
|
+
content: [{ type: "text", text: `当前已在页面:${path}。请继续你的下一步操作。` }]
|
|
50591
|
+
};
|
|
50592
|
+
}
|
|
50593
|
+
const readyPromise = waitForPageReady(path, timeoutMs);
|
|
50594
|
+
await _navigator(path);
|
|
50595
|
+
await readyPromise;
|
|
50596
|
+
return {
|
|
50597
|
+
content: [{ type: "text", text: `已成功跳转至页面:${path}。请继续你的下一步操作。` }]
|
|
50598
|
+
};
|
|
50599
|
+
} catch (err) {
|
|
50600
|
+
return {
|
|
50601
|
+
content: [
|
|
50602
|
+
{
|
|
50603
|
+
type: "text",
|
|
50604
|
+
text: `页面跳转失败:${err instanceof Error ? err.message : String(err)}。`
|
|
50605
|
+
}
|
|
50606
|
+
]
|
|
50607
|
+
};
|
|
50608
|
+
}
|
|
50609
|
+
}
|
|
50610
|
+
);
|
|
50611
|
+
}
|
|
50515
50612
|
function buildPageHandler(name16, route, timeout = 3e4, effectConfig) {
|
|
50516
50613
|
return (input) => {
|
|
50517
50614
|
const callId = randomUUID();
|
|
@@ -50601,10 +50698,10 @@ function withPageTools(server) {
|
|
|
50601
50698
|
}
|
|
50602
50699
|
function registerPageTool(options) {
|
|
50603
50700
|
const { route: routeOption, handlers } = options;
|
|
50604
|
-
const
|
|
50605
|
-
const route =
|
|
50701
|
+
const normalizeRoute2 = (value) => value.replace(/\/+$/, "") || "/";
|
|
50702
|
+
const route = normalizeRoute2(routeOption ?? window.location.pathname);
|
|
50606
50703
|
const handleMessage = async (event) => {
|
|
50607
|
-
if (event.source !== window || event.data?.type !== MSG_TOOL_CALL ||
|
|
50704
|
+
if (event.source !== window || event.data?.type !== MSG_TOOL_CALL || normalizeRoute2(String(event.data?.route ?? "")) !== route || !(event.data.toolName in handlers)) {
|
|
50608
50705
|
return;
|
|
50609
50706
|
}
|
|
50610
50707
|
const { callId, toolName, input } = event.data;
|
|
@@ -50826,6 +50923,7 @@ export {
|
|
|
50826
50923
|
isSSEClientTransport,
|
|
50827
50924
|
isStreamableHTTPClientTransport,
|
|
50828
50925
|
parseSkillFrontMatter,
|
|
50926
|
+
registerNavigateTool,
|
|
50829
50927
|
registerPageTool,
|
|
50830
50928
|
setNavigator,
|
|
50831
50929
|
withPageTools,
|