If your agent misses a 20-second user deadline but keeps calling tools for another minute, you are paying for work nobody wants. The visible symptom is a timeout; the hidden cost is orphaned nested retries and sub-agents operating on fresh, independent timers. As Jack M. outlines on DEV.to, this happens because every child operation receives its own relative timeout rather than inheriting the parentβs absolute finish time. The result is a run that has no shared idea of when to stop, burning API capacity and worker slots long after the user has disconnected.
The Relative Timeout Trap
Consider a standard 25-second product SLA. Your API handler might allow 25 seconds, but if the model SDK allows 20, a search tool allows 15 (with retries), and a sub-agent allows 20, the math breaks. A tool starting at second 18 can consume its full 15 seconds, hand off to a retrying model call, and keep the infrastructure billing well past the 25-second mark. These settings do not add up to a coherent workflow; they create a chain of disjointed timers that ignore the global constraint. The fix is not a prompt instruction telling the LLM to 'hurry up'βit is runtime enforcement.
Implementing the Deadline Envelope
The solution is a RunBudget object that sets an absolute deadlineAt timestamp at the trusted edge, separate from user-provided prompts. This envelope includes a responseReserveMs to account for JSON validation and serialization, ensuring the workflow doesn't fail right at the finish line. Every child operation must calculate its remainingMs from the parentβs deadline. If a toolβs minimum useful time does not fit within the remaining budget after the reserve, it should skip execution, trigger an approved fallback, or return a partial result immediately. This prevents the 'silent continuation' of work that no longer matters.
Propagation and Cancellation Hygiene
You must separate five distinct controls: request deadlines, step limits, tool timeouts, retry budgets, and cancellation signals. An LLM cannot enforce these because it does not own the wall clock or network sockets. When passing budgets to sub-agents, pass the AbortSignal and the calculated timeout. Crucially, retries must earn their place: only retry transient errors if the backoff plus the next attempt fits inside the remaining time. For writes, never blindly retry on timeout; use idempotency keys and reconcile the system of record to avoid duplicate charges or emails.
Graceful Degradation Over Silence
An expired deadline does not have to mean an empty screen. Design final states for Completed, Degraded, Async Handoff, and Cancelled. A degraded response might offer three verified facts while omitting an optional comparison that would have exceeded the budget. This is superior to silently running long after the caller has left. For queued work, reject interactive tasks that expire before dequeue and create new durable jobs with fresh deadlines for background completion. Never let a stale web request accidentally spawn unbounded background work.
Key Takeaways
- Use absolute timestamps (
deadlineAt), not relative durations, for global workflow control. - Always reserve time for response serialization to prevent failures at the final millisecond.
- Retries must check remaining budget before waiting; never retry if the backoff exceeds the deadline.
- Propagate
AbortSignalto all SDK calls to ensure cancellation actually stops network activity. - Distinguish between interactive requests and background jobs; do not inherit browser deadlines for queued tasks.
The Bottom Line
Time belongs to the request, not the component. If your agent architecture treats every tool call as an island with its own timer, you are just subsidizing zombie processes. Enforce the deadline at the runtime boundary, or prepare to pay for answers that arrive after the user has already closed the tab.