@opentiny/next-sdk 0.1.3 → 0.1.4
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/McpSdk.ts +14 -0
- package/WebAgent.ts +5 -0
- package/WebMcp.ts +18 -0
- package/Zod.ts +1 -0
- package/agent/AgentModelProvider.ts +150 -35
- package/agent/type.ts +1 -1
- package/agent/utils/getAISDKTools.ts +35 -0
- package/dist/agent/AgentModelProvider.d.ts +43 -4
- package/dist/agent/AgentModelProvider.js +145 -24
- package/dist/agent/type.d.ts +1 -1
- package/dist/agent/utils/getAISDKTools.d.ts +8 -0
- package/dist/agent/utils/getAISDKTools.js +36 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.es.dev.js +42947 -0
- package/dist/index.es.js +17998 -17742
- package/dist/index.js +10 -4
- package/dist/index.umd.dev.js +43341 -0
- package/dist/index.umd.js +285 -114
- package/dist/mcpsdk@1.17.0.dev.js +21391 -0
- package/dist/mcpsdk@1.17.0.es.dev.js +21389 -0
- package/dist/mcpsdk@1.17.0.es.js +14505 -0
- package/dist/mcpsdk@1.17.0.js +16 -0
- package/dist/remoter/createRemoter.d.ts +10 -2
- package/dist/remoter/createRemoter.js +312 -55
- package/dist/webagent.dev.js +27509 -0
- package/dist/webagent.es.dev.js +27115 -0
- package/dist/webagent.es.js +21448 -0
- package/dist/webagent.js +529 -0
- package/dist/webmcp-full.dev.js +22915 -0
- package/dist/webmcp-full.es.dev.js +22911 -0
- package/dist/webmcp-full.es.js +15821 -0
- package/dist/webmcp-full.js +16 -0
- package/dist/webmcp.dev.js +1373 -0
- package/dist/webmcp.es.dev.js +1366 -0
- package/dist/webmcp.es.js +1232 -0
- package/dist/webmcp.js +1 -0
- package/dist/zod@3.25.76.dev.js +4039 -0
- package/dist/zod@3.25.76.es.dev.js +4035 -0
- package/dist/zod@3.25.76.es.js +2947 -0
- package/dist/zod@3.25.76.js +1 -0
- package/index.ts +16 -4
- package/package.json +16 -4
- package/remoter/createRemoter.ts +327 -62
- package/runtime.html +98 -0
- package/script/utils.ts +26 -0
- package/vite.config.mcpSdk.ts +28 -0
- package/vite.config.ts +13 -12
- package/vite.config.webAgent.ts +19 -0
- package/vite.config.webMcp.ts +40 -0
- package/vite.config.webMcpFull.ts +19 -0
- package/vite.config.zod.ts +23 -0
- package/agent/utils/aiProviderFactories.ts +0 -7
- package/agent/utils/index.ts +0 -79
- package/dist/agent/utils/aiProviderFactories.d.ts +0 -6
- package/dist/agent/utils/aiProviderFactories.js +0 -6
- package/dist/agent/utils/index.d.ts +0 -14
- package/dist/agent/utils/index.js +0 -72
- package/dist/index.cjs.js +0 -365
package/McpSdk.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import Ajv from 'ajv'
|
|
2
|
+
export { Ajv }
|
|
3
|
+
export * from '@modelcontextprotocol/sdk/types.js'
|
|
4
|
+
export * from '@modelcontextprotocol/sdk/shared/uriTemplate.js'
|
|
5
|
+
export * from '@modelcontextprotocol/sdk/server/completable.js'
|
|
6
|
+
export * from '@modelcontextprotocol/sdk/shared/metadataUtils.js'
|
|
7
|
+
export * from '@modelcontextprotocol/sdk/client/index.js'
|
|
8
|
+
export * from '@modelcontextprotocol/sdk/client/auth.js'
|
|
9
|
+
export * from '@modelcontextprotocol/sdk/client/sse.js'
|
|
10
|
+
export * from '@modelcontextprotocol/sdk/client/streamableHttp.js'
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
export * from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
13
|
+
export * from '@modelcontextprotocol/sdk/shared/transport.js'
|
|
14
|
+
export * from '@modelcontextprotocol/sdk/shared/protocol.js'
|
package/WebAgent.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { AgentModelProvider } from './agent/AgentModelProvider'
|
|
2
|
+
export { createRemoter } from './remoter/createRemoter'
|
|
3
|
+
export { getAISDKTools } from './agent/utils/getAISDKTools'
|
|
4
|
+
export { QrCode, type QrCodeOption } from './remoter/QrCode'
|
|
5
|
+
export type * from './agent/type'
|
package/WebMcp.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import Ajv from 'ajv'
|
|
2
|
+
export * from './WebMcpServer'
|
|
3
|
+
export * from './WebMcpClient'
|
|
4
|
+
export { Ajv }
|
|
5
|
+
export { z } from 'zod'
|
|
6
|
+
export { AuthClientProvider } from '@opentiny/next'
|
|
7
|
+
export { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
8
|
+
export { UriTemplate } from '@modelcontextprotocol/sdk/shared/uriTemplate.js'
|
|
9
|
+
export { completable } from '@modelcontextprotocol/sdk/server/completable.js'
|
|
10
|
+
export { getDisplayName } from '@modelcontextprotocol/sdk/shared/metadataUtils.js'
|
|
11
|
+
export type * from 'zod'
|
|
12
|
+
export type * from '@opentiny/next'
|
|
13
|
+
export type * from '@modelcontextprotocol/sdk/types.js'
|
|
14
|
+
export type * from '@modelcontextprotocol/sdk/shared/protocol.js'
|
|
15
|
+
export type * from '@modelcontextprotocol/sdk/shared/transport.js'
|
|
16
|
+
export type * from '@modelcontextprotocol/sdk/client/sse.js'
|
|
17
|
+
export type * from '@modelcontextprotocol/sdk/client/streamableHttp.js'
|
|
18
|
+
export type * from '@modelcontextprotocol/sdk/server/mcp.js'
|
package/Zod.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { z } from 'zod'
|
|
@@ -1,16 +1,41 @@
|
|
|
1
1
|
import { streamText, stepCountIs, generateText } from 'ai'
|
|
2
|
+
import { experimental_createMCPClient as createMCPClient, experimental_MCPClientConfig as MCPClientConfig } from 'ai'
|
|
2
3
|
import type { ToolSet } from 'ai'
|
|
3
|
-
import {
|
|
4
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'
|
|
4
5
|
import type { IAgentModelProviderOption, McpServerConfig } from './type'
|
|
5
|
-
import { AIProviderFactories } from './utils/aiProviderFactories'
|
|
6
6
|
import { ProviderV2 } from '@ai-sdk/provider'
|
|
7
7
|
import { OpenAIProvider } from '@ai-sdk/openai'
|
|
8
|
+
import { createOpenAI } from '@ai-sdk/openai'
|
|
9
|
+
import { createDeepSeek } from '@ai-sdk/deepseek'
|
|
8
10
|
|
|
11
|
+
export const AIProviderFactories = {
|
|
12
|
+
['openai']: createOpenAI,
|
|
13
|
+
['deepseek']: createDeepSeek
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type ChatMethodFn = typeof streamText | typeof generateText
|
|
17
|
+
|
|
18
|
+
/** 一个通用的ai-sdk的agent封装
|
|
19
|
+
* @summary 内部自动管理了 llm, mcpServer, ai-sdk的clients 和 tools
|
|
20
|
+
* @returns 暴露了 chat, chatStream方法
|
|
21
|
+
*/
|
|
9
22
|
export class AgentModelProvider {
|
|
10
23
|
llm: ProviderV2 | OpenAIProvider
|
|
11
|
-
mcpServers
|
|
12
|
-
|
|
24
|
+
/** mcpServers 允许为配置为 McpServerConfig, 或者任意的 MCPTransport
|
|
25
|
+
* 参考: https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-calling#initializing-an-mcp-client */
|
|
26
|
+
mcpServers: McpServerConfig[] = []
|
|
27
|
+
/** ai-sdk的 mcpClient */
|
|
13
28
|
mcpClients: any[] = []
|
|
29
|
+
/** 所有的tools */
|
|
30
|
+
mcpTools: Array<Record<string, any>> = []
|
|
31
|
+
/** 需要实时过滤掉的tools name*/
|
|
32
|
+
ignoreToolnames: string[] = []
|
|
33
|
+
|
|
34
|
+
/** 在 chat 之前,自动更新 所有的tools */
|
|
35
|
+
autoUpdateTools = true
|
|
36
|
+
|
|
37
|
+
/** chat 时,自动更新 所有的tools 后的事件 */
|
|
38
|
+
onUpdatedTools: (() => void) | undefined
|
|
14
39
|
|
|
15
40
|
constructor({ llmConfig, mcpServers, llm }: IAgentModelProviderOption) {
|
|
16
41
|
// 1、保存 mcpServer
|
|
@@ -36,53 +61,143 @@ export class AgentModelProvider {
|
|
|
36
61
|
}
|
|
37
62
|
}
|
|
38
63
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
64
|
+
/** 创建一个 ai-sdk的 mcpClient, 创建失败则返回 Null */
|
|
65
|
+
private async _createOneClient(serverConfig: McpServerConfig) {
|
|
66
|
+
try {
|
|
67
|
+
let transport: MCPClientConfig['transport']
|
|
68
|
+
// transport 一定是 streamableHttp 或者就是: ai-sdk允许的 transport
|
|
69
|
+
if ('type' in serverConfig && serverConfig.type.toLocaleLowerCase() === 'streamablehttp') {
|
|
70
|
+
transport = new StreamableHTTPClientTransport(new URL(serverConfig.url))
|
|
71
|
+
} else {
|
|
72
|
+
transport = serverConfig as MCPClientConfig['transport']
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return createMCPClient({ transport: transport as MCPClientConfig['transport'] })
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error(`Failed to create MCP client`, serverConfig, error)
|
|
78
|
+
return null
|
|
43
79
|
}
|
|
44
80
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
81
|
+
/** 创建 ai-sdk的 mcpClient, 失败则保存为null */
|
|
82
|
+
private async _createMpcClients() {
|
|
83
|
+
// 使用 Promise.all 并行处理所有 mcpServer 项
|
|
84
|
+
this.mcpClients = await Promise.all(
|
|
85
|
+
this.mcpServers.map(async (server) => {
|
|
86
|
+
return this._createOneClient(server)
|
|
87
|
+
})
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
/** 创建所有 mcpClients 的 tools, 失败则保存为null */
|
|
91
|
+
private async _createMpcTools() {
|
|
92
|
+
this.mcpTools = await Promise.all(
|
|
93
|
+
this.mcpClients.map(async (client) => {
|
|
94
|
+
try {
|
|
95
|
+
return client ? await client?.tools?.() : null
|
|
96
|
+
} catch (error) {
|
|
97
|
+
return null
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
/** 关闭所有的 clients */
|
|
103
|
+
async closeAll() {
|
|
104
|
+
await Promise.all(
|
|
105
|
+
this.mcpClients.map(async (client) => {
|
|
106
|
+
try {
|
|
107
|
+
client.close()
|
|
108
|
+
} catch (error) {}
|
|
109
|
+
})
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async initClientsAndTools() {
|
|
114
|
+
await this._createMpcClients()
|
|
115
|
+
await this._createMpcTools()
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async updateMcpServers(mcpServers: McpServerConfig[]) {
|
|
119
|
+
await this.closeAll()
|
|
120
|
+
this.mcpServers = mcpServers
|
|
121
|
+
await this.initClientsAndTools()
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async insertMcpServer(mcpServer: McpServerConfig) {
|
|
125
|
+
const find = this.mcpServers.find((item: any) => item.url === mcpServer.url)
|
|
126
|
+
|
|
127
|
+
if (!find) {
|
|
128
|
+
this.mcpServers = [...this.mcpServers, mcpServer]
|
|
129
|
+
const client = await this._createOneClient(mcpServer)
|
|
130
|
+
this.mcpClients.push(client)
|
|
131
|
+
this.mcpTools.push((await client?.tools?.()) as Record<string, any>)
|
|
132
|
+
return true
|
|
52
133
|
}
|
|
134
|
+
return false
|
|
135
|
+
}
|
|
136
|
+
/** 通过引用,删除一个 mcpServers mcpClients mcpTools ignoreToolnames */
|
|
137
|
+
removeMcpServer(mcpServer: McpServerConfig) {
|
|
138
|
+
const index = this.mcpServers.findIndex((server) => server === mcpServer)
|
|
53
139
|
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
const tools = await getMcpTools(this.mcpClients, options)
|
|
140
|
+
// 移除
|
|
141
|
+
this.mcpServers.splice(index, 1)
|
|
57
142
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
143
|
+
// 移除
|
|
144
|
+
const delClient = this.mcpClients[index]
|
|
145
|
+
this.mcpClients.splice(index, 1)
|
|
146
|
+
try {
|
|
147
|
+
delClient?.close()
|
|
148
|
+
} catch (error) {}
|
|
149
|
+
|
|
150
|
+
// 移除 tools
|
|
151
|
+
const delTool = this.mcpTools[index]
|
|
152
|
+
this.mcpTools.splice(index, 1)
|
|
153
|
+
|
|
154
|
+
// 移除 ignoreToolnames
|
|
155
|
+
if (delTool) {
|
|
156
|
+
Object.keys(delTool).forEach((toolName) => {
|
|
157
|
+
this.ignoreToolnames = this.ignoreToolnames.filter((name) => name !== toolName)
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** 创建临时允许调用的tools集合 */
|
|
163
|
+
tempMergeTools(extraTool = {}) {
|
|
164
|
+
const toolsResult = this.mcpTools.reduce((acc, curr) => ({ ...acc, ...curr }), {})
|
|
165
|
+
Object.assign(toolsResult, extraTool)
|
|
166
|
+
|
|
167
|
+
this.ignoreToolnames.forEach((name) => {
|
|
168
|
+
delete toolsResult[name]
|
|
64
169
|
})
|
|
170
|
+
|
|
171
|
+
return toolsResult
|
|
65
172
|
}
|
|
66
173
|
|
|
67
|
-
async
|
|
68
|
-
|
|
69
|
-
maxSteps = 5,
|
|
70
|
-
|
|
71
|
-
}: Parameters<typeof streamText>[0] & { maxSteps?: number }): Promise<any> {
|
|
174
|
+
async _chat(
|
|
175
|
+
chatMethod: ChatMethodFn,
|
|
176
|
+
{ model, maxSteps = 5, ...options }: Parameters<typeof generateText>[0] & { maxSteps?: number }
|
|
177
|
+
): Promise<any> {
|
|
72
178
|
if (!this.llm) {
|
|
73
179
|
throw new Error('LLM is not initialized')
|
|
74
180
|
}
|
|
75
181
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
182
|
+
if (this.autoUpdateTools) {
|
|
183
|
+
await this._createMpcTools()
|
|
184
|
+
this.onUpdatedTools?.()
|
|
185
|
+
}
|
|
79
186
|
|
|
80
|
-
return
|
|
81
|
-
// @ts-ignore
|
|
187
|
+
return chatMethod({
|
|
188
|
+
// @ts-ignore ProviderV2 是所有llm的父类, 在每一个具体的llm 类都有一个选择model的函数用法
|
|
82
189
|
model: this.llm(model),
|
|
83
|
-
tools: tools as ToolSet,
|
|
190
|
+
tools: this.tempMergeTools(options.tools) as ToolSet,
|
|
84
191
|
stopWhen: stepCountIs(maxSteps),
|
|
85
192
|
...options
|
|
86
193
|
})
|
|
87
194
|
}
|
|
195
|
+
|
|
196
|
+
async chat(options: Parameters<typeof generateText>[0] & { maxSteps?: number }): Promise<any> {
|
|
197
|
+
return this._chat(generateText, options)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async chatStream(options: Parameters<typeof streamText>[0] & { maxSteps?: number }): Promise<any> {
|
|
201
|
+
return this._chat(streamText, options as any)
|
|
202
|
+
}
|
|
88
203
|
}
|
package/agent/type.ts
CHANGED
|
@@ -14,7 +14,7 @@ export interface IAgentModelProviderLlmConfig {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/** Mcp Server的配置对象 */
|
|
17
|
-
export type McpServerConfig = { type: 'streamableHttp' | 'sse'; url: string }
|
|
17
|
+
export type McpServerConfig = { type: 'streamableHttp' | 'sse'; url: string } & { transport: MCPTransport }
|
|
18
18
|
|
|
19
19
|
/** */
|
|
20
20
|
export interface IAgentModelProviderOption {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { dynamicTool, jsonSchema, Tool, ToolCallOptions, ToolSet } from 'ai'
|
|
2
|
+
import { WebMcpClient } from '../../WebMcpClient'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 快速 从官方 mcp 或 WebMcpClient 这2种client中, 抽取成 ai-sdk 所需要的 tool的对象
|
|
6
|
+
* @params client 一个已连接好的 WebMcpClient
|
|
7
|
+
* @returns ai-sdk的 tool 格式的对象。
|
|
8
|
+
*/
|
|
9
|
+
export const getAISDKTools = async (client: WebMcpClient): Promise<ToolSet> => {
|
|
10
|
+
const tools: Record<string, Tool> = {}
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const listToolsResult = await client.listTools()
|
|
14
|
+
|
|
15
|
+
for (const { name, description, inputSchema } of listToolsResult.tools) {
|
|
16
|
+
const execute = async (args: any, options: ToolCallOptions): Promise<any> => {
|
|
17
|
+
return client.callTool({ name, arguments: args }, { signal: options?.abortSignal })
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
tools[name] = dynamicTool({
|
|
21
|
+
description,
|
|
22
|
+
inputSchema: jsonSchema({
|
|
23
|
+
...inputSchema,
|
|
24
|
+
properties: (inputSchema.properties as Record<string, any>) ?? {},
|
|
25
|
+
additionalProperties: false
|
|
26
|
+
}),
|
|
27
|
+
execute
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return tools
|
|
32
|
+
} catch (error) {
|
|
33
|
+
throw error
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -2,17 +2,56 @@ import { streamText, generateText } from 'ai';
|
|
|
2
2
|
import type { IAgentModelProviderOption, McpServerConfig } from './type';
|
|
3
3
|
import { ProviderV2 } from '@ai-sdk/provider';
|
|
4
4
|
import { OpenAIProvider } from '@ai-sdk/openai';
|
|
5
|
+
import { createOpenAI } from '@ai-sdk/openai';
|
|
6
|
+
import { createDeepSeek } from '@ai-sdk/deepseek';
|
|
7
|
+
export declare const AIProviderFactories: {
|
|
8
|
+
openai: typeof createOpenAI;
|
|
9
|
+
deepseek: typeof createDeepSeek;
|
|
10
|
+
};
|
|
11
|
+
type ChatMethodFn = typeof streamText | typeof generateText;
|
|
12
|
+
/** 一个通用的ai-sdk的agent封装
|
|
13
|
+
* @summary 内部自动管理了 llm, mcpServer, ai-sdk的clients 和 tools
|
|
14
|
+
* @returns 暴露了 chat, chatStream方法
|
|
15
|
+
*/
|
|
5
16
|
export declare class AgentModelProvider {
|
|
6
17
|
llm: ProviderV2 | OpenAIProvider;
|
|
18
|
+
/** mcpServers 允许为配置为 McpServerConfig, 或者任意的 MCPTransport
|
|
19
|
+
* 参考: https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-calling#initializing-an-mcp-client */
|
|
7
20
|
mcpServers: McpServerConfig[];
|
|
8
|
-
|
|
21
|
+
/** ai-sdk的 mcpClient */
|
|
9
22
|
mcpClients: any[];
|
|
23
|
+
/** 所有的tools */
|
|
24
|
+
mcpTools: Array<Record<string, any>>;
|
|
25
|
+
/** 需要实时过滤掉的tools name*/
|
|
26
|
+
ignoreToolnames: string[];
|
|
27
|
+
/** 在 chat 之前,自动更新 所有的tools */
|
|
28
|
+
autoUpdateTools: boolean;
|
|
29
|
+
/** chat 时,自动更新 所有的tools 后的事件 */
|
|
30
|
+
onUpdatedTools: (() => void) | undefined;
|
|
10
31
|
constructor({ llmConfig, mcpServers, llm }: IAgentModelProviderOption);
|
|
11
|
-
|
|
12
|
-
|
|
32
|
+
/** 创建一个 ai-sdk的 mcpClient, 创建失败则返回 Null */
|
|
33
|
+
private _createOneClient;
|
|
34
|
+
/** 创建 ai-sdk的 mcpClient, 失败则保存为null */
|
|
35
|
+
private _createMpcClients;
|
|
36
|
+
/** 创建所有 mcpClients 的 tools, 失败则保存为null */
|
|
37
|
+
private _createMpcTools;
|
|
38
|
+
/** 关闭所有的 clients */
|
|
39
|
+
closeAll(): Promise<void>;
|
|
40
|
+
initClientsAndTools(): Promise<void>;
|
|
41
|
+
updateMcpServers(mcpServers: McpServerConfig[]): Promise<void>;
|
|
42
|
+
insertMcpServer(mcpServer: McpServerConfig): Promise<boolean>;
|
|
43
|
+
/** 通过引用,删除一个 mcpServers mcpClients mcpTools ignoreToolnames */
|
|
44
|
+
removeMcpServer(mcpServer: McpServerConfig): void;
|
|
45
|
+
/** 创建临时允许调用的tools集合 */
|
|
46
|
+
tempMergeTools(extraTool?: {}): Record<string, any>;
|
|
47
|
+
_chat(chatMethod: ChatMethodFn, { model, maxSteps, ...options }: Parameters<typeof generateText>[0] & {
|
|
13
48
|
maxSteps?: number;
|
|
14
49
|
}): Promise<any>;
|
|
15
|
-
|
|
50
|
+
chat(options: Parameters<typeof generateText>[0] & {
|
|
51
|
+
maxSteps?: number;
|
|
52
|
+
}): Promise<any>;
|
|
53
|
+
chatStream(options: Parameters<typeof streamText>[0] & {
|
|
16
54
|
maxSteps?: number;
|
|
17
55
|
}): Promise<any>;
|
|
18
56
|
}
|
|
57
|
+
export {};
|
|
@@ -19,12 +19,31 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
19
19
|
return t;
|
|
20
20
|
};
|
|
21
21
|
import { streamText, stepCountIs, generateText } from 'ai';
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
22
|
+
import { experimental_createMCPClient as createMCPClient } from 'ai';
|
|
23
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
24
|
+
import { createOpenAI } from '@ai-sdk/openai';
|
|
25
|
+
import { createDeepSeek } from '@ai-sdk/deepseek';
|
|
26
|
+
export const AIProviderFactories = {
|
|
27
|
+
['openai']: createOpenAI,
|
|
28
|
+
['deepseek']: createDeepSeek
|
|
29
|
+
};
|
|
30
|
+
/** 一个通用的ai-sdk的agent封装
|
|
31
|
+
* @summary 内部自动管理了 llm, mcpServer, ai-sdk的clients 和 tools
|
|
32
|
+
* @returns 暴露了 chat, chatStream方法
|
|
33
|
+
*/
|
|
24
34
|
export class AgentModelProvider {
|
|
25
35
|
constructor({ llmConfig, mcpServers, llm }) {
|
|
26
|
-
|
|
36
|
+
/** mcpServers 允许为配置为 McpServerConfig, 或者任意的 MCPTransport
|
|
37
|
+
* 参考: https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-calling#initializing-an-mcp-client */
|
|
38
|
+
this.mcpServers = [];
|
|
39
|
+
/** ai-sdk的 mcpClient */
|
|
27
40
|
this.mcpClients = [];
|
|
41
|
+
/** 所有的tools */
|
|
42
|
+
this.mcpTools = [];
|
|
43
|
+
/** 需要实时过滤掉的tools name*/
|
|
44
|
+
this.ignoreToolnames = [];
|
|
45
|
+
/** 在 chat 之前,自动更新 所有的tools */
|
|
46
|
+
this.autoUpdateTools = true;
|
|
28
47
|
// 1、保存 mcpServer
|
|
29
48
|
this.mcpServers = mcpServers || [];
|
|
30
49
|
// 2、保存 llm
|
|
@@ -48,40 +67,142 @@ export class AgentModelProvider {
|
|
|
48
67
|
throw new Error('Either llmConfig or llm must be provided');
|
|
49
68
|
}
|
|
50
69
|
}
|
|
51
|
-
|
|
70
|
+
/** 创建一个 ai-sdk的 mcpClient, 创建失败则返回 Null */
|
|
71
|
+
_createOneClient(serverConfig) {
|
|
52
72
|
return __awaiter(this, void 0, void 0, function* () {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
73
|
+
try {
|
|
74
|
+
let transport;
|
|
75
|
+
// transport 一定是 streamableHttp 或者就是: ai-sdk允许的 transport
|
|
76
|
+
if ('type' in serverConfig && serverConfig.type.toLocaleLowerCase() === 'streamablehttp') {
|
|
77
|
+
transport = new StreamableHTTPClientTransport(new URL(serverConfig.url));
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
transport = serverConfig;
|
|
81
|
+
}
|
|
82
|
+
return createMCPClient({ transport: transport });
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
console.error(`Failed to create MCP client`, serverConfig, error);
|
|
86
|
+
return null;
|
|
56
87
|
}
|
|
57
88
|
});
|
|
58
89
|
}
|
|
59
|
-
|
|
90
|
+
/** 创建 ai-sdk的 mcpClient, 失败则保存为null */
|
|
91
|
+
_createMpcClients() {
|
|
60
92
|
return __awaiter(this, void 0, void 0, function* () {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
93
|
+
// 使用 Promise.all 并行处理所有 mcpServer 项
|
|
94
|
+
this.mcpClients = yield Promise.all(this.mcpServers.map((server) => __awaiter(this, void 0, void 0, function* () {
|
|
95
|
+
return this._createOneClient(server);
|
|
96
|
+
})));
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
/** 创建所有 mcpClients 的 tools, 失败则保存为null */
|
|
100
|
+
_createMpcTools() {
|
|
101
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
102
|
+
this.mcpTools = yield Promise.all(this.mcpClients.map((client) => __awaiter(this, void 0, void 0, function* () {
|
|
103
|
+
var _a;
|
|
104
|
+
try {
|
|
105
|
+
return client ? yield ((_a = client === null || client === void 0 ? void 0 : client.tools) === null || _a === void 0 ? void 0 : _a.call(client)) : null;
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
})));
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/** 关闭所有的 clients */
|
|
114
|
+
closeAll() {
|
|
115
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
116
|
+
yield Promise.all(this.mcpClients.map((client) => __awaiter(this, void 0, void 0, function* () {
|
|
117
|
+
try {
|
|
118
|
+
client.close();
|
|
119
|
+
}
|
|
120
|
+
catch (error) { }
|
|
121
|
+
})));
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
initClientsAndTools() {
|
|
125
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
126
|
+
yield this._createMpcClients();
|
|
127
|
+
yield this._createMpcTools();
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
updateMcpServers(mcpServers) {
|
|
131
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
132
|
+
yield this.closeAll();
|
|
133
|
+
this.mcpServers = mcpServers;
|
|
134
|
+
yield this.initClientsAndTools();
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
insertMcpServer(mcpServer) {
|
|
138
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
139
|
+
var _a;
|
|
140
|
+
const find = this.mcpServers.find((item) => item.url === mcpServer.url);
|
|
141
|
+
if (!find) {
|
|
142
|
+
this.mcpServers = [...this.mcpServers, mcpServer];
|
|
143
|
+
const client = yield this._createOneClient(mcpServer);
|
|
144
|
+
this.mcpClients.push(client);
|
|
145
|
+
this.mcpTools.push((yield ((_a = client === null || client === void 0 ? void 0 : client.tools) === null || _a === void 0 ? void 0 : _a.call(client))));
|
|
146
|
+
return true;
|
|
64
147
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
148
|
+
return false;
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
/** 通过引用,删除一个 mcpServers mcpClients mcpTools ignoreToolnames */
|
|
152
|
+
removeMcpServer(mcpServer) {
|
|
153
|
+
const index = this.mcpServers.findIndex((server) => server === mcpServer);
|
|
154
|
+
// 移除
|
|
155
|
+
this.mcpServers.splice(index, 1);
|
|
156
|
+
// 移除
|
|
157
|
+
const delClient = this.mcpClients[index];
|
|
158
|
+
this.mcpClients.splice(index, 1);
|
|
159
|
+
try {
|
|
160
|
+
delClient === null || delClient === void 0 ? void 0 : delClient.close();
|
|
161
|
+
}
|
|
162
|
+
catch (error) { }
|
|
163
|
+
// 移除 tools
|
|
164
|
+
const delTool = this.mcpTools[index];
|
|
165
|
+
this.mcpTools.splice(index, 1);
|
|
166
|
+
// 移除 ignoreToolnames
|
|
167
|
+
if (delTool) {
|
|
168
|
+
Object.keys(delTool).forEach((toolName) => {
|
|
169
|
+
this.ignoreToolnames = this.ignoreToolnames.filter((name) => name !== toolName);
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/** 创建临时允许调用的tools集合 */
|
|
174
|
+
tempMergeTools(extraTool = {}) {
|
|
175
|
+
const toolsResult = this.mcpTools.reduce((acc, curr) => (Object.assign(Object.assign({}, acc), curr)), {});
|
|
176
|
+
Object.assign(toolsResult, extraTool);
|
|
177
|
+
this.ignoreToolnames.forEach((name) => {
|
|
178
|
+
delete toolsResult[name];
|
|
71
179
|
});
|
|
180
|
+
return toolsResult;
|
|
72
181
|
}
|
|
73
|
-
|
|
182
|
+
_chat(chatMethod, _a) {
|
|
74
183
|
return __awaiter(this, void 0, void 0, function* () {
|
|
184
|
+
var _b;
|
|
75
185
|
var { model, maxSteps = 5 } = _a, options = __rest(_a, ["model", "maxSteps"]);
|
|
76
186
|
if (!this.llm) {
|
|
77
187
|
throw new Error('LLM is not initialized');
|
|
78
188
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
189
|
+
if (this.autoUpdateTools) {
|
|
190
|
+
yield this._createMpcTools();
|
|
191
|
+
(_b = this.onUpdatedTools) === null || _b === void 0 ? void 0 : _b.call(this);
|
|
192
|
+
}
|
|
193
|
+
return chatMethod(Object.assign({
|
|
194
|
+
// @ts-ignore ProviderV2 是所有llm的父类, 在每一个具体的llm 类都有一个选择model的函数用法
|
|
195
|
+
model: this.llm(model), tools: this.tempMergeTools(options.tools), stopWhen: stepCountIs(maxSteps) }, options));
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
chat(options) {
|
|
199
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
200
|
+
return this._chat(generateText, options);
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
chatStream(options) {
|
|
204
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
205
|
+
return this._chat(streamText, options);
|
|
85
206
|
});
|
|
86
207
|
}
|
|
87
208
|
}
|
package/dist/agent/type.d.ts
CHANGED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ToolSet } from 'ai';
|
|
2
|
+
import { WebMcpClient } from '../../WebMcpClient';
|
|
3
|
+
/**
|
|
4
|
+
* 快速 从官方 mcp 或 WebMcpClient 这2种client中, 抽取成 ai-sdk 所需要的 tool的对象
|
|
5
|
+
* @params client 一个已连接好的 WebMcpClient
|
|
6
|
+
* @returns ai-sdk的 tool 格式的对象。
|
|
7
|
+
*/
|
|
8
|
+
export declare const getAISDKTools: (client: WebMcpClient) => Promise<ToolSet>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { dynamicTool, jsonSchema } from 'ai';
|
|
11
|
+
/**
|
|
12
|
+
* 快速 从官方 mcp 或 WebMcpClient 这2种client中, 抽取成 ai-sdk 所需要的 tool的对象
|
|
13
|
+
* @params client 一个已连接好的 WebMcpClient
|
|
14
|
+
* @returns ai-sdk的 tool 格式的对象。
|
|
15
|
+
*/
|
|
16
|
+
export const getAISDKTools = (client) => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
|
+
var _a;
|
|
18
|
+
const tools = {};
|
|
19
|
+
try {
|
|
20
|
+
const listToolsResult = yield client.listTools();
|
|
21
|
+
for (const { name, description, inputSchema } of listToolsResult.tools) {
|
|
22
|
+
const execute = (args, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
23
|
+
return client.callTool({ name, arguments: args }, { signal: options === null || options === void 0 ? void 0 : options.abortSignal });
|
|
24
|
+
});
|
|
25
|
+
tools[name] = dynamicTool({
|
|
26
|
+
description,
|
|
27
|
+
inputSchema: jsonSchema(Object.assign(Object.assign({}, inputSchema), { properties: (_a = inputSchema.properties) !== null && _a !== void 0 ? _a : {}, additionalProperties: false })),
|
|
28
|
+
execute
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return tools;
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import Ajv from 'ajv';
|
|
2
|
-
export * from './WebMcpServer';
|
|
3
|
-
export * from './WebMcpClient';
|
|
4
2
|
export { Ajv };
|
|
5
3
|
export { z } from 'zod';
|
|
6
4
|
export { AuthClientProvider } from '@opentiny/next';
|
|
@@ -16,7 +14,10 @@ export type * from '@modelcontextprotocol/sdk/shared/transport.js';
|
|
|
16
14
|
export type * from '@modelcontextprotocol/sdk/client/sse.js';
|
|
17
15
|
export type * from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
18
16
|
export type * from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
19
|
-
export
|
|
17
|
+
export * from './WebMcpServer';
|
|
18
|
+
export * from './WebMcpClient';
|
|
20
19
|
export { createRemoter } from './remoter/createRemoter';
|
|
21
|
-
export {
|
|
20
|
+
export { AgentModelProvider } from './agent/AgentModelProvider';
|
|
21
|
+
export { getAISDKTools } from './agent/utils/getAISDKTools';
|
|
22
22
|
export { QrCode, type QrCodeOption } from './remoter/QrCode';
|
|
23
|
+
export type * from './agent/type';
|