veadk-python 0.2.5__py3-none-any.whl → 0.2.6__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 (52) hide show
  1. veadk/agent.py +19 -7
  2. veadk/cli/cli_deploy.py +2 -0
  3. veadk/cli/cli_init.py +25 -6
  4. veadk/consts.py +20 -1
  5. veadk/database/database_adapter.py +88 -0
  6. veadk/database/kv/redis_database.py +47 -0
  7. veadk/database/local_database.py +22 -4
  8. veadk/database/relational/mysql_database.py +58 -0
  9. veadk/database/vector/opensearch_vector_database.py +6 -3
  10. veadk/database/viking/viking_database.py +69 -0
  11. veadk/integrations/ve_cr/__init__.py +13 -0
  12. veadk/integrations/ve_cr/ve_cr.py +205 -0
  13. veadk/integrations/ve_faas/template/cookiecutter.json +2 -1
  14. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/app.py +24 -1
  15. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/requirements.txt +3 -1
  16. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/run.sh +0 -7
  17. veadk/integrations/ve_faas/ve_faas.py +2 -0
  18. veadk/integrations/ve_faas/web_template/cookiecutter.json +17 -0
  19. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/__init__.py +13 -0
  20. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/clean.py +23 -0
  21. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/config.yaml.example +2 -0
  22. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/deploy.py +41 -0
  23. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/Dockerfile +23 -0
  24. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/app.py +123 -0
  25. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/init_db.py +46 -0
  26. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/models.py +36 -0
  27. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/requirements.txt +4 -0
  28. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/run.sh +21 -0
  29. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/css/style.css +368 -0
  30. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/js/admin.js +0 -0
  31. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/dashboard.html +21 -0
  32. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/edit_post.html +24 -0
  33. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/login.html +21 -0
  34. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/posts.html +53 -0
  35. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/base.html +45 -0
  36. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/index.html +29 -0
  37. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/post.html +14 -0
  38. veadk/integrations/ve_tos/ve_tos.py +92 -30
  39. veadk/knowledgebase/knowledgebase.py +8 -0
  40. veadk/runner.py +49 -16
  41. veadk/tracing/telemetry/attributes/extractors/common_attributes_extractors.py +5 -0
  42. veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py +253 -129
  43. veadk/tracing/telemetry/attributes/extractors/types.py +15 -4
  44. veadk/tracing/telemetry/opentelemetry_tracer.py +11 -5
  45. veadk/tracing/telemetry/telemetry.py +19 -4
  46. veadk/version.py +1 -1
  47. {veadk_python-0.2.5.dist-info → veadk_python-0.2.6.dist-info}/METADATA +1 -1
  48. {veadk_python-0.2.5.dist-info → veadk_python-0.2.6.dist-info}/RECORD +52 -30
  49. {veadk_python-0.2.5.dist-info → veadk_python-0.2.6.dist-info}/WHEEL +0 -0
  50. {veadk_python-0.2.5.dist-info → veadk_python-0.2.6.dist-info}/entry_points.txt +0 -0
  51. {veadk_python-0.2.5.dist-info → veadk_python-0.2.6.dist-info}/licenses/LICENSE +0 -0
  52. {veadk_python-0.2.5.dist-info → veadk_python-0.2.6.dist-info}/top_level.txt +0 -0
@@ -15,7 +15,6 @@
15
15
  import os
16
16
  from veadk.config import getenv
17
17
  from veadk.utils.logger import get_logger
18
- import tos
19
18
  import asyncio
20
19
  from typing import Union
21
20
  from pydantic import BaseModel, Field
@@ -23,8 +22,20 @@ from typing import Any
23
22
  from urllib.parse import urlparse
24
23
  from datetime import datetime
25
24
 
25
+ # Initialize logger before using it
26
26
  logger = get_logger(__name__)
27
27
 
28
+ # Try to import tos module, and provide helpful error message if it fails
29
+ try:
30
+ import tos
31
+ except ImportError as e:
32
+ logger.error(
33
+ "Failed to import 'tos' module. Please install it using: pip install tos\n"
34
+ )
35
+ raise ImportError(
36
+ "Missing 'tos' module. Please install it using: pip install tos\n"
37
+ ) from e
38
+
28
39
 
29
40
  class TOSConfig(BaseModel):
