Expose skill role binding stored vs env override in Admin API

Add enabled_stored and enabled_env_present on skills binding GET/POST so UIs can explain when AIA_SKILL_ROLE_BINDING_ENABLED overrides SQLite. Add Admin hints for save-required and env override. Add skill_role_binding_enabled_stored/env_present helpers and a unit test.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-05-11 15:59:51 +08:00
parent df30b5902f
commit 091a5626e7
4 changed files with 70 additions and 0 deletions

View file

@ -27,6 +27,8 @@ from oclaw.runtime.skill_role_binding import (
normalize_skill_role_binding,
ordered_binding_roles,
skill_role_binding_enabled,
skill_role_binding_enabled_env_present,
skill_role_binding_enabled_stored,
)
from oclaw.runtime.skills_prompt import collect_skill_catalog_entries
from oclaw.runtime.skills import _allowed_tool_names_after_wire_policy, discover_workspace_skill_manifests
@ -352,6 +354,8 @@ def include_skill_routes(
return {
"ok": True,
"enabled": bool(skill_role_binding_enabled(store=store)),
"enabled_stored": bool(skill_role_binding_enabled_stored(store=store)),
"enabled_env_present": bool(skill_role_binding_enabled_env_present()),
"manager_inherit": str(store.get_setting(SKILL_ROLE_BINDING_MANAGER_INHERIT_SETTING) or "").strip() not in {"0", "false", "False"},
"available_roles": roles,
"installed_skills": items,
@ -390,6 +394,8 @@ def include_skill_routes(
return {
"ok": True,
"enabled": bool(skill_role_binding_enabled(store=store)),
"enabled_stored": bool(skill_role_binding_enabled_stored(store=store)),
"enabled_env_present": bool(skill_role_binding_enabled_env_present()),
"manager_inherit": str(store.get_setting(SKILL_ROLE_BINDING_MANAGER_INHERIT_SETTING) or "").strip() not in {"0", "false", "False"},
"available_roles": roles,
"mapping": mapping,

View file

@ -7792,6 +7792,15 @@ async function renderSkills() {
const skillBindingState = { roles: [], names: [], mapping: {}, enabled: false, managerInherit: true };
const skillBindingStatus = el("div", { class: "muted", text: "" });
const skillBindingPersistHint = el("div", {
class: "muted",
style: "margin:6px 0;line-height:1.5;",
text: "Checkboxes and per-role skill lists are not saved until you click Save skill role binding.",
});
const skillBindingEnvHint = el("div", {
class: "muted",
style: "margin:6px 0;line-height:1.5;display:none;",
});
const skillEffectiveState = { items: [] };
const skillBindingEnabledCb = el("input", { type: "checkbox" });
const skillBindingManagerInheritCb = el("input", { type: "checkbox" });
@ -7910,6 +7919,18 @@ async function renderSkills() {
skillBindingState.managerInherit = Object.prototype.hasOwnProperty.call(r, "manager_inherit") ? !!r.manager_inherit : true;
skillBindingEnabledCb.checked = skillBindingState.enabled;
skillBindingManagerInheritCb.checked = skillBindingState.managerInherit;
if (r.enabled_env_present) {
skillBindingEnvHint.style.display = "block";
const stored = !!r.enabled_stored;
const eff = !!r.enabled;
skillBindingEnvHint.textContent =
"Process env AIA_SKILL_ROLE_BINDING_ENABLED is set: it overrides the Admin/SQLite value at runtime. " +
"The checkbox reflects the effective (env) value. Remove or unset that variable on the oclaw process to use Admin only. " +
`(stored in DB: ${String(stored)}, effective: ${String(eff)}).`;
} else {
skillBindingEnvHint.style.display = "none";
skillBindingEnvHint.textContent = "";
}
skillRoleSelect.innerHTML = "";
skillBindingState.roles.forEach((role) => {
skillRoleSelect.appendChild(el("option", { value: role, text: role }));
@ -7942,6 +7963,18 @@ async function renderSkills() {
skillBindingState.managerInherit = Object.prototype.hasOwnProperty.call(r, "manager_inherit") ? !!r.manager_inherit : true;
skillBindingEnabledCb.checked = skillBindingState.enabled;
skillBindingManagerInheritCb.checked = skillBindingState.managerInherit;
if (r.enabled_env_present) {
skillBindingEnvHint.style.display = "block";
const stored = !!r.enabled_stored;
const eff = !!r.enabled;
skillBindingEnvHint.textContent =
"Process env AIA_SKILL_ROLE_BINDING_ENABLED is set: it overrides the Admin/SQLite value at runtime. " +
"The checkbox reflects the effective (env) value. Remove or unset that variable on the oclaw process to use Admin only. " +
`(stored in DB: ${String(stored)}, effective: ${String(eff)}).`;
} else {
skillBindingEnvHint.style.display = "none";
skillBindingEnvHint.textContent = "";
}
skillBindingStatus.textContent = `saved: enabled=${String(r.enabled)} manager_inherit=${String(skillBindingState.managerInherit)}`;
renderSkillBindingList();
renderSkillBindingDashboard();
@ -7960,6 +7993,8 @@ async function renderSkills() {
"When enabled, installed workspace skills only appear in the model skills catalog for the selected role. You can optionally inherit manager-bound skills to other roles.",
}),
skillBindingStatus,
skillBindingPersistHint,
skillBindingEnvHint,
el("label", { class: "row", style: "gap:8px;align-items:center;margin-top:6px;" }, [
skillBindingEnabledCb,
el("span", { text: "Enable role binding (AIA_SKILL_ROLE_BINDING_ENABLED)" }),