camel-ai 0.2.73a4__py3-none-any.whl → 0.2.80a2__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.
- camel/__init__.py +1 -1
- camel/agents/_utils.py +38 -0
- camel/agents/chat_agent.py +2217 -519
- camel/agents/mcp_agent.py +30 -27
- camel/configs/__init__.py +15 -0
- camel/configs/aihubmix_config.py +88 -0
- camel/configs/amd_config.py +70 -0
- camel/configs/cometapi_config.py +104 -0
- camel/configs/minimax_config.py +93 -0
- camel/configs/nebius_config.py +103 -0
- camel/data_collectors/alpaca_collector.py +15 -6
- camel/datasets/base_generator.py +39 -10
- camel/environments/single_step.py +28 -3
- camel/environments/tic_tac_toe.py +1 -1
- camel/interpreters/__init__.py +2 -0
- camel/interpreters/docker/Dockerfile +3 -12
- camel/interpreters/e2b_interpreter.py +34 -1
- camel/interpreters/microsandbox_interpreter.py +395 -0
- camel/loaders/__init__.py +11 -2
- camel/loaders/chunkr_reader.py +9 -0
- camel/memories/agent_memories.py +48 -4
- camel/memories/base.py +26 -0
- camel/memories/blocks/chat_history_block.py +122 -4
- camel/memories/context_creators/score_based.py +25 -384
- camel/memories/records.py +88 -8
- camel/messages/base.py +153 -34
- camel/models/__init__.py +10 -0
- camel/models/aihubmix_model.py +83 -0
- camel/models/aiml_model.py +1 -16
- camel/models/amd_model.py +101 -0
- camel/models/anthropic_model.py +6 -19
- camel/models/aws_bedrock_model.py +2 -33
- camel/models/azure_openai_model.py +114 -89
- camel/models/base_audio_model.py +3 -1
- camel/models/base_model.py +32 -14
- camel/models/cohere_model.py +1 -16
- camel/models/cometapi_model.py +83 -0
- camel/models/crynux_model.py +1 -16
- camel/models/deepseek_model.py +1 -16
- camel/models/fish_audio_model.py +6 -0
- camel/models/gemini_model.py +36 -18
- camel/models/groq_model.py +1 -17
- camel/models/internlm_model.py +1 -16
- camel/models/litellm_model.py +1 -16
- camel/models/lmstudio_model.py +1 -17
- camel/models/minimax_model.py +83 -0
- camel/models/mistral_model.py +1 -16
- camel/models/model_factory.py +27 -1
- camel/models/modelscope_model.py +1 -16
- camel/models/moonshot_model.py +105 -24
- camel/models/nebius_model.py +83 -0
- camel/models/nemotron_model.py +0 -5
- camel/models/netmind_model.py +1 -16
- camel/models/novita_model.py +1 -16
- camel/models/nvidia_model.py +1 -16
- camel/models/ollama_model.py +4 -19
- camel/models/openai_compatible_model.py +62 -41
- camel/models/openai_model.py +62 -57
- camel/models/openrouter_model.py +1 -17
- camel/models/ppio_model.py +1 -16
- camel/models/qianfan_model.py +1 -16
- camel/models/qwen_model.py +1 -16
- camel/models/reka_model.py +1 -16
- camel/models/samba_model.py +34 -47
- camel/models/sglang_model.py +64 -31
- camel/models/siliconflow_model.py +1 -16
- camel/models/stub_model.py +0 -4
- camel/models/togetherai_model.py +1 -16
- camel/models/vllm_model.py +1 -16
- camel/models/volcano_model.py +0 -17
- camel/models/watsonx_model.py +1 -16
- camel/models/yi_model.py +1 -16
- camel/models/zhipuai_model.py +60 -16
- camel/parsers/__init__.py +18 -0
- camel/parsers/mcp_tool_call_parser.py +176 -0
- camel/retrievers/auto_retriever.py +1 -0
- camel/runtimes/daytona_runtime.py +11 -12
- camel/societies/__init__.py +2 -0
- camel/societies/workforce/__init__.py +2 -0
- camel/societies/workforce/events.py +122 -0
- camel/societies/workforce/prompts.py +146 -66
- camel/societies/workforce/role_playing_worker.py +15 -11
- camel/societies/workforce/single_agent_worker.py +302 -65
- camel/societies/workforce/structured_output_handler.py +30 -18
- camel/societies/workforce/task_channel.py +163 -27
- camel/societies/workforce/utils.py +107 -13
- camel/societies/workforce/workflow_memory_manager.py +772 -0
- camel/societies/workforce/workforce.py +1949 -579
- camel/societies/workforce/workforce_callback.py +74 -0
- camel/societies/workforce/workforce_logger.py +168 -145
- camel/societies/workforce/workforce_metrics.py +33 -0
- camel/storages/key_value_storages/json.py +15 -2
- camel/storages/key_value_storages/mem0_cloud.py +48 -47
- camel/storages/object_storages/google_cloud.py +1 -1
- camel/storages/vectordb_storages/oceanbase.py +13 -13
- camel/storages/vectordb_storages/qdrant.py +3 -3
- camel/storages/vectordb_storages/tidb.py +8 -6
- camel/tasks/task.py +4 -3
- camel/toolkits/__init__.py +20 -7
- camel/toolkits/aci_toolkit.py +45 -0
- camel/toolkits/base.py +6 -4
- camel/toolkits/code_execution.py +28 -1
- camel/toolkits/context_summarizer_toolkit.py +684 -0
- camel/toolkits/dappier_toolkit.py +5 -1
- camel/toolkits/dingtalk.py +1135 -0
- camel/toolkits/edgeone_pages_mcp_toolkit.py +11 -31
- camel/toolkits/excel_toolkit.py +1 -1
- camel/toolkits/{file_write_toolkit.py → file_toolkit.py} +430 -36
- camel/toolkits/function_tool.py +13 -3
- camel/toolkits/github_toolkit.py +104 -17
- camel/toolkits/gmail_toolkit.py +1839 -0
- camel/toolkits/google_calendar_toolkit.py +38 -4
- camel/toolkits/google_drive_mcp_toolkit.py +12 -31
- camel/toolkits/hybrid_browser_toolkit/config_loader.py +15 -0
- camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py +77 -8
- camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit_ts.py +884 -88
- camel/toolkits/hybrid_browser_toolkit/installer.py +203 -0
- camel/toolkits/hybrid_browser_toolkit/ts/package-lock.json +5 -612
- camel/toolkits/hybrid_browser_toolkit/ts/package.json +0 -1
- camel/toolkits/hybrid_browser_toolkit/ts/src/browser-session.ts +959 -89
- camel/toolkits/hybrid_browser_toolkit/ts/src/config-loader.ts +9 -2
- camel/toolkits/hybrid_browser_toolkit/ts/src/hybrid-browser-toolkit.ts +281 -213
- camel/toolkits/hybrid_browser_toolkit/ts/src/parent-child-filter.ts +226 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/snapshot-parser.ts +219 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/som-screenshot-injected.ts +543 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/types.ts +23 -3
- camel/toolkits/hybrid_browser_toolkit/ts/websocket-server.js +72 -7
- camel/toolkits/hybrid_browser_toolkit/ws_wrapper.py +582 -132
- camel/toolkits/hybrid_browser_toolkit_py/actions.py +158 -0
- camel/toolkits/hybrid_browser_toolkit_py/browser_session.py +55 -8
- camel/toolkits/hybrid_browser_toolkit_py/config_loader.py +43 -0
- camel/toolkits/hybrid_browser_toolkit_py/hybrid_browser_toolkit.py +321 -8
- camel/toolkits/hybrid_browser_toolkit_py/snapshot.py +10 -4
- camel/toolkits/hybrid_browser_toolkit_py/unified_analyzer.js +45 -4
- camel/toolkits/{openai_image_toolkit.py → image_generation_toolkit.py} +151 -53
- camel/toolkits/klavis_toolkit.py +5 -1
- camel/toolkits/markitdown_toolkit.py +27 -1
- camel/toolkits/math_toolkit.py +64 -10
- camel/toolkits/mcp_toolkit.py +366 -71
- camel/toolkits/memory_toolkit.py +5 -1
- camel/toolkits/message_integration.py +18 -13
- camel/toolkits/minimax_mcp_toolkit.py +195 -0
- camel/toolkits/note_taking_toolkit.py +19 -10
- camel/toolkits/notion_mcp_toolkit.py +16 -26
- camel/toolkits/openbb_toolkit.py +5 -1
- camel/toolkits/origene_mcp_toolkit.py +8 -49
- camel/toolkits/playwright_mcp_toolkit.py +12 -31
- camel/toolkits/resend_toolkit.py +168 -0
- camel/toolkits/search_toolkit.py +264 -91
- camel/toolkits/slack_toolkit.py +64 -10
- camel/toolkits/terminal_toolkit/__init__.py +18 -0
- camel/toolkits/terminal_toolkit/terminal_toolkit.py +957 -0
- camel/toolkits/terminal_toolkit/utils.py +532 -0
- camel/toolkits/vertex_ai_veo_toolkit.py +590 -0
- camel/toolkits/video_analysis_toolkit.py +17 -11
- camel/toolkits/wechat_official_toolkit.py +483 -0
- camel/toolkits/zapier_toolkit.py +5 -1
- camel/types/__init__.py +2 -2
- camel/types/enums.py +274 -7
- camel/types/openai_types.py +2 -2
- camel/types/unified_model_type.py +15 -0
- camel/utils/commons.py +36 -5
- camel/utils/constants.py +3 -0
- camel/utils/context_utils.py +1003 -0
- camel/utils/mcp.py +138 -4
- camel/utils/token_counting.py +43 -20
- {camel_ai-0.2.73a4.dist-info → camel_ai-0.2.80a2.dist-info}/METADATA +223 -83
- {camel_ai-0.2.73a4.dist-info → camel_ai-0.2.80a2.dist-info}/RECORD +170 -141
- camel/loaders/pandas_reader.py +0 -368
- camel/toolkits/openai_agent_toolkit.py +0 -135
- camel/toolkits/terminal_toolkit.py +0 -1550
- {camel_ai-0.2.73a4.dist-info → camel_ai-0.2.80a2.dist-info}/WHEEL +0 -0
- {camel_ai-0.2.73a4.dist-info → camel_ai-0.2.80a2.dist-info}/licenses/LICENSE +0 -0
camel/loaders/chunkr_reader.py
CHANGED
|
@@ -34,6 +34,12 @@ class ChunkrReaderConfig:
|
|
|
34
34
|
high_resolution (bool, optional): Whether to use high resolution OCR.
|
|
35
35
|
(default: :obj:`True`)
|
|
36
36
|
ocr_strategy (str, optional): The OCR strategy. Defaults to 'Auto'.
|
|
37
|
+
**kwargs: Additional keyword arguments to pass to the Chunkr
|
|
38
|
+
Configuration. This accepts all other Configuration parameters
|
|
39
|
+
such as expires_in, pipeline, segment_processing,
|
|
40
|
+
segmentation_strategy, etc.
|
|
41
|
+
See: https://github.com/lumina-ai-inc/chunkr/blob/main/core/src/
|
|
42
|
+
models/task.rs#L749
|
|
37
43
|
"""
|
|
38
44
|
|
|
39
45
|
def __init__(
|
|
@@ -41,10 +47,12 @@ class ChunkrReaderConfig:
|
|
|
41
47
|
chunk_processing: int = 512,
|
|
42
48
|
high_resolution: bool = True,
|
|
43
49
|
ocr_strategy: str = "Auto",
|
|
50
|
+
**kwargs,
|
|
44
51
|
):
|
|
45
52
|
self.chunk_processing = chunk_processing
|
|
46
53
|
self.high_resolution = high_resolution
|
|
47
54
|
self.ocr_strategy = ocr_strategy
|
|
55
|
+
self.kwargs = kwargs
|
|
48
56
|
|
|
49
57
|
|
|
50
58
|
class ChunkrReader:
|
|
@@ -190,4 +198,5 @@ class ChunkrReader:
|
|
|
190
198
|
"Auto": OcrStrategy.AUTO,
|
|
191
199
|
"All": OcrStrategy.ALL,
|
|
192
200
|
}.get(chunkr_config.ocr_strategy, OcrStrategy.ALL),
|
|
201
|
+
**chunkr_config.kwargs,
|
|
193
202
|
)
|
camel/memories/agent_memories.py
CHANGED
|
@@ -51,7 +51,9 @@ class ChatHistoryMemory(AgentMemory):
|
|
|
51
51
|
raise ValueError("`window_size` must be non-negative.")
|
|
52
52
|
self._context_creator = context_creator
|
|
53
53
|
self._window_size = window_size
|
|
54
|
-
self._chat_history_block = ChatHistoryBlock(
|
|
54
|
+
self._chat_history_block = ChatHistoryBlock(
|
|
55
|
+
storage=storage,
|
|
56
|
+
)
|
|
55
57
|
self._agent_id = agent_id
|
|
56
58
|
|
|
57
59
|
@property
|
|
@@ -116,17 +118,35 @@ class ChatHistoryMemory(AgentMemory):
|
|
|
116
118
|
indices_to_remove.append(i)
|
|
117
119
|
# Mark ASSISTANT messages with tool_calls for removal
|
|
118
120
|
elif role == OpenAIBackendRole.ASSISTANT.value:
|
|
119
|
-
|
|
120
|
-
|
|
121
|
+
message_dict = record.get('message', {})
|
|
122
|
+
# Check for tool_calls in message
|
|
123
|
+
has_tool_calls = 'tool_calls' in message_dict
|
|
124
|
+
is_func_calling = (
|
|
125
|
+
message_dict.get('__class__') == 'FunctionCallingMessage'
|
|
126
|
+
and 'args' in message_dict
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
if has_tool_calls or is_func_calling:
|
|
121
130
|
indices_to_remove.append(i)
|
|
122
131
|
|
|
123
132
|
# Remove records in-place
|
|
124
133
|
for i in reversed(indices_to_remove):
|
|
125
134
|
del record_dicts[i]
|
|
126
135
|
|
|
127
|
-
#
|
|
136
|
+
# Clear storage and save the modified records back
|
|
137
|
+
self._chat_history_block.storage.clear()
|
|
128
138
|
self._chat_history_block.storage.save(record_dicts)
|
|
129
139
|
|
|
140
|
+
def pop_records(self, count: int) -> List[MemoryRecord]:
|
|
141
|
+
r"""Removes the most recent records from chat history memory."""
|
|
142
|
+
return self._chat_history_block.pop_records(count)
|
|
143
|
+
|
|
144
|
+
def remove_records_by_indices(
|
|
145
|
+
self, indices: List[int]
|
|
146
|
+
) -> List[MemoryRecord]:
|
|
147
|
+
r"""Removes records at specified indices from chat history memory."""
|
|
148
|
+
return self._chat_history_block.remove_records_by_indices(indices)
|
|
149
|
+
|
|
130
150
|
|
|
131
151
|
class VectorDBMemory(AgentMemory):
|
|
132
152
|
r"""An agent memory wrapper of :obj:`VectorDBBlock`. This memory queries
|
|
@@ -191,6 +211,20 @@ class VectorDBMemory(AgentMemory):
|
|
|
191
211
|
r"""Removes all records from the vector database memory."""
|
|
192
212
|
self._vectordb_block.clear()
|
|
193
213
|
|
|
214
|
+
def pop_records(self, count: int) -> List[MemoryRecord]:
|
|
215
|
+
r"""Rolling back is unsupported for vector database memory."""
|
|
216
|
+
raise NotImplementedError(
|
|
217
|
+
"VectorDBMemory does not support removing historical records."
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
def remove_records_by_indices(
|
|
221
|
+
self, indices: List[int]
|
|
222
|
+
) -> List[MemoryRecord]:
|
|
223
|
+
r"""Removing by indices is unsupported for vector database memory."""
|
|
224
|
+
raise NotImplementedError(
|
|
225
|
+
"VectorDBMemory does not support removing records by indices."
|
|
226
|
+
)
|
|
227
|
+
|
|
194
228
|
|
|
195
229
|
class LongtermAgentMemory(AgentMemory):
|
|
196
230
|
r"""An implementation of the :obj:`AgentMemory` abstract base class for
|
|
@@ -275,3 +309,13 @@ class LongtermAgentMemory(AgentMemory):
|
|
|
275
309
|
r"""Removes all records from the memory."""
|
|
276
310
|
self.chat_history_block.clear()
|
|
277
311
|
self.vector_db_block.clear()
|
|
312
|
+
|
|
313
|
+
def pop_records(self, count: int) -> List[MemoryRecord]:
|
|
314
|
+
r"""Removes recent chat history records while leaving vector memory."""
|
|
315
|
+
return self.chat_history_block.pop_records(count)
|
|
316
|
+
|
|
317
|
+
def remove_records_by_indices(
|
|
318
|
+
self, indices: List[int]
|
|
319
|
+
) -> List[MemoryRecord]:
|
|
320
|
+
r"""Removes records at specified indices from chat history."""
|
|
321
|
+
return self.chat_history_block.remove_records_by_indices(indices)
|
camel/memories/base.py
CHANGED
|
@@ -45,6 +45,32 @@ class MemoryBlock(ABC):
|
|
|
45
45
|
"""
|
|
46
46
|
self.write_records([record])
|
|
47
47
|
|
|
48
|
+
def pop_records(self, count: int) -> List[MemoryRecord]:
|
|
49
|
+
r"""Removes records from the memory and returns the removed records.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
count (int): Number of records to remove.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
List[MemoryRecord]: The records that were removed from the memory
|
|
56
|
+
in their original order.
|
|
57
|
+
"""
|
|
58
|
+
raise NotImplementedError
|
|
59
|
+
|
|
60
|
+
def remove_records_by_indices(
|
|
61
|
+
self, indices: List[int]
|
|
62
|
+
) -> List[MemoryRecord]:
|
|
63
|
+
r"""Removes records at specified indices from the memory.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
indices (List[int]): List of indices to remove. Indices should be
|
|
67
|
+
valid positions in the current record list.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
List[MemoryRecord]: The removed records in their original order.
|
|
71
|
+
"""
|
|
72
|
+
raise NotImplementedError
|
|
73
|
+
|
|
48
74
|
@abstractmethod
|
|
49
75
|
def clear(self) -> None:
|
|
50
76
|
r"""Clears all messages from the memory."""
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
# See the License for the specific language governing permissions and
|
|
12
12
|
# limitations under the License.
|
|
13
13
|
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
|
-
import warnings
|
|
15
14
|
from typing import List, Optional
|
|
16
15
|
|
|
17
16
|
from camel.memories.base import MemoryBlock
|
|
@@ -39,7 +38,7 @@ class ChatHistoryBlock(MemoryBlock):
|
|
|
39
38
|
last message is 1.0, and with each step taken backward, the score
|
|
40
39
|
of the message is multiplied by the `keep_rate`. Higher `keep_rate`
|
|
41
40
|
leads to high possibility to keep history messages during context
|
|
42
|
-
creation.
|
|
41
|
+
creation. (default: :obj:`0.9`)
|
|
43
42
|
"""
|
|
44
43
|
|
|
45
44
|
def __init__(
|
|
@@ -70,7 +69,8 @@ class ChatHistoryBlock(MemoryBlock):
|
|
|
70
69
|
"""
|
|
71
70
|
record_dicts = self.storage.load()
|
|
72
71
|
if len(record_dicts) == 0:
|
|
73
|
-
|
|
72
|
+
# Empty memory is a valid state (e.g., during initialization).
|
|
73
|
+
# Users can check if memory is empty by checking the returned list.
|
|
74
74
|
return list()
|
|
75
75
|
|
|
76
76
|
if window_size is not None and window_size >= 0:
|
|
@@ -81,7 +81,10 @@ class ChatHistoryBlock(MemoryBlock):
|
|
|
81
81
|
if (
|
|
82
82
|
record_dicts
|
|
83
83
|
and record_dicts[0]['role_at_backend']
|
|
84
|
-
in {
|
|
84
|
+
in {
|
|
85
|
+
OpenAIBackendRole.SYSTEM.value,
|
|
86
|
+
OpenAIBackendRole.DEVELOPER.value,
|
|
87
|
+
}
|
|
85
88
|
)
|
|
86
89
|
else 0
|
|
87
90
|
)
|
|
@@ -164,3 +167,118 @@ class ChatHistoryBlock(MemoryBlock):
|
|
|
164
167
|
def clear(self) -> None:
|
|
165
168
|
r"""Clears all chat messages from the memory."""
|
|
166
169
|
self.storage.clear()
|
|
170
|
+
|
|
171
|
+
def pop_records(self, count: int) -> List[MemoryRecord]:
|
|
172
|
+
r"""Removes the most recent records from the memory.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
count (int): Number of records to remove from the end of the
|
|
176
|
+
conversation history. A value of 0 results in no changes.
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
List[MemoryRecord]: The removed records in chronological order.
|
|
180
|
+
"""
|
|
181
|
+
if not isinstance(count, int):
|
|
182
|
+
raise TypeError("`count` must be an integer.")
|
|
183
|
+
if count < 0:
|
|
184
|
+
raise ValueError("`count` must be non-negative.")
|
|
185
|
+
if count == 0:
|
|
186
|
+
return []
|
|
187
|
+
|
|
188
|
+
record_dicts = self.storage.load()
|
|
189
|
+
if not record_dicts:
|
|
190
|
+
return []
|
|
191
|
+
|
|
192
|
+
# Preserve initial system/developer instruction if present.
|
|
193
|
+
protected_prefix = (
|
|
194
|
+
1
|
|
195
|
+
if (
|
|
196
|
+
record_dicts
|
|
197
|
+
and record_dicts[0]['role_at_backend']
|
|
198
|
+
in {
|
|
199
|
+
OpenAIBackendRole.SYSTEM.value,
|
|
200
|
+
OpenAIBackendRole.DEVELOPER.value,
|
|
201
|
+
}
|
|
202
|
+
)
|
|
203
|
+
else 0
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
removable_count = max(len(record_dicts) - protected_prefix, 0)
|
|
207
|
+
if removable_count == 0:
|
|
208
|
+
return []
|
|
209
|
+
|
|
210
|
+
pop_count = min(count, removable_count)
|
|
211
|
+
split_index = len(record_dicts) - pop_count
|
|
212
|
+
|
|
213
|
+
popped_dicts = record_dicts[split_index:]
|
|
214
|
+
remaining_dicts = record_dicts[:split_index]
|
|
215
|
+
|
|
216
|
+
self.storage.clear()
|
|
217
|
+
if remaining_dicts:
|
|
218
|
+
self.storage.save(remaining_dicts)
|
|
219
|
+
|
|
220
|
+
return [MemoryRecord.from_dict(record) for record in popped_dicts]
|
|
221
|
+
|
|
222
|
+
def remove_records_by_indices(
|
|
223
|
+
self, indices: List[int]
|
|
224
|
+
) -> List[MemoryRecord]:
|
|
225
|
+
r"""Removes records at specified indices from the memory.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
indices (List[int]): List of indices to remove. Indices are
|
|
229
|
+
positions in the current record list (0-based).
|
|
230
|
+
System/developer messages at index 0 are protected and will
|
|
231
|
+
not be removed.
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
List[MemoryRecord]: The removed records in their original order.
|
|
235
|
+
"""
|
|
236
|
+
if not indices:
|
|
237
|
+
return []
|
|
238
|
+
|
|
239
|
+
record_dicts = self.storage.load()
|
|
240
|
+
if not record_dicts:
|
|
241
|
+
return []
|
|
242
|
+
|
|
243
|
+
# Preserve initial system/developer instruction if present.
|
|
244
|
+
protected_prefix = (
|
|
245
|
+
1
|
|
246
|
+
if (
|
|
247
|
+
record_dicts
|
|
248
|
+
and record_dicts[0]['role_at_backend']
|
|
249
|
+
in {
|
|
250
|
+
OpenAIBackendRole.SYSTEM.value,
|
|
251
|
+
OpenAIBackendRole.DEVELOPER.value,
|
|
252
|
+
}
|
|
253
|
+
)
|
|
254
|
+
else 0
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
# Filter out protected indices and invalid ones
|
|
258
|
+
valid_indices = sorted(
|
|
259
|
+
{
|
|
260
|
+
idx
|
|
261
|
+
for idx in indices
|
|
262
|
+
if idx >= protected_prefix and idx < len(record_dicts)
|
|
263
|
+
}
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
if not valid_indices:
|
|
267
|
+
return []
|
|
268
|
+
|
|
269
|
+
# Extract records to remove (in original order)
|
|
270
|
+
removed_records = [record_dicts[idx] for idx in valid_indices]
|
|
271
|
+
|
|
272
|
+
# Build remaining records by excluding removed indices
|
|
273
|
+
remaining_dicts = [
|
|
274
|
+
record
|
|
275
|
+
for idx, record in enumerate(record_dicts)
|
|
276
|
+
if idx not in valid_indices
|
|
277
|
+
]
|
|
278
|
+
|
|
279
|
+
# Save back to storage
|
|
280
|
+
self.storage.clear()
|
|
281
|
+
if remaining_dicts:
|
|
282
|
+
self.storage.save(remaining_dicts)
|
|
283
|
+
|
|
284
|
+
return [MemoryRecord.from_dict(record) for record in removed_records]
|