One last variation. Let's show how to make a three-oscillator algebra. The generators are
gens = Join[a /@ Range[3], aD /@ Range[3]]
(* {a[1], a[2], a[3], aD[1], aD[2], aD[3]} *)
We need the relations $\hat{a}_n\hat{a}_m^{\dagger} - \hat{a}_m^{\dagger}\hat{a}_n =\delta_{nm}$ and $\hat{a}_n\hat{a}_m - \hat{a}_m\hat{a}_n =0$, and we implement them as
rels = Join[
Table[{a[n] ** aD[m] - aD[m] ** a[n] - KroneckerDelta[m, n]}, {n, 1, 3}, {m, 1, 3}],
Table[{a[n] ** a[m] - a[m] ** a[n]}, {n, 1, 3}, {m, n + 1, 3}]
] // Flatten;
We can generate a Groebner basis from this as
gbrel = NonCommutativeGroebnerBasis[rels, gens];
but in this case, the relations form a basis already. Then, finally, define
toNormalOrder[expr_] := NonCommutativePolynomialReduce[expr, rels, gens(*, alg*)]
as usual (with alg in there in case you need to add some scalars, as above).
Final note to answer Question 3: This functionality cannot be used for an infinite number of generators and/or relations, because it relies on the explicit computation of a Groebner basis, and then the explicit computation of the reduction of the polynomial relative to this basis. This can only be done, of course, if the numbers of generators and relations are both finite.