veadk-python 0.2.7__py3-none-any.whl → 0.2.9__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 (75) hide show
  1. veadk/agent.py +3 -2
  2. veadk/auth/veauth/opensearch_veauth.py +75 -0
  3. veadk/auth/veauth/postgresql_veauth.py +75 -0
  4. veadk/cli/cli.py +3 -1
  5. veadk/cli/cli_eval.py +160 -0
  6. veadk/cli/cli_prompt.py +9 -2
  7. veadk/cli/cli_web.py +6 -1
  8. veadk/configs/database_configs.py +43 -0
  9. veadk/configs/model_configs.py +32 -0
  10. veadk/consts.py +11 -4
  11. veadk/evaluation/adk_evaluator/adk_evaluator.py +5 -2
  12. veadk/evaluation/base_evaluator.py +95 -68
  13. veadk/evaluation/deepeval_evaluator/deepeval_evaluator.py +23 -15
  14. veadk/evaluation/eval_set_recorder.py +2 -2
  15. veadk/integrations/ve_prompt_pilot/ve_prompt_pilot.py +9 -3
  16. veadk/integrations/ve_tls/utils.py +1 -2
  17. veadk/integrations/ve_tls/ve_tls.py +9 -5
  18. veadk/integrations/ve_tos/ve_tos.py +542 -68
  19. veadk/knowledgebase/backends/base_backend.py +59 -0
  20. veadk/knowledgebase/backends/in_memory_backend.py +82 -0
  21. veadk/knowledgebase/backends/opensearch_backend.py +136 -0
  22. veadk/knowledgebase/backends/redis_backend.py +144 -0
  23. veadk/knowledgebase/backends/utils.py +91 -0
  24. veadk/knowledgebase/backends/vikingdb_knowledge_backend.py +524 -0
  25. veadk/{database/__init__.py → knowledgebase/entry.py} +10 -2
  26. veadk/knowledgebase/knowledgebase.py +120 -139
  27. veadk/memory/__init__.py +22 -0
  28. veadk/memory/long_term_memory.py +124 -41
  29. veadk/{database/base_database.py → memory/long_term_memory_backends/base_backend.py} +10 -22
  30. veadk/memory/long_term_memory_backends/in_memory_backend.py +65 -0
  31. veadk/memory/long_term_memory_backends/mem0_backend.py +129 -0
  32. veadk/memory/long_term_memory_backends/opensearch_backend.py +120 -0
  33. veadk/memory/long_term_memory_backends/redis_backend.py +127 -0
  34. veadk/memory/long_term_memory_backends/vikingdb_memory_backend.py +148 -0
  35. veadk/memory/short_term_memory.py +80 -72
  36. veadk/memory/short_term_memory_backends/base_backend.py +31 -0
  37. veadk/memory/short_term_memory_backends/mysql_backend.py +41 -0
  38. veadk/memory/short_term_memory_backends/postgresql_backend.py +41 -0
  39. veadk/memory/short_term_memory_backends/sqlite_backend.py +48 -0
  40. veadk/runner.py +12 -19
  41. veadk/tools/builtin_tools/generate_image.py +355 -0
  42. veadk/tools/builtin_tools/image_edit.py +56 -16
  43. veadk/tools/builtin_tools/image_generate.py +51 -15
  44. veadk/tools/builtin_tools/video_generate.py +41 -41
  45. veadk/tools/builtin_tools/web_scraper.py +1 -1
  46. veadk/tools/builtin_tools/web_search.py +7 -7
  47. veadk/tools/load_knowledgebase_tool.py +2 -8
  48. veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py +21 -3
  49. veadk/tracing/telemetry/exporters/apmplus_exporter.py +24 -6
  50. veadk/tracing/telemetry/exporters/cozeloop_exporter.py +2 -0
  51. veadk/tracing/telemetry/exporters/inmemory_exporter.py +22 -8
  52. veadk/tracing/telemetry/exporters/tls_exporter.py +2 -0
  53. veadk/tracing/telemetry/opentelemetry_tracer.py +13 -10
  54. veadk/tracing/telemetry/telemetry.py +66 -63
  55. veadk/utils/misc.py +15 -0
  56. veadk/version.py +1 -1
  57. {veadk_python-0.2.7.dist-info → veadk_python-0.2.9.dist-info}/METADATA +28 -5
  58. {veadk_python-0.2.7.dist-info → veadk_python-0.2.9.dist-info}/RECORD +65 -56
  59. veadk/database/database_adapter.py +0 -533
  60. veadk/database/database_factory.py +0 -80
  61. veadk/database/kv/redis_database.py +0 -159
  62. veadk/database/local_database.py +0 -62
  63. veadk/database/relational/mysql_database.py +0 -173
  64. veadk/database/vector/opensearch_vector_database.py +0 -263
  65. veadk/database/vector/type.py +0 -50
  66. veadk/database/viking/__init__.py +0 -13
  67. veadk/database/viking/viking_database.py +0 -638
  68. veadk/database/viking/viking_memory_db.py +0 -525
  69. /veadk/{database/kv → knowledgebase/backends}/__init__.py +0 -0
  70. /veadk/{database/relational → memory/long_term_memory_backends}/__init__.py +0 -0
  71. /veadk/{database/vector → memory/short_term_memory_backends}/__init__.py +0 -0
  72. {veadk_python-0.2.7.dist-info → veadk_python-0.2.9.dist-info}/WHEEL +0 -0
  73. {veadk_python-0.2.7.dist-info → veadk_python-0.2.9.dist-info}/entry_points.txt +0 -0
  74. {veadk_python-0.2.7.dist-info → veadk_python-0.2.9.dist-info}/licenses/LICENSE +0 -0
  75. {veadk_python-0.2.7.dist-info → veadk_python-0.2.9.dist-info}/top_level.txt +0 -0
