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
@@ -0,0 +1,129 @@
1
+ # Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from typing import Any
16
+ from typing_extensions import override
17
+ from pydantic import Field
18
+
19
+ from veadk.configs.database_configs import Mem0Config
20
+
21
+
22
+ from veadk.memory.long_term_memory_backends.base_backend import (
23
+ BaseLongTermMemoryBackend,
24
+ )
25
+ from veadk.utils.logger import get_logger
26
+
27
+ logger = get_logger(__name__)
28
+
29
+ try:
30
+ from mem0 import MemoryClient
31
+
32
+ except ImportError:
33
+ logger.error(
34
+ "Failed to import mem0 or dotenv. Please install them with 'pip install mem0 '"
35
+ )
36
+ raise ImportError("Required packages not installed: mem0")
37
+
38
+
39
+ class Mem0LTMBackend(BaseLongTermMemoryBackend):
40
+ """Mem0 long term memory backend implementation"""
41
+
42
+ mem0_config: Mem0Config = Field(default_factory=Mem0Config)
43
+
44
+ def model_post_init(self, __context: Any) -> None:
45
+ """Initialize Mem0 client"""
46
+
47
+ try:
48
+ self._mem0_client = MemoryClient(
49
+ # base_url=self.mem0_config.base_url, # mem0 endpoint
50
+ api_key=self.mem0_config.api_key, # mem0 API key
51
+ )
52
+ logger.info(f"Initialized Mem0 client for index: {self.index}")
53
+ except Exception as e:
54
+ logger.error(f"Failed to initialize Mem0 client: {str(e)}")
55
+ raise
56
+
57
+ def precheck_index_naming(self):
58
+ """Check if the index name is valid
59
+ For Mem0, there are no specific naming constraints
60
+ """
61
+ pass
62
+
63
+ @override
64
+ def save_memory(self, event_strings: list[str], **kwargs) -> bool:
65
+ """Save memory to Mem0
66
+
67
+ Args:
68
+ event_strings: List of event strings to save
69
+ **kwargs: Additional parameters, including 'user_id' for Mem0
70
+
71
+ Returns:
72
+ bool: True if saved successfully, False otherwise
73
+ """
74
+ user_id = kwargs.get("user_id", "default_user")
75
+
76
+ try:
77
+ logger.info(
78
+ f"Saving {len(event_strings)} events to Mem0 for user: {user_id}"
79
+ )
80
+
81
+ for event_string in event_strings:
82
+ # Save event string to Mem0
83
+ result = self._mem0_client.add(
84
+ [{"role": "user", "content": event_string}],
85
+ user_id=user_id,
86
+ output_format="v1.1",
87
+ )
88
+ logger.debug(f"Saved memory result: {result}")
89
+
90
+ logger.info(f"Successfully saved {len(event_strings)} events to Mem0")
91
+ return True
92
+ except Exception as e:
93
+ logger.error(f"Failed to save memory to Mem0: {str(e)}")
94
+ return False
95
+
96
+ @override
97
+ def search_memory(self, query: str, top_k: int, **kwargs) -> list[str]:
98
+ """Search memory from Mem0
99
+
100
+ Args:
101
+ query: Search query
102
+ top_k: Number of results to return
103
+ **kwargs: Additional parameters, including 'user_id' for Mem0
104
+
105
+ Returns:
106
+ list[str]: List of memory strings
107
+ """
108
+ user_id = kwargs.get("user_id", "default_user")
109
+
110
+ try:
111
+ logger.info(
112
+ f"Searching Mem0 for query: {query}, user: {user_id}, top_k: {top_k}"
113
+ )
114
+
115
+ memories = self._mem0_client.search(
116
+ query, user_id=user_id, output_format="v1.1", top_k=top_k
117
+ )
118
+
119
+ memory_list = []
120
+ if memories.get("results", []):
121
+ for mem in memories["results"]:
122
+ if "memory" in mem:
123
+ memory_list.append(mem["memory"])
124
+
125
+ logger.info(f"Found {len(memory_list)} memories matching query: {query}")
126
+ return memory_list
127
+ except Exception as e:
128
+ logger.error(f"Failed to search memory from Mem0: {str(e)}")
129
+ return []
@@ -0,0 +1,120 @@
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 re
16
+
17
+ from llama_index.core import (
18
+ Document,
19
+ StorageContext,
20
+ VectorStoreIndex,
21
+ )
22
+ from llama_index.core.schema import BaseNode
23
+ from llama_index.embeddings.openai_like import OpenAILikeEmbedding
24
+ from pydantic import Field
25
+ from typing_extensions import Any, override
26
+
27
+ import veadk.config # noqa E401
28
+ from veadk.configs.database_configs import OpensearchConfig
29
+ from veadk.configs.model_configs import EmbeddingModelConfig, NormalEmbeddingModelConfig
30
+ from veadk.knowledgebase.backends.utils import get_llama_index_splitter
31
+ from veadk.memory.long_term_memory_backends.base_backend import (
32
+ BaseLongTermMemoryBackend,
33
+ )
34
+
35
+ try:
36
+ from llama_index.vector_stores.opensearch import (
37
+ OpensearchVectorClient,
38
+ OpensearchVectorStore,
39
+ )
40
+ except ImportError:
41
+ raise ImportError(
42
+ "Please install VeADK extensions\npip install veadk-python[extensions]"
43
+ )
44
+
45
+
46
+ class OpensearchLTMBackend(BaseLongTermMemoryBackend):
47
+ opensearch_config: OpensearchConfig = Field(default_factory=OpensearchConfig)
48
+ """Opensearch client configs"""
49
+
50
+ embedding_config: EmbeddingModelConfig | NormalEmbeddingModelConfig = Field(
51
+ default_factory=EmbeddingModelConfig
52
+ )
53
+ """Embedding model configs"""
54
+
55
+ def precheck_index_naming(self):
56
+ if not (
57
+ isinstance(self.index, str)
58
+ and not self.index.startswith(("_", "-"))
59
+ and self.index.islower()
60
+ and re.match(r"^[a-z0-9_\-.]+$", self.index)
61
+ ):
62
+ raise ValueError(
63
+ "The index name does not conform to the naming rules of OpenSearch"
64
+ )
65
+
66
+ def model_post_init(self, __context: Any) -> None:
67
+ self._opensearch_client = OpensearchVectorClient(
68
+ endpoint=self.opensearch_config.host,
69
+ port=self.opensearch_config.port,
70
+ http_auth=(
71
+ self.opensearch_config.username,
72
+ self.opensearch_config.password,
73
+ ),
74
+ use_ssl=True,
75
+ verify_certs=False,
76
+ dim=self.embedding_config.dim,
77
+ index=self.index, # collection name
78
+ )
79
+
80
+ self._vector_store = OpensearchVectorStore(client=self._opensearch_client)
81
+
82
+ self._storage_context = StorageContext.from_defaults(
83
+ vector_store=self._vector_store
84
+ )
85
+
86
+ self._embed_model = OpenAILikeEmbedding(
87
+ model_name=self.embedding_config.name,
88
+ api_key=self.embedding_config.api_key,
89
+ api_base=self.embedding_config.api_base,
90
+ )
91
+
92
+ self._vector_index = VectorStoreIndex.from_documents(
93
+ documents=[],
94
+ storage_context=self._storage_context,
95
+ embed_model=self._embed_model,
96
+ )
97
+ self._retriever = self._vector_index.as_retriever()
98
+
99
+ @override
100
+ def save_memory(self, event_strings: list[str], **kwargs) -> bool:
101
+ for event_string in event_strings:
102
+ document = Document(text=event_string)
103
+ nodes = self._split_documents([document])
104
+ self._vector_index.insert_nodes(nodes)
105
+ return True
106
+
107
+ @override
108
+ def search_memory(self, query: str, top_k: int, **kwargs) -> list[str]:
109
+ _retriever = self._vector_index.as_retriever(similarity_top_k=top_k)
110
+ retrieved_nodes = _retriever.retrieve(query)
111
+ return [node.text for node in retrieved_nodes]
112
+
113
+ def _split_documents(self, documents: list[Document]) -> list[BaseNode]:
114
+ """Split document into chunks"""
115
+ nodes = []
116
+ for document in documents:
117
+ splitter = get_llama_index_splitter(document.metadata.get("file_path", ""))
118
+ _nodes = splitter.get_nodes_from_documents([document])
119
+ nodes.extend(_nodes)
120
+ return nodes
@@ -0,0 +1,127 @@
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 llama_index.core import (
16
+ Document,
17
+ StorageContext,
18
+ VectorStoreIndex,
19
+ )
20
+ from llama_index.core.schema import BaseNode
21
+ from llama_index.embeddings.openai_like import OpenAILikeEmbedding
22
+ from pydantic import Field
23
+ from typing_extensions import Any, override
24
+
25
+ import veadk.config # noqa E401
26
+ from veadk.configs.database_configs import RedisConfig
27
+ from veadk.configs.model_configs import EmbeddingModelConfig, NormalEmbeddingModelConfig
28
+ from veadk.knowledgebase.backends.utils import get_llama_index_splitter
29
+ from veadk.memory.long_term_memory_backends.base_backend import (
30
+ BaseLongTermMemoryBackend,
31
+ )
32
+
33
+ try:
34
+ from llama_index.vector_stores.redis import RedisVectorStore
35
+ from llama_index.vector_stores.redis.schema import (
36
+ RedisIndexInfo,
37
+ RedisVectorStoreSchema,
38
+ )
39
+ from redis import Redis
40
+ from redisvl.schema.fields import BaseVectorFieldAttributes
41
+ except ImportError:
42
+ raise ImportError(
43
+ "Please install VeADK extensions\npip install veadk-python[extensions]"
44
+ )
45
+
46
+
47
+ class RedisLTMBackend(BaseLongTermMemoryBackend):
48
+ redis_config: RedisConfig = Field(default_factory=RedisConfig)
49
+ """Redis client configs"""
50
+
51
+ embedding_config: EmbeddingModelConfig | NormalEmbeddingModelConfig = Field(
52
+ default_factory=EmbeddingModelConfig
53
+ )
54
+ """Embedding model configs"""
55
+
56
+ def precheck_index_naming(self):
57
+ # no checking
58
+ pass
59
+
60
+ def model_post_init(self, __context: Any) -> None:
61
+ # We will use `from_url` to init Redis client once the
62
+ # AK/SK -> STS token is ready.
63
+ # self._redis_client = Redis.from_url(url=...)
64
+
65
+ self._redis_client = Redis(
66
+ host=self.redis_config.host,
67
+ port=self.redis_config.port,
68
+ db=self.redis_config.db,
69
+ password=self.redis_config.password,
70
+ )
71
+
72
+ self._embed_model = OpenAILikeEmbedding(
73
+ model_name=self.embedding_config.name,
74
+ api_key=self.embedding_config.api_key,
75
+ api_base=self.embedding_config.api_base,
76
+ )
77
+
78
+ self._schema = RedisVectorStoreSchema(
79
+ index=RedisIndexInfo(name=self.index),
80
+ )
81
+ if "vector" in self._schema.fields:
82
+ vector_field = self._schema.fields["vector"]
83
+ if (
84
+ vector_field
85
+ and vector_field.attrs
86
+ and isinstance(vector_field.attrs, BaseVectorFieldAttributes)
87
+ ):
88
+ vector_field.attrs.dims = self.embedding_config.dim
89
+ self._vector_store = RedisVectorStore(
90
+ schema=self._schema,
91
+ redis_client=self._redis_client,
92
+ overwrite=True,
93
+ collection_name=self.index,
94
+ )
95
+
96
+ self._storage_context = StorageContext.from_defaults(
97
+ vector_store=self._vector_store
98
+ )
99
+
100
+ self._vector_index = VectorStoreIndex.from_documents(
101
+ documents=[],
102
+ storage_context=self._storage_context,
103
+ embed_model=self._embed_model,
104
+ )
105
+
106
+ @override
107
+ def save_memory(self, event_strings: list[str], **kwargs) -> bool:
108
+ for event_string in event_strings:
109
+ document = Document(text=event_string)
110
+ nodes = self._split_documents([document])
111
+ self._vector_index.insert_nodes(nodes)
112
+ return True
113
+
114
+ @override
115
+ def search_memory(self, query: str, top_k: int, **kwargs) -> list[str]:
116
+ _retriever = self._vector_index.as_retriever(similarity_top_k=top_k)
117
+ retrieved_nodes = _retriever.retrieve(query)
118
+ return [node.text for node in retrieved_nodes]
119
+
120
+ def _split_documents(self, documents: list[Document]) -> list[BaseNode]:
121
+ """Split document into chunks"""
122
+ nodes = []
123
+ for document in documents:
124
+ splitter = get_llama_index_splitter(document.metadata.get("file_path", ""))
125
+ _nodes = splitter.get_nodes_from_documents([document])
126
+ nodes.extend(_nodes)
127
+ return nodes
@@ -0,0 +1,148 @@
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 re
17
+ import time
18
+ import uuid
19
+ from typing import Any
20
+
21
+ from pydantic import Field
22
+ from typing_extensions import override
23
+
24
+ import veadk.config # noqa E401
25
+ from veadk.config import getenv
26
+ from veadk.memory.long_term_memory_backends.base_backend import (
27
+ BaseLongTermMemoryBackend,
28
+ )
29
+ from veadk.utils.logger import get_logger
30
+
31
+ try:
32
+ from mcp_server_vikingdb_memory.common.memory_client import VikingDBMemoryService
33
+ except ImportError:
34
+ raise ImportError(
35
+ "Please install VeADK extensions\npip install veadk-python[extensions]"
36
+ )
37
+
38
+ logger = get_logger(__name__)
39
+
40
+
41
+ class VikingDBLTMBackend(BaseLongTermMemoryBackend):
42
+ volcengine_access_key: str = Field(
43
+ default_factory=lambda: getenv("VOLCENGINE_ACCESS_KEY")
44
+ )
45
+
46
+ volcengine_secret_key: str = Field(
47
+ default_factory=lambda: getenv("VOLCENGINE_SECRET_KEY")
48
+ )
49
+
50
+ region: str = "cn-beijing"
51
+ """VikingDB memory region"""
52
+
53
+ def precheck_index_naming(self):
54
+ if not (
55
+ isinstance(self.index, str)
56
+ and 1 <= len(self.index) <= 128
57
+ and re.fullmatch(r"^[a-zA-Z][a-zA-Z0-9_]*$", self.index)
58
+ ):
59
+ raise ValueError(
60
+ "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."
61
+ )
62
+
63
+ def model_post_init(self, __context: Any) -> None:
64
+ self._client = VikingDBMemoryService(
65
+ ak=self.volcengine_access_key,
66
+ sk=self.volcengine_secret_key,
67
+ region=self.region,
68
+ )
69
+
70
+ # check whether collection exist, if not, create it
71
+ if not self._collection_exist():
72
+ self._create_collection()
73
+
74
+ def _collection_exist(self) -> bool:
75
+ try:
76
+ self._client.get_collection(collection_name=self.index)
77
+ return True
78
+ except Exception:
79
+ return False
80
+
81
+ def _create_collection(self) -> None:
82
+ response = self._client.create_collection(
83
+ collection_name=self.index,
84
+ description="Created by Volcengine Agent Development Kit VeADK",
85
+ builtin_event_types=["sys_event_v1"],
86
+ )
87
+ return response
88
+
89
+ @override
90
+ def save_memory(self, event_strings: list[str], **kwargs) -> bool:
91
+ user_id = kwargs.get("user_id")
92
+ if user_id is None:
93
+ raise ValueError("user_id is required")
94
+ session_id = str(uuid.uuid1())
95
+ messages = []
96
+ for raw_events in event_strings:
97
+ event = json.loads(raw_events)
98
+ content = event["parts"][0]["text"]
99
+ role = (
100
+ "user" if event["role"] == "user" else "assistant"
101
+ ) # field 'role': viking memory only allow 'assistant','system','user',
102
+ messages.append({"role": role, "content": content})
103
+ metadata = {
104
+ "default_user_id": user_id,
105
+ "default_assistant_id": "assistant",
106
+ "time": int(time.time() * 1000),
107
+ }
108
+ response = self._client.add_messages(
109
+ collection_name=self.index,
110
+ messages=messages,
111
+ metadata=metadata,
112
+ session_id=session_id,
113
+ )
114
+
115
+ if not response.get("code") == 0:
116
+ raise ValueError(f"Save VikingDB memory error: {response}")
117
+
118
+ return True
119
+
120
+ @override
121
+ def search_memory(self, query: str, top_k: int, **kwargs) -> list[str]:
122
+ user_id = kwargs.get("user_id")
123
+ if user_id is None:
124
+ raise ValueError("user_id is required")
125
+ filter = {
126
+ "user_id": user_id,
127
+ "memory_type": ["sys_event_v1"],
128
+ }
129
+ response = self._client.search_memory(
130
+ collection_name=self.index, query=query, filter=filter, limit=top_k
131
+ )
132
+
133
+ if not response.get("code") == 0:
134
+ raise ValueError(f"Search VikingDB memory error: {response}")
135
+
136
+ result = response.get("data", {}).get("result_list", [])
137
+ if result:
138
+ return [
139
+ json.dumps(
140
+ {
141
+ "role": "user",
142
+ "parts": [{"text": r.get("memory_info").get("summary")}],
143
+ },
144
+ ensure_ascii=False,
145
+ )
146
+ for r in result
147
+ ]
148
+ return []