feat(#1082): add description() to ToolGroup + Capability; expose in API + UI tooltips
- hive-sh4re: ToolGroup::description() and Capability::description() return short human-readable strings for each variant - hive-c0re: ToolGroupsSnapshot and CapabilitiesSnapshot now include a `descriptions` map (name → description); get_capabilities now iterates Capability::ALL instead of hardcoding the list - tabs.js: renderToolGroups + renderCapabilities use descriptions[name] as the column header title attribute (native browser tooltip on hover)
This commit is contained in:
parent
4a632fabcc
commit
2368bec634
3 changed files with 62 additions and 6 deletions
|
|
@ -1196,7 +1196,7 @@ window.marked = marked;
|
||||||
|
|
||||||
function renderCapabilities(root, data) {
|
function renderCapabilities(root, data) {
|
||||||
root.replaceChildren();
|
root.replaceChildren();
|
||||||
const { caps, assignments } = data;
|
const { caps, descriptions = {}, assignments } = data;
|
||||||
if (!caps || !caps.length) {
|
if (!caps || !caps.length) {
|
||||||
root.append(el('p', { class: 'meta' }, '(no capabilities defined)'));
|
root.append(el('p', { class: 'meta' }, '(no capabilities defined)'));
|
||||||
return;
|
return;
|
||||||
|
|
@ -1221,7 +1221,7 @@ window.marked = marked;
|
||||||
const hrow = el('tr');
|
const hrow = el('tr');
|
||||||
hrow.append(el('th', { class: 'cap-agent-col' }, 'agent'));
|
hrow.append(el('th', { class: 'cap-agent-col' }, 'agent'));
|
||||||
for (const c of caps) {
|
for (const c of caps) {
|
||||||
hrow.append(el('th', { class: 'cap-col', title: c }, c));
|
hrow.append(el('th', { class: 'cap-col', title: descriptions[c] || c }, c));
|
||||||
}
|
}
|
||||||
hrow.append(el('th', { class: 'cap-save-col' }, ''));
|
hrow.append(el('th', { class: 'cap-save-col' }, ''));
|
||||||
thead.append(hrow);
|
thead.append(hrow);
|
||||||
|
|
@ -1311,7 +1311,7 @@ window.marked = marked;
|
||||||
|
|
||||||
function renderToolGroups(root, data) {
|
function renderToolGroups(root, data) {
|
||||||
root.replaceChildren();
|
root.replaceChildren();
|
||||||
const { groups, assignments } = data;
|
const { groups, descriptions = {}, assignments } = data;
|
||||||
if (!groups || !groups.length) {
|
if (!groups || !groups.length) {
|
||||||
root.append(el('p', { class: 'meta' }, '(no tool groups defined)'));
|
root.append(el('p', { class: 'meta' }, '(no tool groups defined)'));
|
||||||
return;
|
return;
|
||||||
|
|
@ -1337,7 +1337,7 @@ window.marked = marked;
|
||||||
const hrow = el('tr');
|
const hrow = el('tr');
|
||||||
hrow.append(el('th', { class: 'tg-agent-col' }, 'agent'));
|
hrow.append(el('th', { class: 'tg-agent-col' }, 'agent'));
|
||||||
for (const g of groups) {
|
for (const g of groups) {
|
||||||
hrow.append(el('th', { class: 'tg-group-col', title: g }, g));
|
hrow.append(el('th', { class: 'tg-group-col', title: descriptions[g] || g }, g));
|
||||||
}
|
}
|
||||||
hrow.append(el('th', { class: 'tg-save-col' }, ''));
|
hrow.append(el('th', { class: 'tg-save-col' }, ''));
|
||||||
thead.append(hrow);
|
thead.append(hrow);
|
||||||
|
|
|
||||||
|
|
@ -2512,6 +2512,8 @@ struct ToolGroupsSnapshot {
|
||||||
/// Ordered list of all known tool-group names. Drives the column
|
/// Ordered list of all known tool-group names. Drives the column
|
||||||
/// headers in the capabilities table — the UI does not hard-code them.
|
/// headers in the capabilities table — the UI does not hard-code them.
|
||||||
groups: Vec<&'static str>,
|
groups: Vec<&'static str>,
|
||||||
|
/// Short description for each group name. Keys match `groups` entries.
|
||||||
|
descriptions: std::collections::BTreeMap<&'static str, &'static str>,
|
||||||
/// Per-agent assignment map. Absent agents use the role default
|
/// Per-agent assignment map. Absent agents use the role default
|
||||||
/// (agents: messaging+meta+inbox+execution; manager: all groups).
|
/// (agents: messaging+meta+inbox+execution; manager: all groups).
|
||||||
assignments: std::collections::BTreeMap<String, Vec<String>>,
|
assignments: std::collections::BTreeMap<String, Vec<String>>,
|
||||||
|
|
@ -2522,9 +2524,14 @@ async fn get_tool_groups(State(_state): State<AppState>) -> axum::Json<ToolGroup
|
||||||
.iter()
|
.iter()
|
||||||
.map(|g| g.as_str())
|
.map(|g| g.as_str())
|
||||||
.collect();
|
.collect();
|
||||||
|
let descriptions = hive_sh4re::ToolGroup::ALL
|
||||||
|
.iter()
|
||||||
|
.map(|g| (g.as_str(), g.description()))
|
||||||
|
.collect();
|
||||||
let assignments = crate::tool_groups::read();
|
let assignments = crate::tool_groups::read();
|
||||||
axum::Json(ToolGroupsSnapshot {
|
axum::Json(ToolGroupsSnapshot {
|
||||||
groups,
|
groups,
|
||||||
|
descriptions,
|
||||||
assignments,
|
assignments,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -2566,14 +2573,25 @@ struct CapabilitiesSnapshot {
|
||||||
/// Ordered list of all known capability names. Drives the column
|
/// Ordered list of all known capability names. Drives the column
|
||||||
/// headers in the capabilities table — the UI does not hard-code them.
|
/// headers in the capabilities table — the UI does not hard-code them.
|
||||||
caps: Vec<&'static str>,
|
caps: Vec<&'static str>,
|
||||||
|
/// Short description for each capability name. Keys match `caps` entries.
|
||||||
|
descriptions: std::collections::BTreeMap<&'static str, &'static str>,
|
||||||
/// Per-agent capability grant map. Absent agents have no extra caps.
|
/// Per-agent capability grant map. Absent agents have no extra caps.
|
||||||
assignments: std::collections::BTreeMap<String, Vec<String>>,
|
assignments: std::collections::BTreeMap<String, Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_capabilities(State(_state): State<AppState>) -> axum::Json<CapabilitiesSnapshot> {
|
async fn get_capabilities(State(_state): State<AppState>) -> axum::Json<CapabilitiesSnapshot> {
|
||||||
let caps = hive_sh4re::Capability::ALL.iter().map(|c| c.as_str()).collect();
|
use hive_sh4re::Capability;
|
||||||
|
let caps = Capability::ALL.iter().map(|c| c.as_str()).collect();
|
||||||
|
let descriptions = Capability::ALL
|
||||||
|
.iter()
|
||||||
|
.map(|c| (c.as_str(), c.description()))
|
||||||
|
.collect();
|
||||||
let assignments = crate::capabilities::read();
|
let assignments = crate::capabilities::read();
|
||||||
axum::Json(CapabilitiesSnapshot { caps, assignments })
|
axum::Json(CapabilitiesSnapshot {
|
||||||
|
caps,
|
||||||
|
descriptions,
|
||||||
|
assignments,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
|
|
||||||
|
|
@ -876,6 +876,30 @@ impl ToolGroup {
|
||||||
Self::WebTools => "web_tools",
|
Self::WebTools => "web_tools",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Short human-readable description suitable for a tooltip or help text.
|
||||||
|
#[must_use]
|
||||||
|
pub fn description(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Messaging => "send, recv, ask, answer — core agent communication",
|
||||||
|
Self::Meta => "set_status, get_agent_meta — identity and status",
|
||||||
|
Self::Inbox => {
|
||||||
|
"get_loose_ends, cancel_loose_end, remind, request_next_turn — self-scheduling"
|
||||||
|
}
|
||||||
|
Self::Lifecycle => "kill, start, restart, update — container lifecycle (privileged)",
|
||||||
|
Self::Approvals => {
|
||||||
|
"request_init_config, request_apply_commit, request_update_meta_inputs — config change flow (privileged)"
|
||||||
|
}
|
||||||
|
Self::Scheduling => {
|
||||||
|
"request_schedule_prompt and related — operator-visible scheduled prompts (privileged)"
|
||||||
|
}
|
||||||
|
Self::Diagnostics => "get_logs — read host journal and build logs (privileged)",
|
||||||
|
Self::Execution => "bash_run, bash_status — run shell commands in the container",
|
||||||
|
Self::WebTools => {
|
||||||
|
"WebFetch, WebSearch — Claude built-in web egress; not MCP tools"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Per-agent capability grants. Stored in `meta/capabilities.json`
|
/// Per-agent capability grants. Stored in `meta/capabilities.json`
|
||||||
|
|
@ -962,6 +986,20 @@ impl Capability {
|
||||||
Self::QueryAgentState => "query_agent_state",
|
Self::QueryAgentState => "query_agent_state",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Short human-readable description suitable for a tooltip or help text.
|
||||||
|
#[must_use]
|
||||||
|
pub fn description(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::ManageRootAgent => {
|
||||||
|
"lifecycle-manage the root/manager agent on hive crash recovery"
|
||||||
|
}
|
||||||
|
Self::ReadHostJournal => "read host journald via get_host_journal MCP tool",
|
||||||
|
Self::QueryAgentState => {
|
||||||
|
"query non-child agents' loose ends and reminder state via get_loose_ends"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Schedule row shape on the wire — mirror of
|
/// Schedule row shape on the wire — mirror of
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue