Files
oh-my-pi/packages/coding-agent/src/tools/tool-timeouts.ts
T
roboomp 1b6588e520 fix(tools): cap per-tool default timeout with tools.maxTimeout
clampTimeout resolved the per-tool default (bash 300s) whenever the agent
omitted `timeout` and only enforced the tool's own min/max, so the
tools.maxTimeout global ceiling — applied solely in sdk.ts on explicitly
numeric args — was bypassed on the common default-fallback path.

Thread maxTimeout into clampTimeout so the resolved effective timeout,
including the default path, is capped before the per-tool floor/ceiling
apply. Explicit values below the cap still win; maxTimeout <= 0 stays
no-cap. Applied at every call site (bash, eval, browser, debug, lsp,
fetch, and the session-level bash executor), and the bash clamp notice
now names the global ceiling when it is the binding limit.

Fixes #6294
2026-07-22 15:18:27 +00:00

38 lines
1.5 KiB
TypeScript

export interface ToolTimeoutConfig {
/** Default timeout in seconds when agent omits the field */
default: number;
/** Minimum allowed timeout in seconds */
min: number;
/** Maximum allowed timeout in seconds (per-tool ceiling) */
max: number;
}
export const TOOL_TIMEOUTS = {
bash: { default: 300, min: 1, max: 3600 },
eval: { default: 30, min: 1, max: 3600 },
browser: { default: 30, min: 1, max: 300 },
ssh: { default: 60, min: 1, max: 3600 },
fetch: { default: 20, min: 1, max: 45 },
lsp: { default: 20, min: 5, max: 300 },
debug: { default: 30, min: 5, max: 300 },
} as const satisfies Record<string, ToolTimeoutConfig>;
export type ToolWithTimeout = keyof typeof TOOL_TIMEOUTS;
/**
* Clamp a raw timeout to the allowed range for a tool.
*
* When `rawTimeout` is undefined the tool's `default` is used. A positive
* `maxTimeout` (the `tools.maxTimeout` global ceiling) caps the *resolved*
* value — including the default-fallback path — before the per-tool `min`/`max`
* floor and ceiling apply, so a configured global cap governs calls where the
* agent omits `timeout`, not only explicitly-passed values. `maxTimeout <= 0`
* means no global cap.
*/
export function clampTimeout(tool: ToolWithTimeout, rawTimeout?: number, maxTimeout?: number): number {
const config = TOOL_TIMEOUTS[tool];
const timeout = rawTimeout ?? config.default;
const capped = maxTimeout !== undefined && maxTimeout > 0 ? Math.min(timeout, maxTimeout) : timeout;
return Math.max(config.min, Math.min(config.max, capped));
}