Files
oh-my-pi/packages/coding-agent/src/task/spawn-policy.ts
T
Slava Zavadsky 9885ee34fc fix(agent): stop leaking scout into prompts when it is disabled
Hard-coded 'scout' references reached the model even when the scout
agent was disabled via task.disabledAgents or absent from the session
spawn list. Gate every such reference on scout actually being spawnable:
the task tool description, the delegation gates, the plan-mode and
workflowz notices, the glob/grep/ast-grep guidance, and the task
specialization advisory. Prompt shape is otherwise unchanged; only
erroneous references to the unavailable subagent are dropped.

Closes #7313
2026-08-01 23:50:33 -04:00

73 lines
2.2 KiB
TypeScript

/** Default agent used when a session has unrestricted spawning. */
export const DEFAULT_SPAWN_AGENT = "task";
/** Spawn policy derived from a parent agent's `spawns` frontmatter. */
export interface ResolvedSpawnPolicy {
/** True when at least one subagent may be spawned. */
enabled: boolean;
/** Agent used when the caller omits the agent field. */
defaultAgent: string;
/** Explicitly allowed agents, or `null` when the policy is unrestricted. */
allowedAgents: readonly string[] | null;
/** Text used in spawn rejection messages. */
allowedErrorText: string;
/** Backtick-quoted explicit agents for prompt descriptions. */
allowedPromptText?: string;
}
/** Resolves spawn frontmatter into the default and prompt/error surfaces. */
export function resolveSpawnPolicy(parentSpawns: string | boolean | null | undefined): ResolvedSpawnPolicy {
let normalized: string;
if (parentSpawns === false) {
normalized = "";
} else if (parentSpawns === true || parentSpawns === null || parentSpawns === undefined) {
normalized = "*";
} else {
normalized = parentSpawns.trim();
}
if (normalized === "*") {
return {
enabled: true,
defaultAgent: DEFAULT_SPAWN_AGENT,
allowedAgents: null,
allowedErrorText: "*",
};
}
const allowedAgents = normalized
.split(",")
.map(spawn => spawn.trim())
.filter(Boolean);
if (allowedAgents.length === 0) {
return {
enabled: false,
defaultAgent: DEFAULT_SPAWN_AGENT,
allowedAgents,
allowedErrorText: "none (spawns disabled for this agent)",
};
}
return {
enabled: true,
defaultAgent: allowedAgents[0] ?? DEFAULT_SPAWN_AGENT,
allowedAgents,
allowedErrorText: allowedAgents.join(","),
allowedPromptText: allowedAgents.map(agent => `\`${agent}\``).join(", "),
};
}
/**
* Whether the `scout` agent is spawnable in a session: not disabled via
* `task.disabledAgents`, and permitted by the session spawn policy.
*/
export function isScoutSpawnable(
disabledAgents: readonly string[] | undefined,
spawns: string | boolean | null | undefined,
): boolean {
if (disabledAgents?.includes("scout")) return false;
const policy = resolveSpawnPolicy(spawns);
if (!policy.enabled) return false;
return policy.allowedAgents === null || policy.allowedAgents.includes("scout");
}