flock-core 0.3.10__py3-none-any.whl → 0.3.13__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 flock-core might be problematic. Click here for more details.
- flock/core/flock.py +15 -0
- flock/core/flock_agent.py +2 -1
- flock/core/flock_api.py +0 -1
- flock/core/logging/logging.py +172 -17
- flock/core/tools/basic_tools.py +8 -0
- flock/core/tools/llm_tools.py +788 -0
- flock/core/tools/markdown_tools.py +195 -0
- flock/evaluators/memory/memory_evaluator.py +88 -0
- flock/modules/memory/memory_module.py +257 -95
- flock/modules/memory/memory_parser.py +1 -1
- {flock_core-0.3.10.dist-info → flock_core-0.3.13.dist-info}/METADATA +3 -2
- {flock_core-0.3.10.dist-info → flock_core-0.3.13.dist-info}/RECORD +15 -12
- {flock_core-0.3.10.dist-info → flock_core-0.3.13.dist-info}/WHEEL +0 -0
- {flock_core-0.3.10.dist-info → flock_core-0.3.13.dist-info}/entry_points.txt +0 -0
- {flock_core-0.3.10.dist-info → flock_core-0.3.13.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,21 +1,33 @@
|
|
|
1
|
-
"""Memory module implementation for Flock agents."""
|
|
2
|
-
|
|
3
1
|
import json
|
|
4
2
|
import uuid
|
|
5
3
|
from datetime import datetime
|
|
6
|
-
from typing import Any
|
|
4
|
+
from typing import Any, Literal
|
|
7
5
|
|
|
8
6
|
from pydantic import Field
|
|
7
|
+
from tqdm import tqdm
|
|
9
8
|
|
|
10
9
|
from flock.core import FlockAgent, FlockModule, FlockModuleConfig
|
|
11
10
|
from flock.core.logging.logging import get_logger
|
|
12
11
|
from flock.modules.memory.memory_parser import MemoryMappingParser
|
|
13
12
|
from flock.modules.memory.memory_storage import FlockMemoryStore, MemoryEntry
|
|
14
13
|
|
|
14
|
+
logger = get_logger("memory")
|
|
15
|
+
|
|
15
16
|
|
|
16
17
|
class MemoryModuleConfig(FlockModuleConfig):
|
|
17
|
-
"""Configuration for the
|
|
18
|
+
"""Configuration for the MemoryModule.
|
|
18
19
|
|
|
20
|
+
This class defines the configuration for the MemoryModule.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
folder_path: str = Field(
|
|
24
|
+
default="concept_memory/",
|
|
25
|
+
description="Directory where memory file and concept graph will be saved",
|
|
26
|
+
)
|
|
27
|
+
concept_graph_file: str = Field(
|
|
28
|
+
default="concept_graph.png",
|
|
29
|
+
description="Base filename for the concept graph image",
|
|
30
|
+
)
|
|
19
31
|
file_path: str | None = Field(
|
|
20
32
|
default="agent_memory.json", description="Path to save memory file"
|
|
21
33
|
)
|
|
@@ -25,26 +37,25 @@ class MemoryModuleConfig(FlockModuleConfig):
|
|
|
25
37
|
similarity_threshold: float = Field(
|
|
26
38
|
default=0.5, description="Threshold for semantic similarity"
|
|
27
39
|
)
|
|
28
|
-
context_window: int = Field(
|
|
29
|
-
default=3, description="Number of memory entries to return"
|
|
30
|
-
)
|
|
31
40
|
max_length: int = Field(
|
|
32
41
|
default=1000, description="Max length of memory entry before splitting"
|
|
33
42
|
)
|
|
34
43
|
save_after_update: bool = Field(
|
|
35
44
|
default=True, description="Whether to save memory after each update"
|
|
36
45
|
)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
46
|
+
splitting_mode: Literal["summary", "semantic", "characters", "none"] = (
|
|
47
|
+
Field(default="none", description="Mode to split memory content")
|
|
48
|
+
)
|
|
49
|
+
enable_read_only_mode: bool = Field(
|
|
50
|
+
default=False, description="Whether to enable read only mode"
|
|
51
|
+
)
|
|
52
|
+
number_of_concepts_to_extract: int = Field(
|
|
53
|
+
default=3, description="Number of concepts to extract from the memory"
|
|
54
|
+
)
|
|
40
55
|
|
|
41
56
|
|
|
42
57
|
class MemoryModule(FlockModule):
|
|
43
|
-
"""Module that adds memory capabilities to a Flock agent.
|
|
44
|
-
|
|
45
|
-
This module encapsulates all memory-related functionality that was previously
|
|
46
|
-
hardcoded into FlockAgent.
|
|
47
|
-
"""
|
|
58
|
+
"""Module that adds memory capabilities to a Flock agent."""
|
|
48
59
|
|
|
49
60
|
name: str = "memory"
|
|
50
61
|
config: MemoryModuleConfig = Field(
|
|
@@ -52,31 +63,34 @@ class MemoryModule(FlockModule):
|
|
|
52
63
|
description="Memory module configuration",
|
|
53
64
|
)
|
|
54
65
|
memory_store: FlockMemoryStore | None = None
|
|
55
|
-
memory_ops: list = []
|
|
66
|
+
memory_ops: list[Any] = []
|
|
67
|
+
|
|
68
|
+
def __init__(self, name: str, config: MemoryModuleConfig):
|
|
69
|
+
super().__init__(name=name, config=config)
|
|
70
|
+
self.memory_store = FlockMemoryStore.load_from_file(
|
|
71
|
+
self.get_memory_filename(name)
|
|
72
|
+
)
|
|
73
|
+
self.memory_ops = (
|
|
74
|
+
MemoryMappingParser().parse(self.config.memory_mapping)
|
|
75
|
+
if self.config.memory_mapping
|
|
76
|
+
else [{"type": "semantic"}]
|
|
77
|
+
)
|
|
56
78
|
|
|
57
|
-
async def
|
|
79
|
+
async def initialize(
|
|
58
80
|
self, agent: FlockAgent, inputs: dict[str, Any]
|
|
59
81
|
) -> None:
|
|
60
82
|
"""Initialize memory store if needed."""
|
|
61
83
|
if not self.memory_store:
|
|
62
84
|
self.memory_store = FlockMemoryStore.load_from_file(
|
|
63
|
-
self.
|
|
85
|
+
self.get_memory_filename(self.name)
|
|
64
86
|
)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
self.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
self.memory_ops = MemoryMappingParser().parse(
|
|
71
|
-
self.config.memory_mapping
|
|
72
|
-
)
|
|
73
|
-
|
|
87
|
+
self.memory_ops = (
|
|
88
|
+
MemoryMappingParser().parse(self.config.memory_mapping)
|
|
89
|
+
if self.config.memory_mapping
|
|
90
|
+
else [{"type": "semantic"}]
|
|
91
|
+
)
|
|
74
92
|
logger.debug(f"Initialized memory module for agent {agent.name}")
|
|
75
93
|
|
|
76
|
-
async def post_initialize(self, agent: Any, inputs: dict[str, Any]) -> None:
|
|
77
|
-
"""No post-initialization needed."""
|
|
78
|
-
pass
|
|
79
|
-
|
|
80
94
|
async def pre_evaluate(
|
|
81
95
|
self, agent: FlockAgent, inputs: dict[str, Any]
|
|
82
96
|
) -> dict[str, Any]:
|
|
@@ -85,12 +99,11 @@ class MemoryModule(FlockModule):
|
|
|
85
99
|
return inputs
|
|
86
100
|
|
|
87
101
|
try:
|
|
88
|
-
# Convert input to embedding
|
|
89
102
|
input_text = json.dumps(inputs)
|
|
90
103
|
query_embedding = self.memory_store.compute_embedding(input_text)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
104
|
+
concepts = await self._extract_concepts(
|
|
105
|
+
agent, input_text, self.config.number_of_concepts_to_extract
|
|
106
|
+
)
|
|
94
107
|
|
|
95
108
|
memory_results = []
|
|
96
109
|
for op in self.memory_ops:
|
|
@@ -101,7 +114,6 @@ class MemoryModule(FlockModule):
|
|
|
101
114
|
similarity_threshold=self.config.similarity_threshold,
|
|
102
115
|
)
|
|
103
116
|
memory_results.extend(semantic_results)
|
|
104
|
-
|
|
105
117
|
elif op["type"] == "exact":
|
|
106
118
|
exact_results = self.memory_store.exact_match(inputs)
|
|
107
119
|
memory_results.extend(exact_results)
|
|
@@ -116,120 +128,270 @@ class MemoryModule(FlockModule):
|
|
|
116
128
|
return inputs
|
|
117
129
|
|
|
118
130
|
except Exception as e:
|
|
119
|
-
logger.warning(f"Memory retrieval failed: {e
|
|
131
|
+
logger.warning(f"Memory retrieval failed: {e}", agent=agent.name)
|
|
120
132
|
return inputs
|
|
121
133
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
134
|
+
def get_memory_filename(self, module_name: str) -> str:
|
|
135
|
+
"""Generate the full file path for the memory file."""
|
|
136
|
+
folder = self.config.folder_path
|
|
137
|
+
if not folder.endswith(("/", "\\")):
|
|
138
|
+
folder += "/"
|
|
139
|
+
import os
|
|
140
|
+
|
|
141
|
+
if not os.path.exists(folder):
|
|
142
|
+
os.makedirs(folder, exist_ok=True)
|
|
143
|
+
# Determine base filename and extension from file_path config
|
|
144
|
+
if self.config.file_path:
|
|
145
|
+
file_name = self.config.file_path.rsplit("/", 1)[-1].rsplit(
|
|
146
|
+
"\\", 1
|
|
147
|
+
)[-1]
|
|
148
|
+
if "." in file_name:
|
|
149
|
+
base, ext = file_name.rsplit(".", 1)
|
|
150
|
+
ext = f".{ext}"
|
|
151
|
+
else:
|
|
152
|
+
base, ext = file_name, ""
|
|
153
|
+
else:
|
|
154
|
+
base, ext = "agent_memory", ".json"
|
|
155
|
+
return f"{folder}{module_name}_{base}{ext}"
|
|
156
|
+
|
|
157
|
+
def get_concept_graph_filename(self, module_name: str) -> str:
|
|
158
|
+
"""Generate the full file path for the concept graph image."""
|
|
159
|
+
folder = self.config.folder_path
|
|
160
|
+
if not folder.endswith(("/", "\\")):
|
|
161
|
+
folder += "/"
|
|
162
|
+
import os
|
|
163
|
+
|
|
164
|
+
if not os.path.exists(folder):
|
|
165
|
+
os.makedirs(folder, exist_ok=True)
|
|
166
|
+
# Use timestamp to create a unique filename
|
|
167
|
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")[:-3]
|
|
168
|
+
if self.config.concept_graph_file:
|
|
169
|
+
file_name = self.config.concept_graph_file.rsplit("/", 1)[
|
|
170
|
+
-1
|
|
171
|
+
].rsplit("\\", 1)[-1]
|
|
172
|
+
if "." in file_name:
|
|
173
|
+
base, ext = file_name.rsplit(".", 1)
|
|
174
|
+
ext = f".{ext}"
|
|
175
|
+
else:
|
|
176
|
+
base, ext = file_name, ""
|
|
177
|
+
else:
|
|
178
|
+
base, ext = "concept_graph", ".png"
|
|
179
|
+
return f"{folder}{module_name}_{base}_{timestamp}{ext}"
|
|
180
|
+
|
|
181
|
+
async def search_memory(
|
|
182
|
+
self, agent: FlockAgent, query: dict[str, Any]
|
|
183
|
+
) -> list[str]:
|
|
184
|
+
"""Search memory for the query."""
|
|
126
185
|
if not self.memory_store:
|
|
127
|
-
return
|
|
186
|
+
return []
|
|
128
187
|
|
|
129
188
|
try:
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
# Create memory entry
|
|
135
|
-
entry = MemoryEntry(
|
|
136
|
-
id=str(uuid.uuid4()),
|
|
137
|
-
content=chunks,
|
|
138
|
-
embedding=self.memory_store.compute_embedding(chunks).tolist(),
|
|
139
|
-
concepts=chunk_concepts,
|
|
140
|
-
timestamp=datetime.now(),
|
|
189
|
+
input_text = json.dumps(query)
|
|
190
|
+
query_embedding = self.memory_store.compute_embedding(input_text)
|
|
191
|
+
concepts = await self._extract_concepts(
|
|
192
|
+
agent, input_text, self.config.number_of_concepts_to_extract
|
|
141
193
|
)
|
|
142
194
|
|
|
143
|
-
|
|
144
|
-
self.
|
|
195
|
+
memory_results = []
|
|
196
|
+
for op in self.memory_ops:
|
|
197
|
+
if op["type"] == "semantic":
|
|
198
|
+
semantic_results = self.memory_store.retrieve(
|
|
199
|
+
query_embedding,
|
|
200
|
+
concepts,
|
|
201
|
+
similarity_threshold=self.config.similarity_threshold,
|
|
202
|
+
)
|
|
203
|
+
memory_results.extend(semantic_results)
|
|
204
|
+
elif op["type"] == "exact":
|
|
205
|
+
exact_results = self.memory_store.exact_match(query)
|
|
206
|
+
memory_results.extend(exact_results)
|
|
207
|
+
|
|
208
|
+
if memory_results:
|
|
209
|
+
logger.debug(
|
|
210
|
+
f"Found {len(memory_results)} relevant memories",
|
|
211
|
+
agent=agent.name,
|
|
212
|
+
)
|
|
213
|
+
query["memory_results"] = memory_results
|
|
145
214
|
|
|
146
|
-
|
|
147
|
-
self.save_memory()
|
|
215
|
+
return query
|
|
148
216
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
entry_id=entry.id,
|
|
153
|
-
concepts=chunk_concepts,
|
|
154
|
-
)
|
|
217
|
+
except Exception as e:
|
|
218
|
+
logger.warning(f"Memory retrieval failed: {e}", agent=agent.name)
|
|
219
|
+
return query
|
|
155
220
|
|
|
221
|
+
async def add_to_memory(
|
|
222
|
+
self, agent: FlockAgent, data: dict[str, Any]
|
|
223
|
+
) -> None:
|
|
224
|
+
"""Add data to memory."""
|
|
225
|
+
if not self.memory_store:
|
|
226
|
+
return
|
|
227
|
+
|
|
228
|
+
try:
|
|
229
|
+
chunks = await self._get_chunks(agent, data, None)
|
|
230
|
+
await self._store_chunks(agent, chunks)
|
|
156
231
|
except Exception as e:
|
|
157
|
-
logger.warning(f"Memory storage failed: {e
|
|
232
|
+
logger.warning(f"Memory storage failed: {e}", agent=agent.name)
|
|
158
233
|
|
|
159
|
-
|
|
234
|
+
async def post_evaluate(
|
|
235
|
+
self, agent: FlockAgent, inputs: dict[str, Any], result: dict[str, Any]
|
|
236
|
+
) -> dict[str, Any]:
|
|
237
|
+
"""Store results in memory after evaluation."""
|
|
238
|
+
if not self.memory_store:
|
|
239
|
+
return result
|
|
160
240
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
241
|
+
try:
|
|
242
|
+
chunks = await self._get_chunks(agent, inputs, result)
|
|
243
|
+
await self._store_chunks(agent, chunks)
|
|
244
|
+
except Exception as e:
|
|
245
|
+
logger.warning(f"Memory storage failed: {e}", agent=agent.name)
|
|
166
246
|
|
|
167
|
-
|
|
247
|
+
return result
|
|
248
|
+
|
|
249
|
+
async def terminate(
|
|
168
250
|
self, agent: Any, inputs: dict[str, Any], result: dict[str, Any]
|
|
169
251
|
) -> None:
|
|
170
252
|
"""Save memory store if configured."""
|
|
171
253
|
if self.config.save_after_update and self.memory_store:
|
|
172
254
|
self.save_memory()
|
|
173
255
|
|
|
174
|
-
async def _extract_concepts(
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
256
|
+
async def _extract_concepts(
|
|
257
|
+
self, agent: FlockAgent, text: str, number_of_concepts: int = 3
|
|
258
|
+
) -> set[str]:
|
|
259
|
+
"""Extract concepts using the agent's LLM capabilities."""
|
|
260
|
+
existing_concepts = set()
|
|
261
|
+
if self.memory_store and self.memory_store.concept_graph:
|
|
178
262
|
existing_concepts = set(
|
|
179
263
|
self.memory_store.concept_graph.graph.nodes()
|
|
180
264
|
)
|
|
181
265
|
|
|
182
|
-
|
|
266
|
+
input_signature = "text: str | Text to analyze"
|
|
183
267
|
if existing_concepts:
|
|
184
|
-
|
|
268
|
+
input_signature += ", existing_concepts: list[str] | Already known concepts that might apply"
|
|
185
269
|
|
|
186
|
-
# Create signature for concept extraction using agent's capabilities
|
|
187
270
|
concept_signature = agent.create_dspy_signature_class(
|
|
188
271
|
f"{agent.name}_concept_extractor",
|
|
189
272
|
"Extract key concepts from text",
|
|
190
|
-
f"{
|
|
273
|
+
f"{input_signature} -> concepts: list[str] | Max {number_of_concepts} key concepts all lower case",
|
|
191
274
|
)
|
|
192
275
|
|
|
193
|
-
|
|
194
|
-
agent._configure_language_model()
|
|
276
|
+
agent._configure_language_model(agent.model, True, 0.0, 8192)
|
|
195
277
|
predictor = agent._select_task(concept_signature, "Completion")
|
|
196
|
-
|
|
278
|
+
result_obj = predictor(
|
|
197
279
|
text=text,
|
|
198
280
|
existing_concepts=list(existing_concepts)
|
|
199
281
|
if existing_concepts
|
|
200
282
|
else None,
|
|
201
283
|
)
|
|
202
|
-
|
|
203
|
-
concept_list = result.concepts if hasattr(result, "concepts") else []
|
|
284
|
+
concept_list = getattr(result_obj, "concepts", [])
|
|
204
285
|
return set(concept_list)
|
|
205
286
|
|
|
206
|
-
async def
|
|
287
|
+
async def _summarize_mode(
|
|
207
288
|
self, agent: FlockAgent, inputs: dict[str, Any], result: dict[str, Any]
|
|
208
289
|
) -> str:
|
|
209
|
-
"""Extract information chunks
|
|
210
|
-
# Create splitter signature using agent's capabilities
|
|
290
|
+
"""Extract information chunks using summary mode."""
|
|
211
291
|
split_signature = agent.create_dspy_signature_class(
|
|
212
292
|
f"{agent.name}_splitter",
|
|
213
293
|
"Extract a list of potentially needed data and information for future reference",
|
|
214
294
|
"""
|
|
215
295
|
content: str | The content to split
|
|
216
|
-
-> chunks: list[str] |
|
|
296
|
+
-> chunks: list[str] | List of data and information for future reference
|
|
217
297
|
""",
|
|
218
298
|
)
|
|
219
|
-
|
|
220
|
-
# Configure and run the predictor
|
|
221
|
-
agent._configure_language_model()
|
|
299
|
+
agent._configure_language_model(agent.model, True, 0.0, 8192)
|
|
222
300
|
splitter = agent._select_task(split_signature, "Completion")
|
|
223
|
-
|
|
224
|
-
# Get the content to split
|
|
225
301
|
full_text = json.dumps(inputs) + json.dumps(result)
|
|
226
302
|
split_result = splitter(content=full_text)
|
|
227
|
-
|
|
228
303
|
return "\n".join(split_result.chunks)
|
|
229
304
|
|
|
305
|
+
async def _semantic_splitter_mode(
|
|
306
|
+
self, agent: FlockAgent, inputs: dict[str, Any], result: dict[str, Any]
|
|
307
|
+
) -> str | list[dict[str, str]]:
|
|
308
|
+
"""Extract information chunks using semantic mode."""
|
|
309
|
+
split_signature = agent.create_dspy_signature_class(
|
|
310
|
+
f"{self.name}_splitter",
|
|
311
|
+
"Split content into meaningful, self-contained chunks",
|
|
312
|
+
"""
|
|
313
|
+
content: str | The content to split
|
|
314
|
+
-> chunks: list[dict[str,str]] | List of chunks as key-value pairs - keys are a short title and values are the chunk content
|
|
315
|
+
""",
|
|
316
|
+
)
|
|
317
|
+
agent._configure_language_model(agent.model, True, 0.0, 8192)
|
|
318
|
+
splitter = agent._select_task(split_signature, "Completion")
|
|
319
|
+
full_text = json.dumps(inputs) + (json.dumps(result) if result else "")
|
|
320
|
+
split_result = splitter(content=full_text)
|
|
321
|
+
return split_result.chunks
|
|
322
|
+
|
|
323
|
+
async def _character_splitter_mode(
|
|
324
|
+
self, agent: FlockAgent, inputs: dict[str, Any], result: dict[str, Any]
|
|
325
|
+
) -> list[str]:
|
|
326
|
+
"""Extract information chunks by splitting text into fixed character lengths."""
|
|
327
|
+
full_text = json.dumps(inputs) + (json.dumps(result) if result else "")
|
|
328
|
+
return [
|
|
329
|
+
full_text[i : i + self.config.max_length]
|
|
330
|
+
for i in range(0, len(full_text), self.config.max_length)
|
|
331
|
+
]
|
|
332
|
+
|
|
333
|
+
async def _get_chunks(
|
|
334
|
+
self,
|
|
335
|
+
agent: FlockAgent,
|
|
336
|
+
inputs: dict[str, Any],
|
|
337
|
+
result: dict[str, Any] | None,
|
|
338
|
+
) -> str | list[str]:
|
|
339
|
+
"""Get memory chunks based on the configured splitting mode."""
|
|
340
|
+
mode = self.config.splitting_mode
|
|
341
|
+
if mode == "semantic":
|
|
342
|
+
return await self._semantic_splitter_mode(agent, inputs, result)
|
|
343
|
+
elif mode == "summary":
|
|
344
|
+
return await self._summarize_mode(agent, inputs, result)
|
|
345
|
+
elif mode == "characters":
|
|
346
|
+
return await self._character_splitter_mode(agent, inputs, result)
|
|
347
|
+
elif mode == "none":
|
|
348
|
+
return (
|
|
349
|
+
json.dumps(inputs) + json.dumps(result)
|
|
350
|
+
if result
|
|
351
|
+
else json.dumps(inputs)
|
|
352
|
+
)
|
|
353
|
+
else:
|
|
354
|
+
raise ValueError(f"Unknown splitting mode: {mode}")
|
|
355
|
+
|
|
356
|
+
async def _store_chunk(self, agent: FlockAgent, chunk: str) -> None:
|
|
357
|
+
"""Store a single chunk in memory."""
|
|
358
|
+
chunk_concepts = await self._extract_concepts(
|
|
359
|
+
agent, chunk, self.config.number_of_concepts_to_extract
|
|
360
|
+
)
|
|
361
|
+
entry = MemoryEntry(
|
|
362
|
+
id=str(uuid.uuid4()),
|
|
363
|
+
content=chunk,
|
|
364
|
+
embedding=self.memory_store.compute_embedding(chunk).tolist(),
|
|
365
|
+
concepts=chunk_concepts,
|
|
366
|
+
timestamp=datetime.now(),
|
|
367
|
+
)
|
|
368
|
+
self.memory_store.add_entry(entry)
|
|
369
|
+
if self.config.save_after_update:
|
|
370
|
+
self.save_memory()
|
|
371
|
+
logger.debug(
|
|
372
|
+
"Stored interaction in memory",
|
|
373
|
+
agent=agent.name,
|
|
374
|
+
entry_id=entry.id,
|
|
375
|
+
concepts=chunk_concepts,
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
async def _store_chunks(
|
|
379
|
+
self, agent: FlockAgent, chunks: str | list[str]
|
|
380
|
+
) -> None:
|
|
381
|
+
"""Store chunks (single or multiple) in memory."""
|
|
382
|
+
if isinstance(chunks, str):
|
|
383
|
+
await self._store_chunk(agent, chunks)
|
|
384
|
+
elif isinstance(chunks, list):
|
|
385
|
+
for chunk in tqdm(chunks, desc="Storing chunks in memory"):
|
|
386
|
+
await self._store_chunk(agent, chunk)
|
|
387
|
+
|
|
230
388
|
def save_memory(self) -> None:
|
|
231
389
|
"""Save memory store to file."""
|
|
232
390
|
if self.memory_store and self.config.file_path:
|
|
233
391
|
json_str = self.memory_store.model_dump_json()
|
|
234
|
-
|
|
392
|
+
filename = self.get_memory_filename(self.name)
|
|
393
|
+
with open(filename, "w") as file:
|
|
235
394
|
file.write(json_str)
|
|
395
|
+
self.memory_store.concept_graph.save_as_image(
|
|
396
|
+
self.get_concept_graph_filename(self.name)
|
|
397
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flock-core
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.13
|
|
4
4
|
Summary: Declarative LLM Orchestration at Scale
|
|
5
5
|
Author-email: Andre Ratzenberger <andre.ratzenberger@whiteduck.de>
|
|
6
6
|
License-File: LICENSE
|
|
@@ -8,6 +8,7 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
8
8
|
Classifier: Operating System :: OS Independent
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
|
10
10
|
Requires-Python: >=3.10
|
|
11
|
+
Requires-Dist: chromadb>=0.6.3
|
|
11
12
|
Requires-Dist: cloudpickle>=3.1.1
|
|
12
13
|
Requires-Dist: devtools>=0.12.2
|
|
13
14
|
Requires-Dist: dspy==2.5.42
|
|
@@ -30,6 +31,7 @@ Requires-Dist: python-box>=7.3.2
|
|
|
30
31
|
Requires-Dist: python-decouple>=3.8
|
|
31
32
|
Requires-Dist: questionary>=2.1.0
|
|
32
33
|
Requires-Dist: rich>=13.9.4
|
|
34
|
+
Requires-Dist: sentence-transformers>=3.4.1
|
|
33
35
|
Requires-Dist: temporalio>=1.9.0
|
|
34
36
|
Requires-Dist: tiktoken>=0.8.0
|
|
35
37
|
Requires-Dist: toml>=0.10.2
|
|
@@ -39,7 +41,6 @@ Requires-Dist: zep-python>=2.0.2
|
|
|
39
41
|
Provides-Extra: all
|
|
40
42
|
Requires-Dist: docling>=2.18.0; extra == 'all'
|
|
41
43
|
Requires-Dist: markdownify>=0.14.1; extra == 'all'
|
|
42
|
-
Requires-Dist: sentence-transformers>=3.4.1; extra == 'all'
|
|
43
44
|
Requires-Dist: tavily-python>=0.5.0; extra == 'all'
|
|
44
45
|
Provides-Extra: tools
|
|
45
46
|
Requires-Dist: markdownify>=0.14.1; extra == 'tools'
|
|
@@ -10,9 +10,9 @@ flock/cli/load_release_notes.py,sha256=qFcgUrMddAE_TP6x1P-6ZywTUjTknfhTDW5LTxtg1
|
|
|
10
10
|
flock/cli/settings.py,sha256=DkeLUlrb7rGx3nZ04aADU9HXXu5mZTf_DBwT0xhzIv4,7
|
|
11
11
|
flock/cli/assets/release_notes.md,sha256=-RuE-G9Sn8z1LWEdr9iqjuQN7N1K_JMaCzHYoyLR42U,4793
|
|
12
12
|
flock/core/__init__.py,sha256=mPlvKc0SxC2qCvSlgYeP_7EyV8ptmdn24NO8mlQoCSo,559
|
|
13
|
-
flock/core/flock.py,sha256=
|
|
14
|
-
flock/core/flock_agent.py,sha256=
|
|
15
|
-
flock/core/flock_api.py,sha256=
|
|
13
|
+
flock/core/flock.py,sha256=IURlcuNvdsnqKkvgXtX4v_pGWQ8Lfb60X--MT0zvxHo,19881
|
|
14
|
+
flock/core/flock_agent.py,sha256=qG6j-aSxSTEcvv5tjMyw3RTCaBooIGF7IVhAUOrhPOo,11946
|
|
15
|
+
flock/core/flock_api.py,sha256=2rHnmEdtT5KPZYwGesRT7LqwbrgKClODHT-O56u7pcQ,7140
|
|
16
16
|
flock/core/flock_evaluator.py,sha256=j7riJj_KsWoBnKmLiGp-U0CRhxDyJbgEdLGN26tfKm8,1588
|
|
17
17
|
flock/core/flock_factory.py,sha256=nh0tK5UzEPWP5EmFrRvhsAeaZEvaPG5e0tkYkHpTjy0,2606
|
|
18
18
|
flock/core/flock_module.py,sha256=3DmxOc39gQS-tiJcgUCjMaLr8QDDJR4acV_M76Xcf6I,2602
|
|
@@ -24,7 +24,7 @@ flock/core/execution/local_executor.py,sha256=rnIQvaJOs6zZORUcR3vvyS6LPREDJTjayg
|
|
|
24
24
|
flock/core/execution/temporal_executor.py,sha256=OF_uXgQsoUGp6U1ZkcuaidAEKyH7XDtbfrtdF10XQ_4,1675
|
|
25
25
|
flock/core/interpreter/python_interpreter.py,sha256=RaUMZuufsKBNQ4FAeSaOgUuxzs8VYu5TgUUs-xwaxxM,26376
|
|
26
26
|
flock/core/logging/__init__.py,sha256=Q8hp9-1ilPIUIV0jLgJ3_cP7COrea32cVwL7dicPnlM,82
|
|
27
|
-
flock/core/logging/logging.py,sha256=
|
|
27
|
+
flock/core/logging/logging.py,sha256=uWtUZnQI_sdtzLfXo61JPENSNNwplvEuGMPIhsYd-gQ,12448
|
|
28
28
|
flock/core/logging/telemetry.py,sha256=3E9Tyj6AUR6A5RlIufcdCdWm5BAA7tbOsCa7lHoUQaU,5404
|
|
29
29
|
flock/core/logging/trace_and_logged.py,sha256=5vNrK1kxuPMoPJ0-QjQg-EDJL1oiEzvU6UNi6X8FiMs,2117
|
|
30
30
|
flock/core/logging/formatters/enum_builder.py,sha256=LgEYXUv84wK5vwHflZ5h8HBGgvLH3sByvUQe8tZiyY0,981
|
|
@@ -40,17 +40,20 @@ flock/core/mixin/prompt_parser.py,sha256=eOqI-FK3y17gVqpc_y5GF-WmK1Jv8mFlkZxTcgw
|
|
|
40
40
|
flock/core/registry/agent_registry.py,sha256=TUClh9e3eA6YzZC1CMTlsTPvQeqb9jYHewi-zPpcWM8,4987
|
|
41
41
|
flock/core/serialization/secure_serializer.py,sha256=n5-zRvvXddgJv1FFHsaQ2wuYdL3WUSGPvG_LGaffEJo,6144
|
|
42
42
|
flock/core/serialization/serializable.py,sha256=SymJ0YrjBx48mOBItYSqoRpKuzIc4vKWRS6ScTzre7s,2573
|
|
43
|
-
flock/core/tools/basic_tools.py,sha256=
|
|
43
|
+
flock/core/tools/basic_tools.py,sha256=idomjqvphTKIhuEkVS9CCJaigx_j_rv4jHqeDwp8sQY,5037
|
|
44
|
+
flock/core/tools/llm_tools.py,sha256=Bdt4Dpur5dGpxd2KFEQyxjfZazvW1HCDKY6ydMj6UgQ,21811
|
|
45
|
+
flock/core/tools/markdown_tools.py,sha256=W6fGM48yGHbifVlaOk1jOtVcybfRbRmf20VbDOZv8S4,6031
|
|
44
46
|
flock/core/tools/dev_tools/github.py,sha256=a2OTPXS7kWOVA4zrZHynQDcsmEi4Pac5MfSjQOLePzA,5308
|
|
45
47
|
flock/core/util/cli_helper.py,sha256=QSpP10WRNcjXzVFwpTQA8lSBy7707Qlv7uCit1XjUms,49808
|
|
46
48
|
flock/core/util/hydrator.py,sha256=6qNwOwCZB7r6y25BZ--0PGofrAlfMaXbDKFQeP5NLts,11196
|
|
47
49
|
flock/core/util/input_resolver.py,sha256=g9vDPdY4OH-G7qjas5ksGEHueokHGFPMoLOvC-ngeLo,5984
|
|
48
50
|
flock/evaluators/declarative/declarative_evaluator.py,sha256=f8ldgZZp94zC4CoGzBufKvbvtckCGBe9EHTOoAZfZK0,1695
|
|
51
|
+
flock/evaluators/memory/memory_evaluator.py,sha256=SmerXyNaqm8DTV0yw-WqWkn9DXIf6x-nPG1eyTV6NY8,3452
|
|
49
52
|
flock/evaluators/natural_language/natural_language_evaluator.py,sha256=6nVEeh8_uwv_h-d3FWlA0GbzDzRtdhvxCGKirHtyvOU,2012
|
|
50
53
|
flock/evaluators/zep/zep_evaluator.py,sha256=9NOELl7JAuUcx_FQrxY6b-_vN3MjwDyW7ZppPIGeCFc,1954
|
|
51
54
|
flock/modules/callback/callback_module.py,sha256=hCCw-HNYjK4aHnUQfvw26ZP1Q_jdlKb9kDh3BHzbCQA,2916
|
|
52
|
-
flock/modules/memory/memory_module.py,sha256=
|
|
53
|
-
flock/modules/memory/memory_parser.py,sha256=
|
|
55
|
+
flock/modules/memory/memory_module.py,sha256=z0MfMNpIsjL9NEXdfVofQ99z1ZaULQ1Fk3gp3SxEhd8,15246
|
|
56
|
+
flock/modules/memory/memory_parser.py,sha256=FLH7GL8XThvHiCMfX3eQH7Sz-f62fzhAUmO6_gaDI7U,4372
|
|
54
57
|
flock/modules/memory/memory_storage.py,sha256=CNcLDMmvv0x7Z3YMKr6VveS_VCa7rKPw8l2d-XgqokA,27246
|
|
55
58
|
flock/modules/output/output_module.py,sha256=_Hid4ycGEl14m7GEsVGE9wp88SYkQ3eq_x4avUQcTWI,6985
|
|
56
59
|
flock/modules/performance/metrics_module.py,sha256=JsLIVs-2PZ_A8GyYLNVBsNXdSFyrVid3YGd0fu4HXyM,16404
|
|
@@ -406,8 +409,8 @@ flock/workflow/activities.py,sha256=JDfcmn99k5UTN3QNm5hAdn_eRjWRYhWSIw1U0kMOAh4,
|
|
|
406
409
|
flock/workflow/agent_activities.py,sha256=NhBZscflEf2IMfSRa_pBM_TRP7uVEF_O0ROvWZ33eDc,963
|
|
407
410
|
flock/workflow/temporal_setup.py,sha256=VWBgmBgfTBjwM5ruS_dVpA5AVxx6EZ7oFPGw4j3m0l0,1091
|
|
408
411
|
flock/workflow/workflow.py,sha256=I9MryXW_bqYVTHx-nl2epbTqeRy27CAWHHA7ZZA0nAk,1696
|
|
409
|
-
flock_core-0.3.
|
|
410
|
-
flock_core-0.3.
|
|
411
|
-
flock_core-0.3.
|
|
412
|
-
flock_core-0.3.
|
|
413
|
-
flock_core-0.3.
|
|
412
|
+
flock_core-0.3.13.dist-info/METADATA,sha256=FRMEGXMVlB-X__T13_Vu-wiYvaOEJqD-EYuOZ0wQ_9o,20502
|
|
413
|
+
flock_core-0.3.13.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
414
|
+
flock_core-0.3.13.dist-info/entry_points.txt,sha256=rWaS5KSpkTmWySURGFZk6PhbJ87TmvcFQDi2uzjlagQ,37
|
|
415
|
+
flock_core-0.3.13.dist-info/licenses/LICENSE,sha256=iYEqWy0wjULzM9GAERaybP4LBiPeu7Z1NEliLUdJKSc,1072
|
|
416
|
+
flock_core-0.3.13.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|