mindroot 10.6.0__py3-none-any.whl → 10.8.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.

Potentially problematic release.


This version of mindroot might be problematic. Click here for more details.

@@ -24,6 +24,9 @@ import nanoid
24
24
  sse_clients = {}
25
25
  from lib.chatcontext import get_context
26
26
 
27
+ # Track active processing tasks per session
28
+ active_tasks = {}
29
+
27
30
  @service()
28
31
  async def prompt(model: str, instructions: str, temperature=0, max_tokens=400, json=False, context=None):
29
32
  messages = [
@@ -68,7 +71,7 @@ def results_output(results):
68
71
  text = ""
69
72
  for result in results:
70
73
  if 'output' in result['args']:
71
- return result['args']['output']
74
+ return str(result['args']['output'])
72
75
 
73
76
  def results_text_output(results):
74
77
  text = ""
@@ -135,6 +138,9 @@ async def run_task(instructions: str, agent_name:str = None, user:str = None, lo
135
138
 
136
139
  while retried < retries:
137
140
  [results, full_results] = await send_message_to_agent(context.log_id, instructions, context=context)
141
+ print('#####################################################33')
142
+ print("Full results: ", full_results)
143
+ print("Results: ", results)
138
144
  text = results_output(full_results)
139
145
  if text == "":
140
146
  retried += 1
@@ -217,30 +223,61 @@ def process_result(result, formatted_results):
217
223
 
218
224
  return formatted_results
219
225
 
226
+ # Deprecated - use active_tasks instead
220
227
  in_progress = {}
221
228
 
229
+
222
230
  @service()
223
- async def send_message_to_agent(session_id: str, message: str | List[MessageParts], max_iterations=35, context=None, user=None):
224
- global in_progress
225
- existing_session = in_progress.get(session_id, False)
226
- print(existing_session)
227
-
228
- if existing_session:
229
- context_ = await get_context(session_id, user)
230
- context.data['finished_conversation'] = True
231
- await asyncio.sleep(0.4)
232
- else:
233
- print('starting')
231
+ async def cancel_and_wait(session_id: str, user:str, context=None):
232
+ global in_progress, active_tasks
233
+ existing_task = active_tasks.get(session_id)
234
234
 
235
- print('ok')
236
- in_progress[session_id] = True
235
+ if not in_progress.get(session_id, False):
236
+ print(f"SEND_MESSAGE No active processing for session {session_id} to cancel.")
237
+ return
238
+ try:
239
+ print(f"SEND_MESSAGE Cancelling active task for session {session_id}...")
240
+ existing_context = await get_context(session_id, user)
241
+ existing_context.data['cancel_current_turn'] = True
242
+ existing_context.data['finished_conversation'] = True
243
+ existing_context.save_context()
244
+ # Cancel any active command task
245
+ if 'active_command_task' in existing_context.data:
246
+ cmd_task = existing_context.data['active_command_task']
247
+ if cmd_task and not cmd_task.done():
248
+ cmd_task.cancel()
249
+
250
+ await existing_context.save_context()
251
+ except Exception as e:
252
+ print(f"SEND_MESSAGE Error setting cancellation flags: {e}")
253
+
254
+ # Cancel the main task
255
+ existing_task.cancel()
256
+
257
+ # Wait for it to actually finish (with timeout)
258
+ try:
259
+ await asyncio.wait_for(existing_task, timeout=2.0)
260
+ except (asyncio.CancelledError, asyncio.TimeoutError):
261
+ pass # Expected
262
+
263
+ start_wait = time.time()
264
+ while in_progress.get(session_id, False) and (time.time() - start_wait) < 5.0:
265
+ print(f"SEND_MESSAGE Waiting for cancellation of session {session_id} to complete...")
266
+ await asyncio.sleep(0.1)
267
+
268
+ print(f"SEND_MESSAGE Cancellation complete for session {session_id}")
269
+
270
+ @service()
271
+ async def send_message_to_agent(session_id: str, message: str | List[MessageParts], max_iterations=35, context=None, user=None):
272
+ global in_progress, active_tasks
273
+
274
+ # Check if there's an active task for this session
275
+ existing_task = active_tasks.get(session_id)
237
276
 
238
- print('b')
239
- if os.environ.get("MR_MAX_ITERATIONS") is not None:
240
- max_iterations = int(os.environ.get("MR_MAX_ITERATIONS"))
241
277
  if not user:
242
278
  # check context
243
279
  if not context.username:
280
+ print("SEND_MESSAGE No user provided and context has no username")
244
281
  raise Exception("User required")
245
282
  else:
246
283
  user = {"user": context.username }
@@ -248,14 +285,72 @@ async def send_message_to_agent(session_id: str, message: str | List[MessagePart
248
285
  if hasattr(user, "dict"):
249
286
  user = user.dict()
250
287
 
288
+ # If there's an existing task, cancel it and wait for it to finish
289
+ if existing_task and not existing_task.done():
290
+ #print("SEND_MESSAGE rejecting because active task, but sneaking in new user message")
291
+ #if type(message) is str:
292
+ #context.chat_log.add_message({"role": "user", "content": [{"type": "text", "text": message}]})
293
+ #context.chat_log.add_message_role({"role": "user", "content": message })
294
+
295
+ #return []
296
+ print(f"SEND_MESSAGE: Cancelling existing task for session {session_id}")
297
+
298
+ # Load the context to set cancellation flags
299
+ try:
300
+ existing_context = await get_context(session_id, user)
301
+ existing_context.data['cancel_current_turn'] = True
302
+ existing_context.data['finished_conversation'] = True
303
+ existing_context.save_context()
304
+ # Cancel any active command task
305
+ if 'active_command_task' in existing_context.data:
306
+ cmd_task = existing_context.data['active_command_task']
307
+ if cmd_task and not cmd_task.done():
308
+ cmd_task.cancel()
309
+
310
+ await existing_context.save_context()
311
+ except Exception as e:
312
+ print(f"SEND_MESSAGE Error setting cancellation flags: {e}")
313
+
314
+ # Cancel the main task
315
+ existing_task.cancel()
316
+
317
+ # Wait for it to actually finish (with timeout)
318
+ try:
319
+ await asyncio.wait_for(existing_task, timeout=2.0)
320
+ except (asyncio.CancelledError, asyncio.TimeoutError):
321
+ pass # Expected
322
+
323
+ start_wait = time.time()
324
+ while in_progress.get(session_id, False) and (time.time() - start_wait) < 5.0:
325
+ print(f"SEND_MESSAGE Waiting for cancellation of session {session_id} to complete...")
326
+ await asyncio.sleep(0.1)
327
+
328
+
329
+ print(f"SEND_MESSAGE Previous task cancelled for session {session_id}")
330
+
331
+ context.data['cancel_current_turn'] = False
332
+ context.data['finished_conversation'] = False
333
+ context.save_context()
334
+
335
+ in_progress[session_id] = True
336
+ asyncio.sleep(0.2)
337
+
338
+ print('b')
339
+ if os.environ.get("MR_MAX_ITERATIONS") is not None:
340
+ max_iterations = int(os.environ.get("MR_MAX_ITERATIONS"))
251
341
  try:
252
342
  if type(message) is list:
253
343
  message = [m.dict() for m in message]
254
344
 
255
345
  if session_id is None or session_id == "" or message is None or message == "":
256
- print("Invalid session_id or message")
346
+ print("SEND_MESSAGE Invalid session_id or message")
257
347
  return []
258
348
 
349
+ # Create the main processing task and store it
350
+ processing_task = asyncio.current_task()
351
+ active_tasks[session_id] = processing_task
352
+
353
+ print("SEND_MESSAGE proceeding with message processing")
259
354
  print("send_message_to_agent: ", session_id, message, max_iterations)
260
355
  if context is None:
261
356
  context = ChatContext(command_manager, service_manager, user)
@@ -390,9 +485,12 @@ async def send_message_to_agent(session_id: str, message: str | List[MessagePart
390
485
  context.chat_log.add_message({"role": "user", "content": formatted_results})
391
486
  results.append(out_results)
392
487
  else:
393
- print("Processing iteration: ", iterations, "no message added")
488
+ print("SEND_MESSAGE Processing iteration: ", iterations, "no message added")
394
489
  if context.data.get('finished_conversation') is True:
395
490
  termcolor.cprint("Finished conversation, exiting send_message_to_agent", "red")
491
+ if context.data.get('task_result') is not None:
492
+ task_result = context.data.get('task_result')
493
+ full_results.append({ "cmd": "task_result", "args": { "result": task_result } })
396
494
  continue_processing = False
397
495
  except Exception as e:
398
496
  continue_processing = False
@@ -417,7 +515,18 @@ async def send_message_to_agent(session_id: str, message: str | List[MessagePart
417
515
 
418
516
  await context.finished_chat()
419
517
  in_progress.pop(session_id, None)
518
+ active_tasks.pop(session_id, None)
519
+ if len(results) == 0:
520
+ if context.data.get('task_result') is not None:
521
+ task_result = context.data.get('task_result')
522
+ results.append(task_result)
523
+ print("SEND_MESSAGE Done")
420
524
  return [results, full_results]
525
+ except asyncio.CancelledError:
526
+ print(f"Task cancelled for session {session_id}")
527
+ in_progress.pop(session_id, None)
528
+ active_tasks.pop(session_id, None)
529
+ raise # Re-raise to properly handle cancellation
421
530
  except Exception as e:
422
531
  print("Error in send_message_to_agent: ", e)
423
532
  print(traceback.format_exc())
@@ -508,8 +617,7 @@ async def command_result(command: str, result, context=None):
508
617
  @service()
509
618
  async def backend_user_message(message: str, context=None):
510
619
  """
511
- Insert a user message from the backend and signal the frontend to display it.
512
- This allows backend processes to inject messages into the chat without user interaction.
620
+ Signal the frontend to display a user message.
513
621
  """
514
622
  agent_ = context.agent
515
623
  persona = 'user'
@@ -561,10 +669,15 @@ async def cancel_active_response(log_id: str, context=None):
561
669
  # DEBUG TRACE
562
670
  print("\033[91;107m[DEBUG TRACE 6/6] Active command task found and cancelled.\033[0m")
563
671
  print(f"Cancelled active command task for session {log_id}")
672
+ print(f"Removing last assistant message from chat log for session {log_id}")
673
+ await context.chat_log.drop_last('assistant')
674
+
564
675
  except Exception as e:
565
676
  print(f"Error cancelling active command task: {e}")
566
-
677
+
678
+
567
679
  await context.save_context()
568
680
 
569
681
  print(f"Cancelled active response for session {log_id}")
570
682
  return {"status": "cancelled", "log_id": log_id}
683
+
@@ -9,6 +9,7 @@ from .chatlog import ChatLog
9
9
  from .chatlog import extract_delegate_task_log_ids, find_child_logs_by_parent_id, find_chatlog_file
10
10
  from typing import TypeVar, Type, Protocol, runtime_checkable, Set
11
11
  from .utils.debug import debug_box
12
+
12
13
  contexts = {}
13
14
 
14
15
  async def get_context(log_id, user):
mindroot/lib/chatlog.py CHANGED
@@ -62,6 +62,8 @@ class ChatLog:
62
62
  self.agent = log_data.get('agent')
63
63
  self.messages = log_data.get('messages', [])
64
64
  self.parent_log_id = log_data.get('parent_log_id', None)
65
+ # we need the last modification time of the file
66
+ self.last_modified = os.path.getmtime(log_file)
65
67
  print("Loaded log file at ", log_file)
66
68
  print("Message length: ", len(self.messages))
67
69
  else:
@@ -71,12 +73,23 @@ class ChatLog:
71
73
  def _save_log_sync(self) -> None:
72
74
  """Synchronous version for backward compatibility"""
73
75
  log_file = os.path.join(self.log_dir, f'chatlog_{self.log_id}.json')
76
+ self.last_modified = time.time()
74
77
  with open(log_file, 'w') as f:
75
78
  json.dump(self._get_log_data(), f, indent=2)
76
79
 
80
+
81
+ def add_message_role(self, message: Dict[str, str]) -> None:
82
+ for i in range(len(self.messages)-1, -1, -1):
83
+ if self.messages[i]['role'] == message.get('role'):
84
+ self.messages[i]['content'].append(message)
85
+ self.last_modified = time.time()
86
+ self._save_log_sync()
87
+ return
88
+
77
89
  def add_message(self, message: Dict[str, str]) -> None:
78
90
  """Synchronous version for backward compatibility"""
79
91
  should_save = self._add_message_impl(message)
92
+ self.last_modified = time.time()
80
93
  if should_save:
81
94
  self._save_log_sync()
82
95
  else:
@@ -157,6 +170,25 @@ class ChatLog:
157
170
  def get_history(self) -> List[Dict[str, str]]:
158
171
  return self.messages
159
172
 
173
+
174
+ def parsed_commands(self) -> List[Dict[str, any]]:
175
+ commands = []
176
+ filtered = [m for m in self.messages if m['role'] == 'assistant']
177
+ for message in filtered:
178
+ content = message['content']
179
+ if isinstance(content, list) and len(content) > 0 and 'text' in content[0]:
180
+ text = content[0]['text']
181
+ else:
182
+ continue
183
+ try:
184
+ cmd_list = json.loads(text)
185
+ if not isinstance(cmd_list, list):
186
+ cmd_list = [cmd_list]
187
+ commands.extend(cmd_list)
188
+ except (json.JSONDecodeError, TypeError):
189
+ continue
190
+ return commands
191
+
160
192
  def get_recent(self, max_tokens: int = 4096) -> List[Dict[str, str]]:
161
193
  recent_messages = []
162
194
  total_length = 0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mindroot
3
- Version: 10.6.0
3
+ Version: 10.8.0
4
4
  Summary: MindRoot AI Agent Framework
5
5
  Requires-Python: >=3.9
6
6
  License-File: LICENSE
@@ -439,8 +439,9 @@ mindroot/coreplugins/admin/static/js/lit-html/node/directives/when.js,sha256=NLe
439
439
  mindroot/coreplugins/admin/static/js/lit-html/node/directives/when.js.map,sha256=tOonih_-EaqrunhNGshA9xN--WIVdGikjg8MkVp0itQ,1534
440
440
  mindroot/coreplugins/admin/templates/admin.jinja2,sha256=H_oDqoWWk0Da0Jre67LIKvB3h30fmjcZz2T5knUyz0k,13272
441
441
  mindroot/coreplugins/admin/templates/model-preferences-v2.jinja2,sha256=5J3rXYmtp_yMTFCk85SYN03gc4lbidF0Nip6YcqcIW4,891
442
- mindroot/coreplugins/agent/agent.py,sha256=k3G3VaRjGwd1TNYQloytE4NV5cXyVxiuUl1GaMfdTEE,22335
442
+ mindroot/coreplugins/agent/agent.py,sha256=m28_7JNXbqDjo5ZQ2H2goPA1bGoeCLc1riUiDaNa_6E,22903
443
443
  mindroot/coreplugins/agent/agent.py.bak,sha256=X-EmtrpEpdfo-iUw9gj7mLveRVzAApsDWPTwMAuv7Ww,20715
444
+ mindroot/coreplugins/agent/buagentz1.py,sha256=XVRKf-jEHgv6ru-iESg1uPJGgUz3pzeAG-0UjPA4bqw,22404
444
445
  mindroot/coreplugins/agent/cmd_start_example.py,sha256=Mdcd9st6viI6-M7a0-zqkw3IxR9FAxIiZ_8G-tLdIJk,1416
445
446
  mindroot/coreplugins/agent/command_parser.py,sha256=dgMqtVLPQWE2BU7iyjqwKGy5Gh74jcZkiy1JDs07t4E,13166
446
447
  mindroot/coreplugins/agent/ensure_msg_type.py,sha256=P2XSBs3gtjlDQLOF7808nm-Dl5jswyO6qgv0lNRyHXM,240
@@ -461,15 +462,15 @@ mindroot/coreplugins/api_keys/router.py,sha256=pz6VjUDPryKxYgnPt8-5AP1P-wjIIQq2c
461
462
  mindroot/coreplugins/api_keys/inject/admin.jinja2,sha256=t50he2aeK_GJ6838LekBcGjkYRbo5p6OHeTWtlggbyU,372
462
463
  mindroot/coreplugins/api_keys/static/js/api-key-manager.js,sha256=imqlhd85Z-1e7uxDlprphGV_N467WKo8_BYVQsJJ1V0,5327
463
464
  mindroot/coreplugins/chat/__init__.py,sha256=qVdTF1fHZJHwY_ChnPvNFx2Nlg07FHvK0V_JmzfWzdw,230
465
+ mindroot/coreplugins/chat/buservices.py,sha256=MHwkwlWNh8xJ_nnskSBj4N5B1xtFhOMfN-dUyxVC_M8,24635
464
466
  mindroot/coreplugins/chat/buwidget_routes.py,sha256=MtwaPX2vEGDylifWOqcx7EAhDw0y1Y3Y91z58EJaLsc,9982
465
- mindroot/coreplugins/chat/commands.py,sha256=vlgGOvwvjpCbSsW25x4HaeFzeRNWXoEKrdqNpwX_EGg,17077
466
- mindroot/coreplugins/chat/edit_router.py,sha256=25BStzAIvGhULb_07bZw2aNxnpqabKV6CZHl9xrYdbQ,18629
467
+ mindroot/coreplugins/chat/commands.py,sha256=YVmOMyihMoPMxeaQI2f9QAz91Z7lHfjZ01rTfogmyeM,17308
467
468
  mindroot/coreplugins/chat/format_result_msgs.py,sha256=daEdpEyAJIa8b2VkCqSKcw8PaExcB6Qro80XNes_sHA,2
468
469
  mindroot/coreplugins/chat/mod.py,sha256=Xydjv3feKJJRbwdiB7raqiQnWtaS_2GcdC9bXYQX3nE,425
469
470
  mindroot/coreplugins/chat/models.py,sha256=GRcRuDUAJFpyWERPMxkxUaZ21igNlWeeamriruEKiEQ,692
470
471
  mindroot/coreplugins/chat/router.py,sha256=vq9UwYoFoGQMVmDC0TkjH7TWivFwkIe6OU0Scu-dtHg,15998
471
472
  mindroot/coreplugins/chat/router_dedup_patch.py,sha256=lDSpVMSd26pXJwrrdirUmR1Jv_N5VHiDzTS8t3XswDU,918
472
- mindroot/coreplugins/chat/services.py,sha256=cODRoNjE0lrraYBR5fwzMAwB-Y-GBQTr8VCMTzsejlY,22325
473
+ mindroot/coreplugins/chat/services.py,sha256=92KSkTWP5cqbcAg15r89FlDrYSR2jUVyeiIkCMmOaf4,27235
473
474
  mindroot/coreplugins/chat/utils.py,sha256=BiE14PpsAcQSO5vbU88klHGm8cAXJDXxgVgva-EXybU,155
474
475
  mindroot/coreplugins/chat/widget_manager.py,sha256=LrMbZlHqpxbLwdN4XZ4GkLxORwxa1o6IVCrlUDBmGQs,4786
475
476
  mindroot/coreplugins/chat/widget_routes.py,sha256=iV3OwLFnvLDsMHdckJnmVXcUgyyng-zIPNXyK2LAUjc,11802
@@ -2196,8 +2197,8 @@ mindroot/lib/buchatlog.py,sha256=LJZc3ksKgJcStltmHrrwNLaON3EDzhOKVAWj0Wl22wk,586
2196
2197
  mindroot/lib/buchatlog2.py,sha256=Va9FteBWePEjWD9OZcw-OtQfEb-IoCVGTmJeMRaX9is,13729
2197
2198
  mindroot/lib/buchatlog3.py,sha256=SAvcK2m_CW0Jw8p1pqnbrTexcx24PotrsJTqvQ_D290,24573
2198
2199
  mindroot/lib/butemplates.py,sha256=gfHGPTOjvoEenXsR7xokNuqMjOAPuC2DawheH1Ae4bU,12196
2199
- mindroot/lib/chatcontext.py,sha256=CXk-pX-7RG3NiRFsAZWERWxnuFJOHH7FHtOLm-kGRXE,12437
2200
- mindroot/lib/chatlog.py,sha256=ACdixKTn_GlVVfB00fNlphNPMFnRrum_za_mQfGPQoQ,26372
2200
+ mindroot/lib/chatcontext.py,sha256=1NjD3YFmw5KpEi0rAUeFNYU1DRnu2k7kL3KRX4ebJc8,12438
2201
+ mindroot/lib/chatlog.py,sha256=RKEx29JB-48fntWIzsdI4NTu-hp6eKxcpwRmNW6cSAc,27629
2201
2202
  mindroot/lib/chatlog_optimized.py,sha256=rL7KBP-V4_cGgMLihxPm3HoKcjFEyA1uEtPtqvkOa3A,20011
2202
2203
  mindroot/lib/json_escape.py,sha256=5cAmAdNbnYX2uyfQcnse2fFtNI0CdB-AfZ23RwaDm-k,884
2203
2204
  mindroot/lib/model_selector.py,sha256=Wz-8NZoiclmnhLeCNnI3WCuKFmjsO5HE4bK5F8GpZzU,1397
@@ -2251,9 +2252,9 @@ mindroot/protocols/services/stream_chat.py,sha256=fMnPfwaB5fdNMBLTEg8BXKAGvrELKH
2251
2252
  mindroot/registry/__init__.py,sha256=40Xy9bmPHsgdIrOzbtBGzf4XMqXVi9P8oZTJhn0r654,151
2252
2253
  mindroot/registry/component_manager.py,sha256=WZFNPg4SNvpqsM5NFiC2DpgmrJQCyR9cNhrCBpp30Qk,995
2253
2254
  mindroot/registry/data_access.py,sha256=81In5TwETpaqnnY1_-tBQM7rfWvUxZUZkG7lEelRUfU,5321
2254
- mindroot-10.6.0.dist-info/licenses/LICENSE,sha256=8plAmZh8y9ccuuqFFz4kp7G-cO_qsPgAOoHNvabSB4U,1070
2255
- mindroot-10.6.0.dist-info/METADATA,sha256=B_jgoqAFx9YKO_ddBGR0_rVBewpVyTae8JJhUxQI_LY,1035
2256
- mindroot-10.6.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
2257
- mindroot-10.6.0.dist-info/entry_points.txt,sha256=0bpyjMccLttx6VcjDp6zfJPN0Kk0rffor6IdIbP0j4c,50
2258
- mindroot-10.6.0.dist-info/top_level.txt,sha256=gwKm7DmNjhdrCJTYCrxa9Szne4lLpCtrEBltfsX-Mm8,9
2259
- mindroot-10.6.0.dist-info/RECORD,,
2255
+ mindroot-10.8.0.dist-info/licenses/LICENSE,sha256=8plAmZh8y9ccuuqFFz4kp7G-cO_qsPgAOoHNvabSB4U,1070
2256
+ mindroot-10.8.0.dist-info/METADATA,sha256=QoOESWmVk50VB9uKdPhnEWiCiB6TWCuHm7agLKJTImI,1035
2257
+ mindroot-10.8.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
2258
+ mindroot-10.8.0.dist-info/entry_points.txt,sha256=0bpyjMccLttx6VcjDp6zfJPN0Kk0rffor6IdIbP0j4c,50
2259
+ mindroot-10.8.0.dist-info/top_level.txt,sha256=gwKm7DmNjhdrCJTYCrxa9Szne4lLpCtrEBltfsX-Mm8,9
2260
+ mindroot-10.8.0.dist-info/RECORD,,