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,411 @@
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 typing import Any
16
+
17
+ from google.adk.agents.invocation_context import InvocationContext
18
+ from google.adk.events import Event
19
+ from google.adk.models.llm_request import LlmRequest
20
+ from google.adk.models.llm_response import LlmResponse
21
+ from google.adk.tools import BaseTool
22
+ from opentelemetry import trace
23
+ from opentelemetry.context import get_value
24
+ from opentelemetry.sdk.trace import Span, _Span
25
+
26
+ from veadk.tracing.telemetry.attributes.attributes import ATTRIBUTES
27
+ from veadk.tracing.telemetry.attributes.extractors.types import (
28
+ ExtractorResponse,
29
+ LLMAttributesParams,
30
+ ToolAttributesParams,
31
+ )
32
+ from veadk.utils.logger import get_logger
33
+ from veadk.utils.misc import safe_json_serialize
34
+
35
+ logger = get_logger(__name__)
36
+
37
+ meter_uploader = None
38
+
39
+
40
+ def _upload_call_llm_metrics(
41
+ invocation_context: InvocationContext,
42
+ event_id: str,
43
+ llm_request: LlmRequest,
44
+ llm_response: LlmResponse,
45
+ ) -> None:
46
+ """Upload LLM call metrics to configured meter uploaders.
47
+
48
+ This function extracts meter uploaders from agent tracers and records
49
+ LLM call metrics including token usage, latency, and request/response details.
50
+
51
+ Args:
52
+ invocation_context: Context containing agent, session, and user information
53
+ event_id: Unique identifier for this LLM call event
54
+ llm_request: The request sent to the language model
55
+ llm_response: The response received from the language model
56
+ """
57
+ from veadk.agent import Agent
58
+
59
+ if isinstance(invocation_context.agent, Agent):
60
+ tracers = invocation_context.agent.tracers
61
+ for tracer in tracers:
62
+ for exporter in getattr(tracer, "exporters", []):
63
+ if getattr(exporter, "meter_uploader", None):
64
+ global meter_uploader
65
+ meter_uploader = exporter.meter_uploader
66
+ exporter.meter_uploader.record_call_llm(
67
+ invocation_context, event_id, llm_request, llm_response
68
+ )
69
+
70
+
71
+ def _upload_tool_call_metrics(
72
+ tool: BaseTool,
73
+ args: dict[str, Any],
74
+ function_response_event: Event,
75
+ ):
76
+ """Upload tool call metrics to the global meter uploader.
77
+
78
+ Records tool execution metrics including function name, arguments,
79
+ execution time, and response details for observability and debugging.
80
+
81
+ Args:
82
+ tool: The tool instance that was executed
83
+ args: Arguments passed to the tool function
84
+ function_response_event: Event containing the tool's response data
85
+
86
+ Note:
87
+ - Requires global meter_uploader to be initialized
88
+ """
89
+ global meter_uploader
90
+ if meter_uploader:
91
+ meter_uploader.record_tool_call(tool, args, function_response_event)
92
+ else:
93
+ logger.warning(
94
+ "Meter uploader is not initialized yet. Skip recording tool call metrics."
95
+ )
96
+
97
+
98
+ def _set_agent_input_attribute(
99
+ span: Span, invocation_context: InvocationContext
100
+ ) -> None:
101
+ """Set agent input attributes and events on the given span.
102
+
103
+ This function captures the original user input and adds it as span attributes
104
+ and events in OpenTelemetry format. It handles both text and image content
105
+ while avoiding duplicate entries for the same input.
106
+
107
+ Args:
108
+ span: The OpenTelemetry span to annotate with input data
109
+ invocation_context: Context containing user input and session information
110
+
111
+ Note:
112
+ - Only sets input once per span to avoid duplication
113
+ - Supports multimodal content (text and images)
114
+ - Follows gen_ai attribute conventions
115
+ """
116
+ event_names = [event.name for event in span.events]
117
+ if "gen_ai.user.message" in event_names:
118
+ return
119
+
120
+ # input = {
121
+ # "agent_name": invocation_context.agent.name,
122
+ # "app_name": invocation_context.session.app_name,
123
+ # "user_id": invocation_context.user_id,
124
+ # "session_id": invocation_context.session.id,
125
+ # "input": invocation_context.user_content.model_dump(exclude_none=True)
126
+ # if invocation_context.user_content
127
+ # else None,
128
+ # }
129
+
130
+ user_content = invocation_context.user_content
131
+ if user_content and user_content.parts:
132
+ # set gen_ai.input attribute required by APMPlus
133
+ span.set_attribute(
134
+ "gen_ai.input",
135
+ safe_json_serialize(user_content.model_dump(exclude_none=True)),
136
+ )
137
+ span.add_event(
138
+ "gen_ai.user.message",
139
+ {
140
+ "agent_name": invocation_context.agent.name,
141
+ "app_name": invocation_context.session.app_name,
142
+ "user_id": invocation_context.user_id,
143
+ "session_id": invocation_context.session.id,
144
+ },
145
+ )
146
+ for idx, part in enumerate(user_content.parts):
147
+ if part.text:
148
+ span.add_event(
149
+ "gen_ai.user.message",
150
+ {f"parts.{idx}.type": "text", f"parts.{idx}.content": part.text},
151
+ )
152
+ if part.inline_data:
153
+ span.add_event(
154
+ "gen_ai.user.message",
155
+ {
156
+ f"parts.{idx}.type": "image_url",
157
+ f"parts.{idx}.image_url.name": (
158
+ part.inline_data.display_name.split("/")[-1]
159
+ if part.inline_data.display_name
160
+ else "<unknown_image_name>"
161
+ ),
162
+ f"parts.{idx}.image_url.url": (
163
+ part.inline_data.display_name
164
+ if part.inline_data.display_name
165
+ else "<unknown_image_url>"
166
+ ),
167
+ },
168
+ )
169
+
170
+
171
+ def _set_agent_output_attribute(span: Span, llm_response: LlmResponse) -> None:
172
+ """Set agent output attributes and events on the given span.
173
+
174
+ Captures the LLM response content and adds it as span attributes and events
175
+ in OpenTelemetry format for tracing and observability purposes.
176
+
177
+ Args:
178
+ span: The OpenTelemetry span to annotate with output data
179
+ llm_response: The language model response containing generated content
180
+
181
+ Note:
182
+ - Follows gen_ai attribute conventions
183
+ - Handles multipart responses with proper indexing
184
+ """
185
+ content = llm_response.content
186
+ if content and content.parts:
187
+ # set gen_ai.output attribute required by APMPlus
188
+ span.set_attribute(
189
+ "gen_ai.output", safe_json_serialize(content.model_dump(exclude_none=True))
190
+ )
191
+
192
+ for idx, part in enumerate(content.parts):
193
+ if part.text:
194
+ span.add_event(
195
+ "gen_ai.choice",
196
+ {
197
+ f"message.parts.{idx}.type": "text",
198
+ f"message.parts.{idx}.text": part.text,
199
+ },
200
+ )
201
+
202
+
203
+ def set_common_attributes_on_model_span(
204
+ invocation_context: InvocationContext,
205
+ llm_response: LlmResponse,
206
+ current_span: _Span,
207
+ **kwargs,
208
+ ) -> None:
209
+ """Set common attributes on model-related spans including invocation and agent run spans.
210
+
211
+ This function applies standardized attributes across multiple span types to ensure
212
+ consistent telemetry data. It handles token usage accumulation, input/output
213
+ annotation, and hierarchical span attribute propagation.
214
+
215
+ Key Operations:
216
+ - Sets agent input/output on invocation and agent run spans
217
+ - Accumulates token usage across multiple LLM calls
218
+ - Applies common attributes from the ATTRIBUTES mapping
219
+ - Handles span hierarchy and context propagation
220
+
221
+ Args:
222
+ invocation_context: Context containing agent, session, and user information
223
+ llm_response: The language model response with usage metadata
224
+ current_span: The current OpenTelemetry span being processed
225
+ **kwargs: Additional keyword arguments for attribute extraction
226
+ """
227
+ common_attributes = ATTRIBUTES.get("common", {})
228
+ try:
229
+ invocation_span: Span = get_value("invocation_span_instance") # type: ignore
230
+ agent_run_span: Span = get_value("agent_run_span_instance") # type: ignore
231
+
232
+ if invocation_span and invocation_span.name.startswith("invocation"):
233
+ _set_agent_input_attribute(invocation_span, invocation_context)
234
+ _set_agent_output_attribute(invocation_span, llm_response)
235
+ for attr_name, attr_extractor in common_attributes.items():
236
+ value = attr_extractor(**kwargs)
237
+ invocation_span.set_attribute(attr_name, value)
238
+
239
+ # Calculate the token usage for the whole invocation span
240
+ current_step_token_usage = (
241
+ llm_response.usage_metadata.total_token_count
242
+ if llm_response.usage_metadata
243
+ and llm_response.usage_metadata.total_token_count
244
+ else 0
245
+ )
246
+ prev_total_token_usage = (
247
+ invocation_span.attributes["gen_ai.usage.total_tokens"]
248
+ if invocation_span.attributes
249
+ else 0
250
+ )
251
+ accumulated_total_token_usage = (
252
+ current_step_token_usage + int(prev_total_token_usage) # type: ignore
253
+ ) # we can ignore this warning, cause we manually set the attribute to int before
254
+ invocation_span.set_attribute(
255
+ # record input/output token usage?
256
+ "gen_ai.usage.total_tokens",
257
+ accumulated_total_token_usage,
258
+ )
259
+
260
+ if agent_run_span and (
261
+ agent_run_span.name.startswith("agent_run")
262
+ or agent_run_span.name.startswith("invoke_agent")
263
+ ):
264
+ _set_agent_input_attribute(agent_run_span, invocation_context)
265
+ _set_agent_output_attribute(agent_run_span, llm_response)
266
+ for attr_name, attr_extractor in common_attributes.items():
267
+ value = attr_extractor(**kwargs)
268
+ agent_run_span.set_attribute(attr_name, value)
269
+
270
+ for attr_name, attr_extractor in common_attributes.items():
271
+ value = attr_extractor(**kwargs)
272
+ current_span.set_attribute(attr_name, value)
273
+ except Exception as e:
274
+ logger.error(f"Failed to set common attributes for spans: {e}")
275
+
276
+
277
+ def set_common_attributes_on_tool_span(current_span: _Span) -> None:
278
+ """Set common attributes on tool execution spans.
279
+
280
+ Propagates common attributes from the parent invocation span to tool spans
281
+ to maintain consistent context across the execution trace hierarchy.
282
+
283
+ Args:
284
+ current_span: The tool execution span to annotate with common attributes
285
+ """
286
+ common_attributes = ATTRIBUTES.get("common", {})
287
+
288
+ invocation_span: Span = get_value("invocation_span_instance") # type: ignore
289
+
290
+ for attr_name in common_attributes.keys():
291
+ if (
292
+ invocation_span
293
+ and invocation_span.name.startswith("invocation")
294
+ and invocation_span.attributes
295
+ and attr_name in invocation_span.attributes
296
+ ):
297
+ current_span.set_attribute(attr_name, invocation_span.attributes[attr_name])
298
+
299
+
300
+ def trace_tool_call(
301
+ tool: BaseTool,
302
+ args: dict[str, Any],
303
+ function_response_event: Event,
304
+ ) -> None:
305
+ """Trace a tool function call with comprehensive telemetry data.
306
+
307
+ This function is the main entry point for tool call tracing, capturing
308
+ execution details, arguments, responses, and performance metrics for
309
+ debugging and observability purposes.
310
+
311
+ Tracing Data Captured:
312
+ - Tool name and function signature
313
+ - Input arguments and parameter values
314
+ - Execution timing and performance metrics
315
+ - Response data and return values
316
+ - Error information if execution fails
317
+ - Common context attributes (user, session, agent)
318
+
319
+ Args:
320
+ tool: The tool instance being executed
321
+ args: Dictionary of arguments passed to the tool function
322
+ function_response_event: Event containing the tool's execution response
323
+ """
324
+ span = trace.get_current_span()
325
+
326
+ set_common_attributes_on_tool_span(current_span=span) # type: ignore
327
+
328
+ tool_attributes_mapping = ATTRIBUTES.get("tool", {})
329
+ params = ToolAttributesParams(tool, args, function_response_event)
330
+
331
+ for attr_name, attr_extractor in tool_attributes_mapping.items():
332
+ response: ExtractorResponse = attr_extractor(params)
333
+ ExtractorResponse.update_span(span, attr_name, response)
334
+
335
+ _upload_tool_call_metrics(tool, args, function_response_event)
336
+
337
+
338
+ def trace_call_llm(
339
+ invocation_context: InvocationContext,
340
+ event_id: str,
341
+ llm_request: LlmRequest,
342
+ llm_response: LlmResponse,
343
+ ) -> None:
344
+ """Trace a language model call with comprehensive telemetry data.
345
+
346
+ This function is the main entry point for LLM call tracing, capturing
347
+ request/response details, token usage, timing, and context information
348
+ for cost tracking, performance analysis, and debugging.
349
+
350
+ Tracing Data Captured:
351
+ - Model name and provider information
352
+ - Request parameters and prompt content
353
+ - Response content and metadata
354
+ - Token usage (input, output, total)
355
+ - Execution timing and latency
356
+ - Context information (user, session, agent)
357
+ - Error information if the call fails
358
+
359
+ Args:
360
+ invocation_context: Context containing agent, session, and user information
361
+ event_id: Unique identifier for this LLM call event
362
+ llm_request: The request object sent to the language model
363
+ llm_response: The response object received from the language model
364
+ """
365
+ span: Span = trace.get_current_span() # type: ignore
366
+
367
+ from veadk.agent import Agent
368
+
369
+ set_common_attributes_on_model_span(
370
+ invocation_context=invocation_context,
371
+ llm_response=llm_response,
372
+ current_span=span, # type: ignore
373
+ agent_name=invocation_context.agent.name,
374
+ user_id=invocation_context.user_id,
375
+ app_name=invocation_context.app_name,
376
+ session_id=invocation_context.session.id,
377
+ model_provider=invocation_context.agent.model_provider
378
+ if isinstance(invocation_context.agent, Agent)
379
+ else "",
380
+ model_name=invocation_context.agent.model_name
381
+ if isinstance(invocation_context.agent, Agent)
382
+ else "",
383
+ call_type=(
384
+ span.context.trace_state.get("call_type", "")
385
+ if (
386
+ hasattr(span, "context")
387
+ and span.context
388
+ and hasattr(span.context, "trace_state")
389
+ and hasattr(span.context.trace_state, "get")
390
+ )
391
+ else ""
392
+ ),
393
+ )
394
+
395
+ llm_attributes_mapping = ATTRIBUTES.get("llm", {})
396
+ params = LLMAttributesParams(
397
+ invocation_context=invocation_context,
398
+ event_id=event_id,
399
+ llm_request=llm_request,
400
+ llm_response=llm_response,
401
+ )
402
+
403
+ for attr_name, attr_extractor in llm_attributes_mapping.items():
404
+ response: ExtractorResponse = attr_extractor(params)
405
+ ExtractorResponse.update_span(span, attr_name, response)
406
+
407
+ _upload_call_llm_metrics(invocation_context, event_id, llm_request, llm_response)
408
+
409
+
410
+ # Do not modify this function
411
+ def trace_send_data(): ...
veadk/types.py ADDED
@@ -0,0 +1,47 @@
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 pydantic import BaseModel, Field
16
+
17
+ from veadk.agent import Agent
18
+ from veadk.agents.loop_agent import LoopAgent
19
+ from veadk.agents.parallel_agent import ParallelAgent
20
+ from veadk.agents.sequential_agent import SequentialAgent
21
+ from veadk.memory.short_term_memory import ShortTermMemory
22
+
23
+
24
+ class MediaMessage(BaseModel):
25
+ text: str
26
+ """Text-based prompt"""
27
+
28
+ media: str
29
+ """Media file (e.g., `.pdf`, `.docx`, `.png`, `.jpg`, `.jpeg`, `.mp4`, `.mp3`, `.wav`, `.txt`) path"""
30
+
31
+
32
+ class AgentRunConfig(BaseModel):
33
+ """Configuration for running an agent on VeFaaS platform."""
34
+
35
+ model_config = {"arbitrary_types_allowed": True}
36
+
37
+ app_name: str = Field(
38
+ default="veadk_vefaas_app", description="The name of the application"
39
+ )
40
+
41
+ agent: Agent | SequentialAgent | ParallelAgent | LoopAgent = Field(
42
+ ..., description="The root agent instance"
43
+ )
44
+
45
+ short_term_memory: ShortTermMemory = Field(
46
+ default_factory=ShortTermMemory, description="The short-term memory instance"
47
+ )
@@ -0,0 +1,13 @@
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.
@@ -0,0 +1,95 @@
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 dataclasses import dataclass
16
+ from typing import Optional
17
+
18
+ try:
19
+ import pyaudio
20
+
21
+ PYAUDIO_AVAILABLE = True
22
+ except ImportError:
23
+ pyaudio = None
24
+ PYAUDIO_AVAILABLE = False
25
+
26
+ input_audio_config = {
27
+ "chunk": 3200,
28
+ "format": "pcm",
29
+ "channels": 1,
30
+ "sample_rate": 16000,
31
+ "bit_size": pyaudio.paInt16,
32
+ }
33
+
34
+ output_audio_config = {
35
+ "chunk": 3200,
36
+ "format": "pcm",
37
+ "channels": 1,
38
+ "sample_rate": 24000,
39
+ "bit_size": pyaudio.paInt16,
40
+ }
41
+
42
+
43
+ @dataclass
44
+ class AudioConfig:
45
+ """audio config"""
46
+
47
+ format: str
48
+ bit_size: int
49
+ channels: int
50
+ sample_rate: int
51
+ chunk: int
52
+
53
+
54
+ class AudioDeviceManager:
55
+ """audio device manager, handle audio input/output"""
56
+
57
+ def __init__(self, input_config: AudioConfig, output_config: AudioConfig):
58
+ if not PYAUDIO_AVAILABLE:
59
+ raise RuntimeError(
60
+ "pyaudio is not installed. Please install it via: "
61
+ "pip install veadk-python[speech]"
62
+ )
63
+ self.input_config = input_config
64
+ self.output_config = output_config
65
+ self.pyaudio = pyaudio.PyAudio()
66
+ self.input_stream: Optional[pyaudio.Stream] = None
67
+ self.output_stream: Optional[pyaudio.Stream] = None
68
+
69
+ def open_input_stream(self) -> pyaudio.Stream:
70
+ # p = pyaudio.PyAudio()
71
+ self.input_stream = self.pyaudio.open(
72
+ format=self.input_config.bit_size,
73
+ channels=self.input_config.channels,
74
+ rate=self.input_config.sample_rate,
75
+ input=True,
76
+ frames_per_buffer=self.input_config.chunk,
77
+ )
78
+ return self.input_stream
79
+
80
+ def open_output_stream(self) -> pyaudio.Stream:
81
+ self.output_stream = self.pyaudio.open(
82
+ format=self.output_config.bit_size,
83
+ channels=self.output_config.channels,
84
+ rate=self.output_config.sample_rate,
85
+ output=True,
86
+ frames_per_buffer=self.output_config.chunk,
87
+ )
88
+ return self.output_stream
89
+
90
+ def cleanup(self) -> None:
91
+ for stream in [self.input_stream, self.output_stream]:
92
+ if stream:
93
+ stream.stop_stream()
94
+ stream.close()
95
+ self.pyaudio.terminate()