loopengine 0.1.98 → 0.2.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/bin/ability-manager.d.ts +35 -2
- package/dist/bin/ability-manager.js +168 -35
- package/dist/core/ability-details.js +11 -0
- package/dist/core/mcp-abilities.d.ts +91 -0
- package/dist/core/mcp-abilities.js +400 -0
- package/dist/core/mcp-ability-generator.d.ts +59 -0
- package/dist/core/mcp-ability-generator.js +193 -0
- package/dist/core/mcp-apps.d.ts +95 -0
- package/dist/core/mcp-apps.js +254 -0
- package/dist/core/mcp-directory.d.ts +32 -0
- package/dist/core/mcp-directory.js +191 -0
- package/dist/core/run-agent.js +5 -2
- package/dist/core/system-agents/interviewer.d.ts +1 -1
- package/dist/core/system-agents/interviewer.js +1 -1
- package/dist/core/system-agents/templates.d.ts +11 -0
- package/dist/core/system-agents/templates.js +22 -16
- package/dist/core/system-agents/workflow-planner.d.ts +36 -3
- package/dist/core/system-agents/workflow-planner.js +23 -6
- package/dist/core/workspace-abilities.js +1 -1
- package/dist/index.d.ts +7 -3
- package/dist/index.js +6 -2
- package/dist/web/abilities-admin.d.ts +1 -1
- package/dist/web/abilities-admin.js +1 -1
- package/dist/web/agents-config-page.js +187 -11
- package/dist/web/console-shell.js +7 -5
- package/dist/web/dev-ui-styles.js +1 -1
- package/dist/web/global-config-page.js +293 -13
- package/dist/web/interview-admin.js +2 -0
- package/dist/web/templates-admin.d.ts +10 -2
- package/dist/web/templates-admin.js +36 -3
- package/dist/web/templates-page.js +1 -0
- package/dist/web/workflow-admin.d.ts +46 -0
- package/dist/web/workflow-admin.js +195 -3
- package/dist/web/workflow-page.js +33 -3
- package/package.json +10 -1
|
@@ -335,6 +335,16 @@ export const agentsConfigPageHtml = `<!doctype html>
|
|
|
335
335
|
#httpToolAddFieldBtn, #httpToolAddHeaderBtn {
|
|
336
336
|
padding: 6px 12px;
|
|
337
337
|
}
|
|
338
|
+
.app-pick { border: 1px solid var(--line); border-radius: var(--radius); padding: 10px 12px; margin: 6px 0 12px; display: grid; gap: 8px; background: var(--surface); }
|
|
339
|
+
.app-pick-bar { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
|
|
340
|
+
.app-pick-bar input[type=search] { font: inherit; font-size: 12px; padding: 5px 7px; max-width: 240px; }
|
|
341
|
+
.app-pick-list { display: grid; gap: 2px; max-height: 380px; overflow: auto; border: 1px solid var(--line); border-radius: var(--radius); padding: 4px; background: var(--bg); }
|
|
342
|
+
.app-pick-tool { display: flex; gap: 8px; align-items: flex-start; padding: 5px 6px; border-radius: 6px; font-size: 12.5px; }
|
|
343
|
+
.app-pick-tool:hover { background: var(--surface); }
|
|
344
|
+
.app-pick-tool input { margin-top: 3px; }
|
|
345
|
+
.app-pick-tool code { overflow-wrap: anywhere; }
|
|
346
|
+
.app-pick-tool select { font: inherit; font-size: 11.5px; padding: 1px 4px; }
|
|
347
|
+
.app-pick-desc { display: block; }
|
|
338
348
|
</style>
|
|
339
349
|
</head>
|
|
340
350
|
<body data-le-page="agent-config">
|
|
@@ -361,7 +371,7 @@ ${consoleShellScript}
|
|
|
361
371
|
var actauthLoadedFor = null;
|
|
362
372
|
// Same idea again, for the Environment tab's own GET .../env.
|
|
363
373
|
var envLoadedFor = null;
|
|
364
|
-
// Same idea again, for the
|
|
374
|
+
// Same idea again, for the Apps tab's own GET .../abilities.
|
|
365
375
|
var abilitiesLoadedFor = null;
|
|
366
376
|
// The full /agents/:name/config response the currently-open agent was
|
|
367
377
|
// last rendered from — kept around so refreshActauthDependentPanels/
|
|
@@ -637,8 +647,8 @@ ${consoleShellScript}
|
|
|
637
647
|
return '<div class="le-cards" style="margin-bottom:28px">' +
|
|
638
648
|
card(null, 'Model', escapeHtml(modelValue), escapeHtml(modelDetail)) +
|
|
639
649
|
(cfg.abilityCount != null
|
|
640
|
-
? card('abilities', '
|
|
641
|
-
: card('abilities', '
|
|
650
|
+
? card('abilities', 'Apps', String(cfg.abilityCount), cfg.abilityCount ? 'Apps and abilities added to this agent' : 'Add apps and abilities, with the tools you choose')
|
|
651
|
+
: card('abilities', 'Apps', 'Browse', 'Add apps and abilities, with the tools you choose')) +
|
|
642
652
|
card('tools', 'Tools', String(cfg.tools.length), escapeHtml(toolNames.slice(0, 3).join(', ') + (toolNames.length > 3 ? ', \u2026' : '')) || 'None yet') +
|
|
643
653
|
card('skills', 'Skills', String(cfg.skills.length), escapeHtml(cfg.skills.map(function (k) { return k.name; }).join(', ')) || 'None yet') +
|
|
644
654
|
card('actauth', 'Permissions', rules.length + (rules.length === 1 ? ' rule' : ' rules'),
|
|
@@ -2308,7 +2318,7 @@ ${consoleShellScript}
|
|
|
2308
2318
|
});
|
|
2309
2319
|
}
|
|
2310
2320
|
|
|
2311
|
-
// ----
|
|
2321
|
+
// ---- Apps tab: what's already installed for this agent, a
|
|
2312
2322
|
// search box over public (npm, tagged loopengine-ability) packages,
|
|
2313
2323
|
// and a plain spec field for a private ability (a git URL, a local
|
|
2314
2324
|
// file:../path, or a private registry name) — both installs go
|
|
@@ -2349,7 +2359,7 @@ ${consoleShellScript}
|
|
|
2349
2359
|
'<td><code>' + escapeHtml(a.name) + '</code></td>' +
|
|
2350
2360
|
'<td>' + escapeHtml(a.version) + '</td>' +
|
|
2351
2361
|
'<td>' + leShell.abilityOriginBadge(a.origin) + '</td>' +
|
|
2352
|
-
'<td class="hint">' + escapeHtml((a.tools || []).join(', ')) + '</td>' +
|
|
2362
|
+
'<td class="hint">' + escapeHtml((a.tools || []).concat(a.mcp ? a.mcp.tools.map(function (t) { return t.name; }) : []).join(', ')) + '</td>' +
|
|
2353
2363
|
'<td style="white-space:nowrap">' + detailsHtml + ' ' + actionHtml + '</td>' +
|
|
2354
2364
|
'</tr>';
|
|
2355
2365
|
}
|
|
@@ -2374,11 +2384,15 @@ ${consoleShellScript}
|
|
|
2374
2384
|
var installedHtml = installed.length
|
|
2375
2385
|
? '<table><thead><tr><th>Name</th><th>Version</th><th>Source</th><th>Tools</th><th></th></tr></thead><tbody>' + installed.map(renderInstalledAbilityRow).join('') + '</tbody></table>' +
|
|
2376
2386
|
'<p id="abilityUpgradeStatus" class="hint"></p>'
|
|
2377
|
-
: '<p class="hint">
|
|
2387
|
+
: '<p class="hint">Nothing added to this agent yet.</p>';
|
|
2378
2388
|
|
|
2379
|
-
|
|
2389
|
+
// What this agent has first; then the workspace's connected apps (each
|
|
2390
|
+
// with the tools this agent gets), then public and private abilities.
|
|
2391
|
+
return '<h3 style="justify-content:flex-start;align-items:baseline;gap:8px">Installed <span class="hint" style="font-weight:400">the apps and abilities this agent has</span></h3>' + installedHtml +
|
|
2380
2392
|
// Installing by name or spec is on the console's Abilities page.
|
|
2381
2393
|
'<p id="abilityInstallStatus" class="hint"></p>' +
|
|
2394
|
+
'<h3 style="margin-top:24px;justify-content:flex-start;align-items:baseline;gap:8px">Apps <span class="hint" style="font-weight:400">connected in this workspace; choose which of their tools this agent gets, and each one' + String.fromCharCode(8217) + 's permission</span></h3>' +
|
|
2395
|
+
'<div id="agentApps" style="margin-bottom:32px"><p class="hint">Loading…</p></div>' +
|
|
2382
2396
|
'<h3 style="margin-top:24px;justify-content:flex-start;align-items:baseline;gap:8px">Public abilities <span class="hint" style="font-weight:400">npm packages tagged loopengine-ability</span></h3>' +
|
|
2383
2397
|
'<form id="abilitySearchForm" style="display:flex;gap:6px;margin:0 0 10px;max-width:560px">' +
|
|
2384
2398
|
'<input type="search" name="q" placeholder="Search abilities, e.g. gmail" aria-label="Search public abilities" style="flex:1">' +
|
|
@@ -2456,7 +2470,8 @@ ${consoleShellScript}
|
|
|
2456
2470
|
.then(function (result) {
|
|
2457
2471
|
if (!result.ok) throw new Error(result.body.error || 'request failed');
|
|
2458
2472
|
var files = result.body.files || [];
|
|
2459
|
-
|
|
2473
|
+
// added/removed: new rules, and tool files a version dropped (its tools now come from the app's MCP server).
|
|
2474
|
+
var updated = files.filter(function (f) { return f.status === 'updated' || f.status === 'added' || f.status === 'removed'; });
|
|
2460
2475
|
var conflicts = files.filter(function (f) { return f.status === 'conflict'; });
|
|
2461
2476
|
var message;
|
|
2462
2477
|
if (!files.length || (!updated.length && !conflicts.length)) {
|
|
@@ -2565,7 +2580,8 @@ ${consoleShellScript}
|
|
|
2565
2580
|
.then(function (r) { return r.json(); })
|
|
2566
2581
|
.then(function (d) {
|
|
2567
2582
|
if (currentName !== name) return;
|
|
2568
|
-
|
|
2583
|
+
// Connected apps are listed under Apps, above.
|
|
2584
|
+
var abilities = (d.abilities || []).filter(function (a) { return !a.app; });
|
|
2569
2585
|
if (!abilities.length) {
|
|
2570
2586
|
el.innerHTML = '<p><a href="/config?section=abilities#private-abilities">Install private abilities</a></p>';
|
|
2571
2587
|
return;
|
|
@@ -2665,6 +2681,165 @@ ${consoleShellScript}
|
|
|
2665
2681
|
runAbilitySearch(name, '', content, resultsEl, installedNames);
|
|
2666
2682
|
}
|
|
2667
2683
|
loadPrivateAbilitiesFor(name, content, installedNames);
|
|
2684
|
+
loadAgentApps(name, content);
|
|
2685
|
+
}
|
|
2686
|
+
|
|
2687
|
+
// ---- Apps: a connected app's tools for this agent ----
|
|
2688
|
+
// The workspace's connected apps (the console's Apps page). Adding one,
|
|
2689
|
+
// or Choose tools on one already added, opens a picker: each tool with a
|
|
2690
|
+
// checkbox and this agent's permission for it; Save installs the app
|
|
2691
|
+
// with just those tools, or changes the agent's choice.
|
|
2692
|
+
|
|
2693
|
+
var agentApps = { name: null, connected: [], pickers: {} };
|
|
2694
|
+
var DECISION_NAMES = { allow: 'Allow', ask: 'Ask me', deny: 'Never' };
|
|
2695
|
+
|
|
2696
|
+
function loadAgentApps(name, content) {
|
|
2697
|
+
var el = content.querySelector('#agentApps');
|
|
2698
|
+
if (!el) return;
|
|
2699
|
+
if (agentApps.name !== name) agentApps = { name: name, connected: [], pickers: {} };
|
|
2700
|
+
fetch('/config/apps', { cache: 'no-store' })
|
|
2701
|
+
.then(function (r) { return r.json(); })
|
|
2702
|
+
.then(function (d) {
|
|
2703
|
+
if (currentName !== name) return;
|
|
2704
|
+
agentApps.connected = d.connected || [];
|
|
2705
|
+
agentApps.canChange = Boolean(d.canConnect);
|
|
2706
|
+
renderAgentApps();
|
|
2707
|
+
})
|
|
2708
|
+
.catch(function (err) { el.innerHTML = '<p class="error">Could not list apps: ' + escapeHtml(err.message) + '</p>'; });
|
|
2709
|
+
if (!content.dataset.appsWired) {
|
|
2710
|
+
content.dataset.appsWired = '1';
|
|
2711
|
+
content.addEventListener('click', onAgentAppsClick);
|
|
2712
|
+
content.addEventListener('change', onAgentAppsChange);
|
|
2713
|
+
content.addEventListener('input', onAgentAppsInput);
|
|
2714
|
+
}
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2717
|
+
function renderAgentApps() {
|
|
2718
|
+
var content = abilitiesContentEl();
|
|
2719
|
+
var el = content && content.querySelector('#agentApps');
|
|
2720
|
+
if (!el) return;
|
|
2721
|
+
var name = agentApps.name;
|
|
2722
|
+
if (!agentApps.connected.length) {
|
|
2723
|
+
el.innerHTML = '<p class="hint">No apps connected yet. <a href="/config?section=apps">Connect one on the Apps page</a>, then add it here.</p>';
|
|
2724
|
+
return;
|
|
2725
|
+
}
|
|
2726
|
+
el.innerHTML = '<table><thead><tr><th>App</th><th>For this agent</th><th></th></tr></thead><tbody>' + agentApps.connected.map(function (c) {
|
|
2727
|
+
var added = c.agents.indexOf(name) !== -1;
|
|
2728
|
+
var open = agentApps.pickers[c.ability];
|
|
2729
|
+
return '<tr><td><strong>' + escapeHtml(c.title) + '</strong> <span class="hint">' + escapeHtml(c.ability) + '</span></td>' +
|
|
2730
|
+
'<td class="hint">' + (added ? 'Added' : 'Not added') + '</td>' +
|
|
2731
|
+
'<td style="white-space:nowrap"><button type="button" class="app-pick-open" data-ability="' + escapeHtml(c.ability) + '">' + (open ? 'Close' : added ? 'Choose tools' : 'Add') + '</button></td></tr>' +
|
|
2732
|
+
(open ? '<tr><td colspan="3">' + pickerHtml(c.ability) + '</td></tr>' : '');
|
|
2733
|
+
}).join('') + '</tbody></table>' +
|
|
2734
|
+
'<p class="hint" style="margin:6px 0 0"><a href="/config?section=apps">Connect more apps</a></p>';
|
|
2735
|
+
}
|
|
2736
|
+
|
|
2737
|
+
function pickerHtml(ability) {
|
|
2738
|
+
var p = agentApps.pickers[ability];
|
|
2739
|
+
if (p.error) return '<div class="app-pick"><p class="error" style="margin:0">' + escapeHtml(p.error) + '</p></div>';
|
|
2740
|
+
if (!p.tools) return '<div class="app-pick"><p class="hint" style="margin:0">Asking the app for its tools' + String.fromCharCode(8230) + '</p></div>';
|
|
2741
|
+
var chosen = p.tools.filter(function (t) { return t.selected; }).length;
|
|
2742
|
+
var f = (p.filter || '').toLowerCase();
|
|
2743
|
+
var shown = p.tools.filter(function (t) { return !f || (t.remote + ' ' + t.description).toLowerCase().indexOf(f) !== -1; });
|
|
2744
|
+
var disabled = agentApps.canChange && !p.busy ? '' : ' disabled';
|
|
2745
|
+
return '<div class="app-pick">' +
|
|
2746
|
+
'<p class="hint" style="margin:0">Choose the tools this agent can use, and what each may do on its own: Allow runs it, Ask me waits for your OK, Never blocks it. Each starts at the app' + String.fromCharCode(8217) + 's default.</p>' +
|
|
2747
|
+
'<div class="app-pick-bar">' +
|
|
2748
|
+
(p.tools.length > 12 ? '<input type="search" class="app-pick-filter" data-ability="' + escapeHtml(ability) + '" placeholder="Filter tools" value="' + escapeHtml(p.filter || '') + '" aria-label="Filter tools">' : '') +
|
|
2749
|
+
'<button type="button" class="app-pick-readonly" data-ability="' + escapeHtml(ability) + '"' + disabled + '>Select read-only tools</button>' +
|
|
2750
|
+
'<button type="button" class="app-pick-none" data-ability="' + escapeHtml(ability) + '"' + disabled + '>Clear</button>' +
|
|
2751
|
+
'<span class="hint">' + chosen + ' of ' + p.tools.length + ' selected' + (chosen > 20 ? '. That' + String.fromCharCode(8217) + 's a lot: more tools make an agent slower to choose and likelier to pick the wrong one.' : '') + '</span>' +
|
|
2752
|
+
'</div>' +
|
|
2753
|
+
'<div class="app-pick-list">' + shown.map(function (t) {
|
|
2754
|
+
return '<label class="app-pick-tool"><input type="checkbox" class="app-pick-check" data-ability="' + escapeHtml(ability) + '" data-tool="' + escapeHtml(t.remote) + '"' + (t.selected ? ' checked' : '') + disabled + '>' +
|
|
2755
|
+
'<span><code>' + escapeHtml(t.name) + '</code> ' +
|
|
2756
|
+
'<select class="app-pick-decision" data-ability="' + escapeHtml(ability) + '" data-tool="' + escapeHtml(t.remote) + '" aria-label="Permission for ' + escapeHtml(t.name) + '"' + disabled + '>' +
|
|
2757
|
+
['allow', 'ask', 'deny'].map(function (d) { return '<option value="' + d + '"' + (d === t.decision ? ' selected' : '') + '>' + DECISION_NAMES[d] + '</option>'; }).join('') + '</select>' +
|
|
2758
|
+
(t.destructive ? ' <span class="hint">destructive</span>' : t.readOnly ? ' <span class="hint">read-only</span>' : '') +
|
|
2759
|
+
(t.description ? '<span class="hint app-pick-desc">' + escapeHtml(t.description) + '</span>' : '') +
|
|
2760
|
+
'</span></label>';
|
|
2761
|
+
}).join('') + '</div>' +
|
|
2762
|
+
'<div class="app-pick-bar"><button type="button" class="app-pick-save" data-ability="' + escapeHtml(ability) + '"' + (chosen && !p.busy && agentApps.canChange ? '' : ' disabled') + '>' + (p.installed ? 'Save' : 'Add with ' + chosen + ' tool' + (chosen === 1 ? '' : 's')) + '</button>' +
|
|
2763
|
+
(agentApps.canChange ? '' : '<span class="error">Changing an agent' + String.fromCharCode(8217) + 's tools needs LOOPENGINE_ADMIN_AUTH set.</span>') +
|
|
2764
|
+
(p.message ? '<span class="' + (p.messageBad ? 'error' : 'hint') + '">' + escapeHtml(p.message) + '</span>' : '') + '</div>' +
|
|
2765
|
+
'</div>';
|
|
2766
|
+
}
|
|
2767
|
+
|
|
2768
|
+
function pickerTool(ability, remote) {
|
|
2769
|
+
var tools = agentApps.pickers[ability].tools;
|
|
2770
|
+
for (var i = 0; i < tools.length; i++) if (tools[i].remote === remote) return tools[i];
|
|
2771
|
+
return null;
|
|
2772
|
+
}
|
|
2773
|
+
|
|
2774
|
+
function openPicker(ability) {
|
|
2775
|
+
var name = agentApps.name;
|
|
2776
|
+
agentApps.pickers[ability] = { tools: null, filter: '' };
|
|
2777
|
+
renderAgentApps();
|
|
2778
|
+
fetch('/agents/' + encodeURIComponent(name) + '/apps/' + encodeURIComponent(ability), { cache: 'no-store' })
|
|
2779
|
+
.then(function (r) { return r.json().then(function (j) { return { ok: r.ok, body: j }; }); })
|
|
2780
|
+
.then(function (r) {
|
|
2781
|
+
var p = agentApps.pickers[ability];
|
|
2782
|
+
if (!p || agentApps.name !== name) return;
|
|
2783
|
+
if (!r.ok) p.error = r.body.error || 'Could not list its tools.';
|
|
2784
|
+
else { p.tools = r.body.tools; p.installed = r.body.installed; }
|
|
2785
|
+
renderAgentApps();
|
|
2786
|
+
})
|
|
2787
|
+
.catch(function (err) { var p = agentApps.pickers[ability]; if (p) { p.error = err.message; renderAgentApps(); } });
|
|
2788
|
+
}
|
|
2789
|
+
|
|
2790
|
+
function savePicker(ability) {
|
|
2791
|
+
var name = agentApps.name;
|
|
2792
|
+
var p = agentApps.pickers[ability];
|
|
2793
|
+
var tools = p.tools.filter(function (t) { return t.selected; }).map(function (t) { return { remote: t.remote, decision: t.decision }; });
|
|
2794
|
+
p.busy = true;
|
|
2795
|
+
p.message = 'Saving' + String.fromCharCode(8230);
|
|
2796
|
+
p.messageBad = false;
|
|
2797
|
+
renderAgentApps();
|
|
2798
|
+
fetch('/agents/' + encodeURIComponent(name) + '/apps/' + encodeURIComponent(ability), { method: 'PUT', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ tools: tools }) })
|
|
2799
|
+
.then(function (r) { return r.json().then(function (j) { return { ok: r.ok, body: j }; }); })
|
|
2800
|
+
.then(function (r) {
|
|
2801
|
+
p.busy = false;
|
|
2802
|
+
if (!r.ok) { p.message = r.body.error || 'Could not save.'; p.messageBad = true; renderAgentApps(); return; }
|
|
2803
|
+
delete agentApps.pickers[ability];
|
|
2804
|
+
// The Installed table and the counts change too.
|
|
2805
|
+
loadAbilitiesTab(name);
|
|
2806
|
+
})
|
|
2807
|
+
.catch(function (err) { p.busy = false; p.message = err.message; p.messageBad = true; renderAgentApps(); });
|
|
2808
|
+
}
|
|
2809
|
+
|
|
2810
|
+
function onAgentAppsClick(ev) {
|
|
2811
|
+
var t = ev.target;
|
|
2812
|
+
if (!t.dataset || !t.dataset.ability) return;
|
|
2813
|
+
var ability = t.dataset.ability;
|
|
2814
|
+
if (t.classList.contains('app-pick-open')) {
|
|
2815
|
+
if (agentApps.pickers[ability]) { delete agentApps.pickers[ability]; renderAgentApps(); }
|
|
2816
|
+
else openPicker(ability);
|
|
2817
|
+
} else if (t.classList.contains('app-pick-readonly') || t.classList.contains('app-pick-none')) {
|
|
2818
|
+
var readOnly = t.classList.contains('app-pick-readonly');
|
|
2819
|
+
agentApps.pickers[ability].tools.forEach(function (tool) { tool.selected = readOnly ? tool.default === 'allow' : false; });
|
|
2820
|
+
renderAgentApps();
|
|
2821
|
+
} else if (t.classList.contains('app-pick-save')) {
|
|
2822
|
+
savePicker(ability);
|
|
2823
|
+
}
|
|
2824
|
+
}
|
|
2825
|
+
|
|
2826
|
+
function onAgentAppsChange(ev) {
|
|
2827
|
+
var t = ev.target;
|
|
2828
|
+
if (!t.dataset || !t.dataset.tool || !agentApps.pickers[t.dataset.ability]) return;
|
|
2829
|
+
var tool = pickerTool(t.dataset.ability, t.dataset.tool);
|
|
2830
|
+
if (!tool) return;
|
|
2831
|
+
if (t.classList.contains('app-pick-check')) tool.selected = t.checked;
|
|
2832
|
+
if (t.classList.contains('app-pick-decision')) { tool.decision = t.value; tool.selected = true; }
|
|
2833
|
+
renderAgentApps();
|
|
2834
|
+
}
|
|
2835
|
+
|
|
2836
|
+
function onAgentAppsInput(ev) {
|
|
2837
|
+
var t = ev.target;
|
|
2838
|
+
if (!t.classList.contains('app-pick-filter')) return;
|
|
2839
|
+
agentApps.pickers[t.dataset.ability].filter = t.value;
|
|
2840
|
+
renderAgentApps();
|
|
2841
|
+
var again = abilitiesContentEl().querySelector('.app-pick-filter[data-ability="' + t.dataset.ability + '"]');
|
|
2842
|
+
if (again) { again.focus(); again.setSelectionRange(again.value.length, again.value.length); }
|
|
2668
2843
|
}
|
|
2669
2844
|
|
|
2670
2845
|
function applyAbilitiesConfig(name, data) {
|
|
@@ -3470,7 +3645,8 @@ ${consoleShellScript}
|
|
|
3470
3645
|
var CONFIG_TABS = ['overview', 'abilities', 'actauth', 'messaging', 'schedules', 'env', 'advanced'];
|
|
3471
3646
|
// The old Tools and Skills tabs: now parts of Advanced. A link to one
|
|
3472
3647
|
// opens Advanced at that part.
|
|
3473
|
-
|
|
3648
|
+
// The Apps tab keeps the id 'abilities'; ?tab=apps opens it too.
|
|
3649
|
+
var TAB_ALIASES = { tools: 'advanced', skills: 'advanced', apps: 'abilities' };
|
|
3474
3650
|
|
|
3475
3651
|
function resolveTab(tab) {
|
|
3476
3652
|
tab = TAB_ALIASES[tab] || tab;
|
|
@@ -3607,7 +3783,7 @@ ${consoleShellScript}
|
|
|
3607
3783
|
// own skills. Each part keeps its old data-tab-panel name, which the
|
|
3608
3784
|
// code that redraws it looks for; only .tab-panel is shown or hidden.
|
|
3609
3785
|
'<div class="tab-panel" data-tab-panel="advanced">' +
|
|
3610
|
-
'<p class="muted" style="margin:0 0 20px">For building your own: tools and skills that don't come from an ability, Composio tools, subagents and permission rules in full. What each ability adds is in its Details on the
|
|
3786
|
+
'<p class="muted" style="margin:0 0 20px">For building your own: tools and skills that don't come from an ability, Composio tools, subagents and permission rules in full. What each ability adds is in its Details on the Apps tab.</p>' +
|
|
3611
3787
|
'<h2 class="advanced-part" id="advanced-tools">Tools</h2>' +
|
|
3612
3788
|
'<div data-tab-panel="tools">' + renderToolsTabHtml(cfg) + '</div>' +
|
|
3613
3789
|
'<h2 class="advanced-part" id="advanced-skills">Skills</h2>' +
|
|
@@ -32,6 +32,7 @@ export const consoleSidebarHtml = `<aside class="le-sidebar" aria-label="Console
|
|
|
32
32
|
<a class="le-find" href="/workflows/new" data-le-nav="workflows">Describe a workflow</a>
|
|
33
33
|
<nav class="le-foot" aria-label="Settings">
|
|
34
34
|
<a href="/config?section=models" data-le-nav="models">Models</a>
|
|
35
|
+
<a href="/config?section=apps" data-le-nav="apps">Apps</a>
|
|
35
36
|
<a href="/config?section=abilities" data-le-nav="abilities">Abilities</a>
|
|
36
37
|
<a href="/config?section=settings" data-le-nav="settings">Settings</a>
|
|
37
38
|
<div class="le-who" id="leWho" hidden></div>
|
|
@@ -51,10 +52,11 @@ export const consoleShellScript = `<script>
|
|
|
51
52
|
// after the list loads.
|
|
52
53
|
var toSet = {};
|
|
53
54
|
// Tools and Skills live under Advanced (an agent's own tools and skills,
|
|
54
|
-
// Composio, subagents): what an agent can do is shown per
|
|
55
|
-
//
|
|
55
|
+
// Composio, subagents): what an agent can do is shown per app and
|
|
56
|
+
// ability on the Apps tab (id 'abilities', so older links still work).
|
|
57
|
+
// ?tab=tools and ?tab=skills still open Advanced.
|
|
56
58
|
var TABS = [
|
|
57
|
-
['overview', 'Overview'], ['chat', 'Chat'], ['abilities', '
|
|
59
|
+
['overview', 'Overview'], ['chat', 'Chat'], ['abilities', 'Apps'], ['actauth', 'Permissions'],
|
|
58
60
|
['messaging', 'Messaging'], ['schedules', 'Schedules'], ['env', 'Environment'], ['advanced', 'Advanced']
|
|
59
61
|
];
|
|
60
62
|
|
|
@@ -170,7 +172,7 @@ export const consoleShellScript = `<script>
|
|
|
170
172
|
}
|
|
171
173
|
|
|
172
174
|
var section = params.get('section');
|
|
173
|
-
var foot = page === 'config' ? (section === 'abilities' || section === 'gateways' ? 'abilities' : section === 'settings' ? 'settings' : 'models') : page === 'interview' || page === 'templates' ? page : '';
|
|
175
|
+
var foot = page === 'config' ? (section === 'abilities' || section === 'gateways' ? 'abilities' : section === 'apps' ? 'apps' : section === 'settings' ? 'settings' : 'models') : page === 'interview' || page === 'templates' ? page : '';
|
|
174
176
|
var footLinks = document.querySelectorAll('[data-le-nav]');
|
|
175
177
|
for (var i = 0; i < footLinks.length; i++) {
|
|
176
178
|
if (footLinks[i].getAttribute('data-le-nav') === foot) footLinks[i].setAttribute('aria-current', 'page');
|
|
@@ -348,7 +350,7 @@ export const consoleShellScript = `<script>
|
|
|
348
350
|
}
|
|
349
351
|
|
|
350
352
|
// ---- Abilities: where one came from, and what it can do ----
|
|
351
|
-
// Used by the Abilities page and each agent's
|
|
353
|
+
// Used by the Abilities page and each agent's Apps tab.
|
|
352
354
|
|
|
353
355
|
var DECISION_LABELS = { allow: 'Allow', ask: 'Ask me', deny: 'Never' };
|
|
354
356
|
|
|
@@ -108,7 +108,7 @@ export const devUiCss = `
|
|
|
108
108
|
.le-pill.ask, .le-pill.warn { background: var(--warn-soft); color: var(--warn); }
|
|
109
109
|
.le-pill.deny, .le-pill.bad { background: var(--bad-soft); color: var(--bad); }
|
|
110
110
|
/* An ability's details (leShell.toggleAbilityDetails), on the Abilities
|
|
111
|
-
page and each agent's
|
|
111
|
+
page and each agent's Apps tab. */
|
|
112
112
|
.ability-details-row > td { padding: 0 10px 14px; border-top: 0; background: transparent; }
|
|
113
113
|
.ability-details { border: 1px solid var(--accent); border-left-width: 4px; border-radius: var(--radius); background: var(--accent-soft); padding: 12px 16px 14px; }
|
|
114
114
|
.ability-details-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 6px 16px; margin: 0 0 8px; padding-bottom: 8px; border-bottom: 1px solid var(--line); }
|