neuro-simulator 0.3.3__py3-none-any.whl → 0.4.0__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.
Files changed (36) hide show
  1. neuro_simulator/agent/core.py +73 -138
  2. neuro_simulator/agent/llm.py +1 -1
  3. neuro_simulator/agent/memory/manager.py +24 -103
  4. neuro_simulator/agent/tools/add_temp_memory.py +3 -3
  5. neuro_simulator/agent/tools/add_to_core_memory_block.py +2 -2
  6. neuro_simulator/agent/tools/create_core_memory_block.py +2 -2
  7. neuro_simulator/agent/tools/delete_core_memory_block.py +2 -2
  8. neuro_simulator/agent/tools/get_core_memory_block.py +2 -2
  9. neuro_simulator/agent/tools/get_core_memory_blocks.py +2 -2
  10. neuro_simulator/agent/tools/manager.py +86 -63
  11. neuro_simulator/agent/tools/remove_from_core_memory_block.py +2 -2
  12. neuro_simulator/agent/tools/speak.py +2 -2
  13. neuro_simulator/agent/tools/update_core_memory_block.py +2 -2
  14. neuro_simulator/api/system.py +5 -2
  15. neuro_simulator/cli.py +83 -53
  16. neuro_simulator/core/agent_factory.py +0 -1
  17. neuro_simulator/core/application.py +46 -32
  18. neuro_simulator/core/config.py +66 -63
  19. neuro_simulator/core/path_manager.py +69 -0
  20. neuro_simulator/services/audience.py +0 -2
  21. neuro_simulator/services/audio.py +0 -1
  22. neuro_simulator/services/builtin.py +10 -25
  23. neuro_simulator/services/letta.py +19 -1
  24. neuro_simulator/services/stream.py +24 -21
  25. neuro_simulator/utils/logging.py +9 -0
  26. neuro_simulator/utils/queue.py +27 -4
  27. neuro_simulator/utils/websocket.py +1 -3
  28. {neuro_simulator-0.3.3.dist-info → neuro_simulator-0.4.0.dist-info}/METADATA +1 -1
  29. neuro_simulator-0.4.0.dist-info/RECORD +46 -0
  30. neuro_simulator/agent/base.py +0 -43
  31. neuro_simulator/agent/factory.py +0 -30
  32. neuro_simulator/api/stream.py +0 -1
  33. neuro_simulator-0.3.3.dist-info/RECORD +0 -48
  34. {neuro_simulator-0.3.3.dist-info → neuro_simulator-0.4.0.dist-info}/WHEEL +0 -0
  35. {neuro_simulator-0.3.3.dist-info → neuro_simulator-0.4.0.dist-info}/entry_points.txt +0 -0
  36. {neuro_simulator-0.3.3.dist-info → neuro_simulator-0.4.0.dist-info}/top_level.txt +0 -0
@@ -9,34 +9,16 @@ import asyncio
9
9
  import json
10
10
  import logging
11
11
  import re
12
+ from datetime import datetime
12
13
  from pathlib import Path
13
14
  from typing import Any, Dict, List
14
15
 
15
- from ..utils.logging import QueueLogHandler, agent_log_queue
16
- from ..utils.websocket import connection_manager
16
+ from ..core.path_manager import path_manager
17
17
  from .llm import LLMClient
18
18
  from .memory.manager import MemoryManager
19
19
  from .tools.manager import ToolManager
20
20
 
21
-
22
- # Create a logger for the agent
23
- agent_logger = logging.getLogger("neuro_agent")
24
- agent_logger.setLevel(logging.DEBUG)
25
-
26
- # Configure agent logging to use the shared queue
27
- def configure_agent_logging():
28
- """Configure agent logging to use the shared agent_log_queue."""
29
- if agent_logger.hasHandlers():
30
- agent_logger.handlers.clear()
31
-
32
- agent_queue_handler = QueueLogHandler(agent_log_queue)
33
- formatter = logging.Formatter('%(asctime)s - [%(name)-32s] - %(levelname)-8s - %(message)s', datefmt='%H:%M:%S')
34
- agent_queue_handler.setFormatter(formatter)
35
- agent_logger.addHandler(agent_queue_handler)
36
- agent_logger.propagate = False
37
- agent_logger.info("Agent logging configured to use agent_log_queue.")
38
-
39
- configure_agent_logging()
21
+ logger = logging.getLogger("neuro_agent")
40
22
 
