@@ -34,10 +34,10 @@ export const MIN_PI_TIMEOUT_MS = 60 * 1000
3434 * reaped the sandbox and surface as an opaque SDK error.
3535 *
3636 * The reserve matters as much as the cap. The sandbox clock starts at create,
37- * and three commands bracket the agent turn: the clone before it, then the
38- * commit and the push after it, the last two sharing
39- * {@link FINALIZE_TIMEOUT_MS}. Capping at the bare lifetime would mean the
40- * sandbox always died first, taking the agent's finished work with it unpushed .
37+ * and authoring has three commands around the agent turn: the clone before it,
38+ * then the commit and push after it, the last two sharing
39+ * {@link FINALIZE_TIMEOUT_MS}. Plan has no finalize phase and sets that reserve
40+ * to zero. Capping at the bare lifetime would mean the sandbox died first .
4141 *
4242 * Takes the lifetime as an argument rather than reading the provider ceiling
4343 * itself, because that ceiling is no longer the only lifetime a run can get: a
@@ -53,10 +53,17 @@ export const MIN_PI_TIMEOUT_MS = 60 * 1000
5353 * through `ttlMinutes`. Reserving the surrounding commands keeps the agent turn
5454 * inside the lifetime the selected provider actually received.
5555 */
56- export function resolvePiTimeoutMs ( lifetimeMs = resolvePiSandboxLifetimeMs ( ) ) : number {
56+ export function resolvePiTimeoutMs (
57+ lifetimeMs = resolvePiSandboxLifetimeMs ( ) ,
58+ options ?: { finalizePhases ?: number }
59+ ) : number {
60+ const finalizePhases = options ?. finalizePhases ?? 2
5761 return Math . min (
5862 getMaxExecutionTimeout ( ) ,
59- Math . max ( lifetimeMs - CLONE_TIMEOUT_MS - 2 * FINALIZE_TIMEOUT_MS , MIN_PI_TIMEOUT_MS )
63+ Math . max (
64+ lifetimeMs - CLONE_TIMEOUT_MS - finalizePhases * FINALIZE_TIMEOUT_MS ,
65+ MIN_PI_TIMEOUT_MS
66+ )
6067 )
6168}
6269
0 commit comments