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,446 @@
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 asyncio
16
+ import base64
17
+ import concurrent.futures
18
+ import contextvars
19
+ import json
20
+ import mimetypes
21
+ import traceback
22
+ from typing import Dict
23
+
24
+ from google.adk.tools import ToolContext
25
+ from google.genai.types import Blob, Part
26
+ from opentelemetry import trace
27
+ from opentelemetry.trace import Span
28
+ from volcenginesdkarkruntime import Ark
29
+ from volcenginesdkarkruntime.types.images.images import SequentialImageGenerationOptions
30
+
31
+ from veadk.config import getenv, settings
32
+ from veadk.consts import (
33
+ DEFAULT_IMAGE_GENERATE_MODEL_API_BASE,
34
+ DEFAULT_IMAGE_GENERATE_MODEL_NAME,
35
+ )
36
+ from veadk.utils.logger import get_logger
37
+ from veadk.utils.misc import formatted_timestamp, read_file_to_bytes
38
+ from veadk.version import VERSION
39
+
40
+ logger = get_logger(__name__)
41
+
42
+ client = Ark(
43
+ api_key=getenv(
44
+ "MODEL_IMAGE_API_KEY", getenv("MODEL_AGENT_API_KEY", settings.model.api_key)
45
+ ),
46
+ base_url=getenv("MODEL_IMAGE_API_BASE", DEFAULT_IMAGE_GENERATE_MODEL_API_BASE),
47
+ )
48
+
49
+ executor = concurrent.futures.ThreadPoolExecutor(max_workers=8)
50
+ tracer = trace.get_tracer("veadk")
51
+
52
+
53
+ def _build_input_parts(item: dict, task_type: str, image_field):
54
+ input_part = {"role": "user"}
55
+ input_part["parts.0.type"] = "text"
56
+ input_part["parts.0.text"] = json.dumps(item, ensure_ascii=False)
57
+
58
+ if image_field:
59
+ if task_type.startswith("single"):
60
+ assert isinstance(image_field, str), (
61
+ f"single_* task_type image must be str, got {type(image_field)}"
62
+ )
63
+ input_part["parts.1.type"] = "image_url"
64
+ input_part["parts.1.image_url.name"] = "origin_image"
65
+ input_part["parts.1.image_url.url"] = image_field
66
+ elif task_type.startswith("multi"):
67
+ assert isinstance(image_field, list), (
68
+ f"multi_* task_type image must be list, got {type(image_field)}"
69
+ )
70
+ assert len(image_field) <= 10, (
71
+ f"multi_* task_type image list length must be <= 10, got {len(image_field)}"
72
+ )
73
+ for i, image_url in enumerate(image_field):
74
+ idx = i + 1
75
+ input_part[f"parts.{idx}.type"] = "image_url"
76
+ input_part[f"parts.{idx}.image_url.name"] = f"origin_image_{i}"
77
+ input_part[f"parts.{idx}.image_url.url"] = image_url
78
+
79
+ return input_part
80
+
81
+
82
+ def handle_single_task_sync(
83
+ idx: int, item: dict, tool_context
84
+ ) -> tuple[list[dict], list[str]]:
85
+ logger.debug(f"handle_single_task_sync item {idx}: {item}")
86
+ success_list: list[dict] = []
87
+ error_list: list[str] = []
88
+ total_tokens = 0
89
+ output_tokens = 0
90
+ output_part = {"message.role": "model"}
91
+
92
+ task_type = item.get("task_type", "text_to_single")
93
+ prompt = item.get("prompt", "")
94
+ response_format = item.get("response_format", None)
95
+ size = item.get("size", None)
96
+ watermark = item.get("watermark", None)
97
+ image_field = item.get("image", None)
98
+ sequential_image_generation = item.get("sequential_image_generation", None)
99
+ max_images = item.get("max_images", None)
100
+
101
+ input_part = _build_input_parts(item, task_type, image_field)
102
+
103
+ inputs = {"prompt": prompt}
104
+ if size:
105
+ inputs["size"] = size
106
+ if response_format:
107
+ inputs["response_format"] = response_format
108
+ if watermark is not None:
109
+ inputs["watermark"] = watermark
110
+ if sequential_image_generation:
111
+ inputs["sequential_image_generation"] = sequential_image_generation
112
+
113
+ with tracer.start_as_current_span(f"call_llm_task_{idx}") as span:
114
+ try:
115
+ if (
116
+ sequential_image_generation
117
+ and sequential_image_generation == "auto"
118
+ and max_images
119
+ ):
120
+ response = client.images.generate(
121
+ model=getenv("MODEL_IMAGE_NAME", DEFAULT_IMAGE_GENERATE_MODEL_NAME),
122
+ **inputs,
123
+ sequential_image_generation_options=SequentialImageGenerationOptions(
124
+ max_images=max_images
125
+ ),
126
+ )
127
+ else:
128
+ response = client.images.generate(
129
+ model=getenv("MODEL_IMAGE_NAME", DEFAULT_IMAGE_GENERATE_MODEL_NAME),
130
+ **inputs,
131
+ )
132
+
133
+ if not response.error:
134
+ logger.debug(f"task {idx} Image generate response: {response}")
135
+
136
+ total_tokens += getattr(response.usage, "total_tokens", 0) or 0
137
+ output_tokens += getattr(response.usage, "output_tokens", 0) or 0
138
+
139
+ for i, image_data in enumerate(response.data):
140
+ image_name = f"task_{idx}_image_{i}"
141
+ if "error" in image_data:
142
+ logger.error(f"Image {image_name} error: {image_data.error}")
143
+ error_list.append(image_name)
144
+ continue
145
+
146
+ if getattr(image_data, "url", None):
147
+ image_url = image_data.url
148
+ else:
149
+ b64 = getattr(image_data, "b64_json", None)
150
+ if not b64:
151
+ logger.error(
152
+ f"Image {image_name} missing data (no url/b64)"
153
+ )
154
+ error_list.append(image_name)
155
+ continue
156
+ image_bytes = base64.b64decode(b64)
157
+ image_url = _upload_image_to_tos(
158
+ image_bytes=image_bytes, object_key=f"{image_name}.png"
159
+ )
160
+ if not image_url:
161
+ logger.error(f"Upload image to TOS failed: {image_name}")
162
+ error_list.append(image_name)
163
+ continue
164
+ logger.debug(f"Image saved as ADK artifact: {image_name}")
165
+
166
+ tool_context.state[f"{image_name}_url"] = image_url
167
+ output_part[f"message.parts.{i}.type"] = "image_url"
168
+ output_part[f"message.parts.{i}.image_url.name"] = image_name
169
+ output_part[f"message.parts.{i}.image_url.url"] = image_url
170
+ logger.debug(
171
+ f"Image {image_name} generated successfully: {image_url}"
172
+ )
173
+ success_list.append({image_name: image_url})
174
+ else:
175
+ logger.error(
176
+ f"Task {idx} No images returned by model: {response.error}"
177
+ )
178
+ error_list.append(f"task_{idx}")
179
+
180
+ except Exception as e:
181
+ logger.error(f"Error in task {idx}: {e}")
182
+ traceback.print_exc()
183
+ error_list.append(f"task_{idx}")
184
+
185
+ finally:
186
+ add_span_attributes(
187
+ span,
188
+ tool_context,
189
+ input_part=input_part,
190
+ output_part=output_part,
191
+ output_tokens=output_tokens,
192
+ total_tokens=total_tokens,
193
+ request_model=getenv(
194
+ "MODEL_IMAGE_NAME", DEFAULT_IMAGE_GENERATE_MODEL_NAME
195
+ ),
196
+ response_model=getenv(
197
+ "MODEL_IMAGE_NAME", DEFAULT_IMAGE_GENERATE_MODEL_NAME
198
+ ),
199
+ )
200
+ logger.debug(
201
+ f"task {idx} Image generate success_list: {success_list}\nerror_list: {error_list}"
202
+ )
203
+ return success_list, error_list
204
+
205
+
206
+ async def image_generate(tasks: list[dict], tool_context) -> Dict:
207
+ """Generate images with Seedream 4.0.
208
+
209
+ Commit batch image generation requests via tasks.
210
+
211
+ Args:
212
+ tasks (list[dict]):
213
+ A list of image-generation tasks. Each task is a dict.
214
+ Per-task schema
215
+ ---------------
216
+ Required:
217
+ - task_type (str):
218
+ One of:
219
+ * "multi_image_to_group" # 多图生组图
220
+ * "single_image_to_group" # 单图生组图
221
+ * "text_to_group" # 文生组图
222
+ * "multi_image_to_single" # 多图生单图
223
+ * "single_image_to_single" # 单图生单图
224
+ * "text_to_single" # 文生单图
225
+ - prompt (str)
226
+ Text description of the desired image(s). 中文/English 均可。
227
+ 若要指定生成图片的数量,请在prompt中添加"生成N张图片",其中N为具体的数字。
228
+ Optional:
229
+ - size (str)
230
+ 指定生成图像的大小,有两种用法(二选一,不可混用):
231
+ 方式 1:分辨率级别
232
+ 可选值: "1K", "2K", "4K"
233
+ 模型会结合 prompt 中的语义推断合适的宽高比、长宽。
234
+ 方式 2:具体宽高值
235
+ 格式: "<宽度>x<高度>",如 "2048x2048", "2384x1728"
236
+ 约束:
237
+ * 总像素数范围: [1024x1024, 4096x4096]
238
+ * 宽高比范围: [1/16, 16]
239
+ 推荐值:
240
+ - 1:1 → 2048x2048
241
+ - 4:3 → 2384x1728
242
+ - 3:4 → 1728x2304
243
+ - 16:9 → 2560x1440
244
+ - 9:16 → 1440x2560
245
+ - 3:2 → 2496x1664
246
+ - 2:3 → 1664x2496
247
+ - 21:9 → 3024x1296
248
+ 默认值: "2048x2048"
249
+ - response_format (str)
250
+ Return format: "url" (default, URL 24h 过期) | "b64_json".
251
+ - watermark (bool)
252
+ Add watermark. Default: true.
253
+ - image (str | list[str]) # 仅“非文生图”需要。文生图请不要提供 image
254
+ Reference image(s) as URL or Base64.
255
+ * 生成“单图”的任务:传入 string(exactly 1 image)。
256
+ * 生成“组图”的任务:传入 array(2–10 images)。
257
+ - sequential_image_generation (str)
258
+ 控制是否生成“组图”。Default: "disabled".
259
+ * 若要生成组图:必须设为 "auto"。
260
+ - max_images (int)
261
+ 仅当生成组图时生效。控制模型能生成的最多张数,范围 [1, 15], 不设置默认为15。
262
+ 注意这个参数不等于生成的图片数量,而是模型最多能生成的图片数量。
263
+ 在单图组图场景最多 14;多图组图场景需满足 (len(images)+max_images ≤ 15)。
264
+ Model 行为说明(如何由参数推断模式)
265
+ ---------------------------------
266
+ 1) 文生单图: 不提供 image 且 (S 未设置或 S="disabled") → 1 张图。
267
+ 2) 文生组图: 不提供 image 且 S="auto" → 组图,数量由 max_images 控制。
268
+ 3) 单图生单图: image=string 且 (S 未设置或 S="disabled") → 1 张图。
269
+ 4) 单图生组图: image=string 且 S="auto" → 组图,数量 ≤14。
270
+ 5) 多图生单图: image=array (2–10) 且 (S 未设置或 S="disabled") → 1 张图。
271
+ 6) 多图生组图: image=array (2–10) 且 S="auto" → 组图,需满足总数 ≤15。
272
+ 返回结果
273
+ --------
274
+ Dict with generation summary.
275
+ Example:
276
+ {
277
+ "status": "success",
278
+ "success_list": [
279
+ {"image_name": "url"}
280
+ ],
281
+ "error_list": ["image_name"]
282
+ }
283
+ Notes:
284
+ - 组图任务必须 sequential_image_generation="auto"。
285
+ - 如果想要指定生成组图的数量,请在prompt里添加数量说明,例如:"生成3张图片"。
286
+ - size 推荐使用 2048x2048 或表格里的标准比例,确保生成质量。
287
+ """
288
+ model = getenv("MODEL_IMAGE_NAME", DEFAULT_IMAGE_GENERATE_MODEL_NAME)
289
+
290
+ if model.startswith("doubao-seedream-3-0"):
291
+ logger.error(
292
+ f"Image generation by Doubao Seedream 3.0 ({model}) is depracated. Please use Doubao Seedream 4.0 (e.g., doubao-seedream-4-0-250828) instead."
293
+ )
294
+ return {
295
+ "status": "failed",
296
+ "success_list": [],
297
+ "error_list": [
298
+ "Image generation by Doubao Seedream 3.0 ({model}) is depracated. Please use Doubao Seedream 4.0 (e.g., doubao-seedream-4-0-250828) instead."
299
+ ],
300
+ }
301
+
302
+ logger.debug(f"Using model to generate image: {model}")
303
+
304
+ success_list: list[dict] = []
305
+ error_list: list[str] = []
306
+
307
+ logger.debug(f"image_generate tasks: {tasks}")
308
+
309
+ with tracer.start_as_current_span("image_generate"):
310
+ base_ctx = contextvars.copy_context()
311
+
312
+ def make_task(idx, item):
313
+ ctx = base_ctx.copy()
314
+ return lambda: ctx.run(handle_single_task_sync, idx, item, tool_context)
315
+
316
+ loop = asyncio.get_event_loop()
317
+ futures = [
318
+ loop.run_in_executor(executor, make_task(idx, item))
319
+ for idx, item in enumerate(tasks)
320
+ ]
321
+
322
+ results = await asyncio.gather(*futures, return_exceptions=True)
323
+
324
+ for res in results:
325
+ if isinstance(res, Exception):
326
+ logger.error(f"Task raised exception: {res}")
327
+ error_list.append("unknown_task_exception")
328
+ continue
329
+ s, e = res
330
+ success_list.extend(s)
331
+ error_list.extend(e)
332
+
333
+ if not success_list:
334
+ logger.debug(
335
+ f"image_generate success_list: {success_list}\nerror_list: {error_list}"
336
+ )
337
+ return {
338
+ "status": "error",
339
+ "success_list": success_list,
340
+ "error_list": error_list,
341
+ }
342
+ app_name = tool_context._invocation_context.app_name
343
+ user_id = tool_context._invocation_context.user_id
344
+ session_id = tool_context._invocation_context.session.id
345
+ artifact_service = tool_context._invocation_context.artifact_service
346
+
347
+ if artifact_service:
348
+ for image in success_list:
349
+ for _, image_tos_url in image.items():
350
+ filename = f"artifact_{formatted_timestamp()}"
351
+ await artifact_service.save_artifact(
352
+ app_name=app_name,
353
+ user_id=user_id,
354
+ session_id=session_id,
355
+ filename=filename,
356
+ artifact=Part(
357
+ inline_data=Blob(
358
+ display_name=filename,
359
+ data=read_file_to_bytes(image_tos_url),
360
+ mime_type=mimetypes.guess_type(image_tos_url)[0],
361
+ )
362
+ ),
363
+ )
364
+
365
+ logger.debug(
366
+ f"image_generate success_list: {success_list}\nerror_list: {error_list}"
367
+ )
368
+ return {"status": "success", "success_list": success_list, "error_list": error_list}
369
+
370
+
371
+ def add_span_attributes(
372
+ span: Span,
373
+ tool_context: ToolContext,
374
+ input_part: dict = None,
375
+ output_part: dict = None,
376
+ input_tokens: int = None,
377
+ output_tokens: int = None,
378
+ total_tokens: int = None,
379
+ request_model: str = None,
380
+ response_model: str = None,
381
+ ):
382
+ try:
383
+ # common attributes
384
+ app_name = tool_context._invocation_context.app_name
385
+ user_id = tool_context._invocation_context.user_id
386
+ agent_name = tool_context.agent_name
387
+ session_id = tool_context._invocation_context.session.id
388
+ span.set_attribute("gen_ai.agent.name", agent_name)
389
+ span.set_attribute("openinference.instrumentation.veadk", VERSION)
390
+ span.set_attribute("gen_ai.app.name", app_name)
391
+ span.set_attribute("gen_ai.user.id", user_id)
392
+ span.set_attribute("gen_ai.session.id", session_id)
393
+ span.set_attribute("agent_name", agent_name)
394
+ span.set_attribute("agent.name", agent_name)
395
+ span.set_attribute("app_name", app_name)
396
+ span.set_attribute("app.name", app_name)
397
+ span.set_attribute("user.id", user_id)
398
+ span.set_attribute("session.id", session_id)
399
+ span.set_attribute("cozeloop.report.source", "veadk")
400
+
401
+ # llm attributes
402
+ span.set_attribute("gen_ai.system", "openai")
403
+ span.set_attribute("gen_ai.operation.name", "chat")
404
+ if request_model:
405
+ span.set_attribute("gen_ai.request.model", request_model)
406
+ if response_model:
407
+ span.set_attribute("gen_ai.response.model", response_model)
408
+ if total_tokens:
409
+ span.set_attribute("gen_ai.usage.total_tokens", total_tokens)
410
+ if output_tokens:
411
+ span.set_attribute("gen_ai.usage.output_tokens", output_tokens)
412
+ if input_tokens:
413
+ span.set_attribute("gen_ai.usage.input_tokens", input_tokens)
414
+ if input_part:
415
+ span.add_event("gen_ai.user.message", input_part)
416
+ if output_part:
417
+ span.add_event("gen_ai.choice", output_part)
418
+
419
+ except Exception:
420
+ traceback.print_exc()
421
+
422
+
423
+ def _upload_image_to_tos(image_bytes: bytes, object_key: str) -> None:
424
+ try:
425
+ import os
426
+ from datetime import datetime
427
+
428
+ from veadk.integrations.ve_tos.ve_tos import VeTOS
429
+
430
+ timestamp: str = datetime.now().strftime("%Y%m%d%H%M%S%f")[:-3]
431
+ object_key = f"{timestamp}-{object_key}"
432
+ bucket_name = os.getenv("DATABASE_TOS_BUCKET")
433
+ ve_tos = VeTOS()
434
+
435
+ tos_url = ve_tos.build_tos_signed_url(
436
+ object_key=object_key, bucket_name=bucket_name
437
+ )
438
+
439
+ ve_tos.upload_bytes(
440
+ data=image_bytes, object_key=object_key, bucket_name=bucket_name
441
+ )
442
+
443
+ return tos_url
444
+ except Exception as e:
445
+ logger.error(f"Upload to TOS failed: {e}")
446
+ return None
@@ -0,0 +1,67 @@
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 subprocess
16
+
17
+ from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset, StdioServerParameters
18
+
19
+ from veadk.config import getenv
20
+ from veadk.utils.logger import get_logger
21
+
22
+ logger = get_logger(__name__)
23
+
24
+
25
+ def check_env():
26
+ try:
27
+ result = subprocess.run(
28
+ ["npx", "-v"], capture_output=True, text=True, check=True
29
+ )
30
+ version = result.stdout.strip()
31
+ logger.info(f"Check `npx` command done, version: {version}")
32
+ except Exception as e:
33
+ raise Exception(
34
+ "Check `npx` command failed. Please install `npx` command manually."
35
+ ) from e
36
+
37
+ try:
38
+ result = subprocess.run(
39
+ ["lark-mcp", "-V"], capture_output=True, text=True, check=True
40
+ )
41
+ version = result.stdout.strip()
42
+ logger.info(f"Check `lark-mcp` command done, version: {version}")
43
+ except Exception as e:
44
+ raise Exception(
45
+ "Check `lark-mcp` command failed. Please install it manually."
46
+ ) from e
47
+
48
+
49
+ check_env()
50
+
51
+ lark_tools = MCPToolset(
52
+ connection_params=StdioServerParameters(
53
+ command="npx",
54
+ args=[
55
+ "-y",
56
+ "@larksuiteoapi/lark-mcp",
57
+ "mcp",
58
+ "-a",
59
+ getenv("TOOL_LARK_ENDPOINT"),
60
+ "-s",
61
+ getenv("TOOL_LARK_API_KEY"),
62
+ "-u",
63
+ getenv("TOOL_LARK_TOKEN"),
64
+ ],
65
+ errlog=None,
66
+ ),
67
+ )
@@ -0,0 +1,24 @@
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 google.adk.tools.mcp_tool.mcp_toolset import MCPToolset
16
+
17
+ from veadk.config import getenv
18
+ from veadk.utils.mcp_utils import get_mcp_params
19
+
20
+ url = getenv("TOOL_LAS_URL")
21
+ dataset_id = getenv("TOOL_LAS_DATASET_ID")
22
+
23
+
24
+ las = MCPToolset(connection_params=get_mcp_params(url=url))
@@ -0,0 +1,66 @@
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 volcenginesdkarkruntime._models import BaseModel
16
+ from volcenginesdkarkruntime import AsyncArk
17
+ from veadk.utils.logger import get_logger
18
+ from httpx import Timeout
19
+ from veadk.config import getenv, settings
20
+
21
+ logger = get_logger(__name__)
22
+
23
+
24
+ async def link_reader(url_list: list[str]) -> dict:
25
+ """
26
+ Use this tool when you need to fetch content from web pages, PDFs, or Douyin videos.
27
+ It retrieves the title and main content from the provided URLs.
28
+
29
+ Examples: {"url_list": ["abc.com", "xyz.com"]}
30
+ Args:
31
+ url_list (list[str]): A list of URLs to parse (maximum 3).
32
+ Returns:
33
+ list[dict]: A list of dictionaries, each containing the title and content of the corresponding URL.
34
+ """
35
+ logger.debug(f"link_reader url_list: {url_list}")
36
+ try:
37
+ client = AsyncArk(
38
+ api_key=getenv("MODEL_AGENT_API_KEY", settings.model.api_key),
39
+ timeout=Timeout(connect=1.0, timeout=60.0),
40
+ )
41
+ except Exception as e:
42
+ logger.error(f"link_reader client init failed:{e}")
43
+ return []
44
+
45
+ body = {
46
+ "action_name": "LinkReader",
47
+ "tool_name": "LinkReader",
48
+ "parameters": {"url_list": url_list},
49
+ }
50
+
51
+ response = None
52
+ try:
53
+ response = await client.post(
54
+ path="/tools/execute", body=body, cast_to=BaseModel
55
+ )
56
+ response = response.model_dump()
57
+ logger.debug(f"link_reader response: {response}")
58
+
59
+ if response["status_code"] != 200:
60
+ logger.error(f"link_reader failed: {response}")
61
+ return []
62
+ else:
63
+ return response["data"]["ark_web_data_list"]
64
+ except Exception as e:
65
+ logger.error(f"link_reader failed: {e}, response: {response}")
66
+ return []