veadk-python 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (110) hide show
  1. veadk/__init__.py +31 -0
  2. veadk/a2a/__init__.py +13 -0
  3. veadk/a2a/agent_card.py +45 -0
  4. veadk/a2a/remote_ve_agent.py +19 -0
  5. veadk/a2a/ve_a2a_server.py +77 -0
  6. veadk/a2a/ve_agent_executor.py +78 -0
  7. veadk/a2a/ve_task_store.py +37 -0
  8. veadk/agent.py +253 -0
  9. veadk/cli/__init__.py +13 -0
  10. veadk/cli/main.py +278 -0
  11. veadk/cli/services/agentpilot/__init__.py +17 -0
  12. veadk/cli/services/agentpilot/agentpilot.py +77 -0
  13. veadk/cli/services/veapig/__init__.py +17 -0
  14. veadk/cli/services/veapig/apig.py +224 -0
  15. veadk/cli/services/veapig/apig_utils.py +332 -0
  16. veadk/cli/services/vefaas/__init__.py +17 -0
  17. veadk/cli/services/vefaas/template/deploy.py +44 -0
  18. veadk/cli/services/vefaas/template/src/app.py +30 -0
  19. veadk/cli/services/vefaas/template/src/config.py +58 -0
  20. veadk/cli/services/vefaas/vefaas.py +346 -0
  21. veadk/cli/services/vefaas/vefaas_utils.py +408 -0
  22. veadk/cli/services/vetls/__init__.py +17 -0
  23. veadk/cli/services/vetls/vetls.py +87 -0
  24. veadk/cli/studio/__init__.py +13 -0
  25. veadk/cli/studio/agent_processor.py +247 -0
  26. veadk/cli/studio/fast_api.py +232 -0
  27. veadk/cli/studio/model.py +116 -0
  28. veadk/cloud/__init__.py +13 -0
  29. veadk/cloud/cloud_agent_engine.py +144 -0
  30. veadk/cloud/cloud_app.py +123 -0
  31. veadk/cloud/template/app.py +30 -0
  32. veadk/cloud/template/config.py +55 -0
  33. veadk/config.py +131 -0
  34. veadk/consts.py +17 -0
  35. veadk/database/__init__.py +17 -0
  36. veadk/database/base_database.py +45 -0
  37. veadk/database/database_factory.py +80 -0
  38. veadk/database/kv/__init__.py +13 -0
  39. veadk/database/kv/redis_database.py +109 -0
  40. veadk/database/local_database.py +43 -0
  41. veadk/database/relational/__init__.py +13 -0
  42. veadk/database/relational/mysql_database.py +114 -0
  43. veadk/database/vector/__init__.py +13 -0
  44. veadk/database/vector/opensearch_vector_database.py +205 -0
  45. veadk/database/vector/type.py +50 -0
  46. veadk/database/viking/__init__.py +13 -0
  47. veadk/database/viking/viking_database.py +378 -0
  48. veadk/database/viking/viking_memory_db.py +521 -0
  49. veadk/evaluation/__init__.py +17 -0
  50. veadk/evaluation/adk_evaluator/__init__.py +13 -0
  51. veadk/evaluation/adk_evaluator/adk_evaluator.py +291 -0
  52. veadk/evaluation/base_evaluator.py +242 -0
  53. veadk/evaluation/deepeval_evaluator/__init__.py +17 -0
  54. veadk/evaluation/deepeval_evaluator/deepeval_evaluator.py +223 -0
  55. veadk/evaluation/eval_set_file_loader.py +28 -0
  56. veadk/evaluation/eval_set_recorder.py +91 -0
  57. veadk/evaluation/utils/prometheus.py +142 -0
  58. veadk/knowledgebase/__init__.py +17 -0
  59. veadk/knowledgebase/knowledgebase.py +83 -0
  60. veadk/knowledgebase/knowledgebase_database_adapter.py +259 -0
  61. veadk/memory/__init__.py +13 -0
  62. veadk/memory/long_term_memory.py +119 -0
  63. veadk/memory/memory_database_adapter.py +235 -0
  64. veadk/memory/short_term_memory.py +124 -0
  65. veadk/memory/short_term_memory_processor.py +90 -0
  66. veadk/prompts/__init__.py +13 -0
  67. veadk/prompts/agent_default_prompt.py +30 -0
  68. veadk/prompts/prompt_evaluator.py +20 -0
  69. veadk/prompts/prompt_memory_processor.py +55 -0
  70. veadk/prompts/prompt_optimization.py +158 -0
  71. veadk/runner.py +252 -0
  72. veadk/tools/__init__.py +13 -0
  73. veadk/tools/builtin_tools/__init__.py +13 -0
  74. veadk/tools/builtin_tools/lark.py +67 -0
  75. veadk/tools/builtin_tools/las.py +23 -0
  76. veadk/tools/builtin_tools/vesearch.py +49 -0
  77. veadk/tools/builtin_tools/web_scraper.py +76 -0
  78. veadk/tools/builtin_tools/web_search.py +192 -0
  79. veadk/tools/demo_tools.py +58 -0
  80. veadk/tools/load_knowledgebase_tool.py +144 -0
  81. veadk/tools/sandbox/__init__.py +13 -0
  82. veadk/tools/sandbox/browser_sandbox.py +27 -0
  83. veadk/tools/sandbox/code_sandbox.py +30 -0
  84. veadk/tools/sandbox/computer_sandbox.py +27 -0
  85. veadk/tracing/__init__.py +13 -0
  86. veadk/tracing/base_tracer.py +172 -0
  87. veadk/tracing/telemetry/__init__.py +13 -0
  88. veadk/tracing/telemetry/exporters/__init__.py +13 -0
  89. veadk/tracing/telemetry/exporters/apiserver_exporter.py +60 -0
  90. veadk/tracing/telemetry/exporters/apmplus_exporter.py +101 -0
  91. veadk/tracing/telemetry/exporters/base_exporter.py +28 -0
  92. veadk/tracing/telemetry/exporters/cozeloop_exporter.py +69 -0
  93. veadk/tracing/telemetry/exporters/inmemory_exporter.py +88 -0
  94. veadk/tracing/telemetry/exporters/tls_exporter.py +78 -0
  95. veadk/tracing/telemetry/metrics/__init__.py +13 -0
  96. veadk/tracing/telemetry/metrics/opentelemetry_metrics.py +73 -0
  97. veadk/tracing/telemetry/opentelemetry_tracer.py +167 -0
  98. veadk/types.py +23 -0
  99. veadk/utils/__init__.py +13 -0
  100. veadk/utils/logger.py +59 -0
  101. veadk/utils/misc.py +33 -0
  102. veadk/utils/patches.py +85 -0
  103. veadk/utils/volcengine_sign.py +199 -0
  104. veadk/version.py +15 -0
  105. veadk_python-0.1.0.dist-info/METADATA +124 -0
  106. veadk_python-0.1.0.dist-info/RECORD +110 -0
  107. veadk_python-0.1.0.dist-info/WHEEL +5 -0
  108. veadk_python-0.1.0.dist-info/entry_points.txt +2 -0
  109. veadk_python-0.1.0.dist-info/licenses/LICENSE +201 -0
  110. veadk_python-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,259 @@
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
+ Knowledgebase may use different databases, so we need to create
17
+ an adapter to abstract the database operations.
18
+ """
19
+
20
+ import re
21
+ import time
22
+ from typing import BinaryIO, TextIO
23
+
24
+ from pydantic import BaseModel, ConfigDict
25
+
26
+ from veadk.database.base_database import BaseDatabase
27
+ from veadk.database.database_factory import DatabaseBackend
28
+ from veadk.utils.logger import get_logger
29
+
30
+ logger = get_logger(__name__)
31
+
32
+
33
+ def format_collection_name(collection_name: str) -> str:
34
+ replaced_str = re.sub(r"[- ]", "_", collection_name)
35
+ return re.sub(r"[^a-z0-9_]", "", replaced_str).lower()
36
+
37
+
38
+ def get_knowledgebase_adapter(backend: str):
39
+ if backend == DatabaseBackend.REDIS:
40
+ return KnowledgebaseKVDatabaseAdapter
41
+ elif backend == DatabaseBackend.MYSQL:
42
+ return KnowledgebaseRelationalDatabaseAdapter
43
+ elif backend == DatabaseBackend.OPENSEARCH:
44
+ return KnowledgebaseVectorDatabaseAdapter
45
+ elif backend == DatabaseBackend.LOCAL:
46
+ return KnowledgebaseLocalDatabaseAdapter
47
+ elif backend == DatabaseBackend.VIKING:
48
+ return KnowledgebaseVikingDatabaseAdapter
49
+ else:
50
+ raise ValueError(f"Unknown backend: {backend}")
51
+
52
+
53
+ class KnowledgebaseKVDatabaseAdapter(BaseModel):
54
+ model_config = ConfigDict(arbitrary_types_allowed=True)
55
+
56
+ database_client: BaseDatabase
57
+
58
+ def add(self, content: list[str], app_name: str, user_id: str, session_id: str):
59
+ """Add texts to Redis.
60
+
61
+ Key: app_name
62
+ Field: app_name:user_id
63
+ Value: text in List
64
+ """
65
+ # key = f"{app_name}:{user_id}"
66
+ key = f"{app_name}"
67
+
68
+ try:
69
+ for _content in content:
70
+ self.database_client.add(key, _content)
71
+ logger.debug(
72
+ f"Successfully added {len(content)} texts to Redis list key `{key}`."
73
+ )
74
+ except Exception as e:
75
+ logger.error(f"Failed to add texts to Redis list key `{key}`: {e}")
76
+ raise e
77
+
78
+ def query(self, query: str, app_name: str, user_id: str, **kwargs):
79
+ # key = f"{app_name}:{user_id}"
80
+ key = f"{app_name}"
81
+ top_k = 10
82
+
83
+ try:
84
+ result = self.database_client.query(key, query)
85
+ return result[-top_k:]
86
+ except Exception as e:
87
+ logger.error(f"Failed to search from Redis list key '{key}': {e}")
88
+ raise e
89
+
90
+ def delete(self, app_name: str, user_id: str, session_id: str):
91
+ try:
92
+ # key = f"{app_name}:{user_id}:{session_id}"
93
+ key = f"{app_name}"
94
+ self.database_client.delete(key=key)
95
+ logger.info(f"Successfully deleted data for app {app_name}")
96
+ except Exception as e:
97
+ logger.error(f"Failed to delete data: {e}")
98
+ raise e
99
+
100
+
101
+ class KnowledgebaseRelationalDatabaseAdapter(BaseModel):
102
+ model_config = ConfigDict(arbitrary_types_allowed=True)
103
+
104
+ database_client: BaseDatabase
105
+
106
+ def create_table(self, table_name: str):
107
+ sql = f"""
108
+ CREATE TABLE `{table_name}` (
109
+ `id` BIGINT AUTO_INCREMENT PRIMARY KEY,
110
+ `data` TEXT NOT NULL,
111
+ `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
112
+ ) ENGINE=InnoDB DEFAULT CHARSET={self.database_client.config.charset};
113
+ """
114
+ self.database_client.add(sql)
115
+
116
+ def add(self, content: list[str], app_name: str, user_id: str, session_id: str):
117
+ table = app_name
118
+
119
+ if not self.database_client.table_exists(table):
120
+ logger.warning(f"Table {table} does not exist, creating...")
121
+ self.create_table(table)
122
+
123
+ for _content in content:
124
+ sql = f"""
125
+ INSERT INTO `{table}` (`data`)
126
+ VALUES (%s);
127
+ """
128
+ self.database_client.add(sql, params=(_content,))
129
+ logger.info(f"Successfully added {len(content)} texts to table {table}.")
130
+
131
+ def query(self, query: str, app_name: str, user_id: str, **kwargs):
132
+ """Search content from table app_name."""
133
+ table = app_name
134
+ top_k = 10
135
+
136
+ if not self.database_client.table_exists(table):
137
+ logger.warning(
138
+ f"querying {query}, but table `{table}` does not exist, returning empty list."
139
+ )
140
+ return []
141
+
142
+ sql = f"""
143
+ SELECT `data` FROM `{table}` ORDER BY `created_at` DESC LIMIT {top_k};
144
+ """
145
+ results = self.database_client.query(sql)
146
+ return [item["data"] for item in results]
147
+
148
+ def delete(self, app_name: str, user_id: str, session_id: str):
149
+ table = app_name
150
+ try:
151
+ self.database_client.delete(table=table)
152
+ logger.info(f"Successfully deleted data from table {app_name}")
153
+ except Exception as e:
154
+ logger.error(f"Failed to delete data: {e}")
155
+ raise e
156
+
157
+
158
+ class KnowledgebaseVectorDatabaseAdapter(BaseModel):
159
+ model_config = ConfigDict(arbitrary_types_allowed=True)
160
+
161
+ database_client: BaseDatabase
162
+
163
+ def add(self, content: list[str], app_name: str, user_id: str, session_id: str):
164
+ # collection_name = format_collection_name(f"{app_name}_{user_id}")
165
+ # knowledgebase is application specific
166
+ collection_name = format_collection_name(f"{app_name}")
167
+ self.database_client.add(content, collection_name=collection_name)
168
+
169
+ def query(self, query: str, app_name: str, user_id: str, **kwargs):
170
+ # collection_name = format_collection_name(f"{app_name}_{user_id}")
171
+ # knowledgebase is application specific
172
+ collection_name = format_collection_name(f"{app_name}")
173
+ return self.database_client.query(
174
+ query, collection_name=collection_name, **kwargs
175
+ )
176
+
177
+ def delete(self, app_name: str, user_id: str, session_id: str):
178
+ # collection_name = format_collection_name(f"{app_name}_{user_id}")
179
+ # knowledgebase is application specific
180
+ collection_name = format_collection_name(f"{app_name}")
181
+ try:
182
+ self.database_client.delete(collection_name=collection_name)
183
+ logger.info(
184
+ f"Successfully deleted vector database collection for app {app_name}"
185
+ )
186
+ except Exception as e:
187
+ logger.error(f"Failed to delete vector database collection: {e}")
188
+ raise e
189
+
190
+
191
+ class KnowledgebaseLocalDatabaseAdapter(BaseModel):
192
+ model_config = ConfigDict(arbitrary_types_allowed=True)
193
+
194
+ database_client: BaseDatabase
195
+
196
+ def add(self, content: list[str], app_name: str, user_id: str, session_id: str):
197
+ self.database_client.add(content)
198
+
199
+ def query(self, query: str, app_name: str, user_id: str, **kwargs):
200
+ return self.database_client.query(query, **kwargs)
201
+
202
+ def delete(self, app_name: str, user_id: str, session_id: str):
203
+ try:
204
+ self.database_client.delete()
205
+ logger.info(f"Successfully cleared local database for app {app_name}")
206
+ except Exception as e:
207
+ logger.error(f"Failed to clear local database: {e}")
208
+ raise e
209
+
210
+
211
+ class KnowledgebaseVikingDatabaseAdapter(BaseModel):
212
+ model_config = ConfigDict(arbitrary_types_allowed=True)
213
+
214
+ database_client: BaseDatabase
215
+
216
+ def get_or_create_collection(self, collection_name: str):
217
+ if not self.database_client.collection_exists(collection_name):
218
+ self.database_client.create_collection(collection_name)
219
+ count = 0
220
+ while not self.database_client.collection_exists(collection_name):
221
+ time.sleep(1)
222
+ count += 1
223
+ if count > 50:
224
+ raise TimeoutError(
225
+ f"Collection {collection_name} not created after 50 seconds"
226
+ )
227
+
228
+ def add(
229
+ self,
230
+ content: str | list[str] | TextIO | BinaryIO | bytes,
231
+ app_name: str,
232
+ user_id: str,
233
+ session_id: str,
234
+ **kwargs,
235
+ ):
236
+ # collection_name = format_collection_name(f"{app_name}_{user_id}")
237
+ collection_name = format_collection_name(f"{app_name}")
238
+ self.get_or_create_collection(collection_name)
239
+ self.database_client.add(content, collection_name=collection_name, **kwargs)
240
+
241
+ def query(self, query: str, app_name: str, user_id: str, **kwargs):
242
+ collection_name = format_collection_name(f"{app_name}")
243
+ if not self.database_client.collection_exists(collection_name):
244
+ raise ValueError(f"Collection {collection_name} does not exist")
245
+ return self.database_client.query(
246
+ query, collection_name=collection_name, **kwargs
247
+ )
248
+
249
+ def delete(self, app_name: str, user_id: str, session_id: str):
250
+ # collection_name = format_collection_name(f"{app_name}_{user_id}")
251
+ collection_name = format_collection_name(f"{app_name}")
252
+ try:
253
+ self.database_client.delete(collection_name=collection_name)
254
+ logger.info(
255
+ f"Successfully deleted vector database collection for app {app_name}"
256
+ )
257
+ except Exception as e:
258
+ logger.error(f"Failed to delete vector database collection: {e}")
259
+ raise e
@@ -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,119 @@
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
+ # adapted from Google ADK memory service adk-python/src/google/adk/memory/vertex_ai_memory_bank_service.py at 0a9e67dbca67789247e882d16b139dbdc76a329a · google/adk-python
16
+ import json
17
+ from typing import Literal
18
+
19
+ from google.adk.memory.base_memory_service import (
20
+ BaseMemoryService,
21
+ SearchMemoryResponse,
22
+ )
23
+ from google.adk.memory.memory_entry import MemoryEntry
24
+ from google.adk.sessions import Session
25
+ from google.genai import types
26
+ from typing_extensions import override
27
+
28
+ from veadk.config import getenv
29
+ from veadk.database import DatabaseFactory
30
+ from veadk.utils.logger import get_logger
31
+
32
+ from .memory_database_adapter import get_memory_adapter
33
+
34
+ logger = get_logger(__name__)
35
+
36
+
37
+ class LongTermMemory(BaseMemoryService):
38
+ def __init__(
39
+ self,
40
+ backend: Literal[
41
+ "local", "opensearch", "redis", "mysql", "viking"
42
+ ] = "opensearch",
43
+ top_k: int = getenv("LONGTERM_MEMORY_TOP_K", 3),
44
+ ):
45
+ if backend == "viking":
46
+ backend = "viking_mem"
47
+ self.top_k = top_k
48
+ self.backend = backend
49
+
50
+ self.db_client = DatabaseFactory.create(
51
+ backend=backend,
52
+ )
53
+ logger.info(f"Long term memory backend is `{backend}`.")
54
+
55
+ self.adapter = get_memory_adapter(backend)(database_client=self.db_client)
56
+
57
+ @override
58
+ async def add_session_to_memory(
59
+ self,
60
+ session: Session,
61
+ ):
62
+ event_list = []
63
+ for event in session.events:
64
+ if not event.content or not event.content.parts:
65
+ continue
66
+
67
+ message = event.content.model_dump(exclude_none=True, mode="json")
68
+ if (
69
+ "text" not in message["parts"][0]
70
+ ): # remove function_call & function_resp
71
+ continue
72
+ event_list.append(json.dumps(message))
73
+ self.adapter.add(
74
+ event_list,
75
+ app_name=session.app_name,
76
+ user_id=session.user_id,
77
+ session_id=session.id,
78
+ )
79
+
80
+ @override
81
+ async def search_memory(self, *, app_name: str, user_id: str, query: str):
82
+ memory_chunks = self.adapter.query(
83
+ query=query,
84
+ app_name=app_name,
85
+ user_id=user_id,
86
+ )
87
+ if len(memory_chunks) == 0:
88
+ return SearchMemoryResponse()
89
+
90
+ memory_events = []
91
+ for memory in memory_chunks:
92
+ try:
93
+ memory_dict = json.loads(memory)
94
+ try:
95
+ text = memory_dict["parts"][0]["text"]
96
+ role = memory_dict["role"]
97
+ except KeyError as e:
98
+ logger.error(
99
+ f"Memory content: {memory_dict}. Error parsing memory: {e}"
100
+ )
101
+ continue
102
+ except json.JSONDecodeError:
103
+ text = memory
104
+ role = "user"
105
+ memory_events.append(
106
+ MemoryEntry(
107
+ author="user",
108
+ content=types.Content(parts=[types.Part(text=text)], role=role),
109
+ )
110
+ )
111
+ return SearchMemoryResponse(memories=memory_events)
112
+
113
+ @override
114
+ async def delete_memory(self, *, app_name: str, user_id: str):
115
+ self.adapter.delete(
116
+ app_name=app_name,
117
+ user_id=user_id,
118
+ session_id="", # session_id is not used in the adapter delete method
119
+ )
@@ -0,0 +1,235 @@
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
+ Longterm memory may use different databases, so we need to create
17
+ an adapter to abstract the database operations.
18
+ """
19
+
20
+ import re
21
+
22
+ from pydantic import BaseModel, ConfigDict
23
+
24
+ from veadk.database.base_database import BaseDatabase
25
+ from veadk.database.database_factory import DatabaseBackend
26
+ from veadk.utils.logger import get_logger
27
+
28
+ logger = get_logger(__name__)
29
+
30
+
31
+ def format_collection_name(collection_name: str) -> str:
32
+ replaced_str = re.sub(r"[- ]", "_", collection_name)
33
+ return re.sub(r"[^a-z0-9_]", "", replaced_str).lower()
34
+
35
+
36
+ def get_memory_adapter(backend: str):
37
+ if backend == DatabaseBackend.REDIS:
38
+ return MemoryKVDatabaseAdapter
39
+ elif backend == DatabaseBackend.MYSQL:
40
+ return MemoryRelationalDatabaseAdapter
41
+ elif backend == DatabaseBackend.OPENSEARCH:
42
+ return MemoryVectorDatabaseAdapter
43
+ elif backend == DatabaseBackend.LOCAL:
44
+ return MemoryLocalDatabaseAdapter
45
+ elif backend == DatabaseBackend.VIKING_MEM:
46
+ return MemoryVikingDBAdapter
47
+ else:
48
+ raise ValueError(f"Unknown backend: {backend}")
49
+
50
+
51
+ class MemoryKVDatabaseAdapter(BaseModel):
52
+ model_config = ConfigDict(arbitrary_types_allowed=True)
53
+
54
+ database_client: BaseDatabase
55
+
56
+ def add(self, content: list[str], app_name: str, user_id: str, session_id: str):
57
+ """Add texts to Redis.
58
+
59
+ Key: app_name
60
+ Field: app_name:user_id
61
+ Value: text in List
62
+ """
63
+ key = f"{app_name}:{user_id}"
64
+
65
+ try:
66
+ for _content in content:
67
+ self.database_client.add(key, _content)
68
+ logger.debug(
69
+ f"Successfully added {len(content)} texts to Redis list key `{key}`."
70
+ )
71
+ except Exception as e:
72
+ logger.error(f"Failed to add texts to Redis list key `{key}`: {e}")
73
+ raise e
74
+
75
+ def query(self, query: str, app_name: str, user_id: str):
76
+ key = f"{app_name}:{user_id}"
77
+ top_k = 10
78
+
79
+ try:
80
+ result = self.database_client.query(key, query)
81
+ # Get latest top_k records.
82
+ # The data is stored in a Redis list, and the latest data is at the end of the list.
83
+ return result[-top_k:]
84
+ except Exception as e:
85
+ logger.error(f"Failed to search from Redis list key '{key}': {e}")
86
+ raise e
87
+
88
+ def delete(self, app_name: str, user_id: str, session_id: str):
89
+ try:
90
+ self.database_client.delete(
91
+ app_name=app_name, user_id=user_id, session_id=session_id
92
+ )
93
+ logger.info(
94
+ f"Successfully deleted memory data for app {app_name}, user {user_id}, session {session_id}"
95
+ )
96
+ except Exception as e:
97
+ logger.error(f"Failed to delete memory data: {e}")
98
+ raise e
99
+
100
+
101
+ class MemoryRelationalDatabaseAdapter(BaseModel):
102
+ model_config = ConfigDict(arbitrary_types_allowed=True)
103
+
104
+ database_client: BaseDatabase
105
+
106
+ def create_table(self, table_name: str):
107
+ sql = f"""
108
+ CREATE TABLE `{table_name}` (
109
+ `id` BIGINT AUTO_INCREMENT PRIMARY KEY,
110
+ `data` TEXT NOT NULL,
111
+ `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
112
+ ) ENGINE=InnoDB DEFAULT CHARSET={self.database_client.config.charset};
113
+ """
114
+ self.database_client.add(sql)
115
+
116
+ def add(self, content: list[str], app_name: str, user_id: str, session_id: str):
117
+ table = f"{app_name}_{user_id}"
118
+
119
+ if not self.database_client.table_exists(table):
120
+ logger.warning(f"Table {table} does not exist, creating...")
121
+ self.create_table(table)
122
+
123
+ for _content in content:
124
+ sql = f"""
125
+ INSERT INTO `{table}` (`data`)
126
+ VALUES (%s);
127
+ """
128
+ self.database_client.add(sql, params=(_content,))
129
+ logger.info(f"Successfully added {len(content)} texts to table {table}.")
130
+
131
+ def query(self, query: str, app_name: str, user_id: str):
132
+ """Search content from table app_name_user_id."""
133
+ top_k = 10
134
+ table = f"{app_name}_{user_id}"
135
+
136
+ if not self.database_client.table_exists(table):
137
+ logger.warning(
138
+ f"querying {query}, but table `{table}` does not exist, returning empty list."
139
+ )
140
+ return []
141
+
142
+ sql = f"""
143
+ SELECT `data` FROM `{table}` ORDER BY `created_at` DESC LIMIT {top_k};
144
+ """
145
+ results = self.database_client.query(sql)
146
+ return [item["data"] for item in results]
147
+
148
+ def delete(self, app_name: str, user_id: str, session_id: str):
149
+ table = f"{app_name}_{user_id}"
150
+ try:
151
+ self.database_client.delete(table=table)
152
+ logger.info(f"Successfully deleted memory data from table {table}")
153
+ except Exception as e:
154
+ logger.error(f"Failed to delete memory data: {e}")
155
+ raise e
156
+
157
+
158
+ class MemoryVectorDatabaseAdapter(BaseModel):
159
+ model_config = ConfigDict(arbitrary_types_allowed=True)
160
+
161
+ database_client: BaseDatabase
162
+
163
+ def add(self, content: list[str], app_name: str, user_id: str, session_id: str):
164
+ collection_name = format_collection_name(f"{app_name}_{user_id}")
165
+ self.database_client.add(content, collection_name=collection_name)
166
+
167
+ def query(self, query: str, app_name: str, user_id: str):
168
+ collection_name = format_collection_name(f"{app_name}_{user_id}")
169
+ top_k = 10
170
+ return self.database_client.query(
171
+ query, collection_name=collection_name, top_k=top_k
172
+ )
173
+
174
+ def delete(self, app_name: str, user_id: str, session_id: str):
175
+ collection_name = format_collection_name(f"{app_name}_{user_id}")
176
+ try:
177
+ self.database_client.delete(collection_name=collection_name)
178
+ logger.info(
179
+ f"Successfully deleted vector memory database collection for app {app_name}"
180
+ )
181
+ except Exception as e:
182
+ logger.error(f"Failed to delete vector memory database collection: {e}")
183
+ raise e
184
+
185
+
186
+ class MemoryLocalDatabaseAdapter(BaseModel):
187
+ model_config = ConfigDict(arbitrary_types_allowed=True)
188
+
189
+ database_client: BaseDatabase
190
+
191
+ def add(self, content: list[str], app_name: str, user_id: str, session_id: str):
192
+ self.database_client.add(content)
193
+
194
+ def query(self, query: str, app_name: str, user_id: str):
195
+ return self.database_client.query(query)
196
+
197
+ def delete(self, app_name: str, user_id: str, session_id: str):
198
+ try:
199
+ self.database_client.delete()
200
+ logger.info(
201
+ f"Successfully cleared local memory database for app {app_name}"
202
+ )
203
+ except Exception as e:
204
+ logger.error(f"Failed to clear local memory database: {e}")
205
+ raise e
206
+
207
+
208
+ class MemoryVikingDBAdapter(BaseModel):
209
+ model_config = ConfigDict(arbitrary_types_allowed=True)
210
+
211
+ database_client: BaseDatabase
212
+
213
+ def add(
214
+ self, content: list[str], app_name: str, user_id: str, session_id: str, **kwargs
215
+ ):
216
+ kwargs.pop("user_id", None)
217
+
218
+ collection_name = format_collection_name(f"{app_name}_{user_id}")
219
+ self.database_client.add(
220
+ content, collection_name=collection_name, user_id=user_id, **kwargs
221
+ )
222
+
223
+ def query(self, query: str, app_name: str, user_id: str, **kwargs):
224
+ kwargs.pop("user_id", None)
225
+
226
+ collection_name = format_collection_name(f"{app_name}_{user_id}")
227
+ result = self.database_client.query(
228
+ query, collection_name=collection_name, user_id=user_id, **kwargs
229
+ )
230
+ return result
231
+
232
+ def delete(self, app_name: str, user_id: str, session_id: str):
233
+ # collection_name = format_collection_name(f"{app_name}_{user_id}")
234
+ # todo: delete viking memory db
235
+ ...