generic-llm-memorizer 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.
- generic_llm_memorizer-0.1.0/LICENSE +21 -0
- generic_llm_memorizer-0.1.0/PKG-INFO +250 -0
- generic_llm_memorizer-0.1.0/README.md +226 -0
- generic_llm_memorizer-0.1.0/generic_llm_memorizer/__init__.py +17 -0
- generic_llm_memorizer-0.1.0/generic_llm_memorizer/conversation.py +170 -0
- generic_llm_memorizer-0.1.0/generic_llm_memorizer/llm_memorizer.py +226 -0
- generic_llm_memorizer-0.1.0/generic_llm_memorizer/main.py +9 -0
- generic_llm_memorizer-0.1.0/generic_llm_memorizer/memory.py +111 -0
- generic_llm_memorizer-0.1.0/generic_llm_memorizer.egg-info/PKG-INFO +250 -0
- generic_llm_memorizer-0.1.0/generic_llm_memorizer.egg-info/SOURCES.txt +17 -0
- generic_llm_memorizer-0.1.0/generic_llm_memorizer.egg-info/dependency_links.txt +1 -0
- generic_llm_memorizer-0.1.0/generic_llm_memorizer.egg-info/requires.txt +3 -0
- generic_llm_memorizer-0.1.0/generic_llm_memorizer.egg-info/top_level.txt +1 -0
- generic_llm_memorizer-0.1.0/pyproject.toml +33 -0
- generic_llm_memorizer-0.1.0/setup.cfg +4 -0
- generic_llm_memorizer-0.1.0/tests/test_fake.py +105 -0
- generic_llm_memorizer-0.1.0/tests/test_init_from_memory.py +23 -0
- generic_llm_memorizer-0.1.0/tests/test_usage.py +95 -0
- generic_llm_memorizer-0.1.0/tests/test_with_agent.py +183 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 jlesbegu
|
|
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,250 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: generic-llm-memorizer
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A library for managing LLM conversations and context
|
|
5
|
+
Author-email: Your Name <your.email@example.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/yourusername/generic-llm-memorizer
|
|
8
|
+
Project-URL: Documentation, https://github.com/yourusername/generic-llm-memorizer#readme
|
|
9
|
+
Project-URL: Repository, https://github.com/yourusername/generic-llm-memorizer
|
|
10
|
+
Keywords: llm,conversation,chat,ai,prompt,context-management
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
17
|
+
Requires-Python: >=3.12
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: pydantic-ai>=1.76.0
|
|
21
|
+
Requires-Dist: pytest>=9.0.2
|
|
22
|
+
Requires-Dist: pytest-asyncio>=1.3.0
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
# Generic LLM Memorizer
|
|
26
|
+
|
|
27
|
+
A Python library for managing LLM conversations and context with automatic fact extraction and structured data handling.
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install generic-llm-memorizer
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
### Basic Conversation Management
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from generic_llm_memorizer import Conversation
|
|
41
|
+
|
|
42
|
+
# Create a new conversation
|
|
43
|
+
conv = Conversation(system_prompt="You are a helpful assistant.")
|
|
44
|
+
|
|
45
|
+
# Add messages
|
|
46
|
+
conv.add_user_message("Hello, how are you?")
|
|
47
|
+
conv.add_assistant_message("I'm doing well, thank you! How can I help you today?")
|
|
48
|
+
|
|
49
|
+
# Get conversation history
|
|
50
|
+
messages = conv.get_messages()
|
|
51
|
+
|
|
52
|
+
# Format for LLM API (expects list of dicts with role and content)
|
|
53
|
+
from generic_llm_memorizer import format_conversation_for_prompt
|
|
54
|
+
formatted = format_conversation_for_prompt(conv)
|
|
55
|
+
# Output: [{"role": "system", "content": "You are a helpful assistant."}, ...]
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from generic_llm_memorizer import Conversation
|
|
60
|
+
|
|
61
|
+
# Create a new conversation
|
|
62
|
+
conv = Conversation(system_prompt="You are a helpful assistant.")
|
|
63
|
+
|
|
64
|
+
# Add messages
|
|
65
|
+
conv.add_user_message("Hello, how are you?")
|
|
66
|
+
conv.add_assistant_message("I'm doing well, thank you! How can I help you today?")
|
|
67
|
+
|
|
68
|
+
# Get conversation history
|
|
69
|
+
messages = conv.get_messages()
|
|
70
|
+
|
|
71
|
+
# Format for LLM API (expects list of dicts with role and content)
|
|
72
|
+
from generic_llm_memorizer import format_conversation_for_prompt
|
|
73
|
+
formatted = format_conversation_for_prompt(conv)
|
|
74
|
+
# Output: [{"role": "system", "content": "You are a helpful assistant."}, ...]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Persisting Conversations
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from generic_llm_memorizer import Conversation
|
|
81
|
+
|
|
82
|
+
# Save conversation to JSON
|
|
83
|
+
conv_json = conv.to_json()
|
|
84
|
+
with open("conversation.json", "w") as f:
|
|
85
|
+
f.write(conv_json)
|
|
86
|
+
|
|
87
|
+
# Load conversation from JSON
|
|
88
|
+
with open("conversation.json", "r") as f:
|
|
89
|
+
conv_json = f.read()
|
|
90
|
+
loaded_conv = Conversation.from_json(conv_json)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from generic_llm_memorizer import Conversation
|
|
95
|
+
|
|
96
|
+
# Save conversation to JSON
|
|
97
|
+
conv_json = conv.to_json()
|
|
98
|
+
with open("conversation.json", "w") as f:
|
|
99
|
+
f.write(conv_json)
|
|
100
|
+
|
|
101
|
+
# Load conversation from JSON
|
|
102
|
+
with open("conversation.json", "r") as f:
|
|
103
|
+
conv_json = f.read()
|
|
104
|
+
loaded_conv = Conversation.from_json(conv_json)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Utility Functions
|
|
108
|
+
|
|
109
|
+
## Extending with Custom Models
|
|
110
|
+
|
|
111
|
+
You can create your own Pydantic models for domain-specific extractions:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from pydantic import BaseModel
|
|
115
|
+
from typing import List
|
|
116
|
+
from enum import Enum
|
|
117
|
+
|
|
118
|
+
class Priority(str, Enum):
|
|
119
|
+
LOW = "low"
|
|
120
|
+
MEDIUM = "medium"
|
|
121
|
+
HIGH = "high"
|
|
122
|
+
|
|
123
|
+
class Task(BaseModel):
|
|
124
|
+
title: str
|
|
125
|
+
description: str
|
|
126
|
+
priority: Priority
|
|
127
|
+
assignee: str
|
|
128
|
+
|
|
129
|
+
class TaskList(BaseModel):
|
|
130
|
+
tasks: List[Task]
|
|
131
|
+
|
|
132
|
+
# Use with the generic llm_call function
|
|
133
|
+
tasks = llm_call("Extract tasks from this conversation", TaskList)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Advanced Usage with Structured Data Extraction
|
|
137
|
+
|
|
138
|
+
The library now supports a generic `llm_call` function that works with Pydantic models for structured data extraction:
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from typing import Type, TypeVar
|
|
142
|
+
from pydantic import BaseModel
|
|
143
|
+
from generic_llm_memorizer.conversation import Conversation
|
|
144
|
+
from generic_llm_memorizer.memory import Summary, Memory, Fact
|
|
145
|
+
|
|
146
|
+
# Define a generic type variable bounded by BaseModel
|
|
147
|
+
T = TypeVar("T", bound=BaseModel)
|
|
148
|
+
|
|
149
|
+
def llm_call(prompt: str, model_class: Type[T]) -> T:
|
|
150
|
+
"""
|
|
151
|
+
Generic LLM call function that returns structured data.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
prompt: The prompt to send to the LLM
|
|
155
|
+
model_class: The Pydantic model class to parse the response into
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
An instance of the specified model_class
|
|
159
|
+
"""
|
|
160
|
+
# In a real implementation, this would call an actual LLM API
|
|
161
|
+
# and parse the response into the specified Pydantic model
|
|
162
|
+
|
|
163
|
+
# Mock implementation for demonstration
|
|
164
|
+
if model_class == Summary:
|
|
165
|
+
return Summary(content="Mock summary of the conversation")
|
|
166
|
+
elif model_class == Memory:
|
|
167
|
+
return Memory(facts=[
|
|
168
|
+
Fact(
|
|
169
|
+
content="Example fact extracted from conversation",
|
|
170
|
+
kind="example",
|
|
171
|
+
timestamp="2023-01-01T10:00:00Z",
|
|
172
|
+
validity="forever"
|
|
173
|
+
)
|
|
174
|
+
])
|
|
175
|
+
|
|
176
|
+
# Return a default instance of the model
|
|
177
|
+
return model_class()
|
|
178
|
+
|
|
179
|
+
# Usage with LLMMemorizer
|
|
180
|
+
from generic_llm_memorizer.llm_memorizer import LLMMemorizer
|
|
181
|
+
|
|
182
|
+
conversation = Conversation(system_prompt="You are a helpful assistant")
|
|
183
|
+
conversation.add_user_message("Hello, my name is John Doe and I'm a software engineer")
|
|
184
|
+
|
|
185
|
+
memorizer = LLMMemorizer(
|
|
186
|
+
user_id="user_123",
|
|
187
|
+
session_id="session_456",
|
|
188
|
+
llm_call=llm_call,
|
|
189
|
+
conversation=conversation
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
# Extract structured facts
|
|
193
|
+
memory = memorizer.extract_facts()
|
|
194
|
+
print(f"Extracted {len(memory.facts)} facts")
|
|
195
|
+
|
|
196
|
+
# Generate structured summary
|
|
197
|
+
summary = memorizer.summarize()
|
|
198
|
+
print(f"Summary: {summary.content}")
|
|
199
|
+
|
|
200
|
+
## API Reference
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
from generic_llm_memorizer import extract_last_user_message, extract_last_assistant_message
|
|
204
|
+
|
|
205
|
+
# Extract last user message
|
|
206
|
+
last_user = extract_last_user_message(conv)
|
|
207
|
+
|
|
208
|
+
# Extract last assistant message
|
|
209
|
+
last_assistant = extract_last_assistant_message(conv)
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## API Reference
|
|
213
|
+
|
|
214
|
+
### Conversation Class
|
|
215
|
+
|
|
216
|
+
Manages a conversation with an LLM.
|
|
217
|
+
|
|
218
|
+
#### Methods
|
|
219
|
+
|
|
220
|
+
- `add_message(role, content, metadata=None)`: Add a message to the conversation
|
|
221
|
+
- `add_user_message(content, metadata=None)`: Add a user message
|
|
222
|
+
- `add_assistant_message(content, metadata=None)`: Add an assistant message
|
|
223
|
+
- `get_messages()`: Get all messages
|
|
224
|
+
- `get_recent_messages(count)`: Get the most recent messages
|
|
225
|
+
- `clear()`: Clear all messages
|
|
226
|
+
- `to_dict()`: Convert to dictionary format
|
|
227
|
+
- `to_json(indent=2)`: Convert to JSON string
|
|
228
|
+
- `from_dict(data)`: Create from dictionary data
|
|
229
|
+
- `from_json(json_str)`: Create from JSON string
|
|
230
|
+
|
|
231
|
+
### Message Dataclass
|
|
232
|
+
|
|
233
|
+
Represents a single message in a conversation.
|
|
234
|
+
|
|
235
|
+
#### Attributes
|
|
236
|
+
|
|
237
|
+
- `role`: Role of the message sender ("user", "assistant", "system", etc.)
|
|
238
|
+
- `content`: Message content
|
|
239
|
+
- `timestamp`: ISO format timestamp (automatically set)
|
|
240
|
+
- `metadata`: Additional metadata dictionary
|
|
241
|
+
|
|
242
|
+
### Utility Functions
|
|
243
|
+
|
|
244
|
+
- `format_conversation_for_prompt(conversation)`: Format conversation for LLM API
|
|
245
|
+
- `extract_last_user_message(conversation)`: Get last user message content
|
|
246
|
+
- `extract_last_assistant_message(conversation)`: Get last assistant message content
|
|
247
|
+
|
|
248
|
+
## License
|
|
249
|
+
|
|
250
|
+
MIT
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# Generic LLM Memorizer
|
|
2
|
+
|
|
3
|
+
A Python library for managing LLM conversations and context with automatic fact extraction and structured data handling.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install generic-llm-memorizer
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Basic Conversation Management
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from generic_llm_memorizer import Conversation
|
|
17
|
+
|
|
18
|
+
# Create a new conversation
|
|
19
|
+
conv = Conversation(system_prompt="You are a helpful assistant.")
|
|
20
|
+
|
|
21
|
+
# Add messages
|
|
22
|
+
conv.add_user_message("Hello, how are you?")
|
|
23
|
+
conv.add_assistant_message("I'm doing well, thank you! How can I help you today?")
|
|
24
|
+
|
|
25
|
+
# Get conversation history
|
|
26
|
+
messages = conv.get_messages()
|
|
27
|
+
|
|
28
|
+
# Format for LLM API (expects list of dicts with role and content)
|
|
29
|
+
from generic_llm_memorizer import format_conversation_for_prompt
|
|
30
|
+
formatted = format_conversation_for_prompt(conv)
|
|
31
|
+
# Output: [{"role": "system", "content": "You are a helpful assistant."}, ...]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from generic_llm_memorizer import Conversation
|
|
36
|
+
|
|
37
|
+
# Create a new conversation
|
|
38
|
+
conv = Conversation(system_prompt="You are a helpful assistant.")
|
|
39
|
+
|
|
40
|
+
# Add messages
|
|
41
|
+
conv.add_user_message("Hello, how are you?")
|
|
42
|
+
conv.add_assistant_message("I'm doing well, thank you! How can I help you today?")
|
|
43
|
+
|
|
44
|
+
# Get conversation history
|
|
45
|
+
messages = conv.get_messages()
|
|
46
|
+
|
|
47
|
+
# Format for LLM API (expects list of dicts with role and content)
|
|
48
|
+
from generic_llm_memorizer import format_conversation_for_prompt
|
|
49
|
+
formatted = format_conversation_for_prompt(conv)
|
|
50
|
+
# Output: [{"role": "system", "content": "You are a helpful assistant."}, ...]
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Persisting Conversations
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from generic_llm_memorizer import Conversation
|
|
57
|
+
|
|
58
|
+
# Save conversation to JSON
|
|
59
|
+
conv_json = conv.to_json()
|
|
60
|
+
with open("conversation.json", "w") as f:
|
|
61
|
+
f.write(conv_json)
|
|
62
|
+
|
|
63
|
+
# Load conversation from JSON
|
|
64
|
+
with open("conversation.json", "r") as f:
|
|
65
|
+
conv_json = f.read()
|
|
66
|
+
loaded_conv = Conversation.from_json(conv_json)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from generic_llm_memorizer import Conversation
|
|
71
|
+
|
|
72
|
+
# Save conversation to JSON
|
|
73
|
+
conv_json = conv.to_json()
|
|
74
|
+
with open("conversation.json", "w") as f:
|
|
75
|
+
f.write(conv_json)
|
|
76
|
+
|
|
77
|
+
# Load conversation from JSON
|
|
78
|
+
with open("conversation.json", "r") as f:
|
|
79
|
+
conv_json = f.read()
|
|
80
|
+
loaded_conv = Conversation.from_json(conv_json)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Utility Functions
|
|
84
|
+
|
|
85
|
+
## Extending with Custom Models
|
|
86
|
+
|
|
87
|
+
You can create your own Pydantic models for domain-specific extractions:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from pydantic import BaseModel
|
|
91
|
+
from typing import List
|
|
92
|
+
from enum import Enum
|
|
93
|
+
|
|
94
|
+
class Priority(str, Enum):
|
|
95
|
+
LOW = "low"
|
|
96
|
+
MEDIUM = "medium"
|
|
97
|
+
HIGH = "high"
|
|
98
|
+
|
|
99
|
+
class Task(BaseModel):
|
|
100
|
+
title: str
|
|
101
|
+
description: str
|
|
102
|
+
priority: Priority
|
|
103
|
+
assignee: str
|
|
104
|
+
|
|
105
|
+
class TaskList(BaseModel):
|
|
106
|
+
tasks: List[Task]
|
|
107
|
+
|
|
108
|
+
# Use with the generic llm_call function
|
|
109
|
+
tasks = llm_call("Extract tasks from this conversation", TaskList)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Advanced Usage with Structured Data Extraction
|
|
113
|
+
|
|
114
|
+
The library now supports a generic `llm_call` function that works with Pydantic models for structured data extraction:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from typing import Type, TypeVar
|
|
118
|
+
from pydantic import BaseModel
|
|
119
|
+
from generic_llm_memorizer.conversation import Conversation
|
|
120
|
+
from generic_llm_memorizer.memory import Summary, Memory, Fact
|
|
121
|
+
|
|
122
|
+
# Define a generic type variable bounded by BaseModel
|
|
123
|
+
T = TypeVar("T", bound=BaseModel)
|
|
124
|
+
|
|
125
|
+
def llm_call(prompt: str, model_class: Type[T]) -> T:
|
|
126
|
+
"""
|
|
127
|
+
Generic LLM call function that returns structured data.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
prompt: The prompt to send to the LLM
|
|
131
|
+
model_class: The Pydantic model class to parse the response into
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
An instance of the specified model_class
|
|
135
|
+
"""
|
|
136
|
+
# In a real implementation, this would call an actual LLM API
|
|
137
|
+
# and parse the response into the specified Pydantic model
|
|
138
|
+
|
|
139
|
+
# Mock implementation for demonstration
|
|
140
|
+
if model_class == Summary:
|
|
141
|
+
return Summary(content="Mock summary of the conversation")
|
|
142
|
+
elif model_class == Memory:
|
|
143
|
+
return Memory(facts=[
|
|
144
|
+
Fact(
|
|
145
|
+
content="Example fact extracted from conversation",
|
|
146
|
+
kind="example",
|
|
147
|
+
timestamp="2023-01-01T10:00:00Z",
|
|
148
|
+
validity="forever"
|
|
149
|
+
)
|
|
150
|
+
])
|
|
151
|
+
|
|
152
|
+
# Return a default instance of the model
|
|
153
|
+
return model_class()
|
|
154
|
+
|
|
155
|
+
# Usage with LLMMemorizer
|
|
156
|
+
from generic_llm_memorizer.llm_memorizer import LLMMemorizer
|
|
157
|
+
|
|
158
|
+
conversation = Conversation(system_prompt="You are a helpful assistant")
|
|
159
|
+
conversation.add_user_message("Hello, my name is John Doe and I'm a software engineer")
|
|
160
|
+
|
|
161
|
+
memorizer = LLMMemorizer(
|
|
162
|
+
user_id="user_123",
|
|
163
|
+
session_id="session_456",
|
|
164
|
+
llm_call=llm_call,
|
|
165
|
+
conversation=conversation
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
# Extract structured facts
|
|
169
|
+
memory = memorizer.extract_facts()
|
|
170
|
+
print(f"Extracted {len(memory.facts)} facts")
|
|
171
|
+
|
|
172
|
+
# Generate structured summary
|
|
173
|
+
summary = memorizer.summarize()
|
|
174
|
+
print(f"Summary: {summary.content}")
|
|
175
|
+
|
|
176
|
+
## API Reference
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
from generic_llm_memorizer import extract_last_user_message, extract_last_assistant_message
|
|
180
|
+
|
|
181
|
+
# Extract last user message
|
|
182
|
+
last_user = extract_last_user_message(conv)
|
|
183
|
+
|
|
184
|
+
# Extract last assistant message
|
|
185
|
+
last_assistant = extract_last_assistant_message(conv)
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## API Reference
|
|
189
|
+
|
|
190
|
+
### Conversation Class
|
|
191
|
+
|
|
192
|
+
Manages a conversation with an LLM.
|
|
193
|
+
|
|
194
|
+
#### Methods
|
|
195
|
+
|
|
196
|
+
- `add_message(role, content, metadata=None)`: Add a message to the conversation
|
|
197
|
+
- `add_user_message(content, metadata=None)`: Add a user message
|
|
198
|
+
- `add_assistant_message(content, metadata=None)`: Add an assistant message
|
|
199
|
+
- `get_messages()`: Get all messages
|
|
200
|
+
- `get_recent_messages(count)`: Get the most recent messages
|
|
201
|
+
- `clear()`: Clear all messages
|
|
202
|
+
- `to_dict()`: Convert to dictionary format
|
|
203
|
+
- `to_json(indent=2)`: Convert to JSON string
|
|
204
|
+
- `from_dict(data)`: Create from dictionary data
|
|
205
|
+
- `from_json(json_str)`: Create from JSON string
|
|
206
|
+
|
|
207
|
+
### Message Dataclass
|
|
208
|
+
|
|
209
|
+
Represents a single message in a conversation.
|
|
210
|
+
|
|
211
|
+
#### Attributes
|
|
212
|
+
|
|
213
|
+
- `role`: Role of the message sender ("user", "assistant", "system", etc.)
|
|
214
|
+
- `content`: Message content
|
|
215
|
+
- `timestamp`: ISO format timestamp (automatically set)
|
|
216
|
+
- `metadata`: Additional metadata dictionary
|
|
217
|
+
|
|
218
|
+
### Utility Functions
|
|
219
|
+
|
|
220
|
+
- `format_conversation_for_prompt(conversation)`: Format conversation for LLM API
|
|
221
|
+
- `extract_last_user_message(conversation)`: Get last user message content
|
|
222
|
+
- `extract_last_assistant_message(conversation)`: Get last assistant message content
|
|
223
|
+
|
|
224
|
+
## License
|
|
225
|
+
|
|
226
|
+
MIT
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Generic LLM Memorizer - LLM Conversation Management Library
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .conversation import Conversation, Message, format_conversation_for_prompt, extract_last_user_message, extract_last_assistant_message
|
|
6
|
+
|
|
7
|
+
__version__ = "0.1.0"
|
|
8
|
+
__author__ = "Your Name"
|
|
9
|
+
__email__ = "your.email@example.com"
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"Conversation",
|
|
13
|
+
"Message",
|
|
14
|
+
"format_conversation_for_prompt",
|
|
15
|
+
"extract_last_user_message",
|
|
16
|
+
"extract_last_assistant_message"
|
|
17
|
+
]
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Conversation management for LLM interactions.
|
|
3
|
+
Provides classes and functions to manage LLM conversation history and context.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
from dataclasses import asdict, dataclass
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
from typing import Any, Dict, List, Optional
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class Message:
|
|
14
|
+
"""Represents a single message in a conversation."""
|
|
15
|
+
|
|
16
|
+
role: str # "user", "assistant", "system", etc.
|
|
17
|
+
content: str
|
|
18
|
+
timestamp: Optional[str] = None
|
|
19
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
20
|
+
|
|
21
|
+
def __post_init__(self):
|
|
22
|
+
if self.timestamp is None:
|
|
23
|
+
self.timestamp = datetime.now().isoformat()
|
|
24
|
+
if self.metadata is None:
|
|
25
|
+
self.metadata = {}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Conversation:
|
|
29
|
+
"""Manages a conversation with an LLM."""
|
|
30
|
+
|
|
31
|
+
def __init__(self, session_id: str, system_prompt: Optional[str] = None):
|
|
32
|
+
self.session_id = session_id
|
|
33
|
+
self.messages: List[Message] = []
|
|
34
|
+
|
|
35
|
+
if system_prompt:
|
|
36
|
+
self.add_message("system", system_prompt)
|
|
37
|
+
|
|
38
|
+
def add_message(
|
|
39
|
+
self, role: str, content: str, metadata: Optional[Dict[str, Any]] = None
|
|
40
|
+
) -> Message:
|
|
41
|
+
"""Add a message to the conversation."""
|
|
42
|
+
message = Message(role=role, content=content, metadata=metadata)
|
|
43
|
+
self.messages.append(message)
|
|
44
|
+
return message
|
|
45
|
+
|
|
46
|
+
def add_messages(self, messages: List[Message]) -> None:
|
|
47
|
+
"""Add multiple messages to the conversation."""
|
|
48
|
+
self.messages.extend(messages)
|
|
49
|
+
|
|
50
|
+
def insert_summary(self, summary: str) -> None:
|
|
51
|
+
"""Insert a summary message into the conversation."""
|
|
52
|
+
return self.messages.insert(0, Message(role="assistant", content=summary))
|
|
53
|
+
|
|
54
|
+
def add_user_message(
|
|
55
|
+
self, content: str, metadata: Optional[Dict[str, Any]] = None
|
|
56
|
+
) -> Message:
|
|
57
|
+
"""Add a user message to the conversation."""
|
|
58
|
+
return self.add_message("user", content, metadata)
|
|
59
|
+
|
|
60
|
+
def add_assistant_message(
|
|
61
|
+
self, content: str, metadata: Optional[Dict[str, Any]] = None
|
|
62
|
+
) -> Message:
|
|
63
|
+
"""Add an assistant message to the conversation."""
|
|
64
|
+
return self.add_message("assistant", content, metadata)
|
|
65
|
+
|
|
66
|
+
def get_messages(self) -> List[Message]:
|
|
67
|
+
"""Get all messages in the conversation."""
|
|
68
|
+
return self.messages.copy()
|
|
69
|
+
|
|
70
|
+
def get_recent_messages(self, count: int) -> List[Message]:
|
|
71
|
+
"""Get the most recent messages."""
|
|
72
|
+
return (
|
|
73
|
+
self.messages[-count:]
|
|
74
|
+
if count <= len(self.messages)
|
|
75
|
+
else self.messages.copy()
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
def keep_recent_messages(self, count: int):
|
|
79
|
+
"""Keep only the most recent messages."""
|
|
80
|
+
if count < 0:
|
|
81
|
+
raise ValueError("Count must be non-negative")
|
|
82
|
+
self.messages = self.messages[-count:]
|
|
83
|
+
|
|
84
|
+
def delete_old_messages(self, count: int):
|
|
85
|
+
"""Delete the oldest messages from the conversation."""
|
|
86
|
+
if count < 0:
|
|
87
|
+
raise ValueError("Count must be non-negative")
|
|
88
|
+
self.messages = self.messages[count:]
|
|
89
|
+
|
|
90
|
+
def clear(self):
|
|
91
|
+
"""Clear all messages from the conversation."""
|
|
92
|
+
self.messages.clear()
|
|
93
|
+
|
|
94
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
95
|
+
"""Convert conversation to dictionary format."""
|
|
96
|
+
return {
|
|
97
|
+
"session_id": self.session_id,
|
|
98
|
+
"messages": [asdict(msg) for msg in self.messages],
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
def to_json(self, indent: int = 2) -> str:
|
|
102
|
+
"""Convert conversation to JSON string."""
|
|
103
|
+
return json.dumps(self.to_dict(), indent=indent)
|
|
104
|
+
|
|
105
|
+
@classmethod
|
|
106
|
+
def from_dict(cls, session_id: str, data: List[Dict[str, Any]]) -> "Conversation":
|
|
107
|
+
"""Create a conversation from dictionary data."""
|
|
108
|
+
conversation = cls(session_id=session_id)
|
|
109
|
+
conversation.messages = [Message(**msg_dict) for msg_dict in data]
|
|
110
|
+
return conversation
|
|
111
|
+
|
|
112
|
+
@classmethod
|
|
113
|
+
def from_json(cls, json_str: str) -> "Conversation":
|
|
114
|
+
"""Create a conversation from JSON string."""
|
|
115
|
+
data = json.loads(json_str)
|
|
116
|
+
return cls.from_dict(data["session_id"], data["messages"])
|
|
117
|
+
|
|
118
|
+
def __len__(self) -> int:
|
|
119
|
+
return len(self.messages)
|
|
120
|
+
|
|
121
|
+
def __iter__(self):
|
|
122
|
+
return iter(self.messages)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def format_conversation_for_prompt(conversation: Conversation) -> List[Dict[str, str]]:
|
|
126
|
+
"""
|
|
127
|
+
Format conversation for use with LLM APIs that expect a list of message dicts.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
conversation: Conversation object to format
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
List of dictionaries with 'role' and 'content' keys
|
|
134
|
+
"""
|
|
135
|
+
return [
|
|
136
|
+
{"role": msg.role, "content": msg.content}
|
|
137
|
+
for msg in conversation.get_messages()
|
|
138
|
+
]
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def extract_last_user_message(conversation: Conversation) -> Optional[str]:
|
|
142
|
+
"""
|
|
143
|
+
Extract the last user message from a conversation.
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
conversation: Conversation object
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
Content of the last user message, or None if no user messages exist
|
|
150
|
+
"""
|
|
151
|
+
for msg in reversed(conversation.messages):
|
|
152
|
+
if msg.role == "user":
|
|
153
|
+
return msg.content
|
|
154
|
+
return None
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def extract_last_assistant_message(conversation: Conversation) -> Optional[str]:
|
|
158
|
+
"""
|
|
159
|
+
Extract the last assistant message from a conversation.
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
conversation: Conversation object
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
Content of the last assistant message, or None if no assistant messages exist
|
|
166
|
+
"""
|
|
167
|
+
for msg in reversed(conversation.messages):
|
|
168
|
+
if msg.role == "assistant":
|
|
169
|
+
return msg.content
|
|
170
|
+
return None
|