agent-framework-mem0 1.0.0b260127__tar.gz
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.
- agent_framework_mem0-1.0.0b260127/LICENSE +21 -0
- agent_framework_mem0-1.0.0b260127/PKG-INFO +46 -0
- agent_framework_mem0-1.0.0b260127/README.md +20 -0
- agent_framework_mem0-1.0.0b260127/agent_framework_mem0/__init__.py +15 -0
- agent_framework_mem0-1.0.0b260127/agent_framework_mem0/_provider.py +229 -0
- agent_framework_mem0-1.0.0b260127/pyproject.toml +89 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Microsoft Corporation.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agent-framework-mem0
|
|
3
|
+
Version: 1.0.0b260127
|
|
4
|
+
Summary: Mem0 integration for Microsoft Agent Framework.
|
|
5
|
+
Author-email: Microsoft <af-support@microsoft.com>
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: Typing :: Typed
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: agent-framework-core
|
|
20
|
+
Requires-Dist: mem0ai>=1.0.0
|
|
21
|
+
Project-URL: homepage, https://aka.ms/agent-framework
|
|
22
|
+
Project-URL: issues, https://github.com/microsoft/agent-framework/issues
|
|
23
|
+
Project-URL: release_notes, https://github.com/microsoft/agent-framework/releases?q=tag%3Apython-1&expanded=true
|
|
24
|
+
Project-URL: source, https://github.com/microsoft/agent-framework/tree/main/python
|
|
25
|
+
|
|
26
|
+
# Get Started with Microsoft Agent Framework Mem0
|
|
27
|
+
|
|
28
|
+
Please install this package via pip:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install agent-framework-mem0 --pre
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Memory Context Provider
|
|
35
|
+
|
|
36
|
+
The Mem0 context provider enables persistent memory capabilities for your agents, allowing them to remember user preferences and conversation context across different sessions and threads.
|
|
37
|
+
|
|
38
|
+
### Basic Usage Example
|
|
39
|
+
|
|
40
|
+
See the [Mem0 basic example](https://github.com/microsoft/agent-framework/tree/main/python/samples/getting_started/context_providers/mem0/mem0_basic.py) which demonstrates:
|
|
41
|
+
|
|
42
|
+
- Setting up an agent with Mem0 context provider
|
|
43
|
+
- Teaching the agent user preferences
|
|
44
|
+
- Retrieving information using remembered context across new threads
|
|
45
|
+
- Persistent memory
|
|
46
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Get Started with Microsoft Agent Framework Mem0
|
|
2
|
+
|
|
3
|
+
Please install this package via pip:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install agent-framework-mem0 --pre
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Memory Context Provider
|
|
10
|
+
|
|
11
|
+
The Mem0 context provider enables persistent memory capabilities for your agents, allowing them to remember user preferences and conversation context across different sessions and threads.
|
|
12
|
+
|
|
13
|
+
### Basic Usage Example
|
|
14
|
+
|
|
15
|
+
See the [Mem0 basic example](https://github.com/microsoft/agent-framework/tree/main/python/samples/getting_started/context_providers/mem0/mem0_basic.py) which demonstrates:
|
|
16
|
+
|
|
17
|
+
- Setting up an agent with Mem0 context provider
|
|
18
|
+
- Teaching the agent user preferences
|
|
19
|
+
- Retrieving information using remembered context across new threads
|
|
20
|
+
- Persistent memory
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Copyright (c) Microsoft. All rights reserved.
|
|
2
|
+
|
|
3
|
+
import importlib.metadata
|
|
4
|
+
|
|
5
|
+
from ._provider import Mem0Provider
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
__version__ = importlib.metadata.version(__name__)
|
|
9
|
+
except importlib.metadata.PackageNotFoundError:
|
|
10
|
+
__version__ = "0.0.0" # Fallback for development mode
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"Mem0Provider",
|
|
14
|
+
"__version__",
|
|
15
|
+
]
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# Copyright (c) Microsoft. All rights reserved.
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from collections.abc import MutableSequence, Sequence
|
|
5
|
+
from contextlib import AbstractAsyncContextManager
|
|
6
|
+
from typing import Any, TypedDict
|
|
7
|
+
|
|
8
|
+
from agent_framework import ChatMessage, Context, ContextProvider
|
|
9
|
+
from agent_framework.exceptions import ServiceInitializationError
|
|
10
|
+
from mem0 import AsyncMemory, AsyncMemoryClient
|
|
11
|
+
|
|
12
|
+
if sys.version_info >= (3, 12):
|
|
13
|
+
from typing import override # type: ignore # pragma: no cover
|
|
14
|
+
else:
|
|
15
|
+
from typing_extensions import override # type: ignore[import] # pragma: no cover
|
|
16
|
+
|
|
17
|
+
if sys.version_info >= (3, 11):
|
|
18
|
+
from typing import NotRequired, Self # pragma: no cover
|
|
19
|
+
else:
|
|
20
|
+
from typing_extensions import NotRequired, Self # pragma: no cover
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Type aliases for Mem0 search response formats (v1.1 and v2; v1 is deprecated, but matches the type definition for v2)
|
|
24
|
+
class MemorySearchResponse_v1_1(TypedDict):
|
|
25
|
+
results: list[dict[str, Any]]
|
|
26
|
+
relations: NotRequired[list[dict[str, Any]]]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
MemorySearchResponse_v2 = list[dict[str, Any]]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Mem0Provider(ContextProvider):
|
|
33
|
+
"""Mem0 Context Provider."""
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
mem0_client: AsyncMemory | AsyncMemoryClient | None = None,
|
|
38
|
+
api_key: str | None = None,
|
|
39
|
+
application_id: str | None = None,
|
|
40
|
+
agent_id: str | None = None,
|
|
41
|
+
thread_id: str | None = None,
|
|
42
|
+
user_id: str | None = None,
|
|
43
|
+
scope_to_per_operation_thread_id: bool = False,
|
|
44
|
+
context_prompt: str = ContextProvider.DEFAULT_CONTEXT_PROMPT,
|
|
45
|
+
) -> None:
|
|
46
|
+
"""Initializes a new instance of the Mem0Provider class.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
mem0_client: A pre-created Mem0 MemoryClient or None to create a default client.
|
|
50
|
+
api_key: The API key for authenticating with the Mem0 API. If not
|
|
51
|
+
provided, it will attempt to use the MEM0_API_KEY environment variable.
|
|
52
|
+
application_id: The application ID for scoping memories or None.
|
|
53
|
+
agent_id: The agent ID for scoping memories or None.
|
|
54
|
+
thread_id: The thread ID for scoping memories or None.
|
|
55
|
+
user_id: The user ID for scoping memories or None.
|
|
56
|
+
scope_to_per_operation_thread_id: Whether to scope memories to per-operation thread ID.
|
|
57
|
+
context_prompt: The prompt to prepend to retrieved memories.
|
|
58
|
+
"""
|
|
59
|
+
should_close_client = False
|
|
60
|
+
if mem0_client is None:
|
|
61
|
+
mem0_client = AsyncMemoryClient(api_key=api_key)
|
|
62
|
+
should_close_client = True
|
|
63
|
+
|
|
64
|
+
self.api_key = api_key
|
|
65
|
+
self.application_id = application_id
|
|
66
|
+
self.agent_id = agent_id
|
|
67
|
+
self.thread_id = thread_id
|
|
68
|
+
self.user_id = user_id
|
|
69
|
+
self.scope_to_per_operation_thread_id = scope_to_per_operation_thread_id
|
|
70
|
+
self.context_prompt = context_prompt
|
|
71
|
+
self.mem0_client = mem0_client
|
|
72
|
+
self._per_operation_thread_id: str | None = None
|
|
73
|
+
self._should_close_client = should_close_client
|
|
74
|
+
|
|
75
|
+
async def __aenter__(self) -> "Self":
|
|
76
|
+
"""Async context manager entry."""
|
|
77
|
+
if self.mem0_client and isinstance(self.mem0_client, AbstractAsyncContextManager):
|
|
78
|
+
await self.mem0_client.__aenter__()
|
|
79
|
+
return self
|
|
80
|
+
|
|
81
|
+
async def __aexit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: Any) -> None:
|
|
82
|
+
"""Async context manager exit."""
|
|
83
|
+
if self._should_close_client and self.mem0_client and isinstance(self.mem0_client, AbstractAsyncContextManager):
|
|
84
|
+
await self.mem0_client.__aexit__(exc_type, exc_val, exc_tb)
|
|
85
|
+
|
|
86
|
+
async def thread_created(self, thread_id: str | None = None) -> None:
|
|
87
|
+
"""Called when a new thread is created.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
thread_id: The ID of the thread or None.
|
|
91
|
+
"""
|
|
92
|
+
self._validate_per_operation_thread_id(thread_id)
|
|
93
|
+
self._per_operation_thread_id = self._per_operation_thread_id or thread_id
|
|
94
|
+
|
|
95
|
+
@override
|
|
96
|
+
async def invoked(
|
|
97
|
+
self,
|
|
98
|
+
request_messages: ChatMessage | Sequence[ChatMessage],
|
|
99
|
+
response_messages: ChatMessage | Sequence[ChatMessage] | None = None,
|
|
100
|
+
invoke_exception: Exception | None = None,
|
|
101
|
+
**kwargs: Any,
|
|
102
|
+
) -> None:
|
|
103
|
+
self._validate_filters()
|
|
104
|
+
|
|
105
|
+
request_messages_list = (
|
|
106
|
+
[request_messages] if isinstance(request_messages, ChatMessage) else list(request_messages)
|
|
107
|
+
)
|
|
108
|
+
response_messages_list = (
|
|
109
|
+
[response_messages]
|
|
110
|
+
if isinstance(response_messages, ChatMessage)
|
|
111
|
+
else list(response_messages)
|
|
112
|
+
if response_messages
|
|
113
|
+
else []
|
|
114
|
+
)
|
|
115
|
+
messages_list = [*request_messages_list, *response_messages_list]
|
|
116
|
+
|
|
117
|
+
messages: list[dict[str, str]] = [
|
|
118
|
+
{"role": message.role.value, "content": message.text}
|
|
119
|
+
for message in messages_list
|
|
120
|
+
if message.role.value in {"user", "assistant", "system"} and message.text and message.text.strip()
|
|
121
|
+
]
|
|
122
|
+
|
|
123
|
+
if messages:
|
|
124
|
+
await self.mem0_client.add( # type: ignore[misc]
|
|
125
|
+
messages=messages,
|
|
126
|
+
user_id=self.user_id,
|
|
127
|
+
agent_id=self.agent_id,
|
|
128
|
+
run_id=self._per_operation_thread_id if self.scope_to_per_operation_thread_id else self.thread_id,
|
|
129
|
+
metadata={"application_id": self.application_id},
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
@override
|
|
133
|
+
async def invoking(self, messages: ChatMessage | MutableSequence[ChatMessage], **kwargs: Any) -> Context:
|
|
134
|
+
"""Called before invoking the AI model to provide context.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
messages: List of new messages in the thread.
|
|
138
|
+
|
|
139
|
+
Keyword Args:
|
|
140
|
+
**kwargs: not used at present.
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
Context: Context object containing instructions with memories.
|
|
144
|
+
"""
|
|
145
|
+
self._validate_filters()
|
|
146
|
+
messages_list = [messages] if isinstance(messages, ChatMessage) else list(messages)
|
|
147
|
+
input_text = "\n".join(msg.text for msg in messages_list if msg and msg.text and msg.text.strip())
|
|
148
|
+
|
|
149
|
+
# Validate input text is not empty before searching (possible for function approval responses)
|
|
150
|
+
if not input_text.strip():
|
|
151
|
+
return Context(messages=None)
|
|
152
|
+
|
|
153
|
+
# Build filters from init parameters
|
|
154
|
+
filters = self._build_filters()
|
|
155
|
+
|
|
156
|
+
search_response: MemorySearchResponse_v1_1 | MemorySearchResponse_v2 = await self.mem0_client.search( # type: ignore[misc]
|
|
157
|
+
query=input_text,
|
|
158
|
+
filters=filters,
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# Depending on the API version, the response schema varies slightly
|
|
162
|
+
if isinstance(search_response, list):
|
|
163
|
+
memories = search_response
|
|
164
|
+
elif isinstance(search_response, dict) and "results" in search_response:
|
|
165
|
+
memories = search_response["results"]
|
|
166
|
+
else:
|
|
167
|
+
# Fallback for unexpected schema - return response as text as-is
|
|
168
|
+
memories = [search_response]
|
|
169
|
+
|
|
170
|
+
line_separated_memories = "\n".join(memory.get("memory", "") for memory in memories)
|
|
171
|
+
|
|
172
|
+
return Context(
|
|
173
|
+
messages=[ChatMessage(role="user", text=f"{self.context_prompt}\n{line_separated_memories}")]
|
|
174
|
+
if line_separated_memories
|
|
175
|
+
else None
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
def _validate_filters(self) -> None:
|
|
179
|
+
"""Validates that at least one filter is provided.
|
|
180
|
+
|
|
181
|
+
Raises:
|
|
182
|
+
ServiceInitializationError: If no filters are provided.
|
|
183
|
+
"""
|
|
184
|
+
if not self.agent_id and not self.user_id and not self.application_id and not self.thread_id:
|
|
185
|
+
raise ServiceInitializationError(
|
|
186
|
+
"At least one of the filters: agent_id, user_id, application_id, or thread_id is required."
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
def _build_filters(self) -> dict[str, Any]:
|
|
190
|
+
"""Build search filters from initialization parameters.
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
Filter dictionary for mem0 v2 search API containing initialization parameters.
|
|
194
|
+
In the v2 API, filters holds the user_id, agent_id, run_id (thread_id), and app_id
|
|
195
|
+
(application_id) which are required for scoping memory search operations.
|
|
196
|
+
"""
|
|
197
|
+
filters: dict[str, Any] = {}
|
|
198
|
+
|
|
199
|
+
if self.user_id:
|
|
200
|
+
filters["user_id"] = self.user_id
|
|
201
|
+
if self.agent_id:
|
|
202
|
+
filters["agent_id"] = self.agent_id
|
|
203
|
+
if self.scope_to_per_operation_thread_id and self._per_operation_thread_id:
|
|
204
|
+
filters["run_id"] = self._per_operation_thread_id
|
|
205
|
+
elif self.thread_id:
|
|
206
|
+
filters["run_id"] = self.thread_id
|
|
207
|
+
if self.application_id:
|
|
208
|
+
filters["app_id"] = self.application_id
|
|
209
|
+
|
|
210
|
+
return filters
|
|
211
|
+
|
|
212
|
+
def _validate_per_operation_thread_id(self, thread_id: str | None) -> None:
|
|
213
|
+
"""Validates that a new thread ID doesn't conflict with an existing one when scoped.
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
thread_id: The new thread ID or None.
|
|
217
|
+
|
|
218
|
+
Raises:
|
|
219
|
+
ValueError: If a new thread ID is provided when one already exists.
|
|
220
|
+
"""
|
|
221
|
+
if (
|
|
222
|
+
self.scope_to_per_operation_thread_id
|
|
223
|
+
and thread_id
|
|
224
|
+
and self._per_operation_thread_id
|
|
225
|
+
and thread_id != self._per_operation_thread_id
|
|
226
|
+
):
|
|
227
|
+
raise ValueError(
|
|
228
|
+
"Mem0Provider can only be used with one thread at a time when scope_to_per_operation_thread_id is True."
|
|
229
|
+
)
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "agent-framework-mem0"
|
|
3
|
+
description = "Mem0 integration for Microsoft Agent Framework."
|
|
4
|
+
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
version = "1.0.0b260127"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
urls.homepage = "https://aka.ms/agent-framework"
|
|
10
|
+
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
|
11
|
+
urls.release_notes = "https://github.com/microsoft/agent-framework/releases?q=tag%3Apython-1&expanded=true"
|
|
12
|
+
urls.issues = "https://github.com/microsoft/agent-framework/issues"
|
|
13
|
+
classifiers = [
|
|
14
|
+
"License :: OSI Approved :: MIT License",
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.10",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
|
+
"Programming Language :: Python :: 3.14",
|
|
23
|
+
"Typing :: Typed",
|
|
24
|
+
]
|
|
25
|
+
dependencies = [
|
|
26
|
+
"agent-framework-core",
|
|
27
|
+
"mem0ai>=1.0.0",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[tool.uv]
|
|
31
|
+
prerelease = "if-necessary-or-explicit"
|
|
32
|
+
environments = [
|
|
33
|
+
"sys_platform == 'darwin'",
|
|
34
|
+
"sys_platform == 'linux'",
|
|
35
|
+
"sys_platform == 'win32'"
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[tool.uv-dynamic-versioning]
|
|
39
|
+
fallback-version = "0.0.0"
|
|
40
|
+
[tool.pytest.ini_options]
|
|
41
|
+
testpaths = 'tests'
|
|
42
|
+
addopts = "-ra -q -r fEX"
|
|
43
|
+
asyncio_mode = "auto"
|
|
44
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
45
|
+
filterwarnings = [
|
|
46
|
+
"ignore:Support for class-based `config` is deprecated:DeprecationWarning:pydantic.*"
|
|
47
|
+
]
|
|
48
|
+
timeout = 120
|
|
49
|
+
|
|
50
|
+
[tool.ruff]
|
|
51
|
+
extend = "../../pyproject.toml"
|
|
52
|
+
|
|
53
|
+
[tool.coverage.run]
|
|
54
|
+
omit = [
|
|
55
|
+
"**/__init__.py"
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
[tool.pyright]
|
|
59
|
+
extends = "../../pyproject.toml"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
[tool.mypy]
|
|
63
|
+
plugins = ['pydantic.mypy']
|
|
64
|
+
strict = true
|
|
65
|
+
python_version = "3.10"
|
|
66
|
+
ignore_missing_imports = true
|
|
67
|
+
disallow_untyped_defs = true
|
|
68
|
+
no_implicit_optional = true
|
|
69
|
+
check_untyped_defs = true
|
|
70
|
+
warn_return_any = true
|
|
71
|
+
show_error_codes = true
|
|
72
|
+
warn_unused_ignores = false
|
|
73
|
+
disallow_incomplete_defs = true
|
|
74
|
+
disallow_untyped_decorators = true
|
|
75
|
+
|
|
76
|
+
[tool.bandit]
|
|
77
|
+
targets = ["agent_framework_mem0"]
|
|
78
|
+
exclude_dirs = ["tests"]
|
|
79
|
+
|
|
80
|
+
[tool.poe]
|
|
81
|
+
executor.type = "uv"
|
|
82
|
+
include = "../../shared_tasks.toml"
|
|
83
|
+
[tool.poe.tasks]
|
|
84
|
+
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_mem0"
|
|
85
|
+
test = "pytest --cov=agent_framework_mem0 --cov-report=term-missing:skip-covered tests"
|
|
86
|
+
|
|
87
|
+
[build-system]
|
|
88
|
+
requires = ["flit-core >= 3.11,<4.0"]
|
|
89
|
+
build-backend = "flit_core.buildapi"
|