41
23
  class Agent:
42
24
  """
@@ -45,40 +27,65 @@ class Agent:
45
27
  - The "Memory" part (Thinker) handles background memory consolidation.
46
28
  """
47
29
 
48
- def __init__(self, working_dir: str = None):
49
- self.memory_manager = MemoryManager(working_dir)
30
+ def __init__(self):
31
+ if not path_manager:
32
+ raise RuntimeError("PathManager must be initialized before the Agent.")
33
+
34
+ self.memory_manager = MemoryManager()
50
35
  self.tool_manager = ToolManager(self.memory_manager)
51
36
 
52
- # Dual LLM clients
53
37
  self.neuro_llm = LLMClient()
54
38
  self.memory_llm = LLMClient()
55
39
 
56
40
  self._initialized = False
57
41
  self.turn_counter = 0
58
- self.reflection_threshold = 3 # Trigger reflection every 3 turns
59
-
60
- agent_logger.info("Agent instance created with dual-LLM architecture.")
61
- agent_logger.debug(f"Agent working directory: {working_dir}")
42
+ self.reflection_threshold = 3
62
43
 
44
+ logger.info("Agent instance created with dual-LLM architecture.")
45
+
63
46
  async def initialize(self):
64
47
  """Initialize the agent, loading any persistent memory."""
65
48
  if not self._initialized:
66
- agent_logger.info("Initializing agent memory manager...")
49
+ logger.info("Initializing agent memory manager...")
67
50
  await self.memory_manager.initialize()
68
51
  self._initialized = True
69
- agent_logger.info("Agent initialized successfully.")
52
+ logger.info("Agent initialized successfully.")
70
53
 
71
54
  async def reset_all_memory(self):
72
- """Reset all agent memory types."""
55
+ """Reset all agent memory types and clear history logs."""
73
56
  await self.memory_manager.reset_temp_memory()
74
- await self.memory_manager.reset_chat_history()
75
- agent_logger.info("All agent memory has been reset.")
57
+ # Clear history files by overwriting them
58
+ open(path_manager.neuro_history_path, 'w').close()
59
+ open(path_manager.memory_agent_history_path, 'w').close()
60
+ logger.info("All agent memory and history logs have been reset.")
61
+
62
+ async def get_neuro_history(self, limit: int = 20) -> List[Dict[str, Any]]:
63
+ """Reads the last N lines from the Neuro agent's history log."""
64
+ return await self._read_history_log(path_manager.neuro_history_path, limit)
65
+
66
+ async def _append_to_history_log(self, file_path: Path, data: Dict[str, Any]):
67
+ """Appends a new entry to a JSON Lines history file."""
68
+ data['timestamp'] = datetime.now().isoformat()
69
+ with open(file_path, 'a', encoding='utf-8') as f:
70
+ f.write(json.dumps(data, ensure_ascii=False) + '\n')
71
+
72
+ async def _read_history_log(self, file_path: Path, limit: int) -> List[Dict[str, Any]]:
73
+ """Reads the last N lines from a JSON Lines history file."""
74
+ if not file_path.exists():
75
+ return []
76
+ try:
77
+ with open(file_path, 'r', encoding='utf-8') as f:
78
+ lines = f.readlines()
79
+ # Get the last N lines and parse them
80
+ return [json.loads(line) for line in lines[-limit:]]
81
+ except (json.JSONDecodeError, IndexError) as e:
82
+ logger.error(f"Could not read or parse history from {file_path}: {e}")
83
+ return []
76
84
 
77
85
  def _format_tool_schemas_for_prompt(self, schemas: List[Dict[str, Any]]) -> str:
78
86
  """Formats a list of tool schemas into a string for the LLM prompt."""
79
87
  if not schemas:
80
88
  return "No tools available."
