agentkit-sdk-python 0.1.5__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 (120) hide show
  1. agentkit/__init__.py +23 -0
  2. agentkit/apps/__init__.py +58 -0
  3. agentkit/apps/a2a_app/__init__.py +13 -0
  4. agentkit/apps/a2a_app/a2a_app.py +134 -0
  5. agentkit/apps/a2a_app/telemetry.py +119 -0
  6. agentkit/apps/agent_server_app/__init__.py +13 -0
  7. agentkit/apps/agent_server_app/agent_server_app.py +85 -0
  8. agentkit/apps/base_app.py +20 -0
  9. agentkit/apps/mcp_app/__init__.py +13 -0
  10. agentkit/apps/mcp_app/mcp_app.py +150 -0
  11. agentkit/apps/mcp_app/telemetry.py +115 -0
  12. agentkit/apps/simple_app/__init__.py +13 -0
  13. agentkit/apps/simple_app/simple_app.py +94 -0
  14. agentkit/apps/simple_app/simple_app_handlers.py +325 -0
  15. agentkit/apps/simple_app/telemetry.py +124 -0
  16. agentkit/apps/utils.py +45 -0
  17. agentkit/client/__init__.py +26 -0
  18. agentkit/client/base_client.py +219 -0
  19. agentkit/identity/__init__.py +13 -0
  20. agentkit/identity/auth.py +70 -0
  21. agentkit/knowledge/__init__.py +47 -0
  22. agentkit/knowledge/knowledge.py +203 -0
  23. agentkit/knowledge/knowledge_all_types.py +191 -0
  24. agentkit/mcp/__init__.py +79 -0
  25. agentkit/mcp/mcp.py +294 -0
  26. agentkit/mcp/mcp_all_types.py +1212 -0
  27. agentkit/memory/__init__.py +71 -0
  28. agentkit/memory/memory.py +236 -0
  29. agentkit/memory/memory_all_types.py +358 -0
  30. agentkit/runtime/__init__.py +13 -0
  31. agentkit/runtime/runtime.py +191 -0
  32. agentkit/runtime/runtime_all_types.py +624 -0
  33. agentkit/runtime/runtime_v1.py +178 -0
  34. agentkit/runtime/types.py +188 -0
  35. agentkit/toolkit/__init__.py +13 -0
  36. agentkit/toolkit/cli/__init__.py +13 -0
  37. agentkit/toolkit/cli/__main__.py +7 -0
  38. agentkit/toolkit/cli/cli.py +97 -0
  39. agentkit/toolkit/cli/cli_build.py +53 -0
  40. agentkit/toolkit/cli/cli_config.py +170 -0
  41. agentkit/toolkit/cli/cli_deploy.py +52 -0
  42. agentkit/toolkit/cli/cli_destroy.py +53 -0
  43. agentkit/toolkit/cli/cli_init.py +364 -0
  44. agentkit/toolkit/cli/cli_invoke.py +168 -0
  45. agentkit/toolkit/cli/cli_launch.py +34 -0
  46. agentkit/toolkit/cli/cli_status.py +53 -0
  47. agentkit/toolkit/cli/cli_version.py +87 -0
  48. agentkit/toolkit/cli/utils.py +47 -0
  49. agentkit/toolkit/config/__init__.py +52 -0
  50. agentkit/toolkit/config/auto_prompt.py +752 -0
  51. agentkit/toolkit/config/build_config.py +28 -0
  52. agentkit/toolkit/config/common_config.py +18 -0
  53. agentkit/toolkit/config/config.py +306 -0
  54. agentkit/toolkit/config/config_handler.py +331 -0
  55. agentkit/toolkit/config/config_manager.py +48 -0
  56. agentkit/toolkit/config/config_validator.py +121 -0
  57. agentkit/toolkit/config/constants.py +18 -0
  58. agentkit/toolkit/config/dataclass_utils.py +153 -0
  59. agentkit/toolkit/config/deploy_config.py +1 -0
  60. agentkit/toolkit/config/utils.py +57 -0
  61. agentkit/toolkit/config/workflow_configs.py +149 -0
  62. agentkit/toolkit/consts.py +1 -0
  63. agentkit/toolkit/core/__init__.py +13 -0
  64. agentkit/toolkit/core/build/__init__.py +13 -0
  65. agentkit/toolkit/core/build/base_builder.py +6 -0
  66. agentkit/toolkit/core/build/cloud_builder.py +0 -0
  67. agentkit/toolkit/core/build/local_builder.py +0 -0
  68. agentkit/toolkit/core/deploy/__init__.py +13 -0
  69. agentkit/toolkit/core/deploy/base_deployer.py +6 -0
  70. agentkit/toolkit/core/deploy/cloud_deployer.py +0 -0
  71. agentkit/toolkit/core/deploy/local_deployer.py +0 -0
  72. agentkit/toolkit/integrations/__init__.py +17 -0
  73. agentkit/toolkit/integrations/builder/__init__.py +23 -0
  74. agentkit/toolkit/integrations/builder/base.py +59 -0
  75. agentkit/toolkit/integrations/builder/local_docker_builder.py +163 -0
  76. agentkit/toolkit/integrations/builder/ve_core_pipeline_builder.py +853 -0
  77. agentkit/toolkit/integrations/container.py +843 -0
  78. agentkit/toolkit/integrations/runner/__init__.py +26 -0
  79. agentkit/toolkit/integrations/runner/base.py +222 -0
  80. agentkit/toolkit/integrations/runner/local_docker_runner.py +407 -0
  81. agentkit/toolkit/integrations/runner/ve_agentkit_runner.py +665 -0
  82. agentkit/toolkit/integrations/services/__init__.py +26 -0
  83. agentkit/toolkit/integrations/services/cr_service.py +449 -0
  84. agentkit/toolkit/integrations/services/tos_service.py +291 -0
  85. agentkit/toolkit/integrations/utils/__init__.py +21 -0
  86. agentkit/toolkit/integrations/utils/project_archiver.py +276 -0
  87. agentkit/toolkit/integrations/ve_code_pipeline.py +643 -0
  88. agentkit/toolkit/integrations/ve_cr.py +385 -0
  89. agentkit/toolkit/integrations/ve_iam.py +210 -0
  90. agentkit/toolkit/resources/samples/basic.py +79 -0
  91. agentkit/toolkit/resources/samples/basic_stream.py +100 -0
  92. agentkit/toolkit/resources/samples/customer_support_assistant.py +3 -0
  93. agentkit/toolkit/resources/samples/financial_analyst.py +140 -0
  94. agentkit/toolkit/resources/samples/simple_a2a_veadk.py +32 -0
  95. agentkit/toolkit/resources/samples/simple_app_veadk.py +55 -0
  96. agentkit/toolkit/resources/samples/simple_mcp_veadk.py +50 -0
  97. agentkit/toolkit/resources/templates/Dockerfile.j2 +27 -0
  98. agentkit/toolkit/resources/templates/code-pipeline-tos-cr-step.j2 +52 -0
  99. agentkit/toolkit/workflows/__init__.py +27 -0
  100. agentkit/toolkit/workflows/base.py +87 -0
  101. agentkit/toolkit/workflows/hybird_local_ve_workflow_v1.py +381 -0
  102. agentkit/toolkit/workflows/local_workflow_v1.py +262 -0
  103. agentkit/toolkit/workflows/ve_agentkit_workflow.py +369 -0
  104. agentkit/tools/__init__.py +17 -0
  105. agentkit/tools/tools.py +106 -0
  106. agentkit/tools/tools_all_types.py +337 -0
  107. agentkit/utils/__init__.py +41 -0
  108. agentkit/utils/credential.py +44 -0
  109. agentkit/utils/logging_config.py +366 -0
  110. agentkit/utils/misc.py +70 -0
  111. agentkit/utils/request.py +59 -0
  112. agentkit/utils/template_utils.py +256 -0
  113. agentkit/utils/ve_sign.py +247 -0
  114. agentkit/version.py +15 -0
  115. agentkit_sdk_python-0.1.5.dist-info/METADATA +262 -0
  116. agentkit_sdk_python-0.1.5.dist-info/RECORD +120 -0
  117. agentkit_sdk_python-0.1.5.dist-info/WHEEL +5 -0
  118. agentkit_sdk_python-0.1.5.dist-info/entry_points.txt +2 -0
  119. agentkit_sdk_python-0.1.5.dist-info/licenses/LICENSE +201 -0
  120. agentkit_sdk_python-0.1.5.dist-info/top_level.txt +1 -0