30
41
  region: str = Field(
@@ -59,25 +70,76 @@ class VeTOS(BaseModel):
59
70
  logger.info("Connected to TOS successfully.")
60
71
  except Exception as e:
61
72
  logger.error(f"Client initialization failed:{e}")
62
- return None
73
+ self._client = None
74
+
75
+ def _refresh_client(self):
76
+ try:
77
+ if self._client:
78
+ self._client.close()
79
+ self._client = tos.TosClientV2(
80
+ self.config.ak,
81
+ self.config.sk,
82
+ endpoint=f"tos-{self.config.region}.volces.com",
83
+ region=self.config.region,
84
+ )
85
+ logger.info("refreshed client successfully.")
86
+ except Exception as e:
87
+ logger.error(f"Failed to refresh client: {str(e)}")
88
+ self._client = None
63
89
 
64
90
  def create_bucket(self) -> bool:
65
- """If the bucket does not exist, create it"""
91
+ """If the bucket does not exist, create it and set CORS rules"""
92
+ if not self._client:
93
+ logger.error("TOS client is not initialized")
94
+ return False
66
95
  try:
67
96
  self._client.head_bucket(self.config.bucket_name)
68
97
  logger.info(f"Bucket {self.config.bucket_name} already exists")
69
- return True
70
98
  except tos.exceptions.TosServerError as e:
71
99
  if e.status_code == 404:
72
- self._client.create_bucket(
73
- bucket=self.config.bucket_name,
74
- storage_class=tos.StorageClassType.Storage_Class_Standard,
75
- acl=tos.ACLType.ACL_Private,
76
- )
77
- logger.info(f"Bucket {self.config.bucket_name} created successfully")
78
- return True
100
+ try:
101
+ self._client.create_bucket(
102
+ bucket=self.config.bucket_name,
103
+ storage_class=tos.StorageClassType.Storage_Class_Standard,
104
+ acl=tos.ACLType.ACL_Public_Read, # 公开读
105
+ )
106
+ logger.info(
107
+ f"Bucket {self.config.bucket_name} created successfully"
108
+ )
109
+ self._refresh_client()
110
+ except Exception as create_error:
111
+ logger.error(f"Bucket creation failed: {str(create_error)}")
112
+ return False
113
+ else:
114
+ logger.error(f"Bucket check failed: {str(e)}")
115
+ return False
116
+ except Exception as e:
117
+ logger.error(f"Bucket check failed: {str(e)}")
118
+ return False
119
+
120
+ # 确保在所有路径上返回布尔值
121
+ return self._set_cors_rules()
122
+
123
+ def _set_cors_rules(self) -> bool:
124
+ if not self._client:
125
+ logger.error("TOS client is not initialized")
126
+ return False
127
+ try:
128
+ rule = tos.models2.CORSRule(
129
+ allowed_origins=["*"],
130
+ allowed_methods=["GET", "HEAD"],
131
+ allowed_headers=["*"],
132
+ max_age_seconds=1000,
133
+ )
134
+ self._client.put_bucket_cors(self.config.bucket_name, [rule])
135
+ logger.info(
136
+ f"CORS rules for bucket {self.config.bucket_name} set successfully"
137
+ )
138
+ return True
79
139
  except Exception as e:
80
- logger.error(f"Bucket creation failed: {str(e)}")
140
+ logger.error(
141
+ f"Failed to set CORS rules for bucket {self.config.bucket_name}: {str(e)}"
142
+ )
81
143
  return False
82
144
 
83
145
  def build_tos_url(
@@ -103,55 +165,55 @@ class VeTOS(BaseModel):
103
165
  data: Union[str, bytes],
104
166
  ):
105
167
  if isinstance(data, str):
106
- data_type = "file"
168
+ # data is a file path
169
+ return asyncio.to_thread(self._do_upload_file, object_key, data)
107
170
  elif isinstance(data, bytes):
108
- data_type = "bytes"
171
+ # data is bytes content
172
+ return asyncio.to_thread(self._do_upload_bytes, object_key, data)
109
173
  else:
110
174
  error_msg = f"Upload failed: data type error. Only str (file path) and bytes are supported, got {type(data)}"
111
175
  logger.error(error_msg)
112
176
  raise ValueError(error_msg)
113
- if data_type == "file":
114
- return asyncio.to_thread(self._do_upload_file, object_key, data)
115
- elif data_type == "bytes":
116
- return asyncio.to_thread(self._do_upload_bytes, object_key, data)
117
177
 
118
- def _do_upload_bytes(self, object_key: str, bytes: bytes) -> bool:
178
+ def _do_upload_bytes(self, object_key: str, data: bytes) -> None:
119
179
  try:
120
180
  if not self._client:
121
- return False
181
+ return
122
182
  if not self.create_bucket():
123
- return False
183
+ return
124
184
  self._client.put_object(
125
- bucket=self.config.bucket_name, key=object_key, content=bytes
185
+ bucket=self.config.bucket_name, key=object_key, content=data
126
186
  )
127
187
  logger.debug(f"Upload success, object_key: {object_key}")
128
188
  self._close()
129
- return True
189
+ return
130
190
  except Exception as e:
131
191
  logger.error(f"Upload failed: {e}")
132
192
  self._close()
133
- return False
193
+ return
134
194
 
135
- def _do_upload_file(self, object_key: str, file_path: str) -> bool:
195
+ def _do_upload_file(self, object_key: str, file_path: str) -> None:
136
196
  try:
137
197
  if not self._client:
138
- return False
198
+ return
139
199
  if not self.create_bucket():
140
- return False
141
-
200
+ return
142
201
  self._client.put_object_from_file(
143
202
  bucket=self.config.bucket_name, key=object_key, file_path=file_path
144
203
  )
145
204
  self._close()
146
205
  logger.debug(f"Upload success, object_key: {object_key}")
147
- return True
206
+ return
148
207
  except Exception as e:
149
208
  logger.error(f"Upload failed: {e}")
150
209
  self._close()
151
- return False
210
+ return
152
211
 
153
212
  def download(self, object_key: str, save_path: str) -> bool:
154
213
  """download image from TOS"""
214
+ if not self._client:
215
+ logger.error("TOS client is not initialized")
216
+ return False
155
217
  try:
156
218
  object_stream = self._client.get_object(self.config.bucket_name, object_key)
157
219
 
@@ -80,3 +80,11 @@ class KnowledgeBase:
80
80
  if len(result) == 0:
81
81
  logger.warning(f"No documents found in knowledgebase. Query: {query}")
82
82
  return result
83
+
84
+ def delete_doc(self, app_name: str, id: str) -> bool:
85
+ index = build_knowledgebase_index(app_name)
86
+ return self.adapter.delete_doc(index=index, id=id)
87
+
88
+ def list_docs(self, app_name: str, offset: int = 0, limit: int = 100) -> list[dict]:
89
+ index = build_knowledgebase_index(app_name)
90
+ return self.adapter.list_docs(index=index, offset=offset, limit=limit)
veadk/runner.py CHANGED
@@ -27,12 +27,12 @@ from veadk.agent import Agent
27
27
  from veadk.agents.loop_agent import LoopAgent
28
28
  from veadk.agents.parallel_agent import ParallelAgent
29
29
  from veadk.agents.sequential_agent import SequentialAgent
30
+ from veadk.config import getenv
30
31
  from veadk.evaluation import EvalSetRecorder
31
32
  from veadk.memory.short_term_memory import ShortTermMemory
32
33
  from veadk.types import MediaMessage
33
34
  from veadk.utils.logger import get_logger
34
35
  from veadk.utils.misc import read_png_to_bytes
35
- from veadk.integrations.ve_tos.ve_tos import VeTOS
36
36
 
37
37
  logger = get_logger(__name__)
38
38
 
@@ -86,7 +86,9 @@ class Runner:
86
86
  plugins=plugins,
87
87
  )
