@yemi33/minions 0.1.2390 → 0.1.2391
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/dashboard/js/settings.js +46 -10
- package/package.json +1 -1
package/dashboard/js/settings.js
CHANGED
|
@@ -33,6 +33,38 @@ function _isCurrentModelLoad(scope, key, token) {
|
|
|
33
33
|
return _modelLoadEpochs[scope][key] === token;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
// Per-open dedup cache for /api/runtimes/<name>/models payloads.
|
|
37
|
+
// initRuntimeFleetUI() fans out one model fetch per agent PLUS default + CC.
|
|
38
|
+
// When the whole fleet shares a runtime (the common case) those are
|
|
39
|
+
// byte-identical requests, and each one makes the server reloadConfig() from
|
|
40
|
+
// disk + re-run model discovery. Collapsing them to one request per distinct
|
|
41
|
+
// runtime per Settings open removes the N+2 → 1 duplicate round-trips (measured
|
|
42
|
+
// 10 → 1 for an 8-agent single-runtime fleet). forceRefresh (the ↻ button)
|
|
43
|
+
// bypasses the cache and repopulates it with the fresh list. Transient
|
|
44
|
+
// failures are NOT cached so a blip can't poison every agent cell for the open.
|
|
45
|
+
let _modelFetchCache = new Map();
|
|
46
|
+
function _resetModelFetchCache() { _modelFetchCache = new Map(); }
|
|
47
|
+
function _fetchRuntimeModelsPayload(runtimeName, forceRefresh) {
|
|
48
|
+
if (!runtimeName) return Promise.resolve({ models: null });
|
|
49
|
+
if (!forceRefresh) {
|
|
50
|
+
const cached = _modelFetchCache.get(runtimeName);
|
|
51
|
+
if (cached) return cached;
|
|
52
|
+
}
|
|
53
|
+
const suffix = forceRefresh ? '/models/refresh' : '/models';
|
|
54
|
+
const p = fetch('/api/runtimes/' + encodeURIComponent(runtimeName) + suffix, forceRefresh ? { method: 'POST' } : undefined)
|
|
55
|
+
.then(res => (res.ok ? res.json() : null))
|
|
56
|
+
.catch(() => null)
|
|
57
|
+
.then(payload => {
|
|
58
|
+
if (!payload || !Array.isArray(payload.models)) {
|
|
59
|
+
if (_modelFetchCache.get(runtimeName) === p) _modelFetchCache.delete(runtimeName);
|
|
60
|
+
return payload || { models: null };
|
|
61
|
+
}
|
|
62
|
+
return payload;
|
|
63
|
+
});
|
|
64
|
+
_modelFetchCache.set(runtimeName, p);
|
|
65
|
+
return p;
|
|
66
|
+
}
|
|
67
|
+
|
|
36
68
|
async function openSettings() {
|
|
37
69
|
document.getElementById('modal-title').textContent = 'Settings';
|
|
38
70
|
document.getElementById('modal-body').innerHTML = '<p style="color:var(--muted)">Loading...</p>';
|
|
@@ -719,8 +751,16 @@ async function openSettings() {
|
|
|
719
751
|
// hides unmatched rows so operators can see results without tab-hopping.
|
|
720
752
|
const searchInput = document.getElementById('settings-search');
|
|
721
753
|
if (searchInput) {
|
|
754
|
+
// Debounce the filter: _applySettingsSearch runs several full-DOM
|
|
755
|
+
// querySelectorAll scans and reads textContent of every [data-search] row
|
|
756
|
+
// (a forced reflow). Firing that per-keystroke made typing janky on the
|
|
757
|
+
// large Settings DOM. The field itself stays instant; only the filter
|
|
758
|
+
// computation is coalesced to the last keystroke in a ~120ms window.
|
|
759
|
+
let _searchDebounce = null;
|
|
722
760
|
searchInput.addEventListener('input', function() {
|
|
723
|
-
|
|
761
|
+
const val = searchInput.value || '';
|
|
762
|
+
if (_searchDebounce) clearTimeout(_searchDebounce);
|
|
763
|
+
_searchDebounce = setTimeout(function() { _applySettingsSearch(val); }, 120);
|
|
724
764
|
});
|
|
725
765
|
}
|
|
726
766
|
|
|
@@ -822,6 +862,9 @@ async function initRuntimeFleetUI(engineCfg, agentsCfg) {
|
|
|
822
862
|
const ccCliSelect = document.getElementById('set-ccCli');
|
|
823
863
|
if (!cliSelect || !ccCliSelect) return;
|
|
824
864
|
|
|
865
|
+
// Fresh cache per Settings open so a config change between opens is picked up.
|
|
866
|
+
_resetModelFetchCache();
|
|
867
|
+
|
|
825
868
|
// Fetch the registry; render an empty fallback on failure so the rest of the
|
|
826
869
|
// settings panel still works.
|
|
827
870
|
let runtimes = [];
|
|
@@ -917,11 +960,7 @@ async function loadModelsForRuntime(runtimeName, inputId, currentValue, forceRef
|
|
|
917
960
|
return;
|
|
918
961
|
}
|
|
919
962
|
let payload = { models: null };
|
|
920
|
-
|
|
921
|
-
const suffix = forceRefresh ? '/models/refresh' : '/models';
|
|
922
|
-
const res = await fetch('/api/runtimes/' + encodeURIComponent(runtimeName) + suffix, forceRefresh ? { method: 'POST' } : undefined);
|
|
923
|
-
if (res.ok) payload = await res.json();
|
|
924
|
-
} catch { /* fall through to free-text */ }
|
|
963
|
+
payload = await _fetchRuntimeModelsPayload(runtimeName, forceRefresh);
|
|
925
964
|
|
|
926
965
|
if (!_isCurrentModelLoad('runtime', inputId, token)) return;
|
|
927
966
|
const models = Array.isArray(payload.models) ? payload.models : null;
|
|
@@ -962,10 +1001,7 @@ async function loadModelsForAgent(agentId, runtimeName, currentValue) {
|
|
|
962
1001
|
return;
|
|
963
1002
|
}
|
|
964
1003
|
let payload = { models: null };
|
|
965
|
-
|
|
966
|
-
const res = await fetch('/api/runtimes/' + encodeURIComponent(runtimeName) + '/models');
|
|
967
|
-
if (res.ok) payload = await res.json();
|
|
968
|
-
} catch { /* fall through to free-text */ }
|
|
1004
|
+
payload = await _fetchRuntimeModelsPayload(runtimeName, false);
|
|
969
1005
|
|
|
970
1006
|
if (!_isCurrentModelLoad('agent', agentId, token)) return;
|
|
971
1007
|
const models = Array.isArray(payload.models) ? payload.models : null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2391",
|
|
4
4
|
"description": "Multi-agent AI dev team that runs from ~/.minions/ — five autonomous agents share a single engine, dashboard, and knowledge base",
|
|
5
5
|
"bin": {
|
|
6
6
|
"minions": "bin/minions.js"
|