Advanced

Conversation memory

A chatbot that forgets is useless. Learn to keep the full conversation history, append each new message, and send the whole thread so the model responds like it remembers.

What you will see

Messages in history: 4 system: You are a helpful assistant. user: My name is Ada. assistant: Nice to meet you, Ada. user: What is my name?

About 2 min of reading

Quick check

Before this new lesson, one small question about the lesson you just finished. Recall it, do not look it up.

Try It

A chatbot that forgets is useless. State does not live in the model, so the app owns memory: it keeps a message array, appends each exchange, and sends the whole thread back to the model every single call.

1

I keep every exchange in a message log, each entry tagged with a role and content, and print the full list so the conversation is visible.

history = [] def record(role, content): history.append({"role": role, "content": content}) record("user", "My name is Ada.") record("assistant", "Nice to meet you, Ada.") record("user", "What is my name?") print("Conversation memory") print("Messages in history: %d" % len(history)) for m in history: print("%s: %s" % (m["role"], m["content"]))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
Conversation memory Messages in history: 3 user: My name is Ada. assistant: Nice to meet you, Ada. user: What is my name?
The model never stores anything between calls. If you forget to send the whole array, it will answer as if this is the first message.
2

I build the request by putting a system message in front and spreading the entire history into the messages list, then print the complete thread.

history = [] def record(role, content): history.append({"role": role, "content": content}) record("user", "My name is Ada.") record("assistant", "Nice to meet you, Ada.") record("user", "What is my name?") system = {"role": "system", "content": "You are a helpful assistant."} thread = [system, *history] print("Messages in history: %d" % len(thread)) for m in thread: print("%s: %s" % (m["role"], m["content"]))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
Messages in history: 4 system: You are a helpful assistant. user: My name is Ada. assistant: Nice to meet you, Ada. user: What is my name?
Spreading ...history injects every past message, so the model reasons over the whole thread. You must send it all again on the next call.

Data Flow

The app keeps a running message array; each request sends it all to the model, which reasons over the full thread and replies.
1 User sends a new message
↓
2 App appends it to the history array
↓
3 The full array is serialized to JSON
↓
4 The model reads every message
↓
5 The model produces a reply
↓
6 The reply is stored and shown
Why this works
Why state lives on the server

You cannot store the conversation inside the model. Each request is fresh and isolated.

So the app owns the memory:

  • The server keeps an array of messages per user.
  • Each request sends them all back to the model.
  • The reply is appended, and the cycle repeats.

This is why chatbots need a backend. A browser alone cannot hold the conversation between requests. The array is the whole state of the chat.

Examples

Building a message log

Keep every exchange in an array. Each message has a role and content:

const history = [];

function record(role, content) {
  history.push({ role, content });
}

record('user', 'My name is Ada.');
record('assistant', 'Nice to meet you, Ada.');
record('user', 'What is my name?');

Now history holds the entire conversation. When you send it to the model, the model sees everything and can answer correctly. Memory is just this one array.

Sending the thread

Send the full history plus the new message on every call:

const response = await fetch(API_URL, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    model: 'gpt-4o-mini',
    messages: [
      { role: 'system', content: 'You are a helpful assistant.' },
      ...history
    ]
  })
});

Spreading ...history injects every past message. The model never actually stores anything, it only sees what you send. So you must send the whole thread each time.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← A simple chat interface
Previous Lesson
A simple chat interface
Next Lesson
Streaming responses
Streaming responses →