@@ -17,7 +17,7 @@ import json
17
17
  import time
18
18
  import uuid
19
19
  from abc import abstractmethod
20
- from typing import Any
20
+ from typing import Any, Optional
21
21
 
22
22
  from google.adk import Runner
23
23
  from google.adk.evaluation.eval_set import EvalSet
@@ -120,56 +120,72 @@ class BaseEvaluator:
120
120
  # Extract tool_uses from spans with name starting with "execute_tool"
121
121
  for span in spans:
122
122
  if span["name"].startswith("execute_tool"):
123
+ # Extract tool parameters from gen_ai.tool.input
124
+ tool_input_str = span["attributes"].get("gen_ai.tool.input", "{}")
125
+ try:
126
+ tool_input = json.loads(tool_input_str)
127
+ tool_args = tool_input.get("parameters", {})
128
+ except json.JSONDecodeError:
129
+ tool_args = {}
130
+
131
+ # Extract the tool call ID from gen_ai.tool.output
132
+ tool_output_str = span["attributes"].get("gen_ai.tool.output", "{}")
133
+ tool_call_id = None
134
+ try:
135
+ tool_output = json.loads(tool_output_str)
136
+ tool_call_id = tool_output.get("id", None)
137
+ except json.JSONDecodeError:
138
+ tool_call_id = None
139
+
123
140
  tool_uses.append(
124
141
  {
125
- "id": span["attributes"].get("gen_ai.tool.call.id", None),
126
- "args": json.loads(
127
- span["attributes"].get(
128
- "gcp.vertex.agent.tool_call_args", "{}"
129
- )
130
- ),
142
+ "id": tool_call_id,
143
+ "args": tool_args,
131
144
  "name": span["attributes"].get("gen_ai.tool.name", None),
132
145
  }
133
146
  )
134
147
 
135
- # Extract conversation data from spans with name starting with "invocation"
136
- for span in spans:
137
- if span["name"].startswith("invocation"):
138
- # Parse input.value and output.value as JSON
139
- input_value = json.loads(
140
- span["attributes"].get("input.value", "{}")
141
- )
142
- output_value = json.loads(
143
- span["attributes"].get("output.value", "{}")
144
- )
148
+ # Extract conversation data from call_llm spans
149
+ user_input = ""
150
+ final_output = ""
145
151
 