81
-
82
89
  lines = ["Available tools:"]
83
90
  for i, schema in enumerate(schemas):
84
91
  params_str_parts = []
@@ -89,47 +96,31 @@ class Agent:
89
96
  params_str_parts.append(f"{p_name}: {p_type} ({p_req})")
90
97
  params_str = ", ".join(params_str_parts)
91
98
  lines.append(f"{i+1}. {schema.get('name')}({params_str}) - {schema.get('description')}")
92
-
93
99
  return "\n".join(lines)
94
100
 
95
101
  async def _build_neuro_prompt(self, messages: List[Dict[str, str]]) -> str:
96
102
  """Builds the prompt for the Neuro (Actor) LLM."""
97
- template_path = Path(self.memory_manager.memory_dir).parent / "neuro_prompt.txt"
98
- with open(template_path, 'r', encoding='utf-8') as f:
99
- prompt_template = f.read()
103
+ prompt_template = "" # Define a default empty prompt
104
+ if path_manager.neuro_prompt_path.exists():
105
+ with open(path_manager.neuro_prompt_path, 'r', encoding='utf-8') as f:
106
+ prompt_template = f.read()
107
+ else:
108
+ logger.warning(f"Neuro prompt template not found at {path_manager.neuro_prompt_path}")
100
109
 
101
- # Gather context for Neuro Agent
102
110
  tool_schemas = self.tool_manager.get_tool_schemas_for_agent('neuro_agent')
103
111
  tool_descriptions = self._format_tool_schemas_for_prompt(tool_schemas)
104
112
 
105
- # Format Init Memory
106
- init_memory_items = self.memory_manager.init_memory or {}
107
- init_memory_text = "\n".join(f"{key}: {value}" for key, value in init_memory_items.items())
108
-
109
- # Format Core Memory from blocks
113
+ init_memory_text = "\n".join(f"{key}: {value}" for key, value in self.memory_manager.init_memory.items())
114
+
110
115
  core_memory_blocks = await self.memory_manager.get_core_memory_blocks()
111
- core_memory_parts = []
112
- if core_memory_blocks:
113
- for block_id, block in core_memory_blocks.items():
114
- core_memory_parts.append(f"\nBlock: {block.get('title', '')} ({block_id})")
115
- core_memory_parts.append(f"Description: {block.get('description', '')}")
116
- content_items = block.get("content", [])
117
- if content_items:
118
- core_memory_parts.append("Content:")
119
- for item in content_items:
120
- core_memory_parts.append(f" - {item}")
116
+ core_memory_parts = [f"\nBlock: {b.get('title', '')} ({b_id})\nDescription: {b.get('description', '')}\nContent:\n" + "\n".join([f" - {item}" for item in b.get("content", [])]) for b_id, b in core_memory_blocks.items()]
121
117
  core_memory_text = "\n".join(core_memory_parts) if core_memory_parts else "Not set."
122
118
 
123
- # Format Temp Memory
124
- temp_memory_items = self.memory_manager.temp_memory
125
- temp_memory_text = "\n".join(
126
- [f"[{item.get('role', 'system')}] {item.get('content', '')}" for item in temp_memory_items]
127
- ) if temp_memory_items else "Empty."
119
+ temp_memory_text = "\n".join([f"[{item.get('role', 'system')}] {item.get('content', '')}" for item in self.memory_manager.temp_memory]) if self.memory_manager.temp_memory else "Empty."
128
120
 
129
- recent_history = await self.memory_manager.get_recent_chat(entries=10)
130
-
121
+ recent_history = await self._read_history_log(path_manager.neuro_history_path, limit=10)
122
+ recent_history_text = "\n".join([f"{msg.get('role', 'unknown')}: {msg.get('content', '')}" for msg in recent_history])
131
123
  user_messages_text = "\n".join([f"{msg['username']}: {msg['text']}" for msg in messages])
132
- recent_history_text = "\n".join([f"{msg['role']}: {msg['content']}" for msg in recent_history])
133
124
 
