living-ai-documentation 2.1.0 → 2.3.0
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.
- package/dist/src/frontend/agents.js +288 -0
- package/dist/src/frontend/diagram/color-picker.js +72 -0
- package/dist/src/frontend/diagram/defaults-modal.js +302 -0
- package/dist/src/frontend/diagram/edge-panel.js +110 -11
- package/dist/src/frontend/diagram/main.js +5 -8
- package/dist/src/frontend/diagram/network.js +16 -7
- package/dist/src/frontend/diagram/node-panel.js +104 -2
- package/dist/src/frontend/diagram.html +52 -29
- package/dist/src/frontend/i18n/en.json +42 -0
- package/dist/src/frontend/i18n/fr.json +42 -0
- package/dist/src/frontend/index.html +122 -0
- package/dist/src/frontend/workspace/app.js +143 -36
- package/dist/src/frontend/workspace/app.js.map +1 -1
- package/dist/src/frontend/workspace/app.ts +206 -50
- package/dist/src/frontend/workspace/index.html +118 -39
- package/dist/src/frontend/workspace/persistence.js.map +1 -1
- package/dist/src/frontend/workspace/persistence.ts +1 -0
- package/dist/src/frontend/workspace/styles.css +97 -57
- package/dist/src/lib/config.d.ts +23 -0
- package/dist/src/lib/config.d.ts.map +1 -1
- package/dist/src/lib/config.js +16 -0
- package/dist/src/lib/config.js.map +1 -1
- package/dist/src/routes/config.d.ts.map +1 -1
- package/dist/src/routes/config.js +13 -0
- package/dist/src/routes/config.js.map +1 -1
- package/dist/src/routes/workspace.d.ts.map +1 -1
- package/dist/src/routes/workspace.js +255 -104
- package/dist/src/routes/workspace.js.map +1 -1
- package/package.json +1 -1
|
@@ -29,12 +29,30 @@
|
|
|
29
29
|
"nav.export_all_pdf": "Exporter tous les documents en PDF",
|
|
30
30
|
"nav.new_folder": "Nouveau dossier",
|
|
31
31
|
"nav.new_document": "Nouveau document",
|
|
32
|
+
"nav.ai_agents": "Agents IA",
|
|
32
33
|
"nav.word_cloud": "☁ Nuage de mots",
|
|
33
34
|
"nav.diagram": "◇ Diagramme",
|
|
34
35
|
"nav.ai_context": "Contexte IA",
|
|
35
36
|
"nav.files": "📁 Fichiers joints",
|
|
36
37
|
"nav.admin": "⚙ Admin",
|
|
37
38
|
|
|
39
|
+
"agents.title": "Agents IA",
|
|
40
|
+
"agents.subtitle": "Lancer un agent configuré dans le workspace.",
|
|
41
|
+
"agents.empty": "Aucun agent workspace n'est encore configuré.",
|
|
42
|
+
"agents.ready": "Prêt",
|
|
43
|
+
"agents.requires_input": "Input requis",
|
|
44
|
+
"agents.not_ready": "Configuration incomplète",
|
|
45
|
+
"agents.no_provider": "Aucun provider LLM",
|
|
46
|
+
"agents.input_title": "Input agent",
|
|
47
|
+
"agents.input_hint": "Renseignez l'input nécessaire à cette exécution.",
|
|
48
|
+
"agents.run": "Lancer l'agent",
|
|
49
|
+
"agents.loading": "Exécution de l'agent…",
|
|
50
|
+
"agents.success": "Exécution terminée",
|
|
51
|
+
"agents.failure": "Échec de l'exécution",
|
|
52
|
+
"agents.open_document": "Ouvrir le document",
|
|
53
|
+
"agents.load_failed": "Impossible de charger les agents workspace.",
|
|
54
|
+
"agents.run_failed": "Échec de l'exécution de l'agent.",
|
|
55
|
+
|
|
38
56
|
"files.title": "📁 Fichiers joints",
|
|
39
57
|
"files.empty": "Aucun fichier — téléversez-en un depuis un document (trombone, glisser-déposer ou coller).",
|
|
40
58
|
"files.replace": "Remplacer",
|
|
@@ -591,7 +609,26 @@
|
|
|
591
609
|
"diagram.toolbar.shape_editor": "Éditeur de formes personnalisées",
|
|
592
610
|
"diagram.toolbar.arrow": "Flèche (F)",
|
|
593
611
|
"diagram.toolbar.delete": "Supprimer (Suppr)",
|
|
612
|
+
"diagram.toolbar.defaults": "Valeurs par défaut — configurer les tailles, couleurs et styles par défaut",
|
|
594
613
|
"diagram.toolbar.align_guides": "Guides d'alignement — indique l'alignement entre formes du même type",
|
|
614
|
+
"diagram.defaults.title": "Valeurs par défaut",
|
|
615
|
+
"diagram.defaults.section.arrows": "Flèches",
|
|
616
|
+
"diagram.defaults.section.shapes": "Formes",
|
|
617
|
+
"diagram.defaults.field.direction": "Direction",
|
|
618
|
+
"diagram.defaults.field.style": "Style",
|
|
619
|
+
"diagram.defaults.field.font_size": "Taille police",
|
|
620
|
+
"diagram.defaults.field.width": "L",
|
|
621
|
+
"diagram.defaults.field.height": "H",
|
|
622
|
+
"diagram.defaults.field.color": "Couleur",
|
|
623
|
+
"diagram.defaults.style.solid": "Plein",
|
|
624
|
+
"diagram.defaults.style.dashed": "Pointillé",
|
|
625
|
+
"diagram.defaults.shape.box": "Rectangle",
|
|
626
|
+
"diagram.defaults.shape.ellipse": "Ellipse",
|
|
627
|
+
"diagram.defaults.shape.circle": "Cercle",
|
|
628
|
+
"diagram.defaults.shape.database": "Base de données",
|
|
629
|
+
"diagram.defaults.shape.actor": "Acteur",
|
|
630
|
+
"diagram.defaults.shape.postit": "Post-it",
|
|
631
|
+
"diagram.defaults.shape.text_free": "Texte libre",
|
|
595
632
|
"diagram.toolbar.grid": "Grille / Magnétisme (G)",
|
|
596
633
|
"diagram.toolbar.edge_style": "Basculer flèches courbes / droites",
|
|
597
634
|
"diagram.toolbar.resize_corner": "Mode redimensionnement : coin fixe (cliquer pour centre fixe)",
|
|
@@ -609,6 +646,8 @@
|
|
|
609
646
|
"diagram.sidebar.empty": "Aucun diagramme",
|
|
610
647
|
"diagram.sidebar.delete_title": "Supprimer",
|
|
611
648
|
|
|
649
|
+
"diagram.node_panel.color": "Couleur de la forme",
|
|
650
|
+
"diagram.node_panel.save_as_default": "Enregistrer comme valeur par défaut pour ce type de forme",
|
|
612
651
|
"diagram.node_panel.lock": "Verrouiller la sélection",
|
|
613
652
|
"diagram.node_panel.unlock": "Déverrouiller la sélection",
|
|
614
653
|
"diagram.node_panel.edit_label": "Modifier le texte (double-clic)",
|
|
@@ -648,6 +687,9 @@
|
|
|
648
687
|
"diagram.link_panel.save_btn": "Enregistrer",
|
|
649
688
|
"diagram.link_panel.remove_btn": "Retirer",
|
|
650
689
|
|
|
690
|
+
"diagram.edge_panel.font_size_value": "Taille de police",
|
|
691
|
+
"diagram.edge_panel.color": "Couleur de la flèche",
|
|
692
|
+
"diagram.edge_panel.save_as_default": "Enregistrer comme valeur par défaut pour les flèches",
|
|
651
693
|
"diagram.edge_panel.lock": "Verrouiller la flèche",
|
|
652
694
|
"diagram.edge_panel.unlock": "Déverrouiller la flèche",
|
|
653
695
|
"diagram.edge_panel.no_arrow": "Trait simple",
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
<script defer src="/accuracy-gauge.js"></script>
|
|
59
59
|
<script defer src="/validate.js"></script>
|
|
60
60
|
<script defer src="/export.js"></script>
|
|
61
|
+
<script defer src="/agents.js"></script>
|
|
61
62
|
<script defer src="/modals/diagram-link-modal.js"></script>
|
|
62
63
|
<script defer src="/modals/new-folder-modal.js"></script>
|
|
63
64
|
<script defer src="/modals/new-doc-modal.js"></script>
|
|
@@ -557,6 +558,16 @@
|
|
|
557
558
|
Workspace
|
|
558
559
|
</a>
|
|
559
560
|
|
|
561
|
+
<!-- AI Agents -->
|
|
562
|
+
<button
|
|
563
|
+
id="ai-agents-btn"
|
|
564
|
+
type="button"
|
|
565
|
+
data-i18n="nav.ai_agents"
|
|
566
|
+
class="h-[34px] px-3 rounded-[9px] border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 text-[13px] font-bold text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors inline-flex items-center"
|
|
567
|
+
>
|
|
568
|
+
Agents IA
|
|
569
|
+
</button>
|
|
570
|
+
|
|
560
571
|
<!-- Word Cloud -->
|
|
561
572
|
<button
|
|
562
573
|
onclick="openWordCloud()"
|
|
@@ -3111,6 +3122,117 @@
|
|
|
3111
3122
|
</div>
|
|
3112
3123
|
</div>
|
|
3113
3124
|
|
|
3125
|
+
<!-- ── AI agents launch modal ── -->
|
|
3126
|
+
<div
|
|
3127
|
+
id="ai-agents-modal"
|
|
3128
|
+
class="hidden fixed inset-0 z-[55] bg-black/45 flex items-center justify-center p-4"
|
|
3129
|
+
onclick="if(event.target===this)closeAiAgentsModal()"
|
|
3130
|
+
>
|
|
3131
|
+
<div
|
|
3132
|
+
class="w-full max-w-4xl max-h-[82vh] bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-xl shadow-2xl flex flex-col overflow-hidden"
|
|
3133
|
+
onclick="event.stopPropagation()"
|
|
3134
|
+
>
|
|
3135
|
+
<div class="px-5 py-4 border-b border-gray-200 dark:border-gray-800 flex items-start justify-between gap-4">
|
|
3136
|
+
<div>
|
|
3137
|
+
<h2 class="font-semibold text-base text-gray-900 dark:text-gray-100" data-i18n="agents.title">Agents IA</h2>
|
|
3138
|
+
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1" data-i18n="agents.subtitle">
|
|
3139
|
+
Launch a configured workspace agent.
|
|
3140
|
+
</p>
|
|
3141
|
+
</div>
|
|
3142
|
+
<button
|
|
3143
|
+
type="button"
|
|
3144
|
+
onclick="closeAiAgentsModal()"
|
|
3145
|
+
data-i18n-title="common.close"
|
|
3146
|
+
class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 text-xl leading-none px-2"
|
|
3147
|
+
>
|
|
3148
|
+
×
|
|
3149
|
+
</button>
|
|
3150
|
+
</div>
|
|
3151
|
+
<div id="ai-agents-grid" class="p-5 overflow-y-auto grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3">
|
|
3152
|
+
<p class="text-sm text-gray-400" data-i18n="common.loading">Loading…</p>
|
|
3153
|
+
</div>
|
|
3154
|
+
</div>
|
|
3155
|
+
</div>
|
|
3156
|
+
|
|
3157
|
+
<!-- ── AI agent input modal ── -->
|
|
3158
|
+
<div
|
|
3159
|
+
id="ai-agent-input-modal"
|
|
3160
|
+
class="hidden fixed inset-0 z-[56] bg-black/45 flex items-center justify-center p-4"
|
|
3161
|
+
onclick="if(event.target===this)closeAiAgentInputModal()"
|
|
3162
|
+
>
|
|
3163
|
+
<div
|
|
3164
|
+
class="w-full max-w-2xl bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-xl shadow-2xl flex flex-col overflow-hidden"
|
|
3165
|
+
onclick="event.stopPropagation()"
|
|
3166
|
+
>
|
|
3167
|
+
<div class="px-5 py-4 border-b border-gray-200 dark:border-gray-800 flex items-start justify-between gap-4">
|
|
3168
|
+
<div>
|
|
3169
|
+
<h2 id="ai-agent-input-title" class="font-semibold text-base text-gray-900 dark:text-gray-100" data-i18n="agents.input_title">Agent input</h2>
|
|
3170
|
+
<p id="ai-agent-input-hint" class="text-xs text-gray-500 dark:text-gray-400 mt-1" data-i18n="agents.input_hint">
|
|
3171
|
+
Provide the input required for this run.
|
|
3172
|
+
</p>
|
|
3173
|
+
</div>
|
|
3174
|
+
<button
|
|
3175
|
+
type="button"
|
|
3176
|
+
onclick="closeAiAgentInputModal()"
|
|
3177
|
+
data-i18n-title="common.close"
|
|
3178
|
+
class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 text-xl leading-none px-2"
|
|
3179
|
+
>
|
|
3180
|
+
×
|
|
3181
|
+
</button>
|
|
3182
|
+
</div>
|
|
3183
|
+
<div class="p-5 flex flex-col gap-4">
|
|
3184
|
+
<textarea
|
|
3185
|
+
id="ai-agent-user-input"
|
|
3186
|
+
rows="8"
|
|
3187
|
+
class="w-full rounded-lg border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-950 px-3 py-2 text-sm text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500/25 focus:border-blue-500 resize-y"
|
|
3188
|
+
></textarea>
|
|
3189
|
+
<div class="flex justify-end gap-3">
|
|
3190
|
+
<button
|
|
3191
|
+
type="button"
|
|
3192
|
+
onclick="closeAiAgentInputModal()"
|
|
3193
|
+
data-i18n="common.cancel"
|
|
3194
|
+
class="text-sm px-4 py-2 rounded-lg border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
|
3195
|
+
>Cancel</button>
|
|
3196
|
+
<button
|
|
3197
|
+
id="ai-agent-input-run"
|
|
3198
|
+
type="button"
|
|
3199
|
+
data-i18n="agents.run"
|
|
3200
|
+
class="text-sm px-4 py-2 rounded-lg bg-blue-600 hover:bg-blue-700 text-white font-semibold transition-colors"
|
|
3201
|
+
>Run agent</button>
|
|
3202
|
+
</div>
|
|
3203
|
+
</div>
|
|
3204
|
+
</div>
|
|
3205
|
+
</div>
|
|
3206
|
+
|
|
3207
|
+
<!-- ── AI agent persistent toast ── -->
|
|
3208
|
+
<div
|
|
3209
|
+
id="ai-agent-toast"
|
|
3210
|
+
class="hidden fixed right-5 bottom-5 z-[70] w-[min(420px,calc(100vw-2.5rem))] rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 shadow-2xl px-4 py-3"
|
|
3211
|
+
role="status"
|
|
3212
|
+
>
|
|
3213
|
+
<div class="flex items-start gap-3">
|
|
3214
|
+
<span id="ai-agent-toast-icon" class="mt-0.5 h-5 w-5 rounded-full border-2 border-blue-500 border-t-transparent animate-spin shrink-0"></span>
|
|
3215
|
+
<div class="min-w-0 flex-1">
|
|
3216
|
+
<p id="ai-agent-toast-title" class="text-sm font-semibold text-gray-900 dark:text-gray-100" data-i18n="agents.loading">Running agent…</p>
|
|
3217
|
+
<p id="ai-agent-toast-message" class="text-xs text-gray-500 dark:text-gray-400 mt-1 break-words"></p>
|
|
3218
|
+
<button
|
|
3219
|
+
id="ai-agent-toast-open"
|
|
3220
|
+
type="button"
|
|
3221
|
+
data-i18n="agents.open_document"
|
|
3222
|
+
class="hidden mt-3 text-xs px-3 py-1.5 rounded-lg bg-blue-600 hover:bg-blue-700 text-white font-semibold transition-colors"
|
|
3223
|
+
>Open document</button>
|
|
3224
|
+
</div>
|
|
3225
|
+
<button
|
|
3226
|
+
id="ai-agent-toast-close"
|
|
3227
|
+
type="button"
|
|
3228
|
+
data-i18n-title="common.close"
|
|
3229
|
+
class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 text-lg leading-none px-1 shrink-0"
|
|
3230
|
+
>
|
|
3231
|
+
×
|
|
3232
|
+
</button>
|
|
3233
|
+
</div>
|
|
3234
|
+
</div>
|
|
3235
|
+
|
|
3114
3236
|
<!-- ── Generic confirmation modal (used by showConfirm) ── -->
|
|
3115
3237
|
<div
|
|
3116
3238
|
id="confirm-modal"
|
|
@@ -51,9 +51,7 @@ const addButton = document.getElementById("addButton");
|
|
|
51
51
|
const fitButton = document.getElementById("fitButton");
|
|
52
52
|
const testNodeButton = document.getElementById("testNodeButton");
|
|
53
53
|
const loadModelsButton = document.getElementById("loadModelsButton");
|
|
54
|
-
const
|
|
55
|
-
const clearAgentButton = document.getElementById("clearAgentButton");
|
|
56
|
-
const agentResponses = document.getElementById("agentResponses");
|
|
54
|
+
const closePanelButton = document.getElementById("closePanelButton");
|
|
57
55
|
const deleteNodeButton = document.getElementById("deleteNodeButton");
|
|
58
56
|
const renameConfirmOverlay = document.getElementById("renameConfirmOverlay");
|
|
59
57
|
const renameConfirmMessage = document.getElementById("renameConfirmMessage");
|
|
@@ -63,6 +61,14 @@ const deleteConfirmOverlay = document.getElementById("deleteConfirmOverlay");
|
|
|
63
61
|
const deleteConfirmMessage = document.getElementById("deleteConfirmMessage");
|
|
64
62
|
const cancelDeleteButton = document.getElementById("cancelDeleteButton");
|
|
65
63
|
const confirmDeleteButton = document.getElementById("confirmDeleteButton");
|
|
64
|
+
const agentRunOverlay = document.getElementById("agentRunOverlay");
|
|
65
|
+
const agentRunTitle = document.getElementById("agentRunTitle");
|
|
66
|
+
const agentRunHint = document.getElementById("agentRunHint");
|
|
67
|
+
const agentRunInputField = document.getElementById("agentRunInputField");
|
|
68
|
+
const agentRunInput = document.getElementById("agentRunInput");
|
|
69
|
+
const agentRunResult = document.getElementById("agentRunResult");
|
|
70
|
+
const cancelAgentRunButton = document.getElementById("cancelAgentRunButton");
|
|
71
|
+
const executeAgentRunButton = document.getElementById("executeAgentRunButton");
|
|
66
72
|
const fallbackPanelHost = document.getElementById("fallbackPanelHost");
|
|
67
73
|
const configSurface = document.getElementById("configSurface");
|
|
68
74
|
const form = configSurface;
|
|
@@ -72,6 +78,7 @@ const workspaceToastMessage = document.getElementById("workspaceToastMessage");
|
|
|
72
78
|
let toastTimerId = null;
|
|
73
79
|
let savedAgentLabel = null;
|
|
74
80
|
let savedAgentFolder = null;
|
|
81
|
+
let agentRunTargetId = null;
|
|
75
82
|
const fields = {
|
|
76
83
|
name: document.getElementById("nodeName"),
|
|
77
84
|
kind: document.getElementById("nodeKind"),
|
|
@@ -87,7 +94,10 @@ const fields = {
|
|
|
87
94
|
mcpInventory: document.getElementById("mcpInventory"),
|
|
88
95
|
agentSection: document.getElementById("agentSection"),
|
|
89
96
|
systemPrompt: document.getElementById("nodeSystemPrompt"),
|
|
90
|
-
|
|
97
|
+
requiresUserInput: document.getElementById("nodeRequiresUserInput"),
|
|
98
|
+
userInputDescriptionField: document.getElementById("agentUserInputDescriptionField"),
|
|
99
|
+
userInputDescription: document.getElementById("nodeUserInputDescription"),
|
|
100
|
+
expectedOutputMarker: document.getElementById("nodeExpectedOutputMarker"),
|
|
91
101
|
};
|
|
92
102
|
const initialEntities = [
|
|
93
103
|
createEntity("root", "Living AI Documentation", "system", null),
|
|
@@ -236,6 +246,9 @@ form.addEventListener("input", (event) => {
|
|
|
236
246
|
}
|
|
237
247
|
scheduleRender();
|
|
238
248
|
});
|
|
249
|
+
closePanelButton.addEventListener("click", () => {
|
|
250
|
+
selectEntity(null);
|
|
251
|
+
});
|
|
239
252
|
deleteNodeButton.addEventListener("click", (event) => {
|
|
240
253
|
event.preventDefault();
|
|
241
254
|
event.stopPropagation();
|
|
@@ -259,6 +272,11 @@ confirmDeleteButton.addEventListener("click", () => {
|
|
|
259
272
|
closeDeleteConfirmation();
|
|
260
273
|
});
|
|
261
274
|
testNodeButton.addEventListener("click", () => {
|
|
275
|
+
const selected = selectedEntity();
|
|
276
|
+
if (selected?.kind === "agent") {
|
|
277
|
+
openAgentRunDialog();
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
262
280
|
void testSelectedLlmConnection();
|
|
263
281
|
});
|
|
264
282
|
loadModelsButton.addEventListener("click", () => {
|
|
@@ -269,13 +287,15 @@ fields.name.addEventListener("blur", () => {
|
|
|
269
287
|
if (!selected || selected.kind !== "agent")
|
|
270
288
|
return;
|
|
271
289
|
const newName = fields.name.value.trim();
|
|
272
|
-
if (!newName ||
|
|
290
|
+
if (!newName ||
|
|
291
|
+
!savedAgentLabel ||
|
|
292
|
+
!savedAgentFolder ||
|
|
293
|
+
newName === savedAgentLabel)
|
|
273
294
|
return;
|
|
274
295
|
const newFolder = workspaceFolderForProvider(newName);
|
|
275
296
|
if (newFolder === savedAgentFolder)
|
|
276
297
|
return; // slug identique, pas de renommage nécessaire
|
|
277
|
-
renameConfirmMessage.textContent =
|
|
278
|
-
`Renommer le dossier "${savedAgentFolder}" en "${newFolder}" ?`;
|
|
298
|
+
renameConfirmMessage.textContent = `Renommer le dossier "${savedAgentFolder}" en "${newFolder}" ?`;
|
|
279
299
|
renameConfirmOverlay.hidden = false;
|
|
280
300
|
cancelRenameButton.focus();
|
|
281
301
|
});
|
|
@@ -310,12 +330,16 @@ fields.model.addEventListener("change", () => {
|
|
|
310
330
|
selected.config.model = fields.model.value;
|
|
311
331
|
}
|
|
312
332
|
});
|
|
313
|
-
|
|
314
|
-
|
|
333
|
+
cancelAgentRunButton.addEventListener("click", () => {
|
|
334
|
+
closeAgentRunDialog();
|
|
315
335
|
});
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
336
|
+
executeAgentRunButton.addEventListener("click", () => {
|
|
337
|
+
void executeAgentRunFromDialog();
|
|
338
|
+
});
|
|
339
|
+
agentRunOverlay.addEventListener("click", (event) => {
|
|
340
|
+
if (event.target === agentRunOverlay) {
|
|
341
|
+
closeAgentRunDialog();
|
|
342
|
+
}
|
|
319
343
|
});
|
|
320
344
|
void initializeWorkspace();
|
|
321
345
|
function isolatePanelEvents() {
|
|
@@ -328,6 +352,7 @@ function isolateConfirmEvents() {
|
|
|
328
352
|
for (const type of PANEL_EVENT_TYPES) {
|
|
329
353
|
deleteConfirmOverlay.addEventListener(type, stopPanelEventPropagation);
|
|
330
354
|
renameConfirmOverlay.addEventListener(type, stopPanelEventPropagation);
|
|
355
|
+
agentRunOverlay.addEventListener(type, stopPanelEventPropagation);
|
|
331
356
|
}
|
|
332
357
|
}
|
|
333
358
|
function stopPanelEventPropagation(event) {
|
|
@@ -419,6 +444,9 @@ function hydrateEntity(input) {
|
|
|
419
444
|
workspaceFolder: stringValue(config.workspaceFolder) ||
|
|
420
445
|
(kind === "agent" ? workspaceFolderForProvider(label) : ""),
|
|
421
446
|
systemPrompt: stringValue(config.systemPrompt),
|
|
447
|
+
requiresUserInput: config.requiresUserInput === true,
|
|
448
|
+
userInputDescription: stringValue(config.userInputDescription),
|
|
449
|
+
expectedOutputMarker: stringValue(config.expectedOutputMarker),
|
|
422
450
|
},
|
|
423
451
|
};
|
|
424
452
|
}
|
|
@@ -535,6 +563,9 @@ function createEntity(id, label, kind, parentId) {
|
|
|
535
563
|
description: defaultDescription(kind),
|
|
536
564
|
workspaceFolder: kind === "agent" ? workspaceFolderForProvider(label) : "",
|
|
537
565
|
systemPrompt: "",
|
|
566
|
+
requiresUserInput: false,
|
|
567
|
+
userInputDescription: "",
|
|
568
|
+
expectedOutputMarker: "",
|
|
538
569
|
},
|
|
539
570
|
};
|
|
540
571
|
}
|
|
@@ -546,7 +577,7 @@ function cloneEntities(entities) {
|
|
|
546
577
|
}
|
|
547
578
|
function defaultEndpoint(id, kind) {
|
|
548
579
|
if (kind === "llm") {
|
|
549
|
-
return "http://localhost:
|
|
580
|
+
return "http://localhost:11434";
|
|
550
581
|
}
|
|
551
582
|
if (kind === "mcp") {
|
|
552
583
|
return "http://localhost:4321/mcp";
|
|
@@ -769,7 +800,11 @@ function selectEntity(id) {
|
|
|
769
800
|
state.selectedId = id;
|
|
770
801
|
const entity = id ? entityById(id) : null;
|
|
771
802
|
savedAgentLabel = entity?.kind === "agent" ? entity.label : null;
|
|
772
|
-
savedAgentFolder =
|
|
803
|
+
savedAgentFolder =
|
|
804
|
+
entity?.kind === "agent"
|
|
805
|
+
? entity.config.workspaceFolder ||
|
|
806
|
+
workspaceFolderForProvider(entity.label)
|
|
807
|
+
: null;
|
|
773
808
|
layoutGraph();
|
|
774
809
|
syncCameraForPanelChange(hadSelection, Boolean(id), true);
|
|
775
810
|
syncPanelFromSelection();
|
|
@@ -813,6 +848,7 @@ function syncPanelFromSelection() {
|
|
|
813
848
|
fallbackPanelHost.hidden = !hasSelection || supportsHtmlInCanvas;
|
|
814
849
|
if (!selected) {
|
|
815
850
|
addButton.title = "Add LLM provider";
|
|
851
|
+
testNodeButton.textContent = "Test";
|
|
816
852
|
testNodeButton.hidden = true;
|
|
817
853
|
testNodeButton.disabled = true;
|
|
818
854
|
return;
|
|
@@ -828,14 +864,22 @@ function syncPanelFromSelection() {
|
|
|
828
864
|
fields.description.value = selected.config.description;
|
|
829
865
|
fields.typeBadge.textContent = labelForBadge(selected.kind);
|
|
830
866
|
fields.kind.disabled = true;
|
|
831
|
-
fields.llmFields.hidden =
|
|
867
|
+
fields.llmFields.hidden =
|
|
868
|
+
selected.kind === "mcp" || selected.kind === "agent";
|
|
832
869
|
fields.mcpInventory.hidden = selected.kind !== "mcp";
|
|
833
870
|
fields.agentSection.hidden = selected.kind !== "agent";
|
|
834
871
|
fields.systemPrompt.value = selected.config.systemPrompt;
|
|
872
|
+
fields.requiresUserInput.checked = selected.config.requiresUserInput;
|
|
873
|
+
syncUserInputDescriptionVisibility();
|
|
874
|
+
fields.userInputDescription.value = selected.config.userInputDescription;
|
|
875
|
+
fields.expectedOutputMarker.value = selected.config.expectedOutputMarker;
|
|
835
876
|
deleteNodeButton.hidden = isProtectedEntity(selected.id);
|
|
836
|
-
|
|
837
|
-
testNodeButton.hidden = selected.kind !== "llm";
|
|
838
|
-
testNodeButton.disabled =
|
|
877
|
+
testNodeButton.textContent = "Test";
|
|
878
|
+
testNodeButton.hidden = selected.kind !== "llm" && selected.kind !== "agent";
|
|
879
|
+
testNodeButton.disabled =
|
|
880
|
+
selected.kind === "llm"
|
|
881
|
+
? !selected.config.model
|
|
882
|
+
: selected.kind !== "agent";
|
|
839
883
|
addButton.title =
|
|
840
884
|
selected.kind === "llm" || entityById(selected.parentId)?.kind === "llm"
|
|
841
885
|
? "Add agent"
|
|
@@ -854,7 +898,25 @@ function syncSelectedFromForm() {
|
|
|
854
898
|
selected.config.timeout = Number(fields.timeout.value || 30);
|
|
855
899
|
selected.config.description = fields.description.value;
|
|
856
900
|
selected.config.systemPrompt = fields.systemPrompt.value;
|
|
901
|
+
selected.config.requiresUserInput = fields.requiresUserInput.checked;
|
|
902
|
+
selected.config.userInputDescription = fields.userInputDescription.value;
|
|
903
|
+
selected.config.expectedOutputMarker = fields.expectedOutputMarker.value;
|
|
904
|
+
syncUserInputDescriptionVisibility();
|
|
857
905
|
fields.typeBadge.textContent = labelForBadge(selected.kind);
|
|
906
|
+
// Propagate model + timeout to child agents
|
|
907
|
+
if (selected.kind === "llm") {
|
|
908
|
+
for (const entity of state.entities) {
|
|
909
|
+
if (entity.parentId === selected.id && entity.kind === "agent") {
|
|
910
|
+
entity.config.model = selected.config.model;
|
|
911
|
+
entity.config.timeout = selected.config.timeout;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
function syncUserInputDescriptionVisibility() {
|
|
917
|
+
const shouldShow = selectedEntity()?.kind === "agent" && fields.requiresUserInput.checked;
|
|
918
|
+
fields.userInputDescriptionField.hidden = !shouldShow;
|
|
919
|
+
fields.userInputDescription.required = shouldShow;
|
|
858
920
|
}
|
|
859
921
|
function restoreModelSelect(savedModel) {
|
|
860
922
|
const existing = Array.from(fields.model.options).map((o) => o.value);
|
|
@@ -867,7 +929,7 @@ function restoreModelSelect(savedModel) {
|
|
|
867
929
|
}
|
|
868
930
|
fields.model.value = savedModel || (existing[0] ?? "");
|
|
869
931
|
}
|
|
870
|
-
|
|
932
|
+
function openAgentRunDialog() {
|
|
871
933
|
const selected = selectedEntity();
|
|
872
934
|
if (!selected || selected.kind !== "agent")
|
|
873
935
|
return;
|
|
@@ -885,38 +947,80 @@ async function runAgent() {
|
|
|
885
947
|
showSaveToast("Write a system prompt first.", "error");
|
|
886
948
|
return;
|
|
887
949
|
}
|
|
888
|
-
|
|
889
|
-
|
|
950
|
+
if (selected.config.requiresUserInput &&
|
|
951
|
+
!selected.config.userInputDescription.trim()) {
|
|
952
|
+
showSaveToast("Describe the required user input first.", "error");
|
|
953
|
+
return;
|
|
954
|
+
}
|
|
955
|
+
agentRunTargetId = selected.id;
|
|
956
|
+
agentRunTitle.textContent = `Test ${selected.label}`;
|
|
957
|
+
agentRunHint.textContent = selected.config.requiresUserInput
|
|
958
|
+
? selected.config.userInputDescription
|
|
959
|
+
: "Run this agent with its configured system prompt.";
|
|
960
|
+
agentRunInputField.hidden = !selected.config.requiresUserInput;
|
|
961
|
+
agentRunInput.required = selected.config.requiresUserInput;
|
|
962
|
+
agentRunInput.value = "";
|
|
963
|
+
agentRunResult.hidden = true;
|
|
964
|
+
agentRunResult.textContent = "";
|
|
965
|
+
executeAgentRunButton.disabled = false;
|
|
966
|
+
executeAgentRunButton.textContent = "Run";
|
|
967
|
+
agentRunOverlay.hidden = false;
|
|
968
|
+
if (selected.config.requiresUserInput) {
|
|
969
|
+
window.setTimeout(() => agentRunInput.focus(), 0);
|
|
970
|
+
}
|
|
971
|
+
else {
|
|
972
|
+
window.setTimeout(() => executeAgentRunButton.focus(), 0);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
function closeAgentRunDialog() {
|
|
976
|
+
agentRunOverlay.hidden = true;
|
|
977
|
+
agentRunTargetId = null;
|
|
978
|
+
}
|
|
979
|
+
async function executeAgentRunFromDialog() {
|
|
980
|
+
if (agentRunInput.required && !agentRunInput.value.trim()) {
|
|
981
|
+
agentRunInput.reportValidity();
|
|
982
|
+
return;
|
|
983
|
+
}
|
|
984
|
+
const selected = agentRunTargetId ? entityById(agentRunTargetId) : null;
|
|
985
|
+
if (!selected || selected.kind !== "agent") {
|
|
986
|
+
showAgentRunResult("error", "The selected agent is no longer available.");
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
const llm = entityById(selected.parentId ?? "");
|
|
990
|
+
if (!llm || llm.kind !== "llm") {
|
|
991
|
+
showAgentRunResult("error", "No parent LLM found for this agent.");
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
994
|
+
executeAgentRunButton.disabled = true;
|
|
995
|
+
executeAgentRunButton.textContent = "Running…";
|
|
996
|
+
showAgentRunResult("loading", "Running agent…");
|
|
890
997
|
const mcpEntity = state.entities.find((e) => e.kind === "mcp");
|
|
891
998
|
const result = await runAgentPrompt({
|
|
892
999
|
endpoint: llm.config.endpoint,
|
|
893
1000
|
token: llm.config.token,
|
|
894
1001
|
model: llm.config.model,
|
|
895
1002
|
systemPrompt: selected.config.systemPrompt,
|
|
896
|
-
userInput:
|
|
1003
|
+
userInput: agentRunInput.value.trim() || undefined,
|
|
897
1004
|
timeout: llm.config.timeout,
|
|
898
1005
|
mcpEndpoint: mcpEntity?.config.endpoint || undefined,
|
|
1006
|
+
expectedOutputMarker: selected.config.expectedOutputMarker || undefined,
|
|
899
1007
|
});
|
|
900
|
-
|
|
1008
|
+
executeAgentRunButton.disabled = false;
|
|
1009
|
+
executeAgentRunButton.textContent = "Run";
|
|
901
1010
|
if (result.ok && result.content) {
|
|
902
|
-
|
|
903
|
-
const item = document.createElement("div");
|
|
904
|
-
item.className = "agent-response-item";
|
|
905
|
-
const meta = document.createElement("div");
|
|
906
|
-
meta.className = "agent-response-meta";
|
|
907
|
-
meta.textContent = new Date().toLocaleTimeString();
|
|
908
|
-
const content = document.createElement("div");
|
|
909
|
-
content.textContent = result.content;
|
|
910
|
-
item.appendChild(meta);
|
|
911
|
-
item.appendChild(content);
|
|
912
|
-
agentResponses.appendChild(item);
|
|
913
|
-
agentResponses.scrollTop = agentResponses.scrollHeight;
|
|
1011
|
+
showAgentRunResult("success", result.content);
|
|
914
1012
|
showSaveToast("Agent responded.", "success");
|
|
915
1013
|
}
|
|
916
1014
|
else {
|
|
1015
|
+
showAgentRunResult("error", result.error ?? "Agent failed.");
|
|
917
1016
|
showSaveToast(result.error ?? "Agent failed.", "error");
|
|
918
1017
|
}
|
|
919
1018
|
}
|
|
1019
|
+
function showAgentRunResult(state, message) {
|
|
1020
|
+
agentRunResult.hidden = false;
|
|
1021
|
+
agentRunResult.dataset.state = state;
|
|
1022
|
+
agentRunResult.textContent = message;
|
|
1023
|
+
}
|
|
920
1024
|
async function loadModelsForSelect() {
|
|
921
1025
|
const selected = selectedEntity();
|
|
922
1026
|
if (!selected || selected.kind !== "llm")
|
|
@@ -930,7 +1034,10 @@ async function loadModelsForSelect() {
|
|
|
930
1034
|
loadModelsButton.classList.add("loading");
|
|
931
1035
|
loadModelsButton.disabled = true;
|
|
932
1036
|
fields.model.disabled = true;
|
|
933
|
-
const result = await listLlmModels({
|
|
1037
|
+
const result = await listLlmModels({
|
|
1038
|
+
endpoint,
|
|
1039
|
+
token: selected.config.token,
|
|
1040
|
+
});
|
|
934
1041
|
loadModelsButton.classList.remove("loading");
|
|
935
1042
|
loadModelsButton.disabled = false;
|
|
936
1043
|
fields.model.disabled = false;
|