fix: harden subagent control boundaries

This commit is contained in:
Peter Steinberger
2026-03-11 01:44:25 +00:00
parent 68c674d37c
commit aad014c7c1
26 changed files with 1389 additions and 879 deletions

View File

@@ -67,6 +67,22 @@ function supportsSpawnLineage(storeKey: string): boolean {
return isSubagentSessionKey(storeKey) || isAcpSessionKey(storeKey);
}
function normalizeSubagentRole(raw: string): "orchestrator" | "leaf" | undefined {
const normalized = raw.trim().toLowerCase();
if (normalized === "orchestrator" || normalized === "leaf") {
return normalized;
}
return undefined;
}
function normalizeSubagentControlScope(raw: string): "children" | "none" | undefined {
const normalized = raw.trim().toLowerCase();
if (normalized === "children" || normalized === "none") {
return normalized;
}
return undefined;
}
export async function applySessionsPatchToStore(params: {
cfg: OpenClawConfig;
store: Record<string, SessionEntry>;
@@ -134,6 +150,48 @@ export async function applySessionsPatchToStore(params: {
}
}
if ("subagentRole" in patch) {
const raw = patch.subagentRole;
if (raw === null) {
if (existing?.subagentRole) {
return invalid("subagentRole cannot be cleared once set");
}
} else if (raw !== undefined) {
if (!supportsSpawnLineage(storeKey)) {
return invalid("subagentRole is only supported for subagent:* or acp:* sessions");
}
const normalized = normalizeSubagentRole(String(raw));
if (!normalized) {
return invalid('invalid subagentRole (use "orchestrator" or "leaf")');
}
if (existing?.subagentRole && existing.subagentRole !== normalized) {
return invalid("subagentRole cannot be changed once set");
}
next.subagentRole = normalized;
}
}
if ("subagentControlScope" in patch) {
const raw = patch.subagentControlScope;
if (raw === null) {
if (existing?.subagentControlScope) {
return invalid("subagentControlScope cannot be cleared once set");
}
} else if (raw !== undefined) {
if (!supportsSpawnLineage(storeKey)) {
return invalid("subagentControlScope is only supported for subagent:* or acp:* sessions");
}
const normalized = normalizeSubagentControlScope(String(raw));
if (!normalized) {
return invalid('invalid subagentControlScope (use "children" or "none")');
}
if (existing?.subagentControlScope && existing.subagentControlScope !== normalized) {
return invalid("subagentControlScope cannot be changed once set");
}
next.subagentControlScope = normalized;
}
}
if ("label" in patch) {
const raw = patch.label;
if (raw === null) {