Skip to learning content
Learning StudioCourses and practice
Experiences

React · Messages and reducers

Conversation State

A chat interface is a state machine for conversations, messages, generation attempts, and transport events. It's more than a text box that keeps appending strings to an array.

Evidence & limits
What the further reading establishes
Reducers put related state changes in one place when lots of event handlers touch the same data.
What this lab runs
A fixed 18-action trace follows three generation attempts: one completes, one is cancelled and rejects a late delta, and one starts after an edit and regeneration.
What it does not prove
This lesson handles state on one device. It doesn't sync edits between people or devices.

Dataset

Conversation Event Log

Source
Course-authored synthetic actions
License
Not separately licensed
Size
18 reducer actions · 3 generation attempts

Further reading

Lesson progressRestoring progress…

  1. CodeRestoring
  2. ExperimentRestoring
  3. CheckRestoring

Summary

Keep state normalized. A conversation keeps messageIds in order, while messagesById stores each message once. Rendering follows the id list. Streaming updates target a message by id instead of assuming the last item in an array is the active one.

Use three different ids. messageId names the long-lived UI record, attemptId names one try at generation, and requestId names one transport run. A regenerated assistant message can stay in the same place in the conversation while getting a new attempt and request.

Don't mutate old state. A delta action returns a new messages collection and a new version of the target message. It keeps every other message's identity unchanged and ignores events aimed at missing or non-streaming targets. That lets React see exactly what changed.

One delta through normalized stateThis update keeps the conversation in order while treating message, attempt, and request ids as three separate things.
conversation · c-17messageIds: ["m-u1", "m-a1"]messagesById · m-u1user · complete · "Explain masking."messagesById · m-a1assistant · streaming · "A causal"
Messagem-a1stable UI recordAttempta-17.2one generation tryRequestr-17.2one transport run
Action{ type: "TOKEN_DELTA", messageId: "m-a1", requestId: "r-17.2", delta: " mask" }Guardrequest active ∧ message streaming → apply
New objectsnext !== state · next.m-a1 !== state.m-a1Same objectnext.m-u1 === state.m-u1Available controlscanStop: true · canRegenerate: false

Calculate control state. canStop is true only while the active request is streaming. canRegenerate is true only after an assistant attempt reaches a final state. Calculate both from the normalized records so saved booleans can't get out of sync.

Knowledge check

What should the reducer do when a delta's attemptId doesn't match the target message's active attempt?

Implementation

product/chat-reducer.py
0 of 2 exercises verifiedOpen coding workspace →

Create the exact message record you can serialize, including the active attempt and transport ids for assistant output.

Signature
def create_message(options):
Inputs
options record with id, role, and optional content/status/attemptId/requestId
Returns
serializable message dict with the seven canonical fields
Rule
copy stable ids; default content to empty, status to complete, missing request ids to None, and createdAt to 0
Example
assistant + attempt a1 + request r1 → a streaming record carrying both ids
Message record progressive practice rounds
Restoring saved code…
Reference solution

Approach Create the exact message record you can serialize, including the active attempt and transport ids for assistant output.

def create_message(options):    return {        "id": options["id"],        "role": options["role"],        "content": options.get("content", ""),        "status": options.get("status", "complete"),        "attemptId": options.get("attemptId"),        "requestId": options.get("requestId"),        "createdAt": 0,    }

Build message creation and token-delta updates without mutation in Python, then replay the full conversation event log.

Saved results

Results created after your saved code passes its checks

The replay is course data. The validation result is tied to the code you saved and checked.

Loading…