134
125
  return prompt_template.format(
135
126
  tool_descriptions=tool_descriptions,
@@ -142,15 +133,16 @@ class Agent:
142
133
 
143
134
  async def _build_memory_prompt(self, conversation_history: List[Dict[str, str]]) -> str:
144
135
  """Builds the prompt for the Memory (Thinker) LLM."""
145
- template_path = Path(self.memory_manager.memory_dir).parent / "memory_prompt.txt"
146
- with open(template_path, 'r', encoding='utf-8') as f:
147
- prompt_template = f.read()
148
-
149
- # Gather context for Memory Agent
136
+ prompt_template = "" # Define a default empty prompt
137
+ if path_manager.memory_agent_prompt_path.exists():
138
+ with open(path_manager.memory_agent_prompt_path, 'r', encoding='utf-8') as f:
139
+ prompt_template = f.read()
140
+ else:
141
+ logger.warning(f"Memory prompt template not found at {path_manager.memory_agent_prompt_path}")
142
+
150
143
  tool_schemas = self.tool_manager.get_tool_schemas_for_agent('memory_agent')
151
144
  tool_descriptions = self._format_tool_schemas_for_prompt(tool_schemas)
152
-
153
- history_text = "\n".join([f"{msg['role']}: {msg['content']}" for msg in conversation_history])
145
+ history_text = "\n".join([f"{msg.get('role', 'unknown')}: {msg.get('content', '')}" for msg in conversation_history])
154
146
 
155
147
  return prompt_template.format(
156
148
  tool_descriptions=tool_descriptions,
@@ -158,30 +150,18 @@ class Agent:
158
150
  )
159
151
 
160
152
  def _parse_tool_calls(self, response_text: str) -> List[Dict[str, Any]]:
161
- """Parses LLM response for JSON tool calls."""
162
153
  try:
163
- # The LLM is prompted to return a JSON array of tool calls.
164
- # Find the JSON block, which might be wrapped in markdown.
165
- match = re.search(r'''```json\s*([\s\S]*?)\s*```|([[\][\s\S]*]])''', response_text)
154
+ match = re.search(r'''```json\s*([\s\S]*?)\s*```|(\[[\s\S]*\])''', response_text)
166
155
  if not match:
167
- agent_logger.warning(f"No valid JSON tool call block found in response: {response_text}")
156
+ logger.warning(f"No valid JSON tool call block found in response: {response_text}")
168
157
  return []
169
-
170
158
  json_str = match.group(1) or match.group(2)
171
- tool_calls = json.loads(json_str)
172
-
173
- if isinstance(tool_calls, list):
174
- return tool_calls
175
- return []
176
- except json.JSONDecodeError as e:
177
- agent_logger.error(f"Failed to decode JSON from LLM response: {e}\nResponse text: {response_text}")
178
- return []
159
+ return json.loads(json_str)
179
160
  except Exception as e:
180
- agent_logger.error(f"An unexpected error occurred while parsing tool calls: {e}")
161
+ logger.error(f"Failed to parse tool calls from LLM response: {e}")
181
162
  return []
182
163
 
183
164
  async def _execute_tool_calls(self, tool_calls: List[Dict[str, Any]]) -> Dict[str, Any]:
184
- """Executes a list of parsed tool calls."""
185
165
  execution_results = []
186
166
  final_response = ""
187
167
  for tool_call in tool_calls:
@@ -189,78 +169,33 @@ class Agent:
189
169
  params = tool_call.get("params", {})
190
170
  if not tool_name:
191
171
  continue
192
-
193
- agent_logger.info(f"Executing tool: {tool_name} with params: {params}")
172
+ logger.info(f"Executing tool: {tool_name} with params: {params}")
194
173
  try:
195
174
  result = await self.tool_manager.execute_tool(tool_name, **params)
196
175
  execution_results.append({"name": tool_name, "params": params, "result": result})
197
176
  if tool_name == "speak" and result.get("status") == "success":
198
177
  final_response = result.get("spoken_text", "")
199
178
  except Exception as e:
200
- agent_logger.error(f"Error executing tool {tool_name}: {e}")
179
+ logger.error(f"Error executing tool {tool_name}: {e}")
201
180
  execution_results.append({"name": tool_name, "params": params, "error": str(e)})
202
-
203
181
  return {"tool_executions": execution_results, "final_response": final_response}
204
182
 
205
183
  async def process_and_respond(self, messages: List[Dict[str, str]]) -> Dict[str, Any]:
206
- """
207
- The main entry point for the "Neuro" (Actor) flow.
208
- Handles real-time interaction and triggers background reflection.
209
- """
210
184
  await self.initialize()
211
- agent_logger.info(f"Processing {len(messages)} messages in Actor flow.")
185
+ logger.info(f"Processing {len(messages)} messages in Actor flow.")
212
186
 
213
- # Add user messages to context
214
187
  for msg in messages:
215
- await self.memory_manager.add_chat_entry("user", f"{msg['username']}: {msg['text']}")
188
+ await self._append_to_history_log(path_manager.neuro_history_path, {'role': 'user', 'content': f"{msg['username']}: {msg['text']}"})
216
189
 
217
- # Build prompt and get response from Neuro LLM
218
190
  prompt = await self._build_neuro_prompt(messages)
219
191
  response_text = await self.neuro_llm.generate(prompt)
220
- agent_logger.debug(f"Neuro LLM raw response: {response_text[:150] if response_text else 'None'}...")
221
-
222
- # Parse and execute tools
192
+
223
193
  tool_calls = self._parse_tool_calls(response_text)
224
194
  processing_result = await self._execute_tool_calls(tool_calls)
225
195
 
226
- # Add agent's response to context
227
- if processing_result["final_response"]:
228
- await self.memory_manager.add_chat_entry("assistant", processing_result["final_response"])
229
-
230
- # Update dashboard/UI
231
- final_context = await self.memory_manager.get_recent_chat()
232
- # Broadcast to stream clients
233
- await connection_manager.broadcast({"type": "agent_context", "action": "update", "messages": final_context})
234
- # Broadcast to admin clients (Dashboard)
235
- await connection_manager.broadcast_to_admins({"type": "agent_context", "action": "update", "messages": final_context})
196
+ if final_response := processing_result.get("final_response", ""):
197
+ await self._append_to_history_log(path_manager.neuro_history_path, {'role': 'assistant', 'content': final_response})
236
198
 
237
- # Handle reflection trigger
238
- self.turn_counter += 1
239
- if self.turn_counter >= self.reflection_threshold:
240
- agent_logger.info(f"Reflection threshold reached ({self.turn_counter}/{self.reflection_threshold}). Scheduling background reflection.")
241
- history_for_reflection = await self.memory_manager.get_recent_chat(entries=self.reflection_threshold * 2) # Get a bit more context
242
- asyncio.create_task(self.reflect_on_context(history_for_reflection))
243
- self.turn_counter = 0
244
-
245
- agent_logger.info("Actor flow completed.")
246
199
  return processing_result
247
200
 
248
- async def reflect_on_context(self, conversation_history: List[Dict[str, str]]):
249
- """
250
- The main entry point for the "Memory" (Thinker) flow.
251
- Runs in the background to consolidate memories.
252
- """
253
- agent_logger.info("Thinker flow started: Reflecting on recent context.")
254
-
255
- prompt = await self._build_memory_prompt(conversation_history)
256
- response_text = await self.memory_llm.generate(prompt)
257
- agent_logger.debug(f"Memory LLM raw response: {response_text[:150] if response_text else 'None'}...")
258
-
259
- tool_calls = self._parse_tool_calls(response_text)
260
- if not tool_calls:
261
- agent_logger.info("Thinker flow: No memory operations were suggested by the LLM.")
262
- return
263
-
264
- agent_logger.info(f"Thinker flow: Executing {len(tool_calls)} memory operations.")
265
- await self._execute_tool_calls(tool_calls)
266
- agent_logger.info("Thinker flow completed, memory has been updated.")
201
+
@@ -6,7 +6,7 @@ LLM client for the Neuro Simulator's built-in agent.
6
6
  import asyncio
7
7
  import logging
8
8
  from pathlib import Path
9
- from typing import Optional
9
+ from typing import Any, Dict
10
10
 
11
11
  from google import genai
12
12
  from google.genai import types
@@ -1,48 +1,43 @@
1
1
  # neuro_simulator/agent/memory/manager.py
2
2
  """
3
- Advanced memory management for the Neuro Simulator Agent.
3
+ Manages the agent's shared memory state (init, core, temp).
4
4
  """
5
5
 
6
- import asyncio
7
6
  import json
8
7
  import logging
9
- import os
10
8
  import random
11
9
  import string
12
- from datetime import datetime
13
10
  from typing import Any, Dict, List, Optional
11
+ from datetime import datetime
12
+
13
+ from ...core.path_manager import path_manager
14
14
 
15
- # Use the existing agent logger for consistent logging
16
- logger = logging.getLogger("neuro_agent")
15
+ logger = logging.getLogger(__name__.replace("neuro_simulator", "agent", 1))
17
16
 
18
17
  def generate_id(length=6) -> str:
19
18
  """Generate a random ID string."""
20
19
  return ''.join(random.choices(string.ascii_letters + string.digits, k=length))
21
20
 
22
21
  class MemoryManager:
23
- """Manages different types of memory for the agent."""
22
+ """Manages the three types of shared memory for the agent."""
24
23
 
25
- def __init__(self, working_dir: str = None):
26
- if working_dir is None:
27
- working_dir = os.getcwd()
28
-
29
- self.memory_dir = os.path.join(working_dir, "agent", "memory")
30
- os.makedirs(self.memory_dir, exist_ok=True)
31
-
32
- self.init_memory_file = os.path.join(self.memory_dir, "init_memory.json")
33
- self.core_memory_file = os.path.join(self.memory_dir, "core_memory.json")
34
- self.chat_history_file = os.path.join(self.memory_dir, "chat_history.json")
35
- self.temp_memory_file = os.path.join(self.memory_dir, "temp_memory.json")
24
+ def __init__(self):
25
+ """Initializes the MemoryManager using paths from the global path_manager."""
26
+ if not path_manager:
27
+ raise RuntimeError("PathManager not initialized before MemoryManager.")
28
+
29
+ self.init_memory_file = path_manager.init_memory_path
30
+ self.core_memory_file = path_manager.core_memory_path
31
+ self.temp_memory_file = path_manager.temp_memory_path
36
32
 
37
33
  self.init_memory: Dict[str, Any] = {}
38
34
  self.core_memory: Dict[str, Any] = {}
39
- self.chat_history: List[Dict[str, Any]] = []
40
35
  self.temp_memory: List[Dict[str, Any]] = []
41
36
 
42
37
  async def initialize(self):
43
- """Load all memory types from files."""
44
- # Load init memory
45
- if os.path.exists(self.init_memory_file):
38
+ """Load all memory types from files, creating defaults if they don't exist."""
39
+ # Load or create init memory
40
+ if self.init_memory_file.exists():
46
41
  with open(self.init_memory_file, 'r', encoding='utf-8') as f:
47
42
  self.init_memory = json.load(f)
48
43
  else:
@@ -53,29 +48,23 @@ class MemoryManager:
53
48
  }
