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
|
@@ -32,6 +32,9 @@ interface EntityConfig {
|
|
|
32
32
|
description: string;
|
|
33
33
|
workspaceFolder: string;
|
|
34
34
|
systemPrompt: string;
|
|
35
|
+
requiresUserInput: boolean;
|
|
36
|
+
userInputDescription: string;
|
|
37
|
+
expectedOutputMarker: string;
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
interface Entity {
|
|
@@ -144,13 +147,9 @@ const testNodeButton = document.getElementById(
|
|
|
144
147
|
const loadModelsButton = document.getElementById(
|
|
145
148
|
"loadModelsButton",
|
|
146
149
|
) as HTMLButtonElement;
|
|
147
|
-
const
|
|
148
|
-
"
|
|
150
|
+
const closePanelButton = document.getElementById(
|
|
151
|
+
"closePanelButton",
|
|
149
152
|
) as HTMLButtonElement;
|
|
150
|
-
const clearAgentButton = document.getElementById(
|
|
151
|
-
"clearAgentButton",
|
|
152
|
-
) as HTMLButtonElement;
|
|
153
|
-
const agentResponses = document.getElementById("agentResponses") as HTMLElement;
|
|
154
153
|
const deleteNodeButton = document.getElementById(
|
|
155
154
|
"deleteNodeButton",
|
|
156
155
|
) as HTMLButtonElement;
|
|
@@ -178,6 +177,24 @@ const cancelDeleteButton = document.getElementById(
|
|
|
178
177
|
const confirmDeleteButton = document.getElementById(
|
|
179
178
|
"confirmDeleteButton",
|
|
180
179
|
) as HTMLButtonElement;
|
|
180
|
+
const agentRunOverlay = document.getElementById(
|
|
181
|
+
"agentRunOverlay",
|
|
182
|
+
) as HTMLElement;
|
|
183
|
+
const agentRunTitle = document.getElementById("agentRunTitle") as HTMLElement;
|
|
184
|
+
const agentRunHint = document.getElementById("agentRunHint") as HTMLElement;
|
|
185
|
+
const agentRunInputField = document.getElementById(
|
|
186
|
+
"agentRunInputField",
|
|
187
|
+
) as HTMLElement;
|
|
188
|
+
const agentRunInput = document.getElementById(
|
|
189
|
+
"agentRunInput",
|
|
190
|
+
) as HTMLTextAreaElement;
|
|
191
|
+
const agentRunResult = document.getElementById("agentRunResult") as HTMLElement;
|
|
192
|
+
const cancelAgentRunButton = document.getElementById(
|
|
193
|
+
"cancelAgentRunButton",
|
|
194
|
+
) as HTMLButtonElement;
|
|
195
|
+
const executeAgentRunButton = document.getElementById(
|
|
196
|
+
"executeAgentRunButton",
|
|
197
|
+
) as HTMLButtonElement;
|
|
181
198
|
const fallbackPanelHost = document.getElementById(
|
|
182
199
|
"fallbackPanelHost",
|
|
183
200
|
) as HTMLElement;
|
|
@@ -186,13 +203,16 @@ const configSurface = document.getElementById(
|
|
|
186
203
|
) as HTMLFormElement;
|
|
187
204
|
const form = configSurface;
|
|
188
205
|
const workspaceToast = document.getElementById("workspaceToast") as HTMLElement;
|
|
189
|
-
const workspaceToastIcon = document.getElementById(
|
|
206
|
+
const workspaceToastIcon = document.getElementById(
|
|
207
|
+
"workspaceToastIcon",
|
|
208
|
+
) as HTMLElement;
|
|
190
209
|
const workspaceToastMessage = document.getElementById(
|
|
191
210
|
"workspaceToastMessage",
|
|
192
211
|
) as HTMLElement;
|
|
193
212
|
let toastTimerId: number | null = null;
|
|
194
213
|
let savedAgentLabel: string | null = null;
|
|
195
214
|
let savedAgentFolder: string | null = null;
|
|
215
|
+
let agentRunTargetId: string | null = null;
|
|
196
216
|
|
|
197
217
|
const fields = {
|
|
198
218
|
name: document.getElementById("nodeName") as HTMLInputElement,
|
|
@@ -200,9 +220,7 @@ const fields = {
|
|
|
200
220
|
endpoint: document.getElementById("nodeEndpoint") as HTMLInputElement,
|
|
201
221
|
token: document.getElementById("nodeToken") as HTMLInputElement,
|
|
202
222
|
model: document.getElementById("nodeModel") as HTMLSelectElement,
|
|
203
|
-
workspaceField: document.getElementById(
|
|
204
|
-
"agentWorkspaceField",
|
|
205
|
-
) as HTMLElement,
|
|
223
|
+
workspaceField: document.getElementById("agentWorkspaceField") as HTMLElement,
|
|
206
224
|
workspaceFolder: document.getElementById(
|
|
207
225
|
"nodeWorkspaceFolder",
|
|
208
226
|
) as HTMLInputElement,
|
|
@@ -214,8 +232,21 @@ const fields = {
|
|
|
214
232
|
llmFields: document.getElementById("llmFields") as HTMLElement,
|
|
215
233
|
mcpInventory: document.getElementById("mcpInventory") as HTMLElement,
|
|
216
234
|
agentSection: document.getElementById("agentSection") as HTMLElement,
|
|
217
|
-
systemPrompt: document.getElementById(
|
|
218
|
-
|
|
235
|
+
systemPrompt: document.getElementById(
|
|
236
|
+
"nodeSystemPrompt",
|
|
237
|
+
) as HTMLTextAreaElement,
|
|
238
|
+
requiresUserInput: document.getElementById(
|
|
239
|
+
"nodeRequiresUserInput",
|
|
240
|
+
) as HTMLInputElement,
|
|
241
|
+
userInputDescriptionField: document.getElementById(
|
|
242
|
+
"agentUserInputDescriptionField",
|
|
243
|
+
) as HTMLElement,
|
|
244
|
+
userInputDescription: document.getElementById(
|
|
245
|
+
"nodeUserInputDescription",
|
|
246
|
+
) as HTMLTextAreaElement,
|
|
247
|
+
expectedOutputMarker: document.getElementById(
|
|
248
|
+
"nodeExpectedOutputMarker",
|
|
249
|
+
) as HTMLInputElement,
|
|
219
250
|
};
|
|
220
251
|
|
|
221
252
|
const initialEntities: Entity[] = [
|
|
@@ -293,7 +324,6 @@ fitButton.addEventListener("click", () => {
|
|
|
293
324
|
scheduleRender();
|
|
294
325
|
});
|
|
295
326
|
|
|
296
|
-
|
|
297
327
|
canvas.addEventListener("pointerdown", (event) => {
|
|
298
328
|
if (event.target !== canvas) {
|
|
299
329
|
return;
|
|
@@ -398,6 +428,10 @@ form.addEventListener("input", (event) => {
|
|
|
398
428
|
scheduleRender();
|
|
399
429
|
});
|
|
400
430
|
|
|
431
|
+
closePanelButton.addEventListener("click", () => {
|
|
432
|
+
selectEntity(null);
|
|
433
|
+
});
|
|
434
|
+
|
|
401
435
|
deleteNodeButton.addEventListener("click", (event) => {
|
|
402
436
|
event.preventDefault();
|
|
403
437
|
event.stopPropagation();
|
|
@@ -425,6 +459,12 @@ confirmDeleteButton.addEventListener("click", () => {
|
|
|
425
459
|
});
|
|
426
460
|
|
|
427
461
|
testNodeButton.addEventListener("click", () => {
|
|
462
|
+
const selected = selectedEntity();
|
|
463
|
+
if (selected?.kind === "agent") {
|
|
464
|
+
openAgentRunDialog();
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
|
|
428
468
|
void testSelectedLlmConnection();
|
|
429
469
|
});
|
|
430
470
|
|
|
@@ -436,13 +476,18 @@ fields.name.addEventListener("blur", () => {
|
|
|
436
476
|
const selected = selectedEntity();
|
|
437
477
|
if (!selected || selected.kind !== "agent") return;
|
|
438
478
|
const newName = fields.name.value.trim();
|
|
439
|
-
if (
|
|
479
|
+
if (
|
|
480
|
+
!newName ||
|
|
481
|
+
!savedAgentLabel ||
|
|
482
|
+
!savedAgentFolder ||
|
|
483
|
+
newName === savedAgentLabel
|
|
484
|
+
)
|
|
485
|
+
return;
|
|
440
486
|
|
|
441
487
|
const newFolder = workspaceFolderForProvider(newName);
|
|
442
488
|
if (newFolder === savedAgentFolder) return; // slug identique, pas de renommage nécessaire
|
|
443
489
|
|
|
444
|
-
renameConfirmMessage.textContent =
|
|
445
|
-
`Renommer le dossier "${savedAgentFolder}" en "${newFolder}" ?`;
|
|
490
|
+
renameConfirmMessage.textContent = `Renommer le dossier "${savedAgentFolder}" en "${newFolder}" ?`;
|
|
446
491
|
renameConfirmOverlay.hidden = false;
|
|
447
492
|
cancelRenameButton.focus();
|
|
448
493
|
});
|
|
@@ -479,13 +524,18 @@ fields.model.addEventListener("change", () => {
|
|
|
479
524
|
}
|
|
480
525
|
});
|
|
481
526
|
|
|
482
|
-
|
|
483
|
-
|
|
527
|
+
cancelAgentRunButton.addEventListener("click", () => {
|
|
528
|
+
closeAgentRunDialog();
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
executeAgentRunButton.addEventListener("click", () => {
|
|
532
|
+
void executeAgentRunFromDialog();
|
|
484
533
|
});
|
|
485
534
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
535
|
+
agentRunOverlay.addEventListener("click", (event) => {
|
|
536
|
+
if (event.target === agentRunOverlay) {
|
|
537
|
+
closeAgentRunDialog();
|
|
538
|
+
}
|
|
489
539
|
});
|
|
490
540
|
|
|
491
541
|
void initializeWorkspace();
|
|
@@ -501,6 +551,7 @@ function isolateConfirmEvents() {
|
|
|
501
551
|
for (const type of PANEL_EVENT_TYPES) {
|
|
502
552
|
deleteConfirmOverlay.addEventListener(type, stopPanelEventPropagation);
|
|
503
553
|
renameConfirmOverlay.addEventListener(type, stopPanelEventPropagation);
|
|
554
|
+
agentRunOverlay.addEventListener(type, stopPanelEventPropagation);
|
|
504
555
|
}
|
|
505
556
|
}
|
|
506
557
|
|
|
@@ -612,6 +663,9 @@ function hydrateEntity(input: unknown): Entity | null {
|
|
|
612
663
|
stringValue(config.workspaceFolder) ||
|
|
613
664
|
(kind === "agent" ? workspaceFolderForProvider(label) : ""),
|
|
614
665
|
systemPrompt: stringValue(config.systemPrompt),
|
|
666
|
+
requiresUserInput: config.requiresUserInput === true,
|
|
667
|
+
userInputDescription: stringValue(config.userInputDescription),
|
|
668
|
+
expectedOutputMarker: stringValue(config.expectedOutputMarker),
|
|
615
669
|
},
|
|
616
670
|
};
|
|
617
671
|
}
|
|
@@ -664,7 +718,10 @@ function showLoadingToast(message: string) {
|
|
|
664
718
|
workspaceToast.hidden = false;
|
|
665
719
|
}
|
|
666
720
|
|
|
667
|
-
function showSaveToast(
|
|
721
|
+
function showSaveToast(
|
|
722
|
+
message: string,
|
|
723
|
+
state: "success" | "error" = "success",
|
|
724
|
+
) {
|
|
668
725
|
if (toastTimerId) {
|
|
669
726
|
clearTimeout(toastTimerId);
|
|
670
727
|
}
|
|
@@ -736,8 +793,12 @@ function createEntity(id, label, kind, parentId) {
|
|
|
736
793
|
model: "",
|
|
737
794
|
timeout: 180,
|
|
738
795
|
description: defaultDescription(kind),
|
|
739
|
-
workspaceFolder:
|
|
796
|
+
workspaceFolder:
|
|
797
|
+
kind === "agent" ? workspaceFolderForProvider(label) : "",
|
|
740
798
|
systemPrompt: "",
|
|
799
|
+
requiresUserInput: false,
|
|
800
|
+
userInputDescription: "",
|
|
801
|
+
expectedOutputMarker: "",
|
|
741
802
|
},
|
|
742
803
|
};
|
|
743
804
|
}
|
|
@@ -751,7 +812,7 @@ function cloneEntities(entities) {
|
|
|
751
812
|
|
|
752
813
|
function defaultEndpoint(id, kind) {
|
|
753
814
|
if (kind === "llm") {
|
|
754
|
-
return "http://localhost:
|
|
815
|
+
return "http://localhost:11434";
|
|
755
816
|
}
|
|
756
817
|
if (kind === "mcp") {
|
|
757
818
|
return "http://localhost:4321/mcp";
|
|
@@ -1080,7 +1141,11 @@ function selectEntity(id) {
|
|
|
1080
1141
|
state.selectedId = id;
|
|
1081
1142
|
const entity = id ? entityById(id) : null;
|
|
1082
1143
|
savedAgentLabel = entity?.kind === "agent" ? entity.label : null;
|
|
1083
|
-
savedAgentFolder =
|
|
1144
|
+
savedAgentFolder =
|
|
1145
|
+
entity?.kind === "agent"
|
|
1146
|
+
? entity.config.workspaceFolder ||
|
|
1147
|
+
workspaceFolderForProvider(entity.label)
|
|
1148
|
+
: null;
|
|
1084
1149
|
layoutGraph();
|
|
1085
1150
|
syncCameraForPanelChange(hadSelection, Boolean(id), true);
|
|
1086
1151
|
syncPanelFromSelection();
|
|
@@ -1133,6 +1198,7 @@ function syncPanelFromSelection() {
|
|
|
1133
1198
|
|
|
1134
1199
|
if (!selected) {
|
|
1135
1200
|
addButton.title = "Add LLM provider";
|
|
1201
|
+
testNodeButton.textContent = "Test";
|
|
1136
1202
|
testNodeButton.hidden = true;
|
|
1137
1203
|
testNodeButton.disabled = true;
|
|
1138
1204
|
return;
|
|
@@ -1149,14 +1215,22 @@ function syncPanelFromSelection() {
|
|
|
1149
1215
|
fields.description.value = selected.config.description;
|
|
1150
1216
|
fields.typeBadge.textContent = labelForBadge(selected.kind);
|
|
1151
1217
|
fields.kind.disabled = true;
|
|
1152
|
-
fields.llmFields.hidden =
|
|
1218
|
+
fields.llmFields.hidden =
|
|
1219
|
+
selected.kind === "mcp" || selected.kind === "agent";
|
|
1153
1220
|
fields.mcpInventory.hidden = selected.kind !== "mcp";
|
|
1154
1221
|
fields.agentSection.hidden = selected.kind !== "agent";
|
|
1155
1222
|
fields.systemPrompt.value = selected.config.systemPrompt;
|
|
1223
|
+
fields.requiresUserInput.checked = selected.config.requiresUserInput;
|
|
1224
|
+
syncUserInputDescriptionVisibility();
|
|
1225
|
+
fields.userInputDescription.value = selected.config.userInputDescription;
|
|
1226
|
+
fields.expectedOutputMarker.value = selected.config.expectedOutputMarker;
|
|
1156
1227
|
deleteNodeButton.hidden = isProtectedEntity(selected.id);
|
|
1157
|
-
|
|
1158
|
-
testNodeButton.hidden = selected.kind !== "llm";
|
|
1159
|
-
testNodeButton.disabled =
|
|
1228
|
+
testNodeButton.textContent = "Test";
|
|
1229
|
+
testNodeButton.hidden = selected.kind !== "llm" && selected.kind !== "agent";
|
|
1230
|
+
testNodeButton.disabled =
|
|
1231
|
+
selected.kind === "llm"
|
|
1232
|
+
? !selected.config.model
|
|
1233
|
+
: selected.kind !== "agent";
|
|
1160
1234
|
addButton.title =
|
|
1161
1235
|
selected.kind === "llm" || entityById(selected.parentId)?.kind === "llm"
|
|
1162
1236
|
? "Add agent"
|
|
@@ -1177,7 +1251,28 @@ function syncSelectedFromForm() {
|
|
|
1177
1251
|
selected.config.timeout = Number(fields.timeout.value || 30);
|
|
1178
1252
|
selected.config.description = fields.description.value;
|
|
1179
1253
|
selected.config.systemPrompt = fields.systemPrompt.value;
|
|
1254
|
+
selected.config.requiresUserInput = fields.requiresUserInput.checked;
|
|
1255
|
+
selected.config.userInputDescription = fields.userInputDescription.value;
|
|
1256
|
+
selected.config.expectedOutputMarker = fields.expectedOutputMarker.value;
|
|
1257
|
+
syncUserInputDescriptionVisibility();
|
|
1180
1258
|
fields.typeBadge.textContent = labelForBadge(selected.kind);
|
|
1259
|
+
|
|
1260
|
+
// Propagate model + timeout to child agents
|
|
1261
|
+
if (selected.kind === "llm") {
|
|
1262
|
+
for (const entity of state.entities) {
|
|
1263
|
+
if (entity.parentId === selected.id && entity.kind === "agent") {
|
|
1264
|
+
entity.config.model = selected.config.model;
|
|
1265
|
+
entity.config.timeout = selected.config.timeout;
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
function syncUserInputDescriptionVisibility() {
|
|
1272
|
+
const shouldShow =
|
|
1273
|
+
selectedEntity()?.kind === "agent" && fields.requiresUserInput.checked;
|
|
1274
|
+
fields.userInputDescriptionField.hidden = !shouldShow;
|
|
1275
|
+
fields.userInputDescription.required = shouldShow;
|
|
1181
1276
|
}
|
|
1182
1277
|
|
|
1183
1278
|
function restoreModelSelect(savedModel: string) {
|
|
@@ -1192,7 +1287,7 @@ function restoreModelSelect(savedModel: string) {
|
|
|
1192
1287
|
fields.model.value = savedModel || (existing[0] ?? "");
|
|
1193
1288
|
}
|
|
1194
1289
|
|
|
1195
|
-
|
|
1290
|
+
function openAgentRunDialog() {
|
|
1196
1291
|
const selected = selectedEntity();
|
|
1197
1292
|
if (!selected || selected.kind !== "agent") return;
|
|
1198
1293
|
|
|
@@ -1211,9 +1306,60 @@ async function runAgent() {
|
|
|
1211
1306
|
showSaveToast("Write a system prompt first.", "error");
|
|
1212
1307
|
return;
|
|
1213
1308
|
}
|
|
1309
|
+
if (
|
|
1310
|
+
selected.config.requiresUserInput &&
|
|
1311
|
+
!selected.config.userInputDescription.trim()
|
|
1312
|
+
) {
|
|
1313
|
+
showSaveToast("Describe the required user input first.", "error");
|
|
1314
|
+
return;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
agentRunTargetId = selected.id;
|
|
1318
|
+
agentRunTitle.textContent = `Test ${selected.label}`;
|
|
1319
|
+
agentRunHint.textContent = selected.config.requiresUserInput
|
|
1320
|
+
? selected.config.userInputDescription
|
|
1321
|
+
: "Run this agent with its configured system prompt.";
|
|
1322
|
+
agentRunInputField.hidden = !selected.config.requiresUserInput;
|
|
1323
|
+
agentRunInput.required = selected.config.requiresUserInput;
|
|
1324
|
+
agentRunInput.value = "";
|
|
1325
|
+
agentRunResult.hidden = true;
|
|
1326
|
+
agentRunResult.textContent = "";
|
|
1327
|
+
executeAgentRunButton.disabled = false;
|
|
1328
|
+
executeAgentRunButton.textContent = "Run";
|
|
1329
|
+
agentRunOverlay.hidden = false;
|
|
1330
|
+
if (selected.config.requiresUserInput) {
|
|
1331
|
+
window.setTimeout(() => agentRunInput.focus(), 0);
|
|
1332
|
+
} else {
|
|
1333
|
+
window.setTimeout(() => executeAgentRunButton.focus(), 0);
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
function closeAgentRunDialog() {
|
|
1338
|
+
agentRunOverlay.hidden = true;
|
|
1339
|
+
agentRunTargetId = null;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
async function executeAgentRunFromDialog() {
|
|
1343
|
+
if (agentRunInput.required && !agentRunInput.value.trim()) {
|
|
1344
|
+
agentRunInput.reportValidity();
|
|
1345
|
+
return;
|
|
1346
|
+
}
|
|
1214
1347
|
|
|
1215
|
-
|
|
1216
|
-
|
|
1348
|
+
const selected = agentRunTargetId ? entityById(agentRunTargetId) : null;
|
|
1349
|
+
if (!selected || selected.kind !== "agent") {
|
|
1350
|
+
showAgentRunResult("error", "The selected agent is no longer available.");
|
|
1351
|
+
return;
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
const llm = entityById(selected.parentId ?? "");
|
|
1355
|
+
if (!llm || llm.kind !== "llm") {
|
|
1356
|
+
showAgentRunResult("error", "No parent LLM found for this agent.");
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
executeAgentRunButton.disabled = true;
|
|
1361
|
+
executeAgentRunButton.textContent = "Running…";
|
|
1362
|
+
showAgentRunResult("loading", "Running agent…");
|
|
1217
1363
|
|
|
1218
1364
|
const mcpEntity = state.entities.find((e) => e.kind === "mcp");
|
|
1219
1365
|
|
|
@@ -1222,32 +1368,33 @@ async function runAgent() {
|
|
|
1222
1368
|
token: llm.config.token,
|
|
1223
1369
|
model: llm.config.model,
|
|
1224
1370
|
systemPrompt: selected.config.systemPrompt,
|
|
1225
|
-
userInput:
|
|
1371
|
+
userInput: agentRunInput.value.trim() || undefined,
|
|
1226
1372
|
timeout: llm.config.timeout,
|
|
1227
1373
|
mcpEndpoint: mcpEntity?.config.endpoint || undefined,
|
|
1374
|
+
expectedOutputMarker: selected.config.expectedOutputMarker || undefined,
|
|
1228
1375
|
});
|
|
1229
1376
|
|
|
1230
|
-
|
|
1377
|
+
executeAgentRunButton.disabled = false;
|
|
1378
|
+
executeAgentRunButton.textContent = "Run";
|
|
1231
1379
|
|
|
1232
1380
|
if (result.ok && result.content) {
|
|
1233
|
-
|
|
1234
|
-
const item = document.createElement("div");
|
|
1235
|
-
item.className = "agent-response-item";
|
|
1236
|
-
const meta = document.createElement("div");
|
|
1237
|
-
meta.className = "agent-response-meta";
|
|
1238
|
-
meta.textContent = new Date().toLocaleTimeString();
|
|
1239
|
-
const content = document.createElement("div");
|
|
1240
|
-
content.textContent = result.content;
|
|
1241
|
-
item.appendChild(meta);
|
|
1242
|
-
item.appendChild(content);
|
|
1243
|
-
agentResponses.appendChild(item);
|
|
1244
|
-
agentResponses.scrollTop = agentResponses.scrollHeight;
|
|
1381
|
+
showAgentRunResult("success", result.content);
|
|
1245
1382
|
showSaveToast("Agent responded.", "success");
|
|
1246
1383
|
} else {
|
|
1384
|
+
showAgentRunResult("error", result.error ?? "Agent failed.");
|
|
1247
1385
|
showSaveToast(result.error ?? "Agent failed.", "error");
|
|
1248
1386
|
}
|
|
1249
1387
|
}
|
|
1250
1388
|
|
|
1389
|
+
function showAgentRunResult(
|
|
1390
|
+
state: "loading" | "success" | "error",
|
|
1391
|
+
message: string,
|
|
1392
|
+
) {
|
|
1393
|
+
agentRunResult.hidden = false;
|
|
1394
|
+
agentRunResult.dataset.state = state;
|
|
1395
|
+
agentRunResult.textContent = message;
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1251
1398
|
async function loadModelsForSelect() {
|
|
1252
1399
|
const selected = selectedEntity();
|
|
1253
1400
|
if (!selected || selected.kind !== "llm") return;
|
|
@@ -1263,7 +1410,10 @@ async function loadModelsForSelect() {
|
|
|
1263
1410
|
loadModelsButton.disabled = true;
|
|
1264
1411
|
fields.model.disabled = true;
|
|
1265
1412
|
|
|
1266
|
-
const result = await listLlmModels({
|
|
1413
|
+
const result = await listLlmModels({
|
|
1414
|
+
endpoint,
|
|
1415
|
+
token: selected.config.token,
|
|
1416
|
+
});
|
|
1267
1417
|
|
|
1268
1418
|
loadModelsButton.classList.remove("loading");
|
|
1269
1419
|
loadModelsButton.disabled = false;
|
|
@@ -1287,7 +1437,9 @@ async function loadModelsForSelect() {
|
|
|
1287
1437
|
: result.models[0];
|
|
1288
1438
|
selected.config.model = fields.model.value;
|
|
1289
1439
|
testNodeButton.disabled = !fields.model.value;
|
|
1290
|
-
showSaveToast(
|
|
1440
|
+
showSaveToast(
|
|
1441
|
+
`${result.models.length} model${result.models.length === 1 ? "" : "s"} loaded.`,
|
|
1442
|
+
);
|
|
1291
1443
|
scheduleRender();
|
|
1292
1444
|
}
|
|
1293
1445
|
|
|
@@ -1313,7 +1465,10 @@ async function testSelectedLlmConnection() {
|
|
|
1313
1465
|
if (result.ok) {
|
|
1314
1466
|
showSaveToast(result.detail ?? "Connection OK", "success");
|
|
1315
1467
|
} else {
|
|
1316
|
-
showSaveToast(
|
|
1468
|
+
showSaveToast(
|
|
1469
|
+
result.error || `Connection failed (${result.status || "no status"})`,
|
|
1470
|
+
"error",
|
|
1471
|
+
);
|
|
1317
1472
|
}
|
|
1318
1473
|
scheduleRender();
|
|
1319
1474
|
}
|
|
@@ -1587,7 +1742,8 @@ function syncCameraForPanelChange(hadSelection, hasSelection, animate) {
|
|
|
1587
1742
|
// Panel was closed → center selected node in the left area
|
|
1588
1743
|
const selected = selectedEntity();
|
|
1589
1744
|
if (selected) {
|
|
1590
|
-
const panelReserve =
|
|
1745
|
+
const panelReserve =
|
|
1746
|
+
panelWidthForViewport(canvas.clientWidth) + PANEL_GAP;
|
|
1591
1747
|
const availableWidth = canvas.clientWidth - panelReserve;
|
|
1592
1748
|
const targetX = availableWidth / 2 - selected.x * state.zoom;
|
|
1593
1749
|
const appliedDelta = targetX - state.cameraX;
|
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
<meta charset="utf-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
6
|
<title>HTML-in-Canvas Configuration Experiment</title>
|
|
7
|
-
<link
|
|
7
|
+
<link
|
|
8
|
+
rel="stylesheet"
|
|
9
|
+
href="/workspace/styles.css?v=workspace-agent-panel-1"
|
|
10
|
+
/>
|
|
8
11
|
</head>
|
|
9
12
|
<body>
|
|
10
13
|
<main class="app-shell">
|
|
@@ -50,10 +53,10 @@
|
|
|
50
53
|
<div class="panel-kicker">
|
|
51
54
|
<span id="nodeTypeBadge">Provider</span>
|
|
52
55
|
<button
|
|
53
|
-
id="
|
|
54
|
-
class="icon-button
|
|
56
|
+
id="closePanelButton"
|
|
57
|
+
class="icon-button close"
|
|
55
58
|
type="button"
|
|
56
|
-
title="
|
|
59
|
+
title="Close panel"
|
|
57
60
|
>
|
|
58
61
|
×
|
|
59
62
|
</button>
|
|
@@ -87,7 +90,7 @@
|
|
|
87
90
|
id="nodeEndpoint"
|
|
88
91
|
name="nodeEndpoint"
|
|
89
92
|
type="url"
|
|
90
|
-
placeholder="http://localhost:
|
|
93
|
+
placeholder="http://localhost:11434"
|
|
91
94
|
/>
|
|
92
95
|
</label>
|
|
93
96
|
|
|
@@ -163,33 +166,36 @@
|
|
|
163
166
|
placeholder="You are a helpful assistant…"
|
|
164
167
|
></textarea>
|
|
165
168
|
</label>
|
|
166
|
-
<label class="field wide">
|
|
167
|
-
<
|
|
169
|
+
<label class="field wide checkbox-field">
|
|
170
|
+
<input
|
|
171
|
+
id="nodeRequiresUserInput"
|
|
172
|
+
name="nodeRequiresUserInput"
|
|
173
|
+
type="checkbox"
|
|
174
|
+
/>
|
|
175
|
+
<span>Require a user input</span>
|
|
176
|
+
</label>
|
|
177
|
+
<label
|
|
178
|
+
id="agentUserInputDescriptionField"
|
|
179
|
+
class="field wide"
|
|
180
|
+
hidden
|
|
181
|
+
>
|
|
182
|
+
<span>Describe User input</span>
|
|
168
183
|
<textarea
|
|
169
|
-
id="
|
|
170
|
-
name="
|
|
171
|
-
rows="
|
|
172
|
-
placeholder="
|
|
184
|
+
id="nodeUserInputDescription"
|
|
185
|
+
name="nodeUserInputDescription"
|
|
186
|
+
rows="3"
|
|
187
|
+
placeholder="Describe exactly what the user must provide before running this agent."
|
|
173
188
|
></textarea>
|
|
174
189
|
</label>
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
<
|
|
178
|
-
id="
|
|
179
|
-
|
|
180
|
-
type="
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
<button
|
|
185
|
-
id="clearAgentButton"
|
|
186
|
-
class="ghost-button"
|
|
187
|
-
type="button"
|
|
188
|
-
>
|
|
189
|
-
Clear
|
|
190
|
-
</button>
|
|
191
|
-
</div>
|
|
192
|
-
<div id="agentResponses" class="agent-responses" hidden></div>
|
|
190
|
+
<label class="field wide">
|
|
191
|
+
<span>Required output marker</span>
|
|
192
|
+
<input
|
|
193
|
+
id="nodeExpectedOutputMarker"
|
|
194
|
+
name="nodeExpectedOutputMarker"
|
|
195
|
+
type="text"
|
|
196
|
+
placeholder="Optional, e.g. ```mermaid"
|
|
197
|
+
/>
|
|
198
|
+
</label>
|
|
193
199
|
</section>
|
|
194
200
|
|
|
195
201
|
<section id="mcpInventory" class="mcp-inventory" hidden>
|
|
@@ -235,13 +241,24 @@
|
|
|
235
241
|
</section>
|
|
236
242
|
|
|
237
243
|
<footer class="panel-actions">
|
|
238
|
-
<
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
244
|
+
<div class="panel-actions-left">
|
|
245
|
+
<button
|
|
246
|
+
id="testNodeButton"
|
|
247
|
+
class="secondary-button"
|
|
248
|
+
type="button"
|
|
249
|
+
>
|
|
250
|
+
Test
|
|
251
|
+
</button>
|
|
252
|
+
</div>
|
|
253
|
+
<div class="panel-actions-right">
|
|
254
|
+
<button
|
|
255
|
+
id="deleteNodeButton"
|
|
256
|
+
class="danger-button"
|
|
257
|
+
type="button"
|
|
258
|
+
>
|
|
259
|
+
Delete
|
|
260
|
+
</button>
|
|
261
|
+
</div>
|
|
245
262
|
</footer>
|
|
246
263
|
</form>
|
|
247
264
|
</canvas>
|
|
@@ -262,8 +279,20 @@
|
|
|
262
279
|
<p id="renameConfirmMessage" class="confirm-message"></p>
|
|
263
280
|
</div>
|
|
264
281
|
<footer class="confirm-actions">
|
|
265
|
-
<button
|
|
266
|
-
|
|
282
|
+
<button
|
|
283
|
+
id="cancelRenameButton"
|
|
284
|
+
class="secondary-button"
|
|
285
|
+
type="button"
|
|
286
|
+
>
|
|
287
|
+
Annuler
|
|
288
|
+
</button>
|
|
289
|
+
<button
|
|
290
|
+
id="confirmRenameButton"
|
|
291
|
+
class="primary-button"
|
|
292
|
+
type="button"
|
|
293
|
+
>
|
|
294
|
+
Renommer
|
|
295
|
+
</button>
|
|
267
296
|
</footer>
|
|
268
297
|
</section>
|
|
269
298
|
</div>
|
|
@@ -298,6 +327,53 @@
|
|
|
298
327
|
</footer>
|
|
299
328
|
</section>
|
|
300
329
|
</div>
|
|
330
|
+
|
|
331
|
+
<div id="agentRunOverlay" class="confirm-overlay" hidden>
|
|
332
|
+
<section
|
|
333
|
+
class="agent-run-dialog"
|
|
334
|
+
role="dialog"
|
|
335
|
+
aria-modal="true"
|
|
336
|
+
aria-labelledby="agentRunTitle"
|
|
337
|
+
>
|
|
338
|
+
<div>
|
|
339
|
+
<p class="confirm-kicker">Agent test</p>
|
|
340
|
+
<h2 id="agentRunTitle">Run agent</h2>
|
|
341
|
+
<p id="agentRunHint" class="confirm-message"></p>
|
|
342
|
+
</div>
|
|
343
|
+
|
|
344
|
+
<label
|
|
345
|
+
id="agentRunInputField"
|
|
346
|
+
class="field wide agent-run-input-field"
|
|
347
|
+
>
|
|
348
|
+
<span>User input</span>
|
|
349
|
+
<textarea
|
|
350
|
+
id="agentRunInput"
|
|
351
|
+
name="agentRunInput"
|
|
352
|
+
rows="6"
|
|
353
|
+
placeholder="Document ID, question, or any input for the agent…"
|
|
354
|
+
></textarea>
|
|
355
|
+
</label>
|
|
356
|
+
|
|
357
|
+
<div id="agentRunResult" class="agent-run-result" hidden></div>
|
|
358
|
+
|
|
359
|
+
<footer class="confirm-actions">
|
|
360
|
+
<button
|
|
361
|
+
id="cancelAgentRunButton"
|
|
362
|
+
class="secondary-button"
|
|
363
|
+
type="button"
|
|
364
|
+
>
|
|
365
|
+
Close
|
|
366
|
+
</button>
|
|
367
|
+
<button
|
|
368
|
+
id="executeAgentRunButton"
|
|
369
|
+
class="primary-button"
|
|
370
|
+
type="button"
|
|
371
|
+
>
|
|
372
|
+
Run
|
|
373
|
+
</button>
|
|
374
|
+
</footer>
|
|
375
|
+
</section>
|
|
376
|
+
</div>
|
|
301
377
|
</main>
|
|
302
378
|
|
|
303
379
|
<div
|
|
@@ -313,6 +389,9 @@
|
|
|
313
389
|
<span id="workspaceToastMessage">Workspace saved</span>
|
|
314
390
|
</div>
|
|
315
391
|
|
|
316
|
-
<script
|
|
392
|
+
<script
|
|
393
|
+
type="module"
|
|
394
|
+
src="/workspace/app.js?v=workspace-agent-panel-1"
|
|
395
|
+
></script>
|
|
317
396
|
</body>
|
|
318
397
|
</html>
|