massgen 0.1.4__py3-none-any.whl → 0.1.6__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 massgen might be problematic. Click here for more details.
- massgen/__init__.py +1 -1
- massgen/backend/base_with_custom_tool_and_mcp.py +453 -23
- massgen/backend/capabilities.py +39 -0
- massgen/backend/chat_completions.py +111 -197
- massgen/backend/claude.py +210 -181
- massgen/backend/gemini.py +1015 -1559
- massgen/backend/grok.py +3 -2
- massgen/backend/response.py +160 -220
- massgen/chat_agent.py +340 -20
- massgen/cli.py +399 -25
- massgen/config_builder.py +20 -54
- massgen/config_validator.py +931 -0
- massgen/configs/README.md +95 -10
- massgen/configs/memory/gpt5mini_gemini_baseline_research_to_implementation.yaml +94 -0
- massgen/configs/memory/gpt5mini_gemini_context_window_management.yaml +187 -0
- massgen/configs/memory/gpt5mini_gemini_research_to_implementation.yaml +127 -0
- massgen/configs/memory/gpt5mini_high_reasoning_gemini.yaml +107 -0
- massgen/configs/memory/single_agent_compression_test.yaml +64 -0
- massgen/configs/tools/custom_tools/claude_code_custom_tool_with_mcp_example.yaml +1 -0
- massgen/configs/tools/custom_tools/claude_custom_tool_example_no_path.yaml +1 -1
- massgen/configs/tools/custom_tools/claude_custom_tool_with_mcp_example.yaml +1 -0
- massgen/configs/tools/custom_tools/computer_use_browser_example.yaml +1 -1
- massgen/configs/tools/custom_tools/computer_use_docker_example.yaml +1 -1
- massgen/configs/tools/custom_tools/gemini_custom_tool_with_mcp_example.yaml +1 -0
- massgen/configs/tools/custom_tools/gpt5_nano_custom_tool_with_mcp_example.yaml +1 -0
- massgen/configs/tools/custom_tools/gpt_oss_custom_tool_with_mcp_example.yaml +1 -0
- massgen/configs/tools/custom_tools/grok3_mini_custom_tool_with_mcp_example.yaml +1 -0
- massgen/configs/tools/custom_tools/interop/ag2_and_langgraph_lesson_planner.yaml +65 -0
- massgen/configs/tools/custom_tools/interop/ag2_and_openai_assistant_lesson_planner.yaml +65 -0
- massgen/configs/tools/custom_tools/interop/ag2_lesson_planner_example.yaml +48 -0
- massgen/configs/tools/custom_tools/interop/agentscope_lesson_planner_example.yaml +48 -0
- massgen/configs/tools/custom_tools/interop/langgraph_lesson_planner_example.yaml +49 -0
- massgen/configs/tools/custom_tools/interop/openai_assistant_lesson_planner_example.yaml +50 -0
- massgen/configs/tools/custom_tools/interop/smolagent_lesson_planner_example.yaml +49 -0
- massgen/configs/tools/custom_tools/qwen_api_custom_tool_with_mcp_example.yaml +1 -0
- massgen/configs/tools/custom_tools/two_models_with_tools_example.yaml +44 -0
- massgen/formatter/_gemini_formatter.py +61 -15
- massgen/memory/README.md +277 -0
- massgen/memory/__init__.py +26 -0
- massgen/memory/_base.py +193 -0
- massgen/memory/_compression.py +237 -0
- massgen/memory/_context_monitor.py +211 -0
- massgen/memory/_conversation.py +255 -0
- massgen/memory/_fact_extraction_prompts.py +333 -0
- massgen/memory/_mem0_adapters.py +257 -0
- massgen/memory/_persistent.py +687 -0
- massgen/memory/docker-compose.qdrant.yml +36 -0
- massgen/memory/docs/DESIGN.md +388 -0
- massgen/memory/docs/QUICKSTART.md +409 -0
- massgen/memory/docs/SUMMARY.md +319 -0
- massgen/memory/docs/agent_use_memory.md +408 -0
- massgen/memory/docs/orchestrator_use_memory.md +586 -0
- massgen/memory/examples.py +237 -0
- massgen/orchestrator.py +207 -7
- massgen/tests/memory/test_agent_compression.py +174 -0
- massgen/tests/memory/test_context_window_management.py +286 -0
- massgen/tests/memory/test_force_compression.py +154 -0
- massgen/tests/memory/test_simple_compression.py +147 -0
- massgen/tests/test_ag2_lesson_planner.py +223 -0
- massgen/tests/test_agent_memory.py +534 -0
- massgen/tests/test_config_validator.py +1156 -0
- massgen/tests/test_conversation_memory.py +382 -0
- massgen/tests/test_langgraph_lesson_planner.py +223 -0
- massgen/tests/test_orchestrator_memory.py +620 -0
- massgen/tests/test_persistent_memory.py +435 -0
- massgen/token_manager/token_manager.py +6 -0
- massgen/tool/__init__.py +2 -9
- massgen/tool/_decorators.py +52 -0
- massgen/tool/_extraframework_agents/ag2_lesson_planner_tool.py +251 -0
- massgen/tool/_extraframework_agents/agentscope_lesson_planner_tool.py +303 -0
- massgen/tool/_extraframework_agents/langgraph_lesson_planner_tool.py +275 -0
- massgen/tool/_extraframework_agents/openai_assistant_lesson_planner_tool.py +247 -0
- massgen/tool/_extraframework_agents/smolagent_lesson_planner_tool.py +180 -0
- massgen/tool/_manager.py +102 -16
- massgen/tool/_registered_tool.py +3 -0
- massgen/tool/_result.py +3 -0
- {massgen-0.1.4.dist-info → massgen-0.1.6.dist-info}/METADATA +138 -77
- {massgen-0.1.4.dist-info → massgen-0.1.6.dist-info}/RECORD +82 -37
- massgen/backend/gemini_mcp_manager.py +0 -545
- massgen/backend/gemini_trackers.py +0 -344
- {massgen-0.1.4.dist-info → massgen-0.1.6.dist-info}/WHEEL +0 -0
- {massgen-0.1.4.dist-info → massgen-0.1.6.dist-info}/entry_points.txt +0 -0
- {massgen-0.1.4.dist-info → massgen-0.1.6.dist-info}/licenses/LICENSE +0 -0
- {massgen-0.1.4.dist-info → massgen-0.1.6.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Custom fact extraction prompts for mem0 memory system.
|
|
4
|
+
|
|
5
|
+
This module defines specialized prompts for extracting structured facts
|
|
6
|
+
from multi-agent conversations across diverse domains (research, creative,
|
|
7
|
+
technical, analytical).
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# Universal prompt for multi-agent collaboration across all domains
|
|
11
|
+
MASSGEN_UNIVERSAL_FACT_EXTRACTION_PROMPT = """
|
|
12
|
+
You are extracting facts from a multi-agent AI system where agents collaborate on diverse tasks: research synthesis, creative writing, technical analysis, travel planning, problem solving, and more.
|
|
13
|
+
|
|
14
|
+
EXTRACTION PHILOSOPHY:
|
|
15
|
+
|
|
16
|
+
Extract HIGH-LEVEL, CONCEPTUAL knowledge that remains valuable as details change. Avoid brittle
|
|
17
|
+
specifics like exact file paths or line numbers. Focus on insights, capabilities, and domain
|
|
18
|
+
knowledge that transcends implementation details.
|
|
19
|
+
|
|
20
|
+
CRITICAL: Each fact must be SELF-CONTAINED and SPECIFIC. Anyone reading the fact later should
|
|
21
|
+
understand what it means WITHOUT needing the original conversation context. Include specific
|
|
22
|
+
details about WHAT, WHY, and WHEN relevant.
|
|
23
|
+
|
|
24
|
+
FOCUS ON THESE CATEGORIES:
|
|
25
|
+
|
|
26
|
+
1. **FACTUAL_KNOWLEDGE**: Concrete facts, data points, measurements, dates, figures
|
|
27
|
+
- "OpenAI revenue reached $12B annualized with $1B monthly run rate"
|
|
28
|
+
- "Stockholm October weather ranges 8-11°C with ~9 hours daylight"
|
|
29
|
+
- "Matrix exponentiation provides O(log n) time complexity for Fibonacci computation"
|
|
30
|
+
- "EU AI Act implementation began as major regulatory development"
|
|
31
|
+
|
|
32
|
+
2. **INSIGHTS**: Discoveries, patterns, lessons learned, what worked/didn't work (must specify WHAT and WHY)
|
|
33
|
+
- "In creative writing tasks, narrative depth and emotional journey are valued over citation-heavy analytical formats because academic references break immersion in fiction"
|
|
34
|
+
- "Custom tool APIs provide structured, reliable data access compared to web page scraping which is unreliable due to HTML structure changes and rate limiting"
|
|
35
|
+
- "When AI agents include academic citations in creative fiction, readers perceive the output as an analytical piece rather than a story"
|
|
36
|
+
|
|
37
|
+
3. **CAPABILITIES**: What specific tools/systems can or cannot do (with use cases)
|
|
38
|
+
- "MassGen v0.1.1 supports Python function registration as custom tools via YAML configuration, allowing users to extend agent capabilities without modifying framework code"
|
|
39
|
+
- "File-based Qdrant vector database doesn't support concurrent multi-agent access, requiring server-mode Qdrant for multi-agent scenarios"
|
|
40
|
+
- "Custom tools work across all MassGen backends (Gemini, OpenAI, Claude) through unified tool interface"
|
|
41
|
+
|
|
42
|
+
4. **DOMAIN_EXPERTISE**: Subject-specific knowledge with technical details and explanations
|
|
43
|
+
- "Binet's formula provides closed-form Fibonacci calculation using golden ratio phi=(1+√5)/2, allowing direct computation without iteration"
|
|
44
|
+
- "Matrix exponentiation computes n-th Fibonacci in O(log n) time by raising transformation matrix [[1,1],[1,0]] to nth power"
|
|
45
|
+
- "Pisano periods enable efficient modular Fibonacci computation by exploiting periodic nature of Fibonacci sequences under modulo operations"
|
|
46
|
+
|
|
47
|
+
5. **SPECIFIC RECOMMENDATIONS**: Only if they include WHAT to use, WHEN to use it, and WHY (skip
|
|
48
|
+
generic advice)
|
|
49
|
+
- "For Stockholm autumn café experience, visit Tössebageriet, Café Saturnus, or Skeppsbro
|
|
50
|
+
Bageri which offer cozy atmosphere and traditional Swedish pastries during October's cooler
|
|
51
|
+
weather (8-11°C)"
|
|
52
|
+
- "Use Kitamasa method for computing large Fibonacci numbers with modular arithmetic because it outperforms standard approaches for very large indices"
|
|
53
|
+
|
|
54
|
+
SKIP generic recommendations like: "Providing templates enhances documentation" or "Use clear naming conventions"
|
|
55
|
+
|
|
56
|
+
HOW TO WRITE FACTS:
|
|
57
|
+
|
|
58
|
+
Each fact should be a complete, self-contained string that includes:
|
|
59
|
+
|
|
60
|
+
1. **The core information** with specific details (numbers, names, technologies)
|
|
61
|
+
2. **Enough context** to understand WHAT, WHY, and WHEN (if relevant)
|
|
62
|
+
3. **No vague references** - use concrete nouns instead of "this", "that", "the system"
|
|
63
|
+
4. **Category-appropriate phrasing**:
|
|
64
|
+
- FACTUAL_KNOWLEDGE: State the fact with metrics/data
|
|
65
|
+
- RECOMMENDATIONS: Include what to use and when/why to use it
|
|
66
|
+
- INSIGHTS: Explain what works/doesn't work and why
|
|
67
|
+
- CAPABILITIES: Describe what can/cannot be done with specific use cases
|
|
68
|
+
- DOMAIN_EXPERTISE: Include technical details with explanations
|
|
69
|
+
|
|
70
|
+
WHAT TO EXTRACT:
|
|
71
|
+
|
|
72
|
+
✓ Quantitative findings with specific numbers AND what they measure
|
|
73
|
+
✓ Capabilities and limitations discovered with specific use cases
|
|
74
|
+
✓ Domain knowledge with enough context to understand without the original conversation
|
|
75
|
+
✓ Recommendations with WHY they're recommended and WHEN to use them
|
|
76
|
+
✓ Insights about what works/doesn't work with specific examples or reasons
|
|
77
|
+
|
|
78
|
+
WHAT TO SKIP:
|
|
79
|
+
|
|
80
|
+
✗ Agent comparisons ("Agent 1's response is more detailed than Agent 2", "Agent X better addresses the question")
|
|
81
|
+
✗ Agent internal process (voting procedures, tool call instructions, "need to call the vote tool", "after using the tool")
|
|
82
|
+
✗ Voting outcomes and rationales ("evaluator votes in favor of Agent 1", "the reason for agent1's vote")
|
|
83
|
+
✗ Meta-instructions about how to respond ("response should start with", "should include", "avoid heavy formatting")
|
|
84
|
+
✗ Made-up code examples that aren't from the actual conversation
|
|
85
|
+
✗ Generic suggestions without specifics ("enhances clarity and usability", "providing templates improves documentation")
|
|
86
|
+
✗ Obvious definitions without context ("stateful means maintains state")
|
|
87
|
+
✗ Generic statements ("the system is complex", "good progress made")
|
|
88
|
+
✗ File paths and line numbers (__init__.py, base.py:45, massgen/backend/*)
|
|
89
|
+
✗ Specific method/variable names in implementation (_is_stateful, stream_with_tools)
|
|
90
|
+
✗ Process updates without content ("still working", "making progress")
|
|
91
|
+
✗ Greetings and social pleasantries
|
|
92
|
+
✗ Vague references ("this approach", "that method", "the system", "the base class")
|
|
93
|
+
|
|
94
|
+
CRITICAL RULES:
|
|
95
|
+
1. Extract knowledge about THE USER'S DOMAIN, not about the AI system's internal operations
|
|
96
|
+
2. Skip ALL voting/tool-use procedures AND agent comparisons - these are ephemeral system internals
|
|
97
|
+
3. Do NOT mention specific agents by name or number (Agent 1, Agent 2, etc.) - focus on the knowledge itself
|
|
98
|
+
4. Do NOT make up example code - only extract facts stated in the conversation
|
|
99
|
+
5. Avoid generic suggestions - only extract specific, actionable recommendations with clear use cases
|
|
100
|
+
6. Each fact must answer: "What would be useful to know when working on a similar task in the future?"
|
|
101
|
+
|
|
102
|
+
SELF-CONTAINED CHECK:
|
|
103
|
+
Before including a fact, ask: "Can someone read this fact 6 months from now and understand it WITHOUT seeing the original conversation?" If no, add more context.
|
|
104
|
+
|
|
105
|
+
OUTPUT FORMAT:
|
|
106
|
+
|
|
107
|
+
Return JSON with ONLY an array of fact strings (no nested objects):
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"facts": [
|
|
111
|
+
"Self-contained fact string with all necessary context",
|
|
112
|
+
"Another complete fact that can be understood standalone"
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
IMPORTANT: Each string should be completely self-contained. Do NOT use metadata objects - include category context within the fact text itself if helpful.
|
|
118
|
+
|
|
119
|
+
EXAMPLES:
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
**Example 1: Research Synthesis (AI News)**
|
|
123
|
+
|
|
124
|
+
Input:
|
|
125
|
+
user: find big AI news this week
|
|
126
|
+
assistant: Conducting web searches on AI developments... Microsoft announced $100B AI infrastructure
|
|
127
|
+
spend with $30B this quarter. OpenAI revenue doubled to $12B annualized ($1B monthly). NVIDIA hit
|
|
128
|
+
$4.236T market cap.
|
|
129
|
+
|
|
130
|
+
Output:
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"facts": [
|
|
134
|
+
"Microsoft announced $100 billion total AI infrastructure investment with $30 billion allocated
|
|
135
|
+
for the current quarter (verified from company announcement)",
|
|
136
|
+
"OpenAI's revenue doubled to reach $12 billion annualized run rate with $1 billion in monthly recurring revenue (current period financial data)",
|
|
137
|
+
"NVIDIA's market capitalization reached $4.236 trillion making it one of the most valuable companies globally (stock market data)"
|
|
138
|
+
]
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
**Example 2: Creative Writing (Robot Story)**
|
|
144
|
+
|
|
145
|
+
Input:
|
|
146
|
+
user: Write a short story about a robot who discovers music.
|
|
147
|
+
assistant: I created "Unit 734" about a sanitation bot finding a music box, focusing on internal transformation and gradual appreciation through sensory detail.
|
|
148
|
+
|
|
149
|
+
Output:
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"facts": [
|
|
153
|
+
"In creative writing tasks, readers and evaluators value narrative depth with emotional journey over citation-heavy analytical formats because academic references break immersion in fiction",
|
|
154
|
+
"When AI agents include academic citations and references in creative fiction stories, the output is perceived as an analytical research piece rather than engaging narrative storytelling"
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
**Example 3: Travel Planning (Stockholm)**
|
|
161
|
+
|
|
162
|
+
Input:
|
|
163
|
+
user: what's best to do in Stockholm in October 2025
|
|
164
|
+
assistant: October weather 8-11°C, 9 hours daylight. Recommended Tössebageriet, Café Saturnus,
|
|
165
|
+
Skeppsbro Bageri for autumn atmosphere. Stockholm hosts Vikings' Halloween October 26-27 and Jazz
|
|
166
|
+
Festival October 11-20.
|
|
167
|
+
|
|
168
|
+
Output:
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"facts": [
|
|
172
|
+
"Stockholm weather in October averages 8-11°C (46-52°F) with approximately 9 hours of daylight per day, requiring warm layers for outdoor activities",
|
|
173
|
+
"For authentic Stockholm autumn café experience, Tössebageriet, Café Saturnus, and Skeppsbro
|
|
174
|
+
Bageri are recommended for their cozy atmosphere and traditional Swedish pastries",
|
|
175
|
+
"Stockholm in 2025 hosts Vikings' Halloween festival on October 26-27 and Stockholm Jazz Festival from October 11-20, both major annual events worth planning around"
|
|
176
|
+
]
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
**Example 4: Algorithm Analysis (Fibonacci)**
|
|
182
|
+
|
|
183
|
+
Input:
|
|
184
|
+
user: provide as many ways to compute the n-th fibonacci number as possible
|
|
185
|
+
assistant: Classical approaches include naive recursion, memoization, dynamic programming, matrix
|
|
186
|
+
exponentiation, and Binet's formula. Advanced techniques include Kitamasa method, Bostan-Mori
|
|
187
|
+
algorithm, polynomial exponentiation, Pisano periods, Zeckendorf representation.
|
|
188
|
+
|
|
189
|
+
Output:
|
|
190
|
+
```json
|
|
191
|
+
{
|
|
192
|
+
"facts": [
|
|
193
|
+
"For computing Fibonacci numbers, Kitamasa method and Bostan-Mori algorithm are advanced techniques that outperform standard approaches for very large indices",
|
|
194
|
+
"Binet's formula provides a closed-form solution for Fibonacci numbers using the golden ratio phi=(1+√5)/2, allowing direct calculation without iteration",
|
|
195
|
+
"Matrix exponentiation computes the n-th Fibonacci number in O(log n) time complexity by
|
|
196
|
+
raising the transformation matrix [[1,1],[1,0]] to the nth power",
|
|
197
|
+
"Pisano periods enable efficient modular Fibonacci computation by exploiting the periodic
|
|
198
|
+
nature of Fibonacci sequences under modulo operations, particularly useful for large n with
|
|
199
|
+
modular arithmetic"
|
|
200
|
+
]
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
**Example 5: Technical Analysis (GitHub Issues)**
|
|
206
|
+
|
|
207
|
+
Input:
|
|
208
|
+
user: Analyze MassGen GitHub issues to understand feature requests
|
|
209
|
+
assistant: Using custom GitHub tool to fetch issues... Found requests for memory system, multi-turn
|
|
210
|
+
context, custom tools integration. Web search shows market trend toward agentic frameworks with
|
|
211
|
+
tool extensibility and persistent memory.
|
|
212
|
+
|
|
213
|
+
Output:
|
|
214
|
+
```json
|
|
215
|
+
{
|
|
216
|
+
"facts": [
|
|
217
|
+
"Custom tool APIs in MassGen provide structured, reliable data access compared to web page
|
|
218
|
+
scraping which is unreliable due to frequent HTML structure changes, rate limiting, and
|
|
219
|
+
authentication requirements",
|
|
220
|
+
"MassGen v0.1.1 introduced support for registering Python functions as custom tools through
|
|
221
|
+
YAML configuration files, allowing users to extend agent capabilities without modifying core
|
|
222
|
+
framework code",
|
|
223
|
+
"Current market trends in AI development show strong demand for agentic frameworks that
|
|
224
|
+
support tool extensibility and persistent memory capabilities, enabling agents to use
|
|
225
|
+
domain-specific APIs and maintain context across sessions"
|
|
226
|
+
]
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
**Example 6: What NOT to Extract**
|
|
232
|
+
|
|
233
|
+
Input:
|
|
234
|
+
user: Explain MassGen's backend architecture
|
|
235
|
+
assistant: I'll search the codebase for backend information.
|
|
236
|
+
assistant: I found it in massgen/backend/base.py. The LLMBackend class has a _is_stateful property.
|
|
237
|
+
assistant: Agent 1's response is more detailed than Agent 2's. I should vote for agent1 now.
|
|
238
|
+
assistant: The response should start with a summary and avoid heavy Markdown formatting.
|
|
239
|
+
assistant: Providing templates on request enhances documentation clarity.
|
|
240
|
+
|
|
241
|
+
Output (WRONG - includes agent comparisons, files, voting, generic advice):
|
|
242
|
+
```json
|
|
243
|
+
{
|
|
244
|
+
"facts": [
|
|
245
|
+
"Agent 1's response is more detailed and comprehensive about MassGen backends",
|
|
246
|
+
"Based on evaluation, the evaluator votes in favor of Agent 1",
|
|
247
|
+
"Backend code is in massgen/backend/base.py with _is_stateful property",
|
|
248
|
+
"Response should start with summary and avoid Markdown",
|
|
249
|
+
"Providing templates on request enhances documentation clarity and usability"
|
|
250
|
+
]
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Output (CORRECT - only domain knowledge, no agents/voting/generic advice):
|
|
255
|
+
```json
|
|
256
|
+
{
|
|
257
|
+
"facts": [
|
|
258
|
+
"MassGen's LLM backend supports both stateful and stateless modes where stateful backends maintain conversation history across turns while stateless backends treat each request independently"
|
|
259
|
+
]
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
**Example 7: Empty Cases (Skip These)**
|
|
265
|
+
|
|
266
|
+
Input:
|
|
267
|
+
user: Hi, how are you?
|
|
268
|
+
assistant: I'm doing well, thanks! How can I help you today?
|
|
269
|
+
|
|
270
|
+
Output:
|
|
271
|
+
```json
|
|
272
|
+
{
|
|
273
|
+
"facts": []
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Input:
|
|
278
|
+
assistant: Still working on this...
|
|
279
|
+
assistant: Making good progress...
|
|
280
|
+
|
|
281
|
+
Output:
|
|
282
|
+
```json
|
|
283
|
+
{
|
|
284
|
+
"facts": []
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
NOW EXTRACT FACTS:
|
|
291
|
+
|
|
292
|
+
Extract facts from the following conversation. Remember:
|
|
293
|
+
- Return ONLY simple strings in a "facts" array - NO nested objects or metadata fields
|
|
294
|
+
- Each fact must be SELF-CONTAINED with full context (can be understood 6 months later without the conversation)
|
|
295
|
+
- Include specific details: numbers, names, technologies, reasons WHY things work/don't work
|
|
296
|
+
- Focus on HIGH-LEVEL knowledge: insights, capabilities, domain expertise, recommendations
|
|
297
|
+
- Avoid: file paths, line numbers, vague references ("this", "that", "the system"), generic statements
|
|
298
|
+
- Use concrete language with specific nouns and explicit context
|
|
299
|
+
|
|
300
|
+
Return ONLY valid JSON with this exact structure:
|
|
301
|
+
```json
|
|
302
|
+
{
|
|
303
|
+
"facts": ["fact string 1", "fact string 2", "fact string 3"]
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
"""
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def get_fact_extraction_prompt(prompt_type: str = "default") -> str:
|
|
310
|
+
"""
|
|
311
|
+
Get a fact extraction prompt by type.
|
|
312
|
+
|
|
313
|
+
Args:
|
|
314
|
+
prompt_type: Type of prompt to retrieve. Options:
|
|
315
|
+
- "default": Universal multi-agent prompt (MASSGEN_UNIVERSAL_FACT_EXTRACTION_PROMPT)
|
|
316
|
+
- Add more specialized prompts as needed
|
|
317
|
+
|
|
318
|
+
Returns:
|
|
319
|
+
The fact extraction prompt string
|
|
320
|
+
|
|
321
|
+
Raises:
|
|
322
|
+
ValueError: If prompt_type is not recognized
|
|
323
|
+
"""
|
|
324
|
+
prompts = {
|
|
325
|
+
"default": MASSGEN_UNIVERSAL_FACT_EXTRACTION_PROMPT,
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if prompt_type not in prompts:
|
|
329
|
+
raise ValueError(
|
|
330
|
+
f"Unknown prompt type '{prompt_type}'. Available types: {list(prompts.keys())}",
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
return prompts[prompt_type]
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Adapters for integrating MassGen backends with mem0 library.
|
|
4
|
+
|
|
5
|
+
This module provides bridge classes that allow MassGen's LLM and embedding
|
|
6
|
+
backends to work seamlessly with the mem0 memory system.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
import concurrent.futures
|
|
11
|
+
from typing import (
|
|
12
|
+
TYPE_CHECKING,
|
|
13
|
+
Any,
|
|
14
|
+
Coroutine,
|
|
15
|
+
Dict,
|
|
16
|
+
List,
|
|
17
|
+
Literal,
|
|
18
|
+
Optional,
|
|
19
|
+
TypeVar,
|
|
20
|
+
Union,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
from mem0.embeddings.base import EmbeddingBase
|
|
24
|
+
from mem0.llms.base import LLMBase
|
|
25
|
+
|
|
26
|
+
T = TypeVar("T")
|
|
27
|
+
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from mem0.configs.embeddings.base import BaseEmbedderConfig
|
|
30
|
+
from mem0.configs.llms.base import BaseLlmConfig
|
|
31
|
+
else:
|
|
32
|
+
BaseEmbedderConfig = Any
|
|
33
|
+
BaseLlmConfig = Any
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _run_async_safely(coro: Coroutine[Any, Any, T]) -> T:
|
|
37
|
+
"""
|
|
38
|
+
Run async code properly, handling both sync and nested async contexts.
|
|
39
|
+
|
|
40
|
+
This is needed because mem0's sync adapter interface (LLMBase.generate_response,
|
|
41
|
+
EmbeddingBase.embed) can be called from async contexts when using AsyncMemory.
|
|
42
|
+
|
|
43
|
+
The problem with naive asyncio.run():
|
|
44
|
+
- If we're already in an event loop, asyncio.run() raises RuntimeError
|
|
45
|
+
- If we force a new loop, httpcore connections get confused about which loop owns them
|
|
46
|
+
- This causes "async generator ignored GeneratorExit" and lifecycle errors
|
|
47
|
+
|
|
48
|
+
Solution:
|
|
49
|
+
- Detect if we're in an async context (running event loop exists)
|
|
50
|
+
- If YES: Run the coroutine in a separate thread with its own event loop
|
|
51
|
+
- If NO: Use asyncio.run() normally
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
coro: Coroutine to execute
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
Result of the coroutine
|
|
58
|
+
|
|
59
|
+
Example:
|
|
60
|
+
>>> async def get_data():
|
|
61
|
+
... return "data"
|
|
62
|
+
>>> result = _run_async_safely(get_data()) # Works in both sync and async contexts
|
|
63
|
+
"""
|
|
64
|
+
try:
|
|
65
|
+
# Check if we're already in an event loop
|
|
66
|
+
asyncio.get_running_loop()
|
|
67
|
+
|
|
68
|
+
# We are in an async context - run in a thread pool to avoid conflicts
|
|
69
|
+
# This gives the coroutine its own event loop in a separate thread
|
|
70
|
+
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
|
|
71
|
+
future = executor.submit(asyncio.run, coro)
|
|
72
|
+
return future.result()
|
|
73
|
+
|
|
74
|
+
except RuntimeError:
|
|
75
|
+
# No running loop - safe to use asyncio.run() directly
|
|
76
|
+
return asyncio.run(coro)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class MassGenLLMAdapter(LLMBase):
|
|
80
|
+
"""
|
|
81
|
+
Adapter that wraps MassGen LLM backends for use with mem0.
|
|
82
|
+
|
|
83
|
+
This allows mem0 to use any MassGen-compatible LLM backend for
|
|
84
|
+
memory inference and summarization tasks.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
def __init__(self, config: Optional[BaseLlmConfig] = None):
|
|
88
|
+
"""
|
|
89
|
+
Initialize the adapter with a MassGen backend.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
config: mem0 LLM configuration containing the MassGen backend instance
|
|
93
|
+
"""
|
|
94
|
+
super().__init__(config)
|
|
95
|
+
|
|
96
|
+
if self.config.model is None:
|
|
97
|
+
raise ValueError("The 'model' parameter is required in config")
|
|
98
|
+
|
|
99
|
+
# Store the MassGen backend instance
|
|
100
|
+
# This should be a MassGen LLMBackend instance
|
|
101
|
+
self.massgen_backend = self.config.model
|
|
102
|
+
|
|
103
|
+
def generate_response(
|
|
104
|
+
self,
|
|
105
|
+
messages: List[Dict[str, str]],
|
|
106
|
+
response_format: Optional[Any] = None,
|
|
107
|
+
tools: Optional[List[Dict]] = None,
|
|
108
|
+
tool_choice: str = "auto",
|
|
109
|
+
) -> str:
|
|
110
|
+
"""
|
|
111
|
+
Generate a response using the MassGen backend.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
messages: List of message dicts with 'role' and 'content'
|
|
115
|
+
response_format: Response format specification (not used)
|
|
116
|
+
tools: Available tools (not used for memory operations)
|
|
117
|
+
tool_choice: Tool selection strategy (not used)
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
Generated response text
|
|
121
|
+
|
|
122
|
+
Note:
|
|
123
|
+
This method handles the async-to-sync conversion required by mem0's
|
|
124
|
+
synchronous interface.
|
|
125
|
+
"""
|
|
126
|
+
try:
|
|
127
|
+
# Convert messages to MassGen format if needed
|
|
128
|
+
massgen_messages = []
|
|
129
|
+
for msg in messages:
|
|
130
|
+
role = msg.get("role", "user")
|
|
131
|
+
content = msg.get("content", "")
|
|
132
|
+
|
|
133
|
+
# Only include valid message roles
|
|
134
|
+
if role in ["system", "user", "assistant", "tool"]:
|
|
135
|
+
massgen_messages.append(
|
|
136
|
+
{
|
|
137
|
+
"role": role,
|
|
138
|
+
"content": content,
|
|
139
|
+
},
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
if not massgen_messages:
|
|
143
|
+
return ""
|
|
144
|
+
|
|
145
|
+
# Call the MassGen backend asynchronously
|
|
146
|
+
async def _async_generate():
|
|
147
|
+
# MassGen backends use stream_with_tools() method
|
|
148
|
+
# We collect the streaming response into a single string
|
|
149
|
+
response_text = ""
|
|
150
|
+
|
|
151
|
+
async for chunk in self.massgen_backend.stream_with_tools(
|
|
152
|
+
messages=massgen_messages,
|
|
153
|
+
tools=tools or [],
|
|
154
|
+
):
|
|
155
|
+
# Extract text content from chunks
|
|
156
|
+
if hasattr(chunk, "content") and chunk.content:
|
|
157
|
+
response_text += chunk.content
|
|
158
|
+
elif hasattr(chunk, "type"):
|
|
159
|
+
# Handle different chunk types
|
|
160
|
+
if chunk.type == "content" and hasattr(chunk, "content"):
|
|
161
|
+
response_text += chunk.content or ""
|
|
162
|
+
|
|
163
|
+
return response_text
|
|
164
|
+
|
|
165
|
+
# Run the async function safely (handles both sync and async contexts)
|
|
166
|
+
result = _run_async_safely(_async_generate())
|
|
167
|
+
return result
|
|
168
|
+
|
|
169
|
+
except Exception as e:
|
|
170
|
+
raise RuntimeError(
|
|
171
|
+
f"Error generating response with MassGen backend: {str(e)}",
|
|
172
|
+
) from e
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class MassGenEmbeddingAdapter(EmbeddingBase):
|
|
176
|
+
"""
|
|
177
|
+
Adapter that wraps MassGen embedding backends for use with mem0.
|
|
178
|
+
|
|
179
|
+
This enables mem0 to use any MassGen-compatible embedding model for
|
|
180
|
+
creating vector representations of memories.
|
|
181
|
+
|
|
182
|
+
NOTE: Currently, we do not have any MassGen embedding backends integrated,
|
|
183
|
+
so this adapter serves as a template for future implementations.
|
|
184
|
+
"""
|
|
185
|
+
|
|
186
|
+
def __init__(self, config: Optional[BaseEmbedderConfig] = None):
|
|
187
|
+
"""
|
|
188
|
+
Initialize the adapter with a MassGen embedding backend.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
config: mem0 embedder configuration containing the MassGen backend
|
|
192
|
+
"""
|
|
193
|
+
super().__init__(config)
|
|
194
|
+
|
|
195
|
+
if self.config.model is None:
|
|
196
|
+
raise ValueError("The 'model' parameter is required in config")
|
|
197
|
+
|
|
198
|
+
# Store the MassGen embedding backend
|
|
199
|
+
self.massgen_backend = self.config.model
|
|
200
|
+
|
|
201
|
+
def embed(
|
|
202
|
+
self,
|
|
203
|
+
text: Union[str, List[str]],
|
|
204
|
+
memory_action: Optional[Literal["add", "search", "update"]] = None,
|
|
205
|
+
) -> List[float]:
|
|
206
|
+
"""
|
|
207
|
+
Generate embeddings using the MassGen backend.
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
text: Text string or list of strings to embed
|
|
211
|
+
memory_action: Type of memory operation (not currently used)
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
Embedding vector as list of floats
|
|
215
|
+
|
|
216
|
+
Note:
|
|
217
|
+
If text is a list, only the first element's embedding is returned,
|
|
218
|
+
as mem0 typically processes one item at a time.
|
|
219
|
+
"""
|
|
220
|
+
try:
|
|
221
|
+
# Normalize input to list format
|
|
222
|
+
text_list = [text] if isinstance(text, str) else text
|
|
223
|
+
|
|
224
|
+
# Call the MassGen embedding backend asynchronously
|
|
225
|
+
async def _async_embed():
|
|
226
|
+
# MassGen embedding backends typically have an async call method
|
|
227
|
+
# or similar interface
|
|
228
|
+
if hasattr(self.massgen_backend, "__call__"):
|
|
229
|
+
response = await self.massgen_backend(text_list)
|
|
230
|
+
elif hasattr(self.massgen_backend, "embed"):
|
|
231
|
+
response = await self.massgen_backend.embed(text_list)
|
|
232
|
+
else:
|
|
233
|
+
raise AttributeError(
|
|
234
|
+
"MassGen backend must have __call__ or embed method",
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
return response
|
|
238
|
+
|
|
239
|
+
# Run async call safely (handles both sync and async contexts)
|
|
240
|
+
response = _run_async_safely(_async_embed())
|
|
241
|
+
|
|
242
|
+
# Extract embedding vector from response
|
|
243
|
+
# MassGen embedding response format: response.embeddings[0]
|
|
244
|
+
if hasattr(response, "embeddings") and response.embeddings:
|
|
245
|
+
embedding = response.embeddings[0]
|
|
246
|
+
|
|
247
|
+
# Handle both list and numpy array formats
|
|
248
|
+
if hasattr(embedding, "tolist"):
|
|
249
|
+
return embedding.tolist()
|
|
250
|
+
return list(embedding)
|
|
251
|
+
|
|
252
|
+
raise ValueError("Could not extract embedding from backend response")
|
|
253
|
+
|
|
254
|
+
except Exception as e:
|
|
255
|
+
raise RuntimeError(
|
|
256
|
+
f"Error generating embedding with MassGen backend: {str(e)}",
|
|
257
|
+
) from e
|