@opentiny/next-sdk 0.3.0-alpha.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,7 +12,8 @@ import { createDeepSeek, DeepSeekProvider } from '@ai-sdk/deepseek'
12
12
  import { ExtensionClientTransport } from '../transport/ExtensionClientTransport'
13
13
  import { MessageChannelTransport } from '@opentiny/next'
14
14
  import { WebMcpClient } from '../WebMcpClient'
15
- import { getAISDKTools } from './utils/getAISDKTools'
15
+ import { getAISDKTools } from './utils/getAISDKTools'
16
+ import { getBuiltinMcpTools } from './utils/getBuiltinMcpTools'
16
17
  import { generateReActToolsPrompt } from './utils/generateReActPrompt'
17
18
  import { parseReActAction } from './utils/parseReActAction'
18
19
 
@@ -82,6 +83,15 @@ export class AgentModelProvider {
82
83
  private async _createOneClient(serverConfig: McpServerConfig) {
83
84
  try {
84
85
  let transport: MCPClientConfig['transport']
86
+ // builtin 类型:使用 navigator.modelContextTesting 作为工具数据源
87
+ if ('type' in serverConfig && serverConfig.type === 'builtin') {
88
+ const builtinClient = serverConfig.client
89
+ // 包装成与 ai-sdk MCPClient 相同接口:提供 tools() 方法
90
+ return {
91
+ tools: () => getBuiltinMcpTools(builtinClient),
92
+ close: async () => {}
93
+ }
94
+ }
85
95
  // transport 一定是 streamableHttp/sse 或者就是: ai-sdk允许的 transport
86
96
  if ('type' in serverConfig && serverConfig.type.toLocaleLowerCase() === 'streamablehttp') {
87
97
  const configWithHeaders = serverConfig as { url: string; headers?: Record<string, string> }
package/agent/type.ts CHANGED
@@ -4,6 +4,17 @@ import type { MCPClientConfig } from '@ai-sdk/mcp'
4
4
  // 从 MCPClientConfig 中提取 transport 类型
5
5
  export type MCPTransport = MCPClientConfig['transport']
6
6
 
7
+ /**
8
+ * 浏览器内置 WebMCP 测试 API 接口 (如 navigator.modelContextTesting)
9
+ */
10
+ export interface BuiltinMcpClient {
11
+ listTools?: () => Promise<any[]>
12
+ getTools?: () => Promise<any[]>
13
+ executeTool: (name: string, input: string) => Promise<any>
14
+ registerTool?: (config: { name: string; execute: (input: any) => Promise<any> | any; [key: string]: any }) => void
15
+ unregisterTool?: (name: string) => void
16
+ }
17
+
7
18
  type ProviderFactory = 'openai' | 'deepseek' | ((options: any) => ProviderV2)
8
19
 
9
20
  type LlmFactoryConfig = {
@@ -39,6 +50,16 @@ export type McpServerConfig =
39
50
  | { type: 'sse'; url: string; useAISdkClient?: boolean; headers?: Record<string, string> }
40
51
  | { type: 'extension'; url: string; sessionId: string; useAISdkClient?: boolean; headers?: Record<string, string> }
41
52
  | { type: 'local'; transport: MCPTransport; useAISdkClient?: boolean }
53
+ | {
54
+ /**
55
+ * 浏览器内置 WebMCP 类型。
56
+ * 将 `navigator.modelContextTesting` 作为 MCP 工具数据源,
57
+ * 通过 `getBuiltinMcpTools` 适配为 ai-sdk 可调用的 ToolSet。
58
+ */
59
+ type: 'builtin'
60
+ /** 传入 `navigator.modelContextTesting` 对象 */
61
+ client: BuiltinMcpClient
62
+ }
42
63
 
43
64
  /** */
44
65
  export interface IAgentModelProviderOption {
@@ -46,4 +67,4 @@ export interface IAgentModelProviderOption {
46
67
  llmConfig: IAgentModelProviderLlmConfig
47
68
  /** Mcp Server的配置对象的集合,键为服务器名称,值为配置对象 */
48
69
  mcpServers?: Record<string, McpServerConfig>
49
- }
70
+ }
@@ -0,0 +1,74 @@
1
+ import { dynamicTool, jsonSchema, Tool, ToolExecutionOptions, ToolSet } from 'ai'
2
+
3
+ /**
4
+ * 浏览器内置 WebMCP 测试 API 的工具描述格式(Chrome navigator.modelContextTesting)
5
+ */
6
+ type BuiltinToolDescriptor = {
7
+ name: string
8
+ description?: string
9
+ inputSchema?: {
10
+ type?: string
11
+ properties?: Record<string, unknown>
12
+ required?: string[]
13
+ [key: string]: unknown
14
+ }
15
+ }
16
+
17
+ type BuiltinModelContextTesting = {
18
+ listTools?: () => Promise<BuiltinToolDescriptor[]>
19
+ getTools?: () => Promise<BuiltinToolDescriptor[]>
20
+ executeTool?: (name: string, input: string) => Promise<unknown>
21
+ }
22
+
23
+ /**
24
+ * 将浏览器内置 WebMCP 的 `navigator.modelContext` 适配为 ai-sdk 的 ToolSet。
25
+ *
26
+ * 类似 getAISDKTools,但数据源是浏览器原生 API 而非 MCP client。
27
+ * 工具执行时通过 `executeTool(name, JSON.stringify(args))` 代理给浏览器。
28
+ *
29
+ * @param client - `navigator.modelContext` 对象
30
+ * @returns ai-sdk 格式的 ToolSet,可直接传入 streamText/generateText 的 tools 参数
31
+ */
32
+ export const getBuiltinMcpTools = async (client: object | undefined | null): Promise<ToolSet> => {
33
+ const tools: Record<string, Tool> = {}
34
+ if (!client) {
35
+ return tools
36
+ }
37
+
38
+ const testing = client as BuiltinModelContextTesting
39
+
40
+ // 优先使用 listTools,降级到 getTools
41
+ const listFn = testing.listTools ?? testing.getTools
42
+ if (!listFn) {
43
+ return tools
44
+ }
45
+
46
+ const rawList = await listFn.call(testing)
47
+ const list = Array.isArray(rawList) ? (rawList as BuiltinToolDescriptor[]) : []
48
+
49
+ for (const descriptor of list) {
50
+ const { name, description, inputSchema = {} } = descriptor
51
+
52
+ // 规范化 inputSchema:补全 properties/additionalProperties 字段
53
+ const normalizedSchema = {
54
+ type: 'object' as const,
55
+ properties: (inputSchema.properties ?? {}) as Record<string, unknown>,
56
+ ...(inputSchema.required ? { required: inputSchema.required } : {}),
57
+ additionalProperties: false,
58
+ ...inputSchema
59
+ }
60
+
61
+ tools[name] = dynamicTool({
62
+ description: description ?? '',
63
+ inputSchema: jsonSchema(normalizedSchema as Parameters<typeof jsonSchema>[0]),
64
+ async execute(args) {
65
+ if (!testing.executeTool) {
66
+ throw new Error(`navigator.modelContextTesting.executeTool is not available`)
67
+ }
68
+ return testing.executeTool(name, JSON.stringify(args ?? {}))
69
+ }
70
+ })
71
+ }
72
+
73
+ return tools
74
+ }