fix(task): let task.softRequestBudget lower bundled subagent budgets
The soft request budget resolved to `SOFT_REQUEST_BUDGET[agent.name] ?? configured`, so the bundled entries for scout and sonic replaced the configured value outright. Lowering `task.softRequestBudget` to tighten the guard therefore did nothing for exactly the two agents that spawn most often: a scout kept its 100-request budget no matter how small the user set the knob. Only 0 (disable) and raising the value for non-bundled agents had any effect. Treat both numbers as upper bounds and take the smaller one. The bundled entries stay ceilings, so a runaway scout is still stopped at 100 by default and existing behavior is unchanged for anyone who has not lowered the setting; a configured 0 still disables the guard entirely. Resolution moves into `resolveSoftRequestBudget`, which also normalizes negative and fractional inputs, so the rule is testable without standing up a subprocess run. This composes with `task.maxEffort` on a separate axis: effort caps how hard each request thinks, this caps how many requests a run may spend. (cherry picked from commit f0db29f8f725f11390b64ca9342300c482ff5c5d)
This commit is contained in:
@@ -87,8 +87,10 @@ const MCP_CALL_TIMEOUT_MS = 60_000;
|
||||
* agent is driven to one forced final `yield` so partial findings come back
|
||||
* as a real report; only if it still refuses to yield within
|
||||
* {@link BUDGET_STOP_GRACE_REQUESTS} more requests is the run hard-aborted.
|
||||
* The `default` key applies to agents without an explicit entry and can be
|
||||
* overridden via the `task.softRequestBudget` setting (0 disables the guard).
|
||||
* Entries are ceilings, not fixed values: the `default` key applies to agents
|
||||
* without an explicit entry, and the `task.softRequestBudget` setting can only
|
||||
* lower an agent's budget, never raise it above its bundled entry (0 disables
|
||||
* the guard entirely).
|
||||
*/
|
||||
export const SOFT_REQUEST_BUDGET: Record<string, number> = {
|
||||
scout: 100,
|
||||
@@ -96,6 +98,18 @@ export const SOFT_REQUEST_BUDGET: Record<string, number> = {
|
||||
default: 200,
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolves the effective soft request budget for an agent. The configured
|
||||
* `task.softRequestBudget` and the agent's bundled entry are both upper
|
||||
* bounds, so the tighter one wins; a configured budget of 0 disables the
|
||||
* guard regardless of the bundled entry.
|
||||
*/
|
||||
export function resolveSoftRequestBudget(agentName: string, configuredBudget: number): number {
|
||||
const normalized = Math.max(0, Math.trunc(configuredBudget));
|
||||
if (normalized === 0) return 0;
|
||||
return Math.min(normalized, SOFT_REQUEST_BUDGET[agentName] ?? normalized);
|
||||
}
|
||||
|
||||
/** Extra requests allowed after a budget stop for the forced yield to land before the run is hard-aborted. */
|
||||
export const BUDGET_STOP_GRACE_REQUESTS = 5;
|
||||
|
||||
@@ -2446,8 +2460,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
||||
0,
|
||||
Math.trunc(Number(settings.get("task.softRequestBudget") ?? SOFT_REQUEST_BUDGET.default) || 0),
|
||||
);
|
||||
const softRequestBudget =
|
||||
configuredDefaultBudget === 0 ? 0 : (SOFT_REQUEST_BUDGET[agent.name] ?? configuredDefaultBudget);
|
||||
const softRequestBudget = resolveSoftRequestBudget(agent.name, configuredDefaultBudget);
|
||||
const softRequestBudgetNotice = settings.get("task.softRequestBudgetNotice") ?? false;
|
||||
const parentDepth = options.taskDepth ?? 0;
|
||||
const childDepth = parentDepth + 1;
|
||||
|
||||
Reference in New Issue
Block a user