mindroot 10.5.0__py3-none-any.whl → 10.7.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.
- mindroot/coreplugins/admin/static/js/agent-form.js +26 -1
- mindroot/coreplugins/admin/static/js/persona-editor.js +14 -1
- mindroot/coreplugins/agent/agent.py +43 -12
- mindroot/coreplugins/agent/buagentz1.py +540 -0
- mindroot/coreplugins/chat/buservices.py +625 -0
- mindroot/coreplugins/chat/commands.py +4 -0
- mindroot/coreplugins/chat/services.py +136 -8
- mindroot/coreplugins/chat/templates/chat.jinja2 +4 -0
- mindroot/lib/chatcontext.py +1 -0
- mindroot/lib/chatlog.py +40 -0
- {mindroot-10.5.0.dist-info → mindroot-10.7.0.dist-info}/METADATA +1 -1
- {mindroot-10.5.0.dist-info → mindroot-10.7.0.dist-info}/RECORD +16 -14
- {mindroot-10.5.0.dist-info → mindroot-10.7.0.dist-info}/WHEEL +0 -0
- {mindroot-10.5.0.dist-info → mindroot-10.7.0.dist-info}/entry_points.txt +0 -0
- {mindroot-10.5.0.dist-info → mindroot-10.7.0.dist-info}/licenses/LICENSE +0 -0
- {mindroot-10.5.0.dist-info → mindroot-10.7.0.dist-info}/top_level.txt +0 -0
|
@@ -658,7 +658,14 @@ class AgentForm extends BaseEl {
|
|
|
658
658
|
}
|
|
659
659
|
console.log('before',this.agent)
|
|
660
660
|
// Handle all other inputs
|
|
661
|
-
|
|
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:
|
|
@@ -143,9 +143,14 @@ class Agent:
|
|
|
143
143
|
|
|
144
144
|
async def handle_cmds(self, cmd_name, cmd_args, json_cmd=None, context=None):
|
|
145
145
|
# Check both permanent finish and temporary cancellation
|
|
146
|
-
if context.data.get('
|
|
147
|
-
logger.warning("
|
|
148
|
-
print("\033[
|
|
146
|
+
if context.data.get('cancel_current_turn'):
|
|
147
|
+
logger.warning("Turn cancelled, not executing command")
|
|
148
|
+
print("\033[91mTurn cancelled, not executing command\033[0m")
|
|
149
|
+
raise asyncio.CancelledError("Turn cancelled")
|
|
150
|
+
|
|
151
|
+
if context.data.get('finished_conversation'):
|
|
152
|
+
logger.warning("Conversation finished, not executing command")
|
|
153
|
+
print("\033[91mConversation finished, not executing command\033[0m")
|
|
149
154
|
return None
|
|
150
155
|
|
|
151
156
|
logger.info("Command execution: {command}", command=cmd_name)
|
|
@@ -298,19 +303,23 @@ class Agent:
|
|
|
298
303
|
|
|
299
304
|
# Check for cancellation (either permanent or current turn)
|
|
300
305
|
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
306
|
logger.warning("Conversation is finished or halted, exiting stream parsing")
|
|
305
307
|
debug_box(f"""Conversation is finished or halted, exiting stream""")
|
|
306
308
|
debug_box(str(context))
|
|
307
|
-
|
|
309
|
+
|
|
310
|
+
# Add partial command to chat log if present
|
|
308
311
|
if partial_cmd is not None:
|
|
309
312
|
cmd_name = next(iter(partial_cmd))
|
|
310
313
|
if cmd_name in ["say", "json_encoded_md", "think"]:
|
|
311
314
|
context.chat_log.add_message({"role": "assistant", "content": str(partial_cmd[cmd_name])})
|
|
312
315
|
else:
|
|
313
316
|
context.chat_log.add_message({"role": "assistant", "content": str(partial_cmd) + "(Interrupted)"})
|
|
317
|
+
|
|
318
|
+
# Clear the temporary cancel flag so next turn can proceed
|
|
319
|
+
if 'cancel_current_turn' in context.data:
|
|
320
|
+
del context.data['cancel_current_turn']
|
|
321
|
+
await context.save_context()
|
|
322
|
+
|
|
314
323
|
try:
|
|
315
324
|
stream.close()
|
|
316
325
|
except Exception as e:
|
|
@@ -339,14 +348,15 @@ class Agent:
|
|
|
339
348
|
cmd_args = cmd[cmd_name]
|
|
340
349
|
logger.debug(f"Processing command: {cmd}")
|
|
341
350
|
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
|
|
351
|
+
|
|
344
352
|
cmd_task = asyncio.create_task(
|
|
345
353
|
self.handle_cmds(cmd_name, cmd_args, json_cmd=json.dumps(cmd), context=context)
|
|
346
354
|
)
|
|
347
355
|
context.data['active_command_task'] = cmd_task
|
|
348
356
|
try:
|
|
349
357
|
result = await cmd_task
|
|
358
|
+
except asyncio.CancelledError:
|
|
359
|
+
raise # Propagate cancellation up
|
|
350
360
|
finally:
|
|
351
361
|
# Clear the task from context once it's done or cancelled
|
|
352
362
|
if context.data.get('active_command_task') == cmd_task:
|
|
@@ -355,6 +365,14 @@ class Agent:
|
|
|
355
365
|
await context.command_result(cmd_name, result)
|
|
356
366
|
sys_header = "Note: tool command results follow, not user replies"
|
|
357
367
|
sys_header = ""
|
|
368
|
+
|
|
369
|
+
if result == "SYSTEM: WARNING - Command interrupted!\n\n":
|
|
370
|
+
logger.warning("Command was interrupted. Stopping processing.")
|
|
371
|
+
await context.chat_log.drop_last('assistant')
|
|
372
|
+
break
|
|
373
|
+
return results, full_cmds
|
|
374
|
+
|
|
375
|
+
|
|
358
376
|
full_cmds.append({ "SYSTEM": sys_header, "cmd": cmd_name, "args": cmd_args, "result": result})
|
|
359
377
|
if result is not None:
|
|
360
378
|
results.append({"SYSTEM": sys_header, "cmd": cmd_name, "args": { "omitted": "(see command msg.)"}, "result": result})
|
|
@@ -473,6 +491,7 @@ class Agent:
|
|
|
473
491
|
tmp_data = { "messages": new_messages }
|
|
474
492
|
debug_box("Filtering messages")
|
|
475
493
|
#debug_box(tmp_data)
|
|
494
|
+
|
|
476
495
|
tmp_data = await pipeline_manager.filter_messages(tmp_data, context=context)
|
|
477
496
|
new_messages = tmp_data['messages']
|
|
478
497
|
except Exception as e:
|
|
@@ -487,18 +506,30 @@ class Agent:
|
|
|
487
506
|
if not isinstance(context.agent, dict):
|
|
488
507
|
context.agent = await get_agent_data(context.agent, context=context)
|
|
489
508
|
|
|
509
|
+
if 'max_tokens' in context.agent and context.agent['max_tokens'] is not None and context.agent['max_tokens'] != '':
|
|
510
|
+
logger.info(f"Using agent max tokens {max_tokens}")
|
|
511
|
+
max_tokens = context.agent['max_tokens']
|
|
512
|
+
else:
|
|
513
|
+
logger.info(f"Using default max tokens {max_tokens}")
|
|
514
|
+
|
|
490
515
|
if model is None:
|
|
491
516
|
if 'service_models' in context.agent and context.agent['service_models'] is not None:
|
|
492
517
|
if context.agent['service_models'].get('stream_chat', None) is None:
|
|
493
518
|
model = os.environ.get("DEFAULT_LLM_MODEL")
|
|
494
|
-
|
|
519
|
+
|
|
520
|
+
# we need to be able to abort this task if necessary
|
|
495
521
|
stream = await context.stream_chat(model,
|
|
496
522
|
temperature=temperature,
|
|
497
523
|
max_tokens=max_tokens,
|
|
498
524
|
messages=new_messages,
|
|
499
525
|
context=context)
|
|
500
|
-
|
|
501
|
-
|
|
526
|
+
|
|
527
|
+
try:
|
|
528
|
+
ret, full_cmds = await self.parse_cmd_stream(stream, context)
|
|
529
|
+
except asyncio.CancelledError:
|
|
530
|
+
logger.info("Command stream parsing cancelled")
|
|
531
|
+
raise # Propagate cancellation
|
|
532
|
+
|
|
502
533
|
logger.debug("System message was:")
|
|
503
534
|
logger.debug(await self.render_system_msg())
|
|
504
535
|
|