import { z } from "zod"; import { DEFAULT_TOOL_EXECUTION_TIMEOUT_SEC } from "../../api/constants/tool-execution.js"; export const TimeoutConfigSchema = z .object({ shellMaxTimeoutSec: z .number({ error: "timeouts.shellMaxTimeoutSec must be a number" }) .finite("timeouts.shellMaxTimeoutSec must be finite") .positive("timeouts.shellMaxTimeoutSec must be a positive number") .default(600) .describe( "Maximum allowed timeout for shell command execution in seconds", ), shellDefaultTimeoutSec: z .number({ error: "timeouts.shellDefaultTimeoutSec must be a number" }) .finite("timeouts.shellDefaultTimeoutSec must be finite") .positive("timeouts.shellDefaultTimeoutSec must be a positive number") .default(120) .describe( "Default timeout for shell commands when no explicit timeout is specified (seconds)", ), permissionTimeoutSec: z .number({ error: "timeouts.permissionTimeoutSec must be a number" }) .finite("timeouts.permissionTimeoutSec must be finite") .positive("timeouts.permissionTimeoutSec must be a positive number") .default(300) .describe( "How long to wait for a human to approve a tool call before timing out (seconds). Spent by both approval paths: the interactive permission prompt, and the inline wait when a contact's sensitive tool call is escalated to the guardian.", ), questionResponseTimeoutSec: z .number({ error: "timeouts.questionResponseTimeoutSec must be a number" }) .finite("timeouts.questionResponseTimeoutSec must be finite") .positive("timeouts.questionResponseTimeoutSec must be a positive number") .default(1800) .describe( "Backstop timeout for an unanswered ask_question prompt (seconds). The primary way an interactive user dismisses a prompt is by moving on — enqueuing another message supersedes it — so this only bounds a prompt left open with no response and no follow-up message.", ), toolExecutionTimeoutSec: z .number({ error: "timeouts.toolExecutionTimeoutSec must be a number" }) .finite("timeouts.toolExecutionTimeoutSec must be finite") .positive("timeouts.toolExecutionTimeoutSec must be a positive number") .default(DEFAULT_TOOL_EXECUTION_TIMEOUT_SEC) .describe("Default timeout for tool execution in seconds"), providerStreamTimeoutSec: z .number({ error: "timeouts.providerStreamTimeoutSec must be a number" }) .finite("timeouts.providerStreamTimeoutSec must be finite") .positive("timeouts.providerStreamTimeoutSec must be a positive number") .default(1800) .describe( "Timeout for waiting on the LLM provider's streaming response (seconds)", ), backgroundTurnTimeoutSec: z .number({ error: "timeouts.backgroundTurnTimeoutSec must be a number" }) .int("timeouts.backgroundTurnTimeoutSec must be an integer") .positive("timeouts.backgroundTurnTimeoutSec must be a positive integer") .max( 2147483, "timeouts.backgroundTurnTimeoutSec must be at most 2147483 (setTimeout-safe limit)", ) .default(1800) .describe( "Hard timeout for heartbeat and generic background agent turns (seconds)", ), scheduleTurnTimeoutSec: z .number({ error: "timeouts.scheduleTurnTimeoutSec must be a number" }) .int("timeouts.scheduleTurnTimeoutSec must be an integer") .positive("timeouts.scheduleTurnTimeoutSec must be a positive integer") .max( 2147483, "timeouts.scheduleTurnTimeoutSec must be at most 2147483 (setTimeout-safe limit)", ) .default(1800) .describe( "Hard timeout for deliberately-launched scheduled (talk-mode) agent turns (seconds)", ), }) .describe("Timeout configuration for various operations"); export const RateLimitConfigSchema = z .object({ maxRequestsPerMinute: z .number({ error: "rateLimit.maxRequestsPerMinute must be a number" }) .int("rateLimit.maxRequestsPerMinute must be an integer") .nonnegative( "rateLimit.maxRequestsPerMinute must be a non-negative integer", ) .default(0) .describe("Maximum number of LLM requests per minute (0 = unlimited)"), }) .describe("Rate limiting for LLM provider requests"); export type TimeoutConfig = z.infer; export type RateLimitConfig = z.infer;