Skip to main content
Wrap any Vercel AI SDK model with Tuteliq so every turn is screened in both directions, without touching the code that calls the model. This guide uses wrapLanguageModel, so moderation lives on the model itself. No route can forget to moderate, because there is nothing to remember.
The middleware below is verified against ai v6. If you are on an older major, check the middleware type name and the stream part shape before copying.

Two pipelines, two detectors

A tutoring or companion product usually has two distinct conversation types, and they need different detection. Conflating them is the most common mistake. The first is a per-turn gate. The second is a trajectory problem: no single message looks wrong, the arc does. Only the second needs continuation tokens. This page covers the first, then shows the second.

Design decisions

Outbound streaming is the hard part. You cannot moderate a reply before it starts rendering. Three approaches:

Buffer then emit

Collect the whole reply, moderate once, emit. Costs time-to-first-token. The right default for a minors product.

Sentence gated

Release one moderated sentence at a time. Keeps progressive rendering, one call per sentence.

Optimistic

Stream first, retract if flagged. Best latency, but the child has already read it. Not suitable for minors.
Fail open or fail closed, decided per direction. If Tuteliq is unreachable:
  • Inbound (the child’s own message): fail open. A moderation outage must not lock a child out of their lesson.
  • Outbound (the model’s reply): fail closed. If you cannot verify what the model is about to say to a minor, do not say it.
Use verdict_only. Fast mode omits the per-message breakdown, which is the bulk of the response. Use the full response only when writing to a moderator queue. Distress is not a block. If a child says something that flags self_harm or distress_signals, blocking them is the wrong response. Let the turn through and surface the support resources Tuteliq returns.

Moderation helpers

lib/tuteliq/moderation.ts

The middleware

lib/tuteliq/middleware.ts
Non-text stream parts must always be forwarded. If you drop finish or text-end while blocking, the stream never closes and the request hangs.

Wiring it into a route

app/api/chat/route.ts

Human conversations: trajectory, not turns

For chat between a human adult and a child, per-turn scoring is not enough. Grooming is an arc. Pass the continuation token from each call into the next so escalation is tracked across the session, without Tuteliq storing the conversation.
lib/tuteliq/trajectory.ts
Three things that catch people out:
  • Send only new turns. The token carries the history. Resending the whole conversation double-counts tactics.
  • Tokens expire after about 24 hours. An expired or missing token is not an error; the call simply starts a fresh trajectory.
  • Set the child’s profile country so helplines resolve locally. It comes from the user profile, not the language: an Arabic-speaking child in Germany should get German resources.

Evidence capture

Tuteliq operates a content-out pipeline and does not retain the messages you send. If you may need a conversation as evidence for a report to NCMEC, the IWF or a regional hotline, your onFlag handler is where you capture it. Design that in from the first commit rather than discovering it during an incident. Tuteliq issues signed audit receipts proving what was analysed and what verdict was returned, which is the vendor-side artifact a regulator typically asks for. The content itself has to come from you.

Next steps

Continuation tokens

How trajectory state works across turns.

Fast mode

Cutting latency on the inline path.

Node SDK

Full SDK reference.

Incident logging

Routing what moderation surfaces.