# Sequential / Stateful Responses

Use `sequenceIndex` in fixture match criteria to return different responses for the same query on each successive call. This enables testing multi-step agent conversations and retry logic.

## How It Works

- The router tracks how many times each unique match pattern has been hit
- `sequenceIndex: 0` matches the first request, `sequenceIndex: 1` the second, etc.
- Different match patterns have independent counters
- If a sequenceIndex fixture does not match the current count, routing falls through to the next fixture
- Fixtures without `sequenceIndex` match any occurrence (backward compatible)
- Counters reset on `mock.reset()`

## Unit Test: 2-Step Sequence

sequence.test.ts ts

    const mock = new LLMock();
    await mock.start();

    mock.on({ userMessage: "plan", sequenceIndex: 0 }, { content: "Step 1: planning..." });
    mock.on({ userMessage: "plan", sequenceIndex: 1 }, { content: "Step 2: done!" });

    // First request → first response
    const res1 = await fetch(`${mock.url}/v1/chat/completions`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        model: "gpt-4",
        messages: [{ role: "user", content: "plan" }],
        stream: false,
      }),
    });
    const body1 = await res1.json();
    expect(body1.choices[0].message.content).toBe("Step 1: planning...");

    // Second request → second response
    const res2 = await fetch(`${mock.url}/v1/chat/completions`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        model: "gpt-4",
        messages: [{ role: "user", content: "plan" }],
        stream: false,
      }),
    });
    const body2 = await res2.json();
    expect(body2.choices[0].message.content).toBe("Step 2: done!");

## Fallback After Sequence Exhaustion

sequence-fallback.test.ts ts

    // First call matches sequenceIndex 0, subsequent calls fall through to fallback
    mock.on({ userMessage: "once", sequenceIndex: 0 }, { content: "only-first-time" });
    mock.on({ userMessage: "once" }, { content: "fallback" });

    // Request 1 → "only-first-time" (sequenceIndex 0 matches)
    // Request 2 → "fallback" (sequenceIndex 0 won't match, falls through)

## JSON Fixture

fixtures/sequence.json json

    {
      "fixtures": [
        {
          "match": { "userMessage": "plan", "sequenceIndex": 0 },
          "response": { "content": "Step 1: planning..." }
        },
        {
          "match": { "userMessage": "plan", "sequenceIndex": 1 },
          "response": { "content": "Step 2: done!" }
        }
      ]
    }

Sequence counters are per-fixture-match, not global. If you have fixtures matching "alpha" and "beta", their counters are tracked independently.

Need stateless matching? `sequenceIndex` uses a server-side counter that resets on `mock.reset()` and can drift when multiple clients share an instance. If your use case is “different response based on conversation depth” (not “different response for the Nth identical request”), prefer the stateless `turnIndex` or `hasToolResult` fields instead. See Multi-Turn Conversations.