88
88
 
89
- def _convert_messages(self, messages, session_id) -> list:
89
+ def _convert_messages(
90
+ self, messages, session_id, upload_inline_data_to_tos
91
+ ) -> list:
90
92
  if isinstance(messages, str):
91
93
  messages = [types.Content(role="user", parts=[types.Part(text=messages)])]
92
94
  elif isinstance(messages, MediaMessage):
@@ -94,16 +96,26 @@ class Runner:
94
96
  "The MediaMessage only supports PNG format file for now."
95
97
  )
96
98
  data = read_png_to_bytes(messages.media)
97
-
98
- ve_tos = VeTOS()
99
- object_key, tos_url = ve_tos.build_tos_url(
100
- self.user_id, self.app_name, session_id, messages.media
101
- )
102
- try:
103
- asyncio.create_task(ve_tos.upload(object_key, data))
104
- except Exception as e:
105
- logger.error(f"Upload to TOS failed: {e}")
106
- tos_url = None
99
+ tos_url = "<tos_url>"
100
+ if upload_inline_data_to_tos:
101
+ try:
102
+ from veadk.integrations.ve_tos.ve_tos import VeTOS
103
+
104
+ ve_tos = VeTOS()
105
+ object_key, tos_url = ve_tos.build_tos_url(
106
+ self.user_id, self.app_name, session_id, messages.media
107
+ )
108
+ upload_task = ve_tos.upload(object_key, data)
109
+ if upload_task is not None:
110
+ asyncio.create_task(upload_task)
111
+ except Exception as e:
112
+ logger.error(f"Upload to TOS failed: {e}")
113
+ tos_url = None
114
+
115
+ else:
116
+ logger.warning(
117
+ "Loss of multimodal data may occur in the tracing process."
118
+ )
107
119
 
