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.
- 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 +46 -21
- mindroot/coreplugins/agent/buagentz1.py +540 -0
- mindroot/coreplugins/agent/speech_to_speech.py +77 -0
- mindroot/coreplugins/agent/speech_to_speech.py.backup +46 -0
- mindroot/coreplugins/chat/buservices.py +625 -0
- mindroot/coreplugins/chat/commands.py +4 -0
- mindroot/coreplugins/chat/services.py +116 -10
- mindroot/coreplugins/chat/static/css/dark.css +90 -1
- mindroot/coreplugins/chat/static/css/default.css +90 -1
- mindroot/coreplugins/chat/static/css/light.css +724 -0
- mindroot/coreplugins/chat/static/js/chat.js +114 -86
- mindroot/coreplugins/chat/static/js/throttle.js +4 -2
- mindroot/coreplugins/chat/templates/chat.jinja2 +8 -0
- mindroot/lib/chatcontext.py +1 -0
- mindroot/lib/chatlog.py +40 -0
- mindroot/lib/logging/logfiles.py +1 -0
- {mindroot-10.5.0.dist-info → mindroot-10.14.0.dist-info}/METADATA +1 -1
- {mindroot-10.5.0.dist-info → mindroot-10.14.0.dist-info}/RECORD +24 -19
- {mindroot-10.5.0.dist-info → mindroot-10.14.0.dist-info}/WHEEL +0 -0
- {mindroot-10.5.0.dist-info → mindroot-10.14.0.dist-info}/entry_points.txt +0 -0
- {mindroot-10.5.0.dist-info → mindroot-10.14.0.dist-info}/licenses/LICENSE +0 -0
- {mindroot-10.5.0.dist-info → mindroot-10.14.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:
|
|
@@ -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('
|
|
147
|
-
logger.warning("
|
|
148
|
-
print("\033[
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|