crewai-memanto 0.1.0__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.
@@ -0,0 +1,106 @@
1
+ # Environment variables and secrets
2
+ .env
3
+ .env.local
4
+ .env.*.local
5
+ *.key
6
+ *.pem
7
+ *.crt
8
+ secrets/
9
+ .secrets
10
+
11
+ # Python
12
+ __pycache__/
13
+ *.py[cod]
14
+ *$py.class
15
+ *.so
16
+ .Python
17
+ uv.lock
18
+ build/
19
+ develop-eggs/
20
+ dist/
21
+ downloads/
22
+ eggs/
23
+ .eggs/
24
+ lib/
25
+ lib64/
26
+ parts/
27
+ sdist/
28
+ var/
29
+ wheels/
30
+ share/python-wheels/
31
+ *.egg-info/
32
+ .installed.cfg
33
+ *.egg
34
+ MANIFEST
35
+
36
+ # Virtual environments
37
+ venv/
38
+ .venv/
39
+ ENV/
40
+ env/
41
+ .env/
42
+
43
+ # IDEs
44
+ .vscode/
45
+ .idea/
46
+ .claude/
47
+ *.swp
48
+ *.swo
49
+ *~
50
+ .DS_Store
51
+
52
+ # Testing
53
+ .tox/
54
+ .nox/
55
+ .coverage
56
+ .coverage.*
57
+ .cache
58
+ nosetests.xml
59
+ coverage.xml
60
+ *.cover
61
+ *.log
62
+ .pytest_cache/
63
+
64
+ # Jupyter Notebook
65
+ .ipynb_checkpoints
66
+
67
+ # mypy
68
+ .mypy_cache/
69
+ .dmypy.json
70
+ dmypy.json
71
+
72
+ # Pyre type checker
73
+ .pyre/
74
+
75
+ # pytype static type analyzer
76
+ .pytype/
77
+
78
+ # Cython debug symbols
79
+ cython_debug/
80
+
81
+ # Database
82
+ *.db
83
+ *.sqlite
84
+ *.sqlite3
85
+
86
+ # Logs
87
+ logs/
88
+ *.log
89
+ pip-log.txt
90
+ pip-delete-this-directory.txt
91
+
92
+ # OS
93
+ .DS_Store
94
+ Thumbs.db
95
+ Desktop.ini
96
+
97
+ # Temporary files
98
+ tmp/
99
+ temp/
100
+ *.tmp
101
+ *.bak
102
+ *.swp
103
+ *.swo
104
+
105
+ # Generated version file
106
+ **/_version.py
@@ -0,0 +1,226 @@
1
+ Metadata-Version: 2.4
2
+ Name: crewai-memanto
3
+ Version: 0.1.0
4
+ Summary: CrewAI tools and integration for Memanto's persistent memory
5
+ Author-email: Memanto <info@memanto.ai>
6
+ License: MIT
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Operating System :: OS Independent
9
+ Classifier: Programming Language :: Python :: 3
10
+ Requires-Python: <4,>=3.10
11
+ Requires-Dist: crewai>=0.80.0
12
+ Requires-Dist: memanto>=0.1.0
13
+ Requires-Dist: pydantic>=2.0.0
14
+ Requires-Dist: python-dotenv>=1.0.0
15
+ Description-Content-Type: text/markdown
16
+
17
+ # CrewAI + Memanto: Persistent Multi-Agent Memory
18
+
19
+ This package provides [CrewAI](https://github.com/joaomdmoura/crewai) tools for integrating [Memanto's](https://memanto.ai) persistent, cross-agent memory capabilities into your CrewAI pipelines.
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ pip install crewai-memanto
25
+ ```
26
+
27
+ ---
28
+
29
+ A real-world example of CrewAI agents using **Memanto** as their shared, persistent memory layer. Two agents collaborate through a semantic memory database that survives across sessions, agents, and runs.
30
+
31
+ ## What This Demonstrates
32
+
33
+ - **Cross-agent memory sharing**: A Research Agent stores findings that a Writer Agent retrieves
34
+ - **Cross-session persistence**: Run the researcher today, run the writer tomorrow -- memories persist
35
+ - **Typed semantic memory**: 13 memory types (fact, observation, decision, etc.) with confidence scoring
36
+ - **Contradictory memory handling**: Detect and resolve conflicting facts (bonus)
37
+
38
+ ## Architecture
39
+
40
+ ![CrewAI + Memanto: Persistent Multi-Agent Memory](https://github.com/moorcheh-ai/memanto/raw/main/assets/crewai-architecture.png)
41
+
42
+ Both CrewAI agents share the **same Memanto agent ID** (`crewai-research-team`), giving them access to a shared memory namespace.
43
+
44
+ ## Prerequisites
45
+
46
+ - Python 3.10+
47
+ - A [Moorcheh API key](https://console.moorcheh.ai/api-keys) (free tier: 100K ops/month)
48
+ - An [OpenRouter API key](https://openrouter.ai/keys) (for CrewAI's LLM — free tier available)
49
+
50
+ ## Setup
51
+
52
+ ```bash
53
+ # 1. Clone the repo (if you haven't already)
54
+ git clone https://github.com/moorcheh-ai/memanto.git
55
+ cd memanto/examples/crewai-memory
56
+
57
+ # 2. Create a virtual environment
58
+ python -m venv venv
59
+ source venv/bin/activate # Windows: venv\Scripts\activate
60
+
61
+ # 3. Install dependencies
62
+ pip install -r requirements.txt
63
+
64
+ # 4. Configure API keys
65
+ cp .env.example .env
66
+ # Edit .env and add your MOORCHEH_API_KEY and OPENROUTER_API_KEY
67
+ ```
68
+
69
+ ## Quick Start
70
+
71
+ Run the full pipeline (Research Agent + Writer Agent) in one command:
72
+
73
+ ```bash
74
+ python run_full_pipeline.py
75
+ ```
76
+
77
+ ## Step-by-Step Demo (Proves Persistence)
78
+
79
+ This is the recommended flow for your terminal recording:
80
+
81
+ ```bash
82
+ # Step 1: Research Agent stores findings in Memanto
83
+ python run_research.py
84
+
85
+ # Step 2: Writer Agent retrieves those memories in a NEW session
86
+ # (This proves memories persist across sessions!)
87
+ python run_writer.py
88
+
89
+ # Step 3 (Bonus): Demonstrate contradictory memory handling
90
+ python run_contradiction.py
91
+ ```
92
+
93
+ ## Architecture: Why Tool-Based Integration?
94
+
95
+ CrewAI offers two ways to plug in external memory:
96
+
97
+ 1. **Native `StorageBackend` override** — Implement CrewAI's `StorageBackend` protocol and pass it via `Memory(storage=my_backend)`. CrewAI's memory pipeline (LLM analysis, consolidation, composite scoring) runs on top of your backend.
98
+
99
+ 2. **Tool-based integration** — Provide Memanto operations as CrewAI tools that agents call directly.
100
+
101
+ **This example uses the tool-based approach.** Here's why:
102
+
103
+ - **API mismatch**: CrewAI's `StorageBackend.search()` receives a pre-computed **vector embedding**. By the time it reaches the storage layer, the original query text is lost. Memanto's API performs semantic search from **natural language text**, not raw vectors. There's no clean way to bridge this gap without redundant embedding work or losing Memanto's search quality.
104
+
105
+ - **Rich metadata**: The tool-based approach lets the LLM choose the right memory type (out of 13 semantic types), set confidence scores, and add tags at write time. A native backend override only receives what CrewAI's encoding pipeline extracts, which doesn't map to Memanto's type system.
106
+
107
+ - **No dual memory risk**: We explicitly set `memory=False` on all Crews to prevent CrewAI from injecting its own LanceDB-backed memory tools alongside the Memanto tools. When `memory=True`, CrewAI auto-injects "Search memory" and "Save to memory" tools into every agent — running both systems would cause duplicate storage and retrieval confusion.
108
+
109
+ > **Note**: Native `StorageBackend` integrations (like [Hindsight](https://hindsight.vectorize.io/) or [Mengram](https://community.crewai.com/t/mengram-human-like-memory-backend-for-crewai-pr-4595/7363)) work well when the external system accepts vector embeddings directly. Memanto's information-theoretic search operates on text, making the tool-based pattern the better fit.
110
+
111
+ ### Namespace Design
112
+
113
+ All CrewAI agents in this example share a **single Memanto agent ID** (`crewai-research-team`), which maps to one Memanto namespace. This is intentional: the Research Agent stores findings and the Writer Agent retrieves them from the same namespace. Memanto's scope system (`memanto_agent_{agent_id}`) provides the isolation boundary — different crews or projects should use different agent IDs.
114
+
115
+ ## How to Swap CrewAI Memory for Memanto
116
+
117
+ ### Before: CrewAI's Built-in Memory
118
+
119
+ ```python
120
+ from crewai import Crew
121
+
122
+ # CrewAI's built-in memory uses LanceDB locally
123
+ # When memory=True, CrewAI auto-injects "Search memory" and
124
+ # "Save to memory" tools into every agent
125
+ crew = Crew(
126
+ agents=[researcher, writer],
127
+ tasks=[research_task, writing_task],
128
+ memory=True, # Uses LanceDB, lost when storage is cleared
129
+ )
130
+ ```
131
+
132
+ ### After: Memanto Memory (Persistent)
133
+
134
+ ```python
135
+ from memanto.cli.client.sdk_client import SdkClient
136
+ from crewai_memanto import MemantoSetup, create_memanto_tools
137
+
138
+ # 1. Set up Memanto (one-time per session)
139
+ setup = MemantoSetup(api_key="your-moorcheh-key")
140
+ client = setup.setup(agent_id="my-crew")
141
+
142
+ # 2. Create memory tools bound to your agent
143
+ tools = create_memanto_tools(client, agent_id="my-crew")
144
+
145
+ # 3. Give agents Memanto tools instead of using memory=True
146
+ researcher = Agent(
147
+ role="Researcher",
148
+ goal="Research and store findings",
149
+ backstory="...",
150
+ tools=[tools["remember"], tools["recall"]], # Persistent memory!
151
+ )
152
+
153
+ writer = Agent(
154
+ role="Writer",
155
+ goal="Retrieve findings and write",
156
+ backstory="...",
157
+ tools=[tools["recall"], tools["answer"]], # Reads persistent memory!
158
+ )
159
+
160
+ # 4. Run the crew with memory=False to prevent dual memory systems
161
+ crew = Crew(
162
+ agents=[researcher, writer],
163
+ tasks=[...],
164
+ memory=False, # Memanto handles memory via tools
165
+ )
166
+ crew.kickoff()
167
+ ```
168
+
169
+ **Key differences:**
170
+ | Feature | CrewAI Memory | Memanto Memory |
171
+ |---------|---------------|----------------|
172
+ | Persistence | Session only | Permanent |
173
+ | Cross-agent | Same crew only | Any agent, any session |
174
+ | Search | Embedding-based | Semantic (Moorcheh) |
175
+ | Memory types | Untyped | 13 semantic types |
176
+ | Confidence scoring | No | Yes (0.0-1.0) |
177
+ | Conflict detection | No | Yes |
178
+ | Cost at idle | N/A | Zero (serverless) |
179
+
180
+ ## File Structure
181
+
182
+ ```
183
+ examples/crewai-memory/
184
+ ├── README.md # This file
185
+ ├── requirements.txt # Python dependencies
186
+ ├── .env.example # API key template
187
+ ├── memanto_tools.py # CrewAI Tool wrappers around Memanto SdkClient
188
+ ├── agents.py # Research Agent + Writer Agent definitions
189
+ ├── tasks.py # Task definitions
190
+ ├── crew.py # Crew orchestration factories
191
+ ├── run_research.py # Run 1: Research Agent stores findings
192
+ ├── run_writer.py # Run 2: Writer Agent recalls (proves persistence)
193
+ ├── run_full_pipeline.py # Full pipeline in one run
194
+ └── run_contradiction.py # Bonus: contradictory memory handling
195
+ ```
196
+
197
+ ## Bonus: Cursor Integration
198
+
199
+ After running the CrewAI pipeline, you can access the same memories from Cursor:
200
+
201
+ ```bash
202
+ # Connect Cursor to Memanto globally (all projects)
203
+ memanto connect cursor --global
204
+
205
+ # Or for a specific project directory
206
+ memanto connect cursor --project-dir /path/to/your/project
207
+ ```
208
+
209
+ This creates `.cursor/rules/memanto.mdc` (memory instructions) and `.cursor/skills/memanto/SKILL.md` (memory type guide). Open any project in Cursor and ask it to recall your research findings -- it accesses the same Memanto memory namespace used by the CrewAI agents.
210
+
211
+ **Example Cursor prompt after running the CrewAI pipeline:**
212
+ > "Use memanto recall to find what the research team stored about AI agent market size"
213
+
214
+ ## Troubleshooting
215
+
216
+ - **"MOORCHEH_API_KEY not set"**: Copy `.env.example` to `.env` and add your key
217
+ - **"No active session"**: The setup manager handles this automatically; check your API key is valid
218
+ - **"Agent already exists"**: This is normal -- the setup reuses existing agents
219
+ - **CrewAI LLM errors**: Ensure `OPENROUTER_API_KEY` is set, or override with `CREWAI_LLM` env var
220
+
221
+ ## Learn More
222
+
223
+ - [Memanto Documentation](https://docs.memanto.ai)
224
+ - [CrewAI Documentation](https://docs.crewai.com)
225
+ - [Moorcheh API Keys](https://console.moorcheh.ai/api-keys)
226
+ - [OpenRouter](https://openrouter.ai/) — unified LLM gateway (free tier available)
@@ -0,0 +1,210 @@
1
+ # CrewAI + Memanto: Persistent Multi-Agent Memory
2
+
3
+ This package provides [CrewAI](https://github.com/joaomdmoura/crewai) tools for integrating [Memanto's](https://memanto.ai) persistent, cross-agent memory capabilities into your CrewAI pipelines.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install crewai-memanto
9
+ ```
10
+
11
+ ---
12
+
13
+ A real-world example of CrewAI agents using **Memanto** as their shared, persistent memory layer. Two agents collaborate through a semantic memory database that survives across sessions, agents, and runs.
14
+
15
+ ## What This Demonstrates
16
+
17
+ - **Cross-agent memory sharing**: A Research Agent stores findings that a Writer Agent retrieves
18
+ - **Cross-session persistence**: Run the researcher today, run the writer tomorrow -- memories persist
19
+ - **Typed semantic memory**: 13 memory types (fact, observation, decision, etc.) with confidence scoring
20
+ - **Contradictory memory handling**: Detect and resolve conflicting facts (bonus)
21
+
22
+ ## Architecture
23
+
24
+ ![CrewAI + Memanto: Persistent Multi-Agent Memory](https://github.com/moorcheh-ai/memanto/raw/main/assets/crewai-architecture.png)
25
+
26
+ Both CrewAI agents share the **same Memanto agent ID** (`crewai-research-team`), giving them access to a shared memory namespace.
27
+
28
+ ## Prerequisites
29
+
30
+ - Python 3.10+
31
+ - A [Moorcheh API key](https://console.moorcheh.ai/api-keys) (free tier: 100K ops/month)
32
+ - An [OpenRouter API key](https://openrouter.ai/keys) (for CrewAI's LLM — free tier available)
33
+
34
+ ## Setup
35
+
36
+ ```bash
37
+ # 1. Clone the repo (if you haven't already)
38
+ git clone https://github.com/moorcheh-ai/memanto.git
39
+ cd memanto/examples/crewai-memory
40
+
41
+ # 2. Create a virtual environment
42
+ python -m venv venv
43
+ source venv/bin/activate # Windows: venv\Scripts\activate
44
+
45
+ # 3. Install dependencies
46
+ pip install -r requirements.txt
47
+
48
+ # 4. Configure API keys
49
+ cp .env.example .env
50
+ # Edit .env and add your MOORCHEH_API_KEY and OPENROUTER_API_KEY
51
+ ```
52
+
53
+ ## Quick Start
54
+
55
+ Run the full pipeline (Research Agent + Writer Agent) in one command:
56
+
57
+ ```bash
58
+ python run_full_pipeline.py
59
+ ```
60
+
61
+ ## Step-by-Step Demo (Proves Persistence)
62
+
63
+ This is the recommended flow for your terminal recording:
64
+
65
+ ```bash
66
+ # Step 1: Research Agent stores findings in Memanto
67
+ python run_research.py
68
+
69
+ # Step 2: Writer Agent retrieves those memories in a NEW session
70
+ # (This proves memories persist across sessions!)
71
+ python run_writer.py
72
+
73
+ # Step 3 (Bonus): Demonstrate contradictory memory handling
74
+ python run_contradiction.py
75
+ ```
76
+
77
+ ## Architecture: Why Tool-Based Integration?
78
+
79
+ CrewAI offers two ways to plug in external memory:
80
+
81
+ 1. **Native `StorageBackend` override** — Implement CrewAI's `StorageBackend` protocol and pass it via `Memory(storage=my_backend)`. CrewAI's memory pipeline (LLM analysis, consolidation, composite scoring) runs on top of your backend.
82
+
83
+ 2. **Tool-based integration** — Provide Memanto operations as CrewAI tools that agents call directly.
84
+
85
+ **This example uses the tool-based approach.** Here's why:
86
+
87
+ - **API mismatch**: CrewAI's `StorageBackend.search()` receives a pre-computed **vector embedding**. By the time it reaches the storage layer, the original query text is lost. Memanto's API performs semantic search from **natural language text**, not raw vectors. There's no clean way to bridge this gap without redundant embedding work or losing Memanto's search quality.
88
+
89
+ - **Rich metadata**: The tool-based approach lets the LLM choose the right memory type (out of 13 semantic types), set confidence scores, and add tags at write time. A native backend override only receives what CrewAI's encoding pipeline extracts, which doesn't map to Memanto's type system.
90
+
91
+ - **No dual memory risk**: We explicitly set `memory=False` on all Crews to prevent CrewAI from injecting its own LanceDB-backed memory tools alongside the Memanto tools. When `memory=True`, CrewAI auto-injects "Search memory" and "Save to memory" tools into every agent — running both systems would cause duplicate storage and retrieval confusion.
92
+
93
+ > **Note**: Native `StorageBackend` integrations (like [Hindsight](https://hindsight.vectorize.io/) or [Mengram](https://community.crewai.com/t/mengram-human-like-memory-backend-for-crewai-pr-4595/7363)) work well when the external system accepts vector embeddings directly. Memanto's information-theoretic search operates on text, making the tool-based pattern the better fit.
94
+
95
+ ### Namespace Design
96
+
97
+ All CrewAI agents in this example share a **single Memanto agent ID** (`crewai-research-team`), which maps to one Memanto namespace. This is intentional: the Research Agent stores findings and the Writer Agent retrieves them from the same namespace. Memanto's scope system (`memanto_agent_{agent_id}`) provides the isolation boundary — different crews or projects should use different agent IDs.
98
+
99
+ ## How to Swap CrewAI Memory for Memanto
100
+
101
+ ### Before: CrewAI's Built-in Memory
102
+
103
+ ```python
104
+ from crewai import Crew
105
+
106
+ # CrewAI's built-in memory uses LanceDB locally
107
+ # When memory=True, CrewAI auto-injects "Search memory" and
108
+ # "Save to memory" tools into every agent
109
+ crew = Crew(
110
+ agents=[researcher, writer],
111
+ tasks=[research_task, writing_task],
112
+ memory=True, # Uses LanceDB, lost when storage is cleared
113
+ )
114
+ ```
115
+
116
+ ### After: Memanto Memory (Persistent)
117
+
118
+ ```python
119
+ from memanto.cli.client.sdk_client import SdkClient
120
+ from crewai_memanto import MemantoSetup, create_memanto_tools
121
+
122
+ # 1. Set up Memanto (one-time per session)
123
+ setup = MemantoSetup(api_key="your-moorcheh-key")
124
+ client = setup.setup(agent_id="my-crew")
125
+
126
+ # 2. Create memory tools bound to your agent
127
+ tools = create_memanto_tools(client, agent_id="my-crew")
128
+
129
+ # 3. Give agents Memanto tools instead of using memory=True
130
+ researcher = Agent(
131
+ role="Researcher",
132
+ goal="Research and store findings",
133
+ backstory="...",
134
+ tools=[tools["remember"], tools["recall"]], # Persistent memory!
135
+ )
136
+
137
+ writer = Agent(
138
+ role="Writer",
139
+ goal="Retrieve findings and write",
140
+ backstory="...",
141
+ tools=[tools["recall"], tools["answer"]], # Reads persistent memory!
142
+ )
143
+
144
+ # 4. Run the crew with memory=False to prevent dual memory systems
145
+ crew = Crew(
146
+ agents=[researcher, writer],
147
+ tasks=[...],
148
+ memory=False, # Memanto handles memory via tools
149
+ )
150
+ crew.kickoff()
151
+ ```
152
+
153
+ **Key differences:**
154
+ | Feature | CrewAI Memory | Memanto Memory |
155
+ |---------|---------------|----------------|
156
+ | Persistence | Session only | Permanent |
157
+ | Cross-agent | Same crew only | Any agent, any session |
158
+ | Search | Embedding-based | Semantic (Moorcheh) |
159
+ | Memory types | Untyped | 13 semantic types |
160
+ | Confidence scoring | No | Yes (0.0-1.0) |
161
+ | Conflict detection | No | Yes |
162
+ | Cost at idle | N/A | Zero (serverless) |
163
+
164
+ ## File Structure
165
+
166
+ ```
167
+ examples/crewai-memory/
168
+ ├── README.md # This file
169
+ ├── requirements.txt # Python dependencies
170
+ ├── .env.example # API key template
171
+ ├── memanto_tools.py # CrewAI Tool wrappers around Memanto SdkClient
172
+ ├── agents.py # Research Agent + Writer Agent definitions
173
+ ├── tasks.py # Task definitions
174
+ ├── crew.py # Crew orchestration factories
175
+ ├── run_research.py # Run 1: Research Agent stores findings
176
+ ├── run_writer.py # Run 2: Writer Agent recalls (proves persistence)
177
+ ├── run_full_pipeline.py # Full pipeline in one run
178
+ └── run_contradiction.py # Bonus: contradictory memory handling
179
+ ```
180
+
181
+ ## Bonus: Cursor Integration
182
+
183
+ After running the CrewAI pipeline, you can access the same memories from Cursor:
184
+
185
+ ```bash
186
+ # Connect Cursor to Memanto globally (all projects)
187
+ memanto connect cursor --global
188
+
189
+ # Or for a specific project directory
190
+ memanto connect cursor --project-dir /path/to/your/project
191
+ ```
192
+
193
+ This creates `.cursor/rules/memanto.mdc` (memory instructions) and `.cursor/skills/memanto/SKILL.md` (memory type guide). Open any project in Cursor and ask it to recall your research findings -- it accesses the same Memanto memory namespace used by the CrewAI agents.
194
+
195
+ **Example Cursor prompt after running the CrewAI pipeline:**
196
+ > "Use memanto recall to find what the research team stored about AI agent market size"
197
+
198
+ ## Troubleshooting
199
+
200
+ - **"MOORCHEH_API_KEY not set"**: Copy `.env.example` to `.env` and add your key
201
+ - **"No active session"**: The setup manager handles this automatically; check your API key is valid
202
+ - **"Agent already exists"**: This is normal -- the setup reuses existing agents
203
+ - **CrewAI LLM errors**: Ensure `OPENROUTER_API_KEY` is set, or override with `CREWAI_LLM` env var
204
+
205
+ ## Learn More
206
+
207
+ - [Memanto Documentation](https://docs.memanto.ai)
208
+ - [CrewAI Documentation](https://docs.crewai.com)
209
+ - [Moorcheh API Keys](https://console.moorcheh.ai/api-keys)
210
+ - [OpenRouter](https://openrouter.ai/) — unified LLM gateway (free tier available)
@@ -0,0 +1,15 @@
1
+ from .tools import (
2
+ MemantoAnswerTool,
3
+ MemantoRecallTool,
4
+ MemantoRememberTool,
5
+ MemantoSetup,
6
+ create_memanto_tools,
7
+ )
8
+
9
+ __all__ = [
10
+ "MemantoSetup",
11
+ "MemantoRememberTool",
12
+ "MemantoRecallTool",
13
+ "MemantoAnswerTool",
14
+ "create_memanto_tools",
15
+ ]
@@ -0,0 +1,303 @@
1
+ """
2
+ Memanto Tools for CrewAI
3
+
4
+ CrewAI tool wrappers around Memanto's SdkClient for persistent,
5
+ cross-agent memory operations. These tools let CrewAI agents store
6
+ and retrieve memories that survive across sessions and agents.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import logging
12
+ from typing import Any
13
+
14
+ from crewai.tools import BaseTool
15
+ from pydantic import BaseModel, Field
16
+
17
+ from memanto.cli.client.sdk_client import SdkClient
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+ # Valid Memanto memory types for reference in tool descriptions
22
+ VALID_MEMORY_TYPES = (
23
+ "fact, preference, goal, decision, artifact, learning, event, "
24
+ "instruction, relationship, context, observation, commitment, error"
25
+ )
26
+
27
+
28
+ class MemantoSetup:
29
+ """
30
+ Manages Memanto agent lifecycle for CrewAI integration.
31
+
32
+ Handles agent creation, session activation, and teardown so that
33
+ CrewAI scripts can focus on task orchestration.
34
+ """
35
+
36
+ def __init__(self, api_key: str) -> None:
37
+ self.client = SdkClient(api_key=api_key)
38
+
39
+ def setup(
40
+ self,
41
+ agent_id: str,
42
+ pattern: str = "tool",
43
+ description: str | None = None,
44
+ duration_hours: int = 6,
45
+ ) -> SdkClient:
46
+ """Create agent (if needed) and activate a session."""
47
+ try:
48
+ self.client.create_agent(
49
+ agent_id=agent_id,
50
+ pattern=pattern,
51
+ description=description,
52
+ )
53
+ logger.info("Created Memanto agent '%s'", agent_id)
54
+ except Exception:
55
+ logger.info("Memanto agent '%s' already exists, reusing", agent_id)
56
+
57
+ self.client.activate_agent(agent_id, duration_hours=duration_hours)
58
+ logger.info("Activated session for agent '%s'", agent_id)
59
+ return self.client
60
+
61
+ def teardown(self, agent_id: str) -> None:
62
+ """Deactivate the agent session."""
63
+ try:
64
+ self.client.deactivate_agent(agent_id)
65
+ logger.info("Deactivated session for agent '%s'", agent_id)
66
+ except Exception as e:
67
+ logger.warning("Failed to deactivate agent '%s': %s", agent_id, e)
68
+
69
+
70
+ # ---------------------------------------------------------------------------
71
+ # Tool input schemas
72
+ # ---------------------------------------------------------------------------
73
+
74
+
75
+ class RememberInput(BaseModel):
76
+ """Input schema for the Memanto remember tool."""
77
+
78
+ memory_type: str = Field(
79
+ ...,
80
+ description=(
81
+ f"The semantic type of memory to store. Must be one of: {VALID_MEMORY_TYPES}"
82
+ ),
83
+ )
84
+ title: str = Field(
85
+ ...,
86
+ description="Short title for the memory (max 100 characters).",
87
+ )
88
+ content: str = Field(
89
+ ...,
90
+ description="The memory content to store (max 10000 characters). Be concise and atomic.",
91
+ )
92
+ confidence: float = Field(
93
+ default=0.85,
94
+ description="Confidence score from 0.0 to 1.0. Use 1.0 for explicit facts, 0.7-0.85 for observations.",
95
+ )
96
+ tags: str = Field(
97
+ default="",
98
+ description="Comma-separated tags for categorization (e.g. 'market,ai,trend'). Use lowercase.",
99
+ )
100
+
101
+
102
+ class RecallInput(BaseModel):
103
+ """Input schema for the Memanto recall tool."""
104
+
105
+ query: str = Field(
106
+ ...,
107
+ description="Natural language search query to find relevant memories.",
108
+ )
109
+ limit: int = Field(
110
+ default=5,
111
+ description="Maximum number of memories to retrieve (1-20).",
112
+ )
113
+ memory_types: str = Field(
114
+ default="",
115
+ description=(
116
+ "Comma-separated memory types to filter by "
117
+ "(e.g. 'fact,observation'). Leave empty for all types."
118
+ ),
119
+ )
120
+
121
+
122
+ class AnswerInput(BaseModel):
123
+ """Input schema for the Memanto answer tool."""
124
+
125
+ question: str = Field(
126
+ ...,
127
+ description="A question to answer using RAG over the agent's stored memories.",
128
+ )
129
+
130
+
131
+ # ---------------------------------------------------------------------------
132
+ # CrewAI Tool classes
133
+ # ---------------------------------------------------------------------------
134
+
135
+
136
+ class MemantoRememberTool(BaseTool):
137
+ """Store a memory in Memanto's persistent semantic database."""
138
+
139
+ name: str = "memanto_remember"
140
+ description: str = (
141
+ "Store a structured memory in Memanto for long-term persistence. "
142
+ "Use this to save facts, observations, decisions, preferences, or any "
143
+ "information that should be available to other agents or future sessions. "
144
+ "Each memory has a type, title (max 100 chars), content (max 10000 chars), "
145
+ "confidence score, and optional tags."
146
+ )
147
+ args_schema: type[BaseModel] = RememberInput
148
+
149
+ # Injected at construction time
150
+ _client: SdkClient
151
+ _agent_id: str
152
+
153
+ def __init__(self, client: SdkClient, agent_id: str, **kwargs: Any) -> None:
154
+ super().__init__(**kwargs)
155
+ object.__setattr__(self, "_client", client)
156
+ object.__setattr__(self, "_agent_id", agent_id)
157
+
158
+ def _run(
159
+ self,
160
+ memory_type: str,
161
+ title: str,
162
+ content: str,
163
+ confidence: float = 0.85,
164
+ tags: str = "",
165
+ ) -> str:
166
+ tag_list = [t.strip() for t in tags.split(",") if t.strip()] if tags else []
167
+
168
+ result = self._client.remember(
169
+ agent_id=self._agent_id,
170
+ memory_type=memory_type,
171
+ title=title,
172
+ content=content,
173
+ confidence=confidence,
174
+ tags=tag_list,
175
+ source="crewai-agent",
176
+ provenance="explicit_statement",
177
+ )
178
+
179
+ return (
180
+ f"Memory stored successfully.\n"
181
+ f" ID: {result['memory_id']}\n"
182
+ f" Type: {memory_type}\n"
183
+ f" Title: {title}\n"
184
+ f" Confidence: {confidence}"
185
+ )
186
+
187
+
188
+ class MemantoRecallTool(BaseTool):
189
+ """Search and retrieve memories from Memanto's persistent database."""
190
+
191
+ name: str = "memanto_recall"
192
+ description: str = (
193
+ "Search Memanto's persistent memory database using natural language. "
194
+ "Returns stored memories ranked by semantic relevance. Use this to "
195
+ "retrieve facts, research findings, decisions, or any previously "
196
+ "stored information from any agent that shares this memory namespace."
197
+ )
198
+ args_schema: type[BaseModel] = RecallInput
199
+
200
+ _client: SdkClient
201
+ _agent_id: str
202
+
203
+ def __init__(self, client: SdkClient, agent_id: str, **kwargs: Any) -> None:
204
+ super().__init__(**kwargs)
205
+ object.__setattr__(self, "_client", client)
206
+ object.__setattr__(self, "_agent_id", agent_id)
207
+
208
+ def _run(
209
+ self,
210
+ query: str,
211
+ limit: int = 5,
212
+ memory_types: str = "",
213
+ ) -> str:
214
+ type_list = (
215
+ [t.strip() for t in memory_types.split(",") if t.strip()]
216
+ if memory_types
217
+ else None
218
+ )
219
+
220
+ result = self._client.recall(
221
+ agent_id=self._agent_id,
222
+ query=query,
223
+ limit=min(limit, 20),
224
+ type=type_list,
225
+ )
226
+
227
+ memories = result.get("memories", [])
228
+ if not memories:
229
+ return f"No memories found for query: '{query}'"
230
+
231
+ lines = [f"Found {len(memories)} memories for '{query}':\n"]
232
+ for i, mem in enumerate(memories, 1):
233
+ title = mem.get("title", "Untitled")
234
+ content = mem.get("content", "")
235
+ mem_type = mem.get("type", "unknown")
236
+ confidence = mem.get("confidence", "N/A")
237
+ tags = mem.get("tags", [])
238
+ tag_str = f" [tags: {', '.join(tags)}]" if tags else ""
239
+
240
+ lines.append(
241
+ f" {i}. [{mem_type}] {title} (confidence: {confidence}){tag_str}\n"
242
+ f" {content}\n"
243
+ )
244
+
245
+ return "\n".join(lines)
246
+
247
+
248
+ class MemantoAnswerTool(BaseTool):
249
+ """Get AI-generated answers grounded in stored memories (RAG)."""
250
+
251
+ name: str = "memanto_answer"
252
+ description: str = (
253
+ "Ask a question and get an AI-generated answer grounded in the agent's "
254
+ "stored memories using Retrieval-Augmented Generation (RAG). This is "
255
+ "useful for synthesizing insights from multiple stored memories into "
256
+ "a coherent answer."
257
+ )
258
+ args_schema: type[BaseModel] = AnswerInput
259
+
260
+ _client: SdkClient
261
+ _agent_id: str
262
+
263
+ def __init__(self, client: SdkClient, agent_id: str, **kwargs: Any) -> None:
264
+ super().__init__(**kwargs)
265
+ object.__setattr__(self, "_client", client)
266
+ object.__setattr__(self, "_agent_id", agent_id)
267
+
268
+ def _run(self, question: str) -> str:
269
+ result = self._client.answer(
270
+ agent_id=self._agent_id,
271
+ question=question,
272
+ )
273
+
274
+ answer = result.get("answer", "No answer could be generated.")
275
+ sources = result.get("sources", [])
276
+
277
+ output = f"Answer: {answer}"
278
+ if sources:
279
+ output += f"\n\nBased on {len(sources)} memory source(s)."
280
+
281
+ return output
282
+
283
+
284
+ # ---------------------------------------------------------------------------
285
+ # Factory function
286
+ # ---------------------------------------------------------------------------
287
+
288
+
289
+ def create_memanto_tools(
290
+ client: SdkClient,
291
+ agent_id: str,
292
+ ) -> dict[str, BaseTool]:
293
+ """
294
+ Create all Memanto tools bound to a specific client and agent.
295
+
296
+ Returns:
297
+ Dict with keys 'remember', 'recall', 'answer' mapping to tool instances.
298
+ """
299
+ return {
300
+ "remember": MemantoRememberTool(client=client, agent_id=agent_id),
301
+ "recall": MemantoRecallTool(client=client, agent_id=agent_id),
302
+ "answer": MemantoAnswerTool(client=client, agent_id=agent_id),
303
+ }
@@ -0,0 +1,28 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "crewai-memanto"
7
+ version = "0.1.0"
8
+ description = "CrewAI tools and integration for Memanto's persistent memory"
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ requires-python = ">=3.10,<4"
12
+ authors = [
13
+ { name = "Memanto", email = "info@memanto.ai" }
14
+ ]
15
+ dependencies = [
16
+ "crewai>=0.80.0",
17
+ "memanto>=0.1.0",
18
+ "pydantic>=2.0.0",
19
+ "python-dotenv>=1.0.0"
20
+ ]
21
+ classifiers = [
22
+ "Programming Language :: Python :: 3",
23
+ "License :: OSI Approved :: MIT License",
24
+ "Operating System :: OS Independent",
25
+ ]
26
+
27
+ [tool.hatch.build.targets.wheel]
28
+ packages = ["crewai_memanto"]