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.
@@ -658,7 +658,14 @@ class AgentForm extends BaseEl {
658
658
  }
659
659
  console.log('before',this.agent)
660
660
  // Handle all other inputs
661
- const inputValue = type === 'checkbox' ? checked : value;
661
+ let inputValue;
662
+ if (type === 'checkbox') {
663
+ inputValue = checked;
664
+ } else if (type === 'number') {
665
+ inputValue = value === '' ? null : Number(value);
666
+ } else {
667
+ inputValue = value;
668
+ }
662
669
  this.agent = { ...this.agent, [name]: inputValue };
663
670
  console.log('after', this.agent)
664
671
  }
@@ -1273,6 +1280,24 @@ class AgentForm extends BaseEl {
1273
1280
  </details>
1274
1281
  </div>
1275
1282
 
1283
+ <div class="form-group commands-section">
1284
+ <details>
1285
+ <summary>Max Tokens</summary>
1286
+ <div class="commands-category">
1287
+ <div class="form-group">
1288
+ <label>Maximum Tokens:</label>
1289
+ <input
1290
+ type="number"
1291
+ name="max_tokens"
1292
+ .value=${agentForRender.max_tokens || ''}
1293
+ placeholder="Leave empty for model default"
1294
+ @input=${this.handleInputChange}
1295
+ >
1296
+ </div>
1297
+ </div>
1298
+ </details>
1299
+ </div>
1300
+
1276
1301
  <div class="form-group commands-section">
1277
1302
  <details>
1278
1303
  <summary>Recommended Plugins</summary>
@@ -10,7 +10,8 @@ class PersonaEditor extends BaseEl {
10
10
  personas: { type: Array, reflect: true },
11
11
  newPersona: { type: Boolean, reflect: true },
12
12
  facerefFileName: { type: String, reflect: true },
13
- avatarFileName: { type: String, reflect: true }
13
+ avatarFileName: { type: String, reflect: true },
14
+ voiceId: { type: String, reflect: true }
14
15
  };
15
16
 
16
17
  static styles = [
@@ -130,6 +131,7 @@ class PersonaEditor extends BaseEl {
130
131
  this.newPersona = false;
131
132
  this.facerefFileName = '';
132
133
  this.avatarFileName = '';
134
+ this.voiceId = '';
133
135
  this.fetchPersonas();
134
136
  }
135
137
 
@@ -168,13 +170,16 @@ class PersonaEditor extends BaseEl {
168
170
  if (this.scope === 'registry') {
169
171
  // For registry personas, use the full path format
170
172
  const response = await fetch(`/personas/registry/${this.name}`);
173
+ this.voiceId = this.persona.voice_id || '';
171
174
  this.persona = await response.json();
172
175
  } else {
173
176
  const response = await fetch(`/personas/${this.scope}/${this.name}`);
174
177
  this.persona = await response.json();
178
+ this.voiceId = this.persona.voice_id || '';
175
179
  }
176
180
  } else {
177
181
  this.persona = {};
182
+ this.voiceId = '';
178
183
  }
179
184
  }
180
185
 
@@ -194,11 +199,15 @@ class PersonaEditor extends BaseEl {
194
199
  this.persona = {};
195
200
  this.facerefFileName = '';
196
201
  this.avatarFileName = '';
202
+ this.voiceId = '';
197
203
  }
198
204
 
199
205
  handleInputChange(event) {
200
206
  const { name, value, type, checked } = event.target;
201
207
  const inputValue = type === 'checkbox' ? checked : value;
208
+ if (name === 'voice_id') {
209
+ this.voiceId = value;
210
+ }
202
211
  this.persona = { ...this.persona, [name]: inputValue };
203
212
  }
204
213
 
@@ -280,6 +289,10 @@ class PersonaEditor extends BaseEl {
280
289
  <label>Negative Appearance:</label>
281
290
  <textarea class="text_lg" name="negative_appearance" .value=${this.persona.negative_appearance || ''} @input=${this.handleInputChange}></textarea>
282
291
  </div>
292
+ <div class="form-group">
293
+ <label>Voice ID:</label>
294
+ <input class="text_inp" type="text" name="voice_id" .value=${this.voiceId || ''} @input=${this.handleInputChange} placeholder="Optional voice identifier for TTS" />
295
+ </div>
283
296
  <div class="form-group">
284
297
  <label>
285
298
  Moderated:
@@ -100,6 +100,7 @@ def find_new_substring(s1, s2):
100
100
  return s2.replace(s1, '', 1)
101
101
  return s2
102
102
 
103
+
103
104
  class Agent:
104
105
 
105
106
  def __init__(self, model=None, sys_core_template=None, agent=None, clear_model=False, commands=[], context=None):
@@ -143,9 +144,14 @@ class Agent:
143
144
 
144
145
  async def handle_cmds(self, cmd_name, cmd_args, json_cmd=None, context=None):
145
146
  # Check both permanent finish and temporary cancellation
146
- if context.data.get('finished_conversation') or context.data.get('cancel_current_turn'):
147
- logger.warning("Conversation is finished, not executing command")
148
- print("\033[91mConversation is finished, not executing command\033[0m")
147
+ if context.data.get('cancel_current_turn'):
148
+ logger.warning("Turn cancelled, not executing command")
149
+ print("\033[91mTurn cancelled, not executing command\033[0m")
150
+ raise asyncio.CancelledError("Turn cancelled")
151
+
152
+ if context.data.get('finished_conversation'):
153
+ logger.warning("Conversation finished, not executing command")
154
+ print("\033[91mConversation finished, not executing command\033[0m")
149
155
  return None
150
156
 
151
157
  logger.info("Command execution: {command}", command=cmd_name)
@@ -298,19 +304,23 @@ class Agent:
298
304
 
299
305
  # Check for cancellation (either permanent or current turn)
300
306
  if context.data.get('finished_conversation') or context.data.get('cancel_current_turn'):
301
- # Clear the temporary cancel flag so next turn can proceed
302
- if 'cancel_current_turn' in context.data:
303
- del context.data['cancel_current_turn']
304
307
  logger.warning("Conversation is finished or halted, exiting stream parsing")
305
308
  debug_box(f"""Conversation is finished or halted, exiting stream""")
306
309
  debug_box(str(context))
307
- # stream is actually a generator
310
+
311
+ # Add partial command to chat log if present
308
312
  if partial_cmd is not None:
309
313
  cmd_name = next(iter(partial_cmd))
310
314
  if cmd_name in ["say", "json_encoded_md", "think"]:
311
315
  context.chat_log.add_message({"role": "assistant", "content": str(partial_cmd[cmd_name])})
312
316
  else:
313
317
  context.chat_log.add_message({"role": "assistant", "content": str(partial_cmd) + "(Interrupted)"})
318
+
319
+ # Clear the temporary cancel flag so next turn can proceed
320
+ if 'cancel_current_turn' in context.data:
321
+ del context.data['cancel_current_turn']
322
+ await context.save_context()
323
+
314
324
  try:
315
325
  stream.close()
316
326
  except Exception as e:
@@ -339,14 +349,15 @@ class Agent:
339
349
  cmd_args = cmd[cmd_name]
340
350
  logger.debug(f"Processing command: {cmd}")
341
351
  await context.partial_command(cmd_name, json.dumps(cmd_args), cmd_args)
342
-
343
- # Create a task for the command so it can be cancelled
352
+
344
353
  cmd_task = asyncio.create_task(
345
354
  self.handle_cmds(cmd_name, cmd_args, json_cmd=json.dumps(cmd), context=context)
346
355
  )
347
356
  context.data['active_command_task'] = cmd_task
348
357
  try:
349
358
  result = await cmd_task
359
+ except asyncio.CancelledError:
360
+ raise # Propagate cancellation up
350
361
  finally:
351
362
  # Clear the task from context once it's done or cancelled
352
363
  if context.data.get('active_command_task') == cmd_task:
@@ -355,6 +366,15 @@ class Agent:
355
366
  await context.command_result(cmd_name, result)
356
367
  sys_header = "Note: tool command results follow, not user replies"
357
368
  sys_header = ""
369
+
370
+ if result == "SYSTEM: WARNING - Command interrupted!\n\n":
371
+ logger.warning("Command was interrupted. Stopping processing.")
372
+ await context.chat_log.drop_last('assistant')
373
+ await asyncio.sleep(0.5)
374
+ break
375
+ return results, full_cmds
376
+
377
+
358
378
  full_cmds.append({ "SYSTEM": sys_header, "cmd": cmd_name, "args": cmd_args, "result": result})
359
379
  if result is not None:
360
380
  results.append({"SYSTEM": sys_header, "cmd": cmd_name, "args": { "omitted": "(see command msg.)"}, "result": result})
@@ -430,15 +450,7 @@ class Agent:
430
450
  "formatted_datetime": formatted_time,
431
451
  "context_data": self.context.data
432
452
  }
433
- # is say in the command_manager
434
- if 'say' in command_manager.functions.keys():
435
- print("I found say! in the functions!")
436
- else:
437
- print("Say is not in the functions!")
438
- if 'say' in data['command_docs'].keys():
439
- print("I found say in the command docs!")
440
-
441
- # we need to be doubly sure to remove anything from command_docs that is not in command_manager.functions.keys()
453
+
442
454
  for cmd in data['command_docs']:
443
455
  if cmd not in command_manager.functions.keys():
444
456
  print("Removing " + cmd + " from command_docs")
@@ -473,6 +485,7 @@ class Agent:
473
485
  tmp_data = { "messages": new_messages }
474
486
  debug_box("Filtering messages")
475
487
  #debug_box(tmp_data)
488
+
476
489
  tmp_data = await pipeline_manager.filter_messages(tmp_data, context=context)
477
490
  new_messages = tmp_data['messages']
478
491
  except Exception as e:
@@ -487,18 +500,30 @@ class Agent:
487
500
  if not isinstance(context.agent, dict):
488
501
  context.agent = await get_agent_data(context.agent, context=context)
489
502
 
503
+ if 'max_tokens' in context.agent and context.agent['max_tokens'] is not None and context.agent['max_tokens'] != '':
504
+ logger.info(f"Using agent max tokens {max_tokens}")
505
+ max_tokens = context.agent['max_tokens']
506
+ else:
507
+ logger.info(f"Using default max tokens {max_tokens}")
508
+
490
509
  if model is None:
491
510
  if 'service_models' in context.agent and context.agent['service_models'] is not None:
492
511
  if context.agent['service_models'].get('stream_chat', None) is None:
493
512
  model = os.environ.get("DEFAULT_LLM_MODEL")
494
-
513
+
514
+ # we need to be able to abort this task if necessary
495
515
  stream = await context.stream_chat(model,
496
516
  temperature=temperature,
497
517
  max_tokens=max_tokens,
498
518
  messages=new_messages,
499
519
  context=context)
500
-
501
- ret, full_cmds = await self.parse_cmd_stream(stream, context)
520
+
521
+ try:
522
+ ret, full_cmds = await self.parse_cmd_stream(stream, context)
523
+ except asyncio.CancelledError:
524
+ logger.info("Command stream parsing cancelled")
525
+ raise # Propagate cancellation
526
+
502
527
  logger.debug("System message was:")
503
528
  logger.debug(await self.render_system_msg())
504
529