Returning tool errors as is_error results so the model can recover is a good call. One subtlety with the withTimeout wrapper is that a timeout rejects the promise but doesn't necessarily cancel the underlying work, so a slow write tool may still complete after the model has been told it failed and then retries it. Passing an AbortSignal into tools, and reporting 'outcome unknown' rather than a plain failure for non-idempotent tools, can avoid duplicate side effects. Idempotency keys on write tools would be a natural complement to the step budget.