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.
Files changed (135) hide show
  1. agentrun/__init__.py +325 -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 +93 -0
  31. agentrun/integration/builtin/sandbox.py +1234 -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 +31 -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 +46 -0
  43. agentrun/integration/google_adk/tool_adapter.py +235 -0
  44. agentrun/integration/langchain/__init__.py +30 -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 +35 -0
  51. agentrun/integration/langgraph/adapter.py +20 -0
  52. agentrun/integration/langgraph/agent_converter.py +1073 -0
  53. agentrun/integration/langgraph/builtin.py +65 -0
  54. agentrun/integration/pydantic_ai/__init__.py +12 -0
  55. agentrun/integration/pydantic_ai/adapter.py +13 -0
  56. agentrun/integration/pydantic_ai/builtin.py +65 -0
  57. agentrun/integration/pydantic_ai/model_adapter.py +44 -0
  58. agentrun/integration/pydantic_ai/tool_adapter.py +19 -0
  59. agentrun/integration/utils/__init__.py +112 -0
  60. agentrun/integration/utils/adapter.py +560 -0
  61. agentrun/integration/utils/canonical.py +164 -0
  62. agentrun/integration/utils/converter.py +134 -0
  63. agentrun/integration/utils/model.py +110 -0
  64. agentrun/integration/utils/tool.py +1759 -0
  65. agentrun/model/__client_async_template.py +357 -0
  66. agentrun/model/__init__.py +57 -0
  67. agentrun/model/__model_proxy_async_template.py +270 -0
  68. agentrun/model/__model_service_async_template.py +267 -0
  69. agentrun/model/api/__init__.py +6 -0
  70. agentrun/model/api/control.py +1173 -0
  71. agentrun/model/api/data.py +196 -0
  72. agentrun/model/client.py +674 -0
  73. agentrun/model/model.py +235 -0
  74. agentrun/model/model_proxy.py +439 -0
  75. agentrun/model/model_service.py +438 -0
  76. agentrun/sandbox/__aio_sandbox_async_template.py +523 -0
  77. agentrun/sandbox/__browser_sandbox_async_template.py +110 -0
  78. agentrun/sandbox/__client_async_template.py +491 -0
  79. agentrun/sandbox/__code_interpreter_sandbox_async_template.py +463 -0
  80. agentrun/sandbox/__init__.py +69 -0
  81. agentrun/sandbox/__sandbox_async_template.py +463 -0
  82. agentrun/sandbox/__template_async_template.py +152 -0
  83. agentrun/sandbox/aio_sandbox.py +905 -0
  84. agentrun/sandbox/api/__aio_data_async_template.py +335 -0
  85. agentrun/sandbox/api/__browser_data_async_template.py +140 -0
  86. agentrun/sandbox/api/__code_interpreter_data_async_template.py +206 -0
  87. agentrun/sandbox/api/__init__.py +19 -0
  88. agentrun/sandbox/api/__sandbox_data_async_template.py +107 -0
  89. agentrun/sandbox/api/aio_data.py +551 -0
  90. agentrun/sandbox/api/browser_data.py +172 -0
  91. agentrun/sandbox/api/code_interpreter_data.py +396 -0
  92. agentrun/sandbox/api/control.py +1051 -0
  93. agentrun/sandbox/api/playwright_async.py +492 -0
  94. agentrun/sandbox/api/playwright_sync.py +492 -0
  95. agentrun/sandbox/api/sandbox_data.py +154 -0
  96. agentrun/sandbox/browser_sandbox.py +185 -0
  97. agentrun/sandbox/client.py +925 -0
  98. agentrun/sandbox/code_interpreter_sandbox.py +823 -0
  99. agentrun/sandbox/model.py +397 -0
  100. agentrun/sandbox/sandbox.py +848 -0
  101. agentrun/sandbox/template.py +217 -0
  102. agentrun/server/__init__.py +191 -0
  103. agentrun/server/agui_normalizer.py +180 -0
  104. agentrun/server/agui_protocol.py +797 -0
  105. agentrun/server/invoker.py +309 -0
  106. agentrun/server/model.py +427 -0
  107. agentrun/server/openai_protocol.py +535 -0
  108. agentrun/server/protocol.py +140 -0
  109. agentrun/server/server.py +208 -0
  110. agentrun/toolset/__client_async_template.py +62 -0
  111. agentrun/toolset/__init__.py +51 -0
  112. agentrun/toolset/__toolset_async_template.py +204 -0
  113. agentrun/toolset/api/__init__.py +17 -0
  114. agentrun/toolset/api/control.py +262 -0
  115. agentrun/toolset/api/mcp.py +100 -0
  116. agentrun/toolset/api/openapi.py +1251 -0
  117. agentrun/toolset/client.py +102 -0
  118. agentrun/toolset/model.py +321 -0
  119. agentrun/toolset/toolset.py +270 -0
  120. agentrun/utils/__data_api_async_template.py +720 -0
  121. agentrun/utils/__init__.py +5 -0
  122. agentrun/utils/__resource_async_template.py +158 -0
  123. agentrun/utils/config.py +258 -0
  124. agentrun/utils/control_api.py +78 -0
  125. agentrun/utils/data_api.py +1120 -0
  126. agentrun/utils/exception.py +151 -0
  127. agentrun/utils/helper.py +108 -0
  128. agentrun/utils/log.py +77 -0
  129. agentrun/utils/model.py +168 -0
  130. agentrun/utils/resource.py +291 -0
  131. agentrun_inner_test-0.0.46.dist-info/METADATA +263 -0
  132. agentrun_inner_test-0.0.46.dist-info/RECORD +135 -0
  133. agentrun_inner_test-0.0.46.dist-info/WHEEL +5 -0
  134. agentrun_inner_test-0.0.46.dist-info/licenses/LICENSE +201 -0
  135. agentrun_inner_test-0.0.46.dist-info/top_level.txt +1 -0
