freddie 0.0.86 → 0.0.87

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/web/app.js +24 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "freddie",
3
- "version": "0.0.86",
3
+ "version": "0.0.87",
4
4
  "type": "module",
5
5
  "description": "Open JS agent harness built on pi-mono, floosie, xstate, and anentrypoint-design",
6
6
  "bin": {
package/src/web/app.js CHANGED
@@ -16,7 +16,17 @@ function routeFromHash() {
16
16
  const p = m && m[1];
17
17
  return ROUTES.find(r => r.path === p) ? p : 'home';
18
18
  }
19
- const state = { active: routeFromHash(), ts: new Date().toLocaleTimeString(), body: null, error: null };
19
+ const state = { active: routeFromHash(), ts: new Date().toLocaleTimeString(), body: null, error: null, sampler: { ok: 0, bad: 0, total: 0 } };
20
+
21
+ async function refreshSampler() {
22
+ try {
23
+ const j = await fetch('/api/models/sampler').then(r => r.json());
24
+ const ents = Object.values(j.status || {});
25
+ state.sampler = { total: ents.length, ok: ents.filter(s => s && s.available !== false).length, bad: ents.filter(s => s && s.available === false).length };
26
+ } catch { state.sampler = { ok: 0, bad: 0, total: 0 }; }
27
+ }
28
+ await refreshSampler();
29
+ setInterval(() => { refreshSampler().then(rerender); }, 15000);
20
30
 
21
31
  function buildSide() {
22
32
  return Side({ sections: [{ group: 'freddie', items: ROUTES.map(r => ({
@@ -30,8 +40,11 @@ function view() {
30
40
  const route = ROUTES.find(r => r.path === state.active) || ROUTES[0];
31
41
  const body = state.body || EmptyState({ text: 'loading…', glyph: '◌' });
32
42
  const main = h('div', { key: state.active, class: 'fd-page' }, ...(Array.isArray(body) ? body : [body]));
43
+ const samplerPill = state.sampler.total > 0
44
+ ? Chip({ tone: state.sampler.bad > 0 ? 'miss' : 'ok', children: 'sampler ' + state.sampler.ok + '/' + state.sampler.total })
45
+ : Chip({ tone: 'neutral', children: 'sampler —' });
33
46
  return AppShell({
34
- topbar: Topbar({ brand: 'freddie', leaf: 'dashboard', items: [], active: '' }),
47
+ topbar: Topbar({ brand: 'freddie', leaf: samplerPill, items: [], active: '' }),
35
48
  crumb: Crumb({ trail: ['freddie'], leaf: route.path, right: state.error ? Chip({ tone: 'miss', children: 'error' }) : Chip({ tone: 'ok', children: 'live' }) }),
36
49
  side: buildSide(),
37
50
  main,
@@ -75,4 +88,12 @@ applyDiff(root, view());
75
88
  loadActive();
76
89
 
77
90
  if (!window.__debug) window.__debug = {};
78
- window.__debug.dashboard = () => ({ booted: true, tools: host0.pi.tools.size, skills: host0.pi.skills.size, active: state.active });
91
+ window.__debug.dashboard = () => ({ booted: true, tools: host0.pi.tools.size, skills: host0.pi.skills.size, active: state.active, sampler: state.sampler });
92
+
93
+ window.addEventListener('keydown', ev => {
94
+ if ((ev.metaKey || ev.ctrlKey) && (ev.key === 'k' || ev.key === 'K')) {
95
+ ev.preventDefault();
96
+ if (state.active !== 'chat') setActive('chat');
97
+ setTimeout(() => { const ta = root.querySelector('textarea[name="prompt"]'); if (ta) ta.focus(); }, 100);
98
+ }
99
+ });