diff --git a/src/config/types.agent-defaults.ts b/src/config/types.agent-defaults.ts index 604bf88bdcb..363d45b9eae 100644 --- a/src/config/types.agent-defaults.ts +++ b/src/config/types.agent-defaults.ts @@ -269,6 +269,14 @@ export type AgentDefaultsConfig = { * Default: false (only the final heartbeat payload is delivered). */ includeReasoning?: boolean; + /** + * Max timeout in seconds for a heartbeat embedded run. + * Allows heartbeats to fail fast (e.g., 60s) when a model hangs, + * without affecting the global agents.defaults.timeoutSeconds (default 600s). + * + * Default: undefined (inherits agents.defaults.timeoutSeconds). + */ + timeoutSeconds?: number; }; /** Max concurrent agent runs across all conversations. Default: 1 (sequential). */ maxConcurrent?: number; diff --git a/src/config/zod-schema.agent-runtime.ts b/src/config/zod-schema.agent-runtime.ts index 10f0f8637e9..9a40f2ddcbf 100644 --- a/src/config/zod-schema.agent-runtime.ts +++ b/src/config/zod-schema.agent-runtime.ts @@ -35,6 +35,7 @@ export const HeartbeatSchema = z suppressToolErrorWarnings: z.boolean().optional(), lightContext: z.boolean().optional(), isolatedSession: z.boolean().optional(), + timeoutSeconds: z.number().int().positive().optional(), }) .strict() .superRefine((val, ctx) => { diff --git a/src/infra/heartbeat-runner.ts b/src/infra/heartbeat-runner.ts index 7f1b48b2e3b..e51845cdb4e 100644 --- a/src/infra/heartbeat-runner.ts +++ b/src/infra/heartbeat-runner.ts @@ -714,7 +714,7 @@ export async function runHeartbeatOnce(opts: { heartbeatModelOverride || timeoutOverrideSeconds !== undefined ? { isHeartbeat: true, - heartbeatModelOverride, + ...(heartbeatModelOverride !== undefined && { heartbeatModelOverride }), suppressToolErrorWarnings, bootstrapContextMode, ...(timeoutOverrideSeconds !== undefined && { timeoutOverrideSeconds }),