54
49
  await self._save_init_memory()
55
50
 
56
- # Load core memory
57
- if os.path.exists(self.core_memory_file):
51
+ # Load or create core memory
52
+ if self.core_memory_file.exists():
58
53
  with open(self.core_memory_file, 'r', encoding='utf-8') as f:
59
54
  self.core_memory = json.load(f)
60
55
  else:
61
56
  self.core_memory = {"blocks": {}}
62
57
  await self._save_core_memory()
63
58
 
64
- # Load chat history
65
- if os.path.exists(self.chat_history_file):
66
- with open(self.chat_history_file, 'r', encoding='utf-8') as f:
67
- self.chat_history = json.load(f)
68
- else:
69
- self.chat_history = []
70
-
71
- # Load temp memory
72
- if os.path.exists(self.temp_memory_file):
59
+ # Load or create temp memory
60
+ if self.temp_memory_file.exists():
73
61
  with open(self.temp_memory_file, 'r', encoding='utf-8') as f:
74
62
  self.temp_memory = json.load(f)
75
63
  else:
76
64
  self.temp_memory = []
65
+ await self._save_temp_memory()
77
66
 
78
- logger.info("Agent memory manager initialized.")
67
+ logger.info("MemoryManager initialized and memory files loaded/created.")
79
68
 
