loopengine 0.3.6 → 0.3.7
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/web/agents-config-page.js +47 -13
- package/package.json +1 -1
|
@@ -49,6 +49,7 @@ export const agentsConfigPageHtml = `<!doctype html>
|
|
|
49
49
|
form.add-source .schedule-when input[type="number"] { width: 80px; }
|
|
50
50
|
form.add-source .schedule-when select, form.add-source .schedule-when input[type="datetime-local"] { width: auto; }
|
|
51
51
|
.workflow-card { margin-bottom: 10px; }
|
|
52
|
+
tr.schedule-focus td { background: var(--le-accent-soft, #e6f4ef); transition: background 0.3s; }
|
|
52
53
|
.workflow-starts { margin: 10px 0 0; padding: 10px 12px; border: 1px solid var(--le-line, #e5e7eb); border-radius: 8px; background: var(--le-surface, #f6f7f9); }
|
|
53
54
|
.workflow-starts h4 { margin: 0; font-size: 13.5px; font-weight: 600; }
|
|
54
55
|
.wf-start { padding: 10px 0; border-top: 1px solid var(--le-line, #e5e7eb); display: grid; gap: 6px; font-size: 13px; }
|
|
@@ -709,7 +710,7 @@ ${consoleShellScript}
|
|
|
709
710
|
return text.charAt(0).toUpperCase() + text.slice(1);
|
|
710
711
|
}
|
|
711
712
|
|
|
712
|
-
//
|
|
713
|
+
// Ways to run it: four, each with a ? that says what it is. A
|
|
713
714
|
// schedule (pause, resume, remove, add), a webhook, Run now with the
|
|
714
715
|
// values a run is given, and the API call an app makes.
|
|
715
716
|
function wfStartSection(key, title, help, body) {
|
|
@@ -722,14 +723,15 @@ ${consoleShellScript}
|
|
|
722
723
|
function workflowStartsHtml(w, agentName, paramsHtml) {
|
|
723
724
|
var schedules = (w.schedules || []).map(function (x) {
|
|
724
725
|
var state = x.waiting ? '<span class="le-pill ask">Waiting for a decision</span>'
|
|
725
|
-
: x.status === 'paused' ? '<span class="le-pill">Paused</span>'
|
|
726
|
+
: x.status === 'paused' ? '<span class="le-pill warn">Paused</span>'
|
|
726
727
|
: x.status === 'running' ? '<span class="le-pill accent">Running</span>'
|
|
727
728
|
: (x.nextRunAt ? '<span class="hint">next ' + escapeHtml(new Date(x.nextRunAt).toLocaleString()) + '</span>' : '');
|
|
728
729
|
var values = x.params ? Object.keys(x.params).map(function (k) { return escapeHtml(k) + ': ' + escapeHtml(x.params[k]); }).join(' ' + String.fromCharCode(183) + ' ') : '';
|
|
729
730
|
return '<li style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">' +
|
|
730
|
-
'<span
|
|
731
|
+
'<span><a href="?agent=' + encodeURIComponent(agentName) + '&tab=schedules#schedule-' + escapeHtml(x.taskId) + '" class="workflow-schedule-link" data-task="' + escapeHtml(x.taskId) + '" title="See it in the Schedules tab">' +
|
|
732
|
+
escapeHtml(x.describe.charAt(0).toUpperCase() + x.describe.slice(1)) + '</a></span>' + state +
|
|
731
733
|
(values ? '<span class="hint">' + values + '</span>' : '') +
|
|
732
|
-
(x.notify ? '<span class="hint">
|
|
734
|
+
(x.notify ? '<span class="hint">results go to your messaging app</span>' : '') +
|
|
733
735
|
'<span style="display:flex;gap:6px;margin-left:auto">' +
|
|
734
736
|
(x.status === 'paused' ? '<button type="button" class="workflow-schedule-action" data-id="' + escapeHtml(x.taskId) + '" data-action="resume">Resume</button>'
|
|
735
737
|
: x.status === 'scheduled' ? '<button type="button" class="workflow-schedule-action" data-id="' + escapeHtml(x.taskId) + '" data-action="pause">Pause</button>' : '') +
|
|
@@ -737,11 +739,11 @@ ${consoleShellScript}
|
|
|
737
739
|
'</span></li>';
|
|
738
740
|
}).join('');
|
|
739
741
|
var paramNames = Object.keys(w.parameters || {});
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
742
|
+
// A body that shows what a call can carry: its values, and waiting
|
|
743
|
+
// for the result.
|
|
744
|
+
var example = '{ ' + (paramNames.length ? '"params": { ' + paramNames.map(function (p) { return '"' + p + '": "' + String.fromCharCode(8230) + '"'; }).join(', ') + ' }, ' : '') + '"wait": true }';
|
|
743
745
|
var apiUrl = location.origin + '/agents/' + encodeURIComponent(agentName) + '/workflows/' + encodeURIComponent(w.id) + '/run';
|
|
744
|
-
return '<div class="workflow-starts"><h4>
|
|
746
|
+
return '<div class="workflow-starts"><h4>Ways to run it</h4>' +
|
|
745
747
|
wfStartSection('schedule-' + w.id, 'Schedule',
|
|
746
748
|
'Runs it on a timer, like every day at 9:00, with the values you give the schedule. Nobody needs to be there: approvals and questions go to the agent' + String.fromCharCode(8217) + 's messaging app.',
|
|
747
749
|
(schedules ? '<ul class="schedule-history">' + schedules + '</ul>' : '<span class="hint">None yet.</span>') +
|
|
@@ -756,7 +758,9 @@ ${consoleShellScript}
|
|
|
756
758
|
'<div><button type="button" class="workflow-run primary">Run now</button></div>') +
|
|
757
759
|
wfStartSection('api-' + w.id, 'API',
|
|
758
760
|
'Your own app starts a run by calling this address with an API key. Add "wait": true to get the result in the answer, or "callback_url" to have it posted to you when the run ends.',
|
|
759
|
-
'<pre>POST ' + escapeHtml(apiUrl) + String.fromCharCode(10) + escapeHtml(example) + '</pre>'
|
|
761
|
+
'<pre>POST ' + escapeHtml(apiUrl) + String.fromCharCode(10) + escapeHtml(example) + '</pre>' +
|
|
762
|
+
'<p class="hint" style="margin:0">' + (paramNames.length ? '<code>params</code>: ' + paramNames.map(function (p) { return '<code>' + escapeHtml(p) + '</code>' + (w.parameters[p].required ? ' (required)' : '') + (w.parameters[p].description ? ', ' + escapeHtml(w.parameters[p].description) : ''); }).join('; ') + '. ' : 'It takes no params. ') +
|
|
763
|
+
'Optional: <code>"wait": true</code> answers with the result; <code>"notify": true</code> sends it through the agent' + String.fromCharCode(8217) + 's messaging app; <code>"callback_url"</code> posts it to your app when the run ends. Leave them out to get the run' + String.fromCharCode(8217) + 's id back at once.</p>') +
|
|
760
764
|
'</div>';
|
|
761
765
|
}
|
|
762
766
|
|
|
@@ -771,7 +775,7 @@ ${consoleShellScript}
|
|
|
771
775
|
: s.waiting
|
|
772
776
|
? '<span class="le-pill ask">Waiting for a decision</span>'
|
|
773
777
|
: s.status === 'paused'
|
|
774
|
-
? '<span class="le-pill">Schedule paused</span>'
|
|
778
|
+
? '<span class="le-pill warn">Schedule paused</span>'
|
|
775
779
|
: s.status === 'running'
|
|
776
780
|
? '<span class="le-pill accent">Running</span>'
|
|
777
781
|
: '<span class="le-pill good">On</span>' + (s.nextRunAt ? ' <span class="hint">next ' + escapeHtml(new Date(s.nextRunAt).toLocaleString()) + '</span>' : '');
|
|
@@ -833,6 +837,24 @@ ${consoleShellScript}
|
|
|
833
837
|
var workflowsRefreshTimer = null;
|
|
834
838
|
// Set by a workflow's "Add a schedule", for the Schedules tab's form.
|
|
835
839
|
var pendingScheduleWorkflow = null;
|
|
840
|
+
// Set by a schedule on a workflow card (or a #schedule-<id> link): the
|
|
841
|
+
// Schedules tab's row to show.
|
|
842
|
+
var pendingScheduleFocus = /^#schedule-/.test(location.hash) ? location.hash.slice('#schedule-'.length) : null;
|
|
843
|
+
|
|
844
|
+
// Scrolls to that row and marks it for a moment, once the tab has drawn
|
|
845
|
+
// it (it may still be loading).
|
|
846
|
+
function focusScheduleRow(tries) {
|
|
847
|
+
if (!pendingScheduleFocus) return;
|
|
848
|
+
var row = detail.querySelector('#schedule-' + CSS.escape(pendingScheduleFocus));
|
|
849
|
+
if (!row) {
|
|
850
|
+
if ((tries || 0) < 40) setTimeout(function () { focusScheduleRow((tries || 0) + 1); }, 150);
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
pendingScheduleFocus = null;
|
|
854
|
+
row.scrollIntoView({ block: 'center' });
|
|
855
|
+
row.classList.add('schedule-focus');
|
|
856
|
+
setTimeout(function () { row.classList.remove('schedule-focus'); }, 2500);
|
|
857
|
+
}
|
|
836
858
|
var workflowsById = {};
|
|
837
859
|
// Set while a workflow's editor is open, so the running-run refresh
|
|
838
860
|
// doesn't redraw the card under someone typing.
|
|
@@ -1134,6 +1156,17 @@ ${consoleShellScript}
|
|
|
1134
1156
|
var result = card.querySelector('.workflow-result');
|
|
1135
1157
|
var base = '/agents/' + encodeURIComponent(name) + '/workflows/' + encodeURIComponent(id);
|
|
1136
1158
|
card.querySelector('.workflow-edit').addEventListener('click', function () { openWorkflowEditor(name, card); });
|
|
1159
|
+
// A schedule opens its own row in the Schedules tab.
|
|
1160
|
+
var scheduleLinks = card.querySelectorAll('.workflow-schedule-link');
|
|
1161
|
+
for (var sl = 0; sl < scheduleLinks.length; sl++) {
|
|
1162
|
+
scheduleLinks[sl].addEventListener('click', function (ev) {
|
|
1163
|
+
if (ev.metaKey || ev.ctrlKey || ev.shiftKey) return;
|
|
1164
|
+
ev.preventDefault();
|
|
1165
|
+
pendingScheduleFocus = ev.currentTarget.dataset.task;
|
|
1166
|
+
switchTab('schedules');
|
|
1167
|
+
focusScheduleRow();
|
|
1168
|
+
});
|
|
1169
|
+
}
|
|
1137
1170
|
// The ? beside each way it starts shows or hides what it is.
|
|
1138
1171
|
var helps = card.querySelectorAll('.help-q');
|
|
1139
1172
|
for (var hq = 0; hq < helps.length; hq++) {
|
|
@@ -2345,7 +2378,7 @@ ${consoleShellScript}
|
|
|
2345
2378
|
return '<li><span class="le-pill ' + (h.status === 'ok' ? 'good' : 'bad') + '">' + escapeHtml(h.status) + '</span> <span class="hint">' + escapeHtml(fmtScheduleTime(h.ran_at)) + '</span>' +
|
|
2346
2379
|
'<div class="schedule-result">' + escapeHtml(h.status === 'ok' ? (h.result || '') : (h.error || '')) + '</div></li>';
|
|
2347
2380
|
}).join('');
|
|
2348
|
-
return '<tr>' +
|
|
2381
|
+
return '<tr id="schedule-' + escapeHtml(t.task_id) + '">' +
|
|
2349
2382
|
'<td style="min-width:180px"><strong>' + escapeHtml(t.task_name || 'Untitled') + '</strong>' +
|
|
2350
2383
|
(t.workflow
|
|
2351
2384
|
? '<div><span class="le-pill accent">Workflow</span> ' + escapeHtml(t.workflow.title) + '</div><div class="schedule-result hint">' + escapeHtml(t.workflow.start_message) +
|
|
@@ -2381,7 +2414,7 @@ ${consoleShellScript}
|
|
|
2381
2414
|
return '<option value="' + escapeHtml(w.id) + '">' + escapeHtml(w.title) + '</option>';
|
|
2382
2415
|
}).join('') + '</select></div>' +
|
|
2383
2416
|
'<div class="workflow-params" id="scheduleParams" style="margin:0 0 4px 22px"></div>' +
|
|
2384
|
-
'<p class="hint" style="margin:0 0 4px 22px">Each run
|
|
2417
|
+
'<p class="hint" style="margin:0 0 4px 22px">Each run follows the workflow's instructions as they are then, so changing the workflow changes what runs.</p>' +
|
|
2385
2418
|
'<div class="schedule-when"><input type="radio" name="runs" value="message" id="runsMessage"><label for="runsMessage">A message</label></div>' +
|
|
2386
2419
|
'</div>'
|
|
2387
2420
|
: '') +
|
|
@@ -2480,6 +2513,7 @@ ${consoleShellScript}
|
|
|
2480
2513
|
form.scrollIntoView({ block: 'start' });
|
|
2481
2514
|
}
|
|
2482
2515
|
pendingScheduleWorkflow = null;
|
|
2516
|
+
focusScheduleRow();
|
|
2483
2517
|
renderScheduleParams();
|
|
2484
2518
|
if (workflowSelect) workflowSelect.addEventListener('change', renderScheduleParams);
|
|
2485
2519
|
for (var k = 0; k < runsRadios.length; k++) {
|
|
@@ -4413,7 +4447,7 @@ ${consoleShellScript}
|
|
|
4413
4447
|
'<div class="tab-panel" data-tab-panel="overview">' + renderOverviewHtml(cfg) + '</div>' +
|
|
4414
4448
|
// Workflows: the jobs this agent does, each with what starts it.
|
|
4415
4449
|
'<div class="tab-panel" data-tab-panel="workflows">' +
|
|
4416
|
-
'<p class="muted" style="margin:0 0 20px">The jobs this agent does on its own: what it does,
|
|
4450
|
+
'<p class="muted" style="margin:0 0 20px">The jobs this agent does on its own: what it does, the ways to run it (a schedule, a webhook, Run now or an app's API call) and how its runs went. In Chat it can do them too, when you ask.</p>' +
|
|
4417
4451
|
'<section id="workflowsSection"><div id="workflowsContent"><p class="hint">Loading…</p></div></section>' +
|
|
4418
4452
|
'</div>' +
|
|
4419
4453
|
// Advanced: the agent's own tools (and Composio, subagents), then its
|