mindroot 10.5.0__py3-none-any.whl → 10.14.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.
@@ -8,6 +8,7 @@ from typing import List
8
8
  from lib.utils.dataurl import dataurl_to_pil
9
9
  from .models import MessageParts
10
10
  from coreplugins.agent import agent
11
+ from coreplugins.agent.speech_to_speech import SpeechToSpeechAgent
11
12
  from lib.utils.debug import debug_box
12
13
  import os
13
14
  import sys
@@ -24,6 +25,9 @@ import nanoid
24
25
  sse_clients = {}
25
26
  from lib.chatcontext import get_context
26
27
 
28
+ # Track active processing tasks per session
29
+ active_tasks = {}
30
+
27
31
  @service()
28
32
  async def prompt(model: str, instructions: str, temperature=0, max_tokens=400, json=False, context=None):
29
33
  messages = [
@@ -68,7 +72,7 @@ def results_output(results):
68
72
  text = ""
69
73
  for result in results:
70
74
  if 'output' in result['args']:
71
- return result['args']['output']
75
+ return str(result['args']['output'])
72
76
 
73
77
  def results_text_output(results):
74
78
  text = ""
@@ -135,6 +139,9 @@ async def run_task(instructions: str, agent_name:str = None, user:str = None, lo
135
139
 
136
140
  while retried < retries:
137
141
  [results, full_results] = await send_message_to_agent(context.log_id, instructions, context=context)
142
+ print('#####################################################33')
143
+ print("Full results: ", full_results)
144
+ print("Results: ", results)
138
145
  text = results_output(full_results)
139
146
  if text == "":
140
147
  retried += 1
@@ -165,6 +172,11 @@ async def init_chat_session(user:str, agent_name: str, log_id: str, context=None
165
172
  print("context.agent_name: ", context.agent_name)
166
173
  await context.save_context()
167
174
  print("initiated_chat_session: ", log_id, agent_name, context.agent_name, context.agent)
175
+
176
+ if 'live' in context.agent['stream_chat'] or 'realtime' in context.agent['stream_chat']:
177
+ agent = SpeechToSpeechAgent(agent_name, context=context)
178
+ await agent.connect()
179
+
168
180
  return log_id
169
181
 
170
182
  @service()
@@ -217,13 +229,61 @@ def process_result(result, formatted_results):
217
229
 
218
230
  return formatted_results
219
231
 
232
+ # Deprecated - use active_tasks instead
233
+ in_progress = {}
234
+
235
+
236
+ @service()
237
+ async def cancel_and_wait(session_id: str, user:str, context=None):
238
+ global in_progress, active_tasks
239
+ existing_task = active_tasks.get(session_id)
240
+
241
+ if not in_progress.get(session_id, False):
242
+ print(f"SEND_MESSAGE No active processing for session {session_id} to cancel.")
243
+ return
244
+ try:
245
+ print(f"SEND_MESSAGE Cancelling active task for session {session_id}...")
246
+ existing_context = await get_context(session_id, user)
247
+ existing_context.data['cancel_current_turn'] = True
248
+ existing_context.data['finished_conversation'] = True
249
+ existing_context.save_context()
250
+ # Cancel any active command task
251
+ if 'active_command_task' in existing_context.data:
252
+ cmd_task = existing_context.data['active_command_task']
253
+ if cmd_task and not cmd_task.done():
254
+ cmd_task.cancel()
255
+
256
+ await existing_context.save_context()
257
+ except Exception as e:
258
+ print(f"SEND_MESSAGE Error setting cancellation flags: {e}")
259
+
260
+ # Cancel the main task
261
+ existing_task.cancel()
262
+
263
+ # Wait for it to actually finish (with timeout)
264
+ try:
265
+ await asyncio.wait_for(existing_task, timeout=2.0)
266
+ except (asyncio.CancelledError, asyncio.TimeoutError):
267
+ pass # Expected
268
+
269
+ start_wait = time.time()
270
+ while in_progress.get(session_id, False) and (time.time() - start_wait) < 5.0:
271
+ print(f"SEND_MESSAGE Waiting for cancellation of session {session_id} to complete...")
272
+ await asyncio.sleep(0.025)
273
+
274
+ print(f"SEND_MESSAGE Cancellation complete for session {session_id}")
275
+
220
276
  @service()
221
277
  async def send_message_to_agent(session_id: str, message: str | List[MessageParts], max_iterations=35, context=None, user=None):
222
- if os.environ.get("MR_MAX_ITERATIONS") is not None:
223
- max_iterations = int(os.environ.get("MR_MAX_ITERATIONS"))
278
+ global in_progress, active_tasks
279
+
280
+ # Check if there's an active task for this session
281
+ existing_task = active_tasks.get(session_id)
282
+
224
283
  if not user:
225
284
  # check context
226
285
  if not context.username:
286
+ print("SEND_MESSAGE No user provided and context has no username")
227
287
  raise Exception("User required")
228
288
  else:
229
289
  user = {"user": context.username }
@@ -231,20 +291,46 @@ async def send_message_to_agent(session_id: str, message: str | List[MessagePart
231
291
  if hasattr(user, "dict"):
232
292
  user = user.dict()
233
293
 
294
+ context.data['cancel_current_turn'] = False
295
+ context.data['finished_conversation'] = False
296
+ await context.save_context()
297
+
298
+ in_progress[session_id] = True
299
+ await asyncio.sleep(0.05)
300
+
301
+ print('b')
302
+ if os.environ.get("MR_MAX_ITERATIONS") is not None:
303
+ max_iterations = int(os.environ.get("MR_MAX_ITERATIONS"))
234
304
  try:
235
305
  if type(message) is list:
236
306
  message = [m.dict() for m in message]
237
307
 
238
308
  if session_id is None or session_id == "" or message is None or message == "":
239
- print("Invalid session_id or message")
309
+ print("SEND_MESSAGE Invalid session_id or message")
240
310
  return []
241
311
 
312
+ # Create the main processing task and store it
313
+ processing_task = asyncio.current_task()
314
+ active_tasks[session_id] = processing_task
315
+
316
+ print("SEND_MESSAGE proceeding with message processing")
242
317
  print("send_message_to_agent: ", session_id, message, max_iterations)
243
318
  if context is None:
244
319
  context = ChatContext(command_manager, service_manager, user)
245
320
  await context.load_context(session_id)
246
321
 
247
- agent_ = agent.Agent(agent=context.agent)
322
+ if 'live' in context.agent['stream_chat'] or 'realtime' in context.agent['stream_chat']:
323
+ agent_ = SpeechToSpeechAgent(context.agent_name, context=context)
324
+ print('Using SpeechToSpeechAgent for live/realtime chat')
325
+ print()
326
+ print()
327
+ print()
328
+ print('message: ', message)
329
+ results = await agent_.send_message(message)
330
+ return results, []
331
+ else:
332
+ agent_ = agent.Agent(agent=context.agent)
333
+
248
334
  if user is not None and hasattr(user, "keys"):
249
335
  for key in user.keys():
250
336
  context.data[key] = user[key]
@@ -373,9 +459,12 @@ async def send_message_to_agent(session_id: str, message: str | List[MessagePart
373
459
  context.chat_log.add_message({"role": "user", "content": formatted_results})
374
460
  results.append(out_results)
375
461
  else:
376
- print("Processing iteration: ", iterations, "no message added")
462
+ print("SEND_MESSAGE Processing iteration: ", iterations, "no message added")
377
463
  if context.data.get('finished_conversation') is True:
378
464
  termcolor.cprint("Finished conversation, exiting send_message_to_agent", "red")
465
+ if context.data.get('task_result') is not None:
466
+ task_result = context.data.get('task_result')
467
+ full_results.append({ "cmd": "task_result", "args": { "result": task_result } })
379
468
  continue_processing = False
380
469
  except Exception as e:
381
470
  continue_processing = False
@@ -399,10 +488,23 @@ async def send_message_to_agent(session_id: str, message: str | List[MessagePart
399
488
  print("Exiting send_message_to_agent: ", session_id, message, max_iterations)
400
489
 
401
490
  await context.finished_chat()
491
+ in_progress.pop(session_id, None)
492
+ active_tasks.pop(session_id, None)
493
+ if len(results) == 0:
494
+ if context.data.get('task_result') is not None:
495
+ task_result = context.data.get('task_result')
496
+ results.append(task_result)
497
+ print("SEND_MESSAGE Done")
402
498
  return [results, full_results]
499
+ except asyncio.CancelledError:
500
+ print(f"Task cancelled for session {session_id}")
501
+ in_progress.pop(session_id, None)
502
+ active_tasks.pop(session_id, None)
503
+ raise # Re-raise to properly handle cancellation
403
504
  except Exception as e:
404
505
  print("Error in send_message_to_agent: ", e)
405
506
  print(traceback.format_exc())
507
+ in_progress.pop(session_id, None)
406
508
  return []
407
509
 
408
510
  @pipe(name='process_results', priority=5)
@@ -489,8 +591,7 @@ async def command_result(command: str, result, context=None):
489
591
  @service()
490
592
  async def backend_user_message(message: str, context=None):
491
593
  """
492
- Insert a user message from the backend and signal the frontend to display it.
493
- This allows backend processes to inject messages into the chat without user interaction.
594
+ Signal the frontend to display a user message.
494
595
  """
495
596
  agent_ = context.agent
496
597
  persona = 'user'
@@ -542,10 +643,15 @@ async def cancel_active_response(log_id: str, context=None):
542
643
  # DEBUG TRACE
543
644
  print("\033[91;107m[DEBUG TRACE 6/6] Active command task found and cancelled.\033[0m")
544
645
  print(f"Cancelled active command task for session {log_id}")
646
+ print(f"Removing last assistant message from chat log for session {log_id}")
647
+ await context.chat_log.drop_last('assistant')
648
+
545
649
  except Exception as e:
546
650
  print(f"Error cancelling active command task: {e}")
547
-
651
+
652
+
548
653
  await context.save_context()
549
654
 
550
655
  print(f"Cancelled active response for session {log_id}")
551
- return {"status": "cancelled", "log_id": log_id}
656
+ return {"status": "cancelled", "log_id": log_id}
657
+
@@ -1,3 +1,8 @@
1
+ /* Import JetBrains Mono from Google Fonts */
2
+ @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap');
3
+
4
+ /* Base styles */
5
+
1
6
  html, body {
2
7
  background-color: #101020;
3
8
  color: #f0f0f0;
@@ -16,7 +21,7 @@ input, * {
16
21
  background-color: transparent;
17
22
  color: #f0f0f0;
18
23
  margin: 2px 2px;
19
- font-family: ui-sans-serif, -apple-system, system-ui, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, Helvetica, "Apple Color Emoji", Arial, "Segoe UI Emoji", "Segoe UI Symbol";
24
+ /*font-family: ui-sans-serif, -apple-system, system-ui, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, Helvetica, "Apple Color Emoji", Arial, "Segoe UI Emoji", "Segoe UI Symbol";*/
20
25
  }
21
26
 
22
27
  p {
@@ -1020,3 +1025,87 @@ tbody tr {
1020
1025
  .left-side {
1021
1026
  overflow-y: auto;
1022
1027
  }
1028
+
1029
+ /* Enhanced Shell/Terminal output styling */
1030
+ pre.shellout {
1031
+ background: linear-gradient(to bottom, #2d2d2d 0%, #1e1e1e 30px, #1a1a1a 100%);
1032
+ border: 1px solid #404040;
1033
+ border-radius: 12px;
1034
+ padding: 0;
1035
+ margin: 15px 0;
1036
+ overflow-x: auto;
1037
+ max-height: 50vh;
1038
+ overflow-y: auto;
1039
+ box-shadow: 0 8px 16px rgba(0, 0, 0, 0.4),
1040
+ 0 0 0 1px rgba(255, 255, 255, 0.05) inset;
1041
+ position: relative;
1042
+ }
1043
+
1044
+ /* Mock terminal title bar */
1045
+ pre.shellout::before {
1046
+ content: '';
1047
+ display: block;
1048
+ height: 30px;
1049
+ background: linear-gradient(to bottom, #3a3a3a, #2d2d2d);
1050
+ border-bottom: 1px solid #1a1a1a;
1051
+ border-radius: 12px 12px 0 0;
1052
+ position: sticky;
1053
+ top: 0;
1054
+ z-index: 1;
1055
+ }
1056
+
1057
+ /* Terminal window controls (dots) */
1058
+ pre.shellout::after {
1059
+ content: '';
1060
+ position: absolute;
1061
+ top: 11px;
1062
+ left: 12px;
1063
+ width: 12px;
1064
+ height: 12px;
1065
+ background: #ff5f56;
1066
+ border-radius: 50%;
1067
+ box-shadow:
1068
+ 20px 0 0 #ffbd2e,
1069
+ 40px 0 0 #27c93f,
1070
+ 0 0 0 1px rgba(0, 0, 0, 0.2);
1071
+ z-index: 2;
1072
+ }
1073
+
1074
+ /* Code element inside shellout pre */
1075
+ pre.shellout code {
1076
+ background-color: transparent;
1077
+ color: #e8e8e8;
1078
+ font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', 'Monaco', monospace;
1079
+ font-size: 14px;
1080
+ line-height: 1.6;
1081
+ padding: 15px 20px;
1082
+ padding-top: 10px;
1083
+ margin: 0;
1084
+ border: none;
1085
+ white-space: pre-wrap;
1086
+ display: block;
1087
+ font-weight: 400;
1088
+ letter-spacing: 0.02em;
1089
+ }
1090
+
1091
+ /* Custom scrollbar for terminal */
1092
+ pre.shellout::-webkit-scrollbar {
1093
+ width: 10px;
1094
+ height: 10px;
1095
+ }
1096
+
1097
+ pre.shellout::-webkit-scrollbar-track {
1098
+ background: #1a1a1a;
1099
+ border-radius: 0 0 12px 0;
1100
+ }
1101
+
1102
+ pre.shellout::-webkit-scrollbar-thumb {
1103
+ background: #404040;
1104
+ border-radius: 5px;
1105
+ border: 2px solid #1a1a1a;
1106
+ }
1107
+
1108
+ pre.shellout::-webkit-scrollbar-thumb:hover {
1109
+ background: #4a4a4a;
1110
+ }
1111
+
@@ -1,3 +1,8 @@
1
+ /* Import JetBrains Mono from Google Fonts */
2
+ @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap');
3
+
4
+ /* Base styles */
5
+
1
6
  html, body {
2
7
  background-color: #101020;
3
8
  color: #f0f0f0;
@@ -16,7 +21,7 @@ input, * {
16
21
  background-color: transparent;
17
22
  color: #f0f0f0;
18
23
  margin: 2px 2px;
19
- font-family: ui-sans-serif, -apple-system, system-ui, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, Helvetica, "Apple Color Emoji", Arial, "Segoe UI Emoji", "Segoe UI Symbol";
24
+ /*font-family: ui-sans-serif, -apple-system, system-ui, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, Helvetica, "Apple Color Emoji", Arial, "Segoe UI Emoji", "Segoe UI Symbol";*/
20
25
  }
21
26
 
22
27
  p {
@@ -1020,3 +1025,87 @@ tbody tr {
1020
1025
  .left-side {
1021
1026
  overflow-y: auto;
1022
1027
  }
1028
+
1029
+ /* Enhanced Shell/Terminal output styling */
1030
+ pre.shellout {
1031
+ background: linear-gradient(to bottom, #2d2d2d 0%, #1e1e1e 30px, #1a1a1a 100%);
1032
+ border: 1px solid #404040;
1033
+ border-radius: 12px;
1034
+ padding: 0;
1035
+ margin: 15px 0;
1036
+ overflow-x: auto;
1037
+ max-height: 50vh;
1038
+ overflow-y: auto;
1039
+ box-shadow: 0 8px 16px rgba(0, 0, 0, 0.4),
1040
+ 0 0 0 1px rgba(255, 255, 255, 0.05) inset;
1041
+ position: relative;
1042
+ }
1043
+
1044
+ /* Mock terminal title bar */
1045
+ pre.shellout::before {
1046
+ content: '';
1047
+ display: block;
1048
+ height: 30px;
1049
+ background: linear-gradient(to bottom, #3a3a3a, #2d2d2d);
1050
+ border-bottom: 1px solid #1a1a1a;
1051
+ border-radius: 12px 12px 0 0;
1052
+ position: sticky;
1053
+ top: 0;
1054
+ z-index: 1;
1055
+ }
1056
+
1057
+ /* Terminal window controls (dots) */
1058
+ pre.shellout::after {
1059
+ content: '';
1060
+ position: absolute;
1061
+ top: 11px;
1062
+ left: 12px;
1063
+ width: 12px;
1064
+ height: 12px;
1065
+ background: #ff5f56;
1066
+ border-radius: 50%;
1067
+ box-shadow:
1068
+ 20px 0 0 #ffbd2e,
1069
+ 40px 0 0 #27c93f,
1070
+ 0 0 0 1px rgba(0, 0, 0, 0.2);
1071
+ z-index: 2;
1072
+ }
1073
+
1074
+ /* Code element inside shellout pre */
1075
+ pre.shellout code {
1076
+ background-color: transparent;
1077
+ color: #e8e8e8;
1078
+ font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', 'Monaco', monospace;
1079
+ font-size: 14px;
1080
+ line-height: 1.6;
1081
+ padding: 15px 20px;
1082
+ padding-top: 10px;
1083
+ margin: 0;
1084
+ border: none;
1085
+ white-space: pre-wrap;
1086
+ display: block;
1087
+ font-weight: 400;
1088
+ letter-spacing: 0.02em;
1089
+ }
1090
+
1091
+ /* Custom scrollbar for terminal */
1092
+ pre.shellout::-webkit-scrollbar {
1093
+ width: 10px;
1094
+ height: 10px;
1095
+ }
1096
+
1097
+ pre.shellout::-webkit-scrollbar-track {
1098
+ background: #1a1a1a;
1099
+ border-radius: 0 0 12px 0;
1100
+ }
1101
+
1102
+ pre.shellout::-webkit-scrollbar-thumb {
1103
+ background: #404040;
1104
+ border-radius: 5px;
1105
+ border: 2px solid #1a1a1a;
1106
+ }
1107
+
1108
+ pre.shellout::-webkit-scrollbar-thumb:hover {
1109
+ background: #4a4a4a;
1110
+ }
1111
+