80
69
  async def _save_init_memory(self):
81
70
  with open(self.init_memory_file, 'w', encoding='utf-8') as f:
@@ -89,84 +78,16 @@ class MemoryManager:
89
78
  with open(self.core_memory_file, 'w', encoding='utf-8') as f:
90
79
  json.dump(self.core_memory, f, ensure_ascii=False, indent=2)
91
80
 
92
- async def _save_chat_history(self):
93
- with open(self.chat_history_file, 'w', encoding='utf-8') as f:
94
- json.dump(self.chat_history, f, ensure_ascii=False, indent=2)
95
-
96
81
  async def _save_temp_memory(self):
97
82
  with open(self.temp_memory_file, 'w', encoding='utf-8') as f:
98
83
  json.dump(self.temp_memory, f, ensure_ascii=False, indent=2)
99
84
 
100
- async def add_chat_entry(self, role: str, content: str):
101
- entry = {"id": generate_id(), "role": role, "content": content, "timestamp": datetime.now().isoformat()}
102
- self.chat_history.append(entry)
103
- await self._save_chat_history()
104
-
105
- async def add_detailed_chat_entry(self, input_messages: List[Dict[str, str]],
106
- prompt: str, llm_response: str,
107
- tool_executions: List[Dict[str, Any]],
108
- final_response: str, entry_id: str = None):
109
- update_data = {
110
- "input_messages": input_messages, "prompt": prompt, "llm_response": llm_response,
111
- "tool_executions": tool_executions, "final_response": final_response,
112
- "timestamp": datetime.now().isoformat()
113
- }
114
- if entry_id:
115
- for entry in self.chat_history:
116
- if entry.get("id") == entry_id:
117
- entry.update(update_data)
118
- await self._save_chat_history()
119
- return entry_id
120
-
121
- new_entry = {"id": entry_id or generate_id(), "type": "llm_interaction", "role": "assistant", **update_data}
122
- self.chat_history.append(new_entry)
123
- await self._save_chat_history()
124
- return new_entry["id"]
125
-
126
- async def get_recent_chat(self, entries: int = 10) -> List[Dict[str, Any]]:
127
- return self.chat_history[-entries:]
128
-
129
- async def get_detailed_chat_history(self) -> List[Dict[str, Any]]:
130
- return self.chat_history
131
-
132
- async def get_last_agent_response(self) -> Optional[str]:
133
- for entry in reversed(self.chat_history):
134
- if entry.get("type") == "llm_interaction":
135
- final_response = entry.get("final_response", "")
136
- if final_response and final_response not in ["Processing started", "Prompt sent to LLM", "LLM response received"]:
137
- return final_response
138
- elif entry.get("role") == "assistant":
139
- content = entry.get("content", "")
140
- if content and content != "Processing started":
141
- return content
142
- return None
143
-
144
- async def reset_chat_history(self):
145
- self.chat_history = []
146
- await self._save_chat_history()
147
-
148
85
  async def reset_temp_memory(self):
