@stratusagent/dashboard 0.12.2 → 0.12.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stratusagent/dashboard",
3
- "version": "0.12.2",
3
+ "version": "0.12.4",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -1,6 +1,6 @@
1
1
  // Types for the one UI module a test imports. The UI itself is plain ES
2
2
  // modules with no build step; this declaration is what lets `pnpm typecheck`
3
3
  // cover the test without pretending the module is TypeScript.
4
- export type AlwaysMeans = 'scope' | 'origin' | 'tool' | 'session';
4
+ export type AlwaysMeans = 'scope' | 'origin' | 'tool' | 'destination' | 'session';
5
5
  /** The line shown beside **Always allow**, or undefined when the lifetime is unknown. */
6
6
  export const alwaysOffer: (always: AlwaysMeans | undefined, agentName: string) => string | undefined;
package/ui/lib/grants.js CHANGED
@@ -17,6 +17,8 @@ export const alwaysOffer = (always, agentName) => {
17
17
  switch (always) {
18
18
  case 'tool':
19
19
  return `Always allow grants this tool to ${agentName} until an operator revokes it.`;
20
+ case 'destination':
21
+ return `Always allow lets ${agentName} use this tool on this conversation without asking, until revoked.`;
20
22
  case 'session':
21
23
  return 'Always allow stops this tool asking again for the rest of this session.';
22
24
  case 'scope':
@@ -0,0 +1,15 @@
1
+ // Types for a UI module a test imports (see latest.d.ts).
2
+ export interface ServedRuntime {
3
+ provider: string;
4
+ model?: string;
5
+ credentials: string;
6
+ /** Why no run can start on this runtime, when one can't. */
7
+ problem?: string;
8
+ }
9
+ export interface ServingRow {
10
+ title: string;
11
+ detail: string;
12
+ /** True when `detail` is the reason runs fail, not the credential source. */
13
+ problem: boolean;
14
+ }
15
+ export const servingRow: (runtime: ServedRuntime) => ServingRow;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * One row of the Serving card from a `/health` runtime.
3
+ *
4
+ * When no agent's run can resolve a provider, `/health` lists a runtime
5
+ * with `provider: 'none'` and a `problem` saying why and what to do. Shown
6
+ * like any other runtime it read "none · credentials: none", which looks
7
+ * like a setting rather than the reason every turn will fail. A runtime
8
+ * with a problem shows the problem instead.
9
+ */
10
+ export const servingRow = (runtime) => {
11
+ if (typeof runtime.problem === 'string' && runtime.problem.length > 0) {
12
+ return { title: 'No provider', detail: runtime.problem, problem: true };
13
+ }
14
+ return {
15
+ title: runtime.model ? `${runtime.provider} · ${runtime.model}` : runtime.provider,
16
+ detail: `credentials: ${runtime.credentials}`,
17
+ problem: false,
18
+ };
19
+ };
package/ui/styles.css CHANGED
@@ -130,6 +130,9 @@ body {
130
130
  .row .grow { flex: 1; min-width: 0; }
131
131
  .row .title { font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
132
132
  .row .sub { color: var(--muted); font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
133
+ .row .title.problem { white-space: normal; }
134
+ .row .sub.problem { color: var(--danger); white-space: normal; overflow-wrap: break-word; }
135
+ .row .title .pill { margin-left: 4px; vertical-align: 1px; }
133
136
 
134
137
  .pill {
135
138
  font-size: 11px; padding: 2px 8px; border-radius: 999px; font-weight: 600;
@@ -2,6 +2,7 @@ import { ago, duration, el, until } from '../lib/dom.js';
2
2
  import { api } from '../lib/api.js';
3
3
  import { avatar } from '../lib/avatar.js';
4
4
  import { alwaysOffer } from '../lib/grants.js';
5
+ import { servingRow } from '../lib/serving.js';
5
6
  import { isActive, navigate, refreshCore, store } from '../app.js';
6
7
 
7
8
  export const activityPanel = (filter) => {
@@ -121,11 +122,15 @@ const quickStats = () => {
121
122
  health?.runtimes?.length
122
123
  ? el('div', {},
123
124
  el('h3', {}, 'Serving'),
124
- el('div', { class: 'rows' }, ...health.runtimes.map((runtime) => el('div', { class: 'row' },
125
- el('div', { class: 'grow' },
126
- el('div', { class: 'title' }, runtime.model ? `${runtime.provider} · ${runtime.model}` : runtime.provider),
127
- el('div', { class: 'sub' }, `credentials: ${runtime.credentials}`)),
128
- ))))
125
+ el('div', { class: 'rows' }, ...health.runtimes.map((runtime) => {
126
+ const row = servingRow(runtime);
127
+ return el('div', { class: 'row' },
128
+ el('div', { class: 'grow' },
129
+ el('div', { class: row.problem ? 'title problem' : 'title' }, row.title, row.problem ? ' ' : null,
130
+ row.problem ? el('span', { class: 'pill failed' }, 'not serving') : null),
131
+ el('div', { class: row.problem ? 'sub problem' : 'sub' }, row.detail)),
132
+ );
133
+ })))
129
134
  : null,
130
135
  );
131
136
  };