mindroot 8.6.0__py3-none-any.whl → 8.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.
- mindroot/coreplugins/admin/static/js/agent-editor.js +11 -76
- mindroot/coreplugins/admin/static/js/agent-form.js +374 -262
- mindroot/coreplugins/admin/static/js/backup/agent-editor.js +186 -0
- mindroot/coreplugins/admin/static/js/backup/agent-form.js +1133 -0
- mindroot/coreplugins/admin/static/js/backup/agent-list.js +94 -0
- mindroot/lib/plugins/default_plugin_manifest.json +4 -0
- {mindroot-8.6.0.dist-info → mindroot-8.8.0.dist-info}/METADATA +1 -1
- {mindroot-8.6.0.dist-info → mindroot-8.8.0.dist-info}/RECORD +12 -9
- {mindroot-8.6.0.dist-info → mindroot-8.8.0.dist-info}/WHEEL +0 -0
- {mindroot-8.6.0.dist-info → mindroot-8.8.0.dist-info}/entry_points.txt +0 -0
- {mindroot-8.6.0.dist-info → mindroot-8.8.0.dist-info}/licenses/LICENSE +0 -0
- {mindroot-8.6.0.dist-info → mindroot-8.8.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,1133 @@
|
|
|
1
|
+
import { LitElement, html, css } from './lit-core.min.js';
|
|
2
|
+
import { BaseEl } from './base.js';
|
|
3
|
+
import './toggle-switch.js';
|
|
4
|
+
import { unsafeHTML } from '../../../chat/static/js/lit-html/directives/unsafe-html.js';
|
|
5
|
+
import './missing-commands.js';
|
|
6
|
+
import {markdownRenderer} from './markdown-renderer.js';
|
|
7
|
+
import showNotification from './notification.js';
|
|
8
|
+
import './indexed-agents.js';
|
|
9
|
+
|
|
10
|
+
class AgentForm extends BaseEl {
|
|
11
|
+
static properties = {
|
|
12
|
+
agent: { type: Object },
|
|
13
|
+
newAgent: { type: Boolean },
|
|
14
|
+
loading: { type: Boolean },
|
|
15
|
+
personas: { type: Array },
|
|
16
|
+
commands: { type: Object },
|
|
17
|
+
serviceModels: { type: Object },
|
|
18
|
+
missingCommands: { type: Object },
|
|
19
|
+
pendingPlugins: { type: Array },
|
|
20
|
+
showInstructionsEditor: { type: Boolean },
|
|
21
|
+
showTechnicalInstructionsEditor: { type: Boolean },
|
|
22
|
+
indexedAgentsVisible: { type: Boolean }
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
static styles = css`
|
|
26
|
+
:host {
|
|
27
|
+
display: block;
|
|
28
|
+
margin-top: 20px;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.agent-form {
|
|
32
|
+
padding: 15px;
|
|
33
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
34
|
+
border-radius: 8px;
|
|
35
|
+
background: rgba(255, 255, 255, 0.02);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.form-group {
|
|
39
|
+
margin-bottom: 15px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.form-group label {
|
|
43
|
+
display: block;
|
|
44
|
+
margin-bottom: 5px;
|
|
45
|
+
color: #f0f0f0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.required::after {
|
|
49
|
+
content: " *";
|
|
50
|
+
color: #e57373;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
summary::before {
|
|
54
|
+
content: "\u25b6";
|
|
55
|
+
display: inline-block;
|
|
56
|
+
margin-right: 5px;
|
|
57
|
+
transition: transform 0.2s;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
details[open] > summary::before { transform: rotate(90deg); }
|
|
61
|
+
|
|
62
|
+
details > * :not(summary) {
|
|
63
|
+
user-select: none;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.form-group-header {
|
|
67
|
+
display: flex;
|
|
68
|
+
align-items: center;
|
|
69
|
+
justify-content: space-between;
|
|
70
|
+
margin-bottom: 5px;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.form-group-actions {
|
|
74
|
+
display: flex;
|
|
75
|
+
gap: 8px;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.markdown-preview {
|
|
79
|
+
background: rgba(255, 255, 255, 0.05);
|
|
80
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
81
|
+
border-radius: 6px;
|
|
82
|
+
padding: 12px;
|
|
83
|
+
min-height: 100px;
|
|
84
|
+
color: #f0f0f0;
|
|
85
|
+
margin-bottom: 10px;
|
|
86
|
+
max-height: 400px;
|
|
87
|
+
overflow-y: auto;
|
|
88
|
+
overflow-x: hidden;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.markdown-preview ul {
|
|
92
|
+
padding-left: 20px;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.markdown-preview li {
|
|
96
|
+
margin-bottom: 5px;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.markdown-preview ul {
|
|
100
|
+
list-style-type: none;
|
|
101
|
+
padding-left: 0;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.markdown-preview input[type="checkbox"] {
|
|
105
|
+
margin-right: 8px;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.markdown-preview h1, .markdown-preview h2, .markdown-preview h3,
|
|
109
|
+
.markdown-preview h4, .markdown-preview h5, .markdown-preview h6 {
|
|
110
|
+
background: transparent;
|
|
111
|
+
border: none;
|
|
112
|
+
padding: 0;
|
|
113
|
+
margin-top: 1em;
|
|
114
|
+
margin-bottom: 0.5em;
|
|
115
|
+
font-weight: bold;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* Edit button for full-width display */
|
|
119
|
+
.edit-button {
|
|
120
|
+
background: transparent;
|
|
121
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
122
|
+
color: #f0f0f0;
|
|
123
|
+
border-radius: 4px;
|
|
124
|
+
padding: 4px 8px;
|
|
125
|
+
cursor: pointer;
|
|
126
|
+
display: flex;
|
|
127
|
+
align-items: center;
|
|
128
|
+
gap: 5px;
|
|
129
|
+
margin-bottom: 10px;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* Icon button for header */
|
|
133
|
+
.icon-button {
|
|
134
|
+
background: transparent;
|
|
135
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
136
|
+
color: #f0f0f0;
|
|
137
|
+
border-radius: 4px;
|
|
138
|
+
padding: 4px;
|
|
139
|
+
cursor: pointer;
|
|
140
|
+
display: flex;
|
|
141
|
+
align-items: center;
|
|
142
|
+
justify-content: center;
|
|
143
|
+
width: 30px;
|
|
144
|
+
height: 30px;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.edit-button:hover {
|
|
148
|
+
background: rgba(255, 255, 255, 0.1);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.icon-button:hover {
|
|
152
|
+
background: rgba(255, 255, 255, 0.1);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
input[type="text"],
|
|
156
|
+
select,
|
|
157
|
+
textarea {
|
|
158
|
+
width: 100%;
|
|
159
|
+
padding: 8px 12px;
|
|
160
|
+
background: rgba(255, 255, 255, 0.05);
|
|
161
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
162
|
+
border-radius: 6px;
|
|
163
|
+
color: #f0f0f0;
|
|
164
|
+
font-size: 0.95rem;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
textarea {
|
|
168
|
+
min-height: 60vh;
|
|
169
|
+
max-height: 60vh;
|
|
170
|
+
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
textarea::-webkit-scrollbar {
|
|
174
|
+
width: 8px; /* Medium-thin width */
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
textarea::-webkit-scrollbar-track {
|
|
178
|
+
background: #222; /* Dark background */
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
textarea::-webkit-scrollbar-thumb {
|
|
182
|
+
background: #666; /* Medium gray scrollbar handle */
|
|
183
|
+
border-radius: 4px;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
textarea::-webkit-scrollbar-thumb:hover {
|
|
187
|
+
background: #999; /* Lighter on hover */
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
textarea {
|
|
191
|
+
scrollbar-width: thin;
|
|
192
|
+
scrollbar-color: #666 #222;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
input[type="text"]:focus,
|
|
196
|
+
select:focus,
|
|
197
|
+
textarea:focus {
|
|
198
|
+
outline: none;
|
|
199
|
+
border-color: rgba(255, 255, 255, 0.2);
|
|
200
|
+
background: rgba(255, 255, 255, 0.08);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.commands-section {
|
|
204
|
+
margin-top: 20px;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.commands-category {
|
|
208
|
+
margin-bottom: 20px;
|
|
209
|
+
background: rgba(255, 255, 255, 0.02);
|
|
210
|
+
border-radius: 8px;
|
|
211
|
+
padding: 15px;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.commands-category h4 {
|
|
215
|
+
margin-bottom: 15px;
|
|
216
|
+
color: #f0f0f0;
|
|
217
|
+
font-size: 1.1rem;
|
|
218
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
|
219
|
+
padding-bottom: 8px;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.commands-grid {
|
|
223
|
+
display: grid;
|
|
224
|
+
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
|
225
|
+
gap: 12px;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.command-item {
|
|
229
|
+
display: flex;
|
|
230
|
+
align-items: center;
|
|
231
|
+
justify-content: space-between;
|
|
232
|
+
padding: 8px 12px;
|
|
233
|
+
background: rgba(255, 255, 255, 0.05);
|
|
234
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
235
|
+
border-radius: 6px;
|
|
236
|
+
cursor: pointer;
|
|
237
|
+
transition: all 0.2s;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.command-item:hover {
|
|
241
|
+
background: rgba(255, 255, 255, 0.08);
|
|
242
|
+
border-color: rgba(255, 255, 255, 0.2);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.command-info {
|
|
246
|
+
flex: 1;
|
|
247
|
+
margin-right: 12px;
|
|
248
|
+
position: relative;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.command-name {
|
|
252
|
+
color: #f0f0f0;
|
|
253
|
+
font-weight: 500;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.tooltip-text {
|
|
257
|
+
visibility: hidden;
|
|
258
|
+
position: absolute;
|
|
259
|
+
z-index: 1;
|
|
260
|
+
left: 0;
|
|
261
|
+
top: 100%;
|
|
262
|
+
margin-top: 10px;
|
|
263
|
+
width: 250px;
|
|
264
|
+
background-color: rgba(0, 0, 0, 0.9);
|
|
265
|
+
color: #fff;
|
|
266
|
+
text-align: left;
|
|
267
|
+
padding: 8px 12px;
|
|
268
|
+
border-radius: 6px;
|
|
269
|
+
font-size: 0.9em;
|
|
270
|
+
line-height: 1.4;
|
|
271
|
+
white-space: normal;
|
|
272
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.command-info:hover .tooltip-text {
|
|
276
|
+
visibility: visible;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.btn {
|
|
280
|
+
padding: 8px 16px;
|
|
281
|
+
background: #2196F3;
|
|
282
|
+
border: none;
|
|
283
|
+
border-radius: 4px;
|
|
284
|
+
color: white;
|
|
285
|
+
cursor: pointer;
|
|
286
|
+
font-size: 0.95rem;
|
|
287
|
+
transition: all 0.2s;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.btn:hover {
|
|
291
|
+
background: #1976D2;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.btn:disabled {
|
|
295
|
+
opacity: 0.5;
|
|
296
|
+
cursor: not-allowed;
|
|
297
|
+
}
|
|
298
|
+
`;
|
|
299
|
+
|
|
300
|
+
constructor() {
|
|
301
|
+
super();
|
|
302
|
+
this.attachShadow({mode: 'open'});
|
|
303
|
+
this.personas = [];
|
|
304
|
+
this.commands = {};
|
|
305
|
+
this.showInstructionsEditor = false;
|
|
306
|
+
this.loading = false;
|
|
307
|
+
this.plugins = [];
|
|
308
|
+
this.providerMapping = {}; // Map display names to module names
|
|
309
|
+
this.agent = {
|
|
310
|
+
commands: [],
|
|
311
|
+
name: '',
|
|
312
|
+
hashver: '',
|
|
313
|
+
preferred_providers: [],
|
|
314
|
+
thinking_level: 'off', // Default to medium
|
|
315
|
+
persona: '',
|
|
316
|
+
recommended_plugins: []
|
|
317
|
+
};
|
|
318
|
+
this.showTechnicalInstructionsEditor = false;
|
|
319
|
+
this.newAgent = false;
|
|
320
|
+
this.pendingPlugins = [];
|
|
321
|
+
this.fetchPersonas();
|
|
322
|
+
this.resetEditors();
|
|
323
|
+
this.fetchCommands();
|
|
324
|
+
this.fetchServiceModels();
|
|
325
|
+
this.fetchPlugins();
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
async fetchMissingCommands() {
|
|
329
|
+
if (!this.agent.name) return;
|
|
330
|
+
|
|
331
|
+
// Skip API call for new agents that haven't been saved yet
|
|
332
|
+
if (this.newAgent) {
|
|
333
|
+
this.missingCommands = {};
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
try {
|
|
338
|
+
const response = await fetch(`/admin/missing-commands/${this.agent.name}`);
|
|
339
|
+
if (!response.ok) throw new Error('Failed to fetch missing commands');
|
|
340
|
+
this.missingCommands = await response.json();
|
|
341
|
+
console.log('Fetched missing commands:', this.missingCommands);
|
|
342
|
+
this.requestUpdate();
|
|
343
|
+
} catch (error) {
|
|
344
|
+
this.missingCommands = {};
|
|
345
|
+
console.log(`Error fetching missing commands: ${error.message}`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
updated(changedProperties) {
|
|
350
|
+
// Handle newAgent property changes
|
|
351
|
+
if (changedProperties.has('newAgent')) {
|
|
352
|
+
console.log('newAgent changed to:', this.newAgent);
|
|
353
|
+
if (this.newAgent) {
|
|
354
|
+
// Initialize empty agent with defaults for new agent
|
|
355
|
+
this.agent = {
|
|
356
|
+
...this.agent,
|
|
357
|
+
commands: this.agent.commands || [],
|
|
358
|
+
preferred_providers: this.agent.preferred_providers || [],
|
|
359
|
+
recommended_plugins: this.agent.recommended_plugins || []
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
console.log('Updated with changes:', changedProperties);
|
|
365
|
+
super.updated(changedProperties);
|
|
366
|
+
if (changedProperties.has('agent')) {
|
|
367
|
+
console.log('Agent updated:', this.agent);
|
|
368
|
+
// Force select element to update
|
|
369
|
+
const select = this.shadowRoot.querySelector('select[name="persona"]');
|
|
370
|
+
if (select && this.agent.persona) {
|
|
371
|
+
select.value = this.agent.persona;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (this.agent.name) {
|
|
375
|
+
this.fetchMissingCommands();
|
|
376
|
+
this.checkRecommendedPlugins();
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
resetEditors() {
|
|
382
|
+
this.showInstructionsEditor = false;
|
|
383
|
+
this.showTechnicalInstructionsEditor = false;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
async fetchServiceModels() {
|
|
387
|
+
try {
|
|
388
|
+
const response = await fetch('/service-models');
|
|
389
|
+
if (!response.ok) throw new Error('Failed to fetch service models');
|
|
390
|
+
const data = await response.json();
|
|
391
|
+
this.serviceModels = data;
|
|
392
|
+
console.log('Fetched service models:', this.serviceModels);
|
|
393
|
+
// now re-render everything (force)
|
|
394
|
+
this.requestUpdate();
|
|
395
|
+
} catch (error) {
|
|
396
|
+
showNotification('error', `Error loading service models: ${error.message}`);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Fetch available personas
|
|
401
|
+
async fetchPersonas() {
|
|
402
|
+
try {
|
|
403
|
+
const response = await fetch('/personas/local');
|
|
404
|
+
if (!response.ok) throw new Error('Failed to fetch personas');
|
|
405
|
+
this.personas = await response.json();
|
|
406
|
+
console.log('Fetched personas:', this.personas);
|
|
407
|
+
console.log('Current agent persona:', this.agent.persona);
|
|
408
|
+
} catch (error) {
|
|
409
|
+
showNotification('error', `Error loading personas: ${error.message}`);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
async fetchPlugins() {
|
|
414
|
+
try {
|
|
415
|
+
const response = await fetch('/plugin-manager/get-all-plugins');
|
|
416
|
+
if (!response.ok) throw new Error('Failed to fetch plugins');
|
|
417
|
+
const result = await response.json();
|
|
418
|
+
this.plugins = result.data.filter(plugin => plugin.enabled);
|
|
419
|
+
console.log('Fetched plugins:', this.plugins);
|
|
420
|
+
|
|
421
|
+
// Add category (module name) for each plugin if available
|
|
422
|
+
for (const plugin of this.plugins) {
|
|
423
|
+
let name = plugin.name;
|
|
424
|
+
if (plugin.source_path) {
|
|
425
|
+
plugin.source = plugin.source_path
|
|
426
|
+
name = plugin.source_path.split('/').filter(Boolean).pop();
|
|
427
|
+
}
|
|
428
|
+
if (plugin.github_url) {
|
|
429
|
+
plugin.source = plugin.github_url
|
|
430
|
+
}
|
|
431
|
+
const uniqueId = name.replace(/[^a-zA-Z0-9]/g, '_');
|
|
432
|
+
name = uniqueId;
|
|
433
|
+
plugin.name = name
|
|
434
|
+
plugin._uniqueId = uniqueId;
|
|
435
|
+
plugin._id = uniqueId
|
|
436
|
+
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
} catch (error) {
|
|
440
|
+
showNotification('error', `Error loading plugins: ${error.message}`);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
renderMarkdown(text) {
|
|
445
|
+
return markdownRenderer.parse(text);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
async checkRecommendedPlugins() {
|
|
450
|
+
if (!this.agent.name || !this.agent.recommended_plugins || this.agent.recommended_plugins.length === 0) {
|
|
451
|
+
this.pendingPlugins = [];
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Skip API call for new agents that haven't been saved yet
|
|
456
|
+
if (this.newAgent) {
|
|
457
|
+
this.pendingPlugins = [];
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
try {
|
|
462
|
+
// Check which recommended plugins are not installed
|
|
463
|
+
const response = await fetch(`/admin/check-recommended-plugins/${this.agent.name}`);
|
|
464
|
+
if (!response.ok) throw new Error('Failed to check recommended plugins');
|
|
465
|
+
const result = await response.json();
|
|
466
|
+
|
|
467
|
+
if (result.pending_plugins) {
|
|
468
|
+
this.pendingPlugins = result.pending_plugins;
|
|
469
|
+
} else {
|
|
470
|
+
this.pendingPlugins = [];
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
console.log('Pending plugins:', this.pendingPlugins);
|
|
474
|
+
this.requestUpdate();
|
|
475
|
+
} catch (error) {
|
|
476
|
+
console.log(`Error checking recommended plugins: ${error.message}`);
|
|
477
|
+
this.pendingPlugins = [];
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
async installRecommendedPlugins() {
|
|
482
|
+
const response = await fetch(`/admin/install-recommended-plugins/${this.agent.name}`, {
|
|
483
|
+
method: 'POST'
|
|
484
|
+
});
|
|
485
|
+
const result = await response.json();
|
|
486
|
+
showNotification('success', 'Recommended plugins installed. Please refresh the page to see the changes.');
|
|
487
|
+
this.checkRecommendedPlugins();
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
async fetchCommands() {
|
|
491
|
+
try {
|
|
492
|
+
const response = await fetch('/commands');
|
|
493
|
+
if (!response.ok) throw new Error('Failed to fetch commands');
|
|
494
|
+
const data = await response.json();
|
|
495
|
+
this.commands = this.organizeCommands(data);
|
|
496
|
+
} catch (error) {
|
|
497
|
+
showNotification('error', `Error loading commands: ${error.message}`);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
organizeCommands(commands) {
|
|
502
|
+
const grouped = {};
|
|
503
|
+
for (const [cmdName, cmdInfoArray] of Object.entries(commands)) {
|
|
504
|
+
const cmdInfo = cmdInfoArray[0];
|
|
505
|
+
const provider = cmdInfo.provider || 'Other';
|
|
506
|
+
if (!grouped[provider]) {
|
|
507
|
+
grouped[provider] = [];
|
|
508
|
+
this.plugins.push(provider)
|
|
509
|
+
}
|
|
510
|
+
grouped[provider].push({
|
|
511
|
+
name: cmdName,
|
|
512
|
+
provider,
|
|
513
|
+
providerName: provider,
|
|
514
|
+
docstring: cmdInfo.docstring,
|
|
515
|
+
flags: cmdInfo.flags,
|
|
516
|
+
uniqueId: `${cmdName}_${provider}`.replace(/[^a-zA-Z0-9]/g, '_')
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
this.providerMapping[provider] = provider;
|
|
520
|
+
}
|
|
521
|
+
return grouped;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
handleInputChange(event) {
|
|
525
|
+
const { name, value, type, checked } = event.target;
|
|
526
|
+
console.log({name, value, type})
|
|
527
|
+
if (name === 'commands') {
|
|
528
|
+
if (!Array.isArray(this.agent.commands)) {
|
|
529
|
+
this.agent.commands = [];
|
|
530
|
+
}
|
|
531
|
+
if (checked) {
|
|
532
|
+
this.agent.commands.push(value);
|
|
533
|
+
} else {
|
|
534
|
+
this.agent.commands = this.agent.commands.filter(command => command !== value);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// Update the entire agent object WITHOUT overwriting commands
|
|
538
|
+
this.agent = { ...this.agent };
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// Handle required_plugins similar to commands
|
|
543
|
+
if (name === 'recommended_plugins') {
|
|
544
|
+
if (!this.agent.recommended_plugins || !Array.isArray(this.agent.recommended_plugins)) {
|
|
545
|
+
this.agent.recommended_plugins = [];
|
|
546
|
+
}
|
|
547
|
+
if (checked) {
|
|
548
|
+
this.agent.recommended_plugins.push(value);
|
|
549
|
+
} else {
|
|
550
|
+
this.agent.recommended_plugins = this.agent.recommended_plugins.filter(plugin => plugin !== value);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
this.agent = { ...this.agent };
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
console.log('before',this.agent)
|
|
557
|
+
// Handle all other inputs
|
|
558
|
+
const inputValue = type === 'checkbox' ? checked : value;
|
|
559
|
+
this.agent = { ...this.agent, [name]: inputValue };
|
|
560
|
+
console.log('after', this.agent)
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
handlePreferredProviderChange(e) {
|
|
564
|
+
const { value, checked, id } = e.detail || e.target;
|
|
565
|
+
console.log(`Preferred provider change: ID=${id || 'unknown'} Value=${value}, Checked=${checked}`);
|
|
566
|
+
|
|
567
|
+
// Ensure preferred_providers is always an array
|
|
568
|
+
if (!Array.isArray(this.agent.preferred_providers)) {
|
|
569
|
+
this.agent.preferred_providers = [];
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
let preferred_providers = [...this.agent.preferred_providers];
|
|
573
|
+
|
|
574
|
+
if (checked) {
|
|
575
|
+
if (!preferred_providers.includes(id)) {
|
|
576
|
+
preferred_providers.push(id);
|
|
577
|
+
console.log(`Added ${id} to preferred_providers: ${preferred_providers.join(', ')}`);
|
|
578
|
+
}
|
|
579
|
+
} else {
|
|
580
|
+
const index = preferred_providers.indexOf(id);
|
|
581
|
+
if (index !== -1) preferred_providers.splice(index, 1);
|
|
582
|
+
console.log(`Removed ${id} from preferred_providers: ${preferred_providers.join(', ')}`);
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
this.agent = { ...this.agent, preferred_providers };
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
validateForm() {
|
|
589
|
+
// Get current form values to ensure we're validating the latest state
|
|
590
|
+
const nameInput = this.shadowRoot.querySelector('input[name="name"]');
|
|
591
|
+
const personaSelect = this.shadowRoot.querySelector('select[name="persona"]');
|
|
592
|
+
const instructionsTextarea = this.shadowRoot.querySelector('textarea[name="instructions"]');
|
|
593
|
+
|
|
594
|
+
const currentName = nameInput?.value || this.agent.name;
|
|
595
|
+
const currentPersona = personaSelect?.value || this.agent.persona;
|
|
596
|
+
const currentInstructions = instructionsTextarea?.value || this.agent.instructions;
|
|
597
|
+
|
|
598
|
+
if (!currentName?.trim()) {
|
|
599
|
+
showNotification('error', 'Name is required');
|
|
600
|
+
return false;
|
|
601
|
+
}
|
|
602
|
+
if (!currentPersona?.trim()) {
|
|
603
|
+
showNotification('error', 'Persona is required');
|
|
604
|
+
return false;
|
|
605
|
+
}
|
|
606
|
+
if (!currentInstructions?.trim()) {
|
|
607
|
+
showNotification('error', 'Instructions are required');
|
|
608
|
+
return false;
|
|
609
|
+
}
|
|
610
|
+
return true;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
async handleSubmit(event) { // Complete replacement of method
|
|
614
|
+
event?.preventDefault();
|
|
615
|
+
|
|
616
|
+
// Check if this is a partial save (from instruction save buttons)
|
|
617
|
+
const isPartialSave = event?.submitter?.classList.contains('partial-save') ||
|
|
618
|
+
(event?.target?.classList.contains('icon-button') &&
|
|
619
|
+
(this.showInstructionsEditor || this.showTechnicalInstructionsEditor));
|
|
620
|
+
|
|
621
|
+
// For partial saves, update the agent with current textarea values before saving
|
|
622
|
+
if (isPartialSave) {
|
|
623
|
+
if (this.showInstructionsEditor) {
|
|
624
|
+
const instructionsTextarea = this.shadowRoot.querySelector('textarea[name="instructions"]');
|
|
625
|
+
if (instructionsTextarea) this.agent.instructions = instructionsTextarea.value;
|
|
626
|
+
}
|
|
627
|
+
if (this.showTechnicalInstructionsEditor) {
|
|
628
|
+
const techInstructionsTextarea = this.shadowRoot.querySelector('textarea[name="technicalInstructions"]');
|
|
629
|
+
if (techInstructionsTextarea) this.agent.technicalInstructions = techInstructionsTextarea.value;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// Store current form state before any operations
|
|
634
|
+
const formState = {
|
|
635
|
+
name: this.agent.name,
|
|
636
|
+
persona: this.agent.persona,
|
|
637
|
+
instructions: this.agent.instructions,
|
|
638
|
+
technicalInstructions: this.agent.technicalInstructions,
|
|
639
|
+
commands: [...(this.agent.commands || [])],
|
|
640
|
+
recommended_plugins: [...(this.agent.recommended_plugins || [])],
|
|
641
|
+
preferred_providers: [...(this.agent.preferred_providers || [])]
|
|
642
|
+
};
|
|
643
|
+
|
|
644
|
+
// Skip full validation for partial saves
|
|
645
|
+
if (!isPartialSave && !this.validateForm()) {
|
|
646
|
+
// Restore form state on validation error
|
|
647
|
+
this.agent = {
|
|
648
|
+
...this.agent,
|
|
649
|
+
...formState
|
|
650
|
+
};
|
|
651
|
+
// Force update to refresh the form
|
|
652
|
+
this.requestUpdate();
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
// For new agents, ensure we have default values
|
|
657
|
+
if (this.newAgent) {
|
|
658
|
+
this.agent.commands = this.agent.commands || [];
|
|
659
|
+
this.agent.preferred_providers = this.agent.preferred_providers || [];
|
|
660
|
+
this.agent.recommended_plugins = this.agent.recommended_plugins || [];
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
try {
|
|
664
|
+
this.loading = true;
|
|
665
|
+
const method = this.newAgent ? 'POST' : 'PUT';
|
|
666
|
+
const url = this.newAgent ? '/agents/local' : `/agents/local/${this.agent.name}`;
|
|
667
|
+
|
|
668
|
+
const cmdSwitches = this.shadowRoot.querySelectorAll('.toggle-command')
|
|
669
|
+
console.log({cmdSwitches})
|
|
670
|
+
let cmdsOn = []
|
|
671
|
+
for (const cmdSwitch of cmdSwitches) {
|
|
672
|
+
console.log({cmdSwitch})
|
|
673
|
+
if (cmdSwitch.checked) {
|
|
674
|
+
cmdsOn.push(cmdSwitch.id.replace('cmd-', ''))
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
if (cmdsOn.length > 0) {
|
|
678
|
+
this.agent.commands = cmdsOn
|
|
679
|
+
}
|
|
680
|
+
for (let cmd in this.missingCommands) {
|
|
681
|
+
if (!this.agent.commands.includes(cmd)) {
|
|
682
|
+
this.agent.commands.push(cmd)
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
console.log('Saving, commands are:', this.agent.commands)
|
|
687
|
+
|
|
688
|
+
const selectedModelsEls = this.shadowRoot.querySelectorAll('.service-model-select');
|
|
689
|
+
console.log('Selected models:', selectedModelsEls, this.agent.service_models);
|
|
690
|
+
for (const select of selectedModelsEls) {
|
|
691
|
+
const selectedValue = select.value;
|
|
692
|
+
const serviceName = select.name;
|
|
693
|
+
if (selectedValue) {
|
|
694
|
+
console.log(`Selected value for ${serviceName}:`, selectedValue);
|
|
695
|
+
const [provider, model] = selectedValue.split('__');
|
|
696
|
+
if (!this.agent.service_models) {
|
|
697
|
+
this.agent.service_models = {};
|
|
698
|
+
}
|
|
699
|
+
this.agent.service_models[serviceName] = { provider, model }
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
console.log('Agent before saving:', this.agent);
|
|
704
|
+
const formData = new FormData();
|
|
705
|
+
const agentData = { ...this.agent };
|
|
706
|
+
|
|
707
|
+
agentData.flags = [];
|
|
708
|
+
if (this.agent.uncensored) {
|
|
709
|
+
// Make sure flags is an array
|
|
710
|
+
if (!Array.isArray(agentData.flags)) {
|
|
711
|
+
agentData.flags = [];
|
|
712
|
+
}
|
|
713
|
+
agentData.flags.push('uncensored');
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
formData.append('agent', JSON.stringify(agentData));
|
|
717
|
+
|
|
718
|
+
const response = await fetch(url, {
|
|
719
|
+
method,
|
|
720
|
+
body: formData
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
if (!response.ok) {
|
|
724
|
+
throw new Error('Failed to save agent');
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// Get the saved agent data from response and update local state
|
|
728
|
+
const savedAgent = await response.json();
|
|
729
|
+
|
|
730
|
+
// For partial saves, just update with saved data and preserve current agent state
|
|
731
|
+
if (isPartialSave) {
|
|
732
|
+
// Store the current edited values before merging
|
|
733
|
+
const currentInstructions = this.agent.instructions;
|
|
734
|
+
const currentTechnicalInstructions = this.agent.technicalInstructions;
|
|
735
|
+
|
|
736
|
+
this.agent = {
|
|
737
|
+
...this.agent,
|
|
738
|
+
...savedAgent
|
|
739
|
+
};
|
|
740
|
+
|
|
741
|
+
// Restore the edited field values to prevent server response from overwriting them
|
|
742
|
+
if (this.showInstructionsEditor) {
|
|
743
|
+
this.agent.instructions = currentInstructions;
|
|
744
|
+
}
|
|
745
|
+
if (this.showTechnicalInstructionsEditor) {
|
|
746
|
+
this.agent.technicalInstructions = currentTechnicalInstructions;
|
|
747
|
+
}
|
|
748
|
+
} else {
|
|
749
|
+
// For full saves, merge with current form values
|
|
750
|
+
this.agent = {
|
|
751
|
+
...savedAgent,
|
|
752
|
+
name: this.shadowRoot.querySelector('input[name="name"]')?.value || savedAgent.name,
|
|
753
|
+
persona: this.shadowRoot.querySelector('select[name="persona"]')?.value || savedAgent.persona,
|
|
754
|
+
thinking_level: this.shadowRoot.querySelector('select[name="thinking_level"]')?.value || savedAgent.thinking_level
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
// Reset editors after partial save (from icon buttons)
|
|
759
|
+
if (isPartialSave) {
|
|
760
|
+
this.showInstructionsEditor = false;
|
|
761
|
+
this.showTechnicalInstructionsEditor = false;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
showNotification('success', `Agent ${this.agent.name} saved successfully`);
|
|
765
|
+
|
|
766
|
+
// Dispatch event with merged data to preserve form state
|
|
767
|
+
this.dispatchEvent(new CustomEvent('agent-saved', {
|
|
768
|
+
detail: { ...this.agent, isPartialSave }, // Include the partial save flag
|
|
769
|
+
bubbles: true,
|
|
770
|
+
composed: true
|
|
771
|
+
}));
|
|
772
|
+
} catch (error) {
|
|
773
|
+
showNotification('error', `Error saving agent: ${error.message}`);
|
|
774
|
+
|
|
775
|
+
// Restore form state on error
|
|
776
|
+
this.agent = {
|
|
777
|
+
...this.agent,
|
|
778
|
+
...formState
|
|
779
|
+
};
|
|
780
|
+
|
|
781
|
+
// Force update to refresh the form with restored data
|
|
782
|
+
this.requestUpdate();
|
|
783
|
+
} finally {
|
|
784
|
+
this.loading = false;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
renderRequiredPlugins() {
|
|
789
|
+
// Ensure required_plugins is always an array
|
|
790
|
+
if (!Array.isArray(this.agent.recommended_plugins)) {
|
|
791
|
+
this.agent.recommended_plugins = [];
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
if (!this.plugins || this.plugins.length === 0) {
|
|
795
|
+
// Fetch plugins if not already loaded
|
|
796
|
+
if (!this.pluginsFetched) {
|
|
797
|
+
this.pluginsFetched = true;
|
|
798
|
+
this.fetchPlugins();
|
|
799
|
+
}
|
|
800
|
+
return html`<div>Loading plugins...</div>`;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
return html`
|
|
804
|
+
<div class="commands-category">
|
|
805
|
+
<h4>Recommended Plugins</h4>
|
|
806
|
+
<div class="commands-grid">
|
|
807
|
+
${this.plugins.map(plugin => {
|
|
808
|
+
|
|
809
|
+
const toggleId = `req_${plugin._uniqueId}`;
|
|
810
|
+
let source = plugin.remote_source
|
|
811
|
+
if (!source) source = plugin.github_url
|
|
812
|
+
if (!source) return null;
|
|
813
|
+
|
|
814
|
+
return html`
|
|
815
|
+
<div class="command-item">
|
|
816
|
+
<div class="command-info">
|
|
817
|
+
<div class="command-name">${source}</div>
|
|
818
|
+
</div>
|
|
819
|
+
<toggle-switch
|
|
820
|
+
.checked=${Boolean(this.agent.recommended_plugins.includes(source))}
|
|
821
|
+
id="${toggleId}"
|
|
822
|
+
@toggle-change=${(e) => this.handleInputChange({
|
|
823
|
+
target: {
|
|
824
|
+
plugin: plugin,
|
|
825
|
+
name: 'recommended_plugins',
|
|
826
|
+
value: source,
|
|
827
|
+
type: 'checkbox',
|
|
828
|
+
checked: e.detail.checked
|
|
829
|
+
}
|
|
830
|
+
})}>
|
|
831
|
+
</toggle-switch>
|
|
832
|
+
</div>
|
|
833
|
+
`;})}
|
|
834
|
+
</div>
|
|
835
|
+
</div>
|
|
836
|
+
`;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
renderCommands() {
|
|
840
|
+
return Object.entries(this.commands).map(([provider, commands]) => html`
|
|
841
|
+
<div class="commands-category">
|
|
842
|
+
<details>
|
|
843
|
+
<summary>${provider}</summary>
|
|
844
|
+
<div class="commands-grid">
|
|
845
|
+
${commands.map(command => html`
|
|
846
|
+
<div class="command-item">
|
|
847
|
+
<div class="command-info">
|
|
848
|
+
<div class="command-name">${command.name}</div>
|
|
849
|
+
${command.docstring ? html`
|
|
850
|
+
<div class="tooltip-text">${command.docstring}</div>
|
|
851
|
+
` : ''}
|
|
852
|
+
</div>
|
|
853
|
+
<toggle-switch
|
|
854
|
+
class="toggle-command"
|
|
855
|
+
.checked=${this.agent.commands?.includes(command.name) || false}
|
|
856
|
+
id="cmd-${command.name}"
|
|
857
|
+
@toggle-change=${(e) => this.handleInputChange({
|
|
858
|
+
target: {
|
|
859
|
+
name: 'commands',
|
|
860
|
+
value: command.name,
|
|
861
|
+
type: 'checkbox',
|
|
862
|
+
checked: e.detail.checked
|
|
863
|
+
}
|
|
864
|
+
})}>
|
|
865
|
+
</toggle-switch>
|
|
866
|
+
</div>
|
|
867
|
+
`)}
|
|
868
|
+
</div>
|
|
869
|
+
</details>
|
|
870
|
+
</div>
|
|
871
|
+
`);
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
renderServiceModels() {
|
|
875
|
+
if (this.serviceModels === undefined || Object.keys(this.serviceModels).length === 0) {
|
|
876
|
+
return html`<div>Loading service models...</div>`;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
console.log('Service models:', this.serviceModels);
|
|
880
|
+
console.log('Agent service models:', this.agent.service_models);
|
|
881
|
+
return html`
|
|
882
|
+
<div class="commands-category">
|
|
883
|
+
<h4>Service Models</h4>
|
|
884
|
+
<div class="commands-grid">
|
|
885
|
+
${Object.entries(this.serviceModels).map(([serviceName, providers]) => html`
|
|
886
|
+
<div class="command-item">
|
|
887
|
+
<div class="command-info">
|
|
888
|
+
<div class="command-name">${serviceName}</div>
|
|
889
|
+
</div>
|
|
890
|
+
<select name="${serviceName}"
|
|
891
|
+
class="service-model-select"
|
|
892
|
+
@change=${this.handleInputChange}>
|
|
893
|
+
${Object.entries(providers).map(([provider, models]) => html`
|
|
894
|
+
<optgroup label="${provider}">
|
|
895
|
+
${models.map(model => html`
|
|
896
|
+
<option
|
|
897
|
+
?selected=${this.agent.service_models &&
|
|
898
|
+
this.agent.service_models[serviceName] &&
|
|
899
|
+
this.agent.service_models[serviceName].provider == provider &&
|
|
900
|
+
this.agent.service_models[serviceName].model == model}
|
|
901
|
+
value="${provider}__${model}">${model}</option>
|
|
902
|
+
`)}
|
|
903
|
+
</optgroup>
|
|
904
|
+
`)}
|
|
905
|
+
</select>
|
|
906
|
+
</div>
|
|
907
|
+
`)}
|
|
908
|
+
</div>
|
|
909
|
+
`
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
|
|
913
|
+
renderPreferredProviders() {
|
|
914
|
+
// Ensure preferred_providers is always an array
|
|
915
|
+
if (!Array.isArray(this.agent.preferred_providers)) {
|
|
916
|
+
this.agent.preferred_providers = [];
|
|
917
|
+
}
|
|
918
|
+
console.log('Preferred providers:', this.agent.preferred_providers);
|
|
919
|
+
return html`
|
|
920
|
+
<div class="commands-category">
|
|
921
|
+
<h4>Preferred Providers</h4>
|
|
922
|
+
<div class="commands-grid">
|
|
923
|
+
${this.plugins.map(plugin => {
|
|
924
|
+
// Use provider name (module name) as the value
|
|
925
|
+
// Create a unique ID for each toggle
|
|
926
|
+
const toggleId = `pref_${plugin.name}`
|
|
927
|
+
console.log(`Rendering preferred provider for plugin: ${plugin.name}`)
|
|
928
|
+
return html`
|
|
929
|
+
<div class="command-item" data-provider="${plugin.name}">
|
|
930
|
+
<div class="command-info">
|
|
931
|
+
<div class="command-name">${plugin.name}</div>
|
|
932
|
+
</div>
|
|
933
|
+
<toggle-switch
|
|
934
|
+
.checked=${this.agent.preferred_providers?.includes(plugin.name) || false}
|
|
935
|
+
id="${toggleId}"
|
|
936
|
+
@toggle-change=${(e) => this.handlePreferredProviderChange({
|
|
937
|
+
detail: {
|
|
938
|
+
plugin: plugin.name,
|
|
939
|
+
value: plugin.name,
|
|
940
|
+
id: plugin.name,
|
|
941
|
+
checked: e.detail.checked
|
|
942
|
+
}
|
|
943
|
+
})}>
|
|
944
|
+
</toggle-switch>
|
|
945
|
+
</div>
|
|
946
|
+
`;})}
|
|
947
|
+
</div>
|
|
948
|
+
</div>
|
|
949
|
+
`;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
renderPendingPlugins() {
|
|
953
|
+
if (!this.pendingPlugins || this.pendingPlugins.length === 0) {
|
|
954
|
+
return html``;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
return html`
|
|
958
|
+
<div class="form-group commands-section">
|
|
959
|
+
<div class="commands-category">
|
|
960
|
+
<h4>Pending Recommended Plugins</h4>
|
|
961
|
+
<p>This agent recommends the following plugins that are not yet installed:</p>
|
|
962
|
+
<ul>
|
|
963
|
+
${this.pendingPlugins.map(plugin => html`<li>${plugin}</li>`)}
|
|
964
|
+
</ul>
|
|
965
|
+
<button class="btn" @click=${this.installRecommendedPlugins}>
|
|
966
|
+
Install Recommended Plugins
|
|
967
|
+
</button>
|
|
968
|
+
</div>
|
|
969
|
+
</div>
|
|
970
|
+
`;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
_render() {
|
|
974
|
+
return html`
|
|
975
|
+
<form class="agent-form" @submit=${this.handleSubmit}>
|
|
976
|
+
<div class="form-group">
|
|
977
|
+
<label class="required">Name:</label>
|
|
978
|
+
<input type="text" name="name"
|
|
979
|
+
.value=${this.agent.name || ''}
|
|
980
|
+
@input=${this.handleInputChange}>
|
|
981
|
+
</div>
|
|
982
|
+
|
|
983
|
+
<div class="form-group">
|
|
984
|
+
<label class="required">Persona:</label>
|
|
985
|
+
<select name="persona"
|
|
986
|
+
value=${this.agent.persona || ''}
|
|
987
|
+
@change=${this.handleInputChange}>
|
|
988
|
+
<option value="">Select a persona</option>
|
|
989
|
+
${this.personas.map(persona => html`
|
|
990
|
+
<option value="${persona.name}" ?selected=${persona.name === this.agent.persona}>${persona.name}</option>
|
|
991
|
+
`)}
|
|
992
|
+
</select>
|
|
993
|
+
</div>
|
|
994
|
+
|
|
995
|
+
<div class="form-group">
|
|
996
|
+
<div class="form-group-header">
|
|
997
|
+
<label class="required">Instructions:</label>
|
|
998
|
+
<div class="form-group-actions">
|
|
999
|
+
${this.showInstructionsEditor ? html`
|
|
1000
|
+
<button type="button" class="icon-button partial-save" @click=${async (e) => { e.preventDefault(); await this.handleSubmit(e); }}>
|
|
1001
|
+
<span class="material-icons">save</span>
|
|
1002
|
+
</button>
|
|
1003
|
+
` : html`
|
|
1004
|
+
<button type="button" class="icon-button" @click=${() => this.showInstructionsEditor = true}>
|
|
1005
|
+
<span class="material-icons">edit</span>
|
|
1006
|
+
</button>
|
|
1007
|
+
`}
|
|
1008
|
+
</div>
|
|
1009
|
+
</div>
|
|
1010
|
+
${this.showInstructionsEditor ? html`
|
|
1011
|
+
<textarea name="instructions"
|
|
1012
|
+
.value=${this.agent.instructions || ''}></textarea>
|
|
1013
|
+
` : html`
|
|
1014
|
+
<div class="markdown-preview">
|
|
1015
|
+
${unsafeHTML(this.renderMarkdown(this.agent.instructions || ''))}
|
|
1016
|
+
</div>
|
|
1017
|
+
`}
|
|
1018
|
+
</div>
|
|
1019
|
+
|
|
1020
|
+
<div class="form-group">
|
|
1021
|
+
<div class="form-group-header">
|
|
1022
|
+
<label>Technical Instructions:</label>
|
|
1023
|
+
<div class="form-group-actions">
|
|
1024
|
+
${this.showTechnicalInstructionsEditor ? html`
|
|
1025
|
+
<button type="button" class="icon-button partial-save" @click=${async (e) => { e.preventDefault(); await this.handleSubmit(e); }}>
|
|
1026
|
+
<span class="material-icons">save</span>
|
|
1027
|
+
</button>
|
|
1028
|
+
` : html`
|
|
1029
|
+
<button type="button" class="icon-button" @click=${() => this.showTechnicalInstructionsEditor = true}>
|
|
1030
|
+
<span class="material-icons">edit</span>
|
|
1031
|
+
</button>
|
|
1032
|
+
`}
|
|
1033
|
+
</div>
|
|
1034
|
+
</div>
|
|
1035
|
+
${this.showTechnicalInstructionsEditor ? html`
|
|
1036
|
+
<textarea name="technicalInstructions"
|
|
1037
|
+
.value=${this.agent.technicalInstructions || ''}></textarea>
|
|
1038
|
+
` : html`
|
|
1039
|
+
<div class="markdown-preview">
|
|
1040
|
+
${unsafeHTML(this.renderMarkdown(this.agent.technicalInstructions || ''))}
|
|
1041
|
+
</div>
|
|
1042
|
+
`}
|
|
1043
|
+
</div>
|
|
1044
|
+
|
|
1045
|
+
<div class="form-group">
|
|
1046
|
+
<label>
|
|
1047
|
+
Uncensored:
|
|
1048
|
+
<toggle-switch
|
|
1049
|
+
.checked=${this.agent.uncensored || false}
|
|
1050
|
+
@toggle-change=${(e) => this.handleInputChange({
|
|
1051
|
+
target: {
|
|
1052
|
+
name: 'uncensored',
|
|
1053
|
+
type: 'checkbox',
|
|
1054
|
+
checked: e.detail.checked
|
|
1055
|
+
}
|
|
1056
|
+
})}>
|
|
1057
|
+
</toggle-switch>
|
|
1058
|
+
</label>
|
|
1059
|
+
</div>
|
|
1060
|
+
|
|
1061
|
+
<div class="form-group reasoning-level-group">
|
|
1062
|
+
<label>Reasoning Effort:</label>
|
|
1063
|
+
<select name="thinking_level"
|
|
1064
|
+
value=${this.agent.thinking_level || 'off'}
|
|
1065
|
+
@change=${this.handleInputChange}>
|
|
1066
|
+
<option value="off"
|
|
1067
|
+
?selected=${(this.agent.thinking_level || 'off') === 'off'}>
|
|
1068
|
+
Off
|
|
1069
|
+
</option>
|
|
1070
|
+
<option value="low"
|
|
1071
|
+
?selected=${(this.agent.thinking_level || 'off') === 'low'}>
|
|
1072
|
+
Low
|
|
1073
|
+
</option>
|
|
1074
|
+
<option value="medium"
|
|
1075
|
+
?selected=${(this.agent.thinking_level || 'off') === 'medium'}>
|
|
1076
|
+
Medium
|
|
1077
|
+
</option>
|
|
1078
|
+
<option value="high"
|
|
1079
|
+
?selected=${(this.agent.thinking_level || 'off') === 'high'}>
|
|
1080
|
+
High
|
|
1081
|
+
</option>
|
|
1082
|
+
</select>
|
|
1083
|
+
</div>
|
|
1084
|
+
|
|
1085
|
+
${this.renderPendingPlugins()}
|
|
1086
|
+
|
|
1087
|
+
<div class="form-group commands-section">
|
|
1088
|
+
<details>
|
|
1089
|
+
<summary>Preferred Providers</summary>
|
|
1090
|
+
${this.renderPreferredProviders()}
|
|
1091
|
+
</details>
|
|
1092
|
+
</div>
|
|
1093
|
+
|
|
1094
|
+
<div class="form-group commands-section">
|
|
1095
|
+
<details>
|
|
1096
|
+
<summary>Select Models</summary>
|
|
1097
|
+
${this.renderServiceModels()}
|
|
1098
|
+
</details>
|
|
1099
|
+
</div>
|
|
1100
|
+
|
|
1101
|
+
<div class="form-group commands-section">
|
|
1102
|
+
<details>
|
|
1103
|
+
<summary>Recommended Plugins</summary>
|
|
1104
|
+
${this.renderRequiredPlugins()}
|
|
1105
|
+
</details>
|
|
1106
|
+
</div>
|
|
1107
|
+
|
|
1108
|
+
${this.agent.name && this.missingCommands && Object.keys(this.missingCommands).length > 0 ? html`
|
|
1109
|
+
<div class="form-group commands-section">
|
|
1110
|
+
<details>
|
|
1111
|
+
<summary>Missing Commands (${Object.keys(this.missingCommands).length})</summary>
|
|
1112
|
+
<missing-commands .agentName=${this.agent.name}></missing-commands>
|
|
1113
|
+
</details>
|
|
1114
|
+
</div>
|
|
1115
|
+
` : ''}
|
|
1116
|
+
|
|
1117
|
+
<div class="form-group commands-section">
|
|
1118
|
+
<details><summary>Available Commands</summary>
|
|
1119
|
+
${this.renderCommands()}
|
|
1120
|
+
</details>
|
|
1121
|
+
</div>
|
|
1122
|
+
|
|
1123
|
+
<div class="agent-insert-end"></div>
|
|
1124
|
+
<button class="btn" type="submit" ?disabled=${this.loading}>
|
|
1125
|
+
${this.loading ? 'Saving...' : 'Save'}
|
|
1126
|
+
</button>
|
|
1127
|
+
|
|
1128
|
+
</form>
|
|
1129
|
+
`;
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
customElements.define('agent-form', AgentForm);
|