agentrun-sdk 0.0.4__py3-none-any.whl

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.
Files changed (128) hide show
  1. agentrun/__init__.py +209 -0
  2. agentrun/agent_runtime/__client_async_template.py +466 -0
  3. agentrun/agent_runtime/__endpoint_async_template.py +345 -0
  4. agentrun/agent_runtime/__init__.py +53 -0
  5. agentrun/agent_runtime/__runtime_async_template.py +477 -0
  6. agentrun/agent_runtime/api/__data_async_template.py +58 -0
  7. agentrun/agent_runtime/api/__init__.py +6 -0
  8. agentrun/agent_runtime/api/control.py +1362 -0
  9. agentrun/agent_runtime/api/data.py +98 -0
  10. agentrun/agent_runtime/client.py +868 -0
  11. agentrun/agent_runtime/endpoint.py +649 -0
  12. agentrun/agent_runtime/model.py +362 -0
  13. agentrun/agent_runtime/runtime.py +904 -0
  14. agentrun/credential/__client_async_template.py +177 -0
  15. agentrun/credential/__credential_async_template.py +216 -0
  16. agentrun/credential/__init__.py +28 -0
  17. agentrun/credential/api/__init__.py +5 -0
  18. agentrun/credential/api/control.py +606 -0
  19. agentrun/credential/client.py +319 -0
  20. agentrun/credential/credential.py +381 -0
  21. agentrun/credential/model.py +248 -0
  22. agentrun/integration/__init__.py +21 -0
  23. agentrun/integration/agentscope/__init__.py +12 -0
  24. agentrun/integration/agentscope/adapter.py +17 -0
  25. agentrun/integration/agentscope/builtin.py +65 -0
  26. agentrun/integration/agentscope/message_adapter.py +185 -0
  27. agentrun/integration/agentscope/model_adapter.py +60 -0
  28. agentrun/integration/agentscope/tool_adapter.py +59 -0
  29. agentrun/integration/builtin/__init__.py +16 -0
  30. agentrun/integration/builtin/model.py +97 -0
  31. agentrun/integration/builtin/sandbox.py +276 -0
  32. agentrun/integration/builtin/toolset.py +47 -0
  33. agentrun/integration/crewai/__init__.py +12 -0
  34. agentrun/integration/crewai/adapter.py +9 -0
  35. agentrun/integration/crewai/builtin.py +65 -0
  36. agentrun/integration/crewai/model_adapter.py +27 -0
  37. agentrun/integration/crewai/tool_adapter.py +26 -0
  38. agentrun/integration/google_adk/__init__.py +12 -0
  39. agentrun/integration/google_adk/adapter.py +15 -0
  40. agentrun/integration/google_adk/builtin.py +65 -0
  41. agentrun/integration/google_adk/message_adapter.py +144 -0
  42. agentrun/integration/google_adk/model_adapter.py +43 -0
  43. agentrun/integration/google_adk/tool_adapter.py +25 -0
  44. agentrun/integration/langchain/__init__.py +9 -0
  45. agentrun/integration/langchain/adapter.py +15 -0
  46. agentrun/integration/langchain/builtin.py +71 -0
  47. agentrun/integration/langchain/message_adapter.py +141 -0
  48. agentrun/integration/langchain/model_adapter.py +37 -0
  49. agentrun/integration/langchain/tool_adapter.py +50 -0
  50. agentrun/integration/langgraph/__init__.py +13 -0
  51. agentrun/integration/langgraph/adapter.py +20 -0
  52. agentrun/integration/langgraph/builtin.py +65 -0
  53. agentrun/integration/pydantic_ai/__init__.py +12 -0
  54. agentrun/integration/pydantic_ai/adapter.py +13 -0
  55. agentrun/integration/pydantic_ai/builtin.py +65 -0
  56. agentrun/integration/pydantic_ai/model_adapter.py +44 -0
  57. agentrun/integration/pydantic_ai/tool_adapter.py +19 -0
  58. agentrun/integration/utils/__init__.py +112 -0
  59. agentrun/integration/utils/adapter.py +167 -0
  60. agentrun/integration/utils/canonical.py +157 -0
  61. agentrun/integration/utils/converter.py +134 -0
  62. agentrun/integration/utils/model.py +107 -0
  63. agentrun/integration/utils/tool.py +1714 -0
  64. agentrun/model/__client_async_template.py +357 -0
  65. agentrun/model/__init__.py +57 -0
  66. agentrun/model/__model_proxy_async_template.py +270 -0
  67. agentrun/model/__model_service_async_template.py +267 -0
  68. agentrun/model/api/__init__.py +6 -0
  69. agentrun/model/api/control.py +1173 -0
  70. agentrun/model/api/data.py +196 -0
  71. agentrun/model/client.py +674 -0
  72. agentrun/model/model.py +218 -0
  73. agentrun/model/model_proxy.py +439 -0
  74. agentrun/model/model_service.py +438 -0
  75. agentrun/sandbox/__browser_sandbox_async_template.py +113 -0
  76. agentrun/sandbox/__client_async_template.py +466 -0
  77. agentrun/sandbox/__code_interpreter_sandbox_async_template.py +466 -0
  78. agentrun/sandbox/__init__.py +54 -0
  79. agentrun/sandbox/__sandbox_async_template.py +398 -0
  80. agentrun/sandbox/__template_async_template.py +150 -0
  81. agentrun/sandbox/api/__browser_data_async_template.py +140 -0
  82. agentrun/sandbox/api/__code_interpreter_data_async_template.py +206 -0
  83. agentrun/sandbox/api/__init__.py +17 -0
  84. agentrun/sandbox/api/__sandbox_data_async_template.py +100 -0
  85. agentrun/sandbox/api/browser_data.py +172 -0
  86. agentrun/sandbox/api/code_interpreter_data.py +396 -0
  87. agentrun/sandbox/api/control.py +1051 -0
  88. agentrun/sandbox/api/playwright_async.py +492 -0
  89. agentrun/sandbox/api/playwright_sync.py +492 -0
  90. agentrun/sandbox/api/sandbox_data.py +140 -0
  91. agentrun/sandbox/browser_sandbox.py +191 -0
  92. agentrun/sandbox/client.py +878 -0
  93. agentrun/sandbox/code_interpreter_sandbox.py +829 -0
  94. agentrun/sandbox/model.py +269 -0
  95. agentrun/sandbox/sandbox.py +737 -0
  96. agentrun/sandbox/template.py +215 -0
  97. agentrun/server/__init__.py +82 -0
  98. agentrun/server/invoker.py +131 -0
  99. agentrun/server/model.py +225 -0
  100. agentrun/server/openai_protocol.py +798 -0
  101. agentrun/server/protocol.py +96 -0
  102. agentrun/server/server.py +192 -0
  103. agentrun/toolset/__client_async_template.py +62 -0
  104. agentrun/toolset/__init__.py +51 -0
  105. agentrun/toolset/__toolset_async_template.py +204 -0
  106. agentrun/toolset/api/__init__.py +17 -0
  107. agentrun/toolset/api/control.py +262 -0
  108. agentrun/toolset/api/mcp.py +100 -0
  109. agentrun/toolset/api/openapi.py +1184 -0
  110. agentrun/toolset/client.py +102 -0
  111. agentrun/toolset/model.py +160 -0
  112. agentrun/toolset/toolset.py +271 -0
  113. agentrun/utils/__data_api_async_template.py +715 -0
  114. agentrun/utils/__init__.py +5 -0
  115. agentrun/utils/__resource_async_template.py +158 -0
  116. agentrun/utils/config.py +258 -0
  117. agentrun/utils/control_api.py +78 -0
  118. agentrun/utils/data_api.py +1110 -0
  119. agentrun/utils/exception.py +149 -0
  120. agentrun/utils/helper.py +34 -0
  121. agentrun/utils/log.py +77 -0
  122. agentrun/utils/model.py +168 -0
  123. agentrun/utils/resource.py +291 -0
  124. agentrun_sdk-0.0.4.dist-info/METADATA +262 -0
  125. agentrun_sdk-0.0.4.dist-info/RECORD +128 -0
  126. agentrun_sdk-0.0.4.dist-info/WHEEL +5 -0
  127. agentrun_sdk-0.0.4.dist-info/licenses/LICENSE +201 -0
  128. agentrun_sdk-0.0.4.dist-info/top_level.txt +1 -0