108
120
  messages = [
109
121
  types.Content(
@@ -123,7 +135,11 @@ class Runner:
123
135
  elif isinstance(messages, list):
124
136
  converted_messages = []
125
137
  for message in messages:
126
- converted_messages.extend(self._convert_messages(message, session_id))
138
+ converted_messages.extend(
139
+ self._convert_messages(
140
+ message, session_id, upload_inline_data_to_tos
141
+ )
142
+ )
127
143
  messages = converted_messages
128
144
  else:
129
145
  raise ValueError(f"Unknown message type: {type(messages)}")
@@ -142,7 +158,13 @@ class Runner:
142
158
  if run_config is not None:
143
159
  stream_mode = run_config.streaming_mode
144
160
  else:
145
- run_config = RunConfig(streaming_mode=stream_mode)
161
+ run_config = RunConfig(
162
+ streaming_mode=stream_mode,
163
+ max_llm_calls=int(getenv("MODEL_AGENT_MAX_LLM_CALLS", 100)),
164
+ )
165
+
166
+ logger.info(f"Run config: {run_config}")
167
+
146
168
  try:
147
169
 
148
170
  async def event_generator():
@@ -172,6 +194,7 @@ class Runner:
172
194
  print() # end with a new line
173
195
  except LlmCallsLimitExceededError as e:
174
196
  logger.warning(f"Max number of llm calls limit exceeded: {e}")
197
+ final_output = ""
175
198
 
176
199
  return final_output
177
200
 
@@ -182,8 +205,11 @@ class Runner:
182
205
  stream: bool = False,
183
206
  run_config: RunConfig | None = None,
184
207
  save_tracing_data: bool = False,
208
+ upload_inline_data_to_tos: bool = False,
185
209
  ):
186
- converted_messages: list = self._convert_messages(messages, session_id)
210
+ converted_messages: list = self._convert_messages(
211
+ messages, session_id, upload_inline_data_to_tos
212
+ )
187
213
 
188
214
  await self.short_term_memory.create_session(
189
215
  app_name=self.app_name, user_id=self.user_id, session_id=session_id
@@ -231,7 +257,13 @@ class Runner:
231
257
  session_id: str,
232
258
  run_config: RunConfig | None = None,
233
259
  ):
234
- run_config = RunConfig() if not run_config else run_config
260
+ run_config = (
261
+ RunConfig(max_llm_calls=int(getenv("MODEL_AGENT_MAX_LLM_CALLS", 100)))
262
+ if not run_config
263
+ else run_config
264
+ )
265
+
266
+ logger.info(f"Run config: {run_config}")
235
267
 
236
268
  await self.short_term_memory.create_session(
237
269
  app_name=self.app_name, user_id=self.user_id, session_id=session_id
@@ -263,6 +295,7 @@ class Runner:
263
295
  final_output += chunk
264
296
  except LlmCallsLimitExceededError as e:
265
297
  logger.warning(f"Max number of llm calls limit exceeded: {e}")
298
+ final_output = ""
266
299
 
267
300
  return final_output
268
301
 
@@ -49,6 +49,10 @@ def common_cozeloop_report_source(**kwargs) -> str:
49
49
  return "veadk"
50
50
 
51
51
 
52
+ def common_cozeloop_call_type(**kwargs) -> str:
53
+ return kwargs.get("call_type")
54
+
55
+
52
56
  def llm_openinference_instrumentation_veadk(**kwargs) -> str:
53
57
  return VERSION
54
58
 
@@ -68,4 +72,5 @@ COMMON_ATTRIBUTES = {
68
72
  "user.id": common_gen_ai_user_id, # CozeLoop / TLS required
69
73
  "session.id": common_gen_ai_session_id, # CozeLoop / TLS required
70
74
  "cozeloop.report.source": common_cozeloop_report_source, # CozeLoop required
75
+ "cozeloop.call_type": common_cozeloop_call_type, # CozeLoop required
71
76
  }