veadk-python 0.2.27__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 (218) hide show
  1. veadk/__init__.py +37 -0
  2. veadk/a2a/__init__.py +13 -0
  3. veadk/a2a/agent_card.py +45 -0
  4. veadk/a2a/remote_ve_agent.py +390 -0
  5. veadk/a2a/utils/__init__.py +13 -0
  6. veadk/a2a/utils/agent_to_a2a.py +170 -0
  7. veadk/a2a/ve_a2a_server.py +93 -0
  8. veadk/a2a/ve_agent_executor.py +78 -0
  9. veadk/a2a/ve_middlewares.py +313 -0
  10. veadk/a2a/ve_task_store.py +37 -0
  11. veadk/agent.py +402 -0
  12. veadk/agent_builder.py +93 -0
  13. veadk/agents/loop_agent.py +68 -0
  14. veadk/agents/parallel_agent.py +72 -0
  15. veadk/agents/sequential_agent.py +64 -0
  16. veadk/auth/__init__.py +13 -0
  17. veadk/auth/base_auth.py +22 -0
  18. veadk/auth/ve_credential_service.py +203 -0
  19. veadk/auth/veauth/__init__.py +13 -0
  20. veadk/auth/veauth/apmplus_veauth.py +58 -0
  21. veadk/auth/veauth/ark_veauth.py +75 -0
  22. veadk/auth/veauth/base_veauth.py +50 -0
  23. veadk/auth/veauth/cozeloop_veauth.py +13 -0
  24. veadk/auth/veauth/opensearch_veauth.py +75 -0
  25. veadk/auth/veauth/postgresql_veauth.py +75 -0
  26. veadk/auth/veauth/prompt_pilot_veauth.py +60 -0
  27. veadk/auth/veauth/speech_veauth.py +54 -0
  28. veadk/auth/veauth/utils.py +69 -0
  29. veadk/auth/veauth/vesearch_veauth.py +62 -0
  30. veadk/auth/veauth/viking_mem0_veauth.py +91 -0
  31. veadk/cli/__init__.py +13 -0
  32. veadk/cli/cli.py +58 -0
  33. veadk/cli/cli_clean.py +87 -0
  34. veadk/cli/cli_create.py +163 -0
  35. veadk/cli/cli_deploy.py +233 -0
  36. veadk/cli/cli_eval.py +215 -0
  37. veadk/cli/cli_init.py +214 -0
  38. veadk/cli/cli_kb.py +110 -0
  39. veadk/cli/cli_pipeline.py +285 -0
  40. veadk/cli/cli_prompt.py +86 -0
  41. veadk/cli/cli_update.py +106 -0
  42. veadk/cli/cli_uploadevalset.py +139 -0
  43. veadk/cli/cli_web.py +143 -0
  44. veadk/cloud/__init__.py +13 -0
  45. veadk/cloud/cloud_agent_engine.py +485 -0
  46. veadk/cloud/cloud_app.py +475 -0
  47. veadk/config.py +115 -0
  48. veadk/configs/__init__.py +13 -0
  49. veadk/configs/auth_configs.py +133 -0
  50. veadk/configs/database_configs.py +132 -0
  51. veadk/configs/model_configs.py +78 -0
  52. veadk/configs/tool_configs.py +54 -0
  53. veadk/configs/tracing_configs.py +110 -0
  54. veadk/consts.py +74 -0
  55. veadk/evaluation/__init__.py +17 -0
  56. veadk/evaluation/adk_evaluator/__init__.py +17 -0
  57. veadk/evaluation/adk_evaluator/adk_evaluator.py +302 -0
  58. veadk/evaluation/base_evaluator.py +642 -0
  59. veadk/evaluation/deepeval_evaluator/__init__.py +17 -0
  60. veadk/evaluation/deepeval_evaluator/deepeval_evaluator.py +339 -0
  61. veadk/evaluation/eval_set_file_loader.py +48 -0
  62. veadk/evaluation/eval_set_recorder.py +146 -0
  63. veadk/evaluation/types.py +65 -0
  64. veadk/evaluation/utils/prometheus.py +196 -0
  65. veadk/integrations/__init__.py +13 -0
  66. veadk/integrations/ve_apig/__init__.py +13 -0
  67. veadk/integrations/ve_apig/ve_apig.py +349 -0
  68. veadk/integrations/ve_apig/ve_apig_utils.py +332 -0
  69. veadk/integrations/ve_code_pipeline/__init__.py +13 -0
  70. veadk/integrations/ve_code_pipeline/ve_code_pipeline.py +431 -0
  71. veadk/integrations/ve_cozeloop/__init__.py +13 -0
  72. veadk/integrations/ve_cozeloop/ve_cozeloop.py +96 -0
  73. veadk/integrations/ve_cr/__init__.py +13 -0
  74. veadk/integrations/ve_cr/ve_cr.py +220 -0
  75. veadk/integrations/ve_faas/__init__.py +13 -0
  76. veadk/integrations/ve_faas/template/cookiecutter.json +15 -0
  77. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/__init__.py +13 -0
  78. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/clean.py +23 -0
  79. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/config.yaml.example +6 -0
  80. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/deploy.py +106 -0
  81. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/__init__.py +13 -0
  82. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/agent.py +25 -0
  83. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/app.py +202 -0
  84. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/requirements.txt +3 -0
  85. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/run.sh +49 -0
  86. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{ cookiecutter.app_name }}/__init__.py +14 -0
  87. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{ cookiecutter.app_name }}/agent.py +27 -0
  88. veadk/integrations/ve_faas/ve_faas.py +754 -0
  89. veadk/integrations/ve_faas/ve_faas_utils.py +408 -0
  90. veadk/integrations/ve_faas/web_template/cookiecutter.json +20 -0
  91. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/__init__.py +13 -0
  92. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/clean.py +23 -0
  93. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/config.yaml.example +2 -0
  94. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/deploy.py +44 -0
  95. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/Dockerfile +23 -0
  96. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/app.py +123 -0
  97. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/init_db.py +46 -0
  98. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/models.py +36 -0
  99. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/requirements.txt +4 -0
  100. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/run.sh +21 -0
  101. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/css/style.css +368 -0
  102. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/js/admin.js +0 -0
  103. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/dashboard.html +21 -0
  104. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/edit_post.html +24 -0
  105. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/login.html +21 -0
  106. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/posts.html +53 -0
  107. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/base.html +45 -0
  108. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/index.html +29 -0
  109. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/post.html +14 -0
  110. veadk/integrations/ve_identity/__init__.py +110 -0
  111. veadk/integrations/ve_identity/auth_config.py +261 -0
  112. veadk/integrations/ve_identity/auth_mixins.py +650 -0
  113. veadk/integrations/ve_identity/auth_processor.py +385 -0
  114. veadk/integrations/ve_identity/function_tool.py +158 -0
  115. veadk/integrations/ve_identity/identity_client.py +864 -0
  116. veadk/integrations/ve_identity/mcp_tool.py +181 -0
  117. veadk/integrations/ve_identity/mcp_toolset.py +431 -0
  118. veadk/integrations/ve_identity/models.py +228 -0
  119. veadk/integrations/ve_identity/token_manager.py +188 -0
  120. veadk/integrations/ve_identity/utils.py +151 -0
  121. veadk/integrations/ve_prompt_pilot/__init__.py +13 -0
  122. veadk/integrations/ve_prompt_pilot/ve_prompt_pilot.py +85 -0
  123. veadk/integrations/ve_tls/__init__.py +13 -0
  124. veadk/integrations/ve_tls/utils.py +116 -0
  125. veadk/integrations/ve_tls/ve_tls.py +212 -0
  126. veadk/integrations/ve_tos/ve_tos.py +710 -0
  127. veadk/integrations/ve_viking_db_memory/__init__.py +13 -0
  128. veadk/integrations/ve_viking_db_memory/ve_viking_db_memory.py +308 -0
  129. veadk/knowledgebase/__init__.py +17 -0
  130. veadk/knowledgebase/backends/__init__.py +13 -0
  131. veadk/knowledgebase/backends/base_backend.py +72 -0
  132. veadk/knowledgebase/backends/in_memory_backend.py +91 -0
  133. veadk/knowledgebase/backends/opensearch_backend.py +162 -0
  134. veadk/knowledgebase/backends/redis_backend.py +172 -0
  135. veadk/knowledgebase/backends/utils.py +92 -0
  136. veadk/knowledgebase/backends/vikingdb_knowledge_backend.py +608 -0
  137. veadk/knowledgebase/entry.py +25 -0
  138. veadk/knowledgebase/knowledgebase.py +307 -0
  139. veadk/memory/__init__.py +35 -0
  140. veadk/memory/long_term_memory.py +365 -0
  141. veadk/memory/long_term_memory_backends/__init__.py +13 -0
  142. veadk/memory/long_term_memory_backends/base_backend.py +35 -0
  143. veadk/memory/long_term_memory_backends/in_memory_backend.py +67 -0
  144. veadk/memory/long_term_memory_backends/mem0_backend.py +155 -0
  145. veadk/memory/long_term_memory_backends/opensearch_backend.py +124 -0
  146. veadk/memory/long_term_memory_backends/redis_backend.py +140 -0
  147. veadk/memory/long_term_memory_backends/vikingdb_memory_backend.py +189 -0
  148. veadk/memory/short_term_memory.py +252 -0
  149. veadk/memory/short_term_memory_backends/__init__.py +13 -0
  150. veadk/memory/short_term_memory_backends/base_backend.py +31 -0
  151. veadk/memory/short_term_memory_backends/mysql_backend.py +49 -0
  152. veadk/memory/short_term_memory_backends/postgresql_backend.py +49 -0
  153. veadk/memory/short_term_memory_backends/sqlite_backend.py +55 -0
  154. veadk/memory/short_term_memory_processor.py +100 -0
  155. veadk/processors/__init__.py +26 -0
  156. veadk/processors/base_run_processor.py +120 -0
  157. veadk/prompts/__init__.py +13 -0
  158. veadk/prompts/agent_default_prompt.py +30 -0
  159. veadk/prompts/prompt_evaluator.py +20 -0
  160. veadk/prompts/prompt_memory_processor.py +55 -0
  161. veadk/prompts/prompt_optimization.py +150 -0
  162. veadk/runner.py +732 -0
  163. veadk/tools/__init__.py +13 -0
  164. veadk/tools/builtin_tools/__init__.py +13 -0
  165. veadk/tools/builtin_tools/agent_authorization.py +94 -0
  166. veadk/tools/builtin_tools/generate_image.py +23 -0
  167. veadk/tools/builtin_tools/image_edit.py +300 -0
  168. veadk/tools/builtin_tools/image_generate.py +446 -0
  169. veadk/tools/builtin_tools/lark.py +67 -0
  170. veadk/tools/builtin_tools/las.py +24 -0
  171. veadk/tools/builtin_tools/link_reader.py +66 -0
  172. veadk/tools/builtin_tools/llm_shield.py +381 -0
  173. veadk/tools/builtin_tools/load_knowledgebase.py +97 -0
  174. veadk/tools/builtin_tools/mcp_router.py +29 -0
  175. veadk/tools/builtin_tools/run_code.py +113 -0
  176. veadk/tools/builtin_tools/tts.py +253 -0
  177. veadk/tools/builtin_tools/vesearch.py +49 -0
  178. veadk/tools/builtin_tools/video_generate.py +363 -0
  179. veadk/tools/builtin_tools/web_scraper.py +76 -0
  180. veadk/tools/builtin_tools/web_search.py +83 -0
  181. veadk/tools/demo_tools.py +58 -0
  182. veadk/tools/load_knowledgebase_tool.py +149 -0
  183. veadk/tools/sandbox/__init__.py +13 -0
  184. veadk/tools/sandbox/browser_sandbox.py +37 -0
  185. veadk/tools/sandbox/code_sandbox.py +40 -0
  186. veadk/tools/sandbox/computer_sandbox.py +34 -0
  187. veadk/tracing/__init__.py +13 -0
  188. veadk/tracing/base_tracer.py +58 -0
  189. veadk/tracing/telemetry/__init__.py +13 -0
  190. veadk/tracing/telemetry/attributes/attributes.py +29 -0
  191. veadk/tracing/telemetry/attributes/extractors/common_attributes_extractors.py +180 -0
  192. veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py +858 -0
  193. veadk/tracing/telemetry/attributes/extractors/tool_attributes_extractors.py +152 -0
  194. veadk/tracing/telemetry/attributes/extractors/types.py +164 -0
  195. veadk/tracing/telemetry/exporters/__init__.py +13 -0
  196. veadk/tracing/telemetry/exporters/apmplus_exporter.py +558 -0
  197. veadk/tracing/telemetry/exporters/base_exporter.py +39 -0
  198. veadk/tracing/telemetry/exporters/cozeloop_exporter.py +129 -0
  199. veadk/tracing/telemetry/exporters/inmemory_exporter.py +248 -0
  200. veadk/tracing/telemetry/exporters/tls_exporter.py +139 -0
  201. veadk/tracing/telemetry/opentelemetry_tracer.py +320 -0
  202. veadk/tracing/telemetry/telemetry.py +411 -0
  203. veadk/types.py +47 -0
  204. veadk/utils/__init__.py +13 -0
  205. veadk/utils/audio_manager.py +95 -0
  206. veadk/utils/auth.py +294 -0
  207. veadk/utils/logger.py +59 -0
  208. veadk/utils/mcp_utils.py +44 -0
  209. veadk/utils/misc.py +184 -0
  210. veadk/utils/patches.py +101 -0
  211. veadk/utils/volcengine_sign.py +205 -0
  212. veadk/version.py +15 -0
  213. veadk_python-0.2.27.dist-info/METADATA +373 -0
  214. veadk_python-0.2.27.dist-info/RECORD +218 -0
  215. veadk_python-0.2.27.dist-info/WHEEL +5 -0
  216. veadk_python-0.2.27.dist-info/entry_points.txt +2 -0
  217. veadk_python-0.2.27.dist-info/licenses/LICENSE +201 -0
  218. veadk_python-0.2.27.dist-info/top_level.txt +1 -0
