Skip to content

Sequences

When the LLM response contains a list of items rather than a single object, use the Sequence wrapper. It saves you from creating a dedicated class with a single array property just to hold a list.

Basic Usage

Pass Sequence::of(ClassName::class) as the response model to extract a typed collection.

use Cognesy\Instructor\StructuredOutput;
use Cognesy\Instructor\Extras\Sequence\Sequence;

class Person {
    public string $name;
    public int $age;
}

$text = <<<TEXT
    Jason is 25 years old. Jane is 18 yo. John is 30 years old
    and Anna is 2 years younger than him.
TEXT;

$list = (new StructuredOutput)->with(
    messages: $text,
    responseModel: Sequence::of(Person::class),
)->get();

The returned $list is a Sequence instance containing fully validated Person objects.

Working with Sequences

Sequence implements ArrayAccess and IteratorAggregate, so you can use it like an array. It also provides convenience methods for common operations.

$list->count();       // Number of extracted items
$list->first();       // First item
$list->last();        // Last item
$list->get(1);        // Item at index 1
$list->all();         // All items as a plain array
$list->toArray();     // Alias for all()

// Iterate directly
foreach ($list as $person) {
    echo $person->name;
}

// Array access
$person = $list[0];

Streaming Sequences

One of the most powerful features of sequences is streaming completed items. While partials() yields the entire object on every property change, sequence() yields only when a new item in the list is fully populated.

$stream = (new StructuredOutput)
    ->with(
        messages: $text,
        responseModel: Sequence::of(Person::class),
    )
    ->stream();

foreach ($stream->sequence() as $person) {
    // Each yield is an individual completed item
    echo "Extracted: {$person->name}\n";
}

// Get the final, fully validated sequence
$people = $stream->finalValue();

This is ideal for progressive UI updates -- you can render each person in a list as soon as the LLM finishes generating their data, without waiting for the entire response.

Keep in mind that items yielded during streaming are deserialized but not yet validated. Only the final sequence returned by finalValue() is fully validated.

Named Sequences

You can provide a name and description to give the LLM more context about what the collection represents.

$list = (new StructuredOutput)->with(
    messages: $transcript,
    responseModel: Sequence::of(
        class: ActionItem::class,
        name: 'meetingActionItems',
        description: 'Action items extracted from a meeting transcript',
    ),
)->get();

Combining with Output Formats

You can combine sequences with output formats. For example, to get the sequence data as a plain array of arrays:

$data = (new StructuredOutput)
    ->withResponseModel(Sequence::of(Person::class))
    ->intoArray()
    ->with(messages: $text)
    ->get();

// Result: ['list' => [['name' => 'Jason', 'age' => 25], ...]]