veadk-python 0.2.27__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. veadk/__init__.py +37 -0
  2. veadk/a2a/__init__.py +13 -0
  3. veadk/a2a/agent_card.py +45 -0
  4. veadk/a2a/remote_ve_agent.py +390 -0
  5. veadk/a2a/utils/__init__.py +13 -0
  6. veadk/a2a/utils/agent_to_a2a.py +170 -0
  7. veadk/a2a/ve_a2a_server.py +93 -0
  8. veadk/a2a/ve_agent_executor.py +78 -0
  9. veadk/a2a/ve_middlewares.py +313 -0
  10. veadk/a2a/ve_task_store.py +37 -0
  11. veadk/agent.py +402 -0
  12. veadk/agent_builder.py +93 -0
  13. veadk/agents/loop_agent.py +68 -0
  14. veadk/agents/parallel_agent.py +72 -0
  15. veadk/agents/sequential_agent.py +64 -0
  16. veadk/auth/__init__.py +13 -0
  17. veadk/auth/base_auth.py +22 -0
  18. veadk/auth/ve_credential_service.py +203 -0
  19. veadk/auth/veauth/__init__.py +13 -0
  20. veadk/auth/veauth/apmplus_veauth.py +58 -0
  21. veadk/auth/veauth/ark_veauth.py +75 -0
  22. veadk/auth/veauth/base_veauth.py +50 -0
  23. veadk/auth/veauth/cozeloop_veauth.py +13 -0
  24. veadk/auth/veauth/opensearch_veauth.py +75 -0
  25. veadk/auth/veauth/postgresql_veauth.py +75 -0
  26. veadk/auth/veauth/prompt_pilot_veauth.py +60 -0
  27. veadk/auth/veauth/speech_veauth.py +54 -0
  28. veadk/auth/veauth/utils.py +69 -0
  29. veadk/auth/veauth/vesearch_veauth.py +62 -0
  30. veadk/auth/veauth/viking_mem0_veauth.py +91 -0
  31. veadk/cli/__init__.py +13 -0
  32. veadk/cli/cli.py +58 -0
  33. veadk/cli/cli_clean.py +87 -0
  34. veadk/cli/cli_create.py +163 -0
  35. veadk/cli/cli_deploy.py +233 -0
  36. veadk/cli/cli_eval.py +215 -0
  37. veadk/cli/cli_init.py +214 -0
  38. veadk/cli/cli_kb.py +110 -0
  39. veadk/cli/cli_pipeline.py +285 -0
  40. veadk/cli/cli_prompt.py +86 -0
  41. veadk/cli/cli_update.py +106 -0
  42. veadk/cli/cli_uploadevalset.py +139 -0
  43. veadk/cli/cli_web.py +143 -0
  44. veadk/cloud/__init__.py +13 -0
  45. veadk/cloud/cloud_agent_engine.py +485 -0
  46. veadk/cloud/cloud_app.py +475 -0
  47. veadk/config.py +115 -0
  48. veadk/configs/__init__.py +13 -0
  49. veadk/configs/auth_configs.py +133 -0
  50. veadk/configs/database_configs.py +132 -0
  51. veadk/configs/model_configs.py +78 -0
  52. veadk/configs/tool_configs.py +54 -0
  53. veadk/configs/tracing_configs.py +110 -0
  54. veadk/consts.py +74 -0
  55. veadk/evaluation/__init__.py +17 -0
  56. veadk/evaluation/adk_evaluator/__init__.py +17 -0
  57. veadk/evaluation/adk_evaluator/adk_evaluator.py +302 -0
  58. veadk/evaluation/base_evaluator.py +642 -0
  59. veadk/evaluation/deepeval_evaluator/__init__.py +17 -0
  60. veadk/evaluation/deepeval_evaluator/deepeval_evaluator.py +339 -0
  61. veadk/evaluation/eval_set_file_loader.py +48 -0
  62. veadk/evaluation/eval_set_recorder.py +146 -0
  63. veadk/evaluation/types.py +65 -0
  64. veadk/evaluation/utils/prometheus.py +196 -0
  65. veadk/integrations/__init__.py +13 -0
  66. veadk/integrations/ve_apig/__init__.py +13 -0
  67. veadk/integrations/ve_apig/ve_apig.py +349 -0
  68. veadk/integrations/ve_apig/ve_apig_utils.py +332 -0
  69. veadk/integrations/ve_code_pipeline/__init__.py +13 -0
  70. veadk/integrations/ve_code_pipeline/ve_code_pipeline.py +431 -0
  71. veadk/integrations/ve_cozeloop/__init__.py +13 -0
  72. veadk/integrations/ve_cozeloop/ve_cozeloop.py +96 -0
  73. veadk/integrations/ve_cr/__init__.py +13 -0
  74. veadk/integrations/ve_cr/ve_cr.py +220 -0
  75. veadk/integrations/ve_faas/__init__.py +13 -0
  76. veadk/integrations/ve_faas/template/cookiecutter.json +15 -0
  77. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/__init__.py +13 -0
  78. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/clean.py +23 -0
  79. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/config.yaml.example +6 -0
  80. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/deploy.py +106 -0
  81. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/__init__.py +13 -0
  82. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/agent.py +25 -0
  83. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/app.py +202 -0
  84. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/requirements.txt +3 -0
  85. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/run.sh +49 -0
  86. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{ cookiecutter.app_name }}/__init__.py +14 -0
  87. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{ cookiecutter.app_name }}/agent.py +27 -0
  88. veadk/integrations/ve_faas/ve_faas.py +754 -0
  89. veadk/integrations/ve_faas/ve_faas_utils.py +408 -0
  90. veadk/integrations/ve_faas/web_template/cookiecutter.json +20 -0
  91. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/__init__.py +13 -0
  92. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/clean.py +23 -0
  93. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/config.yaml.example +2 -0
  94. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/deploy.py +44 -0
  95. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/Dockerfile +23 -0
  96. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/app.py +123 -0
  97. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/init_db.py +46 -0
  98. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/models.py +36 -0
  99. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/requirements.txt +4 -0
  100. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/run.sh +21 -0
  101. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/css/style.css +368 -0
  102. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/js/admin.js +0 -0
  103. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/dashboard.html +21 -0
  104. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/edit_post.html +24 -0
  105. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/login.html +21 -0
  106. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/posts.html +53 -0
  107. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/base.html +45 -0
  108. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/index.html +29 -0
  109. veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/post.html +14 -0
  110. veadk/integrations/ve_identity/__init__.py +110 -0
  111. veadk/integrations/ve_identity/auth_config.py +261 -0
  112. veadk/integrations/ve_identity/auth_mixins.py +650 -0
  113. veadk/integrations/ve_identity/auth_processor.py +385 -0
  114. veadk/integrations/ve_identity/function_tool.py +158 -0
  115. veadk/integrations/ve_identity/identity_client.py +864 -0
  116. veadk/integrations/ve_identity/mcp_tool.py +181 -0
  117. veadk/integrations/ve_identity/mcp_toolset.py +431 -0
  118. veadk/integrations/ve_identity/models.py +228 -0
  119. veadk/integrations/ve_identity/token_manager.py +188 -0
  120. veadk/integrations/ve_identity/utils.py +151 -0
  121. veadk/integrations/ve_prompt_pilot/__init__.py +13 -0
  122. veadk/integrations/ve_prompt_pilot/ve_prompt_pilot.py +85 -0
  123. veadk/integrations/ve_tls/__init__.py +13 -0
  124. veadk/integrations/ve_tls/utils.py +116 -0
  125. veadk/integrations/ve_tls/ve_tls.py +212 -0
  126. veadk/integrations/ve_tos/ve_tos.py +710 -0
  127. veadk/integrations/ve_viking_db_memory/__init__.py +13 -0
  128. veadk/integrations/ve_viking_db_memory/ve_viking_db_memory.py +308 -0
  129. veadk/knowledgebase/__init__.py +17 -0
  130. veadk/knowledgebase/backends/__init__.py +13 -0
  131. veadk/knowledgebase/backends/base_backend.py +72 -0
  132. veadk/knowledgebase/backends/in_memory_backend.py +91 -0
  133. veadk/knowledgebase/backends/opensearch_backend.py +162 -0
  134. veadk/knowledgebase/backends/redis_backend.py +172 -0
  135. veadk/knowledgebase/backends/utils.py +92 -0
  136. veadk/knowledgebase/backends/vikingdb_knowledge_backend.py +608 -0
  137. veadk/knowledgebase/entry.py +25 -0
  138. veadk/knowledgebase/knowledgebase.py +307 -0
  139. veadk/memory/__init__.py +35 -0
  140. veadk/memory/long_term_memory.py +365 -0
  141. veadk/memory/long_term_memory_backends/__init__.py +13 -0
  142. veadk/memory/long_term_memory_backends/base_backend.py +35 -0
  143. veadk/memory/long_term_memory_backends/in_memory_backend.py +67 -0
  144. veadk/memory/long_term_memory_backends/mem0_backend.py +155 -0
  145. veadk/memory/long_term_memory_backends/opensearch_backend.py +124 -0
  146. veadk/memory/long_term_memory_backends/redis_backend.py +140 -0
  147. veadk/memory/long_term_memory_backends/vikingdb_memory_backend.py +189 -0
  148. veadk/memory/short_term_memory.py +252 -0
  149. veadk/memory/short_term_memory_backends/__init__.py +13 -0
  150. veadk/memory/short_term_memory_backends/base_backend.py +31 -0
  151. veadk/memory/short_term_memory_backends/mysql_backend.py +49 -0
  152. veadk/memory/short_term_memory_backends/postgresql_backend.py +49 -0
  153. veadk/memory/short_term_memory_backends/sqlite_backend.py +55 -0
  154. veadk/memory/short_term_memory_processor.py +100 -0
  155. veadk/processors/__init__.py +26 -0
  156. veadk/processors/base_run_processor.py +120 -0
  157. veadk/prompts/__init__.py +13 -0
  158. veadk/prompts/agent_default_prompt.py +30 -0
  159. veadk/prompts/prompt_evaluator.py +20 -0
  160. veadk/prompts/prompt_memory_processor.py +55 -0
  161. veadk/prompts/prompt_optimization.py +150 -0
  162. veadk/runner.py +732 -0
  163. veadk/tools/__init__.py +13 -0
  164. veadk/tools/builtin_tools/__init__.py +13 -0
  165. veadk/tools/builtin_tools/agent_authorization.py +94 -0
  166. veadk/tools/builtin_tools/generate_image.py +23 -0
  167. veadk/tools/builtin_tools/image_edit.py +300 -0
  168. veadk/tools/builtin_tools/image_generate.py +446 -0
  169. veadk/tools/builtin_tools/lark.py +67 -0
  170. veadk/tools/builtin_tools/las.py +24 -0
  171. veadk/tools/builtin_tools/link_reader.py +66 -0
  172. veadk/tools/builtin_tools/llm_shield.py +381 -0
  173. veadk/tools/builtin_tools/load_knowledgebase.py +97 -0
  174. veadk/tools/builtin_tools/mcp_router.py +29 -0
  175. veadk/tools/builtin_tools/run_code.py +113 -0
  176. veadk/tools/builtin_tools/tts.py +253 -0
  177. veadk/tools/builtin_tools/vesearch.py +49 -0
  178. veadk/tools/builtin_tools/video_generate.py +363 -0
  179. veadk/tools/builtin_tools/web_scraper.py +76 -0
  180. veadk/tools/builtin_tools/web_search.py +83 -0
  181. veadk/tools/demo_tools.py +58 -0
  182. veadk/tools/load_knowledgebase_tool.py +149 -0
  183. veadk/tools/sandbox/__init__.py +13 -0
  184. veadk/tools/sandbox/browser_sandbox.py +37 -0
  185. veadk/tools/sandbox/code_sandbox.py +40 -0
  186. veadk/tools/sandbox/computer_sandbox.py +34 -0
  187. veadk/tracing/__init__.py +13 -0
  188. veadk/tracing/base_tracer.py +58 -0
  189. veadk/tracing/telemetry/__init__.py +13 -0
  190. veadk/tracing/telemetry/attributes/attributes.py +29 -0
  191. veadk/tracing/telemetry/attributes/extractors/common_attributes_extractors.py +180 -0
  192. veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py +858 -0
  193. veadk/tracing/telemetry/attributes/extractors/tool_attributes_extractors.py +152 -0
  194. veadk/tracing/telemetry/attributes/extractors/types.py +164 -0
  195. veadk/tracing/telemetry/exporters/__init__.py +13 -0
  196. veadk/tracing/telemetry/exporters/apmplus_exporter.py +558 -0
  197. veadk/tracing/telemetry/exporters/base_exporter.py +39 -0
  198. veadk/tracing/telemetry/exporters/cozeloop_exporter.py +129 -0
  199. veadk/tracing/telemetry/exporters/inmemory_exporter.py +248 -0
  200. veadk/tracing/telemetry/exporters/tls_exporter.py +139 -0
  201. veadk/tracing/telemetry/opentelemetry_tracer.py +320 -0
  202. veadk/tracing/telemetry/telemetry.py +411 -0
  203. veadk/types.py +47 -0
  204. veadk/utils/__init__.py +13 -0
  205. veadk/utils/audio_manager.py +95 -0
  206. veadk/utils/auth.py +294 -0
  207. veadk/utils/logger.py +59 -0
  208. veadk/utils/mcp_utils.py +44 -0
  209. veadk/utils/misc.py +184 -0
  210. veadk/utils/patches.py +101 -0
  211. veadk/utils/volcengine_sign.py +205 -0
  212. veadk/version.py +15 -0
  213. veadk_python-0.2.27.dist-info/METADATA +373 -0
  214. veadk_python-0.2.27.dist-info/RECORD +218 -0
  215. veadk_python-0.2.27.dist-info/WHEEL +5 -0
  216. veadk_python-0.2.27.dist-info/entry_points.txt +2 -0
  217. veadk_python-0.2.27.dist-info/licenses/LICENSE +201 -0
  218. veadk_python-0.2.27.dist-info/top_level.txt +1 -0