@@ -0,0 +1,754 @@
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 json
16
+ import time
17
+
18
+ import requests
19
+ import volcenginesdkcore
20
+ import volcenginesdkvefaas
21
+ from volcenginesdkvefaas.models.env_for_create_function_input import (
22
+ EnvForCreateFunctionInput,
23
+ )
24
+ from volcenginesdkvefaas.models.tag_for_create_function_input import (
25
+ TagForCreateFunctionInput,
26
+ )
27
+
28
+ import veadk.config
29
+ from veadk.integrations.ve_apig.ve_apig import APIGateway
30
+ from veadk.integrations.ve_faas.ve_faas_utils import (
31
+ signed_request,
32
+ zip_and_encode_folder,
33
+ )
34
+ from veadk.utils.logger import get_logger
35
+ from veadk.utils.misc import formatted_timestamp, getenv
36
+ from veadk.utils.volcengine_sign import ve_request
37
+
38
+ logger = get_logger(__name__)
39
+
40
+
41
+ class VeFaaS:
42
+ def __init__(self, access_key: str, secret_key: str, region: str = "cn-beijing"):
43
+ self.ak = access_key
44
+ self.sk = secret_key
45
+ self.region = region
46
+
47
+ configuration = volcenginesdkcore.Configuration()
48
+ configuration.ak = self.ak
49
+ configuration.sk = self.sk
50
+ configuration.region = region
51
+
52
+ configuration.client_side_validation = True
53
+ volcenginesdkcore.Configuration.set_default(configuration)
54
+
55
+ self.client = volcenginesdkvefaas.VEFAASApi(
56
+ volcenginesdkcore.ApiClient(configuration)
57
+ )
58
+
59
+ self.apig_client = APIGateway(self.ak, self.sk, self.region)
60
+
61
+ self.template_id = "6874f3360bdbc40008ecf8c7"
62
+
63
+ def _upload_and_mount_code(self, function_id: str, path: str):
64
+ """Upload code to VeFaaS temp bucket and mount to function instance.
65
+
66
+ Args:
67
+ function_id (str): Target function ID.
68
+ path (str): Local project path.
69
+ """
70
+ # Get zipped code data
71
+ code_zip_data, code_zip_size, error = zip_and_encode_folder(path)
72
+ logger.info(
73
+ f"Zipped project size: {code_zip_size / 1024 / 1024:.2f} MB",
74
+ )
75
+
76
+ # Upload code to VeFaaS temp bucket
77
+ req = volcenginesdkvefaas.GetCodeUploadAddressRequest(
78
+ function_id=function_id, content_length=code_zip_size
79
+ )
80
+ response = self.client.get_code_upload_address(req)
81
+ upload_url = response.upload_address
82
+
83
+ headers = {
84
+ "Content-Type": "application/zip",
85
+ }
86
+ response = requests.put(url=upload_url, data=code_zip_data, headers=headers)
87
+ if not (200 <= response.status_code < 300):
88
+ error_message = f"Upload failed to {upload_url} with status code {response.status_code}: {response.text}"
89
+ raise ValueError(error_message)
90
+
91
+ # Mount the TOS bucket to function instance
92
+ res = signed_request(
93
+ ak=self.ak,
94
+ sk=self.sk,
95
+ target="CodeUploadCallback",
96
+ body={"FunctionId": function_id},
97
+ )
98
+
99
+ return res
100
+
101
+ def _create_function(self, function_name: str, path: str):
102
+ # Read envs
103
+ envs = []
104
+ for key, value in veadk.config.veadk_environments.items():
105
+ envs.append(EnvForCreateFunctionInput(key=key, value=value))
106
+ logger.info(
107
+ f"Fetch {len(envs)} environment variables.",
108
+ )
109
+
110
+ # Create function
111
+ res = self.client.create_function(
112
+ volcenginesdkvefaas.CreateFunctionRequest(
113
+ command="./run.sh",
114
+ name=function_name,
115
+ description="Created by VeADK (Volcengine Agent Development Kit)",
116
+ tags=[TagForCreateFunctionInput(key="provider", value="veadk")],
117
+ runtime="native-python3.12/v1",
118
+ request_timeout=1800,
119
+ envs=envs,
120
+ memory_mb=2048,
121
+ role=getenv("IAM_ROLE", None, allow_false_values=True),
122
+ )
123
+ )
124
+
125
+ # avoid print secrets
126
+ logger.debug(
127
+ f"Function creation in {res.project_name} project with ID {res.id}"
128
+ )
129
+
130
+ function_id = res.id
131
+
132
+ # Upload and mount code using extracted method
133
+ self._upload_and_mount_code(function_id, path)
134
+
135
+ return function_name, function_id
136
+
137
+ def _create_application(
138
+ self,
139
+ application_name: str,
140
+ function_name: str,
141
+ gateway_name: str,
142
+ upstream_name: str,
143
+ service_name: str,
144
+ enable_key_auth: bool = False,
145
+ ):
146
+ response = ve_request(
147
+ request_body={
148
+ "Name": application_name,
149
+ "Services": [],
150
+ "IAM": [],
151
+ "Config": {
152
+ "Region": self.region,
153
+ "FunctionName": function_name,
154
+ "GatewayName": gateway_name,
155
+ "ServiceName": service_name,
156
+ "UpstreamName": upstream_name,
157
+ "EnableKeyAuth": enable_key_auth,
158
+ "EnableMcpSession": True,
159
+ },
160
+ "TemplateId": self.template_id,
161
+ },
162
+ action="CreateApplication",
163
+ ak=self.ak,
164
+ sk=self.sk,
165
+ service="vefaas",
166
+ version="2021-03-03",
167
+ region="cn-beijing",
168
+ host="open.volcengineapi.com",
169
+ )
170
+
171
+ try:
172
+ if response["Result"]["Status"] == "create_success":
173
+ return response["Result"]["Id"]
174
+ else:
175
+ raise ValueError(f"Create application failed: {response}")
176
+ except Exception as _:
177
+ raise ValueError(f"Create application failed: {response}")
178
+
179
+ def _release_application(self, app_id: str):
180
+ _ = ve_request(
181
+ request_body={"Id": app_id},
182
+ action="ReleaseApplication",
183
+ ak=self.ak,
184
+ sk=self.sk,
185
+ service="vefaas",
186
+ version="2021-03-03",
187
+ region="cn-beijing",
188
+ host="open.volcengineapi.com",
189
+ )
190
+
191
+ status, full_response = self._get_application_status(app_id)
192
+ while status not in ["deploy_success", "deploy_fail"]:
193
+ time.sleep(10)
194
+ status, full_response = self._get_application_status(app_id)
195
+
196
+ if status == "deploy_success":
197
+ cloud_resource = full_response["Result"]["CloudResource"]
198
+ cloud_resource = json.loads(cloud_resource)
199
+ url = cloud_resource["framework"]["url"]["system_url"]
200
+ return url
201
+ else:
202
+ logger.error(
203
+ f"Release application failed. Application ID: {app_id}, Status: {status}"
204
+ )
205
+ import re
206
+
207
+ logs = "\n".join(self._get_application_logs(app_id=app_id))
208
+ log_text = re.sub(
209
+ r'([{"\']?(key|secret|token|pass|auth|credential|access|api|ak|sk|doubao|volces|coze)[^"\'\s]*["\']?\s*[:=]\s*)(["\']?)([^"\'\s]+)(["\']?)|([A-Za-z0-9+/=]{20,})',
210
+ lambda m: (
211
+ f"{m.group(1)}{m.group(3)}******{m.group(5)}"
212
+ if m.group(1)
213
+ else "******"
214
+ ),
215
+ logs,
216
+ flags=re.IGNORECASE,
217
+ )
218
+ raise Exception(f"Release application failed. Logs:\n{log_text}")
219
+
220
+ def _get_application_status(self, app_id: str):
221
+ response = ve_request(
222
+ request_body={"Id": app_id},
223
+ action="GetApplication",
224
+ ak=self.ak,
225
+ sk=self.sk,
226
+ service="vefaas",
227
+ version="2021-03-03",
228
+ region="cn-beijing",
229
+ host="open.volcengineapi.com",
230
+ )
231
+ return response["Result"]["Status"], response
232
+
233
+ def _list_application(self, app_id: str = None, app_name: str = None):
234
+ # firt match app_id. if app_id is None,then match app_name and remove app_id
235
+ request_body = {
236
+ "OrderBy": {"Key": "CreateTime", "Ascend": False},
237
+ "FunctionId": app_id if app_id else None,
238
+ "Filters": (
239
+ [{"Item": {"Key": "Name", "Value": [app_name]}}]
240
+ if app_name and not app_id
241
+ else None
242
+ ),
243
+ }
244
+ # remove None
245
+ request_body = {k: v for k, v in request_body.items() if v is not None}
246
+
247
+ page_size = 50
248
+ page_number = 1
249
+ all_items = []
250
+ total_page = None
251
+ while True:
252
+ try:
253
+ request_body.update({"PageNumber": page_number, "PageSize": page_size})
254
+ response = ve_request(
255
+ request_body=request_body,
256
+ action="ListApplications",
257
+ ak=self.ak,
258
+ sk=self.sk,
259
+ service="vefaas",
260
+ version="2021-03-03",
261
+ region="cn-beijing",
262
+ host="open.volcengineapi.com",
263
+ )
264
+ result = response.get("Result", {})
265
+ items = result.get("Items", [])
266
+ all_items.extend(items)
267
+
268
+ if total_page is None:
269
+ total = result.get("Total", 0)
270
+ total_page = (total + page_size - 1) // page_size
271
+
272
+ if page_number >= total_page or not items:
273
+ break
274
+ page_number += 1
275
+ except Exception as e:
276
+ raise ValueError(
277
+ f"List application failed. Error: {str(e)}. Response: {response}."
278
+ )
279
+ return all_items
280
+
281
+ def _update_function_code(
282
+ self,
283
+ application_name: str, # application name
284
+ path: str,
285
+ ) -> tuple[str, str, str]:
286
+ """Update existing application function code while preserving URL.
287
+
288
+ Args:
289
+ application_name (str): Application name to update.
290
+ path (str): Local project path.
291
+
292
+ Returns:
293
+ tuple[str, str, str]: URL, app_id, function_id
294
+ """
295
+ # Naming check
296
+ if "_" in application_name:
297
+ raise ValueError("Function or Application name cannot contain '_'.")
298
+
299
+ # Find existing application
300
+ app_id = self.find_app_id_by_name(application_name)
301
+ if not app_id:
302
+ raise ValueError(
303
+ f"Application '{application_name}' not found. Use deploy() for new applications."
304
+ )
305
+
306
+ # Get application status and extract function info
307
+ status, full_response = self._get_application_status(app_id)
308
+
309
+ # Extract function name from application config
310
+ cloud_resource = full_response["Result"]["CloudResource"]
311
+ cloud_resource = json.loads(cloud_resource)
312
+ function_name = cloud_resource["framework"]["function"]["Name"]
313
+ # existing_url = cloud_resource["framework"]["url"]["system_url"]
314
+ function_id = cloud_resource["framework"]["function"]["Id"]
315
+ if not function_id:
316
+ raise ValueError(f"Function '{function_name}' not found for update")
317
+
318
+ logger.info(
319
+ f"Start to update VeFaaS function {function_name} with path {path}."
320
+ )
321
+
322
+ # Upload and mount code using extracted method
323
+ self._upload_and_mount_code(function_id, path)
324
+
325
+ # Use update_function client method to apply changes
326
+ self.client.update_function(
327
+ volcenginesdkvefaas.UpdateFunctionRequest(
328
+ id=function_id,
329
+ request_timeout=1800, # Keep same timeout as deploy
330
+ )
331
+ )
332
+
333
+ logger.info(f"Function updated successfully: {function_id}")
334
+
335
+ logger.info(f"VeFaaS function {function_name} with ID {function_id} updated.")
336
+
337
+ # Release the application to apply changes
338
+ url = self._release_application(app_id)
339
+
340
+ logger.info(f"VeFaaS application {application_name} with ID {app_id} released.")
341
+
342
+ logger.info(
343
+ f"VeFaaS application {application_name} with ID {app_id} updated on {url}."
344
+ )
345
+
346
+ return url, app_id, function_id
347
+
348
+ def get_application_details(self, app_id: str = None, app_name: str = None):
349
+ if not app_id and not app_name:
350
+ raise ValueError("app_id and app_name cannot be both empty.")
351
+ apps = self._list_application(app_id=app_id, app_name=app_name)
352
+ if app_id:
353
+ for app in apps:
354
+ if app["Id"] == app_id:
355
+ return app
356
+ return None
357
+ else:
358
+ for app in apps:
359
+ if app["Name"] == app_name:
360
+ return app
361
+
362
+ def get_application_route(
363
+ self, app_id: str = None, app_name: str = None
364
+ ) -> tuple[str, str, str] | None:
365
+ app = self.get_application_details(
366
+ app_id=app_id,
367
+ app_name=app_name,
368
+ )
369
+ if not app:
370
+ return None
371
+
372
+ cloud_resource = json.loads(app["CloudResource"])
373
+ gateway_id = cloud_resource["framework"]["triggers"][0]["DetailedConfig"][
374
+ "GatewayId"
375
+ ]
376
+ service_id = cloud_resource["framework"]["triggers"][0]["Routes"][0][
377
+ "ServiceId"
378
+ ]
379
+ route_id = cloud_resource["framework"]["triggers"][0]["Routes"][0]["Id"]
380
+ return gateway_id, service_id, route_id
381
+
382
+ def find_app_id_by_name(self, name: str):
383
+ apps = self._list_application(app_name=name)
384
+ for app in apps:
385
+ if app["Name"] == name:
386
+ return app["Id"]
387
+ logger.warning(f"Application with name {name} not found.")
388
+ return None
389
+
390
+ def delete(self, app_id: str):
391
+ try:
392
+ ve_request(
393
+ request_body={"Id": app_id},
394
+ action="DeleteApplication",
395
+ ak=self.ak,
396
+ sk=self.sk,
397
+ service="vefaas",
398
+ version="2021-03-03",
399
+ region="cn-beijing",
400
+ host="open.volcengineapi.com",
401
+ )
402
+ except Exception as e:
403
+ logger.error(f"Delete application failed. Response: {e}")
404
+
405
+ def deploy(
406
+ self,
407
+ name: str,
408
+ path: str,
409
+ gateway_name: str = "",
410
+ gateway_service_name: str = "",
411
+ gateway_upstream_name: str = "",
412
+ enable_key_auth: bool = False,
413
+ ) -> tuple[str, str, str]:
414
+ """Deploy an agent project to VeFaaS service.
415
+
416
+ Args:
417
+ name (str): Application name (warning: not function name).
418
+ path (str): Project path.
419
+ gateway_name (str, optional): Gateway name. Defaults to "".
420
+ gateway_service_name (str, optional): Gateway service name. Defaults to "".
421
+ gateway_upstream_name (str, optional): Gateway upstream name. Defaults to "".
422
+ enable_key_auth (bool, optional): Enable key auth. Defaults to False.
423
+
424
+ Returns:
425
+ tuple[str, str, str]: (url, app_id, function_id)
426
+ """
427
+ # Naming check
428
+ if "_" in name:
429
+ raise ValueError("Function or Application name cannot contain '_'.")
430
+
431
+ # Give default names
432
+ if not gateway_name:
433
+ gateway_name = f"{name}-gw-{formatted_timestamp()}"
434
+
435
+ existing_gateways = self.apig_client.list_gateways()
436
+ for gateway_instance in existing_gateways.items:
437
+ if (
438
+ gateway_instance.type == "serverless"
439
+ and gateway_instance.name != gateway_name
440
+ ):
441
+ logger.warning(
442
+ f"You have at least one serverless gateway {gateway_instance.name}, but not {gateway_name}. Using {gateway_instance.name} instead."
443
+ )
444
+ gateway_name = gateway_instance.name
445
+ break
446
+
447
+ if not gateway_service_name:
448
+ gateway_service_name = f"{name}-gw-svr-{formatted_timestamp()}"
449
+ if not gateway_upstream_name:
450
+ gateway_upstream_name = f"{name}-gw-us-{formatted_timestamp()}"
451
+
452
+ function_name = f"{name}-fn"
453
+
454
+ logger.info(
455
+ f"Start to create VeFaaS function {function_name} with path {path}. Gateway: {gateway_name}, Gateway Service: {gateway_service_name}, Gateway Upstream: {gateway_upstream_name}."
456
+ )
457
+ function_name, function_id = self._create_function(function_name, path)
458
+ logger.info(f"VeFaaS function {function_name} with ID {function_id} created.")
459
+
460
+ logger.info(f"Start to create VeFaaS application {name}.")
461
+ app_id = self._create_application(
462
+ name,
463
+ function_name,
464
+ gateway_name,
465
+ gateway_upstream_name,
466
+ gateway_service_name,
467
+ enable_key_auth,
468
+ )
469
+
470
+ logger.info(f"VeFaaS application {name} with ID {app_id} created.")
471
+ logger.info(f"Start to release VeFaaS application {app_id}.")
472
+ url = self._release_application(app_id)
473
+ logger.info(f"VeFaaS application {name} with ID {app_id} released.")
474
+
475
+ logger.info(f"VeFaaS application {name} with ID {app_id} deployed on {url}.")
476
+
477
+ return url, app_id, function_id
478
+
479
+ def _create_image_function(self, function_name: str, image: str):
480
+ """Create function using container image instead of code upload."""
481
+ # Read environment variables from veadk configuration
482
+ envs = []
483
+ for key, value in veadk.config.veadk_environments.items():
484
+ envs.append(EnvForCreateFunctionInput(key=key, value=value))
485
+ logger.info(
486
+ f"Fetch {len(envs)} environment variables for image function.",
487
+ )
488
+
489
+ # Create function with container image source configuration
490
+ res = self.client.create_function(
491
+ volcenginesdkvefaas.CreateFunctionRequest(
492
+ command="bash ./run.sh", # Custom startup command
493
+ name=function_name,
494
+ description="Created by VeADK (Volcengine Agent Development Kit)",
495
+ tags=[TagForCreateFunctionInput(key="provider", value="veadk")],
496
+ runtime="native/v1", # Native runtime required for container images
497
+ source_type="image", # Set source type to container image
498
+ source=image, # Container image URL
499
+ request_timeout=1800, # Request timeout in seconds
500
+ envs=envs, # Environment variables from configuration
501
+ )
502
+ )
503
+
504
+ # Log function creation success without exposing sensitive information
505
+ logger.debug(
506
+ f"Function creation in {res.project_name} project with ID {res.id}"
507
+ )
508
+
509
+ function_id = res.id
510
+ logger.info(
511
+ f"Function {function_name} created with image {image} and ID {function_id}"
512
+ )
513
+
514
+ return function_name, function_id
515
+
516
+ def query_user_cr_vpc_tunnel(
517
+ self, registry_name: str, max_attempts: int = 6
518
+ ) -> bool:
519
+ """Query and enable CR VPC tunnel for user registry access."""
520
+ logger.info(f"Setting up CR VPC tunnel for registry: {registry_name}")
521
+ waiting_times = 30
522
+
523
+ try:
524
+ for attempt in range(max_attempts):
525
+ # Check current status
526
+ logger.info(
527
+ f"Checking tunnel status (attempt {attempt + 1}/{max_attempts})"
528
+ )
529
+ query_resp = ve_request(
530
+ request_body={"Registry": registry_name},
531
+ action="QueryUserCrVpcTunnel",
532
+ ak=self.ak,
533
+ sk=self.sk,
534
+ service="vefaas",
535
+ version="2021-03-03",
536
+ region="cn-beijing",
537
+ host="open.volcengineapi.com",
538
+ )
539
+
540
+ current_status = query_resp.get("Result", {}).get("Ready", False)
541
+ logger.info(f"Current tunnel status: {current_status}")
542
+
543
+ # Always try to enable
544
+ logger.info("Enable VPC tunnel")
545
+ enable_resp = ve_request(
546
+ request_body={"Registry": registry_name},
547
+ action="EnableUserCrVpcTunnel",
548
+ ak=self.ak,
549
+ sk=self.sk,
550
+ service="vefaas",
551
+ version="2021-03-03",
552
+ region="cn-beijing",
553
+ host="open.volcengineapi.com",
554
+ )
555
+
556
+ # Handle EnableUserCrVpcTunnel response correctly
557
+ enable_result = enable_resp.get("Result", {})
558
+ enable_status = enable_result.get("Status", "")
559
+ enable_message = enable_result.get("Message", "")
560
+
561
+ if enable_status == "success":
562
+ logger.info("Enable tunnel succeeded")
563
+ elif enable_status == "failed":
564
+ logger.warning(f"Enable tunnel failed: {enable_message}")
565
+ else:
566
+ logger.warning(f"Enable tunnel unknown status: {enable_status}")
567
+
568
+ # Verify final status
569
+ logger.info("Verifying tunnel status")
570
+ verify_resp = ve_request(
571
+ request_body={"Registry": registry_name},
572
+ action="QueryUserCrVpcTunnel",
573
+ ak=self.ak,
574
+ sk=self.sk,
575
+ service="vefaas",
576
+ version="2021-03-03",
577
+ region="cn-beijing",
578
+ host="open.volcengineapi.com",
579
+ )
580
+
581
+ final_status = verify_resp.get("Result", {}).get("Ready", False)
582
+ logger.info(f"Final tunnel status: {final_status}")
583
+
584
+ if final_status:
585
+ logger.info(
586
+ f"CR VPC tunnel successfully enabled for {registry_name}"
587
+ )
588
+ return True
589
+
590
+ # If not ready and not last attempt, wait and retry
591
+ if attempt < max_attempts - 1:
592
+ logger.warning(
593
+ f"Tunnel not ready, waiting {waiting_times}s before retry"
594
+ )
595
+ time.sleep(waiting_times)
596
+
597
+ except Exception as e:
598
+ raise ValueError(f"Failed to setup CR VPC tunnel: {str(e)}")
599
+
600
+ return False
601
+
602
+ def _create_image_function(self, function_name: str, image: str):
603
+ """Create function using container image instead of code upload."""
604
+ # Read environment variables from veadk configuration
605
+ envs = []
606
+ for key, value in veadk.config.veadk_environments.items():
607
+ envs.append(EnvForCreateFunctionInput(key=key, value=value))
608
+ logger.info(
609
+ f"Fetch {len(envs)} environment variables for image function.",
610
+ )
611
+
612
+ # Create function with container image source configuration
613
+ res = self.client.create_function(
614
+ volcenginesdkvefaas.CreateFunctionRequest(
615
+ command="bash ./run.sh", # Custom startup command
616
+ name=function_name,
617
+ description="Created by VeADK (Volcengine Agent Development Kit)",
618
+ tags=[TagForCreateFunctionInput(key="provider", value="veadk")],
619
+ runtime="native/v1", # Native runtime required for container images
620
+ source_type="image", # Set source type to container image
621
+ source=image, # Container image URL
622
+ request_timeout=1800, # Request timeout in seconds
623
+ envs=envs, # Environment variables from configuration
624
+ )
625
+ )
626
+
627
+ # Log function creation success without exposing sensitive information
628
+ logger.debug(
629
+ f"Function creation in {res.project_name} project with ID {res.id}"
630
+ )
631
+
632
+ function_id = res.id
633
+ logger.info(
634
+ f"Function {function_name} created with image {image} and ID {function_id}"
635
+ )
636
+
637
+ return function_name, function_id
638
+
639
+ def deploy_image(
640
+ self,
641
+ name: str,
642
+ image: str,
643
+ registry_name: str,
644
+ gateway_name: str = "",
645
+ gateway_service_name: str = "",
646
+ gateway_upstream_name: str = "",
647
+ ) -> tuple[str, str, str]:
648
+ """Deploy application using container image.
649
+
650
+ Args:
651
+ name (str): Application name.
652
+ image (str): Container image URL.
653
+ gateway_name (str, optional): Gateway name. Defaults to "".
654
+ gateway_service_name (str, optional): Gateway service name. Defaults to "".
655
+ gateway_upstream_name (str, optional): Gateway upstream name. Defaults to "".
656
+
657
+ Returns:
658
+ tuple[str, str, str]: (url, app_id, function_id)
659
+ """
660
+ # Validate application name format
661
+ is_ready = self.query_user_cr_vpc_tunnel(registry_name)
662
+ if not is_ready:
663
+ raise ValueError("CR VPC tunnel is not ready")
664
+
665
+ if "_" in name:
666
+ raise ValueError("Function or Application name cannot contain '_'.")
667
+
668
+ # Generate default gateway names with timestamp if not provided
669
+ if not gateway_name:
670
+ gateway_name = f"{name}-gw-{formatted_timestamp()}"
671
+
672
+ # Check for existing serverless gateways to reuse
673
+ existing_gateways = self.apig_client.list_gateways()
674
+ for gateway_instance in existing_gateways.items:
675
+ if (
676
+ gateway_instance.type == "serverless"
677
+ and gateway_instance.name != gateway_name
678
+ ):
679
+ logger.warning(
680
+ f"You have at least one serverless gateway {gateway_instance.name}, but not {gateway_name}. Using {gateway_instance.name} instead."
681
+ )
682
+ gateway_name = gateway_instance.name
683
+ break
684
+
685
+ # Set default gateway service and upstream names
686
+ if not gateway_service_name:
687
+ gateway_service_name = f"{name}-gw-svr-{formatted_timestamp()}"
688
+ if not gateway_upstream_name:
689
+ gateway_upstream_name = f"{name}-gw-us-{formatted_timestamp()}"
690
+
691
+ function_name = f"{name}-fn"
692
+
693
+ # Log deployment start with image information
694
+ logger.info(
695
+ f"Start to create VeFaaS function {function_name} with image {image}. Gateway: {gateway_name}, Gateway Service: {gateway_service_name}, Gateway Upstream: {gateway_upstream_name}."
696
+ )
697
+
698
+ # Create function using container image method
699
+ function_name, function_id = self._create_image_function(function_name, image)
700
+ logger.info(f"VeFaaS function {function_name} with ID {function_id} created.")
701
+
702
+ # Create application using existing application creation logic
703
+ logger.info(f"Start to create VeFaaS application {name}.")
704
+ app_id = self._create_application(
705
+ name,
706
+ function_name,
707
+ gateway_name,
708
+ gateway_upstream_name,
709
+ gateway_service_name,
710
+ )
711
+
712
+ # Release application and get deployment URL
713
+ logger.info(f"VeFaaS application {name} with ID {app_id} created.")
714
+ logger.info(f"Start to release VeFaaS application {app_id}.")
715
+ # Release application with retry
716
+ max_attempts = 5
717
+ attempt = 0
718
+ while True:
719
+ try:
720
+ url = self._release_application(app_id)
721
+ logger.info(f"VeFaaS application {name} with ID {app_id} released.")
722
+ break
723
+ except Exception:
724
+ attempt += 1
725
+ if attempt < max_attempts:
726
+ wait_time = 30 * attempt
727
+ logger.info(
728
+ f"Image sync still in progress. Waiting {wait_time} seconds before retry {attempt}/{max_attempts}."
729
+ )
730
+ time.sleep(wait_time)
731
+ else:
732
+ raise
733
+
734
+ logger.info(f"VeFaaS application {name} with ID {app_id} deployed on {url}.")
735
+
736
+ return url, app_id, function_id
737
+
738
+ def _get_application_logs(self, app_id: str) -> list[str]:
739
+ response = _ = ve_request(
740
+ request_body={"Id": app_id, "Limit": 99999, "RevisionNumber": 1},
741
+ action="GetApplicationRevisionLog",
742
+ ak=self.ak,
743
+ sk=self.sk,
744
+ service="vefaas",
745
+ version="2021-03-03",
746
+ region="cn-beijing",
747
+ host="open.volcengineapi.com",
748
+ )
749
+
750
+ try:
751
+ logs = response["Result"]["LogLines"]
752
+ return logs
753
+ except Exception as _:
754
+ raise ValueError(f"Get application log failed. Response: {response}")