multi_agent_chat/permissions: layer user allow-list into subagent compile

This commit is contained in:
CREDO23 2026-05-14 21:57:38 +02:00
parent e99c06c887
commit ef1152b80e
25 changed files with 304 additions and 62 deletions

View file

@ -9,9 +9,10 @@ matching OpenCode's ``permission/index.ts`` evaluation order):
needs to *deny* what the user has explicitly forbidden; the default
``ask`` fallback would otherwise double-prompt every safe read-only
call.
2. ``extra_rulesets`` caller-supplied rulesets. Each subagent
contributes its own (KB: destructive-FS ``ask`` rules; connectors:
per-tool ``allow``/``ask``).
2. ``subagent_rulesets`` caller-supplied rulesets contributed by the
consuming subagent. Each subagent passes its coded rules (KB:
destructive-FS ``ask`` rules; connectors: per-tool ``allow``/``ask``)
plus, when present, the user's persisted allow-list for that subagent.
Connector deny synthesis from ``new_chat._synthesize_connector_deny_rules``
is intentionally NOT replicated: the multi-agent orchestrator already
@ -36,32 +37,34 @@ _SURFSENSE_DEFAULTS = Ruleset(
def build_permission_mw(
*,
flags: AgentFeatureFlags,
extra_rulesets: list[Ruleset] | None = None,
subagent_rulesets: list[Ruleset] | None = None,
) -> PermissionMiddleware | None:
"""Return a configured :class:`PermissionMiddleware` or ``None`` when no work is needed.
Args:
flags: Feature toggles. ``enable_permission`` switches the engine on;
``disable_new_agent_stack`` overrides everything for safety.
extra_rulesets: Caller-supplied rulesets layered after the defaults.
Subagents pass their own ruleset here so each subagent owns its
rules without aliasing a shared engine. Presence of any extra
ruleset forces the middleware on regardless of
``enable_permission`` an explicit ``ask`` rule always asks.
subagent_rulesets: Caller-supplied rulesets layered after the
defaults. Subagents pass their own coded ruleset here (and,
when present, the user's persisted allow-list for that
subagent) so each subagent owns its own rule surface without
aliasing a shared engine. Presence of any subagent ruleset
forces the middleware on regardless of ``enable_permission``
an explicit ``ask`` rule always asks.
Returns:
``None`` when the engine has no rules to enforce
(``enable_permission=False`` and no extras); a configured middleware
otherwise.
(``enable_permission=False`` and no subagent rulesets); a
configured middleware otherwise.
"""
permission_enabled = flags.enable_permission and not flags.disable_new_agent_stack
has_extras = bool(extra_rulesets)
if not (permission_enabled or has_extras):
has_subagent_rulesets = bool(subagent_rulesets)
if not (permission_enabled or has_subagent_rulesets):
return None
rulesets: list[Ruleset] = [_SURFSENSE_DEFAULTS]
if extra_rulesets:
rulesets.extend(extra_rulesets)
if subagent_rulesets:
rulesets.extend(subagent_rulesets)
return PermissionMiddleware(rulesets=rulesets)