loopengine 0.3.5 → 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.
|
@@ -49,6 +49,19 @@ 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; }
|
|
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); }
|
|
54
|
+
.workflow-starts h4 { margin: 0; font-size: 13.5px; font-weight: 600; }
|
|
55
|
+
.wf-start { padding: 10px 0; border-top: 1px solid var(--le-line, #e5e7eb); display: grid; gap: 6px; font-size: 13px; }
|
|
56
|
+
.wf-start:first-of-type { border-top: 0; padding-top: 6px; }
|
|
57
|
+
.wf-start-head { display: flex; align-items: center; gap: 6px; }
|
|
58
|
+
.wf-start-head strong { font-size: 13px; }
|
|
59
|
+
.help-q { width: 18px; height: 18px; padding: 0; border-radius: 50%; font-size: 11px; line-height: 16px; font-weight: 600; text-align: center; cursor: pointer; }
|
|
60
|
+
.help-text { margin: 0; }
|
|
61
|
+
.help-text[hidden] { display: none; }
|
|
62
|
+
.wf-start .schedule-history { margin: 0; gap: 6px; }
|
|
63
|
+
.wf-start .workflow-params { margin: 0; }
|
|
64
|
+
.wf-start pre { margin: 0; padding: 8px 10px; border-radius: 6px; background: var(--le-bg, #fff); border: 1px solid var(--le-line, #e5e7eb); font-size: 12px; white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
52
65
|
.workflow-steps-text { white-space: pre-wrap; overflow-wrap: anywhere; font-size: 13px; margin: 6px 0 0; padding: 8px 10px; border-radius: 6px; background: var(--le-surface, #f6f7f9); }
|
|
53
66
|
.workflow-params { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
|
|
54
67
|
.workflow-params[hidden] { display: none; }
|
|
@@ -692,39 +705,63 @@ ${consoleShellScript}
|
|
|
692
705
|
function workflowStartsSummary(w) {
|
|
693
706
|
var parts = (w.schedules || []).filter(function (x) { return x.repeating && x.status !== 'paused'; }).map(function (x) { return x.describe; });
|
|
694
707
|
if (w.webhooks) parts.push(w.webhooks === 1 ? 'when its webhook is called' : 'when one of its ' + w.webhooks + ' webhooks is called');
|
|
695
|
-
if (!parts.length) return '
|
|
708
|
+
if (!parts.length) return 'No schedule or webhook yet';
|
|
696
709
|
var text = parts.join(', and ');
|
|
697
710
|
return text.charAt(0).toUpperCase() + text.slice(1);
|
|
698
711
|
}
|
|
699
712
|
|
|
700
|
-
//
|
|
701
|
-
//
|
|
702
|
-
|
|
713
|
+
// Ways to run it: four, each with a ? that says what it is. A
|
|
714
|
+
// schedule (pause, resume, remove, add), a webhook, Run now with the
|
|
715
|
+
// values a run is given, and the API call an app makes.
|
|
716
|
+
function wfStartSection(key, title, help, body) {
|
|
717
|
+
return '<div class="wf-start">' +
|
|
718
|
+
'<div class="wf-start-head"><strong>' + title + '</strong>' +
|
|
719
|
+
'<button type="button" class="help-q" aria-expanded="false" aria-controls="help-' + key + '" aria-label="What is ' + title.toLowerCase() + '?">?</button></div>' +
|
|
720
|
+
'<p class="hint help-text" hidden>' + help + '</p>' + body + '</div>';
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
function workflowStartsHtml(w, agentName, paramsHtml) {
|
|
703
724
|
var schedules = (w.schedules || []).map(function (x) {
|
|
704
725
|
var state = x.waiting ? '<span class="le-pill ask">Waiting for a decision</span>'
|
|
705
|
-
: x.status === 'paused' ? '<span class="le-pill">Paused</span>'
|
|
726
|
+
: x.status === 'paused' ? '<span class="le-pill warn">Paused</span>'
|
|
706
727
|
: x.status === 'running' ? '<span class="le-pill accent">Running</span>'
|
|
707
728
|
: (x.nextRunAt ? '<span class="hint">next ' + escapeHtml(new Date(x.nextRunAt).toLocaleString()) + '</span>' : '');
|
|
708
729
|
var values = x.params ? Object.keys(x.params).map(function (k) { return escapeHtml(k) + ': ' + escapeHtml(x.params[k]); }).join(' ' + String.fromCharCode(183) + ' ') : '';
|
|
709
730
|
return '<li style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">' +
|
|
710
|
-
'<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 +
|
|
711
733
|
(values ? '<span class="hint">' + values + '</span>' : '') +
|
|
712
|
-
(x.notify ? '<span class="hint">
|
|
734
|
+
(x.notify ? '<span class="hint">results go to your messaging app</span>' : '') +
|
|
713
735
|
'<span style="display:flex;gap:6px;margin-left:auto">' +
|
|
714
736
|
(x.status === 'paused' ? '<button type="button" class="workflow-schedule-action" data-id="' + escapeHtml(x.taskId) + '" data-action="resume">Resume</button>'
|
|
715
737
|
: x.status === 'scheduled' ? '<button type="button" class="workflow-schedule-action" data-id="' + escapeHtml(x.taskId) + '" data-action="pause">Pause</button>' : '') +
|
|
716
738
|
'<button type="button" class="delete-btn workflow-schedule-action" data-id="' + escapeHtml(x.taskId) + '" data-action="cancel">Remove</button>' +
|
|
717
739
|
'</span></li>';
|
|
718
740
|
}).join('');
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
'
|
|
727
|
-
|
|
741
|
+
var paramNames = Object.keys(w.parameters || {});
|
|
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 }';
|
|
745
|
+
var apiUrl = location.origin + '/agents/' + encodeURIComponent(agentName) + '/workflows/' + encodeURIComponent(w.id) + '/run';
|
|
746
|
+
return '<div class="workflow-starts"><h4>Ways to run it</h4>' +
|
|
747
|
+
wfStartSection('schedule-' + w.id, 'Schedule',
|
|
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.',
|
|
749
|
+
(schedules ? '<ul class="schedule-history">' + schedules + '</ul>' : '<span class="hint">None yet.</span>') +
|
|
750
|
+
'<div><button type="button" class="workflow-add-schedule">Add a schedule</button></div>') +
|
|
751
|
+
wfStartSection('webhook-' + w.id, 'Webhook',
|
|
752
|
+
'A private web address another app (Stripe, GitHub, Shopify or your own) calls when something happens. Each call starts a run, with values taken from what the app sends.',
|
|
753
|
+
'<span' + (w.webhooks ? '' : ' class="hint"') + '>' + (w.webhooks ? (w.webhooks === 1 ? '1 webhook is on.' : w.webhooks + ' webhooks are on.') : 'None yet.') + '</span>' +
|
|
754
|
+
'<div><button type="button" class="workflow-hooks-btn">' + (w.webhooks ? 'Webhooks' : 'Add a webhook') + '</button></div>') +
|
|
755
|
+
wfStartSection('run-' + w.id, 'Run now',
|
|
756
|
+
'Starts a run right away, from here' + (paramNames.length ? ', with the values you fill in' : '') + '. It shows under Recent runs as it goes.',
|
|
757
|
+
(paramsHtml ? '<div class="workflow-params">' + paramsHtml + '</div>' : '') +
|
|
758
|
+
'<div><button type="button" class="workflow-run primary">Run now</button></div>') +
|
|
759
|
+
wfStartSection('api-' + w.id, 'API',
|
|
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.',
|
|
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>') +
|
|
764
|
+
'</div>';
|
|
728
765
|
}
|
|
729
766
|
|
|
730
767
|
function renderWorkflowsHtml(name, workflows) {
|
|
@@ -738,7 +775,7 @@ ${consoleShellScript}
|
|
|
738
775
|
: s.waiting
|
|
739
776
|
? '<span class="le-pill ask">Waiting for a decision</span>'
|
|
740
777
|
: s.status === 'paused'
|
|
741
|
-
? '<span class="le-pill">Schedule paused</span>'
|
|
778
|
+
? '<span class="le-pill warn">Schedule paused</span>'
|
|
742
779
|
: s.status === 'running'
|
|
743
780
|
? '<span class="le-pill accent">Running</span>'
|
|
744
781
|
: '<span class="le-pill good">On</span>' + (s.nextRunAt ? ' <span class="hint">next ' + escapeHtml(new Date(s.nextRunAt).toLocaleString()) + '</span>' : '');
|
|
@@ -763,15 +800,15 @@ ${consoleShellScript}
|
|
|
763
800
|
'<div style="display:flex;justify-content:space-between;gap:10px;flex-wrap:wrap;align-items:baseline">' +
|
|
764
801
|
'<strong>' + escapeHtml(w.title) + '</strong><span>' + state + '</span></div>' +
|
|
765
802
|
'<p class="hint" style="margin:4px 0 6px">' + escapeHtml(w.description) + (s ? ' ' + String.fromCharCode(183) + ' ' + escapeHtml(workflowStartsSummary(w)) : '') + '</p>' +
|
|
766
|
-
'<details><summary class="hint">Instructions <span>(the ' + escapeHtml(w.id) + ' skill)</span></summary><div class="workflow-steps-text">' + escapeHtml(w.instructions) + '</div></details>' +
|
|
767
|
-
workflowStartsHtml(w) +
|
|
768
|
-
|
|
769
|
-
(runs ? '<details class="workflow-runs"' + ((w.recentRuns || []).some(function (r) { return r.status === 'running' || r.status === 'awaiting_approval'; }) ? ' open' : '') + '><summary class="hint">Recent runs (' + w.recentRuns.length + ')</summary><ul class="schedule-history">' + runs + '</ul></details>'
|
|
770
|
-
|
|
771
|
-
|
|
803
|
+
'<details open><summary class="hint">Instructions <span>(the ' + escapeHtml(w.id) + ' skill)</span></summary><div class="workflow-steps-text">' + escapeHtml(w.instructions) + '</div></details>' +
|
|
804
|
+
workflowStartsHtml(w, name, params) +
|
|
805
|
+
'<div class="hint workflow-result" style="margin-top:6px"></div><div class="workflow-hooks" hidden></div>' +
|
|
806
|
+
(runs ? '<details class="workflow-runs" style="margin-top:10px"' + ((w.recentRuns || []).some(function (r) { return r.status === 'running' || r.status === 'awaiting_approval'; }) ? ' open' : '') + '><summary class="hint">Recent runs (' + w.recentRuns.length + ')</summary><ul class="schedule-history">' + runs + '</ul></details>'
|
|
807
|
+
: '<p class="hint" style="margin:10px 0 0">No runs yet.</p>') +
|
|
808
|
+
'<div style="display:flex;gap:6px;flex-wrap:wrap;margin-top:10px">' +
|
|
772
809
|
'<button type="button" class="workflow-edit">Edit</button>' +
|
|
773
|
-
'<button type="button" class="delete-btn workflow-forget">
|
|
774
|
-
'</div><div class="
|
|
810
|
+
'<button type="button" class="delete-btn workflow-forget">Remove workflow</button>' +
|
|
811
|
+
'</div><div class="workflow-editor" hidden></div></div>';
|
|
775
812
|
}).join('') + '<p class="hint" style="margin:6px 0 0"><a href="/workflows/new">Describe another workflow</a></p>';
|
|
776
813
|
}
|
|
777
814
|
|
|
@@ -800,6 +837,24 @@ ${consoleShellScript}
|
|
|
800
837
|
var workflowsRefreshTimer = null;
|
|
801
838
|
// Set by a workflow's "Add a schedule", for the Schedules tab's form.
|
|
802
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
|
+
}
|
|
803
858
|
var workflowsById = {};
|
|
804
859
|
// Set while a workflow's editor is open, so the running-run refresh
|
|
805
860
|
// doesn't redraw the card under someone typing.
|
|
@@ -1101,6 +1156,27 @@ ${consoleShellScript}
|
|
|
1101
1156
|
var result = card.querySelector('.workflow-result');
|
|
1102
1157
|
var base = '/agents/' + encodeURIComponent(name) + '/workflows/' + encodeURIComponent(id);
|
|
1103
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
|
+
}
|
|
1170
|
+
// The ? beside each way it starts shows or hides what it is.
|
|
1171
|
+
var helps = card.querySelectorAll('.help-q');
|
|
1172
|
+
for (var hq = 0; hq < helps.length; hq++) {
|
|
1173
|
+
helps[hq].addEventListener('click', function (ev) {
|
|
1174
|
+
var btn = ev.currentTarget;
|
|
1175
|
+
var text = btn.closest('.wf-start').querySelector('.help-text');
|
|
1176
|
+
text.hidden = !text.hidden;
|
|
1177
|
+
btn.setAttribute('aria-expanded', String(!text.hidden));
|
|
1178
|
+
});
|
|
1179
|
+
}
|
|
1104
1180
|
card.querySelector('.workflow-hooks-btn').addEventListener('click', function () { openWorkflowHooks(name, card); });
|
|
1105
1181
|
// Add a schedule: the Schedules tab's form, with this workflow chosen.
|
|
1106
1182
|
card.querySelector('.workflow-add-schedule').addEventListener('click', function () {
|
|
@@ -1137,7 +1213,7 @@ ${consoleShellScript}
|
|
|
1137
1213
|
});
|
|
1138
1214
|
card.querySelector('.workflow-forget').addEventListener('click', function (ev) {
|
|
1139
1215
|
var btn = ev.currentTarget;
|
|
1140
|
-
if (btn.dataset.confirming !== '1') { btn.dataset.confirming = '1'; btn.textContent = 'Click again
|
|
1216
|
+
if (btn.dataset.confirming !== '1') { btn.dataset.confirming = '1'; btn.textContent = 'Click again: its schedules and webhooks go; its instructions stay as a skill for Chat'; return; }
|
|
1141
1217
|
fetchJsonRetryOnce(base, { method: 'DELETE' }).then(function () { loadWorkflowsSection(name); });
|
|
1142
1218
|
});
|
|
1143
1219
|
}
|
|
@@ -2302,7 +2378,7 @@ ${consoleShellScript}
|
|
|
2302
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>' +
|
|
2303
2379
|
'<div class="schedule-result">' + escapeHtml(h.status === 'ok' ? (h.result || '') : (h.error || '')) + '</div></li>';
|
|
2304
2380
|
}).join('');
|
|
2305
|
-
return '<tr>' +
|
|
2381
|
+
return '<tr id="schedule-' + escapeHtml(t.task_id) + '">' +
|
|
2306
2382
|
'<td style="min-width:180px"><strong>' + escapeHtml(t.task_name || 'Untitled') + '</strong>' +
|
|
2307
2383
|
(t.workflow
|
|
2308
2384
|
? '<div><span class="le-pill accent">Workflow</span> ' + escapeHtml(t.workflow.title) + '</div><div class="schedule-result hint">' + escapeHtml(t.workflow.start_message) +
|
|
@@ -2327,7 +2403,7 @@ ${consoleShellScript}
|
|
|
2327
2403
|
var list = tasks.length
|
|
2328
2404
|
? '<div class="le-table-wrap"><table><thead><tr><th>Task</th><th>When</th><th>Status</th><th>Last run</th><th></th></tr></thead><tbody>' + tasks.map(renderScheduleRow).join('') + '</tbody></table></div>'
|
|
2329
2405
|
: '<p class="hint">Nothing scheduled yet.</p>';
|
|
2330
|
-
return '<p class="muted" style="margin:0 0 20px">Workflows and messages this agent runs on a timer, like a cron job. A workflow schedule
|
|
2406
|
+
return '<p class="muted" style="margin:0 0 20px">Workflows and messages this agent runs on a timer, like a cron job. A workflow schedule runs the workflow's instructions as they are at each run. Each run works like an app calling it over HTTP: an approval goes wherever the Messaging tab sends it, and with nowhere set, a call that needs approval is denied. The agent can also schedule its own tasks when asked in Chat (“remind me tomorrow at 9”); they appear here too.</p>' +
|
|
2331
2407
|
'<section><h3>Scheduled (' + active.length + ' active)</h3>' + list + '</section>' +
|
|
2332
2408
|
'<section><h3>New schedule</h3>' +
|
|
2333
2409
|
'<form class="add-source" id="scheduleForm" style="max-width:560px">' +
|
|
@@ -2338,7 +2414,7 @@ ${consoleShellScript}
|
|
|
2338
2414
|
return '<option value="' + escapeHtml(w.id) + '">' + escapeHtml(w.title) + '</option>';
|
|
2339
2415
|
}).join('') + '</select></div>' +
|
|
2340
2416
|
'<div class="workflow-params" id="scheduleParams" style="margin:0 0 4px 22px"></div>' +
|
|
2341
|
-
'<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>' +
|
|
2342
2418
|
'<div class="schedule-when"><input type="radio" name="runs" value="message" id="runsMessage"><label for="runsMessage">A message</label></div>' +
|
|
2343
2419
|
'</div>'
|
|
2344
2420
|
: '') +
|
|
@@ -2437,6 +2513,7 @@ ${consoleShellScript}
|
|
|
2437
2513
|
form.scrollIntoView({ block: 'start' });
|
|
2438
2514
|
}
|
|
2439
2515
|
pendingScheduleWorkflow = null;
|
|
2516
|
+
focusScheduleRow();
|
|
2440
2517
|
renderScheduleParams();
|
|
2441
2518
|
if (workflowSelect) workflowSelect.addEventListener('change', renderScheduleParams);
|
|
2442
2519
|
for (var k = 0; k < runsRadios.length; k++) {
|
|
@@ -4370,7 +4447,7 @@ ${consoleShellScript}
|
|
|
4370
4447
|
'<div class="tab-panel" data-tab-panel="overview">' + renderOverviewHtml(cfg) + '</div>' +
|
|
4371
4448
|
// Workflows: the jobs this agent does, each with what starts it.
|
|
4372
4449
|
'<div class="tab-panel" data-tab-panel="workflows">' +
|
|
4373
|
-
'<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>' +
|
|
4374
4451
|
'<section id="workflowsSection"><div id="workflowsContent"><p class="hint">Loading…</p></div></section>' +
|
|
4375
4452
|
'</div>' +
|
|
4376
4453
|
// Advanced: the agent's own tools (and Composio, subagents), then its
|
|
@@ -56,8 +56,8 @@ export const consoleShellScript = `<script>
|
|
|
56
56
|
// ability on the Apps tab (id 'abilities', so older links still work).
|
|
57
57
|
// ?tab=tools and ?tab=skills still open Advanced.
|
|
58
58
|
var TABS = [
|
|
59
|
-
['overview', 'Overview'], ['workflows', 'Workflows'], ['
|
|
60
|
-
['messaging', 'Messaging'], ['schedules', 'Schedules'], ['env', 'Environment'], ['advanced', 'Advanced']
|
|
59
|
+
['overview', 'Overview'], ['workflows', 'Workflows'], ['abilities', 'Apps'], ['actauth', 'Permissions'],
|
|
60
|
+
['messaging', 'Messaging'], ['schedules', 'Schedules'], ['env', 'Environment'], ['advanced', 'Advanced'], ['chat', 'Chat']
|
|
61
61
|
];
|
|
62
62
|
|
|
63
63
|
function esc(s) {
|
|
@@ -72,11 +72,13 @@ export const consoleShellScript = `<script>
|
|
|
72
72
|
return '/agents/config?agent=' + enc(name) + (tab && tab !== 'overview' ? '&tab=' + enc(tab) : '');
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
//
|
|
76
|
-
//
|
|
75
|
+
// An agent in the list opens its Overview. Switching agents keeps you
|
|
76
|
+
// where you are: on a config tab you land on the same tab for the other
|
|
77
|
+
// agent, and in Chat on its Chat.
|
|
77
78
|
function agentHref(name) {
|
|
78
79
|
if (page === 'agent-config') return tabHref(name, params.get('tab') || 'overview');
|
|
79
|
-
return tabHref(name, 'chat');
|
|
80
|
+
if (page === 'chat') return tabHref(name, 'chat');
|
|
81
|
+
return tabHref(name, 'overview');
|
|
80
82
|
}
|
|
81
83
|
|
|
82
84
|
function renderList() {
|
|
@@ -207,10 +207,13 @@ export declare function prepareWorkflowRun(agentName: string, agentDir: string,
|
|
|
207
207
|
* matter is kept. A body with `start_message` (and no `instructions`) is
|
|
208
208
|
* still taken, as before. */
|
|
209
209
|
export declare function updateWorkflow(agentDir: string, id: string, input: Record<string, unknown>): Workflow;
|
|
210
|
-
/**
|
|
211
|
-
*
|
|
210
|
+
/** Removes a workflow: its skill stays, as a plain skill the agent can
|
|
211
|
+
* still use in chat, and what started it goes: its schedules are
|
|
212
|
+
* cancelled and its webhooks deleted (their URLs stop working). Returns
|
|
213
|
+
* how many of each. */
|
|
212
214
|
export declare function forgetWorkflow(agentName: string, agentDir: string, id: string): Promise<{
|
|
213
215
|
cancelled: number;
|
|
216
|
+
webhooks: number;
|
|
214
217
|
}>;
|
|
215
218
|
export declare function agentDirIn(projectDir: string, name: string): string;
|
|
216
219
|
export {};
|
|
@@ -11,7 +11,7 @@ import { writeSkill } from './skills-admin.js';
|
|
|
11
11
|
import { createFromTemplateObject, installFailureReason, templateChecklist } from './templates-admin.js';
|
|
12
12
|
import { templateScheduleStart } from '../core/system-agents/templates.js';
|
|
13
13
|
import { planParameters, planWebhook, planWorkflowWithModel, slugify, workflowTemplate } from '../core/system-agents/workflow-planner.js';
|
|
14
|
-
import { createTrigger, listTriggers, publicTrigger } from '../core/workflow-triggers.js';
|
|
14
|
+
import { createTrigger, getTriggerStore, listTriggers, publicTrigger } from '../core/workflow-triggers.js';
|
|
15
15
|
import { mcpAbilityNames } from '../core/mcp-ability-generator.js';
|
|
16
16
|
import { clearWorkflowFields, migrateWorkflowsFile, readWorkflow, readWorkflows, setWorkflowFields, validateParams, workflowRunMessage } from '../core/workflows.js';
|
|
17
17
|
import { isUnderWay, listRuns } from '../core/workflow-runs.js';
|
|
@@ -634,8 +634,10 @@ export function updateWorkflow(agentDir, id, input) {
|
|
|
634
634
|
setWorkflowFields(agentDir, id, instructions !== undefined ? { ...(title ? { title } : {}), instructions, parameters } : { ...(title ? { title } : {}), startMessage, ...(trigger ? { trigger } : {}), parameters });
|
|
635
635
|
return readWorkflow(agentDir, id);
|
|
636
636
|
}
|
|
637
|
-
/**
|
|
638
|
-
*
|
|
637
|
+
/** Removes a workflow: its skill stays, as a plain skill the agent can
|
|
638
|
+
* still use in chat, and what started it goes: its schedules are
|
|
639
|
+
* cancelled and its webhooks deleted (their URLs stop working). Returns
|
|
640
|
+
* how many of each. */
|
|
639
641
|
export async function forgetWorkflow(agentName, agentDir, id) {
|
|
640
642
|
clearWorkflowFields(agentDir, id);
|
|
641
643
|
let cancelled = 0;
|
|
@@ -643,7 +645,12 @@ export async function forgetWorkflow(agentName, agentDir, id) {
|
|
|
643
645
|
await cancelScheduledTask(task.task_id);
|
|
644
646
|
cancelled++;
|
|
645
647
|
}
|
|
646
|
-
|
|
648
|
+
let webhooks = 0;
|
|
649
|
+
for (const trigger of await listTriggers(agentName, id)) {
|
|
650
|
+
await getTriggerStore().remove(trigger.trigger_id);
|
|
651
|
+
webhooks++;
|
|
652
|
+
}
|
|
653
|
+
return { cancelled, webhooks };
|
|
647
654
|
}
|
|
648
655
|
export function agentDirIn(projectDir, name) {
|
|
649
656
|
return join(projectDir, 'agents', name);
|