146
- user_content = json.loads(input_value.get("new_message", {}))
147
- final_response = json.loads(json.dumps(user_content))
148
- final_response["parts"][0]["text"] = (
149
- output_value.get("content", {})
150
- .get("parts", [{}])[0]
151
- .get("text", None)
152
- )
153
- final_response["role"] = None
154
- conversation.append(
155
- {
156
- "invocation_id": output_value.get(
157
- "invocation_id", str(uuid.uuid4())
158
- ),
159
- "user_content": user_content,
160
- "final_response": final_response,
161
- "intermediate_data": {
162
- "tool_uses": tool_uses,
163
- "intermediate_responses": [],
164
- },
165
- "creation_timestamp": span["start_time"] / 1e9,
166
- }
167
- )
168
- user_id = input_value.get("user_id", None)
169
- app_name = (
170
- span["name"].replace("invocation", "").strip().strip("[]")
171
- )
172
- creation_timestamp = span["start_time"] / 1e9
152
+ # Find the first call_llm span for user input and the last one for final output
153
+ call_llm_spans = [span for span in spans if span["name"] == "call_llm"]
154
+
155
+ if call_llm_spans:
156
+ # Get user input from the first call_llm span
157
+ first_span = call_llm_spans[0]
158
+ user_input = first_span["attributes"].get("gen_ai.prompt.0.content", "")
159
+
160
+ # Get final output from the last call_llm span
161
+ last_span = call_llm_spans[-1]
162
+ final_output = last_span["attributes"].get(
163
+ "gen_ai.completion.0.content", ""
164
+ )
165
+
166
+ # Get metadata from any span
167
+ app_name = first_span["attributes"].get("gen_ai.app.name", "")
168
+ user_id = first_span["attributes"].get("gen_ai.user.id", "")
169
+ creation_timestamp = first_span["start_time"] / 1e9
170
+
171
+ if user_input and final_output:
172
+ # Create user_content and final_response in the expected format
173
+ user_content = {"role": "user", "parts": [{"text": user_input}]}
174
+
175
+ final_response = {"role": "model", "parts": [{"text": final_output}]}
176
+
177
+ conversation.append(
178
+ {
179
+ "invocation_id": str(uuid.uuid4()),
180
+ "user_content": user_content,
181
+ "final_response": final_response,
182
+ "intermediate_data": {
183
+ "tool_uses": tool_uses,
184
+ "intermediate_responses": [],
185
+ },
186
+ "creation_timestamp": creation_timestamp,
187
+ }
188
+ )
173
189
 
