Pathfinding AI stops to calculate path; needs constant movement

I made a pathfinding system. However, since computing path takes time, it is possible to see the AI stop every time it reaches the end of its waypoint to compute a new path before moving to a new target again. I tried making it compute path in advance (specifically, compute path at the 2nd waypoint and break the loop/run that new path at the 3rd waypoint), but all that does is make the AI stutters even more when I thought it is supposed to have already computed a new path.

The actual AI logic is in activateAI function, always found at the end of the script.

Original AI script that does not update path til it reached destination

local players = game:GetService('Players')
local runService = game:GetService('RunService')
local pathfindingService = game:GetService('PathfindingService')
local npc = script.Parent
local humanoid = npc.Humanoid
local rootPart = npc.HumanoidRootPart
rootPart:SetNetworkOwner(nil)

local function addPartsFromParentToTable(parent, toTable)
	for _, child in pairs(parent:GetChildren()) do
		if child:IsA('BasePart') then
			table.insert(toTable, child)
		end
	end
end

local function computePath(path, origin, destination)
	local success, err
	local retries = 0
	repeat
		retries += 1
		success, err = pcall(function()
			path:ComputeAsync(origin, destination)
		end)
	until success and path.Status == Enum.PathStatus.Success or retries == 3
end

local function createPath(origin, destination)
	local path = pathfindingService:CreatePath({
		AgentRadius = 3,
		AgentHeight = 6,
		AgentCanJump = false,
		Costs = {
			Snow = math.huge,
			Metal = math.huge,
		},
	})
	computePath(path, origin, destination)
	return path
end

local function moveToDestination(path)
	for _, waypoint in pairs(path:GetWaypoints()) do
		humanoid:MoveTo(waypoint.Position)
		humanoid.MoveToFinished:Wait()
	end
end

local function checkProximity(targetRoot)
	if (targetRoot.Position - rootPart.Position).Magnitude < 10 then
		local targetCharacter = targetRoot.Parent
		local excludeParts = {}

		addPartsFromParentToTable(targetCharacter, excludeParts)
		addPartsFromParentToTable(npc, excludeParts)

		local rayParams = RaycastParams.new()
		rayParams.FilterDescendantsInstances = excludeParts
		rayParams.FilterType = Enum.RaycastFilterType.Exclude

		local rayDirection = targetRoot.Position - rootPart.Position
		local result = workspace:Raycast(rootPart.Position, rayDirection, rayParams)
		if not result then
			targetRoot.Parent.Humanoid:TakeDamage(100)
			return true
		end
	end
end

local function findNearestPlayer()
	local nearestDistance, nearestPlayer
	for _, player in pairs(players:GetPlayers()) do
		if player.Character then
			local char = player.Character
			if char:FindFirstChild('HumanoidRootPart') and char.Humanoid.Health > 0 then
				local charPos = char.HumanoidRootPart.Position
				if not nearestDistance or (charPos - rootPart.Position).Magnitude < nearestDistance then
					nearestDistance = (charPos - rootPart.Position).Magnitude
					nearestPlayer = player
				end
			end
		end
	end
	return nearestPlayer
end

for _, bodyPart in pairs(npc:GetChildren()) do
	if bodyPart:IsA('BasePart') then
		bodyPart.Touched:Connect(function(hit)
			if hit.Parent:FindFirstChild('Humanoid') then
				hit.Parent.Humanoid:TakeDamage(100)
			end
		end)
	end
end

local targetKilled
local function activateAI()
	while true do
		task.wait()
		local player = findNearestPlayer()
		if player then
			local character = player.Character
			local playerRoot = character.HumanoidRootPart

			local origin = rootPart.Position
			local destination = playerRoot.Position + playerRoot.Velocity
			local path = createPath(origin, destination)

			local heartbeatConnection
			heartbeatConnection = runService.Heartbeat:Connect(function()
				local result = checkProximity(playerRoot)
				if result then
					humanoid:MoveTo(rootPart.Position)
					targetKilled = true
					heartbeatConnection:Disconnect()
				end
			end)

			for _, waypoint in pairs(path:GetWaypoints()) do
				if targetKilled then
					targetKilled = nil
					break
				end
				humanoid:MoveTo(waypoint.Position)
				humanoid.MoveToFinished:Wait()
			end
			heartbeatConnection:Disconnect()
		end
	end
end

activateAI()

Here is the version that I tried to make the AI update its waypoints constantly

local players = game:GetService('Players')
local runService = game:GetService('RunService')
local pathfindingService = game:GetService('PathfindingService')
local npc = script.Parent
local humanoid = npc.Humanoid
local rootPart = npc.HumanoidRootPart
rootPart:SetNetworkOwner(nil)

local function addPartFromParentToTable(parent, toTable)
	for _, child in pairs(parent:GetChildren()) do
		if child:IsA('BasePart') then
			table.insert(toTable, child)
		end
	end
end