149
86
  """Reset temp memory to a default empty state."""
150
87
  self.temp_memory = []
151
88
  await self._save_temp_memory()
152
89
  logger.info("Agent temp memory has been reset.")
153
90
 
154
- async def get_full_context(self) -> str:
155
- context_parts = ["=== INIT MEMORY (Immutable) ===", json.dumps(self.init_memory, indent=2)]
156
- context_parts.append("\n=== CORE MEMORY (Long-term, Mutable) ===")
157
- if "blocks" in self.core_memory:
158
- for block_id, block in self.core_memory["blocks"].items():
159
- context_parts.append(f"\nBlock: {block.get('title', '')} ({block_id})")
160
- context_parts.append(f"Description: {block.get('description', '')}")
161
- context_parts.append("Content:")
162
- for item in block.get("content", []):
163
- context_parts.append(f" - {item}")
164
- if self.temp_memory:
165
- context_parts.append("\n=== TEMP MEMORY (Processing State) ===")
166
- for item in self.temp_memory:
167
- context_parts.append(f"[{item.get('role', 'system')}] {item.get('content', '')}")
168
- return "\n".join(context_parts)
169
-
170
91
  async def add_temp_memory(self, content: str, role: str = "system"):
171
92
  self.temp_memory.append({"id": generate_id(), "content": content, "role": role, "timestamp": datetime.now().isoformat()})