@@ -0,0 +1,189 @@
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 json
16
+ import os
17
+ import re
18
+ import time
19
+ import uuid
20
+ from typing import Any
21
+
22
+ from pydantic import Field
23
+ from typing_extensions import override
24
+
25
+ import veadk.config # noqa E401
26
+ from veadk.auth.veauth.utils import get_credential_from_vefaas_iam
27
+ from veadk.integrations.ve_viking_db_memory.ve_viking_db_memory import (
28
+ VikingDBMemoryClient,
29
+ )
30
+ from veadk.memory.long_term_memory_backends.base_backend import (
31
+ BaseLongTermMemoryBackend,
32
+ )
33
+ from veadk.utils.logger import get_logger
34
+
35
+ logger = get_logger(__name__)
36
+
37
+
38
+ class VikingDBLTMBackend(BaseLongTermMemoryBackend):
39
+ volcengine_access_key: str | None = Field(
40
+ default_factory=lambda: os.getenv("VOLCENGINE_ACCESS_KEY")
41
+ )
42
+
43
+ volcengine_secret_key: str | None = Field(
44
+ default_factory=lambda: os.getenv("VOLCENGINE_SECRET_KEY")
45
+ )
46
+
47
+ session_token: str = ""
48
+
49
+ region: str = "cn-beijing"
50
+ """VikingDB memory region"""
51
+
52
+ memory_type: list[str] = Field(default_factory=list)
53
+
54
+ def model_post_init(self, __context: Any) -> None:
55
+ # We get memory type from:
56
+ # 1. user input
57
+ # 2. environment variable
58
+ # 3. default value
59
+ if not self.memory_type:
60
+ env_memory_type = os.getenv("DATABASE_VIKINGMEM_MEMORY_TYPE")
61
+ if env_memory_type:
62
+ # "event_1, event_2" -> ["event_1", "event_2"]
63
+ self.memory_type = [x.strip() for x in env_memory_type.split(",")]
64
+ else:
65
+ # self.memory_type = ["sys_event_v1", "event_v1"]
66
+ self.memory_type = ["sys_event_v1"]
67
+
68
+ logger.info(f"Using memory type: {self.memory_type}")
69
+
70
+ # check whether collection exist, if not, create it
71
+ if not self._collection_exist():
72
+ self._create_collection()
73
+
74
+ def precheck_index_naming(self):
75
+ if not (
76
+ isinstance(self.index, str)
77
+ and 1 <= len(self.index) <= 128
78
+ and re.fullmatch(r"^[a-zA-Z][a-zA-Z0-9_]*$", self.index)
79
+ ):
80
+ raise ValueError(
81
+ "The index name does not conform to the rules: it must start with an English letter, contain only letters, numbers, and underscores, and have a length of 1-128."
82
+ )
83
+
84
+ def _collection_exist(self) -> bool:
85
+ try:
86
+ client = self._get_client()
87
+ client.get_collection(collection_name=self.index)
88
+ logger.info(f"Collection {self.index} exist.")
89
+ return True
90
+ except Exception:
91
+ logger.info(f"Collection {self.index} not exist.")
92
+ return False
93
+
94
+ def _create_collection(self) -> None:
95
+ logger.info(
96
+ f"Create collection with collection_name={self.index}, builtin_event_types={self.memory_type}"
97
+ )
98
+ client = self._get_client()
99
+ response = client.create_collection(
100
+ collection_name=self.index,
101
+ description="Created by Volcengine Agent Development Kit VeADK",
102
+ builtin_event_types=self.memory_type,
103
+ )
104
+ logger.debug(f"Create collection with response {response}")
105
+ return response
106
+
107
+ def _get_client(self) -> VikingDBMemoryClient:
108
+ if not (self.volcengine_access_key and self.volcengine_secret_key):
109
+ cred = get_credential_from_vefaas_iam()
110
+ self.volcengine_access_key = cred.access_key_id
111
+ self.volcengine_secret_key = cred.secret_access_key
112
+ self.session_token = cred.session_token
113
+
114
+ return VikingDBMemoryClient(
115
+ ak=self.volcengine_access_key,
116
+ sk=self.volcengine_secret_key,
117
+ sts_token=self.session_token,
118
+ region=self.region,
119
+ )
120
+
121
+ @override
122
+ def save_memory(self, user_id: str, event_strings: list[str], **kwargs) -> bool:
123
+ session_id = str(uuid.uuid1())
124
+ messages = []
125
+ for raw_events in event_strings:
126
+ event = json.loads(raw_events)
127
+ content = event["parts"][0]["text"]
128
+ role = (
129
+ "user" if event["role"] == "user" else "assistant"
130
+ ) # field 'role': viking memory only allow 'assistant','system','user',
131
+ messages.append({"role": role, "content": content})
132
+ metadata = {
133
+ "default_user_id": user_id,
134
+ "default_assistant_id": "assistant",
135
+ "time": int(time.time() * 1000),
136
+ }
137
+
138
+ logger.debug(
139
+ f"Request for add {len(messages)} memory to VikingDB: collection_name={self.index}, metadata={metadata}, session_id={session_id}"
140
+ )
141
+
142
+ client = self._get_client()
143
+ response = client.add_messages(
144
+ collection_name=self.index,
145
+ messages=messages,
146
+ metadata=metadata,
147
+ session_id=session_id,
148
+ )
149
+
150
+ logger.debug(f"Response from add memory to VikingDB: {response}")
151
+
152
+ if not response.get("code") == 0:
153
+ raise ValueError(f"Save VikingDB memory error: {response}")
154
+
155
+ return True
156
+
157
+ @override
158
+ def search_memory(
159
+ self, user_id: str, query: str, top_k: int, **kwargs
160
+ ) -> list[str]:
161
+ filter = {"user_id": user_id, "memory_type": self.memory_type}
162
+
163
+ logger.debug(
164
+ f"Request for search memory in VikingDB: filter={filter}, collection_name={self.index}, query={query}, limit={top_k}"
165
+ )
166
+
167
+ client = self._get_client()
168
+ response = client.search_memory(
169
+ collection_name=self.index, query=query, filter=filter, limit=top_k
170
+ )
171
+
172
+ logger.debug(f"Response from search memory in VikingDB: {response}")
173
+
174
+ if not response.get("code") == 0:
175
+ raise ValueError(f"Search VikingDB memory error: {response}")
176
+
177
+ result = response.get("data", {}).get("result_list", [])
178
+ if result:
179
+ return [
180
+ json.dumps(
181
+ {
182
+ "role": "user",
183
+ "parts": [{"text": r.get("memory_info").get("summary")}],
184
+ },
185
+ ensure_ascii=False,
186
+ )
187
+ for r in result
188
+ ]
189
+ return []
@@ -0,0 +1,252 @@
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 functools import wraps
16
+ from typing import Any, Callable, Literal
17
+
18
+ from google.adk.sessions import (
19
+ BaseSessionService,
20
+ DatabaseSessionService,
21
+ InMemorySessionService,
22
+ Session,
23
+ )
24
+ from pydantic import BaseModel, Field, PrivateAttr
25
+
26
+ from veadk.memory.short_term_memory_backends.mysql_backend import (
27
+ MysqlSTMBackend,
28
+ )
29
+ from veadk.memory.short_term_memory_backends.postgresql_backend import (
30
+ PostgreSqlSTMBackend,
31
+ )
32
+ from veadk.memory.short_term_memory_backends.sqlite_backend import (
33
+ SQLiteSTMBackend,
34
+ )
35
+ from veadk.utils.logger import get_logger
36
+
37
+ logger = get_logger(__name__)
38
+
39
+
40
+ def wrap_get_session_with_callbacks(obj, callback_fn: Callable):
41
+ get_session_fn = getattr(obj, "get_session")
42
+
43
+ @wraps(get_session_fn)
44
+ def wrapper(*args, **kwargs):
45
+ result = get_session_fn(*args, **kwargs)
46
+ callback_fn(result, *args, **kwargs)
47
+ return result
48
+
49
+ setattr(obj, "get_session", wrapper)
50
+
51
+
52
+ class ShortTermMemory(BaseModel):
53
+ """Short term memory for agent execution.
54
+
55
+ The short term memory represents the context of the agent model. All content in the short term memory will be sent to agent model directly, including the system prompt, historical user prompt, and historical model responses.
56
+
57
+ Attributes:
58
+ backend (Literal["local", "mysql", "sqlite", "postgresql", "database"]):
59
+ The backend of short term memory:
60
+ - `local` for in-memory storage
61
+ - `mysql` for mysql / PostgreSQL storage
62
+ - `sqlite` for locally sqlite storage
63
+ backend_configs (dict): Configuration dict for init short term memory backend.
64
+ db_url (str):
65
+ Database connection url for init short term memory backend.
66
+ For example, `sqlite:///./test.db`. Once set, it will override the `backend` parameter.
67
+ local_database_path (str):
68
+ Local database path, only used when `backend` is `sqlite`.
69
+ Default to `/tmp/veadk_local_database.db`.
70
+ after_load_memory_callback (Callable | None):
71
+ A callback to be called after loading memory from the backend. The callback function should accept `Session` as an input.
72
+
73
+ Examples:
74
+ ### In-memory simple memory
75
+
76
+ You can initialize a short term memory with in-memory storage:
77
+
78
+ ```python
79
+ from veadk import Agent, Runner
80
+ from veadk.memory.short_term_memory import ShortTermMemory
81
+ import asyncio
82
+
83
+ session_id = "veadk_playground_session"
84
+
85
+ agent = Agent()
86
+ short_term_memory = ShortTermMemory(backend="local")
87
+
88
+ runner = Runner(
89
+ agent=agent, short_term_memory=short_term_memory)
90
+
91
+ # This invocation will be stored in short-term memory
92
+ response = asyncio.run(runner.run(
93
+ messages="My name is VeADK", session_id=session_id
94
+ ))
95
+ print(response)
96
+
97
+ # The history invocation can be fetched by model
98
+ response = asyncio.run(runner.run(
99
+ messages="Do you remember my name?", session_id=session_id # keep the same `session_id`
100
+ ))
101
+ print(response)
102
+ ```
103
+
104
+ ### Memory with a Database URL
105
+
106
+ Also you can use a databasae connection URL to initialize a short-term memory:
107
+
108
+ ```python
109
+ from veadk.memory.short_term_memory import ShortTermMemory
110
+
111
+ short_term_memory = ShortTermMemory(db_url="...")
112
+ ```
113
+
114
+ ### Memory with SQLite
115
+
116
+ Once you want to start the short term memory with a local SQLite, you can specify the backend to `sqlite`. It will create a local database in `local_database_path`:
117
+
118
+ ```python
119
+ from veadk.memory.short_term_memory import ShortTermMemory
120
+
121
+ short_term_memory = ShortTermMemory(backend="sqlite", local_database_path="")
122
+ ```
123
+ """
124
+
125
+ backend: Literal["local", "mysql", "sqlite", "postgresql", "database"] = "local"
126
+
127
+ backend_configs: dict = Field(default_factory=dict)
128
+
129
+ db_url: str = ""
130
+
131
+ local_database_path: str = "/tmp/veadk_local_database.db"
132
+
133
+ after_load_memory_callback: Callable | None = None
134
+
135
+ _session_service: BaseSessionService = PrivateAttr()
136
+
137
+ def model_post_init(self, __context: Any) -> None:
138
+ if self.db_url:
139
+ logger.info("The `db_url` is set, ignore `backend` option.")
140
+ if self.db_url.count("@") > 1 or self.db_url.count(":") > 2:
141
+ logger.warning(
142
+ "Multiple `@` or `:` symbols detected in the database URL. "
143
+ "Please encode `username` or `password` with `urllib.parse.quote_plus`. "
144
+ "Examples: p@ssword→p%40ssword."
145
+ )
146
+ self._session_service = DatabaseSessionService(db_url=self.db_url)
147
+ else:
148
+ if self.backend == "database":
149
+ logger.warning(
150
+ "Backend `database` is deprecated, use `sqlite` to create short term memory."
151
+ )
152
+ self.backend = "sqlite"
153
+ match self.backend:
154
+ case "local":
155
+ self._session_service = InMemorySessionService()
156
+ case "mysql":
157
+ self._session_service = MysqlSTMBackend(
158
+ **self.backend_configs
159
+ ).session_service
160
+ case "sqlite":
161
+ self._session_service = SQLiteSTMBackend(
162
+ local_path=self.local_database_path
163
+ ).session_service
164
+ case "postgresql":
165
+ self._session_service = PostgreSqlSTMBackend(
166
+ **self.backend_configs
167
+ ).session_service
168
+
169
+ if self.after_load_memory_callback:
170
+ wrap_get_session_with_callbacks(
171
+ self._session_service, self.after_load_memory_callback
172
+ )
173
+
174
+ @property
175
+ def session_service(self) -> BaseSessionService:
176
+ return self._session_service
177
+
178
+ async def create_session(
179
+ self,
180
+ app_name: str,
181
+ user_id: str,
182
+ session_id: str,
183
+ ) -> Session | None:
184
+ """Create or retrieve a user session.
185
+
186
+ Short term memory can attempt to create a new session for a given application and user. If a session with the same `session_id` already exists, it will be returned instead of creating a new one.
187
+
188
+ If the underlying session service is backed by a database (`DatabaseSessionService`), the method first lists all existing sessions for the given `app_name` and `user_id` and logs the number of sessions found. It then checks whether a session with the specified `session_id` already exists:
189
+ - If it exists → returns the existing session.
190
+ - If it does not exist → creates and returns a new session.
191
+
192
+ Args:
193
+ app_name (str): The name of the application associated with the session.
194
+ user_id (str): The unique identifier of the user.
195
+ session_id (str): The unique identifier of the session to be created or retrieved.
196
+
197
+ Returns:
198
+ Session | None: The retrieved or newly created `Session` object, or `None` if the session creation failed.
199
+
200
+ Examples:
201
+ Create a new session manually:
202
+
203
+ ```python
204
+ import asyncio
205
+
206
+ from veadk.memory import ShortTermMemory
207
+
208
+ app_name = "app_name"
209
+ user_id = "user_id"
210
+ session_id = "session_id"
211
+
212
+ short_term_memory = ShortTermMemory()
213
+
214
+ session = asyncio.run(
215
+ short_term_memory.create_session(
216
+ app_name=app_name, user_id=user_id, session_id=session_id
217
+ )
218
+ )
219
+
220
+ print(session)
221
+
222
+ session = asyncio.run(
223
+ short_term_memory.session_service.get_session(
224
+ app_name=app_name, user_id=user_id, session_id=session_id
225
+ )
226
+ )
227
+
228
+ print(session)
229
+ ```
230
+ """
231
+ if isinstance(self._session_service, DatabaseSessionService):
232
+ list_sessions_response = await self._session_service.list_sessions(
233
+ app_name=app_name, user_id=user_id
234
+ )
235
+
236
+ logger.debug(
237
+ f"Loaded {len(list_sessions_response.sessions)} sessions from db {self.db_url}."
238
+ )
239
+
240
+ session = await self._session_service.get_session(
241
+ app_name=app_name, user_id=user_id, session_id=session_id
242
+ )
243
+
244
+ if session:
245
+ logger.info(
246
+ f"Session {session_id} already exists with app_name={app_name} user_id={user_id}."
247
+ )
248
+ return session
249
+ else:
250
+ return await self._session_service.create_session(
251
+ app_name=app_name, user_id=user_id, session_id=session_id
252
+ )
@@ -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,31 @@
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
+
16
+ from abc import ABC, abstractmethod
17
+ from functools import cached_property
18
+
19
+ from google.adk.sessions import BaseSessionService
20
+ from pydantic import BaseModel
21
+
22
+
23
+ class BaseShortTermMemoryBackend(ABC, BaseModel):
24
+ """
25
+ Base class for short term memory backend.
26
+ """
27
+
28
+ @cached_property
29
+ @abstractmethod
30
+ def session_service(self) -> BaseSessionService:
31
+ """Return the session service instance."""
@@ -0,0 +1,49 @@
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 functools import cached_property
16
+ from typing import Any
17
+
18
+ from google.adk import version as adk_version
19
+ from google.adk.sessions import (
20
+ BaseSessionService,
21
+ DatabaseSessionService,
22
+ )
23
+ from packaging.version import parse as parse_version
24
+ from pydantic import Field
25
+ from typing_extensions import override
26
+ from urllib.parse import quote_plus
27
+
28
+ import veadk.config # noqa E401
29
+ from veadk.configs.database_configs import MysqlConfig
30
+ from veadk.memory.short_term_memory_backends.base_backend import (
31
+ BaseShortTermMemoryBackend,
32
+ )
33
+
34
+
35
+ class MysqlSTMBackend(BaseShortTermMemoryBackend):
36
+ mysql_config: MysqlConfig = Field(default_factory=MysqlConfig)
37
+
38
+ def model_post_init(self, context: Any) -> None:
39
+ encoded_username = quote_plus(self.mysql_config.user)
40
+ encoded_password = quote_plus(self.mysql_config.password)
41
+ if parse_version(adk_version.__version__) < parse_version("1.19.0"):
42
+ self._db_url = f"mysql+pymysql://{encoded_username}:{encoded_password}@{self.mysql_config.host}/{self.mysql_config.database}"
43
+ else:
44
+ self._db_url = f"mysql+aiomysql://{encoded_username}:{encoded_password}@{self.mysql_config.host}/{self.mysql_config.database}"
45
+
46
+ @cached_property
47
+ @override
48
+ def session_service(self) -> BaseSessionService:
49
+ return DatabaseSessionService(db_url=self._db_url)
@@ -0,0 +1,49 @@
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 functools import cached_property
16
+ from typing import Any
17
+ from urllib.parse import quote_plus
18
+
19
+ from google.adk import version as adk_version
20
+ from google.adk.sessions import (
21
+ BaseSessionService,
22
+ DatabaseSessionService,
23
+ )
24
+ from packaging.version import parse as parse_version
25
+ from pydantic import Field
26
+ from typing_extensions import override
27
+
28
+ import veadk.config # noqa E401
29
+ from veadk.configs.database_configs import PostgreSqlConfig
30
+ from veadk.memory.short_term_memory_backends.base_backend import (
31
+ BaseShortTermMemoryBackend,
32
+ )
33
+
34
+
35
+ class PostgreSqlSTMBackend(BaseShortTermMemoryBackend):
36
+ postgresql_config: PostgreSqlConfig = Field(default_factory=PostgreSqlConfig)
37
+
38
+ def model_post_init(self, context: Any) -> None:
39
+ encoded_username = quote_plus(self.postgresql_config.user)
40
+ encoded_password = quote_plus(self.postgresql_config.password)
41
+ if parse_version(adk_version.__version__) < parse_version("1.19.0"):
42
+ self._db_url = f"postgresql://{encoded_username}:{encoded_password}@{self.postgresql_config.host}:{self.postgresql_config.port}/{self.postgresql_config.database}"
43
+ else:
44
+ self._db_url = f"postgresql+asyncpg://{encoded_username}:{encoded_password}@{self.postgresql_config.host}:{self.postgresql_config.port}/{self.postgresql_config.database}"
45
+
46
+ @cached_property
47
+ @override
48
+ def session_service(self) -> BaseSessionService:
49
+ return DatabaseSessionService(db_url=self._db_url)
@@ -0,0 +1,55 @@
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 os
16
+ import sqlite3
17
+ from functools import cached_property
18
+ from typing import Any
19
+
20
+ from google.adk import version as adk_version
21
+ from google.adk.sessions import (
22
+ BaseSessionService,
23
+ DatabaseSessionService,
24
+ )
25
+ from packaging.version import parse as parse_version
26
+ from typing_extensions import override
27
+
28
+ from veadk.memory.short_term_memory_backends.base_backend import (
29
+ BaseShortTermMemoryBackend,
30
+ )
31
+
32
+
33
+ class SQLiteSTMBackend(BaseShortTermMemoryBackend):
34
+ local_path: str
35
+
36
+ def model_post_init(self, context: Any) -> None:
37
+ self.local_path = os.path.abspath(self.local_path)
38
+ # if the DB file not exists, create it
39
+ if not self._db_exists():
40
+ os.makedirs(os.path.dirname(self.local_path), exist_ok=True)
41
+ conn = sqlite3.connect(self.local_path)
42
+ conn.close()
43
+
44
+ if parse_version(adk_version.__version__) < parse_version("1.19.0"):
45
+ self._db_url = f"sqlite:///{self.local_path}"
46
+ else:
47
+ self._db_url = f"sqlite+aiosqlite:///{self.local_path}"
48
+
49
+ @cached_property
50
+ @override
51
+ def session_service(self) -> BaseSessionService:
52
+ return DatabaseSessionService(db_url=self._db_url)
53
+
54
+ def _db_exists(self) -> bool:
55
+ return os.path.exists(self.local_path)