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,320 @@
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 __future__ import annotations
16
+
17
+ import json
18
+ import time
19
+ from typing import Any
20
+
21
+ from opentelemetry import trace as trace_api
22
+ from opentelemetry.sdk import trace as trace_sdk
23
+ from opentelemetry.sdk.resources import Resource
24
+ from opentelemetry.sdk.trace import SpanLimits, TracerProvider
25
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor, SimpleSpanProcessor
26
+ from pydantic import BaseModel, ConfigDict, Field, field_validator
27
+ from typing_extensions import override
28
+
29
+ from veadk.tracing.base_tracer import BaseTracer
30
+ from veadk.tracing.telemetry.exporters.apmplus_exporter import APMPlusExporter
31
+ from veadk.tracing.telemetry.exporters.base_exporter import BaseExporter
32
+ from veadk.tracing.telemetry.exporters.inmemory_exporter import InMemoryExporter
33
+ from veadk.utils.logger import get_logger
34
+ from veadk.utils.misc import get_agent_dir
35
+ from veadk.utils.patches import patch_google_adk_telemetry
36
+
37
+ logger = get_logger(__name__)
38
+
39
+
40
+ def _update_resource_attributions(
41
+ provider: TracerProvider, resource_attributes: dict
42
+ ) -> None:
43
+ """Update the resource attributes of a TracerProvider instance.
44
+
45
+ This function merges new resource attributes with the existing ones in the
46
+ provider, allowing dynamic configuration of telemetry metadata.
47
+
48
+ Args:
49
+ provider: The TracerProvider instance to update
50
+ resource_attributes: Dictionary of attributes to merge with existing resources
51
+ """
52
+ provider._resource = provider._resource.merge(Resource.create(resource_attributes))
53
+
54
+
55
+ class OpentelemetryTracer(BaseModel, BaseTracer):
56
+ """OpenTelemetry-based tracer implementation for comprehensive agent observability.
57
+
58
+ This class provides a complete tracing solution using OpenTelemetry standards,
59
+ supporting multiple exporters for different observability platforms. It captures
60
+ detailed execution traces including LLM calls, tool invocations, and agent workflow
61
+ patterns for debugging and performance analysis.
62
+
63
+ Key Features:
64
+ - Multi-exporter support (APMPlus, in-memory, custom exporters)
65
+ - Thread-safe span processing with configurable limits
66
+ - Local trace dumping with JSON serialization
67
+ - Resource attribute management for metadata enrichment
68
+ - Force flush capabilities for immediate data export
69
+
70
+ Architecture:
71
+ The tracer initializes a global TracerProvider with custom span processors for
72
+ each configured exporter. It maintains an internal in-memory exporter for local
73
+ operations while supporting external observability platforms simultaneously.
74
+
75
+ Attributes:
76
+ name: Identifier for this tracer instance, used in file naming and logging
77
+ exporters: List of exporter instances for sending trace data to different backends
78
+
79
+ Examples:
80
+ Basic usage with APMPlus exporter:
81
+ ```python
82
+ exporters = [
83
+ CozeloopExporter(),
84
+ APMPlusExporter(),
85
+ TLSExporter(),
86
+ ]
87
+ tracer = OpentelemetryTracer(exporters=exporters)
88
+ ```
89
+
90
+ Note:
91
+ - InMemoryExporter cannot be explicitly added to exporters list
92
+ - Span limits are set to 4096 attributes for comprehensive data capture
93
+ """
94
+
95
+ model_config = ConfigDict(arbitrary_types_allowed=True)
96
+
97
+ name: str = Field(
98
+ default="veadk_opentelemetry_tracer", description="The identifier of tracer."
99
+ )
100
+
101
+ exporters: list[BaseExporter] = Field(
102
+ default_factory=list,
103
+ description="The exporters to export spans.",
104
+ )
105
+
106
+ # Forbid InMemoryExporter in exporters list
107
+ # cause we need to set custom in-memory span processor by VeADK
108
+ @field_validator("exporters")
109
+ @classmethod
110
+ def forbid_inmemory_exporter(cls, v: list[BaseExporter]) -> list[BaseExporter]:
111
+ """Validate that InMemoryExporter is not explicitly added to exporters list.
112
+
113
+ InMemoryExporter is automatically managed internally and should not be
114
+ included in the user-provided exporters list to avoid conflicts.
115
+
116
+ Args:
117
+ v: List of exporter instances to validate
118
+
119
+ Returns:
120
+ list[BaseExporter]: The validated list of exporters
121
+
122
+ Raises:
123
+ ValueError: If InMemoryExporter is found in the exporters list
124
+ """
125
+ for e in v:
126
+ if isinstance(e, InMemoryExporter):
127
+ raise ValueError("InMemoryExporter is not allowed in exporters list")
128
+ return v
129
+
130
+ def model_post_init(self, context: Any) -> None:
131
+ """Initialize the tracer after model construction.
132
+
133
+ This method performs post-initialization setup including Google ADK
134
+ telemetry patching and global tracer provider configuration.
135
+ """
136
+ # Replace Google ADK tracing funcs
137
+ # `trace_call_llm` and `trace_tool_call`
138
+ patch_google_adk_telemetry()
139
+
140
+ # We save internal processors for tracing data dump
141
+ self._processors = []
142
+
143
+ # Initialize global tracer provider to avoid VeFaaS global tracer
144
+ # provider conflicts
145
+ self._init_global_tracer_provider()
146
+
147
+ def _init_global_tracer_provider(self) -> None:
148
+ """Initialize the global OpenTelemetry tracer provider with configured exporters.
149
+
150
+ This method sets up the global tracer provider, configures span processors
151
+ for each exporter, and ensures proper resource attribution. It also handles
152
+ duplicate exporter detection and in-memory span collection setup.
153
+ """
154
+ # set provider anyway, then get global provider
155
+ trace_api.set_tracer_provider(
156
+ trace_sdk.TracerProvider(
157
+ span_limits=SpanLimits(
158
+ max_attributes=4096,
159
+ )
160
+ )
161
+ )
162
+ global_tracer_provider: TracerProvider = trace_api.get_tracer_provider() # type: ignore
163
+
164
+ span_processors = global_tracer_provider._active_span_processor._span_processors
165
+ have_apmplus_exporter = any(
166
+ isinstance(p, (BatchSpanProcessor, SimpleSpanProcessor))
167
+ and hasattr(p.span_exporter, "_endpoint")
168
+ and "apmplus" in p.span_exporter._endpoint
169
+ for p in span_processors
170
+ )
171
+
172
+ if have_apmplus_exporter:
173
+ self.exporters = [
174
+ e for e in self.exporters if not isinstance(e, APMPlusExporter)
175
+ ]
176
+
177
+ for exporter in self.exporters:
178
+ processor = exporter.processor
179
+ resource_attributes = exporter.resource_attributes
180
+
181
+ if resource_attributes:
182
+ _update_resource_attributions(
183
+ global_tracer_provider, resource_attributes
184
+ )
185
+
186
+ if processor:
187
+ global_tracer_provider.add_span_processor(processor)
188
+ self._processors.append(processor)
189
+
190
+ logger.debug(
191
+ f"Add span processor for exporter `{exporter.__class__.__name__}` to OpentelemetryTracer."
192
+ )
193
+ else:
194
+ logger.error(
195
+ f"Add span processor for exporter `{exporter.__class__.__name__}` to OpentelemetryTracer failed."
196
+ )
197
+
198
+ self._inmemory_exporter = InMemoryExporter()
199
+ if self._inmemory_exporter.processor:
200
+ # make sure the in memory exporter processor is added at index 0
201
+ # because we use this to record all spans
202
+ global_tracer_provider._active_span_processor._span_processors = (
203
+ self._inmemory_exporter.processor,
204
+ ) + global_tracer_provider._active_span_processor._span_processors
205
+
206
+ self._processors.append(self._inmemory_exporter.processor)
207
+ self.exporters.append(self._inmemory_exporter)
208
+ else:
209
+ logger.warning(
210
+ "InMemoryExporter processor is not initialized, cannot add to OpentelemetryTracer."
211
+ )
212
+
213
+ logger.info(
214
+ f"Init OpentelemetryTracer with {len(self._processors)} exporter(s)."
215
+ )
216
+
217
+ @property
218
+ def trace_file_path(self) -> str:
219
+ """Get the file path of the most recent trace dump.
220
+
221
+ Returns:
222
+ str: Full path to the trace file, or placeholder if not yet dumped
223
+ """
224
+ return self._trace_file_path
225
+
226
+ @property
227
+ def trace_id(self) -> str:
228
+ """Get the current trace ID in hexadecimal format.
229
+
230
+ Returns:
231
+ str: Hexadecimal representation of the current trace ID, or
232
+ placeholder string if trace ID cannot be retrieved
233
+ """
234
+ try:
235
+ trace_id = hex(int(self._inmemory_exporter._exporter.trace_id))[2:] # type: ignore
236
+ return trace_id
237
+ except Exception as e:
238
+ logger.error(f"Failed to get trace_id from InMemoryExporter: {e}")
239
+ return self._trace_id
240
+
241
+ def force_export(self) -> None:
242
+ """Force immediate export of all pending spans across all processors.
243
+
244
+ This method triggers force_flush on all configured span processors,
245
+ ensuring that buffered span data is immediately sent to exporters.
246
+ Includes a small delay between flushes to prevent overwhelming exporters.
247
+ """
248
+ for processor in self._processors:
249
+ time.sleep(0.05)
250
+ processor.force_flush()
251
+
252
+ @override
253
+ def dump(
254
+ self,
255
+ user_id: str = "unknown_user_id",
256
+ session_id: str = "unknown_session_id",
257
+ path: str = get_agent_dir(),
258
+ ) -> str:
259
+ """Dump collected trace data to a local JSON file.
260
+
261
+ This method exports all spans associated with the current session to a
262
+ structured JSON file for offline analysis. The file includes span metadata,
263
+ timing information, attributes, and parent-child relationships.
264
+
265
+ Args:
266
+ user_id: User identifier for trace organization and file naming
267
+ session_id: Session identifier for filtering and organizing spans
268
+ path: Directory path for the output file. Defaults to agents directory
269
+
270
+ Returns:
271
+ str: Full path to the created trace file, or empty string if export fails
272
+
273
+ Note:
274
+ - Forces export of all pending spans before dumping
275
+ - Filters spans by session_id for relevant data only
276
+ - File format is structured JSON with span details and relationships
277
+ - Supports non-ASCII characters for international content
278
+ """
279
+
280
+ def _build_trace_file_path(path: str, user_id: str, session_id: str) -> str:
281
+ return f"{path}/{self.name}_{user_id}_{session_id}_{self.trace_id}.json"
282
+
283
+ if not self._inmemory_exporter:
284
+ logger.warning(
285
+ "InMemoryExporter is not initialized. Please check your tracer exporters."
286
+ )
287
+ return ""
288
+ self.force_export()
289
+
290
+ spans = self._inmemory_exporter._exporter.get_finished_spans( # type: ignore
291
+ session_id=session_id
292
+ )
293
+ data = (
294
+ [
295
+ {
296
+ "name": s.name,
297
+ "span_id": s.context.span_id,
298
+ "trace_id": s.context.trace_id,
299
+ "start_time": s.start_time,
300
+ "end_time": s.end_time,
301
+ "attributes": dict(s.attributes),
302
+ "parent_span_id": s.parent.span_id if s.parent else None,
303
+ }
304
+ for s in spans
305
+ ]
306
+ if spans
307
+ else []
308
+ )
309
+
310
+ self._trace_file_path = _build_trace_file_path(path, user_id, session_id)
311
+ with open(self._trace_file_path, "w") as f:
312
+ json.dump(
313
+ data, f, indent=4, ensure_ascii=False
314
+ ) # ensure_ascii=False to support Chinese characters
315
+
316
+ logger.info(
317
+ f"OpenTelemetryTracer dumps {len(spans)} spans to {self._trace_file_path}. Trace id: {self.trace_id} (hex)"
318
+ )
319
+
320
+ return self._trace_file_path