@@ -0,0 +1,102 @@
1
+ """
2
+ This file is auto generated by the code generation script.
3
+ Do not modify this file manually.
4
+ Use the `make codegen` command to regenerate.
5
+
6
+ 当前文件为自动生成的控制 API 客户端代码。请勿手动修改此文件。
7
+ 使用 `make codegen` 命令重新生成。
8
+
9
+ source: agentrun/toolset/__client_async_template.py
10
+
11
+ ToolSet 客户端 / ToolSet Client
12
+
13
+ 此模块提供工具集的客户端API。
14
+ This module provides the client API for toolsets.
15
+ """
16
+
17
+ from typing import Optional
18
+
19
+ from alibabacloud_devs20230714.models import ListToolsetsRequest
20
+
21
+ from agentrun.toolset.api.control import ToolControlAPI
22
+ from agentrun.toolset.model import ToolSetListInput
23
+ from agentrun.utils.config import Config
24
+ from agentrun.utils.exception import HTTPError
25
+
26
+ from .toolset import ToolSet
27
+
28
+
29
+ class ToolSetClient:
30
+ """ToolSet 客户端 / ToolSet Client
31
+
32
+ 提供工具集的获取和列表功能。
33
+ Provides get and list functions for toolsets.
34
+ """
35
+
36
+ def __init__(self, config: Optional[Config] = None):
37
+ """初始化客户端 / Initialize client
38
+
39
+ Args:
40
+ config: 配置对象,可选 / Configuration object, optional
41
+ """
42
+ self.__control_api = ToolControlAPI(config)
43
+
44
+ async def get_async(
45
+ self,
46
+ name: str,
47
+ config: Optional[Config] = None,
48
+ ):
49
+ try:
50
+ result = await self.__control_api.get_toolset_async(
51
+ name=name,
52
+ config=config,
53
+ )
54
+ except HTTPError as e:
55
+ raise e.to_resource_error("ToolSet", name) from e
56
+
57
+ return ToolSet.from_inner_object(result)
58
+
59
+ def get(
60
+ self,
61
+ name: str,
62
+ config: Optional[Config] = None,
63
+ ):
64
+ try:
65
+ result = self.__control_api.get_toolset(
66
+ name=name,
67
+ config=config,
68
+ )
69
+ except HTTPError as e:
70
+ raise e.to_resource_error("ToolSet", name) from e
71
+
72
+ return ToolSet.from_inner_object(result)
73
+
74
+ async def list_async(
75
+ self,
76
+ input: Optional[ToolSetListInput] = None,
77
+ config: Optional[Config] = None,
78
+ ):
79
+ if input is None:
80
+ input = ToolSetListInput()
81
+
82
+ result = await self.__control_api.list_toolsets_async(
83
+ input=ListToolsetsRequest().from_map(input.model_dump()),
84
+ config=config,
85
+ )
86
+
87
+ return [ToolSet.from_inner_object(item) for item in result.data]
88
+
89
+ def list(
90
+ self,
91
+ input: Optional[ToolSetListInput] = None,
92
+ config: Optional[Config] = None,
93
+ ):
94
+ if input is None:
95
+ input = ToolSetListInput()
96
+
97
+ result = self.__control_api.list_toolsets(
98
+ input=ListToolsetsRequest().from_map(input.model_dump()),
99
+ config=config,
100
+ )
101
+
102
+ return [ToolSet.from_inner_object(item) for item in result.data]
@@ -0,0 +1,321 @@
1
+ """ToolSet 模型定义 / ToolSet Model Definitions
2
+
3
+ 定义工具集相关的数据模型和枚举。
4
+ Defines data models and enumerations related to toolsets.
5
+ """
6
+
7
+ from enum import Enum
8
+ from typing import Any, Dict, List, Optional
9
+
10
+ from agentrun.utils.model import BaseModel, Field, PageableInput
11
+
12
+
13
+ class SchemaType(str, Enum):
14
+ """Schema 类型 / Schema Type"""
15
+
16
+ MCP = "MCP"
17
+ """MCP 协议 / MCP Protocol"""
18
+ OpenAPI = "OpenAPI"
19
+ """OpenAPI 规范 / OpenAPI Specification"""
20
+
21
+
22
+ class ToolSetStatusOutputsUrls(BaseModel):
23
+ internet_url: Optional[str] = None
24
+ intranet_url: Optional[str] = None
25
+
26
+
27
+ class MCPServerConfig(BaseModel):
28
+ headers: Optional[Dict[str, str]] = None
29
+ transport_type: Optional[str] = None
30
+ url: Optional[str] = None
31
+
32
+
33
+ class ToolMeta(BaseModel):
34
+ description: Optional[str] = None
35
+ input_schema: Optional[Dict[str, Any]] = None
36
+ name: Optional[str] = None
37
+
38
+
39
+ class OpenAPIToolMeta(BaseModel):
40
+ method: Optional[str] = None
41
+ path: Optional[str] = None
42
+ tool_id: Optional[str] = None
43
+ tool_name: Optional[str] = None
44
+
45
+
46
+ class ToolSetStatusOutputs(BaseModel):
47
+ function_arn: Optional[str] = None
48
+ mcp_server_config: Optional[MCPServerConfig] = None
49
+ open_api_tools: Optional[List[OpenAPIToolMeta]] = None
50
+ tools: Optional[List[ToolMeta]] = None
51
+ urls: Optional[ToolSetStatusOutputsUrls] = None
52
+
53
+
54
+ class APIKeyAuthParameter(BaseModel):
55
+ encrypted: Optional[bool] = None
56
+ in_: Optional[str] = None
57
+ key: Optional[str] = None
58
+ value: Optional[str] = None
59
+
60
+
61
+ class AuthorizationParameters(BaseModel):
62
+ api_key_parameter: Optional[APIKeyAuthParameter] = None
63
+
64
+
65
+ class Authorization(BaseModel):
66
+ parameters: Optional[AuthorizationParameters] = None
67
+ type: Optional[str] = None
68
+
69
+
70
+ class ToolSetSchema(BaseModel):
71
+ detail: Optional[str] = None
72
+ type: Optional[SchemaType] = None
73
+
74
+
75
+ class ToolSetSpec(BaseModel):
76
+ auth_config: Optional[Authorization] = None
77
+ tool_schema: Optional[ToolSetSchema] = Field(alias="schema", default=None)
78
+
79
+
80
+ class ToolSetStatus(BaseModel):
81
+ observed_generation: Optional[int] = None
82
+ observed_time: Optional[str] = None
83
+ outputs: Optional[ToolSetStatusOutputs] = None
84
+ phase: Optional[str] = None
85
+
86
+
87
+ class ToolSetListInput(PageableInput):
88
+ keyword: Optional[str] = None
89
+ label_selector: Optional[List[str]] = None
90
+
91
+
92
+ class ToolSchema(BaseModel):
93
+ """JSON Schema 兼容的工具参数描述
94
+
95
+ 支持完整的 JSON Schema 字段,能够描述复杂的嵌套数据结构。
96
+ """
97
+
98
+ # 基本字段
99
+ type: Optional[str] = None
100
+ description: Optional[str] = None
101
+ title: Optional[str] = None
102
+
103
+ # 对象类型字段
104
+ properties: Optional[Dict[str, "ToolSchema"]] = None
105
+ required: Optional[List[str]] = None
106
+ additional_properties: Optional[bool] = None
107
+
108
+ # 数组类型字段
109
+ items: Optional["ToolSchema"] = None
110
+ min_items: Optional[int] = None
111
+ max_items: Optional[int] = None
112
+
113
+ # 字符串类型字段
114
+ pattern: Optional[str] = None
115
+ min_length: Optional[int] = None
116
+ max_length: Optional[int] = None
117
+ format: Optional[str] = None # date, date-time, email, uri 等
118
+ enum: Optional[List[Any]] = None
119
+
120
+ # 数值类型字段
121
+ minimum: Optional[float] = None
122
+ maximum: Optional[float] = None
123
+ exclusive_minimum: Optional[float] = None
124
+ exclusive_maximum: Optional[float] = None
125
+
126
+ # 联合类型
127
+ any_of: Optional[List["ToolSchema"]] = None
128
+ one_of: Optional[List["ToolSchema"]] = None
129
+ all_of: Optional[List["ToolSchema"]] = None
130
+
131
+ # 默认值
132
+ default: Optional[Any] = None
133
+
134
+ @classmethod
135
+ def from_any_openapi_schema(cls, schema: Any) -> "ToolSchema":
136
+ """从任意 OpenAPI/JSON Schema 创建 ToolSchema
137
+
138
+ 递归解析所有嵌套结构,保留完整的 schema 信息。
139
+ """
140
+ if not schema or not isinstance(schema, dict):
141
+ return cls(type="string")
142
+
143
+ from pydash import get as pg
144
+
145
+ # 解析 properties
146
+ properties_raw = pg(schema, "properties", {})
147
+ properties = (
148
+ {
149
+ key: cls.from_any_openapi_schema(value)
150
+ for key, value in properties_raw.items()
151
+ }
152
+ if properties_raw
153
+ else None
154
+ )
155
+
156
+ # 解析 items
157
+ items_raw = pg(schema, "items")
158
+ items = cls.from_any_openapi_schema(items_raw) if items_raw else None
159
+
160
+ # 解析联合类型
161
+ any_of_raw = pg(schema, "anyOf")
162
+ any_of = (
163
+ [cls.from_any_openapi_schema(s) for s in any_of_raw]
164
+ if any_of_raw
165
+ else None
166
+ )
167
+
168
+ one_of_raw = pg(schema, "oneOf")
169
+ one_of = (
170
+ [cls.from_any_openapi_schema(s) for s in one_of_raw]
171
+ if one_of_raw
172
+ else None
173
+ )
174
+
175
+ all_of_raw = pg(schema, "allOf")
176
+ all_of = (
177
+ [cls.from_any_openapi_schema(s) for s in all_of_raw]
178
+ if all_of_raw
179
+ else None
180
+ )
181
+
182
+ return cls(
183
+ # 基本字段
184
+ type=pg(schema, "type"),
185
+ description=pg(schema, "description"),
186
+ title=pg(schema, "title"),
187
+ # 对象类型
188
+ properties=properties,
189
+ required=pg(schema, "required"),
190
+ additional_properties=pg(schema, "additionalProperties"),
191
+ # 数组类型
192
+ items=items,
193
+ min_items=pg(schema, "minItems"),
194
+ max_items=pg(schema, "maxItems"),
195
+ # 字符串类型
196
+ pattern=pg(schema, "pattern"),
197
+ min_length=pg(schema, "minLength"),
198
+ max_length=pg(schema, "maxLength"),
199
+ format=pg(schema, "format"),
200
+ enum=pg(schema, "enum"),
201
+ # 数值类型
202
+ minimum=pg(schema, "minimum"),
203
+ maximum=pg(schema, "maximum"),
204
+ exclusive_minimum=pg(schema, "exclusiveMinimum"),
205
+ exclusive_maximum=pg(schema, "exclusiveMaximum"),
206
+ # 联合类型
207
+ any_of=any_of,
208
+ one_of=one_of,
209
+ all_of=all_of,
210
+ # 默认值
211
+ default=pg(schema, "default"),
212
+ )
213
+
214
+ def to_json_schema(self) -> Dict[str, Any]:
215
+ """转换为标准 JSON Schema 格式"""
216
+ result: Dict[str, Any] = {}
217
+
218
+ # 基本字段
219
+ if self.type:
220
+ result["type"] = self.type
221
+ if self.description:
222
+ result["description"] = self.description
223
+ if self.title:
224
+ result["title"] = self.title
225
+
226
+ # 对象类型
227
+ if self.properties:
228
+ result["properties"] = {
229
+ k: v.to_json_schema() for k, v in self.properties.items()
230
+ }
231
+ if self.required:
232
+ result["required"] = self.required
233
+ if self.additional_properties is not None:
234
+ result["additionalProperties"] = self.additional_properties
235
+
236
+ # 数组类型
237
+ if self.items:
238
+ result["items"] = self.items.to_json_schema()
239
+ if self.min_items is not None:
240
+ result["minItems"] = self.min_items
241
+ if self.max_items is not None:
242
+ result["maxItems"] = self.max_items
243
+
244
+ # 字符串类型
245
+ if self.pattern:
246
+ result["pattern"] = self.pattern
247
+ if self.min_length is not None:
248
+ result["minLength"] = self.min_length
249
+ if self.max_length is not None:
250
+ result["maxLength"] = self.max_length
251
+ if self.format:
252
+ result["format"] = self.format
253
+ if self.enum:
254
+ result["enum"] = self.enum
255
+
256
+ # 数值类型
257
+ if self.minimum is not None:
258
+ result["minimum"] = self.minimum
259
+ if self.maximum is not None:
260
+ result["maximum"] = self.maximum
261
+ if self.exclusive_minimum is not None:
262
+ result["exclusiveMinimum"] = self.exclusive_minimum
263
+ if self.exclusive_maximum is not None:
264
+ result["exclusiveMaximum"] = self.exclusive_maximum
265
+
266
+ # 联合类型
267
+ if self.any_of:
268
+ result["anyOf"] = [s.to_json_schema() for s in self.any_of]
269
+ if self.one_of:
270
+ result["oneOf"] = [s.to_json_schema() for s in self.one_of]
271
+ if self.all_of:
272
+ result["allOf"] = [s.to_json_schema() for s in self.all_of]
273
+
274
+ # 默认值
275
+ if self.default is not None:
276
+ result["default"] = self.default
277
+
278
+ return result
279
+
280
+
281
+ class ToolInfo(BaseModel):
282
+ name: Optional[str] = None
283
+ description: Optional[str] = None
284
+ parameters: Optional[ToolSchema] = None
285
+
286
+ @classmethod
287
+ def from_mcp_tool(cls, tool: Any):
288
+ """从 MCP tool 创建 ToolInfo"""
289
+ if hasattr(tool, "name"):
290
+ # MCP Tool 对象
291
+ tool_name = tool.name
292
+ tool_description = getattr(tool, "description", None)
293
+ input_schema = getattr(tool, "inputSchema", None) or getattr(
294
+ tool, "input_schema", None
295
+ )
296
+ elif isinstance(tool, dict):
297
+ # 字典格式
298
+ tool_name = tool.get("name")
299
+ tool_description = tool.get("description")
300
+ input_schema = tool.get("inputSchema") or tool.get("input_schema")
301
+ else:
302
+ raise ValueError(f"Unsupported MCP tool format: {type(tool)}")
303
+
304
+ if not tool_name:
305
+ raise ValueError("MCP tool must have a name")
306
+
307
+ # 构建 parameters schema
308
+ parameters = None
309
+ if input_schema:
310
+ if isinstance(input_schema, dict):
311
+ parameters = ToolSchema.from_any_openapi_schema(input_schema)
312
+ elif hasattr(input_schema, "model_dump"):
313
+ parameters = ToolSchema.from_any_openapi_schema(
314
+ input_schema.model_dump()
315
+ )
316
+
317
+ return cls(
318
+ name=tool_name,
319
+ description=tool_description,
320
+ parameters=parameters or ToolSchema(type="object", properties={}),
321
+ )
@@ -0,0 +1,270 @@
1
+ """
2
+ This file is auto generated by the code generation script.
3
+ Do not modify this file manually.
4
+ Use the `make codegen` command to regenerate.
5
+
6
+ 当前文件为自动生成的控制 API 客户端代码。请勿手动修改此文件。
7
+ 使用 `make codegen` 命令重新生成。
8
+
9
+ source: agentrun/toolset/__toolset_async_template.py
10
+
11
+ ToolSet 资源类 / ToolSet Resource Class
12
+
13
+ 提供工具集资源的面向对象封装和完整生命周期管理。
14
+ Provides object-oriented wrapper and complete lifecycle management for toolset resources.
15
+ """
16
+
17
+ from typing import Any, Dict, Optional, Tuple
18
+
19
+ import pydash
20
+
21
+ from agentrun.utils.config import Config
22
+ from agentrun.utils.log import logger
23
+ from agentrun.utils.model import BaseModel
24
+
25
+ from .model import (
26
+ MCPServerConfig,
27
+ SchemaType,
28
+ ToolInfo,
29
+ ToolSetSpec,
30
+ ToolSetStatus,
31
+ )
32
+
33
+
34
+ class ToolSet(BaseModel):
35
+ """工具集资源 / ToolSet Resource
36
+
37
+ 提供工具集的查询、调用等功能。
38
+ Provides query, invocation and other functionality for toolsets.
39
+
40
+ Attributes:
41
+ created_time: 创建时间 / Creation time
42
+ description: 描述 / Description
43
+ generation: 版本号 / Generation number
44
+ kind: 资源类型 / Resource kind
45
+ labels: 标签 / Labels
46
+ name: 工具集名称 / ToolSet name
47
+ spec: 规格配置 / Specification
48
+ status: 状态 / Status
49
+ uid: 唯一标识符 / Unique identifier
50
+ """
51
+
52
+ created_time: Optional[str] = None
53
+ description: Optional[str] = None
54
+ generation: Optional[int] = None
55
+ kind: Optional[str] = None
56
+ labels: Optional[Dict[str, str]] = None
57
+ name: Optional[str] = None
58
+ spec: Optional[ToolSetSpec] = None
59
+ status: Optional[ToolSetStatus] = None
60
+ uid: Optional[str] = None
61
+
62
+ @classmethod
63
+ def __get_client(cls, config: Optional[Config] = None):
64
+ from .client import ToolSetClient
65
+
66
+ return ToolSetClient(config)
67
+
68
+ @classmethod
69
+ async def get_by_name_async(
70
+ cls, name: str, config: Optional[Config] = None
71
+ ):
72
+ cli = cls.__get_client(config)
73
+ return await cli.get_async(name=name)
74
+
75
+ @classmethod
76
+ def get_by_name(cls, name: str, config: Optional[Config] = None):
77
+ cli = cls.__get_client(config)
78
+ return cli.get(name=name)
79
+
80
+ def type(self):
81
+ return SchemaType(pydash.get(self, "spec.tool_schema.type", ""))
82
+
83
+ def _get_openapi_auth_defaults(
84
+ self,
85
+ ) -> Tuple[Dict[str, Any], Dict[str, Any]]:
86
+ headers: Dict[str, Any] = {}
87
+ query: Dict[str, Any] = {}
88
+
89
+ auth_config = pydash.get(self, "spec.auth_config", None)
90
+ auth_type = getattr(auth_config, "type", None) if auth_config else None
91
+
92
+ if auth_type == "APIKey":
93
+ api_key_param = pydash.get(
94
+ auth_config,
95
+ "parameters.api_key_parameter",
96
+ None,
97
+ )
98
+ if api_key_param:
99
+ key = getattr(api_key_param, "key", None)
100
+ value = getattr(api_key_param, "value", None)
101
+ location = getattr(api_key_param, "in_", None)
102
+ if key and value is not None:
103
+ if location == "header":
104
+ headers[key] = value
105
+ elif location == "query":
106
+ query[key] = value
107
+
108
+ return headers, query
109
+
110
+ def _get_openapi_base_url(self) -> Optional[str]:
111
+ return pydash.get(
112
+ self,
113
+ "status.outputs.urls.intranet_url",
114
+ None,
115
+ ) or pydash.get(self, "status.outputs.urls.internet_url", None)
116
+
117
+ async def get_async(self, config: Optional[Config] = None):
118
+ if self.name is None:
119
+ raise ValueError("ToolSet name is required to get the ToolSet.")
120
+
121
+ result = await self.get_by_name_async(name=self.name, config=config)
122
+ return self.update_self(result)
123
+
124
+ def get(self, config: Optional[Config] = None):
125
+ if self.name is None:
126
+ raise ValueError("ToolSet name is required to get the ToolSet.")
127
+
128
+ result = self.get_by_name(name=self.name, config=config)
129
+ return self.update_self(result)
130
+
131
+ async def list_tools_async(self, config: Optional[Config] = None):
132
+ """异步获取工具列表,返回统一的 ToolInfo 列表"""
133
+ if self.type() == SchemaType.MCP:
134
+ mcp_tools = pydash.get(self, "status.outputs.tools", [])
135
+ return [ToolInfo.from_mcp_tool(tool) for tool in mcp_tools]
136
+ elif self.type() == SchemaType.OpenAPI:
137
+ # 直接使用 to_apiset 转换
138
+ apiset = self.to_apiset(config=config)
139
+ return apiset.tools()
140
+ return []
141
+
142
+ def list_tools(self, config: Optional[Config] = None):
143
+ """同步获取工具列表,返回统一的 ToolInfo 列表"""
144
+ if self.type() == SchemaType.MCP:
145
+ mcp_tools = pydash.get(self, "status.outputs.tools", [])
146
+ return [ToolInfo.from_mcp_tool(tool) for tool in mcp_tools]
147
+ elif self.type() == SchemaType.OpenAPI:
148
+ # 直接使用 to_apiset 转换
149
+ apiset = self.to_apiset(config=config)
150
+ return apiset.tools()
151
+ return []
152
+
153
+ async def call_tool_async(
154
+ self,
155
+ name: str,
156
+ arguments: Optional[Dict[str, str]] = None,
157
+ config: Optional[Config] = None,
158
+ ):
159
+ """异步调用工具,统一使用 ApiSet 实现"""
160
+ apiset = self.to_apiset(config=config)
161
+
162
+ # 对于 OpenAPI,可能需要解析 operation name
163
+ if self.type() == SchemaType.OpenAPI:
164
+ # 尝试查找实际的 operation name
165
+ tool = apiset.get_tool(name)
166
+ if tool is None:
167
+ # 尝试通过 tool_id 映射查找
168
+ openapi_tools = (
169
+ pydash.get(self, "status.outputs.open_api_tools", []) or []
170
+ )
171
+ for tool_meta in openapi_tools:
172
+ if tool_meta is None:
173
+ continue
174
+ if hasattr(tool_meta, "model_dump"):
175
+ tool_meta = tool_meta.model_dump()
176
+ if not isinstance(tool_meta, dict):
177
+ continue
178
+ if tool_meta.get("tool_id") == name:
179
+ name = tool_meta.get("tool_name") or name
180
+ break
181
+
182
+ logger.debug("invoke tool %s with arguments %s", name, arguments)
183
+ result = await apiset.invoke_async(
184
+ name=name, arguments=arguments, config=config
185
+ )
186
+ logger.debug("invoke tool %s got result %s", name, result)
187
+ return result
188
+
189
+ def call_tool(
190
+ self,
191
+ name: str,
192
+ arguments: Optional[Dict[str, str]] = None,
193
+ config: Optional[Config] = None,
194
+ ):
195
+ """同步调用工具,统一使用 ApiSet 实现"""
196
+ apiset = self.to_apiset(config=config)
197
+
198
+ # 对于 OpenAPI,可能需要解析 operation name
199
+ if self.type() == SchemaType.OpenAPI:
200
+ # 尝试查找实际的 operation name
201
+ tool = apiset.get_tool(name)
202
+ if tool is None:
203
+ # 尝试通过 tool_id 映射查找
204
+ openapi_tools = (
205
+ pydash.get(self, "status.outputs.open_api_tools", []) or []
206
+ )
207
+ for tool_meta in openapi_tools:
208
+ if tool_meta is None:
209
+ continue
210
+ if hasattr(tool_meta, "model_dump"):
211
+ tool_meta = tool_meta.model_dump()
212
+ if not isinstance(tool_meta, dict):
213
+ continue
214
+ if tool_meta.get("tool_id") == name:
215
+ name = tool_meta.get("tool_name") or name
216
+ break
217
+
218
+ logger.debug("invoke tool %s with arguments %s", name, arguments)
219
+ result = apiset.invoke(name=name, arguments=arguments, config=config)
220
+ logger.debug("invoke tool %s got result %s", name, result)
221
+ return result
222
+
223
+ def to_apiset(self, config: Optional[Config] = None):
224
+ """将 ToolSet 转换为统一的 ApiSet 对象
225
+
226
+ Returns:
227
+ ApiSet: 统一的工具集接口
228
+ """
229
+ from .api.openapi import ApiSet
230
+
231
+ if self.type() == SchemaType.MCP:
232
+ from .api.mcp import MCPToolSet
233
+
234
+ mcp_server_config: MCPServerConfig = pydash.get(
235
+ self, "status.outputs.mcp_server_config", None
236
+ )
237
+ assert (
238
+ mcp_server_config.url is not None
239
+ ), "MCP server URL is missing."
240
+
241
+ cfg = Config.with_configs(
242
+ config, Config(headers=mcp_server_config.headers)
243
+ )
244
+
245
+ mcp_client = MCPToolSet(
246
+ url=mcp_server_config.url,
247
+ config=cfg,
248
+ )
249
+
250
+ # 获取 MCP tools
251
+ mcp_tools = pydash.get(self, "status.outputs.tools", [])
252
+
253
+ return ApiSet.from_mcp_tools(
254
+ tools=mcp_tools,
255
+ mcp_client=mcp_client,
256
+ config=cfg,
257
+ )
258
+
259
+ elif self.type() == SchemaType.OpenAPI:
260
+ headers, query = self._get_openapi_auth_defaults()
261
+
262
+ return ApiSet.from_openapi_schema(
263
+ schema=pydash.get(self, "spec.tool_schema.detail", None),
264
+ base_url=self._get_openapi_base_url(),
265
+ headers=headers,
266
+ query_params=query,
267
+ config=config,
268
+ )
269
+
270
+ raise ValueError(f"Unsupported ToolSet type: {self.type()}")