@@ -0,0 +1,665 @@
1
+ # Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import logging
16
+ import requests
17
+ import time
18
+ import json
19
+ from typing import Dict, Any, Optional, Tuple, List
20
+ from dataclasses import dataclass, field
21
+ from datetime import datetime
22
+ from urllib.parse import urljoin
23
+ from rich.console import Console
24
+ from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TaskProgressColumn, TimeElapsedColumn, TimeRemainingColumn
25
+
26
+ from agentkit.toolkit.config import CommonConfig, AUTO_CREATE_VE, is_valid_config
27
+ from agentkit.toolkit.config.dataclass_utils import AutoSerializableMixin
28
+ from agentkit.utils.misc import generate_random_id, generate_runtime_name, generate_runtime_role_name, generate_apikey_name, generate_client_token
29
+ from agentkit.runtime.runtime import AgentkitRuntime, ARTIFACT_TYPE_DOCKER_IMAGE, PROJECT_NAME_DEFAULT, API_KEY_LOCATION, RUNTIME_STATUS_READY, RUNTIME_STATUS_ERROR, RUNTIME_STATUS_UPDATING, RUNTIME_STATUS_UNRELEASED, GetAgentkitRuntimeRequest
30
+ from agentkit.runtime.runtime_v1 import AgentkitRuntime as AgentkitRuntimeV1
31
+ from agentkit.runtime.types import CreateAgentkitRuntimeRequest, CreateAgentkitRuntimeResponse, DeleteAgentkitRuntimeRequest, AuthorizerConfiguration, KeyAuth_
32
+ from agentkit.toolkit.integrations.ve_iam import VeIAM
33
+ import agentkit.runtime.runtime_all_types as runtime_all_types
34
+
35
+
36
+
37
+ from .base import Runner
38
+
39
+ logger = logging.getLogger(__name__)
40
+
41
+ console = Console()
42
+
43
+ @dataclass
44
+ class VeAgentkitRunnerConfig(AutoSerializableMixin):
45
+ """VeAgentkit Runner配置"""
46
+ common_config: Optional[CommonConfig] = field(default=None, metadata={"system": True, "description": "公共配置"})
47
+
48
+ # Runtime配置
49
+ runtime_id: str = field(default=AUTO_CREATE_VE, metadata={"description": "Runtime ID,Auto表示自动创建"})
50
+ runtime_name: str = field(default=AUTO_CREATE_VE, metadata={"description": "Runtime名称,Auto表示自动生成"})
51
+ runtime_role_name: str = field(default=AUTO_CREATE_VE, metadata={"description": "Runtime角色名称,Auto表示自动创建"})
52
+ runtime_apikey: str = field(default="", metadata={"description": "Runtime API密钥"})
53
+ runtime_apikey_name: str = field(default=AUTO_CREATE_VE, metadata={"description": "Runtime API密钥名称,Auto表示自动生成"})
54
+ runtime_endpoint: str = field(default="", metadata={"description": "Runtime访问端点"})
55
+ runtime_envs: Dict[str, str] = field(default_factory=dict, metadata={"description": "Runtime环境变量"})
56
+
57
+ # 镜像配置
58
+ image_url: str = field(default="", metadata={"description": "容器镜像完整URL"})
59
+
60
+
61
+ @dataclass
62
+ class VeAgentkitDeployResult(AutoSerializableMixin):
63
+ """部署结果"""
64
+ success: bool = field(default=False)
65
+ runtime_id: str = field(default="")
66
+ runtime_name: str = field(default="")
67
+ runtime_endpoint: str = field(default="")
68
+ runtime_apikey: str = field(default="")
69
+ message: str = field(default="")
70
+ error: str = field(default="")
71
+
72
+
73
+ class VeAgentkitRuntimeRunner(Runner):
74
+ """VeAgentkit Runtime Runner
75
+
76
+ 负责管理云上Runtime的生命周期,包括:
77
+ - 创建和管理Runtime实例
78
+ - 部署和更新Runtime配置
79
+ - 调用Runtime服务
80
+ - 监控Runtime状态
81
+ - 清理Runtime资源
82
+ """
83
+
84
+ def __init__(self):
85
+ self.agentkit_runtime = AgentkitRuntime()
86
+ self.agentkit_runtime_v1 = AgentkitRuntimeV1()
87
+
88
+ def deploy(self, config: Dict[str, Any]) -> Tuple[bool, Dict[str, Any]]:
89
+ """部署Runtime
90
+
91
+ Args:
92
+ config: 部署配置,包含Runtime相关配置
93
+
94
+ Returns:
95
+ (成功标志, 部署结果字典)
96
+ """
97
+ try:
98
+ runner_config = VeAgentkitRunnerConfig.from_dict(config)
99
+ runner_config.common_config = CommonConfig.from_dict(runner_config.common_config)
100
+
101
+ if not runner_config.image_url:
102
+ return False, {"error": "镜像URL不能为空,请先构建镜像"}
103
+
104
+ # 准备Runtime配置
105
+ if not self._prepare_runtime_config(runner_config):
106
+ return False, {"error": "Runtime配置准备失败"}
107
+
108
+ # ensure_role_for_agentkit
109
+ ve_iam = VeIAM()
110
+ if not ve_iam.ensure_role_for_agentkit(runner_config.runtime_role_name):
111
+ return False, {"error": "创建Runtime角色失败"}
112
+
113
+ # 部署Runtime
114
+ if runner_config.runtime_id == AUTO_CREATE_VE:
115
+ return self._create_new_runtime(runner_config)
116
+ else:
117
+ return self._update_existing_runtime(runner_config)
118
+
119
+ except Exception as e:
120
+ logger.error(f"Runtime部署失败: {str(e)}")
121
+ return False, {"error": str(e)}
122
+
123
+ def destroy(self, config: Dict[str, Any]) -> bool:
124
+ """销毁Runtime
125
+
126
+ Args:
127
+ config: 销毁配置,包含Runtime ID
128
+
129
+ Returns:
130
+ 是否成功
131
+ """
132
+ try:
133
+ runner_config = VeAgentkitRunnerConfig.from_dict(config)
134
+
135
+ if not runner_config.runtime_id or runner_config.runtime_id == AUTO_CREATE_VE:
136
+ console.print("未配置Runtime ID,跳过销毁")
137
+ return True
138
+
139
+ # 删除Runtime
140
+ delete_request = DeleteAgentkitRuntimeRequest(
141
+ RuntimeId=runner_config.runtime_id
142
+ )
143
+
144
+ self.agentkit_runtime.delete(delete_request)
145
+ console.print(f"[green]✅ Runtime销毁成功: {runner_config.runtime_id}[/green]")
146
+ return True
147
+
148
+ except Exception as e:
149
+ logger.error(f"Runtime销毁失败: {str(e)}")
150
+ return False
151
+
152
+ def status(self, config: Dict[str, Any]) -> Dict[str, Any]:
153
+ """获取Runtime状态
154
+
155
+ Args:
156
+ config: 状态查询配置,包含Runtime ID
157
+
158
+ Returns:
159
+ Runtime状态信息
160
+ """
161
+ try:
162
+ runner_config = VeAgentkitRunnerConfig.from_dict(config)
163
+
164
+ if not runner_config.runtime_id or runner_config.runtime_id == AUTO_CREATE_VE:
165
+ return {"status": "not_deployed", "message": "未部署Runtime"}
166
+
167
+ # 获取Runtime信息
168
+ runtime = self.agentkit_runtime.get(
169
+ GetAgentkitRuntimeRequest(RuntimeId=runner_config.runtime_id)
170
+ )
171
+ if runner_config.runtime_apikey == "":
172
+ runner_config.runtime_apikey = runtime.authorizer_configuration.KeyAuth.ApiKey
173
+ # 检查Endpoint连通性
174
+ ping_status = None
175
+ if runtime.status == RUNTIME_STATUS_READY and runtime.endpoint:
176
+ try:
177
+ ping_response = requests.get(
178
+ urljoin(runtime.endpoint, "ping"),
179
+ headers={"Authorization": f"Bearer {runner_config.runtime_apikey}"},
180
+ timeout=10
181
+ )
182
+ ping_status = ping_response.status_code == 200
183
+ except Exception as e:
184
+ logger.error(f"检查Endpoint连通性失败: {str(e)}")
185
+ ping_status = False
186
+
187
+ return {
188
+ "runtime_id": runner_config.runtime_id,
189
+ "runtime_name": runtime.name if hasattr(runtime, 'name') else runner_config.runtime_name,
190
+ "status": runtime.status,
191
+ "endpoint": runtime.endpoint if hasattr(runtime, 'endpoint') else "",
192
+ "image_url": runtime.artifact_url if hasattr(runtime, 'artifact_url') else "",
193
+ "ping_status": ping_status,
194
+ "timestamp": datetime.now().isoformat()
195
+ }
196
+
197
+ except Exception as e:
198
+ logger.error(f"获取Runtime状态失败: {str(e)}")
199
+ if "InvalidAgentKitRuntime.NotFound" in str(e):
200
+ return {"status": "not found", "message": f"Runtime未找到,可能已经被删除,请检查Runtime ID: {runner_config.runtime_id} 是否正确"}
201
+ return {"status": "error", "error": str(e)}
202
+
203
+ def invoke(self, config: Dict[str, Any], payload: Dict[str, Any], headers: Optional[Dict[str, str]] = None, stream: Optional[bool] = None) -> Tuple[bool, Any]:
204
+ """调用Runtime服务
205
+
206
+ Args:
207
+ config: 调用配置,包含Runtime端点和API密钥
208
+ payload: 请求负载
209
+ headers: 请求头
210
+ stream: 是否使用流式调用。None=自动检测(默认), True=强制流式, False=强制非流式
211
+
212
+ Returns:
213
+ 如果 stream=False: (成功标志, 响应数据字典)
214
+ 如果 stream=True: (成功标志, 生成器对象) - 可通过 for 循环迭代事件
215
+ """
216
+ try:
217
+ runner_config = VeAgentkitRunnerConfig.from_dict(config)
218
+
219
+ # 获取Runtime端点和API密钥
220
+ endpoint = runner_config.runtime_endpoint
221
+ api_key = runner_config.runtime_apikey
222
+ if not endpoint or not api_key:
223
+ if not runner_config.runtime_id or runner_config.runtime_id == AUTO_CREATE_VE:
224
+ return False, {"error": "Runtime未部署"}
225
+
226
+ # 自动获取Runtime信息
227
+ try:
228
+ runtime = self.agentkit_runtime.get(
229
+ GetAgentkitRuntimeRequest(RuntimeId=runner_config.runtime_id)
230
+ )
231
+ except Exception as e:
232
+ if "NotFound" in str(e):
233
+ return False, {"error": "配置的Runtime已被外部操作删除,请重新部署"}
234
+ raise e
235
+ endpoint = runtime.endpoint
236
+ api_key = runtime.authorizer_configuration.KeyAuth.ApiKey
237
+
238
+ if not endpoint or not api_key:
239
+ return False, {"error": f"无法获取Runtime端点或API密钥, runtime: {runtime}"}
240
+
241
+ # 构造调用URL
242
+ invoke_endpoint = urljoin(endpoint, "invoke")
243
+
244
+ # 准备请求头
245
+ if headers is None:
246
+ headers = {}
247
+
248
+ if not headers.get("Authorization"):
249
+ headers["Authorization"] = f"Bearer {api_key}"
250
+
251
+ # 使用基类的通用 HTTP 调用方法
252
+ return self._http_post_invoke(
253
+ endpoint=invoke_endpoint,
254
+ payload=payload,
255
+ headers=headers,
256
+ stream=stream,
257
+ timeout=60
258
+ )
259
+
260
+ except Exception as e:
261
+ logger.error(f"Runtime调用失败: {str(e)}")
262
+ return False, {"error": str(e)}
263
+
264
+ def _prepare_runtime_config(self, config: VeAgentkitRunnerConfig) -> bool:
265
+ """准备Runtime配置
266
+
267
+ Args:
268
+ config: Runner配置
269
+
270
+ Returns:
271
+ 是否成功
272
+ """
273
+ try:
274
+ # 检查并创建Runtime名称
275
+ if config.runtime_name == AUTO_CREATE_VE or not config.runtime_name:
276
+ config.runtime_name = generate_runtime_name(config.common_config.agent_name)
277
+ console.print(f"✅ 生成Runtime名称: {config.runtime_name}")
278
+
279
+ # 检查并创建角色名称
280
+ if config.runtime_role_name == AUTO_CREATE_VE or not config.runtime_role_name:
281
+ # config.runtime_role_name = "TestRoleForAgentKit" #
282
+ config.runtime_role_name = generate_runtime_role_name()
283
+ console.print(f"✅ 生成角色名称: {config.runtime_role_name}")
284
+
285
+ # 检查并创建API密钥名称
286
+ if config.runtime_apikey_name == AUTO_CREATE_VE or not config.runtime_apikey_name:
287
+ config.runtime_apikey_name = generate_apikey_name()
288
+ console.print(f"✅ 生成API密钥名称: {config.runtime_apikey_name}")
289
+
290
+ return True
291
+
292
+ except Exception as e:
293
+ logger.error(f"Runtime配置准备失败: {str(e)}")
294
+ return False
295
+
296
+ def _create_new_runtime(self, config: VeAgentkitRunnerConfig) -> Tuple[bool, Dict[str, Any]]:
297
+ """创建新Runtime
298
+
299
+ Args:
300
+ config: Runner配置
301
+
302
+ Returns:
303
+ (成功标志, 部署结果字典)
304
+ """
305
+ try:
306
+ console.print(f"[blue]正在创建Runtime: {config.runtime_name}[/blue]")
307
+
308
+ # 构建创建请求
309
+ envs = [{"Key": str(k), "Value": str(v)} for k, v in config.runtime_envs.items()]
310
+
311
+ create_request = CreateAgentkitRuntimeRequest(
312
+ Name=config.runtime_name,
313
+ Description= config.common_config.description if is_valid_config(config.common_config.description) else f"Auto created by AgentKit CLI for agent project {config.common_config.agent_name}",
314
+ ArtifactType=ARTIFACT_TYPE_DOCKER_IMAGE,
315
+ ArtifactUrl=config.image_url,
316
+ RoleName=config.runtime_role_name,
317
+ Envs=envs,
318
+ ProjectName=PROJECT_NAME_DEFAULT,
319
+ AuthorizerConfiguration=AuthorizerConfiguration(
320
+ KeyAuth=KeyAuth_(
321
+ ApiKey=config.runtime_apikey,
322
+ ApiKeyName=config.runtime_apikey_name,
323
+ ApiKeyLocation=API_KEY_LOCATION
324
+ ),
325
+ ),
326
+ ClientToken=generate_client_token(),
327
+ Tags=[{"Key": "environment", "Value": "test"}],
328
+ ApmplusEnable=True,
329
+ )
330
+
331
+ # console.print("创建请求:")
332
+ # console.print(json.dumps(create_request.model_dump(by_alias=True), indent=2))
333
+
334
+ # 创建Runtime
335
+ runtime_resp, request_id = self.agentkit_runtime.create(create_request)
336
+ config.runtime_id = runtime_resp.id
337
+
338
+ console.print(f"✅ [green]创建Runtime成功: {runtime_resp.id}, request_id: {request_id}[/green]")
339
+ console.print("[blue]等待Runtime状态为Ready...[/blue]")
340
+ console.print("[blue]💡 提示:Runtime初始化中,请耐心等待,不要中断进程[/blue]")
341
+
342
+ # 等待Runtime就绪
343
+ success, runtime, error = self._wait_for_runtime_status(
344
+ runtime_id=config.runtime_id,
345
+ target_status=RUNTIME_STATUS_READY,
346
+ task_description="等待Runtime就绪...",
347
+ timeout=None, # 创建时不设超时
348
+ error_message="初始化失败"
349
+ )
350
+
351
+ if not success:
352
+ console.print(f"[yellow]⚠️ Runtime未成功初始化: {config.runtime_id}[/yellow]")
353
+ console.print(f"[yellow]错误信息: {error}[/yellow]")
354
+
355
+ # 交互式询问用户是否清理
356
+ user_input = input("\n是否清理失败的Runtime? (y/n): ").strip().lower()
357
+
358
+ if user_input in ['y', 'yes', '是']:
359
+ console.print(f"[blue]正在清理失败的Runtime: {config.runtime_id}[/blue]")
360
+ try:
361
+ delete_request = DeleteAgentkitRuntimeRequest(
362
+ RuntimeId=config.runtime_id
363
+ )
364
+ self.agentkit_runtime.delete(delete_request)
365
+ console.print(f"[green]✅ Runtime清理成功[/green]")
366
+ except Exception as e:
367
+ if not "InvalidAgentKitRuntime.NotFound" in str(e):
368
+ console.print(f"[red]清理Runtime失败: {str(e)}[/red]")
369
+ else:
370
+ console.print(f"[yellow]已跳过清理,Runtime保留: {config.runtime_id}[/yellow]")
371
+
372
+ return False, {"error": error}
373
+
374
+ console.print(f"Endpoint: {runtime.endpoint}")
375
+ config.runtime_endpoint = runtime.endpoint
376
+ config.runtime_apikey = runtime.authorizer_configuration.KeyAuth.ApiKey
377
+
378
+ return True, {
379
+ "runtime_id": config.runtime_id,
380
+ "runtime_name": config.runtime_name,
381
+ "runtime_endpoint": runtime.endpoint,
382
+ "runtime_apikey": config.runtime_apikey,
383
+ "runtime_apikey_name": config.runtime_apikey_name,
384
+ "runtime_role_name": config.runtime_role_name,
385
+ "message": "Runtime创建成功"
386
+ }
387
+
388
+ except Exception as e:
389
+ logger.error(f"创建Runtime失败: {str(e)}")
390
+ return False, {"error": str(e)}
391
+
392
+ def _wait_for_runtime_status(
393
+ self,
394
+ runtime_id: str,
395
+ target_status: str,
396
+ task_description: str,
397
+ timeout: Optional[int] = None,
398
+ error_message: str = "等待Runtime状态变化失败"
399
+ ) -> Tuple[bool, Optional[Any], Optional[str]]:
400
+ """等待Runtime达到目标状态(单状态版本)
401
+
402
+ Args:
403
+ runtime_id: Runtime ID
404
+ target_status: 目标状态
405
+ task_description: 进度条任务描述
406
+ timeout: 超时时间(秒),None表示不超时
407
+ error_message: 失败时的错误消息
408
+
409
+ Returns:
410
+ (是否成功, Runtime对象或None, 错误信息或None)
411
+ """
412
+ # 调用多状态版本,传入单个状态作为列表
413
+ return self._wait_for_runtime_status_multiple(
414
+ runtime_id=runtime_id,
415
+ target_statuses=[target_status],
416
+ task_description=task_description,
417
+ timeout=timeout,
418
+ error_message=error_message
419
+ )
420
+
421
+ def _wait_for_runtime_status_multiple(
422
+ self,
423
+ runtime_id: str,
424
+ target_statuses: List[str],
425
+ task_description: str,
426
+ timeout: Optional[int] = None,
427
+ error_message: str = "等待Runtime状态变化失败"
428
+ ) -> Tuple[bool, Optional[Any], Optional[str]]:
429
+ """等待Runtime达到多个目标状态之一
430
+
431
+ Args:
432
+ runtime_id: Runtime ID
433
+ target_statuses: 目标状态列表
434
+ task_description: 进度条任务描述
435
+ timeout: 超时时间(秒),None表示不超时
436
+ error_message: 失败时的错误消息
437
+
438
+ Returns:
439
+ (是否成功, Runtime对象或None, 错误信息或None)
440
+ """
441
+ last_status = None
442
+ start_time = time.time()
443
+ total_time = timeout if timeout else 300 # 用于进度条显示
444
+
445
+ with Progress(
446
+ SpinnerColumn(),
447
+ TextColumn("[progress.description]{task.description}"),
448
+ BarColumn(),
449
+ TaskProgressColumn(),
450
+ TimeElapsedColumn(),
451
+ console=console
452
+ ) as progress:
453
+
454
+ task = progress.add_task(task_description, total=total_time)
455
+
456
+ while True:
457
+ runtime = self.agentkit_runtime.get(
458
+ GetAgentkitRuntimeRequest(RuntimeId=runtime_id)
459
+ )
460
+
461
+ # 检查是否达到任一目标状态
462
+ if runtime.status in target_statuses:
463
+ progress.update(task, completed=1, total=1)
464
+ console.print(f"✅ Runtime状态为{runtime.status}")
465
+ return True, runtime, None
466
+
467
+ # 检查是否出错
468
+ if runtime.status == RUNTIME_STATUS_ERROR:
469
+ progress.update(task, description="[red]Runtime操作失败[/red]")
470
+ return False, None, f"Runtime状态为Error,{error_message}"
471
+
472
+ # 计算已用时间
473
+ elapsed_time = time.time() - start_time
474
+
475
+ # 检查超时
476
+ if timeout and elapsed_time > timeout:
477
+ progress.update(task, description="[red]等待超时[/red]")
478
+ return False, None, f"{error_message}(超时{timeout}秒)"
479
+
480
+ # 状态变化时更新进度条描述
481
+ if runtime.status != last_status:
482
+ progress.update(task, description=f"Runtime状态: {runtime.status}")
483
+ last_status = runtime.status
484
+
485
+ # 更新进度
486
+ progress.update(task, completed=min(elapsed_time, total_time))
487
+
488
+ time.sleep(3)
489
+
490
+ def _needs_runtime_update(self, runtime: runtime_all_types.GetAgentKitRuntimeResponse, config: VeAgentkitRunnerConfig) -> Tuple[bool, str]:
491
+ """检查Runtime是否需要更新
492
+
493
+ Args:
494
+ runtime: 现有Runtime对象
495
+ config: 新的Runner配置
496
+
497
+ Returns:
498
+ (是否需要更新, 更新原因描述)
499
+ """
500
+
501
+ update_reasons = []
502
+
503
+ # 检查镜像URL是否变化
504
+ if runtime.artifact_url != config.image_url:
505
+ update_reasons.append(f"镜像URL变化: {runtime.artifact_url} -> {config.image_url}")
506
+
507
+ # 检查环境变量是否变化
508
+ # 系统自动注入的环境变量前缀,这些不应该被用户修改
509
+ SYSTEM_ENV_PREFIXES = ('OTEL_', 'ENABLE_APMPLUS', 'APMPLUS_')
510
+
511
+ # 将runtime的envs转换为字典进行比较(过滤系统环境变量)
512
+ runtime_envs = {}
513
+ if hasattr(runtime, 'envs') and runtime.envs:
514
+ for env in runtime.envs:
515
+ key = None
516
+ value = None
517
+
518
+ # 尝试小写属性名(runtime_all_types返回的对象)
519
+ if hasattr(env, 'key') and hasattr(env, 'value'):
520
+ key, value = env.key, env.value
521
+ # 尝试大写属性名(兼容其他类型)
522
+ elif hasattr(env, 'Key') and hasattr(env, 'Value'):
523
+ key, value = env.Key, env.Value
524
+ # 如果是字典类型
525
+ elif isinstance(env, dict):
526
+ key = env.get('key') or env.get('Key', '')
527
+ value = env.get('value') or env.get('Value', '')
528
+
529
+ # 过滤掉系统环境变量
530
+ if key and not key.startswith(SYSTEM_ENV_PREFIXES):
531
+ runtime_envs[key] = value
532
+
533
+ # 比较环境变量(只比较用户自定义的)
534
+ if runtime_envs != config.runtime_envs:
535
+ # 找出具体差异
536
+ added_keys = set(config.runtime_envs.keys()) - set(runtime_envs.keys())
537
+ removed_keys = set(runtime_envs.keys()) - set(config.runtime_envs.keys())
538
+ changed_keys = {k for k in set(runtime_envs.keys()) & set(config.runtime_envs.keys())
539
+ if runtime_envs[k] != config.runtime_envs.get(k)}
540
+
541
+ env_changes = []
542
+ if added_keys:
543
+ env_changes.append(f"新增环境变量: {', '.join(added_keys)}")
544
+ if removed_keys:
545
+ env_changes.append(f"删除环境变量: {', '.join(removed_keys)}")
546
+ if changed_keys:
547
+ env_changes.append(f"修改环境变量: {', '.join(changed_keys)}")
548
+
549
+ if env_changes:
550
+ update_reasons.append("环境变量变化: " + "; ".join(env_changes))
551
+
552
+ needs_update = len(update_reasons) > 0
553
+ reason = " | ".join(update_reasons) if needs_update else "配置无变化"
554
+
555
+ return needs_update, reason
556
+
557
+ def _update_existing_runtime(self, config: VeAgentkitRunnerConfig) -> Tuple[bool, Dict[str, Any]]:
558
+ """更新现有Runtime
559
+
560
+ Args:
561
+ config: Runner配置
562
+
563
+ Returns:
564
+ (成功标志, 更新结果字典)
565
+ """
566
+ try:
567
+ console.print("[red]当前功能正在测试,因此会打印较多日志,以供调试[/red]")
568
+ console.print(f"正在更新Runtime: {config.runtime_id}")
569
+
570
+ # 获取现有Runtime信息
571
+ runtime = self.agentkit_runtime_v1.get(
572
+ runtime_all_types.GetAgentKitRuntimeRequest(runtime_id=config.runtime_id)
573
+ )
574
+
575
+ if not runtime:
576
+ return False, {"error": f"未找到Runtime: {config.runtime_id},无法更新Runtime,请检查Runtime状态"}
577
+
578
+ if runtime.artifact_type != ARTIFACT_TYPE_DOCKER_IMAGE:
579
+ return False, {"error": f"不支持的Runtime类型: {runtime.artifact_type}"}
580
+
581
+ # 检查是否需要更新
582
+ # needs_update, update_reason = self._needs_runtime_update(runtime, config)
583
+ needs_update = True # 现在总是更新
584
+
585
+ if not needs_update:
586
+ console.print(f"✅ Runtime配置已是最新,无需更新")
587
+ config.runtime_endpoint = runtime.endpoint
588
+ config.runtime_apikey = runtime.authorizer_configuration.key_auth.api_key
589
+
590
+ return True, {
591
+ "runtime_id": config.runtime_id,
592
+ "runtime_name": runtime.name if hasattr(runtime, 'name') else config.runtime_name,
593
+ "runtime_endpoint": runtime.endpoint,
594
+ "runtime_apikey": config.runtime_apikey,
595
+ "message": "Runtime配置已是最新"
596
+ }
597
+
598
+ console.print(f"开始更新Runtime...")
599
+
600
+ envs = [{"Key": str(k), "Value": str(v)} for k, v in config.runtime_envs.items()]
601
+ self.agentkit_runtime_v1.update(runtime_all_types.UpdateAgentKitRuntimeRequest(
602
+ runtime_id=config.runtime_id,
603
+ artifact_url=config.image_url,
604
+ description=config.common_config.description,
605
+ envs=envs,
606
+ client_token=generate_client_token(),
607
+ ))
608
+
609
+ console.print("✅ Runtime更新请求已提交")
610
+
611
+ # 阶段1:等待Runtime更新完成,状态可能变为UnReleased或直接变为Ready
612
+ console.print("[blue]等待Runtime更新完成...[/blue]")
613
+ success, updated_runtime, error = self._wait_for_runtime_status_multiple(
614
+ runtime_id=config.runtime_id,
615
+ target_statuses=[RUNTIME_STATUS_UNRELEASED, RUNTIME_STATUS_READY],
616
+ task_description="等待Runtime更新完成...",
617
+ timeout=180,
618
+ error_message="更新失败"
619
+ )
620
+
621
+ if not success:
622
+ return False, {"error": error}
623
+
624
+ # 检查当前状态:如果已经是Ready,说明更新直接完成,无需发布
625
+ if updated_runtime.status == RUNTIME_STATUS_READY:
626
+ console.print("[green]✅ Runtime已直接更新至Ready状态,无需发布步骤[/green]")
627
+ else:
628
+ # 阶段2:状态为UnReleased,需要发布更新
629
+ console.print("[blue]开始发布Runtime更新...[/blue]")
630
+ self.agentkit_runtime_v1.release(
631
+ runtime_all_types.ReleaseAgentKitRuntimeRequest(
632
+ runtime_id=config.runtime_id,
633
+ )
634
+ )
635
+
636
+ # 等待发布完成
637
+ console.print("[blue]等待Runtime发布完成,状态变为Ready...[/blue]")
638
+ console.print("[blue]💡 提示:Runtime发布中,请耐心等待,不要中断进程[/blue]")
639
+
640
+ success, updated_runtime, error = self._wait_for_runtime_status(
641
+ runtime_id=config.runtime_id,
642
+ target_status=RUNTIME_STATUS_READY,
643
+ task_description="等待Runtime发布完成...",
644
+ timeout=300,
645
+ error_message="发布失败"
646
+ )
647
+
648
+ if not success:
649
+ return False, {"error": error}
650
+
651
+ console.print(f"Endpoint: {updated_runtime.endpoint}")
652
+ config.runtime_endpoint = updated_runtime.endpoint
653
+ config.runtime_apikey = updated_runtime.authorizer_configuration.KeyAuth.ApiKey
654
+
655
+ return True, {
656
+ "runtime_id": config.runtime_id,
657
+ "runtime_name": runtime.name if hasattr(runtime, 'name') else config.runtime_name,
658
+ "runtime_endpoint": runtime.endpoint,
659
+ "runtime_apikey": config.runtime_apikey,
660
+ "message": "Runtime更新完成"
661
+ }
662
+
663
+ except Exception as e:
664
+ logger.error(f"更新Runtime失败: {str(e)}")
665
+ return False, {"error": str(e)}
@@ -0,0 +1,26 @@
1
+ # Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from .cr_service import CRService, CRServiceConfig, CRServiceResult, CRConfigCallback, DefaultCRConfigCallback
16
+ from .tos_service import TOSService, TOSServiceConfig
17
+
18
+ __all__ = [
19
+ 'CRService',
20
+ 'CRServiceConfig',
21
+ 'CRServiceResult',
22
+ 'CRConfigCallback',
23
+ 'DefaultCRConfigCallback',
24
+ 'TOSService',
25
+ 'TOSServiceConfig'
26
+ ]