local function computeNewPath(path, origin, destination)
	local success, err
	local count = 0
	repeat
		count += 1
		success, err = pcall(function()
			path:ComputeAsync(origin, destination)
		end)
	until success and path.Status == Enum.PathStatus.Success or count == 3
end

local function createNewPath(origin, destination)
	local path = pathfindingService:CreatePath({
		AgentRadius = 3,
		AgentHeight = 6,
		AgentCanJump = false,
		Costs = {
			Snow = math.huge,
			Metal = math.huge,
		},
	})
	computeNewPath(path, origin, destination)
	return path
end

local function moveTowardsDestination(path)
	for _, waypoint in path:GetWaypoints() do
		humanoid:MoveTo(waypoint.Position)
		humanoid.MoveToFinished:Wait()
	end
end

local function checkProximity(targetRoot)
	if (targetRoot.Position - rootPart.Position).Magnitude < 10 then
		local targetCharacter = targetRoot.Parent

		local bodiesExempt = {}

		addPartFromParentToTable(targetCharacter, bodiesExempt)
		addPartFromParentToTable(npc, bodiesExempt)

		local rayParams = RaycastParams.new()
		rayParams.FilterDescendantsInstances = bodiesExempt
		rayParams.FilterType = Enum.RaycastFilterType.Exclude

		local rayDirection = targetRoot.Position - rootPart.Position

		local result = workspace:Raycast(rootPart.Position, rayDirection, rayParams)
		if not result then
			targetRoot.Parent.Humanoid:TakeDamage(100)
			return true
		end
	end
end

local function findNearestPlayer()
	local nearestDistance, nearestTarget
	for _, player in pairs(players:GetPlayers()) do
		if player.Character then
			local character = player.Character
			if character:FindFirstChild('HumanoidRootPart') and character.Humanoid.Health ~= 0 then
				local charPos = character.HumanoidRootPart.Position
				if nearestDistance == nil or (charPos - rootPart.Position).Magnitude < nearestDistance then
					nearestDistance = (charPos - rootPart.Position).Magnitude
					nearestTarget = player
				end
			end
		end
	end
	return nearestTarget
end

for _, bodyPart in pairs(npc:GetChildren()) do
	if bodyPart:IsA('BasePart') then
		bodyPart.Touched:Connect(function(hit)
			if hit.Parent:FindFirstChild('Humanoid') then
				hit.Parent.Humanoid:TakeDamage(100)
			end
		end)
	end
end

local targetKilled
local newWaypoints
local autoPlayer
local function activateAI()
	while true do
		task.wait()
		local player = findNearestPlayer()
		if newWaypoints and autoPlayer == player then
			print('Planned')
			local character = player.Character
			local playerRoot = character.HumanoidRootPart

			local runInstance
			runInstance = runService.Heartbeat:Connect(function()
				local result = checkProximity(playerRoot)
				if result then
					humanoid:MoveTo(rootPart.Position)
					targetKilled = true
					runInstance:Disconnect()
				end
			end)

			local allWaypoints = newWaypoints:GetWaypoints()
			newWaypoints, autoPlayer = nil, nil
			for i, waypoint in pairs(allWaypoints) do
				if targetKilled or player ~= findNearestPlayer() then
					targetKilled = nil
					break
				elseif i == 2 then
					if player == findNearestPlayer() then
						autoPlayer = player
						task.spawn(function() newWaypoints = createNewPath(allWaypoints[3], playerRoot.Position + playerRoot.Velocity) end)
					end
				elseif i == 3 and newWaypoints then
					break
				end
				humanoid:MoveTo(waypoint.Position)
				humanoid.MoveToFinished:Wait()
			end
			runInstance:Disconnect()
		elseif player then
			print('Created new')
			local character = player.Character
			local playerRoot = character.HumanoidRootPart

			local origin = rootPart.Position
			local destination = playerRoot.Position + playerRoot.Velocity
			local newPath = createNewPath(origin, destination)

			local runInstance
			runInstance = runService.Heartbeat:Connect(function()
				local result = checkProximity(playerRoot)
				if result then
					humanoid:MoveTo(rootPart.Position)
					targetKilled = true
					runInstance:Disconnect()
				end
			end)

			local allWaypoints = newPath:GetWaypoints()
			newWaypoints, autoPlayer = nil, nil
			for i, waypoint in pairs(allWaypoints) do
				if targetKilled or player ~= findNearestPlayer() then
					targetKilled = nil
					break
				elseif i == 2 then
					if player == findNearestPlayer() then
						autoPlayer = player
						task.spawn(function() newWaypoints = createNewPath(allWaypoints[3], playerRoot.Position + playerRoot.Velocity) end)
					end
				elseif i == 3 and newWaypoints then
					break
				end
				humanoid:MoveTo(waypoint.Position)
				humanoid.MoveToFinished:Wait()
			end
			runInstance:Disconnect()
		end
	end
end

activateAI()