@@ -0,0 +1,96 @@
1
+ """协议抽象层 / Protocol Abstraction Layer
2
+
3
+ 定义协议接口,支持未来扩展多种协议格式(OpenAI, Anthropic, Google 等)。
4
+ Defines protocol interfaces, supporting future expansion of various protocol formats (OpenAI, Anthropic, Google, etc.).
5
+
6
+ 基于 Router 的设计 / Router-based design:
7
+ - 每个协议提供自己的 FastAPI Router / Each protocol provides its own FastAPI Router
8
+ - Server 负责挂载 Router 并管理路由前缀 / Server mounts Routers and manages route prefixes
9
+ - 协议完全自治,无需向 Server 声明接口 / Protocols are fully autonomous, no need to declare interfaces to Server
10
+ """
11
+
12
+ from abc import ABC, abstractmethod
13
+ from typing import Awaitable, Callable, TYPE_CHECKING, Union
14
+
15
+ from .model import AgentRequest, AgentResult
16
+
17
+ if TYPE_CHECKING:
18
+ from fastapi import APIRouter
19
+
20
+ from .invoker import AgentInvoker
21
+
22
+
23
+ class ProtocolHandler(ABC):
24
+ """协议处理器基类 / Protocol Handler Base Class
25
+
26
+ 基于 Router 的设计 / Router-based design:
27
+ 协议通过 as_fastapi_router() 方法提供完整的路由定义,包括所有端点、请求处理、响应格式化等。
28
+ Protocol provides complete route definitions through as_fastapi_router() method, including all endpoints, request handling, response formatting, etc.
29
+
30
+ Server 只需挂载 Router 并管理路由前缀,无需了解协议细节。
31
+ Server only needs to mount Router and manage route prefixes, without knowing protocol details.
32
+ """
33
+
34
+ @abstractmethod
35
+ def as_fastapi_router(self, agent_invoker: "AgentInvoker") -> "APIRouter":
36
+ """
37
+ 将协议转换为 FastAPI Router
38
+
39
+ 协议自己决定:
40
+ - 有哪些端点
41
+ - 端点的路径
42
+ - HTTP 方法
43
+ - 请求/响应处理
44
+
45
+ Args:
46
+ agent_invoker: Agent 调用器,用于执行用户的 invoke_agent
47
+
48
+ Returns:
49
+ APIRouter: FastAPI 路由器,包含该协议的所有端点
50
+
51
+ Example:
52
+ ```python
53
+ def as_fastapi_router(self, agent_invoker):
54
+ router = APIRouter()
55
+
56
+ @router.post("/chat/completions")
57
+ async def chat_completions(request: Request):
58
+ data = await request.json()
59
+ agent_request = parse_request(data)
60
+ result = await agent_invoker.invoke(agent_request)
61
+ return format_response(result)
62
+
63
+ return router
64
+ ```
65
+ """
66
+ pass
67
+
68
+ def get_prefix(self) -> str:
69
+ """
70
+ 获取协议建议的路由前缀
71
+
72
+ Server 会优先使用用户指定的前缀,如果没有指定则使用此建议值。
73
+
74
+ Returns:
75
+ str: 建议的前缀,如 "/v1" 或 ""
76
+
77
+ Example:
78
+ - OpenAI 协议: "/v1"
79
+ - Anthropic 协议: "/anthropic"
80
+ - 无前缀: ""
81
+ """
82
+ return ""
83
+
84
+
85
+ # Handler 类型定义
86
+ # 同步 handler: 普通函数,直接返回 AgentResult
87
+ SyncInvokeAgentHandler = Callable[[AgentRequest], AgentResult]
88
+
89
+ # 异步 handler: 协程函数,返回 Awaitable[AgentResult]
90
+ AsyncInvokeAgentHandler = Callable[[AgentRequest], Awaitable[AgentResult]]
91
+
92
+ # 通用 handler: 可以是同步或异步
93
+ InvokeAgentHandler = Union[
94
+ SyncInvokeAgentHandler,
95
+ AsyncInvokeAgentHandler,
96
+ ]
@@ -0,0 +1,192 @@
1
+ """AgentRun HTTP Server / AgentRun HTTP 服务器
2
+
3
+ 基于 Router 的设计 / Router-based design:
4
+ - 每个协议提供自己的 Router / Each protocol provides its own Router
5
+ - Server 负责挂载 Router 并管理路由前缀 / Server mounts Routers and manages route prefixes
6
+ - 支持多协议同时运行 / Supports running multiple protocols simultaneously
7
+ """
8
+
9
+ from typing import Any, Dict, List, Optional
10
+
11
+ from fastapi import FastAPI
12
+ import uvicorn
13
+
14
+ from agentrun.utils.log import logger
15
+
16
+ from .invoker import AgentInvoker
17
+ from .openai_protocol import OpenAIProtocolHandler
18
+ from .protocol import InvokeAgentHandler, ProtocolHandler
19
+
20
+
21
+ class AgentRunServer:
22
+ """AgentRun HTTP Server / AgentRun HTTP 服务器
23
+
24
+ 基于 Router 的架构 / Router-based architecture:
25
+ - 每个协议提供完整的 FastAPI Router / Each protocol provides a complete FastAPI Router
26
+ - Server 只负责组装和前缀管理 / Server only handles assembly and prefix management
27
+ - 易于扩展新协议 / Easy to extend with new protocols
28
+
29
+ Example (默认 OpenAI 协议 / Default OpenAI protocol):
30
+ >>> def invoke_agent(request: AgentRequest):
31
+ ... return "Hello, world!"
32
+ >>>
33
+ >>> server = AgentRunServer(invoke_agent=invoke_agent)
34
+ >>> server.start(port=8000)
35
+ # 可访问 / Accessible: POST http://localhost:8000/v1/chat/completions
36
+
37
+ Example (自定义前缀 / Custom prefix):
38
+ >>> server = AgentRunServer(
39
+ ... invoke_agent=invoke_agent,
40
+ ... prefix_overrides={"OpenAIProtocolHandler": "/api/v1"}
41
+ ... )
42
+ >>> server.start(port=8000)
43
+ # 可访问 / Accessible: POST http://localhost:8000/api/v1/chat/completions
44
+
45
+ Example (多协议 / Multiple protocols):
46
+ >>> server = AgentRunServer(
47
+ ... invoke_agent=invoke_agent,
48
+ ... protocols=[
49
+ ... OpenAIProtocolHandler(),
50
+ ... CustomProtocolHandler(),
51
+ ... ]
52
+ ... )
53
+ >>> server.start(port=8000)
54
+
55
+ Example (集成到现有 FastAPI 应用 / Integrate with existing FastAPI app):
56
+ >>> from fastapi import FastAPI
57
+ >>>
58
+ >>> app = FastAPI()
59
+ >>> agent_server = AgentRunServer(invoke_agent=invoke_agent)
60
+ >>> app.mount("/agent", agent_server.as_fastapi_app())
61
+ # 可访问 / Accessible: POST http://localhost:8000/agent/v1/chat/completions
62
+ """
63
+
64
+ def __init__(
65
+ self,
66
+ invoke_agent: InvokeAgentHandler,
67
+ protocols: Optional[List[ProtocolHandler]] = None,
68
+ prefix_overrides: Optional[Dict[str, str]] = None,
69
+ ):
70
+ """初始化 AgentRun Server / Initialize AgentRun Server
71
+
72
+ Args:
73
+ invoke_agent: Agent 调用回调函数 / Agent invocation callback function
74
+ - 可以是同步或异步函数 / Can be synchronous or asynchronous function
75
+ - 支持返回字符串、AgentResponse 或生成器 / Supports returning string, AgentResponse or generator
76
+
77
+ protocols: 协议处理器列表 / List of protocol handlers
78
+ - 默认使用 OpenAI 协议 / Default uses OpenAI protocol
79
+ - 可以添加自定义协议 / Can add custom protocols
80
+
81
+ prefix_overrides: 协议前缀覆盖 / Protocol prefix overrides
82
+ - 格式 / Format: {协议类名 / protocol class name: 前缀 / prefix}
83
+ - 例如 / Example: {"OpenAIProtocolHandler": "/api/v1"}
84
+ """
85
+ self.app = FastAPI(title="AgentRun Server")
86
+ self.agent_invoker = AgentInvoker(invoke_agent)
87
+
88
+ # 默认使用 OpenAI 协议
89
+ if protocols is None:
90
+ protocols = [OpenAIProtocolHandler()]
91
+
92
+ self.prefix_overrides = prefix_overrides or {}
93
+
94
+ # 挂载所有协议的 Router
95
+ self._mount_protocols(protocols)
96
+
97
+ def _mount_protocols(self, protocols: List[ProtocolHandler]):
98
+ """挂载所有协议的路由
99
+
100
+ Args:
101
+ protocols: 协议处理器列表
102
+ """
103
+ for protocol in protocols:
104
+ # 获取协议的 Router
105
+ router = protocol.as_fastapi_router(self.agent_invoker)
106
+
107
+ # 确定路由前缀
108
+ prefix = self._get_protocol_prefix(protocol)
109
+
110
+ # 挂载到主应用
111
+ self.app.include_router(router, prefix=prefix)
112
+
113
+ logger.info(
114
+ f"✅ 已挂载协议: {protocol.__class__.__name__} ->"
115
+ f" {prefix or '(无前缀)'}"
116
+ )
117
+
118
+ def _get_protocol_prefix(self, protocol: ProtocolHandler) -> str:
119
+ """获取协议的路由前缀
120
+
121
+ 优先级:
122
+ 1. 用户指定的覆盖前缀
123
+ 2. 协议自己的建议前缀
124
+ 3. 基于协议类名的默认前缀
125
+
126
+ Args:
127
+ protocol: 协议处理器
128
+
129
+ Returns:
130
+ str: 路由前缀
131
+ """
132
+ protocol_name = protocol.__class__.__name__
133
+
134
+ # 1. 检查用户覆盖
135
+ if protocol_name in self.prefix_overrides:
136
+ return self.prefix_overrides[protocol_name]
137
+
138
+ # 2. 使用协议建议
139
+ suggested_prefix = protocol.get_prefix()
140
+ if suggested_prefix:
141
+ return suggested_prefix
142
+
143
+ # 3. 默认前缀(基于类名)
144
+ # OpenAIProtocolHandler -> /openai
145
+ name_without_handler = protocol_name.replace(
146
+ "ProtocolHandler", ""
147
+ ).replace("Handler", "")
148
+ return f"/{name_without_handler.lower()}"
149
+
150
+ def start(
151
+ self,
152
+ host: str = "0.0.0.0",
153
+ port: int = 9000,
154
+ log_level: str = "info",
155
+ **kwargs: Any,
156
+ ):
157
+ """启动 HTTP 服务器
158
+
159
+ Args:
160
+ host: 监听地址,默认 0.0.0.0
161
+ port: 监听端口,默认 9000
162
+ log_level: 日志级别,默认 info
163
+ **kwargs: 传递给 uvicorn.run 的其他参数
164
+ """
165
+ logger.info(f"🚀 启动 AgentRun Server: http://{host}:{port}")
166
+
167
+ # 打印路由信息
168
+ # for route in self.app.routes:
169
+ # if hasattr(route, "methods") and hasattr(route, "path"):
170
+ # methods = ", ".join(route.methods) # type: ignore
171
+ # logger.info(f" {methods:10} {route.path}") # type: ignore
172
+
173
+ uvicorn.run(
174
+ self.app, host=host, port=port, log_level=log_level, **kwargs
175
+ )
176
+
177
+ def as_fastapi_app(self) -> FastAPI:
178
+ """导出 FastAPI 应用
179
+
180
+ 用于集成到现有的 FastAPI 项目中。
181
+
182
+ Returns:
183
+ FastAPI: FastAPI 应用实例
184
+
185
+ Example:
186
+ >>> from fastapi import FastAPI
187
+ >>>
188
+ >>> app = FastAPI()
189
+ >>> agent_server = AgentRunServer(invoke_agent=invoke_agent)
190
+ >>> app.mount("/agent", agent_server.as_fastapi_app())
191
+ """
192
+ return self.app
@@ -0,0 +1,62 @@
1
+ """ToolSet 客户端 / ToolSet Client
2
+
3
+ 此模块提供工具集的客户端API。
4
+ This module provides the client API for toolsets.
5
+ """
6
+
7
+ from typing import Optional
8
+
9
+ from alibabacloud_devs20230714.models import ListToolsetsRequest
10
+
11
+ from agentrun.toolset.api.control import ToolControlAPI
12
+ from agentrun.toolset.model import ToolSetListInput
13
+ from agentrun.utils.config import Config
14
+ from agentrun.utils.exception import HTTPError
15
+
16
+ from .toolset import ToolSet
17
+
18
+
19
+ class ToolSetClient:
20
+ """ToolSet 客户端 / ToolSet Client
21
+
22
+ 提供工具集的获取和列表功能。
23
+ Provides get and list functions for toolsets.
24
+ """
25
+
26
+ def __init__(self, config: Optional[Config] = None):
27
+ """初始化客户端 / Initialize client
28
+
29
+ Args:
30
+ config: 配置对象,可选 / Configuration object, optional
31
+ """
32
+ self.__control_api = ToolControlAPI(config)
33
+
34
+ async def get_async(
35
+ self,
36
+ name: str,
37
+ config: Optional[Config] = None,
38
+ ):
39
+ try:
40
+ result = await self.__control_api.get_toolset_async(
41
+ name=name,
42
+ config=config,
43
+ )
44
+ except HTTPError as e:
45
+ raise e.to_resource_error("ToolSet", name) from e
46
+
47
+ return ToolSet.from_inner_object(result)
48
+
49
+ async def list_async(
50
+ self,
51
+ input: Optional[ToolSetListInput] = None,
52
+ config: Optional[Config] = None,
53
+ ):
54
+ if input is None:
55
+ input = ToolSetListInput()
56
+
57
+ result = await self.__control_api.list_toolsets_async(
58
+ input=ListToolsetsRequest().from_map(input.model_dump()),
59
+ config=config,
60
+ )
61
+
62
+ return [ToolSet.from_inner_object(item) for item in result.data]
@@ -0,0 +1,51 @@
1
+ """ToolSet 模块 / ToolSet Module
2
+
3
+ 此模块提供工具集管理功能。
4
+ This module provides toolset management functionality.
5
+ """
6
+
7
+ from .api import ApiSet, MCPSession, MCPToolSet, OpenAPI, ToolControlAPI
8
+ from .client import ToolSetClient
9
+ from .model import (
10
+ APIKeyAuthParameter,
11
+ Authorization,
12
+ AuthorizationParameters,
13
+ MCPServerConfig,
14
+ OpenAPIToolMeta,
15
+ SchemaType,
16
+ ToolInfo,
17
+ ToolMeta,
18
+ ToolSchema,
19
+ ToolSetListInput,
20
+ ToolSetSchema,
21
+ ToolSetSpec,
22
+ ToolSetStatus,
23
+ ToolSetStatusOutputs,
24
+ ToolSetStatusOutputsUrls,
25
+ )
26
+ from .toolset import ToolSet
27
+
28
+ __all__ = [
29
+ "ToolControlAPI",
30
+ "MCPSession",
31
+ "MCPToolSet",
32
+ "OpenAPI",
33
+ "ApiSet",
34
+ "ToolSetListInput",
35
+ "ToolSetClient",
36
+ "ToolSet",
37
+ "SchemaType",
38
+ "ToolSetStatusOutputsUrls",
39
+ "MCPServerConfig",
40
+ "ToolMeta",
41
+ "ToolInfo",
42
+ "ToolSchema",
43
+ "OpenAPIToolMeta",
44
+ "ToolSetStatusOutputs",
45
+ "APIKeyAuthParameter",
46
+ "AuthorizationParameters",
47
+ "Authorization",
48
+ "ToolSetSchema",
49
+ "ToolSetSpec",
50
+ "ToolSetStatus",
51
+ ]
@@ -0,0 +1,204 @@
1
+ """ToolSet 资源类 / ToolSet Resource Class
2
+
3
+ 提供工具集资源的面向对象封装和完整生命周期管理。
4
+ Provides object-oriented wrapper and complete lifecycle management for toolset resources.
5
+ """
6
+
7
+ from typing import Any, Dict, Optional, Tuple
8
+
9
+ import pydash
10
+
11
+ from agentrun.utils.config import Config
12
+ from agentrun.utils.log import logger
13
+ from agentrun.utils.model import BaseModel
14
+
15
+ from .api.openapi import OpenAPI
16
+ from .model import (
17
+ MCPServerConfig,
18
+ SchemaType,
19
+ ToolInfo,
20
+ ToolSetSpec,
21
+ ToolSetStatus,
22
+ )
23
+
24
+
25
+ class ToolSet(BaseModel):
26
+ """工具集资源 / ToolSet Resource
27
+
28
+ 提供工具集的查询、调用等功能。
29
+ Provides query, invocation and other functionality for toolsets.
30
+
31
+ Attributes:
32
+ created_time: 创建时间 / Creation time
33
+ description: 描述 / Description
34
+ generation: 版本号 / Generation number
35
+ kind: 资源类型 / Resource kind
36
+ labels: 标签 / Labels
37
+ name: 工具集名称 / ToolSet name
38
+ spec: 规格配置 / Specification
39
+ status: 状态 / Status
40
+ uid: 唯一标识符 / Unique identifier
41
+ """
42
+
43
+ created_time: Optional[str] = None
44
+ description: Optional[str] = None
45
+ generation: Optional[int] = None
46
+ kind: Optional[str] = None
47
+ labels: Optional[Dict[str, str]] = None
48
+ name: Optional[str] = None
49
+ spec: Optional[ToolSetSpec] = None
50
+ status: Optional[ToolSetStatus] = None
51
+ uid: Optional[str] = None
52
+
53
+ @classmethod
54
+ def __get_client(cls, config: Optional[Config] = None):
55
+ from .client import ToolSetClient
56
+
57
+ return ToolSetClient(config)
58
+
59
+ @classmethod
60
+ async def get_by_name_async(
61
+ cls, name: str, config: Optional[Config] = None
62
+ ):
63
+ cli = cls.__get_client(config)
64
+ return await cli.get_async(name=name)
65
+
66
+ def type(self):
67
+ return SchemaType(pydash.get(self, "spec.tool_schema.type", ""))
68
+
69
+ def _get_openapi_auth_defaults(
70
+ self,
71
+ ) -> Tuple[Dict[str, Any], Dict[str, Any]]:
72
+ headers: Dict[str, Any] = {}
73
+ query: Dict[str, Any] = {}
74
+
75
+ auth_config = pydash.get(self, "spec.auth_config", None)
76
+ auth_type = getattr(auth_config, "type", None) if auth_config else None
77
+
78
+ if auth_type == "APIKey":
79
+ api_key_param = pydash.get(
80
+ auth_config,
81
+ "parameters.api_key_parameter",
82
+ None,
83
+ )
84
+ if api_key_param:
85
+ key = getattr(api_key_param, "key", None)
86
+ value = getattr(api_key_param, "value", None)
87
+ location = getattr(api_key_param, "in_", None)
88
+ if key and value is not None:
89
+ if location == "header":
90
+ headers[key] = value
91
+ elif location == "query":
92
+ query[key] = value
93
+
94
+ return headers, query
95
+
96
+ def _get_openapi_base_url(self) -> Optional[str]:
97
+ return pydash.get(
98
+ self,
99
+ "status.outputs.urls.intranet_url",
100
+ None,
101
+ ) or pydash.get(self, "status.outputs.urls.internet_url", None)
102
+
103
+ async def get_async(self, config: Optional[Config] = None):
104
+ if self.name is None:
105
+ raise ValueError("ToolSet name is required to get the ToolSet.")
106
+
107
+ result = await self.get_by_name_async(name=self.name, config=config)
108
+ return self.update_self(result)
109
+
110
+ async def list_tools_async(self, config: Optional[Config] = None):
111
+ """异步获取工具列表,返回统一的 ToolInfo 列表"""
112
+ if self.type() == SchemaType.MCP:
113
+ mcp_tools = pydash.get(self, "status.outputs.tools", [])
114
+ return [ToolInfo.from_mcp_tool(tool) for tool in mcp_tools]
115
+ elif self.type() == SchemaType.OpenAPI:
116
+ # 直接使用 to_apiset 转换
117
+ apiset = self.to_apiset(config=config)
118
+ return apiset.tools()
119
+ return []
120
+
121
+ async def call_tool_async(
122
+ self,
123
+ name: str,
124
+ arguments: Optional[Dict[str, str]] = None,
125
+ config: Optional[Config] = None,
126
+ ):
127
+ """异步调用工具,统一使用 ApiSet 实现"""
128
+ apiset = self.to_apiset(config=config)
129
+
130
+ # 对于 OpenAPI,可能需要解析 operation name
131
+ if self.type() == SchemaType.OpenAPI:
132
+ # 尝试查找实际的 operation name
133
+ tool = apiset.get_tool(name)
134
+ if tool is None:
135
+ # 尝试通过 tool_id 映射查找
136
+ openapi_tools = (
137
+ pydash.get(self, "status.outputs.open_api_tools", []) or []
138
+ )
139
+ for tool_meta in openapi_tools:
140
+ if tool_meta is None:
141
+ continue
142
+ if hasattr(tool_meta, "model_dump"):
143
+ tool_meta = tool_meta.model_dump()
144
+ if not isinstance(tool_meta, dict):
145
+ continue
146
+ if tool_meta.get("tool_id") == name:
147
+ name = tool_meta.get("tool_name") or name
148
+ break
149
+
150
+ logger.debug("invoke tool %s with arguments %s", name, arguments)
151
+ result = await apiset.invoke_async(
152
+ name=name, arguments=arguments, config=config
153
+ )
154
+ logger.debug("invoke tool %s got result %s", name, result)
155
+ return result
156
+
157
+ def to_apiset(self, config: Optional[Config] = None):
158
+ """将 ToolSet 转换为统一的 ApiSet 对象
159
+
160
+ Returns:
161
+ ApiSet: 统一的工具集接口
162
+ """
163
+ from .api.openapi import ApiSet
164
+
165
+ if self.type() == SchemaType.MCP:
166
+ from .api.mcp import MCPToolSet
167
+
168
+ mcp_server_config: MCPServerConfig = pydash.get(
169
+ self, "status.outputs.mcp_server_config", None
170
+ )
171
+ assert (
172
+ mcp_server_config.url is not None
173
+ ), "MCP server URL is missing."
174
+
175
+ cfg = Config.with_configs(
176
+ config, Config(headers=mcp_server_config.headers)
177
+ )
178
+
179
+ mcp_client = MCPToolSet(
180
+ url=mcp_server_config.url,
181
+ config=cfg,
182
+ )
183
+
184
+ # 获取 MCP tools
185
+ mcp_tools = pydash.get(self, "status.outputs.tools", [])
186
+
187
+ return ApiSet.from_mcp_tools(
188
+ tools=mcp_tools,
189
+ mcp_client=mcp_client,
190
+ config=cfg,
191
+ )
192
+
193
+ elif self.type() == SchemaType.OpenAPI:
194
+ headers, query = self._get_openapi_auth_defaults()
195
+
196
+ return ApiSet.from_openapi_schema(
197
+ schema=pydash.get(self, "spec.tool_schema.detail", None),
198
+ base_url=self._get_openapi_base_url(),
199
+ headers=headers,
200
+ query_params=query,
201
+ config=config,
202
+ )
203
+
204
+ raise ValueError(f"Unsupported ToolSet type: {self.type()}")
@@ -0,0 +1,17 @@
1
+ """ToolSet API 模块 / ToolSet API Module
2
+
3
+ 此模块包含工具集的 API 接口。
4
+ This module contains API interfaces for toolsets.
5
+ """
6
+
7
+ from .control import ToolControlAPI
8
+ from .mcp import MCPSession, MCPToolSet
9
+ from .openapi import ApiSet, OpenAPI
10
+
11
+ __all__ = [
12
+ "ToolControlAPI",
13
+ "MCPSession",
14
+ "MCPToolSet",
15
+ "OpenAPI",
16
+ "ApiSet",
17
+ ]