veadk-python 0.2.2__py3-none-any.whl → 0.2.5__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.
- veadk/agent.py +31 -21
- veadk/agents/loop_agent.py +55 -0
- veadk/agents/parallel_agent.py +60 -0
- veadk/agents/sequential_agent.py +55 -0
- veadk/cli/cli_deploy.py +14 -1
- veadk/cli/cli_web.py +27 -0
- veadk/cloud/cloud_app.py +21 -6
- veadk/consts.py +14 -1
- veadk/database/viking/viking_database.py +3 -3
- veadk/evaluation/adk_evaluator/__init__.py +4 -0
- veadk/evaluation/adk_evaluator/adk_evaluator.py +170 -217
- veadk/evaluation/base_evaluator.py +26 -20
- veadk/evaluation/deepeval_evaluator/deepeval_evaluator.py +8 -5
- veadk/{tracing/telemetry/metrics/__init__.py → integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/clean.py} +10 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/app.py +40 -7
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/run.sh +11 -5
- veadk/integrations/ve_faas/ve_faas.py +5 -1
- veadk/integrations/ve_tos/ve_tos.py +176 -0
- veadk/runner.py +162 -39
- veadk/tools/builtin_tools/image_edit.py +236 -0
- veadk/tools/builtin_tools/image_generate.py +236 -0
- veadk/tools/builtin_tools/video_generate.py +326 -0
- veadk/tools/sandbox/browser_sandbox.py +19 -9
- veadk/tools/sandbox/code_sandbox.py +21 -11
- veadk/tools/sandbox/computer_sandbox.py +16 -9
- veadk/tracing/base_tracer.py +6 -200
- veadk/tracing/telemetry/attributes/attributes.py +29 -0
- veadk/tracing/telemetry/attributes/extractors/common_attributes_extractors.py +71 -0
- veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py +451 -0
- veadk/tracing/telemetry/attributes/extractors/tool_attributes_extractors.py +76 -0
- veadk/tracing/telemetry/attributes/extractors/types.py +75 -0
- veadk/tracing/telemetry/exporters/apmplus_exporter.py +97 -38
- veadk/tracing/telemetry/exporters/base_exporter.py +10 -10
- veadk/tracing/telemetry/exporters/cozeloop_exporter.py +20 -13
- veadk/tracing/telemetry/exporters/inmemory_exporter.py +49 -32
- veadk/tracing/telemetry/exporters/tls_exporter.py +18 -12
- veadk/tracing/telemetry/opentelemetry_tracer.py +105 -102
- veadk/tracing/telemetry/telemetry.py +238 -0
- veadk/types.py +6 -1
- veadk/utils/misc.py +41 -1
- veadk/utils/patches.py +25 -0
- veadk/version.py +1 -1
- veadk_python-0.2.5.dist-info/METADATA +345 -0
- veadk_python-0.2.5.dist-info/RECORD +127 -0
- veadk/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/__pycache__/agent.cpython-310.pyc +0 -0
- veadk/__pycache__/config.cpython-310.pyc +0 -0
- veadk/__pycache__/consts.cpython-310.pyc +0 -0
- veadk/__pycache__/runner.cpython-310.pyc +0 -0
- veadk/__pycache__/types.cpython-310.pyc +0 -0
- veadk/__pycache__/version.cpython-310.pyc +0 -0
- veadk/a2a/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/a2a/__pycache__/agent_card.cpython-310.pyc +0 -0
- veadk/a2a/__pycache__/remote_ve_agent.cpython-310.pyc +0 -0
- veadk/a2a/__pycache__/ve_a2a_server.cpython-310.pyc +0 -0
- veadk/a2a/__pycache__/ve_agent_executor.cpython-310.pyc +0 -0
- veadk/cli/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/cli/__pycache__/cli.cpython-310.pyc +0 -0
- veadk/cli/__pycache__/cli_deploy.cpython-310.pyc +0 -0
- veadk/cli/__pycache__/cli_init.cpython-310.pyc +0 -0
- veadk/cli/__pycache__/cli_prompt.cpython-310.pyc +0 -0
- veadk/cli/__pycache__/cli_studio.cpython-310.pyc +0 -0
- veadk/cli/__pycache__/cli_web.cpython-310.pyc +0 -0
- veadk/cli/__pycache__/main.cpython-310.pyc +0 -0
- veadk/cloud/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/cloud/__pycache__/cloud_agent_engine.cpython-310.pyc +0 -0
- veadk/cloud/__pycache__/cloud_app.cpython-310.pyc +0 -0
- veadk/database/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/database/__pycache__/base_database.cpython-310.pyc +0 -0
- veadk/database/__pycache__/database_adapter.cpython-310.pyc +0 -0
- veadk/database/__pycache__/database_factory.cpython-310.pyc +0 -0
- veadk/database/__pycache__/local_database.cpython-310.pyc +0 -0
- veadk/database/kv/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/database/relational/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/database/vector/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/database/vector/__pycache__/opensearch_vector_database.cpython-310.pyc +0 -0
- veadk/database/vector/__pycache__/type.cpython-310.pyc +0 -0
- veadk/database/viking/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/evaluation/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/evaluation/__pycache__/base_evaluator.cpython-310.pyc +0 -0
- veadk/evaluation/__pycache__/eval_set_file_loader.cpython-310.pyc +0 -0
- veadk/evaluation/__pycache__/eval_set_recorder.cpython-310.pyc +0 -0
- veadk/evaluation/__pycache__/types.cpython-310.pyc +0 -0
- veadk/evaluation/adk_evaluator/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/evaluation/deepeval_evaluator/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/evaluation/deepeval_evaluator/__pycache__/deepeval_evaluator.cpython-310.pyc +0 -0
- veadk/evaluation/utils/__pycache__/prometheus.cpython-310.pyc +0 -0
- veadk/integrations/ve_apig/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/integrations/ve_apig/__pycache__/apig.cpython-310.pyc +0 -0
- veadk/integrations/ve_apig/__pycache__/ve_apig.cpython-310.pyc +0 -0
- veadk/integrations/ve_faas/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/integrations/ve_faas/__pycache__/types.cpython-310.pyc +0 -0
- veadk/integrations/ve_faas/__pycache__/ve_faas.cpython-310.pyc +0 -0
- veadk/integrations/ve_faas/__pycache__/ve_faas_utils.cpython-310.pyc +0 -0
- veadk/integrations/ve_faas/__pycache__/vefaas.cpython-310.pyc +0 -0
- veadk/integrations/ve_faas/__pycache__/vefaas_utils.cpython-310.pyc +0 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/__pycache__/agent.cpython-310.pyc +0 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/__pycache__/app.cpython-310.pyc +0 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/__pycache__/studio_app.cpython-310.pyc +0 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{ cookiecutter.app_name|replace('-', '_') }}/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{ cookiecutter.app_name|replace('-', '_') }}/__pycache__/agent.cpython-310.pyc +0 -0
- veadk/integrations/ve_prompt_pilot/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/integrations/ve_prompt_pilot/__pycache__/agentpilot.cpython-310.pyc +0 -0
- veadk/knowledgebase/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/knowledgebase/__pycache__/knowledgebase.cpython-310.pyc +0 -0
- veadk/knowledgebase/__pycache__/knowledgebase_database_adapter.cpython-310.pyc +0 -0
- veadk/memory/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/memory/__pycache__/long_term_memory.cpython-310.pyc +0 -0
- veadk/memory/__pycache__/memory_database_adapter.cpython-310.pyc +0 -0
- veadk/memory/__pycache__/short_term_memory.cpython-310.pyc +0 -0
- veadk/memory/__pycache__/short_term_memory_processor.cpython-310.pyc +0 -0
- veadk/prompts/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/prompts/__pycache__/agent_default_prompt.cpython-310.pyc +0 -0
- veadk/prompts/__pycache__/prompt_memory_processor.cpython-310.pyc +0 -0
- veadk/prompts/__pycache__/prompt_optimization.cpython-310.pyc +0 -0
- veadk/tools/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/tools/__pycache__/demo_tools.cpython-310.pyc +0 -0
- veadk/tools/__pycache__/load_knowledgebase_tool.cpython-310.pyc +0 -0
- veadk/tools/builtin_tools/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/tools/builtin_tools/__pycache__/lark.cpython-310.pyc +0 -0
- veadk/tools/builtin_tools/__pycache__/vesearch.cpython-310.pyc +0 -0
- veadk/tools/builtin_tools/__pycache__/web_search.cpython-310.pyc +0 -0
- veadk/tools/sandbox/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/tracing/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/tracing/__pycache__/base_tracer.cpython-310.pyc +0 -0
- veadk/tracing/telemetry/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/tracing/telemetry/__pycache__/opentelemetry_tracer.cpython-310.pyc +0 -0
- veadk/tracing/telemetry/exporters/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/tracing/telemetry/exporters/__pycache__/apiserver_exporter.cpython-310.pyc +0 -0
- veadk/tracing/telemetry/exporters/__pycache__/apmplus_exporter.cpython-310.pyc +0 -0
- veadk/tracing/telemetry/exporters/__pycache__/base_exporter.cpython-310.pyc +0 -0
- veadk/tracing/telemetry/exporters/__pycache__/cozeloop_exporter.cpython-310.pyc +0 -0
- veadk/tracing/telemetry/exporters/__pycache__/inmemory_exporter.cpython-310.pyc +0 -0
- veadk/tracing/telemetry/exporters/__pycache__/tls_exporter.cpython-310.pyc +0 -0
- veadk/tracing/telemetry/metrics/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/tracing/telemetry/metrics/__pycache__/opentelemetry_metrics.cpython-310.pyc +0 -0
- veadk/tracing/telemetry/metrics/opentelemetry_metrics.py +0 -73
- veadk/utils/__pycache__/__init__.cpython-310.pyc +0 -0
- veadk/utils/__pycache__/logger.cpython-310.pyc +0 -0
- veadk/utils/__pycache__/mcp_utils.cpython-310.pyc +0 -0
- veadk/utils/__pycache__/misc.cpython-310.pyc +0 -0
- veadk/utils/__pycache__/patches.cpython-310.pyc +0 -0
- veadk/utils/__pycache__/volcengine_sign.cpython-310.pyc +0 -0
- veadk_python-0.2.2.dist-info/METADATA +0 -144
- veadk_python-0.2.2.dist-info/RECORD +0 -213
- {veadk_python-0.2.2.dist-info → veadk_python-0.2.5.dist-info}/WHEEL +0 -0
- {veadk_python-0.2.2.dist-info → veadk_python-0.2.5.dist-info}/entry_points.txt +0 -0
- {veadk_python-0.2.2.dist-info → veadk_python-0.2.5.dist-info}/licenses/LICENSE +0 -0
- {veadk_python-0.2.2.dist-info → veadk_python-0.2.5.dist-info}/top_level.txt +0 -0
|
@@ -18,96 +18,74 @@ import json
|
|
|
18
18
|
import time
|
|
19
19
|
from typing import Any
|
|
20
20
|
|
|
21
|
-
from openinference.instrumentation.google_adk import GoogleADKInstrumentor
|
|
22
21
|
from opentelemetry import trace as trace_api
|
|
23
22
|
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
|
|
24
23
|
from opentelemetry.sdk import trace as trace_sdk
|
|
25
24
|
from opentelemetry.sdk.resources import Resource
|
|
26
25
|
from opentelemetry.sdk.trace import TracerProvider
|
|
27
26
|
from opentelemetry.sdk.trace.export import BatchSpanProcessor, SimpleSpanProcessor
|
|
28
|
-
from pydantic import BaseModel, ConfigDict, Field
|
|
27
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
29
28
|
from typing_extensions import override
|
|
30
29
|
|
|
31
30
|
from veadk.tracing.base_tracer import BaseTracer
|
|
32
31
|
from veadk.tracing.telemetry.exporters.apmplus_exporter import APMPlusExporter
|
|
33
32
|
from veadk.tracing.telemetry.exporters.base_exporter import BaseExporter
|
|
34
33
|
from veadk.tracing.telemetry.exporters.inmemory_exporter import InMemoryExporter
|
|
35
|
-
from veadk.tracing.telemetry.
|
|
34
|
+
from veadk.tracing.telemetry.exporters.inmemory_exporter import (
|
|
35
|
+
_INMEMORY_EXPORTER_INSTANCE,
|
|
36
|
+
)
|
|
36
37
|
from veadk.utils.logger import get_logger
|
|
38
|
+
from veadk.utils.patches import patch_google_adk_telemetry
|
|
37
39
|
|
|
38
40
|
logger = get_logger(__name__)
|
|
39
41
|
|
|
40
|
-
DEFAULT_VEADK_TRACER_NAME = "veadk_global_tracer"
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
def _update_resource_attributions(
|
|
44
|
+
provider: TracerProvider, resource_attributes: dict
|
|
45
|
+
) -> None:
|
|
44
46
|
provider._resource = provider._resource.merge(Resource.create(resource_attributes))
|
|
45
47
|
|
|
46
48
|
|
|
47
49
|
class OpentelemetryTracer(BaseModel, BaseTracer):
|
|
48
50
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
49
|
-
|
|
50
|
-
default=[],
|
|
51
|
-
description="The exporters to export spans.",
|
|
52
|
-
)
|
|
51
|
+
|
|
53
52
|
name: str = Field(
|
|
54
|
-
|
|
53
|
+
default="veadk_opentelemetry_tracer", description="The identifier of tracer."
|
|
55
54
|
)
|
|
56
55
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
description="The
|
|
56
|
+
exporters: list[BaseExporter] = Field(
|
|
57
|
+
default_factory=list,
|
|
58
|
+
description="The exporters to export spans.",
|
|
60
59
|
)
|
|
61
60
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
@field_validator("exporters")
|
|
62
|
+
@classmethod
|
|
63
|
+
def forbid_inmemory_exporter(cls, v: list[BaseExporter]) -> list[BaseExporter]:
|
|
64
|
+
for e in v:
|
|
65
|
+
if isinstance(e, InMemoryExporter):
|
|
66
|
+
raise ValueError("InMemoryExporter is not allowed in exporters list")
|
|
67
|
+
return v
|
|
65
68
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
self._inmemory_exporter = exporter
|
|
69
|
+
def model_post_init(self, context: Any) -> None:
|
|
70
|
+
patch_google_adk_telemetry()
|
|
71
|
+
self._init_global_tracer_provider()
|
|
70
72
|
|
|
71
|
-
|
|
72
|
-
self._inmemory_exporter = InMemoryExporter()
|
|
73
|
-
self.exporters.append(self._inmemory_exporter)
|
|
74
|
-
# ========================================================================
|
|
75
|
-
|
|
76
|
-
# Process meter-related attributes
|
|
77
|
-
self._meter_contexts = []
|
|
78
|
-
self._meter_uploaders = []
|
|
79
|
-
for exporter in self.exporters:
|
|
80
|
-
meter_context = exporter.get_meter_context()
|
|
81
|
-
if meter_context is not None:
|
|
82
|
-
self._meter_contexts.append(meter_context)
|
|
73
|
+
# GoogleADKInstrumentor().instrument()
|
|
83
74
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
self._meter_uploaders.append(meter_uploader)
|
|
87
|
-
# ================================
|
|
88
|
-
|
|
89
|
-
# init tracer provider
|
|
90
|
-
# VeADK operates on global OpenTelemetry provider, hence return nothing
|
|
91
|
-
self._init_tracer_provider()
|
|
92
|
-
|
|
93
|
-
# just for debug
|
|
94
|
-
self._trace_file_path = ""
|
|
95
|
-
|
|
96
|
-
GoogleADKInstrumentor().instrument()
|
|
75
|
+
def _init_global_tracer_provider(self) -> None:
|
|
76
|
+
self._processors = []
|
|
97
77
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
# finally, get global provider
|
|
101
|
-
tracer_provider = trace_sdk.TracerProvider()
|
|
102
|
-
trace_api.set_tracer_provider(tracer_provider)
|
|
78
|
+
# set provider anyway, then get global provider
|
|
79
|
+
trace_api.set_tracer_provider(trace_sdk.TracerProvider())
|
|
103
80
|
global_tracer_provider: TracerProvider = trace_api.get_tracer_provider() # type: ignore
|
|
104
81
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
82
|
+
span_processors = global_tracer_provider._active_span_processor._span_processors
|
|
83
|
+
have_apmplus_exporter = any(
|
|
84
|
+
isinstance(p, (BatchSpanProcessor, SimpleSpanProcessor))
|
|
85
|
+
and isinstance(p.span_exporter, OTLPSpanExporter)
|
|
86
|
+
and "apmplus" in p.span_exporter._endpoint
|
|
87
|
+
for p in span_processors
|
|
88
|
+
)
|
|
111
89
|
|
|
112
90
|
if have_apmplus_exporter:
|
|
113
91
|
self.exporters = [
|
|
@@ -115,54 +93,83 @@ class OpentelemetryTracer(BaseModel, BaseTracer):
|
|
|
115
93
|
]
|
|
116
94
|
|
|
117
95
|
for exporter in self.exporters:
|
|
118
|
-
processor
|
|
119
|
-
|
|
120
|
-
|
|
96
|
+
processor = exporter.processor
|
|
97
|
+
resource_attributes = exporter.resource_attributes
|
|
98
|
+
|
|
99
|
+
if resource_attributes:
|
|
100
|
+
_update_resource_attributions(
|
|
121
101
|
global_tracer_provider, resource_attributes
|
|
122
102
|
)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
103
|
+
|
|
104
|
+
if processor:
|
|
105
|
+
global_tracer_provider.add_span_processor(processor)
|
|
106
|
+
self._processors.append(processor)
|
|
107
|
+
|
|
108
|
+
logger.debug(
|
|
109
|
+
f"Add span processor for exporter `{exporter.__class__.__name__}` to OpentelemetryTracer."
|
|
110
|
+
)
|
|
111
|
+
else:
|
|
112
|
+
logger.error(
|
|
113
|
+
f"Add span processor for exporter `{exporter.__class__.__name__}` to OpentelemetryTracer failed."
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
self._inmemory_exporter = _INMEMORY_EXPORTER_INSTANCE
|
|
117
|
+
if self._inmemory_exporter.processor:
|
|
118
|
+
# make sure the in memory exporter processor is added at index 0
|
|
119
|
+
# because we use this to record all spans
|
|
120
|
+
global_tracer_provider._active_span_processor._span_processors = (
|
|
121
|
+
self._inmemory_exporter.processor,
|
|
122
|
+
) + global_tracer_provider._active_span_processor._span_processors
|
|
123
|
+
|
|
124
|
+
self._processors.append(self._inmemory_exporter.processor)
|
|
125
|
+
else:
|
|
126
|
+
logger.warning(
|
|
127
|
+
"InMemoryExporter processor is not initialized, cannot add to OpentelemetryTracer."
|
|
126
128
|
)
|
|
127
|
-
|
|
128
|
-
logger.
|
|
129
|
+
|
|
130
|
+
logger.info(f"Init OpentelemetryTracer with {len(self._processors)} exporters.")
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def trace_file_path(self) -> str:
|
|
134
|
+
return self._trace_file_path
|
|
135
|
+
|
|
136
|
+
@property
|
|
137
|
+
def trace_id(self) -> str:
|
|
138
|
+
try:
|
|
139
|
+
trace_id = hex(int(self._inmemory_exporter._exporter.trace_id))[2:] # type: ignore
|
|
140
|
+
return trace_id
|
|
141
|
+
except Exception as e:
|
|
142
|
+
logger.error(f"Failed to get trace_id from InMemoryExporter: {e}")
|
|
143
|
+
return self._trace_id
|
|
144
|
+
|
|
145
|
+
def force_export(self) -> None:
|
|
146
|
+
"""Force to export spans in all processors."""
|
|
147
|
+
for processor in self._processors:
|
|
148
|
+
time.sleep(0.05)
|
|
149
|
+
processor.force_flush()
|
|
129
150
|
|
|
130
151
|
@override
|
|
131
152
|
def dump(
|
|
132
153
|
self,
|
|
133
|
-
user_id: str,
|
|
134
|
-
session_id: str,
|
|
154
|
+
user_id: str = "unknown_user_id",
|
|
155
|
+
session_id: str = "unknown_session_id",
|
|
135
156
|
path: str = "/tmp",
|
|
136
157
|
) -> str:
|
|
158
|
+
def _build_trace_file_path(path: str, user_id: str, session_id: str) -> str:
|
|
159
|
+
return f"{path}/{self.name}_{user_id}_{session_id}_{self.trace_id}.json"
|
|
160
|
+
|
|
137
161
|
if not self._inmemory_exporter:
|
|
138
162
|
logger.warning(
|
|
139
163
|
"InMemoryExporter is not initialized. Please check your tracer exporters."
|
|
140
164
|
)
|
|
141
165
|
return ""
|
|
166
|
+
self.force_export()
|
|
142
167
|
|
|
143
|
-
|
|
144
|
-
completion_tokens = self._inmemory_exporter._real_exporter.completion_tokens
|
|
145
|
-
|
|
146
|
-
# upload
|
|
147
|
-
for meter_uploader in self._meter_uploaders:
|
|
148
|
-
meter_uploader.record(
|
|
149
|
-
prompt_tokens=prompt_tokens, completion_tokens=completion_tokens
|
|
150
|
-
)
|
|
151
|
-
# clear tokens after dump
|
|
152
|
-
self._inmemory_exporter._real_exporter.completion_tokens = []
|
|
153
|
-
self._inmemory_exporter._real_exporter.prompt_tokens = []
|
|
154
|
-
|
|
155
|
-
for processor in self._processors:
|
|
156
|
-
time.sleep(0.05) # give some time for the exporter to upload spans
|
|
157
|
-
processor.force_flush()
|
|
158
|
-
|
|
159
|
-
spans = self._inmemory_exporter._real_exporter.get_finished_spans(
|
|
168
|
+
spans = self._inmemory_exporter._exporter.get_finished_spans( # type: ignore
|
|
160
169
|
session_id=session_id
|
|
161
170
|
)
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
else:
|
|
165
|
-
data = [
|
|
171
|
+
data = (
|
|
172
|
+
[
|
|
166
173
|
{
|
|
167
174
|
"name": s.name,
|
|
168
175
|
"span_id": s.context.span_id,
|
|
@@ -174,22 +181,18 @@ class OpentelemetryTracer(BaseModel, BaseTracer):
|
|
|
174
181
|
}
|
|
175
182
|
for s in spans
|
|
176
183
|
]
|
|
184
|
+
if spans
|
|
185
|
+
else []
|
|
186
|
+
)
|
|
177
187
|
|
|
178
|
-
|
|
179
|
-
self.
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
self._trace_file_path = file_path
|
|
188
|
+
self._trace_file_path = _build_trace_file_path(path, user_id, session_id)
|
|
189
|
+
with open(self._trace_file_path, "w") as f:
|
|
190
|
+
json.dump(
|
|
191
|
+
data, f, indent=4, ensure_ascii=False
|
|
192
|
+
) # ensure_ascii=False to support Chinese characters
|
|
185
193
|
|
|
186
|
-
for exporter in self.exporters:
|
|
187
|
-
if not isinstance(exporter, InMemoryExporter):
|
|
188
|
-
exporter.export()
|
|
189
194
|
logger.info(
|
|
190
|
-
f"OpenTelemetryTracer
|
|
195
|
+
f"OpenTelemetryTracer dumps {len(spans)} spans to {self._trace_file_path}. Trace id: {self.trace_id} (hex)"
|
|
191
196
|
)
|
|
192
197
|
|
|
193
|
-
self.
|
|
194
|
-
logger.info(f"OpenTelemetryTracer dumps {len(spans)} spans to {file_path}")
|
|
195
|
-
return file_path
|
|
198
|
+
return self._trace_file_path
|
|
@@ -0,0 +1,238 @@
|
|
|
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.sdk.trace import _Span
|
|
24
|
+
|
|
25
|
+
from veadk.tracing.telemetry.attributes.attributes import ATTRIBUTES
|
|
26
|
+
from veadk.tracing.telemetry.attributes.extractors.types import (
|
|
27
|
+
ExtractorResponse,
|
|
28
|
+
LLMAttributesParams,
|
|
29
|
+
ToolAttributesParams,
|
|
30
|
+
)
|
|
31
|
+
from veadk.tracing.telemetry.exporters.inmemory_exporter import (
|
|
32
|
+
_INMEMORY_EXPORTER_INSTANCE,
|
|
33
|
+
)
|
|
34
|
+
from veadk.utils.logger import get_logger
|
|
35
|
+
|
|
36
|
+
logger = get_logger(__name__)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def upload_metrics(
|
|
40
|
+
invocation_context: InvocationContext,
|
|
41
|
+
llm_request: LlmRequest,
|
|
42
|
+
llm_response: LlmResponse,
|
|
43
|
+
) -> None:
|
|
44
|
+
from veadk.agent import Agent
|
|
45
|
+
|
|
46
|
+
if isinstance(invocation_context.agent, Agent):
|
|
47
|
+
tracers = invocation_context.agent.tracers
|
|
48
|
+
for tracer in tracers:
|
|
49
|
+
for exporter in getattr(tracer, "exporters", []):
|
|
50
|
+
if getattr(exporter, "meter_uploader", None):
|
|
51
|
+
exporter.meter_uploader.record(llm_request, llm_response)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _set_agent_input_attribute(
|
|
55
|
+
span: _Span, invocation_context: InvocationContext
|
|
56
|
+
) -> None:
|
|
57
|
+
# We only save the original user input as the agent input
|
|
58
|
+
# hence once the `agent.input` has been set, we don't overwrite it
|
|
59
|
+
event_names = [event.name for event in span.events]
|
|
60
|
+
if "gen_ai.user.message" in event_names:
|
|
61
|
+
return
|
|
62
|
+
|
|
63
|
+
# input = {
|
|
64
|
+
# "agent_name": invocation_context.agent.name,
|
|
65
|
+
# "app_name": invocation_context.session.app_name,
|
|
66
|
+
# "user_id": invocation_context.user_id,
|
|
67
|
+
# "session_id": invocation_context.session.id,
|
|
68
|
+
# "input": invocation_context.user_content.model_dump(exclude_none=True)
|
|
69
|
+
# if invocation_context.user_content
|
|
70
|
+
# else None,
|
|
71
|
+
# }
|
|
72
|
+
|
|
73
|
+
user_content = invocation_context.user_content
|
|
74
|
+
if user_content and user_content.parts:
|
|
75
|
+
span.add_event(
|
|
76
|
+
"gen_ai.user.message",
|
|
77
|
+
{
|
|
78
|
+
"agent_name": invocation_context.agent.name,
|
|
79
|
+
"app_name": invocation_context.session.app_name,
|
|
80
|
+
"user_id": invocation_context.user_id,
|
|
81
|
+
"session_id": invocation_context.session.id,
|
|
82
|
+
},
|
|
83
|
+
)
|
|
84
|
+
for idx, part in enumerate(user_content.parts):
|
|
85
|
+
if part.text:
|
|
86
|
+
span.add_event(
|
|
87
|
+
"gen_ai.user.message",
|
|
88
|
+
{f"parts.{idx}.type": "text", f"parts.{idx}.content": part.text},
|
|
89
|
+
)
|
|
90
|
+
if part.inline_data:
|
|
91
|
+
span.add_event(
|
|
92
|
+
"gen_ai.user.message",
|
|
93
|
+
{
|
|
94
|
+
f"parts.{idx}.type": "image_url",
|
|
95
|
+
f"parts.{idx}.image_url.name": part.inline_data.display_name.split(
|
|
96
|
+
"/"
|
|
97
|
+
)[-1],
|
|
98
|
+
f"parts.{idx}.image_url.url": part.inline_data.display_name,
|
|
99
|
+
},
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _set_agent_output_attribute(span: _Span, llm_response: LlmResponse) -> None:
|
|
104
|
+
content = llm_response.content
|
|
105
|
+
if content and content.parts:
|
|
106
|
+
for idx, part in enumerate(content.parts):
|
|
107
|
+
if part.text:
|
|
108
|
+
span.add_event(
|
|
109
|
+
"gen_ai.choice",
|
|
110
|
+
{
|
|
111
|
+
f"message.parts.{idx}.type": "text",
|
|
112
|
+
f"message.parts.{idx}.text": part.text,
|
|
113
|
+
},
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def set_common_attributes_on_model_span(
|
|
118
|
+
invocation_context: InvocationContext,
|
|
119
|
+
llm_response: LlmResponse,
|
|
120
|
+
current_span: _Span,
|
|
121
|
+
**kwargs,
|
|
122
|
+
) -> None:
|
|
123
|
+
if current_span.context:
|
|
124
|
+
current_span_id = current_span.context.trace_id
|
|
125
|
+
else:
|
|
126
|
+
logger.warning(
|
|
127
|
+
"Current span context is missing, failed to get `trace_id` to set common attributes."
|
|
128
|
+
)
|
|
129
|
+
return
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
spans = _INMEMORY_EXPORTER_INSTANCE.processor.spans # type: ignore
|
|
133
|
+
|
|
134
|
+
spans_in_current_trace = [
|
|
135
|
+
span
|
|
136
|
+
for span in spans
|
|
137
|
+
if span.context and span.context.trace_id == current_span_id
|
|
138
|
+
]
|
|
139
|
+
|
|
140
|
+
common_attributes = ATTRIBUTES.get("common", {})
|
|
141
|
+
for span in spans_in_current_trace:
|
|
142
|
+
if span.is_recording():
|
|
143
|
+
if span.name.startswith("invocation"):
|
|
144
|
+
span.set_attribute("gen_ai.operation.name", "chain")
|
|
145
|
+
_set_agent_input_attribute(span, invocation_context)
|
|
146
|
+
_set_agent_output_attribute(span, llm_response)
|
|
147
|
+
elif span.name.startswith("agent_run"):
|
|
148
|
+
span.set_attribute("gen_ai.operation.name", "agent")
|
|
149
|
+
_set_agent_input_attribute(span, invocation_context)
|
|
150
|
+
_set_agent_output_attribute(span, llm_response)
|
|
151
|
+
for attr_name, attr_extractor in common_attributes.items():
|
|
152
|
+
value = attr_extractor(**kwargs)
|
|
153
|
+
span.set_attribute(attr_name, value)
|
|
154
|
+
except Exception as e:
|
|
155
|
+
logger.error(f"Failed to set common attributes for spans: {e}")
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def set_common_attributes_on_tool_span(current_span: _Span) -> None:
|
|
159
|
+
# find parent span (generally a llm span)
|
|
160
|
+
if not current_span.context:
|
|
161
|
+
logger.warning(
|
|
162
|
+
f"Get tool span's context failed. Skip setting common attributes for span {current_span.name}"
|
|
163
|
+
)
|
|
164
|
+
return
|
|
165
|
+
|
|
166
|
+
if not current_span.parent:
|
|
167
|
+
logger.warning(
|
|
168
|
+
f"Get tool span's parent failed. Skip setting common attributes for span {current_span.name}"
|
|
169
|
+
)
|
|
170
|
+
return
|
|
171
|
+
|
|
172
|
+
parent_span_id = current_span.parent.span_id
|
|
173
|
+
for span in _INMEMORY_EXPORTER_INSTANCE.processor.spans: # type: ignore
|
|
174
|
+
if span.context.span_id == parent_span_id:
|
|
175
|
+
common_attributes = ATTRIBUTES.get("common", {})
|
|
176
|
+
for attr_name in common_attributes.keys():
|
|
177
|
+
current_span.set_attribute(attr_name, span.attributes[attr_name])
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def trace_send_data(): ...
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def trace_tool_call(
|
|
184
|
+
tool: BaseTool,
|
|
185
|
+
args: dict[str, Any],
|
|
186
|
+
function_response_event: Event,
|
|
187
|
+
) -> None:
|
|
188
|
+
span = trace.get_current_span()
|
|
189
|
+
|
|
190
|
+
set_common_attributes_on_tool_span(current_span=span) # type: ignore
|
|
191
|
+
|
|
192
|
+
tool_attributes_mapping = ATTRIBUTES.get("tool", {})
|
|
193
|
+
params = ToolAttributesParams(tool, args, function_response_event)
|
|
194
|
+
|
|
195
|
+
for attr_name, attr_extractor in tool_attributes_mapping.items():
|
|
196
|
+
response: ExtractorResponse = attr_extractor(params)
|
|
197
|
+
ExtractorResponse.update_span(span, attr_name, response)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def trace_call_llm(
|
|
201
|
+
invocation_context: InvocationContext,
|
|
202
|
+
event_id: str,
|
|
203
|
+
llm_request: LlmRequest,
|
|
204
|
+
llm_response: LlmResponse,
|
|
205
|
+
) -> None:
|
|
206
|
+
span = trace.get_current_span()
|
|
207
|
+
|
|
208
|
+
from veadk.agent import Agent
|
|
209
|
+
|
|
210
|
+
set_common_attributes_on_model_span(
|
|
211
|
+
invocation_context=invocation_context,
|
|
212
|
+
llm_response=llm_response,
|
|
213
|
+
current_span=span, # type: ignore
|
|
214
|
+
agent_name=invocation_context.agent.name,
|
|
215
|
+
user_id=invocation_context.user_id,
|
|
216
|
+
app_name=invocation_context.app_name,
|
|
217
|
+
session_id=invocation_context.session.id,
|
|
218
|
+
model_provider=invocation_context.agent.model_provider
|
|
219
|
+
if isinstance(invocation_context.agent, Agent)
|
|
220
|
+
else "",
|
|
221
|
+
model_name=invocation_context.agent.model_name
|
|
222
|
+
if isinstance(invocation_context.agent, Agent)
|
|
223
|
+
else "",
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
llm_attributes_mapping = ATTRIBUTES.get("llm", {})
|
|
227
|
+
params = LLMAttributesParams(
|
|
228
|
+
invocation_context=invocation_context,
|
|
229
|
+
event_id=event_id,
|
|
230
|
+
llm_request=llm_request,
|
|
231
|
+
llm_response=llm_response,
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
for attr_name, attr_extractor in llm_attributes_mapping.items():
|
|
235
|
+
response: ExtractorResponse = attr_extractor(params)
|
|
236
|
+
ExtractorResponse.update_span(span, attr_name, response)
|
|
237
|
+
|
|
238
|
+
upload_metrics(invocation_context, llm_request, llm_response)
|
veadk/types.py
CHANGED
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
from pydantic import BaseModel, Field
|
|
16
16
|
|
|
17
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
|
|
18
21
|
from veadk.memory.short_term_memory import ShortTermMemory
|
|
19
22
|
|
|
20
23
|
|
|
@@ -35,7 +38,9 @@ class AgentRunConfig(BaseModel):
|
|
|
35
38
|
default="veadk_vefaas_app", description="The name of the application"
|
|
36
39
|
)
|
|
37
40
|
|
|
38
|
-
agent: Agent
|
|
41
|
+
agent: Agent | SequentialAgent | ParallelAgent | LoopAgent = Field(
|
|
42
|
+
..., description="The root agent instance"
|
|
43
|
+
)
|
|
39
44
|
|
|
40
45
|
short_term_memory: ShortTermMemory = Field(
|
|
41
46
|
default_factory=ShortTermMemory, description="The short-term memory instance"
|
veadk/utils/misc.py
CHANGED
|
@@ -13,9 +13,11 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
import importlib.util
|
|
16
|
+
import json
|
|
16
17
|
import sys
|
|
17
18
|
import time
|
|
18
19
|
import types
|
|
20
|
+
from typing import Any, Dict, List, MutableMapping, Tuple
|
|
19
21
|
|
|
20
22
|
import requests
|
|
21
23
|
|
|
@@ -27,7 +29,7 @@ def read_file(file_path):
|
|
|
27
29
|
return data
|
|
28
30
|
|
|
29
31
|
|
|
30
|
-
def formatted_timestamp():
|
|
32
|
+
def formatted_timestamp() -> str:
|
|
31
33
|
# YYYYMMDDHHMMSS
|
|
32
34
|
return time.strftime("%Y%m%d%H%M%S", time.localtime())
|
|
33
35
|
|
|
@@ -60,3 +62,41 @@ def load_module_from_file(module_name: str, file_path: str) -> types.ModuleType:
|
|
|
60
62
|
)
|
|
61
63
|
else:
|
|
62
64
|
raise ImportError(f"Could not load module {module_name} from {file_path}")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def flatten_dict(
|
|
68
|
+
d: MutableMapping[str, Any], parent_key: str = "", sep: str = "_"
|
|
69
|
+
) -> Dict[str, Any]:
|
|
70
|
+
"""Flatten a nested dictionary.
|
|
71
|
+
|
|
72
|
+
Input:
|
|
73
|
+
{"a": {"b": 1}}
|
|
74
|
+
Output:
|
|
75
|
+
{"a_b": 1}
|
|
76
|
+
"""
|
|
77
|
+
items: List[Tuple[str, Any]] = []
|
|
78
|
+
for k, v in d.items():
|
|
79
|
+
new_key = f"{parent_key}{sep}{k}" if parent_key else k
|
|
80
|
+
if isinstance(v, MutableMapping):
|
|
81
|
+
items.extend(flatten_dict(v, new_key, sep=sep).items())
|
|
82
|
+
else:
|
|
83
|
+
items.append((new_key, v))
|
|
84
|
+
return dict(items)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def safe_json_serialize(obj) -> str:
|
|
88
|
+
"""Convert any Python object to a JSON-serializable type or string.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
obj: The object to serialize.
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
The JSON-serialized object string or <non-serializable> if the object cannot be serialized.
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
return json.dumps(
|
|
99
|
+
obj, ensure_ascii=False, default=lambda o: "<not serializable>"
|
|
100
|
+
)
|
|
101
|
+
except (TypeError, OverflowError):
|
|
102
|
+
return "<not serializable>"
|
veadk/utils/patches.py
CHANGED
|
@@ -13,7 +13,14 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
import asyncio
|
|
16
|
+
import sys
|
|
17
|
+
from typing import Callable
|
|
16
18
|
|
|
19
|
+
from veadk.tracing.telemetry.telemetry import (
|
|
20
|
+
trace_call_llm,
|
|
21
|
+
trace_send_data,
|
|
22
|
+
trace_tool_call,
|
|
23
|
+
)
|
|
17
24
|
from veadk.utils.logger import get_logger
|
|
18
25
|
|
|
19
26
|
logger = get_logger(__name__)
|
|
@@ -53,3 +60,21 @@ def patch_asyncio():
|
|
|
53
60
|
raise
|
|
54
61
|
|
|
55
62
|
CancelScope.__exit__ = patched_cancel_scope_exit
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def patch_google_adk_telemetry() -> None:
|
|
66
|
+
trace_functions = {
|
|
67
|
+
"trace_tool_call": trace_tool_call,
|
|
68
|
+
"trace_call_llm": trace_call_llm,
|
|
69
|
+
"trace_send_data": trace_send_data,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
for mod_name, mod in sys.modules.items():
|
|
73
|
+
if mod_name.startswith("google.adk"):
|
|
74
|
+
for var_name in dir(mod):
|
|
75
|
+
var = getattr(mod, var_name, None)
|
|
76
|
+
if var_name in trace_functions.keys() and isinstance(var, Callable):
|
|
77
|
+
setattr(mod, var_name, trace_functions[var_name])
|
|
78
|
+
logger.debug(
|
|
79
|
+
f"Patch {mod_name} {var_name} with {trace_functions[var_name]}"
|
|
80
|
+
)
|
veadk/version.py
CHANGED