174
190
  eval_cases.append(
175
191
  {
@@ -194,33 +210,43 @@ class BaseEvaluator:
194
210
 
195
211
  return evalset
196
212
 
197
- def build_eval_set(self, file_path: str):
213
+ def build_eval_set(
214
+ self, eval_set: Optional[EvalSet] = None, file_path: Optional[str] = None
215
+ ):
198
216
  """Generate evaluation data from a given file and assign it to the class attribute `invocation_list`."""
199
- eval_case_data_list: list[EvalTestCase] = []
200
217
 
201
- try:
202
- with open(file_path, "r") as f:
203
- file_content = json.load(f)
204
- except json.JSONDecodeError as e:
205
- raise ValueError(f"Invalid JSON format in file {file_path}: {e}")
206
- except Exception as e:
207
- raise ValueError(f"Error reading file {file_path}: {e}")
208
-
209
- if isinstance(file_content, dict) and "eval_cases" in file_content:
210
- eval_cases = self._build_eval_set_from_eval_json(file_path).eval_cases
211
- elif (
212
- isinstance(file_content, list)
213
- and len(file_content) > 0
214
- and all(
215
- isinstance(span, dict) and "trace_id" in span for span in file_content
216
- )
217
- ):
218
- eval_cases = self._build_eval_set_from_tracing_json(file_path).eval_cases
218
+ if eval_set is None and file_path is None:
219
+ raise ValueError("eval_set or file_path is required")
220
+ if eval_set:
221
+ eval_cases = eval_set.eval_cases
219
222
  else:
220
- raise ValueError(
221
- f"Unsupported file format in {file_path}. Please provide a valid file."
222
- )
223
+ try:
224
+ with open(file_path, "r", encoding="utf-8") as f:
225
+ file_content = json.load(f)
226
+ except json.JSONDecodeError as e:
227
+ raise ValueError(f"Invalid JSON format in file {file_path}: {e}")
228
+ except Exception as e:
229
+ raise ValueError(f"Error reading file {file_path}: {e}")
230
+
231
+ if isinstance(file_content, dict) and "eval_cases" in file_content:
232
+ eval_cases = self._build_eval_set_from_eval_json(file_path).eval_cases
233
+ elif (
234
+ isinstance(file_content, list)
235
+ and len(file_content) > 0
236
+ and all(
237
+ isinstance(span, dict) and "trace_id" in span
238
+ for span in file_content
239
+ )
240
+ ):
241
+ eval_cases = self._build_eval_set_from_tracing_json(
242
+ file_path
243
+ ).eval_cases
244
+ else:
245
+ raise ValueError(
246
+ f"Unsupported file format in {file_path}. Please provide a valid file."
247
+ )
223
248
 
249
+ eval_case_data_list: list[EvalTestCase] = []
224
250
  for eval_case in eval_cases:
225
251
  eval_case_data = EvalTestCase(invocations=[])
226
252
  if eval_case.session_input:
@@ -368,8 +394,9 @@ class BaseEvaluator:
368
394
  @abstractmethod
369
395
  async def evaluate(
370
396
  self,
371
- eval_set_file_path: str,
372
397
  metrics: list[Any],
398
+ eval_set: Optional[EvalSet],
399
+ eval_set_file_path: Optional[str],
373
400
  eval_id: str,
374
401
  ):
375
402
  """An abstract method for evaluation based on metrics。"""
@@ -22,16 +22,16 @@ from deepeval.models import LocalModel
22
22
  from deepeval.test_case import LLMTestCase
23
23
  from deepeval.test_case.llm_test_case import ToolCall
24
24
  from typing_extensions import override
25
-
25
+ from typing import Optional
26
+ from google.adk.evaluation.eval_set import EvalSet
26
27
  from veadk.config import getenv
27
- from veadk.evaluation.types import EvalResultCaseData, EvalResultMetadata
28
- from veadk.utils.logger import get_logger
29
-
30
28
  from veadk.evaluation.base_evaluator import BaseEvaluator, EvalResultData, MetricResult
29
+ from veadk.evaluation.types import EvalResultCaseData, EvalResultMetadata
31
30
  from veadk.evaluation.utils.prometheus import (
32
31
  PrometheusPushgatewayConfig,
33
32
  push_to_prometheus,
34
33
  )
34
+ from veadk.utils.logger import get_logger
35
35
 
36
36
  logger = get_logger(__name__)
37
37
 
@@ -45,20 +45,27 @@ class DeepevalEvaluator(BaseEvaluator):
45
45
  def __init__(
46
46
  self,
47
47
  agent,
48
- judge_model_api_key: str = getenv("MODEL_JUDGE_API_KEY"),
49
- judge_model_name: str = getenv(
50
- "MODEL_JUDGE_NAME",
51
- "doubao-seed-1-6-250615",
52
- ),
53
- judge_model_api_base: str = getenv(
54
- "MODEL_JUDGE_API_BASE",
55
- "https://ark.cn-beijing.volces.com/api/v3/",
56
- ),
48
+ judge_model_api_key: str = "",
49
+ judge_model_name: str = "",
50
+ judge_model_api_base: str = "",
57
51
  name: str = "veadk_deepeval_evaluator",
58
52
  prometheus_config: PrometheusPushgatewayConfig | None = None,
59
53
  ):
60
54
  super().__init__(agent=agent, name=name)
61
55
 
56
+ if not judge_model_api_key:
57
+ judge_model_api_key = getenv("MODEL_JUDGE_API_KEY")
58
+ if not judge_model_name:
59
+ judge_model_name = getenv(
60
+ "MODEL_JUDGE_NAME",
61
+ "doubao-seed-1-6-250615",
62
+ )
63
+ if not judge_model_api_base:
64
+ judge_model_api_base = getenv(
65
+ "MODEL_JUDGE_API_BASE",
66
+ "https://ark.cn-beijing.volces.com/api/v3/",
67
+ )
68
+
62
69
  self.judge_model_name = judge_model_name
63
70
  self.judge_model = LocalModel(
64
71
  model=judge_model_name,
@@ -71,13 +78,14 @@ class DeepevalEvaluator(BaseEvaluator):
71
78
  @override
72
79
  async def evaluate(
73
80
  self,
74
- eval_set_file_path: str,
75
81
  metrics: list[BaseMetric],
82
+ eval_set: Optional[EvalSet] = None,
83
+ eval_set_file_path: Optional[str] = None,
76
84
  eval_id: str = f"test_{formatted_timestamp()}",
77
85
  ):
78
86
  """Target to Google ADK, we will use the same evaluation case format as Google ADK."""
79
87
  # Get evaluation data by parsing eval set file
80
- self.build_eval_set(eval_set_file_path)
88
+ self.build_eval_set(eval_set, eval_set_file_path)
81
89
 
82
90
  # Get actual data by running agent
83
91
  logger.info("Start to run agent for actual data.")
@@ -21,7 +21,7 @@ from google.adk.evaluation.local_eval_sets_manager import LocalEvalSetsManager
21
21
  from google.adk.sessions import BaseSessionService
22
22
 
23
23
  from veadk.utils.logger import get_logger
24
- from veadk.utils.misc import formatted_timestamp
24
+ from veadk.utils.misc import formatted_timestamp, get_temp_dir
25
25
 
26
26
  logger = get_logger(__name__)
27
27
 
@@ -30,7 +30,7 @@ class EvalSetRecorder(LocalEvalSetsManager):
30
30
  def __init__(
31
31
  self, session_service: BaseSessionService, eval_set_id: str = "default"
32
32
  ):
33
- super().__init__(agents_dir="/tmp/")
33
+ super().__init__(agents_dir=get_temp_dir())
34
34
  self.eval_set_id = eval_set_id if eval_set_id != "" else "default"
35
35
  self.session_service: BaseSessionService = session_service
36
36
 
@@ -16,7 +16,6 @@ from __future__ import annotations
16
16
 
17
17
  import agent_pilot as ap
18
18
  from agent_pilot.models import TaskType
19
-
20
19
  from veadk import Agent
21
20
  from veadk.prompts import prompt_optimization
22
21
  from veadk.utils.logger import get_logger
@@ -26,9 +25,15 @@ logger = get_logger(__name__)
26
25
 
27
26
  class VePromptPilot:
28
27
  def __init__(
29
- self, api_key: str, path: str = "", task_id: str | None = None
28
+ self,
29
+ api_key: str,
30
+ workspace_id: str,
31
+ path: str = "",
32
+ task_id: str | None = None,
30
33
  ) -> None:
31
34
  self.api_key = api_key
35
+ self.workspace_id = workspace_id
36
+
32
37
  self.path = path
33
38
 
34
39
  def optimize(
@@ -57,12 +62,13 @@ class VePromptPilot:
57
62
  usage = None
58
63
  for chunk in ap.generate_prompt_stream(
59
64
  task_description=task_description,
60
- current_prompt=agent.instruction,
65
+ current_prompt=str(agent.instruction),
61
66
  model_name=model_name,
62
67
  task_type=TaskType.DIALOG,
63
68
  temperature=1.0,
64
69
  top_p=0.7,
65
70
  api_key=self.api_key,
71
+ workspace_id=self.workspace_id,
66
72
  ): # stream chunks of optimized prompt
67
73
  # Process each chunk as it arrives
68
74
  optimized_prompt += chunk.data.content if chunk.data else ""
@@ -17,6 +17,7 @@ import json
17
17
  from typing import Any, Literal
18
18
 
19
19
  import httpx
20
+ from veadk.utils.logger import get_logger
20
21
  from volcengine.ApiInfo import ApiInfo
21
22
  from volcengine.auth.SignerV4 import SignerV4
22
23
  from volcengine.tls.const import (
@@ -28,8 +29,6 @@ from volcengine.tls.const import (
28
29
  )
29
30
  from volcengine.tls.TLSService import TLSService
30
31
 
31
- from veadk.utils.logger import get_logger
32
-
33
32
  logger = get_logger(__name__)
34
33
 
35
34
  HEADER_API_VERSION = "x-tls-apiversion"
@@ -28,9 +28,8 @@ class VeTLS:
28
28
  region: str = "cn-beijing",
29
29
  ):
30
30
  try:
31
- from volcengine.tls.TLSService import TLSService
32
-
33
31
  from veadk.integrations.ve_tls.utils import ve_tls_request
32
+ from volcengine.tls.TLSService import TLSService
34
33
  except ImportError:
35
34
  raise ImportError(
36
35
  "Please install volcengine SDK before init VeTLS: pip install volcengine"
@@ -162,11 +161,12 @@ class VeTLS:
162
161
  client=self._client,
163
162
  api="CreateTraceInstance",
164
163
  body=request_body,
164
+ request_headers={"TraceTag": "veadk"},
165
165
  )
166
166
 
167
- if res["ErrorCode"] == "TopicAlreadyExist":
167
+ if "ErrorCode" in res and res["ErrorCode"] == "TopicAlreadyExist":
168
168
  logger.debug(
169
- f"Log project '{trace_instance_name}' already exists. Check its ID."
169
+ f"Tracing instance '{trace_instance_name}' already exists. Check its ID."
170
170
  )
171
171
  return self.get_trace_instance_by_name(
172
172
  log_project_id, trace_instance_name
@@ -176,10 +176,14 @@ class VeTLS:
176
176
  res = self._ve_tls_request(
177
177
  client=self._client,
178
178
  api="DescribeTraceInstance",
179
- body={"TraceInstanceID": res["TraceInstanceID"]},
179
+ params={"TraceInstanceId": res["TraceInstanceId"]},
180
180
  method="GET",
181
181
  )
182
182
 
183
+ logger.info(
184
+ f"Create tracing instance finished, tracing instance ID: {res['TraceInstanceId']}"
185
+ )
186
+
183
187
  return res
184
188
  except KeyError:
185
189
  raise ValueError(f"Failed to create tracing instance: {res}")