agentrun-inner-test 0.0.46__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 +325 -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 +93 -0
- agentrun/integration/builtin/sandbox.py +1234 -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 +31 -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 +46 -0
- agentrun/integration/google_adk/tool_adapter.py +235 -0
- agentrun/integration/langchain/__init__.py +30 -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 +35 -0
- agentrun/integration/langgraph/adapter.py +20 -0
- agentrun/integration/langgraph/agent_converter.py +1073 -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 +560 -0
- agentrun/integration/utils/canonical.py +164 -0
- agentrun/integration/utils/converter.py +134 -0
- agentrun/integration/utils/model.py +110 -0
- agentrun/integration/utils/tool.py +1759 -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 +235 -0
- agentrun/model/model_proxy.py +439 -0
- agentrun/model/model_service.py +438 -0
- agentrun/sandbox/__aio_sandbox_async_template.py +523 -0
- agentrun/sandbox/__browser_sandbox_async_template.py +110 -0
- agentrun/sandbox/__client_async_template.py +491 -0
- agentrun/sandbox/__code_interpreter_sandbox_async_template.py +463 -0
- agentrun/sandbox/__init__.py +69 -0
- agentrun/sandbox/__sandbox_async_template.py +463 -0
- agentrun/sandbox/__template_async_template.py +152 -0
- agentrun/sandbox/aio_sandbox.py +905 -0
- agentrun/sandbox/api/__aio_data_async_template.py +335 -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 +19 -0
- agentrun/sandbox/api/__sandbox_data_async_template.py +107 -0
- agentrun/sandbox/api/aio_data.py +551 -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 +154 -0
- agentrun/sandbox/browser_sandbox.py +185 -0
- agentrun/sandbox/client.py +925 -0
- agentrun/sandbox/code_interpreter_sandbox.py +823 -0
- agentrun/sandbox/model.py +397 -0
- agentrun/sandbox/sandbox.py +848 -0
- agentrun/sandbox/template.py +217 -0
- agentrun/server/__init__.py +191 -0
- agentrun/server/agui_normalizer.py +180 -0
- agentrun/server/agui_protocol.py +797 -0
- agentrun/server/invoker.py +309 -0
- agentrun/server/model.py +427 -0
- agentrun/server/openai_protocol.py +535 -0
- agentrun/server/protocol.py +140 -0
- agentrun/server/server.py +208 -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 +1251 -0
- agentrun/toolset/client.py +102 -0
- agentrun/toolset/model.py +321 -0
- agentrun/toolset/toolset.py +270 -0
- agentrun/utils/__data_api_async_template.py +720 -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 +1120 -0
- agentrun/utils/exception.py +151 -0
- agentrun/utils/helper.py +108 -0
- agentrun/utils/log.py +77 -0
- agentrun/utils/model.py +168 -0
- agentrun/utils/resource.py +291 -0
- agentrun_inner_test-0.0.46.dist-info/METADATA +263 -0
- agentrun_inner_test-0.0.46.dist-info/RECORD +135 -0
- agentrun_inner_test-0.0.46.dist-info/WHEEL +5 -0
- agentrun_inner_test-0.0.46.dist-info/licenses/LICENSE +201 -0
- agentrun_inner_test-0.0.46.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"""AgentRun HTTP Server / AgentRun HTTP 服务器
|
|
2
|
+
|
|
3
|
+
基于 Router 的设计:
|
|
4
|
+
- 每个协议提供自己的 Router
|
|
5
|
+
- Server 负责挂载 Router 并管理路由前缀
|
|
6
|
+
- 支持多协议同时运行(OpenAI + AG-UI)
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Any, List, Optional, Sequence
|
|
10
|
+
|
|
11
|
+
from fastapi import FastAPI
|
|
12
|
+
import uvicorn
|
|
13
|
+
|
|
14
|
+
from agentrun.utils.log import logger
|
|
15
|
+
|
|
16
|
+
from .agui_protocol import AGUIProtocolHandler
|
|
17
|
+
from .invoker import AgentInvoker
|
|
18
|
+
from .model import ServerConfig
|
|
19
|
+
from .openai_protocol import OpenAIProtocolHandler
|
|
20
|
+
from .protocol import InvokeAgentHandler, ProtocolHandler
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class AgentRunServer:
|
|
24
|
+
"""AgentRun HTTP Server / AgentRun HTTP 服务器
|
|
25
|
+
|
|
26
|
+
基于 Router 的架构:
|
|
27
|
+
- 每个协议提供完整的 FastAPI Router
|
|
28
|
+
- Server 只负责组装和前缀管理
|
|
29
|
+
- 易于扩展新协议
|
|
30
|
+
|
|
31
|
+
Example (最简单用法):
|
|
32
|
+
>>> def invoke_agent(request: AgentRequest):
|
|
33
|
+
... return "Hello, world!"
|
|
34
|
+
>>>
|
|
35
|
+
>>> server = AgentRunServer(invoke_agent=invoke_agent)
|
|
36
|
+
>>> server.start(port=8000)
|
|
37
|
+
# 可访问:
|
|
38
|
+
# POST http://localhost:8000/openai/v1/chat/completions (OpenAI)
|
|
39
|
+
# POST http://localhost:8000/agui/v1/run (AG-UI)
|
|
40
|
+
|
|
41
|
+
Example (流式输出):
|
|
42
|
+
>>> async def invoke_agent(request: AgentRequest):
|
|
43
|
+
... yield "Hello, "
|
|
44
|
+
... yield "world!"
|
|
45
|
+
>>>
|
|
46
|
+
>>> server = AgentRunServer(invoke_agent=invoke_agent)
|
|
47
|
+
>>> server.start(port=8000)
|
|
48
|
+
|
|
49
|
+
Example (使用事件):
|
|
50
|
+
>>> from agentrun.server import AgentResult, EventType
|
|
51
|
+
>>>
|
|
52
|
+
>>> async def invoke_agent(request: AgentRequest):
|
|
53
|
+
... yield AgentResult(
|
|
54
|
+
... event=EventType.STEP_STARTED,
|
|
55
|
+
... data={"step_name": "thinking"}
|
|
56
|
+
... )
|
|
57
|
+
... yield "I'm thinking..."
|
|
58
|
+
... yield AgentResult(
|
|
59
|
+
... event=EventType.STEP_FINISHED,
|
|
60
|
+
... data={"step_name": "thinking"}
|
|
61
|
+
... )
|
|
62
|
+
>>>
|
|
63
|
+
>>> server = AgentRunServer(invoke_agent=invoke_agent)
|
|
64
|
+
>>> server.start(port=8000)
|
|
65
|
+
|
|
66
|
+
Example (仅 OpenAI 协议):
|
|
67
|
+
>>> server = AgentRunServer(
|
|
68
|
+
... invoke_agent=invoke_agent,
|
|
69
|
+
... protocols=[OpenAIProtocolHandler()]
|
|
70
|
+
... )
|
|
71
|
+
>>> server.start(port=8000)
|
|
72
|
+
|
|
73
|
+
Example (集成到现有 FastAPI 应用):
|
|
74
|
+
>>> from fastapi import FastAPI
|
|
75
|
+
>>>
|
|
76
|
+
>>> app = FastAPI()
|
|
77
|
+
>>> agent_server = AgentRunServer(invoke_agent=invoke_agent)
|
|
78
|
+
>>> app.mount("/agent", agent_server.as_fastapi_app())
|
|
79
|
+
# 可访问: POST http://localhost:8000/agent/openai/v1/chat/completions
|
|
80
|
+
|
|
81
|
+
Example (配置 CORS):
|
|
82
|
+
>>> server = AgentRunServer(
|
|
83
|
+
... invoke_agent=invoke_agent,
|
|
84
|
+
... config=ServerConfig(cors_origins=["http://localhost:3000"])
|
|
85
|
+
... )
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
def __init__(
|
|
89
|
+
self,
|
|
90
|
+
invoke_agent: InvokeAgentHandler,
|
|
91
|
+
protocols: Optional[List[ProtocolHandler]] = None,
|
|
92
|
+
config: Optional[ServerConfig] = None,
|
|
93
|
+
):
|
|
94
|
+
"""初始化 AgentRun Server
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
invoke_agent: Agent 调用回调函数
|
|
98
|
+
- 可以是同步或异步函数
|
|
99
|
+
- 支持返回字符串或 AgentResult
|
|
100
|
+
- 支持使用 yield 进行流式输出
|
|
101
|
+
|
|
102
|
+
protocols: 协议处理器列表
|
|
103
|
+
- 默认使用 OpenAI + AG-UI 协议
|
|
104
|
+
- 可以添加自定义协议
|
|
105
|
+
|
|
106
|
+
config: 服务器配置
|
|
107
|
+
- cors_origins: CORS 允许的源列表
|
|
108
|
+
- openai: OpenAI 协议配置
|
|
109
|
+
- agui: AG-UI 协议配置
|
|
110
|
+
"""
|
|
111
|
+
self.app = FastAPI(title="AgentRun Server")
|
|
112
|
+
self.agent_invoker = AgentInvoker(invoke_agent)
|
|
113
|
+
|
|
114
|
+
# 配置 CORS
|
|
115
|
+
self._setup_cors(config.cors_origins if config else None)
|
|
116
|
+
|
|
117
|
+
# 默认使用 OpenAI 和 AG-UI 协议
|
|
118
|
+
if protocols is None:
|
|
119
|
+
protocols = [
|
|
120
|
+
OpenAIProtocolHandler(config),
|
|
121
|
+
AGUIProtocolHandler(config),
|
|
122
|
+
]
|
|
123
|
+
|
|
124
|
+
# 挂载所有协议的 Router
|
|
125
|
+
self._mount_protocols(protocols)
|
|
126
|
+
|
|
127
|
+
def _setup_cors(self, cors_origins: Optional[Sequence[str]] = None):
|
|
128
|
+
"""配置 CORS 中间件
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
cors_origins: 允许的源列表,默认为 ["*"] 允许所有源
|
|
132
|
+
"""
|
|
133
|
+
if not cors_origins:
|
|
134
|
+
return
|
|
135
|
+
|
|
136
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
137
|
+
|
|
138
|
+
origins = list(cors_origins) if cors_origins else ["*"]
|
|
139
|
+
|
|
140
|
+
self.app.add_middleware(
|
|
141
|
+
CORSMiddleware,
|
|
142
|
+
allow_origins=origins,
|
|
143
|
+
allow_credentials=True,
|
|
144
|
+
allow_methods=["*"],
|
|
145
|
+
allow_headers=["*"],
|
|
146
|
+
expose_headers=["*"],
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
logger.debug(f"CORS 已启用,允许的源: {origins}")
|
|
150
|
+
|
|
151
|
+
def _mount_protocols(self, protocols: List[ProtocolHandler]):
|
|
152
|
+
"""挂载所有协议的路由
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
protocols: 协议处理器列表
|
|
156
|
+
"""
|
|
157
|
+
for protocol in protocols:
|
|
158
|
+
# 获取协议的 Router
|
|
159
|
+
router = protocol.as_fastapi_router(self.agent_invoker)
|
|
160
|
+
|
|
161
|
+
# 使用协议定义的前缀
|
|
162
|
+
prefix = protocol.get_prefix()
|
|
163
|
+
|
|
164
|
+
# 挂载到主应用
|
|
165
|
+
self.app.include_router(router, prefix=prefix)
|
|
166
|
+
|
|
167
|
+
logger.debug(
|
|
168
|
+
f"已挂载协议: {protocol.__class__.__name__} ->"
|
|
169
|
+
f" {prefix or '(无前缀)'}"
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
def start(
|
|
173
|
+
self,
|
|
174
|
+
host: str = "0.0.0.0",
|
|
175
|
+
port: int = 9000,
|
|
176
|
+
log_level: str = "info",
|
|
177
|
+
**kwargs: Any,
|
|
178
|
+
):
|
|
179
|
+
"""启动 HTTP 服务器
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
host: 监听地址,默认 0.0.0.0
|
|
183
|
+
port: 监听端口,默认 9000
|
|
184
|
+
log_level: 日志级别,默认 info
|
|
185
|
+
**kwargs: 传递给 uvicorn.run 的其他参数
|
|
186
|
+
"""
|
|
187
|
+
logger.info(f"启动 AgentRun Server: http://{host}:{port}")
|
|
188
|
+
|
|
189
|
+
uvicorn.run(
|
|
190
|
+
self.app, host=host, port=port, log_level=log_level, **kwargs
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
def as_fastapi_app(self) -> FastAPI:
|
|
194
|
+
"""导出 FastAPI 应用
|
|
195
|
+
|
|
196
|
+
用于集成到现有的 FastAPI 项目中。
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
FastAPI: FastAPI 应用实例
|
|
200
|
+
|
|
201
|
+
Example:
|
|
202
|
+
>>> from fastapi import FastAPI
|
|
203
|
+
>>>
|
|
204
|
+
>>> app = FastAPI()
|
|
205
|
+
>>> agent_server = AgentRunServer(invoke_agent=invoke_agent)
|
|
206
|
+
>>> app.mount("/agent", agent_server.as_fastapi_app())
|
|
207
|
+
"""
|
|
208
|
+
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
|
+
]
|