172
93
  if len(self.temp_memory) > 20:
@@ -201,4 +122,4 @@ class MemoryManager:
201
122
  async def delete_core_memory_block(self, block_id: str):
202
123
  if "blocks" in self.core_memory and block_id in self.core_memory["blocks"]:
203
124
  del self.core_memory["blocks"][block_id]
204
- await self._save_core_memory()
125
+ await self._save_core_memory()
@@ -1,10 +1,10 @@
1
1
  # neuro_simulator/agent/tools/add_temp_memory.py
2
2
  """The Add Temp Memory tool for the agent."""
3
3
 
4
- from typing import Dict, Any, List
4
+ from typing import Any, Dict, List
5
5
 
6
- from .base import BaseTool
7
- from ..memory.manager import MemoryManager
6
+ from neuro_simulator.agent.tools.base import BaseTool
7
+ from neuro_simulator.agent.memory.manager import MemoryManager
8
8
 
9
9
  class AddTempMemoryTool(BaseTool):
10
10
  """Tool to add an entry to the agent's temporary memory."""
@@ -3,8 +3,8 @@
3
3
 
4
4
  from typing import Dict, Any, List
5
5
 
6
- from .base import BaseTool
7
- from ..memory.manager import MemoryManager
6
+ from neuro_simulator.agent.tools.base import BaseTool
7
+ from neuro_simulator.agent.memory.manager import MemoryManager
8
8
 
9
9
  class AddToCoreMemoryBlockTool(BaseTool):
10
10
  """Tool to add an item to an existing core memory block's content list."""
@@ -3,8 +3,8 @@
3
3
 
4
4
  from typing import Dict, Any, List
5
5
 
6
- from .base import BaseTool
7
- from ..memory.manager import MemoryManager
6
+ from neuro_simulator.agent.tools.base import BaseTool
7
+ from neuro_simulator.agent.memory.manager import MemoryManager
8
8
 
9
9
  class CreateCoreMemoryBlockTool(BaseTool):
10
10
  """Tool to create a new core memory block."""
@@ -3,8 +3,8 @@
3
3
 
4
4
  from typing import Dict, Any, List
5
5
 
6
- from .base import BaseTool
7
- from ..memory.manager import MemoryManager
6
+ from neuro_simulator.agent.tools.base import BaseTool
7
+ from neuro_simulator.agent.memory.manager import MemoryManager
8
8
 
9
9
  class DeleteCoreMemoryBlockTool(BaseTool):
10
10
  """Tool to delete an existing core memory block."""
@@ -3,8 +3,8 @@
3
3
 
4
4
  from typing import Dict, Any, List
5
5
 
6
- from .base import BaseTool
7
- from ..memory.manager import MemoryManager
6
+ from neuro_simulator.agent.tools.base import BaseTool
7
+ from neuro_simulator.agent.memory.manager import MemoryManager
8
8
 
9
9
  class GetCoreMemoryBlockTool(BaseTool):
10
10
  """Tool to retrieve a single core memory block by its ID."""
@@ -3,8 +3,8 @@
3
3
 
4
4
  from typing import Dict, Any, List
5
5
 
6
- from .base import BaseTool
7
- from ..memory.manager import MemoryManager
6
+ from neuro_simulator.agent.tools.base import BaseTool
7
+ from neuro_simulator.agent.memory.manager import MemoryManager
8
8
 
9
9
  class GetCoreMemoryBlocksTool(BaseTool):
10
10
  """Tool to retrieve all core memory blocks."""