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.
- veadk/__init__.py +37 -0
- veadk/a2a/__init__.py +13 -0
- veadk/a2a/agent_card.py +45 -0
- veadk/a2a/remote_ve_agent.py +390 -0
- veadk/a2a/utils/__init__.py +13 -0
- veadk/a2a/utils/agent_to_a2a.py +170 -0
- veadk/a2a/ve_a2a_server.py +93 -0
- veadk/a2a/ve_agent_executor.py +78 -0
- veadk/a2a/ve_middlewares.py +313 -0
- veadk/a2a/ve_task_store.py +37 -0
- veadk/agent.py +402 -0
- veadk/agent_builder.py +93 -0
- veadk/agents/loop_agent.py +68 -0
- veadk/agents/parallel_agent.py +72 -0
- veadk/agents/sequential_agent.py +64 -0
- veadk/auth/__init__.py +13 -0
- veadk/auth/base_auth.py +22 -0
- veadk/auth/ve_credential_service.py +203 -0
- veadk/auth/veauth/__init__.py +13 -0
- veadk/auth/veauth/apmplus_veauth.py +58 -0
- veadk/auth/veauth/ark_veauth.py +75 -0
- veadk/auth/veauth/base_veauth.py +50 -0
- veadk/auth/veauth/cozeloop_veauth.py +13 -0
- veadk/auth/veauth/opensearch_veauth.py +75 -0
- veadk/auth/veauth/postgresql_veauth.py +75 -0
- veadk/auth/veauth/prompt_pilot_veauth.py +60 -0
- veadk/auth/veauth/speech_veauth.py +54 -0
- veadk/auth/veauth/utils.py +69 -0
- veadk/auth/veauth/vesearch_veauth.py +62 -0
- veadk/auth/veauth/viking_mem0_veauth.py +91 -0
- veadk/cli/__init__.py +13 -0
- veadk/cli/cli.py +58 -0
- veadk/cli/cli_clean.py +87 -0
- veadk/cli/cli_create.py +163 -0
- veadk/cli/cli_deploy.py +233 -0
- veadk/cli/cli_eval.py +215 -0
- veadk/cli/cli_init.py +214 -0
- veadk/cli/cli_kb.py +110 -0
- veadk/cli/cli_pipeline.py +285 -0
- veadk/cli/cli_prompt.py +86 -0
- veadk/cli/cli_update.py +106 -0
- veadk/cli/cli_uploadevalset.py +139 -0
- veadk/cli/cli_web.py +143 -0
- veadk/cloud/__init__.py +13 -0
- veadk/cloud/cloud_agent_engine.py +485 -0
- veadk/cloud/cloud_app.py +475 -0
- veadk/config.py +115 -0
- veadk/configs/__init__.py +13 -0
- veadk/configs/auth_configs.py +133 -0
- veadk/configs/database_configs.py +132 -0
- veadk/configs/model_configs.py +78 -0
- veadk/configs/tool_configs.py +54 -0
- veadk/configs/tracing_configs.py +110 -0
- veadk/consts.py +74 -0
- veadk/evaluation/__init__.py +17 -0
- veadk/evaluation/adk_evaluator/__init__.py +17 -0
- veadk/evaluation/adk_evaluator/adk_evaluator.py +302 -0
- veadk/evaluation/base_evaluator.py +642 -0
- veadk/evaluation/deepeval_evaluator/__init__.py +17 -0
- veadk/evaluation/deepeval_evaluator/deepeval_evaluator.py +339 -0
- veadk/evaluation/eval_set_file_loader.py +48 -0
- veadk/evaluation/eval_set_recorder.py +146 -0
- veadk/evaluation/types.py +65 -0
- veadk/evaluation/utils/prometheus.py +196 -0
- veadk/integrations/__init__.py +13 -0
- veadk/integrations/ve_apig/__init__.py +13 -0
- veadk/integrations/ve_apig/ve_apig.py +349 -0
- veadk/integrations/ve_apig/ve_apig_utils.py +332 -0
- veadk/integrations/ve_code_pipeline/__init__.py +13 -0
- veadk/integrations/ve_code_pipeline/ve_code_pipeline.py +431 -0
- veadk/integrations/ve_cozeloop/__init__.py +13 -0
- veadk/integrations/ve_cozeloop/ve_cozeloop.py +96 -0
- veadk/integrations/ve_cr/__init__.py +13 -0
- veadk/integrations/ve_cr/ve_cr.py +220 -0
- veadk/integrations/ve_faas/__init__.py +13 -0
- veadk/integrations/ve_faas/template/cookiecutter.json +15 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/__init__.py +13 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/clean.py +23 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/config.yaml.example +6 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/deploy.py +106 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/__init__.py +13 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/agent.py +25 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/app.py +202 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/requirements.txt +3 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/run.sh +49 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{ cookiecutter.app_name }}/__init__.py +14 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{ cookiecutter.app_name }}/agent.py +27 -0
- veadk/integrations/ve_faas/ve_faas.py +754 -0
- veadk/integrations/ve_faas/ve_faas_utils.py +408 -0
- veadk/integrations/ve_faas/web_template/cookiecutter.json +20 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/__init__.py +13 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/clean.py +23 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/config.yaml.example +2 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/deploy.py +44 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/Dockerfile +23 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/app.py +123 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/init_db.py +46 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/models.py +36 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/requirements.txt +4 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/run.sh +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/css/style.css +368 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/js/admin.js +0 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/dashboard.html +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/edit_post.html +24 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/login.html +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/posts.html +53 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/base.html +45 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/index.html +29 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/post.html +14 -0
- veadk/integrations/ve_identity/__init__.py +110 -0
- veadk/integrations/ve_identity/auth_config.py +261 -0
- veadk/integrations/ve_identity/auth_mixins.py +650 -0
- veadk/integrations/ve_identity/auth_processor.py +385 -0
- veadk/integrations/ve_identity/function_tool.py +158 -0
- veadk/integrations/ve_identity/identity_client.py +864 -0
- veadk/integrations/ve_identity/mcp_tool.py +181 -0
- veadk/integrations/ve_identity/mcp_toolset.py +431 -0
- veadk/integrations/ve_identity/models.py +228 -0
- veadk/integrations/ve_identity/token_manager.py +188 -0
- veadk/integrations/ve_identity/utils.py +151 -0
- veadk/integrations/ve_prompt_pilot/__init__.py +13 -0
- veadk/integrations/ve_prompt_pilot/ve_prompt_pilot.py +85 -0
- veadk/integrations/ve_tls/__init__.py +13 -0
- veadk/integrations/ve_tls/utils.py +116 -0
- veadk/integrations/ve_tls/ve_tls.py +212 -0
- veadk/integrations/ve_tos/ve_tos.py +710 -0
- veadk/integrations/ve_viking_db_memory/__init__.py +13 -0
- veadk/integrations/ve_viking_db_memory/ve_viking_db_memory.py +308 -0
- veadk/knowledgebase/__init__.py +17 -0
- veadk/knowledgebase/backends/__init__.py +13 -0
- veadk/knowledgebase/backends/base_backend.py +72 -0
- veadk/knowledgebase/backends/in_memory_backend.py +91 -0
- veadk/knowledgebase/backends/opensearch_backend.py +162 -0
- veadk/knowledgebase/backends/redis_backend.py +172 -0
- veadk/knowledgebase/backends/utils.py +92 -0
- veadk/knowledgebase/backends/vikingdb_knowledge_backend.py +608 -0
- veadk/knowledgebase/entry.py +25 -0
- veadk/knowledgebase/knowledgebase.py +307 -0
- veadk/memory/__init__.py +35 -0
- veadk/memory/long_term_memory.py +365 -0
- veadk/memory/long_term_memory_backends/__init__.py +13 -0
- veadk/memory/long_term_memory_backends/base_backend.py +35 -0
- veadk/memory/long_term_memory_backends/in_memory_backend.py +67 -0
- veadk/memory/long_term_memory_backends/mem0_backend.py +155 -0
- veadk/memory/long_term_memory_backends/opensearch_backend.py +124 -0
- veadk/memory/long_term_memory_backends/redis_backend.py +140 -0
- veadk/memory/long_term_memory_backends/vikingdb_memory_backend.py +189 -0
- veadk/memory/short_term_memory.py +252 -0
- veadk/memory/short_term_memory_backends/__init__.py +13 -0
- veadk/memory/short_term_memory_backends/base_backend.py +31 -0
- veadk/memory/short_term_memory_backends/mysql_backend.py +49 -0
- veadk/memory/short_term_memory_backends/postgresql_backend.py +49 -0
- veadk/memory/short_term_memory_backends/sqlite_backend.py +55 -0
- veadk/memory/short_term_memory_processor.py +100 -0
- veadk/processors/__init__.py +26 -0
- veadk/processors/base_run_processor.py +120 -0
- veadk/prompts/__init__.py +13 -0
- veadk/prompts/agent_default_prompt.py +30 -0
- veadk/prompts/prompt_evaluator.py +20 -0
- veadk/prompts/prompt_memory_processor.py +55 -0
- veadk/prompts/prompt_optimization.py +150 -0
- veadk/runner.py +732 -0
- veadk/tools/__init__.py +13 -0
- veadk/tools/builtin_tools/__init__.py +13 -0
- veadk/tools/builtin_tools/agent_authorization.py +94 -0
- veadk/tools/builtin_tools/generate_image.py +23 -0
- veadk/tools/builtin_tools/image_edit.py +300 -0
- veadk/tools/builtin_tools/image_generate.py +446 -0
- veadk/tools/builtin_tools/lark.py +67 -0
- veadk/tools/builtin_tools/las.py +24 -0
- veadk/tools/builtin_tools/link_reader.py +66 -0
- veadk/tools/builtin_tools/llm_shield.py +381 -0
- veadk/tools/builtin_tools/load_knowledgebase.py +97 -0
- veadk/tools/builtin_tools/mcp_router.py +29 -0
- veadk/tools/builtin_tools/run_code.py +113 -0
- veadk/tools/builtin_tools/tts.py +253 -0
- veadk/tools/builtin_tools/vesearch.py +49 -0
- veadk/tools/builtin_tools/video_generate.py +363 -0
- veadk/tools/builtin_tools/web_scraper.py +76 -0
- veadk/tools/builtin_tools/web_search.py +83 -0
- veadk/tools/demo_tools.py +58 -0
- veadk/tools/load_knowledgebase_tool.py +149 -0
- veadk/tools/sandbox/__init__.py +13 -0
- veadk/tools/sandbox/browser_sandbox.py +37 -0
- veadk/tools/sandbox/code_sandbox.py +40 -0
- veadk/tools/sandbox/computer_sandbox.py +34 -0
- veadk/tracing/__init__.py +13 -0
- veadk/tracing/base_tracer.py +58 -0
- veadk/tracing/telemetry/__init__.py +13 -0
- veadk/tracing/telemetry/attributes/attributes.py +29 -0
- veadk/tracing/telemetry/attributes/extractors/common_attributes_extractors.py +180 -0
- veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py +858 -0
- veadk/tracing/telemetry/attributes/extractors/tool_attributes_extractors.py +152 -0
- veadk/tracing/telemetry/attributes/extractors/types.py +164 -0
- veadk/tracing/telemetry/exporters/__init__.py +13 -0
- veadk/tracing/telemetry/exporters/apmplus_exporter.py +558 -0
- veadk/tracing/telemetry/exporters/base_exporter.py +39 -0
- veadk/tracing/telemetry/exporters/cozeloop_exporter.py +129 -0
- veadk/tracing/telemetry/exporters/inmemory_exporter.py +248 -0
- veadk/tracing/telemetry/exporters/tls_exporter.py +139 -0
- veadk/tracing/telemetry/opentelemetry_tracer.py +320 -0
- veadk/tracing/telemetry/telemetry.py +411 -0
- veadk/types.py +47 -0
- veadk/utils/__init__.py +13 -0
- veadk/utils/audio_manager.py +95 -0
- veadk/utils/auth.py +294 -0
- veadk/utils/logger.py +59 -0
- veadk/utils/mcp_utils.py +44 -0
- veadk/utils/misc.py +184 -0
- veadk/utils/patches.py +101 -0
- veadk/utils/volcengine_sign.py +205 -0
- veadk/version.py +15 -0
- veadk_python-0.2.27.dist-info/METADATA +373 -0
- veadk_python-0.2.27.dist-info/RECORD +218 -0
- veadk_python-0.2.27.dist-info/WHEEL +5 -0
- veadk_python-0.2.27.dist-info/entry_points.txt +2 -0
- veadk_python-0.2.27.dist-info/licenses/LICENSE +201 -0
- veadk_python-0.2.27.dist-info/top_level.txt +1 -0
|
@@ -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,35 @@
|
|
|
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 abc import ABC, abstractmethod
|
|
16
|
+
|
|
17
|
+
from pydantic import BaseModel
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class BaseLongTermMemoryBackend(ABC, BaseModel):
|
|
21
|
+
index: str
|
|
22
|
+
|
|
23
|
+
@abstractmethod
|
|
24
|
+
def precheck_index_naming(self):
|
|
25
|
+
"""Check the index name is valid or not"""
|
|
26
|
+
|
|
27
|
+
@abstractmethod
|
|
28
|
+
def save_memory(self, user_id: str, event_strings: list[str], **kwargs) -> bool:
|
|
29
|
+
"""Save memory to long term memory backend"""
|
|
30
|
+
|
|
31
|
+
@abstractmethod
|
|
32
|
+
def search_memory(
|
|
33
|
+
self, user_id: str, query: str, top_k: int, **kwargs
|
|
34
|
+
) -> list[str]:
|
|
35
|
+
"""Retrieve memory from long term memory backend"""
|
|
@@ -0,0 +1,67 @@
|
|
|
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 Document, VectorStoreIndex
|
|
16
|
+
from llama_index.core.schema import BaseNode
|
|
17
|
+
from llama_index.embeddings.openai_like import OpenAILikeEmbedding
|
|
18
|
+
from pydantic import Field
|
|
19
|
+
from typing_extensions import Any, override
|
|
20
|
+
|
|
21
|
+
from veadk.configs.model_configs import EmbeddingModelConfig
|
|
22
|
+
from veadk.knowledgebase.backends.utils import get_llama_index_splitter
|
|
23
|
+
from veadk.memory.long_term_memory_backends.base_backend import (
|
|
24
|
+
BaseLongTermMemoryBackend,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class InMemoryLTMBackend(BaseLongTermMemoryBackend):
|
|
29
|
+
embedding_config: EmbeddingModelConfig = Field(default_factory=EmbeddingModelConfig)
|
|
30
|
+
"""Embedding model configs"""
|
|
31
|
+
|
|
32
|
+
def model_post_init(self, __context: Any) -> None:
|
|
33
|
+
self._embed_model = OpenAILikeEmbedding(
|
|
34
|
+
model_name=self.embedding_config.name,
|
|
35
|
+
api_key=self.embedding_config.api_key,
|
|
36
|
+
api_base=self.embedding_config.api_base,
|
|
37
|
+
)
|
|
38
|
+
self._vector_index = VectorStoreIndex([], embed_model=self._embed_model)
|
|
39
|
+
|
|
40
|
+
def precheck_index_naming(self):
|
|
41
|
+
# no checking
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
@override
|
|
45
|
+
def save_memory(self, user_id: str, event_strings: list[str], **kwargs) -> bool:
|
|
46
|
+
for event_string in event_strings:
|
|
47
|
+
document = Document(text=event_string)
|
|
48
|
+
nodes = self._split_documents([document])
|
|
49
|
+
self._vector_index.insert_nodes(nodes)
|
|
50
|
+
return True
|
|
51
|
+
|
|
52
|
+
@override
|
|
53
|
+
def search_memory(
|
|
54
|
+
self, user_id: str, query: str, top_k: int, **kwargs
|
|
55
|
+
) -> list[str]:
|
|
56
|
+
_retriever = self._vector_index.as_retriever(similarity_top_k=top_k)
|
|
57
|
+
retrieved_nodes = _retriever.retrieve(query)
|
|
58
|
+
return [node.text for node in retrieved_nodes]
|
|
59
|
+
|
|
60
|
+
def _split_documents(self, documents: list[Document]) -> list[BaseNode]:
|
|
61
|
+
"""Split document into chunks"""
|
|
62
|
+
nodes = []
|
|
63
|
+
for document in documents:
|
|
64
|
+
splitter = get_llama_index_splitter(document.metadata.get("file_path", ""))
|
|
65
|
+
_nodes = splitter.get_nodes_from_documents([document])
|
|
66
|
+
nodes.extend(_nodes)
|
|
67
|
+
return nodes
|
|
@@ -0,0 +1,155 @@
|
|
|
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
|
+
|
|
17
|
+
from pydantic import Field
|
|
18
|
+
from typing_extensions import override
|
|
19
|
+
|
|
20
|
+
from veadk.auth.veauth.viking_mem0_veauth import get_viking_mem0_token
|
|
21
|
+
from veadk.configs.database_configs import Mem0Config
|
|
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
|
+
if not self.mem0_config.api_key:
|
|
48
|
+
if not self.mem0_config.api_key_id and not self.mem0_config.project_id:
|
|
49
|
+
raise ValueError(
|
|
50
|
+
"API Key not set, auto fetching api key needs `api_key_id` or `project_id`"
|
|
51
|
+
)
|
|
52
|
+
self.mem0_config.api_key = get_viking_mem0_token(
|
|
53
|
+
api_key_id=self.mem0_config.api_key_id,
|
|
54
|
+
memory_project_id=self.mem0_config.project_id,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
self._mem0_client = MemoryClient(
|
|
59
|
+
host=self.mem0_config.base_url, # mem0 endpoint
|
|
60
|
+
api_key=self.mem0_config.api_key, # mem0 API key
|
|
61
|
+
)
|
|
62
|
+
logger.info(
|
|
63
|
+
f"Initialized Mem0 client for host: {self.mem0_config.base_url}"
|
|
64
|
+
)
|
|
65
|
+
logger.info(f"Initialized Mem0 client for index: {self.index}")
|
|
66
|
+
except Exception as e:
|
|
67
|
+
logger.error(
|
|
68
|
+
f"Failed to initialize Mem0 client for host {self.mem0_config.base_url} : {str(e)}"
|
|
69
|
+
)
|
|
70
|
+
raise
|
|
71
|
+
|
|
72
|
+
def precheck_index_naming(self):
|
|
73
|
+
"""Check if the index name is valid
|
|
74
|
+
For Mem0, there are no specific naming constraints
|
|
75
|
+
"""
|
|
76
|
+
pass
|
|
77
|
+
|
|
78
|
+
@override
|
|
79
|
+
def save_memory(
|
|
80
|
+
self, event_strings: list[str], user_id: str = "default_user", **kwargs
|
|
81
|
+
) -> bool:
|
|
82
|
+
"""Save memory to Mem0
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
event_strings: List of event strings to save
|
|
86
|
+
**kwargs: Additional parameters, including 'user_id' for Mem0
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
bool: True if saved successfully, False otherwise
|
|
90
|
+
"""
|
|
91
|
+
try:
|
|
92
|
+
logger.info(
|
|
93
|
+
f"Saving {len(event_strings)} events to Mem0 for user: {user_id}"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
for event_string in event_strings:
|
|
97
|
+
# Save event string to Mem0
|
|
98
|
+
result = self._mem0_client.add(
|
|
99
|
+
[{"role": "user", "content": event_string}],
|
|
100
|
+
user_id=user_id,
|
|
101
|
+
output_format="v1.1",
|
|
102
|
+
async_mode=True,
|
|
103
|
+
)
|
|
104
|
+
logger.debug(f"Saved memory result: {result}")
|
|
105
|
+
|
|
106
|
+
logger.info(f"Successfully saved {len(event_strings)} events to Mem0")
|
|
107
|
+
return True
|
|
108
|
+
except Exception as e:
|
|
109
|
+
logger.error(f"Failed to save memory to Mem0: {str(e)}")
|
|
110
|
+
return False
|
|
111
|
+
|
|
112
|
+
@override
|
|
113
|
+
def search_memory(
|
|
114
|
+
self, query: str, top_k: int, user_id: str = "default_user", **kwargs
|
|
115
|
+
) -> list[str]:
|
|
116
|
+
"""Search memory from Mem0
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
query: Search query
|
|
120
|
+
top_k: Number of results to return
|
|
121
|
+
**kwargs: Additional parameters, including 'user_id' for Mem0
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
list[str]: List of memory strings
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
try:
|
|
128
|
+
logger.info(
|
|
129
|
+
f"Searching Mem0 for query: {query}, user: {user_id}, top_k: {top_k}"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
memories = self._mem0_client.search(
|
|
133
|
+
query, user_id=user_id, output_format="v1.1", top_k=top_k
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
logger.debug(f"return relevant memories: {memories}")
|
|
137
|
+
|
|
138
|
+
memory_list = []
|
|
139
|
+
# 如果 memories 是列表,直接返回
|
|
140
|
+
if isinstance(memories, list):
|
|
141
|
+
for mem in memories:
|
|
142
|
+
if "memory" in mem:
|
|
143
|
+
memory_list.append(mem["memory"])
|
|
144
|
+
return memory_list
|
|
145
|
+
|
|
146
|
+
if memories.get("results", []):
|
|
147
|
+
for mem in memories["results"]:
|
|
148
|
+
if "memory" in mem:
|
|
149
|
+
memory_list.append(mem["memory"])
|
|
150
|
+
|
|
151
|
+
logger.info(f"Found {len(memory_list)} memories matching query: {query}")
|
|
152
|
+
return memory_list
|
|
153
|
+
except Exception as e:
|
|
154
|
+
logger.error(f"Failed to search memory from Mem0: {str(e)}")
|
|
155
|
+
return []
|
|
@@ -0,0 +1,124 @@
|
|
|
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 Document, VectorStoreIndex
|
|
18
|
+
from llama_index.core.schema import BaseNode
|
|
19
|
+
from llama_index.embeddings.openai_like import OpenAILikeEmbedding
|
|
20
|
+
from pydantic import Field
|
|
21
|
+
from typing_extensions import Any, override
|
|
22
|
+
|
|
23
|
+
import veadk.config # noqa E401
|
|
24
|
+
from veadk.configs.database_configs import OpensearchConfig
|
|
25
|
+
from veadk.configs.model_configs import EmbeddingModelConfig, NormalEmbeddingModelConfig
|
|
26
|
+
from veadk.knowledgebase.backends.utils import get_llama_index_splitter
|
|
27
|
+
from veadk.memory.long_term_memory_backends.base_backend import (
|
|
28
|
+
BaseLongTermMemoryBackend,
|
|
29
|
+
)
|
|
30
|
+
from veadk.utils.logger import get_logger
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
from llama_index.vector_stores.opensearch import (
|
|
34
|
+
OpensearchVectorClient,
|
|
35
|
+
OpensearchVectorStore,
|
|
36
|
+
)
|
|
37
|
+
except ImportError:
|
|
38
|
+
raise ImportError(
|
|
39
|
+
"Please install VeADK extensions\npip install veadk-python[extensions]"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
logger = get_logger(__name__)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class OpensearchLTMBackend(BaseLongTermMemoryBackend):
|
|
46
|
+
opensearch_config: OpensearchConfig = Field(default_factory=OpensearchConfig)
|
|
47
|
+
"""Opensearch client configs"""
|
|
48
|
+
|
|
49
|
+
embedding_config: EmbeddingModelConfig | NormalEmbeddingModelConfig = Field(
|
|
50
|
+
default_factory=EmbeddingModelConfig
|
|
51
|
+
)
|
|
52
|
+
"""Embedding model configs"""
|
|
53
|
+
|
|
54
|
+
def model_post_init(self, __context: Any) -> None:
|
|
55
|
+
self._embed_model = OpenAILikeEmbedding(
|
|
56
|
+
model_name=self.embedding_config.name,
|
|
57
|
+
api_key=self.embedding_config.api_key,
|
|
58
|
+
api_base=self.embedding_config.api_base,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
def precheck_index_naming(self, index: str):
|
|
62
|
+
if not (
|
|
63
|
+
isinstance(index, str)
|
|
64
|
+
and not index.startswith(("_", "-"))
|
|
65
|
+
and index.islower()
|
|
66
|
+
and re.match(r"^[a-z0-9_\-.]+$", index)
|
|
67
|
+
):
|
|
68
|
+
raise ValueError(
|
|
69
|
+
f"The index name {index} does not conform to the naming rules of OpenSearch"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
def _create_vector_index(self, index: str) -> VectorStoreIndex:
|
|
73
|
+
logger.info(f"Create OpenSearch vector index with index={index}")
|
|
74
|
+
|
|
75
|
+
self.precheck_index_naming(index)
|
|
76
|
+
|
|
77
|
+
opensearch_client = OpensearchVectorClient(
|
|
78
|
+
endpoint=self.opensearch_config.host,
|
|
79
|
+
port=self.opensearch_config.port,
|
|
80
|
+
http_auth=(
|
|
81
|
+
self.opensearch_config.username,
|
|
82
|
+
self.opensearch_config.password,
|
|
83
|
+
),
|
|
84
|
+
use_ssl=True,
|
|
85
|
+
verify_certs=False,
|
|
86
|
+
dim=self.embedding_config.dim,
|
|
87
|
+
index=index,
|
|
88
|
+
)
|
|
89
|
+
vector_store = OpensearchVectorStore(client=opensearch_client)
|
|
90
|
+
return VectorStoreIndex.from_vector_store(
|
|
91
|
+
vector_store=vector_store, embed_model=self._embed_model
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
@override
|
|
95
|
+
def save_memory(self, user_id: str, event_strings: list[str], **kwargs) -> bool:
|
|
96
|
+
index = f"{self.index}_{user_id}"
|
|
97
|
+
vector_index = self._create_vector_index(index)
|
|
98
|
+
|
|
99
|
+
for event_string in event_strings:
|
|
100
|
+
document = Document(text=event_string)
|
|
101
|
+
nodes = self._split_documents([document])
|
|
102
|
+
vector_index.insert_nodes(nodes)
|
|
103
|
+
return True
|
|
104
|
+
|
|
105
|
+
@override
|
|
106
|
+
def search_memory(
|
|
107
|
+
self, user_id: str, query: str, top_k: int, **kwargs
|
|
108
|
+
) -> list[str]:
|
|
109
|
+
index = f"{self.index}_{user_id}"
|
|
110
|
+
|
|
111
|
+
vector_index = self._create_vector_index(index)
|
|
112
|
+
|
|
113
|
+
_retriever = vector_index.as_retriever(similarity_top_k=top_k)
|
|
114
|
+
retrieved_nodes = _retriever.retrieve(query)
|
|
115
|
+
return [node.text for node in retrieved_nodes]
|
|
116
|
+
|
|
117
|
+
def _split_documents(self, documents: list[Document]) -> list[BaseNode]:
|
|
118
|
+
"""Split document into chunks"""
|
|
119
|
+
nodes = []
|
|
120
|
+
for document in documents:
|
|
121
|
+
splitter = get_llama_index_splitter(document.metadata.get("file_path", ""))
|
|
122
|
+
_nodes = splitter.get_nodes_from_documents([document])
|
|
123
|
+
nodes.extend(_nodes)
|
|
124
|
+
return nodes
|
|
@@ -0,0 +1,140 @@
|
|
|
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 Document, VectorStoreIndex
|
|
16
|
+
from llama_index.core.schema import BaseNode
|
|
17
|
+
from llama_index.embeddings.openai_like import OpenAILikeEmbedding
|
|
18
|
+
from pydantic import Field
|
|
19
|
+
from typing_extensions import Any, override
|
|
20
|
+
|
|
21
|
+
import veadk.config # noqa E401
|
|
22
|
+
from veadk.configs.database_configs import RedisConfig
|
|
23
|
+
from veadk.configs.model_configs import EmbeddingModelConfig, NormalEmbeddingModelConfig
|
|
24
|
+
from veadk.knowledgebase.backends.utils import get_llama_index_splitter
|
|
25
|
+
from veadk.memory.long_term_memory_backends.base_backend import (
|
|
26
|
+
BaseLongTermMemoryBackend,
|
|
27
|
+
)
|
|
28
|
+
from veadk.utils.logger import get_logger
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
from llama_index.vector_stores.redis import RedisVectorStore
|
|
32
|
+
from redis import Redis
|
|
33
|
+
from redisvl.schema import IndexSchema
|
|
34
|
+
|
|
35
|
+
except ImportError:
|
|
36
|
+
raise ImportError(
|
|
37
|
+
"Please install VeADK extensions\npip install veadk-python[extensions]"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
logger = get_logger(__name__)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class RedisLTMBackend(BaseLongTermMemoryBackend):
|
|
45
|
+
redis_config: RedisConfig = Field(default_factory=RedisConfig)
|
|
46
|
+
"""Redis client configs"""
|
|
47
|
+
|
|
48
|
+
embedding_config: EmbeddingModelConfig | NormalEmbeddingModelConfig = Field(
|
|
49
|
+
default_factory=EmbeddingModelConfig
|
|
50
|
+
)
|
|
51
|
+
"""Embedding model configs"""
|
|
52
|
+
|
|
53
|
+
def model_post_init(self, __context: Any) -> None:
|
|
54
|
+
self._embed_model = OpenAILikeEmbedding(
|
|
55
|
+
model_name=self.embedding_config.name,
|
|
56
|
+
api_key=self.embedding_config.api_key,
|
|
57
|
+
api_base=self.embedding_config.api_base,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
def precheck_index_naming(self, index: str):
|
|
61
|
+
# no checking
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
def _create_vector_index(self, index: str) -> VectorStoreIndex:
|
|
65
|
+
logger.info(f"Create Redis vector index with index={index}")
|
|
66
|
+
|
|
67
|
+
self.precheck_index_naming(index)
|
|
68
|
+
|
|
69
|
+
# We will use `from_url` to init Redis client once the
|
|
70
|
+
# AK/SK -> STS token is ready.
|
|
71
|
+
# self._redis_client = Redis.from_url(url=...)
|
|
72
|
+
redis_client = Redis(
|
|
73
|
+
host=self.redis_config.host,
|
|
74
|
+
port=self.redis_config.port,
|
|
75
|
+
db=self.redis_config.db,
|
|
76
|
+
password=self.redis_config.password,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Create an index for each user
|
|
80
|
+
# Should be Optimized in the future
|
|
81
|
+
schema = IndexSchema.from_dict(
|
|
82
|
+
{
|
|
83
|
+
"index": {"name": index, "prefix": index, "key_separator": "_"},
|
|
84
|
+
"fields": [
|
|
85
|
+
{"name": "id", "type": "tag", "attrs": {"sortable": False}},
|
|
86
|
+
{"name": "doc_id", "type": "tag", "attrs": {"sortable": False}},
|
|
87
|
+
{"name": "text", "type": "text", "attrs": {"weight": 1.0}},
|
|
88
|
+
{
|
|
89
|
+
"name": "vector",
|
|
90
|
+
"type": "vector",
|
|
91
|
+
"attrs": {
|
|
92
|
+
"dims": self.embedding_config.dim,
|
|
93
|
+
"algorithm": "flat",
|
|
94
|
+
"distance_metric": "cosine",
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
}
|
|
99
|
+
)
|
|
100
|
+
vector_store = RedisVectorStore(schema=schema, redis_client=redis_client)
|
|
101
|
+
|
|
102
|
+
logger.info(
|
|
103
|
+
f"Create vector store done, index_name={vector_store.index_name} prefix={vector_store.schema.index.prefix}"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
return VectorStoreIndex.from_vector_store(
|
|
107
|
+
vector_store=vector_store, embed_model=self._embed_model
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
@override
|
|
111
|
+
def save_memory(self, user_id: str, event_strings: list[str], **kwargs) -> bool:
|
|
112
|
+
index = f"veadk-ltm/{self.index}/{user_id}"
|
|
113
|
+
vector_index = self._create_vector_index(index)
|
|
114
|
+
|
|
115
|
+
for event_string in event_strings:
|
|
116
|
+
document = Document(text=event_string)
|
|
117
|
+
nodes = self._split_documents([document])
|
|
118
|
+
vector_index.insert_nodes(nodes)
|
|
119
|
+
|
|
120
|
+
return True
|
|
121
|
+
|
|
122
|
+
@override
|
|
123
|
+
def search_memory(
|
|
124
|
+
self, user_id: str, query: str, top_k: int, **kwargs
|
|
125
|
+
) -> list[str]:
|
|
126
|
+
index = f"veadk-ltm/{self.index}/{user_id}"
|
|
127
|
+
vector_index = self._create_vector_index(index)
|
|
128
|
+
|
|
129
|
+
_retriever = vector_index.as_retriever(similarity_top_k=top_k)
|
|
130
|
+
retrieved_nodes = _retriever.retrieve(query)
|
|
131
|
+
return [node.text for node in retrieved_nodes]
|
|
132
|
+
|
|
133
|
+
def _split_documents(self, documents: list[Document]) -> list[BaseNode]:
|
|
134
|
+
"""Split document into chunks"""
|
|
135
|
+
nodes = []
|
|
136
|
+
for document in documents:
|
|
137
|
+
splitter = get_llama_index_splitter(document.metadata.get("file_path", ""))
|
|
138
|
+
_nodes = splitter.get_nodes_from_documents([document])
|
|
139
|
+
nodes.extend(_nodes)
|
|
140
|
+
return nodes
|