veadk-python 0.1.0__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.

Potentially problematic release.


This version of veadk-python might be problematic. Click here for more details.

Files changed (110) hide show
  1. veadk/__init__.py +31 -0
  2. veadk/a2a/__init__.py +13 -0
  3. veadk/a2a/agent_card.py +45 -0
  4. veadk/a2a/remote_ve_agent.py +19 -0
  5. veadk/a2a/ve_a2a_server.py +77 -0
  6. veadk/a2a/ve_agent_executor.py +78 -0
  7. veadk/a2a/ve_task_store.py +37 -0
  8. veadk/agent.py +253 -0
  9. veadk/cli/__init__.py +13 -0
  10. veadk/cli/main.py +278 -0
  11. veadk/cli/services/agentpilot/__init__.py +17 -0
  12. veadk/cli/services/agentpilot/agentpilot.py +77 -0
  13. veadk/cli/services/veapig/__init__.py +17 -0
  14. veadk/cli/services/veapig/apig.py +224 -0
  15. veadk/cli/services/veapig/apig_utils.py +332 -0
  16. veadk/cli/services/vefaas/__init__.py +17 -0
  17. veadk/cli/services/vefaas/template/deploy.py +44 -0
  18. veadk/cli/services/vefaas/template/src/app.py +30 -0
  19. veadk/cli/services/vefaas/template/src/config.py +58 -0
  20. veadk/cli/services/vefaas/vefaas.py +346 -0
  21. veadk/cli/services/vefaas/vefaas_utils.py +408 -0
  22. veadk/cli/services/vetls/__init__.py +17 -0
  23. veadk/cli/services/vetls/vetls.py +87 -0
  24. veadk/cli/studio/__init__.py +13 -0
  25. veadk/cli/studio/agent_processor.py +247 -0
  26. veadk/cli/studio/fast_api.py +232 -0
  27. veadk/cli/studio/model.py +116 -0
  28. veadk/cloud/__init__.py +13 -0
  29. veadk/cloud/cloud_agent_engine.py +144 -0
  30. veadk/cloud/cloud_app.py +123 -0
  31. veadk/cloud/template/app.py +30 -0
  32. veadk/cloud/template/config.py +55 -0
  33. veadk/config.py +131 -0
  34. veadk/consts.py +17 -0
  35. veadk/database/__init__.py +17 -0
  36. veadk/database/base_database.py +45 -0
  37. veadk/database/database_factory.py +80 -0
  38. veadk/database/kv/__init__.py +13 -0
  39. veadk/database/kv/redis_database.py +109 -0
  40. veadk/database/local_database.py +43 -0
  41. veadk/database/relational/__init__.py +13 -0
  42. veadk/database/relational/mysql_database.py +114 -0
  43. veadk/database/vector/__init__.py +13 -0
  44. veadk/database/vector/opensearch_vector_database.py +205 -0
  45. veadk/database/vector/type.py +50 -0
  46. veadk/database/viking/__init__.py +13 -0
  47. veadk/database/viking/viking_database.py +378 -0
  48. veadk/database/viking/viking_memory_db.py +521 -0
  49. veadk/evaluation/__init__.py +17 -0
  50. veadk/evaluation/adk_evaluator/__init__.py +13 -0
  51. veadk/evaluation/adk_evaluator/adk_evaluator.py +291 -0
  52. veadk/evaluation/base_evaluator.py +242 -0
  53. veadk/evaluation/deepeval_evaluator/__init__.py +17 -0
  54. veadk/evaluation/deepeval_evaluator/deepeval_evaluator.py +223 -0
  55. veadk/evaluation/eval_set_file_loader.py +28 -0
  56. veadk/evaluation/eval_set_recorder.py +91 -0
  57. veadk/evaluation/utils/prometheus.py +142 -0
  58. veadk/knowledgebase/__init__.py +17 -0
  59. veadk/knowledgebase/knowledgebase.py +83 -0
  60. veadk/knowledgebase/knowledgebase_database_adapter.py +259 -0
  61. veadk/memory/__init__.py +13 -0
  62. veadk/memory/long_term_memory.py +119 -0
  63. veadk/memory/memory_database_adapter.py +235 -0
  64. veadk/memory/short_term_memory.py +124 -0
  65. veadk/memory/short_term_memory_processor.py +90 -0
  66. veadk/prompts/__init__.py +13 -0
  67. veadk/prompts/agent_default_prompt.py +30 -0
  68. veadk/prompts/prompt_evaluator.py +20 -0
  69. veadk/prompts/prompt_memory_processor.py +55 -0
  70. veadk/prompts/prompt_optimization.py +158 -0
  71. veadk/runner.py +252 -0
  72. veadk/tools/__init__.py +13 -0
  73. veadk/tools/builtin_tools/__init__.py +13 -0
  74. veadk/tools/builtin_tools/lark.py +67 -0
  75. veadk/tools/builtin_tools/las.py +23 -0
  76. veadk/tools/builtin_tools/vesearch.py +49 -0
  77. veadk/tools/builtin_tools/web_scraper.py +76 -0
  78. veadk/tools/builtin_tools/web_search.py +192 -0
  79. veadk/tools/demo_tools.py +58 -0
  80. veadk/tools/load_knowledgebase_tool.py +144 -0
  81. veadk/tools/sandbox/__init__.py +13 -0
  82. veadk/tools/sandbox/browser_sandbox.py +27 -0
  83. veadk/tools/sandbox/code_sandbox.py +30 -0
  84. veadk/tools/sandbox/computer_sandbox.py +27 -0
  85. veadk/tracing/__init__.py +13 -0
  86. veadk/tracing/base_tracer.py +172 -0
  87. veadk/tracing/telemetry/__init__.py +13 -0
  88. veadk/tracing/telemetry/exporters/__init__.py +13 -0
  89. veadk/tracing/telemetry/exporters/apiserver_exporter.py +60 -0
  90. veadk/tracing/telemetry/exporters/apmplus_exporter.py +101 -0
  91. veadk/tracing/telemetry/exporters/base_exporter.py +28 -0
  92. veadk/tracing/telemetry/exporters/cozeloop_exporter.py +69 -0
  93. veadk/tracing/telemetry/exporters/inmemory_exporter.py +88 -0
  94. veadk/tracing/telemetry/exporters/tls_exporter.py +78 -0
  95. veadk/tracing/telemetry/metrics/__init__.py +13 -0
  96. veadk/tracing/telemetry/metrics/opentelemetry_metrics.py +73 -0
  97. veadk/tracing/telemetry/opentelemetry_tracer.py +167 -0
  98. veadk/types.py +23 -0
  99. veadk/utils/__init__.py +13 -0
  100. veadk/utils/logger.py +59 -0
  101. veadk/utils/misc.py +33 -0
  102. veadk/utils/patches.py +85 -0
  103. veadk/utils/volcengine_sign.py +199 -0
  104. veadk/version.py +15 -0
  105. veadk_python-0.1.0.dist-info/METADATA +124 -0
  106. veadk_python-0.1.0.dist-info/RECORD +110 -0
  107. veadk_python-0.1.0.dist-info/WHEEL +5 -0
  108. veadk_python-0.1.0.dist-info/entry_points.txt +2 -0
  109. veadk_python-0.1.0.dist-info/licenses/LICENSE +201 -0
  110. veadk_python-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,28 @@
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 abc import ABC, abstractmethod
16
+ from typing import Any
17
+
18
+
19
+ class BaseExporter(ABC):
20
+ def __init__(self) -> None:
21
+ pass
22
+
23
+ @abstractmethod
24
+ def get_processor(self) -> Any:
25
+ pass
26
+
27
+ def get_meter_context(self) -> Any:
28
+ pass
@@ -0,0 +1,69 @@
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 opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
16
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor
17
+ from pydantic import BaseModel, Field
18
+ from typing_extensions import override
19
+
20
+ from veadk.config import getenv
21
+ from veadk.tracing.telemetry.exporters.base_exporter import BaseExporter
22
+ from veadk.utils.logger import get_logger
23
+
24
+ logger = get_logger(__name__)
25
+
26
+
27
+ class CozeloopExporterConfig(BaseModel):
28
+ endpoint: str = Field(
29
+ ...,
30
+ default_factory=lambda: getenv(
31
+ "OBSERVABILITY_OPENTELEMETRY_COZELOOP_ENDPOINT",
32
+ "https://api.coze.cn/v1/loop/opentelemetry/v1/traces",
33
+ ),
34
+ )
35
+ space_id: str = Field(
36
+ ...,
37
+ default_factory=lambda: getenv(
38
+ "OBSERVABILITY_OPENTELEMETRY_COZELOOP_SERVICE_NAME"
39
+ ),
40
+ )
41
+ token: str = Field(
42
+ ...,
43
+ default_factory=lambda: getenv("OBSERVABILITY_OPENTELEMETRY_COZELOOP_API_KEY"),
44
+ )
45
+
46
+
47
+ class CozeloopExporter(BaseModel, BaseExporter):
48
+ config: CozeloopExporterConfig = Field(default_factory=CozeloopExporterConfig)
49
+
50
+ @override
51
+ def get_processor(self):
52
+ headers = {
53
+ "cozeloop-workspace-id": self.config.space_id,
54
+ "authorization": f"Bearer {self.config.token}",
55
+ }
56
+ exporter = OTLPSpanExporter(
57
+ endpoint=self.config.endpoint,
58
+ headers=headers,
59
+ timeout=10,
60
+ )
61
+ self._real_exporter = exporter
62
+ processor = BatchSpanProcessor(exporter)
63
+ return processor, None
64
+
65
+ def export(self):
66
+ self._real_exporter.force_flush()
67
+ logger.info(
68
+ f"CozeloopExporter exports data to {self.config.endpoint}, space id: {self.config.space_id}"
69
+ )
@@ -0,0 +1,88 @@
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 typing
16
+ from typing import Any
17
+
18
+ from opentelemetry.sdk.trace import ReadableSpan, export
19
+ from pydantic import BaseModel
20
+ from typing_extensions import override
21
+
22
+ from veadk.tracing.telemetry.exporters.base_exporter import BaseExporter
23
+
24
+
25
+ # ======== Adapted from Google ADK ========
26
+ class _InMemoryExporter(export.SpanExporter):
27
+ def __init__(self, session_trace_dict):
28
+ super().__init__()
29
+ self._spans = []
30
+ self.session_trace_dict = session_trace_dict
31
+ self.trace_id = ""
32
+ self.prompt_tokens = []
33
+ self.completion_tokens = []
34
+
35
+ @override
36
+ def export(self, spans: typing.Sequence[ReadableSpan]) -> export.SpanExportResult:
37
+ for span in spans:
38
+ trace_id = span.context.trace_id
39
+ self.trace_id = trace_id
40
+ if span.name == "call_llm":
41
+ attributes = dict(span.attributes)
42
+ prompt_token = attributes.get("gen_ai.usage.prompt_tokens", None)
43
+ completion_token = attributes.get(
44
+ "gen_ai.usage.completion_tokens", None
45
+ )
46
+ if prompt_token:
47
+ self.prompt_tokens.append(prompt_token)
48
+ if completion_token:
49
+ self.completion_tokens.append(completion_token)
50
+ if span.name == "call_llm":
51
+ attributes = dict(span.attributes)
52
+ session_id = attributes.get("gcp.vertex.agent.session_id", None)
53
+ if session_id:
54
+ if session_id not in self.session_trace_dict:
55
+ self.session_trace_dict[session_id] = [trace_id]
56
+ else:
57
+ self.session_trace_dict[session_id] += [trace_id]
58
+ self._spans.extend(spans)
59
+ return export.SpanExportResult.SUCCESS
60
+
61
+ @override
62
+ def force_flush(self, timeout_millis: int = 30000) -> bool:
63
+ return True
64
+
65
+ def get_finished_spans(self, session_id: str):
66
+ trace_ids = self.session_trace_dict.get(session_id, None)
67
+ if trace_ids is None or not trace_ids:
68
+ return []
69
+ return [x for x in self._spans if x.context.trace_id in trace_ids]
70
+
71
+ def clear(self):
72
+ self._spans.clear()
73
+
74
+
75
+ class InMemoryExporter(BaseModel, BaseExporter):
76
+ name: str = "inmemory_exporter"
77
+
78
+ def model_post_init(self, __context: Any) -> None:
79
+ self._exporter = _InMemoryExporter({})
80
+
81
+ @override
82
+ def get_processor(self):
83
+ self._real_exporter = self._exporter
84
+ processor = export.SimpleSpanProcessor(self._exporter)
85
+ return processor, None
86
+
87
+ def get_meter_context(self) -> Any:
88
+ return None
@@ -0,0 +1,78 @@
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 opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
16
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor
17
+ from pydantic import BaseModel, Field
18
+ from typing_extensions import override
19
+
20
+ from veadk.config import getenv
21
+ from veadk.tracing.telemetry.exporters.base_exporter import BaseExporter
22
+ from veadk.utils.logger import get_logger
23
+
24
+ logger = get_logger(__name__)
25
+
26
+
27
+ class TLSExporterConfig(BaseModel):
28
+ endpoint: str = Field(
29
+ ...,
30
+ default_factory=lambda: getenv(
31
+ "OBSERVABILITY_OPENTELEMETRY_TLS_ENDPOINT",
32
+ "https://tls-cn-beijing.volces.com:4318/v1/traces",
33
+ ),
34
+ )
35
+ region: str = Field(
36
+ ...,
37
+ default_factory=lambda: getenv(
38
+ "OBSERVABILITY_OPENTELEMETRY_TLS_REGION",
39
+ "cn-beijing",
40
+ ),
41
+ )
42
+ topic_id: str = Field(
43
+ ...,
44
+ default_factory=lambda: getenv("OBSERVABILITY_OPENTELEMETRY_TLS_SERVICE_NAME"),
45
+ )
46
+ access_key: str = Field(
47
+ ..., default_factory=lambda: getenv("VOLCENGINE_ACCESS_KEY")
48
+ )
49
+ secret_key: str = Field(
50
+ ..., default_factory=lambda: getenv("VOLCENGINE_SECRET_KEY")
51
+ )
52
+
53
+
54
+ class TLSExporter(BaseModel, BaseExporter):
55
+ config: TLSExporterConfig = Field(default_factory=TLSExporterConfig)
56
+
57
+ @override
58
+ def get_processor(self):
59
+ headers = {
60
+ "x-tls-otel-tracetopic": self.config.topic_id,
61
+ "x-tls-otel-ak": self.config.access_key,
62
+ "x-tls-otel-sk": self.config.secret_key,
63
+ "x-tls-otel-region": self.config.region,
64
+ }
65
+ exporter = OTLPSpanExporter(
66
+ endpoint=self.config.endpoint,
67
+ headers=headers,
68
+ timeout=10,
69
+ )
70
+ self._real_exporter = exporter
71
+ processor = BatchSpanProcessor(exporter)
72
+ return processor, None
73
+
74
+ def export(self):
75
+ self._real_exporter.force_flush()
76
+ logger.info(
77
+ f"TLSExporter exports data to {self.config.endpoint}, topic id: {self.config.topic_id}"
78
+ )
@@ -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,73 @@
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 time
16
+
17
+ from opentelemetry.metrics._internal import Meter
18
+ from opentelemetry.sdk.metrics import MeterProvider
19
+ from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
20
+
21
+ from veadk.config import getenv
22
+
23
+
24
+ class MeterContext:
25
+ def __init__(
26
+ self,
27
+ meter: Meter,
28
+ provider: MeterProvider,
29
+ reader: PeriodicExportingMetricReader,
30
+ ):
31
+ self.meter = meter
32
+ self.provider = provider
33
+ self.reader = reader
34
+
35
+
36
+ class MeterUploader:
37
+ def __init__(self, meter_context: MeterContext):
38
+ self.meter = meter_context.meter
39
+ self.provider = meter_context.provider
40
+ self.reader = meter_context.reader
41
+
42
+ self.base_attributes = {
43
+ "gen_ai_system": "volcengine",
44
+ "server_address": "api.volcengine.com",
45
+ "gen_ai_response_model": getenv("MODEL_AGENT_NAME", "unknown"),
46
+ "stream": "false",
47
+ "gen_ai_operation_name": "chat_completions",
48
+ }
49
+ self.llm_invoke_counter = self.meter.create_counter(
50
+ name="gen_ai.chat.count",
51
+ description="Number of LLM invocations",
52
+ unit="count",
53
+ )
54
+ self.token_usage = self.meter.create_histogram(
55
+ name="gen_ai.client.token.usage",
56
+ description="Token consumption of LLM invocations",
57
+ unit="count",
58
+ )
59
+
60
+ def record(self, prompt_tokens: list[int], completion_tokens: list[int]):
61
+ self.llm_invoke_counter.add(len(completion_tokens), self.base_attributes)
62
+
63
+ for prompt_token in prompt_tokens:
64
+ token_attributes = {**self.base_attributes, "gen_ai_token_type": "input"}
65
+ self.token_usage.record(prompt_token, attributes=token_attributes)
66
+ for completion_token in completion_tokens:
67
+ token_attributes = {**self.base_attributes, "gen_ai_token_type": "output"}
68
+ self.token_usage.record(completion_token, attributes=token_attributes)
69
+
70
+ def close(self):
71
+ time.sleep(0.05)
72
+ self.reader.force_flush()
73
+ self.provider.shutdown()
@@ -0,0 +1,167 @@
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 openinference.instrumentation.google_adk import GoogleADKInstrumentor
22
+ from opentelemetry.sdk import trace as trace_sdk
23
+ from opentelemetry.sdk.resources import Resource
24
+ from opentelemetry.sdk.trace import TracerProvider
25
+ from pydantic import BaseModel, ConfigDict, Field
26
+ from typing_extensions import override
27
+
28
+ from veadk.tracing.base_tracer import BaseTracer
29
+ from veadk.tracing.telemetry.exporters.apiserver_exporter import ApiServerExporter
30
+ from veadk.tracing.telemetry.exporters.base_exporter import BaseExporter
31
+ from veadk.tracing.telemetry.exporters.inmemory_exporter import InMemoryExporter
32
+ from veadk.tracing.telemetry.metrics.opentelemetry_metrics import MeterUploader
33
+ from veadk.utils.logger import get_logger
34
+
35
+ logger = get_logger(__name__)
36
+
37
+ DEFAULT_VEADK_TRACER_NAME = "veadk_global_tracer"
38
+
39
+
40
+ def update_resource_attributions(provider: TracerProvider, resource_attributes: dict):
41
+ provider._resource = provider._resource.merge(Resource.create(resource_attributes))
42
+
43
+
44
+ class OpentelemetryTracer(BaseModel, BaseTracer):
45
+ model_config = ConfigDict(arbitrary_types_allowed=True)
46
+ exporters: list[BaseExporter] = Field(
47
+ default=[],
48
+ description="The exporters to export spans.",
49
+ )
50
+ name: str = Field(
51
+ DEFAULT_VEADK_TRACER_NAME, description="The identifier of tracer."
52
+ )
53
+
54
+ def model_post_init(self, context: Any, /) -> None:
55
+ self._processors = []
56
+ self._inmemory_exporter: InMemoryExporter = None
57
+
58
+ # Inmemory & APIServer are the default exporters
59
+ have_inmemory_exporter = False
60
+ have_apiserver_exporter = False
61
+ for exporter in self.exporters:
62
+ if isinstance(exporter, InMemoryExporter):
63
+ have_inmemory_exporter = True
64
+ elif isinstance(exporter, ApiServerExporter):
65
+ have_apiserver_exporter = True
66
+
67
+ if not have_inmemory_exporter:
68
+ inmemory_exporter = InMemoryExporter()
69
+ self.exporters.append(inmemory_exporter)
70
+ self._inmemory_exporter = inmemory_exporter
71
+ if not have_apiserver_exporter:
72
+ apiserver_exporter = ApiServerExporter()
73
+ self.exporters.append(apiserver_exporter)
74
+ self._apiserver_exporter = apiserver_exporter
75
+
76
+ tracer_provider = trace_sdk.TracerProvider()
77
+ for exporter in self.exporters:
78
+ processor, resource_attributes = exporter.get_processor()
79
+ if resource_attributes is not None:
80
+ update_resource_attributions(tracer_provider, resource_attributes)
81
+ tracer_provider.add_span_processor(processor)
82
+
83
+ logger.debug(f"Add exporter `{exporter.__class__.__name__}` to tracing.")
84
+ self._processors.append(processor)
85
+ logger.debug(f"Init OpentelemetryTracer with {len(self.exporters)} exporters.")
86
+
87
+ self._meter_contexts = []
88
+ self._meter_uploaders = []
89
+ for exporter in self.exporters:
90
+ meter_context = exporter.get_meter_context()
91
+ if meter_context is not None:
92
+ self._meter_contexts.append(meter_context)
93
+
94
+ for meter_context in self._meter_contexts:
95
+ meter_uploader = MeterUploader(meter_context)
96
+ self._meter_uploaders.append(meter_uploader)
97
+
98
+ # just for debug
99
+ self._trace_file_path = ""
100
+
101
+ # patch this before starting instrumentation
102
+ # enable_veadk_tracing(self.dump)
103
+
104
+ GoogleADKInstrumentor().instrument(tracer_provider=tracer_provider)
105
+
106
+ @override
107
+ def dump(
108
+ self,
109
+ user_id: str,
110
+ session_id: str,
111
+ path: str = "/tmp",
112
+ ) -> str:
113
+ prompt_tokens = self._inmemory_exporter._real_exporter.prompt_tokens
114
+ completion_tokens = self._inmemory_exporter._real_exporter.completion_tokens
115
+
116
+ # upload
117
+ for meter_uploader in self._meter_uploaders:
118
+ meter_uploader.record(
119
+ prompt_tokens=prompt_tokens, completion_tokens=completion_tokens
120
+ )
121
+ # clear tokens after dump
122
+ self._inmemory_exporter._real_exporter.completion_tokens = []
123
+ self._inmemory_exporter._real_exporter.prompt_tokens = []
124
+
125
+ for processor in self._processors:
126
+ time.sleep(0.05) # give some time for the exporter to upload spans
127
+ processor.force_flush()
128
+
129
+ spans = self._inmemory_exporter._real_exporter.get_finished_spans(
130
+ session_id=session_id
131
+ )
132
+ if not spans:
133
+ data = []
134
+ else:
135
+ data = [
136
+ {
137
+ "name": s.name,
138
+ "span_id": s.context.span_id,
139
+ "trace_id": s.context.trace_id,
140
+ "start_time": s.start_time,
141
+ "end_time": s.end_time,
142
+ "attributes": dict(s.attributes),
143
+ "parent_span_id": s.parent.span_id if s.parent else None,
144
+ }
145
+ for s in spans
146
+ ]
147
+
148
+ trace_id = hex(int(self._inmemory_exporter._real_exporter.trace_id))[2:]
149
+ self._trace_id = trace_id
150
+ file_path = f"{path}/{self.name}_{user_id}_{session_id}_{trace_id}.json"
151
+ with open(file_path, "w") as f:
152
+ json.dump(data, f, indent=4)
153
+
154
+ self._trace_file_path = file_path
155
+
156
+ for exporter in self.exporters:
157
+ if not isinstance(exporter, InMemoryExporter) and not isinstance(
158
+ exporter, ApiServerExporter
159
+ ):
160
+ exporter.export()
161
+ logger.info(
162
+ f"OpenTelemetryTracer tracing done, trace id: {self._trace_id} (hex)"
163
+ )
164
+
165
+ self._spans = spans
166
+ logger.info(f"OpenTelemetryTracer dumps {len(spans)} spans to {file_path}")
167
+ return file_path
veadk/types.py ADDED
@@ -0,0 +1,23 @@
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
16
+
17
+
18
+ class MediaMessage(BaseModel):
19
+ text: str
20
+ """Text-based prompt"""
21
+
22
+ media: str
23
+ """Media file (e.g., `.pdf`, `.docx`, `.png`, `.jpg`, `.jpeg`, `.mp4`, `.mp3`, `.wav`, `.txt`) path"""
@@ -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.
veadk/utils/logger.py ADDED
@@ -0,0 +1,59 @@
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 sys
16
+
17
+ from loguru import logger
18
+
19
+ from veadk.config import getenv
20
+
21
+
22
+ def filter_log():
23
+ import logging
24
+ import warnings
25
+
26
+ from urllib3.exceptions import InsecureRequestWarning
27
+
28
+ # ignore all warnings
29
+ warnings.filterwarnings("ignore")
30
+
31
+ # ignore UserWarning
32
+ warnings.filterwarnings(
33
+ "ignore", category=UserWarning, module="opensearchpy.connection.http_urllib3"
34
+ )
35
+
36
+ # ignore InsecureRequestWarning
37
+ warnings.filterwarnings("ignore", category=InsecureRequestWarning)
38
+
39
+ # disable logs
40
+ logging.basicConfig(level=logging.ERROR)
41
+
42
+
43
+ def setup_logger():
44
+ logger.remove()
45
+ logger.add(
46
+ sys.stdout,
47
+ format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level}</level> | <cyan>{file}:{line}</cyan> - {message}",
48
+ colorize=True,
49
+ level=getenv("LOGGING_LEVEL", "DEBUG"),
50
+ )
51
+ return logger
52
+
53
+
54
+ filter_log()
55
+ setup_logger()
56
+
57
+
58
+ def get_logger(name: str):
59
+ return logger.bind(name=name)
veadk/utils/misc.py ADDED
@@ -0,0 +1,33 @@
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 time
16
+
17
+
18
+ def read_file(file_path):
19
+ with open(file_path, "r", encoding="utf-8") as f:
20
+ data = f.readlines()
21
+ data = [x.strip() for x in data]
22
+ return data
23
+
24
+
25
+ def formatted_timestamp():
26
+ # YYYYMMDDHHMMSS
27
+ return time.strftime("%Y%m%d%H%M%S", time.localtime())
28
+
29
+
30
+ def read_png_to_bytes(png_path: str) -> bytes:
31
+ with open(png_path, "rb") as f:
32
+ data = f.read()
33
+ return data