Files
Skald-Circle/web/css/system-agents.css
dguiducci 85536755ee
Nightly Build / build (push) Successful in 7m33s
feat: a "Run now" button for the memory lints — one pass, for whoever asked
The two memory lints run weekly, which is right for maintenance and wrong for
the moment somebody has just reorganised their notes and wants to know what the
lint makes of them. Each agent's tab now carries a button that starts one pass
immediately, for the caller.

It runs as the caller — their pool, their sessions, their hub — so the report
lands with the person who asked. The shared lint is the interesting case: its
scheduled pass runs as the admin because the shared store belongs to nobody, but
a member pressing the button reads the same store and gets the report themselves,
which is coherent with shared memory being readable by every member anyway.

Two settings are treated differently on purpose. Due-ness is skipped, exactly as
manual /compact skips the compactor's token threshold: the interval answers
*when*, and a human asking is a good enough answer to that. The Enabled switch
is honoured: it answers *whether*, and that one is the admin's.

The conversation review gets no button (AgentScope::PerSubject): it is about
somebody else and picks its own subjects, so "run it for me" has no meaning.
The frontend reads that from the agent's scope, not from a list of ids.

A second starter breaks an invariant the scheduler used to hold for free.
system_agent_runs::start sweeps any leftover `running` row of the same agent to
`failed` before inserting, which was safe only because one sequential loop was
the only thing that ever started a pass; a manual run overlapping a scheduled
one would have marked a healthy run as interrupted and duplicated its work. So
the agent list moves out of the scheduler and onto Skald as SystemAgents, which
holds the registry plus an in-flight guard both paths claim through — keyed on
what the pass is *about*, so an instance-wide agent is one slot no matter who
runs it, and a per-subject review is keyed on the subject rather than on the
supervisor lending the runtime.

has_work is answered synchronously, before anything is spawned: it leaves no run
row, so without that the button would say "started" over a log that never gains
a row. Everything after it is spawned — a pass is an LLM turn, and no HTTP
request should be held open for one. The run row exists before the browser is
answered, so the log itself is the progress surface; the page polls it quietly
until the pass leaves `running`.
2026-08-02 21:40:21 +01:00

160 lines
4.1 KiB
CSS

/* System agents page — the background agents the instance runs.
One tab per agent; a tab holds that agent's settings and its run history.
The settings form reuses the `.config-*` classes from config.css, so an owned
config set looks identical wherever it is edited. */
.sa-page {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
width: 100%;
overflow-y: auto;
}
.sa-body {
padding: 1.5rem;
}
.sa-subtitle {
font-size: 0.85rem;
color: var(--bs-secondary-color);
margin-bottom: 1rem;
max-width: 65ch;
}
/* ── Tabs ──────────────────────────────────────────────────────────────────── */
.sa-tab-bar {
display: flex;
gap: 0.25rem;
border-bottom: 1px solid var(--bs-border-color);
margin-bottom: 1rem;
overflow-x: auto;
}
.sa-tab {
display: inline-flex;
align-items: center;
gap: 0.4rem;
background: none;
border: none;
border-bottom: 2px solid transparent;
color: var(--bs-secondary-color);
font-size: 0.88rem;
padding: 0.5rem 0.85rem;
white-space: nowrap;
cursor: pointer;
}
.sa-tab:hover { color: var(--bs-body-color); }
.sa-tab--active {
color: var(--bs-body-color);
border-bottom-color: var(--bs-primary);
font-weight: 500;
}
/* ── Selected agent: description + settings ────────────────────────────────── */
.sa-agent-panel { margin-bottom: 1.25rem; }
.sa-agent-desc {
font-size: 0.85rem;
color: var(--bs-secondary-color);
max-width: 75ch;
margin-bottom: 1rem;
}
.sa-agent-config { margin-bottom: 0; }
/* Run now: the button, its one-line explanation, and the answer to the press —
on one row, wrapping on a narrow viewport rather than pushing the table down. */
.sa-agent-actions {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0.6rem;
margin-bottom: 1rem;
}
.sa-run-hint {
color: var(--bs-secondary-color);
font-size: 0.78rem;
}
.sa-run-msg {
display: inline-flex;
align-items: center;
gap: 0.35rem;
font-size: 0.82rem;
color: var(--bs-body-color);
background: var(--bs-tertiary-bg);
border-radius: 0.4rem;
padding: 0.2rem 0.55rem;
}
.sa-run-msg--error { color: var(--bs-danger); }
/* ── Run table ─────────────────────────────────────────────────────────────── */
.sa-table-wrap {
border: 1px solid var(--bs-border-color);
border-radius: 0.5rem;
overflow-x: auto;
}
.sa-table { margin-bottom: 0; }
.sa-row--clickable { cursor: pointer; }
.sa-row--clickable:hover td { background: var(--bs-tertiary-bg); }
.sa-agent {
font-family: monospace;
font-size: 0.82rem;
}
.sa-date {
font-size: 0.82rem;
color: var(--bs-secondary-color);
white-space: nowrap;
}
.sa-num {
font-variant-numeric: tabular-nums;
font-size: 0.85rem;
white-space: nowrap;
}
.sa-status {
display: inline-flex;
align-items: center;
gap: 0.3rem;
font-size: 0.8rem;
white-space: nowrap;
}
.sa-status--completed { color: var(--bs-success); }
.sa-status--failed { color: var(--bs-danger); }
.sa-status--running { color: var(--bs-secondary-color); }
.sa-status--cancelled { color: var(--bs-secondary-color); }
.sa-result {
font-size: 0.82rem;
color: var(--bs-secondary-color);
}
.sa-error {
color: var(--bs-danger);
display: inline-block;
max-width: 40ch;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
vertical-align: bottom;
}
.sa-state {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.4rem;
padding: 3rem;
justify-content: center;
color: var(--bs-secondary-color);
font-size: 0.9rem;
}
.sa-state--empty i { font-size: 1.6rem; opacity: 0.6; }
.sa-state--error { color: var(--bs-danger); flex-direction: row; }
.sa-pagination {
display: flex;
align-items: center;
gap: 0.75rem;
margin-top: 1rem;
justify-content: center;
}
.sa-page-info {
font-size: 0.82rem;
color: var(--bs-secondary-color);
}