chore: add UI field hover help and update project notes
This commit is contained in:
@@ -120,6 +120,101 @@ const MANIFEST_EVENT_TRIGGERS = [
|
||||
const RUN_MANIFEST_EDITOR_VALUE = "__editor__";
|
||||
const RUN_MANIFEST_EDITOR_LABEL = "[Use Manifest Editor JSON]";
|
||||
|
||||
const LABEL_HELP_BY_CONTROL = Object.freeze({
|
||||
"session-select": "Select which session the graph and feed should focus on.",
|
||||
"graph-manifest-select": "Choose the manifest context used when rendering the selected session graph.",
|
||||
"run-prompt": "Describe the task objective you want the run to complete.",
|
||||
"run-manifest-select": "Choose a saved manifest or use the JSON currently in the editor.",
|
||||
"run-execution-mode": "Use provider for live model execution or mock for simulated execution.",
|
||||
"run-provider": "Choose which model provider backend handles provider-mode runs.",
|
||||
"run-topology-hint": "Optional hint that nudges orchestration toward a topology strategy.",
|
||||
"run-flags": "Optional JSON object passed in as initial run flags.",
|
||||
"run-validation-nodes": "Optional comma-separated node IDs to simulate validation outcomes for.",
|
||||
"events-limit": "Set how many recent runtime events are loaded per refresh.",
|
||||
"cfg-webhook-url": "Webhook endpoint that receives runtime event notifications.",
|
||||
"cfg-webhook-severity": "Minimum severity level that triggers webhook notifications.",
|
||||
"cfg-webhook-always": "Event types that should always notify, regardless of severity.",
|
||||
"cfg-security-mode": "Policy behavior used when a command violates security rules.",
|
||||
"cfg-security-binaries": "Comma-separated command binaries permitted by policy.",
|
||||
"cfg-security-timeout": "Maximum command execution time before forced timeout.",
|
||||
"cfg-security-inherit": "Environment variable names to pass through to subprocesses.",
|
||||
"cfg-security-scrub": "Environment variable names to strip before command execution.",
|
||||
"cfg-limit-concurrent": "Maximum number of agents that can run concurrently across sessions.",
|
||||
"cfg-limit-session": "Maximum number of agents that can run concurrently within a single session.",
|
||||
"cfg-limit-depth": "Maximum recursive spawn depth allowed for agent tasks.",
|
||||
"cfg-topology-depth": "Maximum orchestration graph depth permitted by topology rules.",
|
||||
"cfg-topology-retries": "Maximum retry expansions allowed by topology orchestration.",
|
||||
"cfg-relationship-children": "Maximum children each persona relationship can spawn.",
|
||||
"cfg-port-base": "Starting port number for provisioning port allocations.",
|
||||
"cfg-port-block-size": "Number of ports reserved per allocated block.",
|
||||
"cfg-port-block-count": "Number of port blocks available for allocation.",
|
||||
"cfg-port-primary-offset": "Offset within each block used for the primary service port.",
|
||||
"manifest-path": "Workspace-relative manifest file path to load, validate, or save.",
|
||||
"helper-topology-sequential": "Allow sequential execution topology in this manifest.",
|
||||
"helper-topology-parallel": "Allow parallel execution topology in this manifest.",
|
||||
"helper-topology-hierarchical": "Allow hierarchical parent-child execution topology.",
|
||||
"helper-topology-retry-unrolled": "Allow retry-unrolled topology for explicit retry paths.",
|
||||
"helper-topology-max-depth": "Top-level cap on orchestration depth in this manifest.",
|
||||
"helper-topology-max-retries": "Top-level cap on retry attempts in this manifest.",
|
||||
"helper-entry-node-id": "Node ID used as the pipeline entry point.",
|
||||
"helper-persona-id": "Stable persona identifier referenced by nodes and relationships.",
|
||||
"helper-persona-display-name": "Human-readable persona name shown in summaries and tooling.",
|
||||
"helper-persona-model-constraint": "Optional model restriction for this persona only.",
|
||||
"helper-persona-system-prompt": "Base prompt template that defines persona behavior.",
|
||||
"helper-persona-allowlist": "Comma-separated tool names this persona may use.",
|
||||
"helper-persona-banlist": "Comma-separated tool names this persona must not use.",
|
||||
"helper-relationship-parent": "Parent persona ID that can spawn or delegate to the child.",
|
||||
"helper-relationship-child": "Child persona ID allowed under the selected parent.",
|
||||
"helper-relationship-max-depth": "Optional override limiting recursion depth for this relationship.",
|
||||
"helper-relationship-max-children": "Optional override limiting child fan-out for this relationship.",
|
||||
"helper-node-id": "Unique pipeline node identifier used by entry node and edges.",
|
||||
"helper-node-actor-id": "Runtime actor identifier assigned to this node.",
|
||||
"helper-node-persona-id": "Persona applied when this node executes.",
|
||||
"helper-node-topology-kind": "Optional node-level topology override.",
|
||||
"helper-node-block-id": "Optional topology block identifier for grouped scheduling logic.",
|
||||
"helper-node-max-retries": "Optional node-level retry limit override.",
|
||||
"helper-edge-from": "Source node where this edge starts.",
|
||||
"helper-edge-to": "Target node activated when this edge condition matches.",
|
||||
"helper-edge-trigger-kind": "Choose whether edge activation is status-based or event-based.",
|
||||
"helper-edge-on": "Node status value that triggers this edge when using status mode.",
|
||||
"helper-edge-event": "Domain event name that triggers this edge when using event mode.",
|
||||
"helper-edge-when": "Optional JSON array of additional conditions required to follow the edge.",
|
||||
});
|
||||
|
||||
function extractLabelText(label) {
|
||||
const clone = label.cloneNode(true);
|
||||
for (const field of clone.querySelectorAll("input, select, textarea")) {
|
||||
field.remove();
|
||||
}
|
||||
return clone.textContent?.replace(/\s+/g, " ").trim() || "this field";
|
||||
}
|
||||
|
||||
function applyLabelTooltips(root = document) {
|
||||
for (const label of root.querySelectorAll("label")) {
|
||||
const control = label.querySelector("input,select,textarea");
|
||||
if (!control) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let help = LABEL_HELP_BY_CONTROL[control.id] || "";
|
||||
if (!help) {
|
||||
for (const className of control.classList) {
|
||||
help = LABEL_HELP_BY_CONTROL[className] || "";
|
||||
if (help) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!help) {
|
||||
const labelText = extractLabelText(label).toLowerCase();
|
||||
help = `Set ${labelText} for this configuration.`;
|
||||
}
|
||||
|
||||
label.title = help;
|
||||
control.title = help;
|
||||
}
|
||||
}
|
||||
|
||||
function fmtMoney(value) {
|
||||
return `$${Number(value || 0).toFixed(4)}`;
|
||||
}
|
||||
@@ -575,6 +670,8 @@ function renderManifestHelper() {
|
||||
`;
|
||||
})
|
||||
.join("");
|
||||
|
||||
applyLabelTooltips(dom.manifestForm);
|
||||
}
|
||||
|
||||
function readManifestDraftFromHelper() {
|
||||
@@ -1737,6 +1834,7 @@ async function refreshAll() {
|
||||
|
||||
async function initialize() {
|
||||
bindUiEvents();
|
||||
applyLabelTooltips();
|
||||
|
||||
try {
|
||||
await apiRequest("/api/health");
|
||||
|
||||
Reference in New Issue
Block a user