Voice AI

Build an Adaptive SMS Quiz Agent with Telnyx Edge Compute

SMS is a good channel for small learning workflows because the interaction is simple: send a prompt, wait for a reply, continue from the last turn.

This Telnyx code example builds that pattern as an adaptive quiz. A user texts start, receives a multiple-choice question, answers with A, B, or C, and gets the next question by SMS. The agent remembers the score and adjusts difficulty as the quiz continues.

The code example is here:

https://github.com/team-telnyx/telnyx-code-examples/tree/main/multi-turn-sms-quiz-agent

You need a Telnyx API key, a Telnyx number that can send and receive SMS, and the code sample.

What This Example Builds

The sample is a Node.js and TypeScript app running on Telnyx Edge Compute.

It creates a five-question SMS quiz about Edge Compute, the Agent SDK, StatefulActors, durable state, SQL storage, Telnyx Messaging, and Telnyx Inference.

The user experience is intentionally direct:

User texts: start
Agent replies: Q1/5 ...
User texts: A
Agent replies: correct or incorrect feedback, then Q2/5 ...

Each question has three choices:

A) ...
B) ...
C) ...

The questions are written with short, concrete examples. For example, durable state is explained like a storage unit: you can leave something there, come back later, and it is still available.

Architecture

user sends sms
  -> telnyx messaging webhook
  -> edge function receives event
  -> one QuizAgent actor is selected for that sender
  -> actor saves state and queues work
  -> telnyx inference generates or grades the quiz turn
  -> telnyx messaging sends the next sms

The important part is the actor boundary. The code uses one QuizAgent StatefulActor per sender phone number.

That means one person can be on question two while another person is on question five. Their scores, current questions, and difficulty levels do not collide.

Why StatefulActors Fit This Problem

A quiz is a multi-turn workflow. The agent has to remember:

  • whether the quiz has started
  • the current question
  • the correct answer
  • the user's score
  • the current difficulty
  • how many questions have been asked

The sample stores that with this.setState().

That is what makes the SMS flow feel continuous. The user does not need to send all context again. They can reply with B, and the actor already knows which question B belongs to.

Adaptive Difficulty

The quiz has three difficulty levels:

easy -> medium -> hard

When the user answers correctly, the quiz can move up. When the user misses, it can move down or stay easy.

The code keeps that rule predictable:

correct answer: increase difficulty
incorrect answer: decrease difficulty

Telnyx Inference generates the next question and grades the answer, but the code owns the final difficulty rule. That makes the behavior easier to understand and easier to test.

The Core Code

The actor starts with an idle state:

protected override initialState(): QuizState {
  return {
    phase: "idle",
    score: 0,
    difficulty: "easy",
    turn: 0,
    currentQuestion: "",
    currentAnswer: "",
    from: "",
    to: "",
    startedAt: 0,
    updatedAt: 0,
  };
}

When a message arrives, the route picks the actor by sender phone number:

await env.QUIZ.idFromName(actorNameForPhone(from)).receive({
  text,
  from,
  to,
  eventId,
});

The actor saves the message, deduplicates the webhook event, and queues process() so the SMS webhook can return quickly.

When it is time to send a question, the actor calls Telnyx Inference:

await this.env.TELNYX.ai.openai.chat.createCompletion({
  model,
  messages,
});

When it is time to reply by SMS, the actor sends through the Telnyx binding:

await this.env.TELNYX.messages.send({
  from: telnyxNumber,
  to: userNumber,
  text,
});

Run The Example

Clone the repo:

git clone https://github.com/team-telnyx/telnyx-code-examples.git
cd telnyx-code-examples/multi-turn-sms-quiz-agent
npm install

Run the checks:

npm run typecheck
npm run types

Deploy:

npm run ship

Then point your Telnyx Messaging Profile webhook to the deployed function route and text start to your Telnyx number.

Why This Pattern Matters

The same pattern works beyond quizzes.

Any SMS workflow that needs memory across turns can use the same shape:

  • intake forms
  • onboarding flows
  • appointment questions
  • training checks
  • support triage
  • lightweight surveys

The key is that the sender gets a durable actor. Each incoming SMS becomes one step in a longer stateful conversation.

Resources

  • Code example: https://github.com/team-telnyx/telnyx-code-examples/tree/main/multi-turn-sms-quiz-agent

Ready to build with low-latency voice AI?

Join developers building the future of real-time conversations