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.
- agentrun/__init__.py +209 -0
- agentrun/agent_runtime/__client_async_template.py +466 -0
- agentrun/agent_runtime/__endpoint_async_template.py +345 -0
- agentrun/agent_runtime/__init__.py +53 -0
- agentrun/agent_runtime/__runtime_async_template.py +477 -0
- agentrun/agent_runtime/api/__data_async_template.py +58 -0
- agentrun/agent_runtime/api/__init__.py +6 -0
- agentrun/agent_runtime/api/control.py +1362 -0
- agentrun/agent_runtime/api/data.py +98 -0
- agentrun/agent_runtime/client.py +868 -0
- agentrun/agent_runtime/endpoint.py +649 -0
- agentrun/agent_runtime/model.py +362 -0
- agentrun/agent_runtime/runtime.py +904 -0
- agentrun/credential/__client_async_template.py +177 -0
- agentrun/credential/__credential_async_template.py +216 -0
- agentrun/credential/__init__.py +28 -0
- agentrun/credential/api/__init__.py +5 -0
- agentrun/credential/api/control.py +606 -0
- agentrun/credential/client.py +319 -0
- agentrun/credential/credential.py +381 -0
- agentrun/credential/model.py +248 -0
- agentrun/integration/__init__.py +21 -0
- agentrun/integration/agentscope/__init__.py +12 -0
- agentrun/integration/agentscope/adapter.py +17 -0
- agentrun/integration/agentscope/builtin.py +65 -0
- agentrun/integration/agentscope/message_adapter.py +185 -0
- agentrun/integration/agentscope/model_adapter.py +60 -0
- agentrun/integration/agentscope/tool_adapter.py +59 -0
- agentrun/integration/builtin/__init__.py +16 -0
- agentrun/integration/builtin/model.py +97 -0
- agentrun/integration/builtin/sandbox.py +276 -0
- agentrun/integration/builtin/toolset.py +47 -0
- agentrun/integration/crewai/__init__.py +12 -0
- agentrun/integration/crewai/adapter.py +9 -0
- agentrun/integration/crewai/builtin.py +65 -0
- agentrun/integration/crewai/model_adapter.py +27 -0
- agentrun/integration/crewai/tool_adapter.py +26 -0
- agentrun/integration/google_adk/__init__.py +12 -0
- agentrun/integration/google_adk/adapter.py +15 -0
- agentrun/integration/google_adk/builtin.py +65 -0
- agentrun/integration/google_adk/message_adapter.py +144 -0
- agentrun/integration/google_adk/model_adapter.py +43 -0
- agentrun/integration/google_adk/tool_adapter.py +25 -0
- agentrun/integration/langchain/__init__.py +9 -0
- agentrun/integration/langchain/adapter.py +15 -0
- agentrun/integration/langchain/builtin.py +71 -0
- agentrun/integration/langchain/message_adapter.py +141 -0
- agentrun/integration/langchain/model_adapter.py +37 -0
- agentrun/integration/langchain/tool_adapter.py +50 -0
- agentrun/integration/langgraph/__init__.py +13 -0
- agentrun/integration/langgraph/adapter.py +20 -0
- agentrun/integration/langgraph/builtin.py +65 -0
- agentrun/integration/pydantic_ai/__init__.py +12 -0
- agentrun/integration/pydantic_ai/adapter.py +13 -0
- agentrun/integration/pydantic_ai/builtin.py +65 -0
- agentrun/integration/pydantic_ai/model_adapter.py +44 -0
- agentrun/integration/pydantic_ai/tool_adapter.py +19 -0
- agentrun/integration/utils/__init__.py +112 -0
- agentrun/integration/utils/adapter.py +167 -0
- agentrun/integration/utils/canonical.py +157 -0
- agentrun/integration/utils/converter.py +134 -0
- agentrun/integration/utils/model.py +107 -0
- agentrun/integration/utils/tool.py +1714 -0
- agentrun/model/__client_async_template.py +357 -0
- agentrun/model/__init__.py +57 -0
- agentrun/model/__model_proxy_async_template.py +270 -0
- agentrun/model/__model_service_async_template.py +267 -0
- agentrun/model/api/__init__.py +6 -0
- agentrun/model/api/control.py +1173 -0
- agentrun/model/api/data.py +196 -0
- agentrun/model/client.py +674 -0
- agentrun/model/model.py +218 -0
- agentrun/model/model_proxy.py +439 -0
- agentrun/model/model_service.py +438 -0
- agentrun/sandbox/__browser_sandbox_async_template.py +113 -0
- agentrun/sandbox/__client_async_template.py +466 -0
- agentrun/sandbox/__code_interpreter_sandbox_async_template.py +466 -0
- agentrun/sandbox/__init__.py +54 -0
- agentrun/sandbox/__sandbox_async_template.py +398 -0
- agentrun/sandbox/__template_async_template.py +150 -0
- agentrun/sandbox/api/__browser_data_async_template.py +140 -0
- agentrun/sandbox/api/__code_interpreter_data_async_template.py +206 -0
- agentrun/sandbox/api/__init__.py +17 -0
- agentrun/sandbox/api/__sandbox_data_async_template.py +100 -0
- agentrun/sandbox/api/browser_data.py +172 -0
- agentrun/sandbox/api/code_interpreter_data.py +396 -0
- agentrun/sandbox/api/control.py +1051 -0
- agentrun/sandbox/api/playwright_async.py +492 -0
- agentrun/sandbox/api/playwright_sync.py +492 -0
- agentrun/sandbox/api/sandbox_data.py +140 -0
- agentrun/sandbox/browser_sandbox.py +191 -0
- agentrun/sandbox/client.py +878 -0
- agentrun/sandbox/code_interpreter_sandbox.py +829 -0
- agentrun/sandbox/model.py +269 -0
- agentrun/sandbox/sandbox.py +737 -0
- agentrun/sandbox/template.py +215 -0
- agentrun/server/__init__.py +82 -0
- agentrun/server/invoker.py +131 -0
- agentrun/server/model.py +225 -0
- agentrun/server/openai_protocol.py +798 -0
- agentrun/server/protocol.py +96 -0
- agentrun/server/server.py +192 -0
- agentrun/toolset/__client_async_template.py +62 -0
- agentrun/toolset/__init__.py +51 -0
- agentrun/toolset/__toolset_async_template.py +204 -0
- agentrun/toolset/api/__init__.py +17 -0
- agentrun/toolset/api/control.py +262 -0
- agentrun/toolset/api/mcp.py +100 -0
- agentrun/toolset/api/openapi.py +1184 -0
- agentrun/toolset/client.py +102 -0
- agentrun/toolset/model.py +160 -0
- agentrun/toolset/toolset.py +271 -0
- agentrun/utils/__data_api_async_template.py +715 -0
- agentrun/utils/__init__.py +5 -0
- agentrun/utils/__resource_async_template.py +158 -0
- agentrun/utils/config.py +258 -0
- agentrun/utils/control_api.py +78 -0
- agentrun/utils/data_api.py +1110 -0
- agentrun/utils/exception.py +149 -0
- agentrun/utils/helper.py +34 -0
- agentrun/utils/log.py +77 -0
- agentrun/utils/model.py +168 -0
- agentrun/utils/resource.py +291 -0
- agentrun_sdk-0.0.4.dist-info/METADATA +262 -0
- agentrun_sdk-0.0.4.dist-info/RECORD +128 -0
- agentrun_sdk-0.0.4.dist-info/WHEEL +5 -0
- agentrun_sdk-0.0.4.dist-info/licenses/LICENSE +201 -0
- 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
|
+
]
|