Skip to content

3.1 Message History & Thread

Tujuan bab

Setelah bab ini kamu bisa:

  • Memasang storage provider dan menjelaskan kenapa memory tidak bisa jalan tanpanya
  • Mengaktifkan message history pada agent dengan Memory
  • Menjelaskan perbedaan thread dan resource, dan memilih nilai yang tepat untuk keduanya
  • Mengatur lastMessages dan memahami dampaknya pada biaya
  • Menghindari bug urutan pesan yang muncul saat aplikasi klien mengirim riwayat lengkap

Prasyarat

Memasang storage

Memory memerlukan tempat menyimpan. Untuk pengembangan lokal, libSQL berbasis file adalah pilihan paling mudah — tidak butuh server database terpisah, dan datanya bertahan antar restart.

bash
npm install @mastra/memory@latest @mastra/libsql@latest

Lalu pasang di instance Mastra:

ts
// src/mastra/index.ts
import { Mastra } from '@mastra/core'
import { LibSQLStore } from '@mastra/libsql'

export const mastra = new Mastra({
  storage: new LibSQLStore({
    id: 'mastra-storage',
    url: 'file:./mastra.db',
  }),
})

Dua catatan tentang potongan ini:

id wajib diisi. Dokumentasi menandai ini secara khusus. Tanpa id, konfigurasi storage-mu tidak lengkap.

url menentukan sifat penyimpanan. Nilai 'file:./mastra.db' menyimpan ke berkas dan bertahan antar restart. Nilai ':memory:' menyimpan di RAM dan hilang begitu proses berhenti — berguna untuk pengujian otomatis, tapi akan membuatmu bingung kalau tidak sengaja terpakai saat pengembangan.

Storage yang dipasang di instance Mastra berlaku untuk semua agent yang terdaftar. Ini salah satu manfaat konkret dari mendaftarkan agent yang disinggung di 0.2.

Mengaktifkan message history

ts
// src/mastra/agents/memory-agent.ts
import { Agent } from '@mastra/core/agent'
import { Memory } from '@mastra/memory'

export const memoryAgent = new Agent({
  id: 'memory-agent',
  name: 'Memory Agent',
  instructions: 'Kamu asisten yang membantu dan mengingat percakapan.',
  model: 'openai/gpt-5.6-sol',
  memory: new Memory({
    options: {
      lastMessages: 10,
    },
  }),
})

Itu saja. Dengan Memory terpasang, agent kini menerima sepuluh pesan terakhir dari percakapan sebagai konteks di setiap panggilan.

Perhatikan bahwa new Memory() di sini tidak menyebutkan storage — ia memakai storage dari instance Mastra. Kamu juga bisa memberi storage khusus per Memory bila perlu, dan itu ditunjukkan di 3.3.

Thread dan resource

Ini konsep yang harus benar sejak awal, karena salah memilih akan menghasilkan bug yang membingungkan dan berpotensi membocorkan data antar pengguna.

Mastra mengatur percakapan dengan dua pengenal:

  • Thread — satu sesi percakapan, berisi urutan pesan
  • Resource — pemilik thread itu: pengguna, organisasi, proyek, atau entitas lain dalam domain aplikasimu
resource: "user-8842"  (satu pengguna)

   ├── thread: "chat-2026-09-01"   → 24 pesan
   ├── thread: "chat-2026-09-04"   → 8 pesan
   └── thread: "chat-2026-09-06"   → 3 pesan  ← sedang berlangsung

Analogi yang paling dekat: resource adalah akunmu di aplikasi chat, thread adalah masing-masing ruang percakapan di dalamnya.

Saat memanggil agent, keduanya diberikan lewat opsi memory:

ts
// run.mjs
import { mastra } from './src/mastra/index.ts'

const agent = mastra.getAgentById('memory-agent')

const memoryOptions = {
  resource: 'user-8842',
  thread: 'chat-2026-09-06',
}

const pertama = await agent.generate('Nama saya Sari dan saya alergi kacang.', {
  memory: memoryOptions,
})
console.log(pertama.text)

const kedua = await agent.generate('Rekomendasikan menu makan siang untuk saya.', {
  memory: memoryOptions,
})
console.log(kedua.text)

Panggilan kedua akan memperhitungkan alergi yang disebut di panggilan pertama, karena keduanya berada di thread yang sama.

Di Studio kamu tidak perlu mengaturnya

Studio membuat thread dan resource ID secara otomatis. Saat memanggil stream() atau generate() sendiri dari kode, kamu yang harus menyediakannya secara eksplisit.

Memilih nilai yang benar

PengenalIsi denganJangan isi dengan
resourceID pengguna dari sistem autentikasimuNilai tetap seperti 'user', atau nilai yang dikirim klien tanpa diverifikasi
threadID percakapan yang kamu buat dan simpanNilai acak baru di setiap permintaan

Dua kesalahan yang paling merugikan:

resource yang sama untuk semua pengguna. Ini menggabungkan ingatan semua orang menjadi satu. Selain kacau, ini kebocoran data — terutama setelah working memory aktif di bab berikutnya, karena preferensi satu pengguna akan terbawa ke percakapan pengguna lain.

thread baru di setiap permintaan. Agent tidak akan pernah mengingat apa pun, karena tiap pesan mendarat di percakapan yang berbeda. Gejalanya persis seperti memory tidak aktif sama sekali, sehingga sering disalahartikan sebagai konfigurasi yang gagal.

Ambil resource dari server, bukan dari klien

Nilai resource menentukan ingatan siapa yang dibaca. Kalau nilainya berasal dari data yang dikirim klien tanpa diverifikasi, siapa pun bisa membaca ingatan pengguna lain hanya dengan menggantinya.

Ambil dari sesi terautentikasi di sisi server. Pola pengambilannya lewat RequestContext dibahas di 9.2 dan 9.3.

lastMessages dan biayanya

lastMessages: 10 berarti sepuluh pesan terakhir ikut dikirim di setiap panggilan model. Angka ini punya konsekuensi langsung yang perlu kamu sadari:

lastMessages: 10   →  ~10 pesan × setiap panggilan model × setiap putaran loop
lastMessages: 50   →  lima kali lipat dari itu

Ingat dari 2.3 bahwa satu pertanyaan yang melibatkan tool memicu beberapa panggilan model. Riwayat ikut serta di semua panggilan itu.

Panduan praktis:

Jenis aplikasiTitik awal yang wajar
Tanya-jawab pendek5–10
Asisten percakapan10–20
Sesi kerja panjang20–40, ditambah observational memory

Menaikkan angka bukan satu-satunya jalan untuk ingatan yang lebih panjang, dan biasanya bukan yang terbaik. Untuk mengingat hal dari jauh di belakang, ada semantic recall; untuk percakapan yang sangat panjang, ada observational memory. Keduanya menyelesaikan masalah itu tanpa membengkakkan setiap panggilan.

Jebakan saat memakai memory dari aplikasi klien

Ini peringatan yang ditulis eksplisit di dokumentasi, dan layak diperhatikan sebelum kamu menyambungkan frontend.

Kirim hanya pesan baru dari klien, bukan seluruh riwayat percakapan.

Alasannya dua. Pertama, redundan — Mastra sudah memuat riwayat dari storage, jadi mengirimnya lagi hanya menggandakan data. Kedua, dan ini yang lebih berbahaya, hal itu bisa menyebabkan bug urutan pesan saat timestamp dari sisi klien berbenturan dengan timestamp yang tersimpan.

❌ Klien mengirim:                 ✅ Klien mengirim:
[pesan1, pesan2, ..., pesanBaru]   [pesanBaru]
+ threadId                          + threadId
                                    (Mastra memuat sisanya dari storage)

Kebiasaan mengirim seluruh riwayat datang dari pengalaman memakai API model secara langsung, di mana memang begitu caranya. Dengan memory, tanggung jawab itu sudah berpindah.

Bagaimana potongannya tersusun

Kesalahan umum

Gejala: Agent tidak mengingat apa pun, padahal Memory sudah dipasang dan storage sudah dikonfigurasi. Penyebab: Biasanya salah satu dari dua. thread diisi nilai baru di setiap permintaan — misalnya hasil crypto.randomUUID() yang dipanggil tiap kali — sehingga tiap pesan mendarat di percakapan berbeda. Atau opsi memory sama sekali tidak diteruskan ke generate()/stream(). Perbaikan: Simpan threadId di sisi aplikasimu dan pakai nilai yang sama selama percakapan berlangsung. Pastikan opsi { memory: { resource, thread } } benar-benar diteruskan di setiap pemanggilan.

Gejala: Pesan muncul dengan urutan yang kacau, atau agent seperti membaca percakapan dua kali. Penyebab: Aplikasi klien mengirim seluruh riwayat percakapan bersama pesan baru. Mastra memuat riwayat dari storage sekaligus menerima riwayat dari klien, dan timestamp keduanya bisa berbenturan. Perbaikan: Kirim hanya pesan baru dari klien. Biarkan Mastra yang menyusun riwayatnya.

Coba sendiri

Tantangan: Bangun asisten catatan harian bernama jurnal-agent yang mengingat isi percakapan dalam satu sesi, dan buktikan bahwa pemisahan thread maupun resource benar-benar bekerja.

Ketentuan:

  1. Pasang LibSQLStore dengan url: 'file:./mastra.db' di instance Mastra
  2. Aktifkan Memory dengan lastMessages: 8
  3. Tulis skrip yang menjalankan empat skenario dan mencetak hasilnya:
    • A — resource user-a, thread t1: sebut sebuah fakta, lalu tanyakan kembali di pesan berikutnya
    • B — resource user-a, thread t2: tanyakan fakta yang sama
    • C — resource user-b, thread t1: tanyakan fakta yang sama
    • D — jalankan ulang skenario A setelah proses dimatikan dan dinyalakan lagi
  4. Ubah url menjadi ':memory:', ulangi skenario D, dan bandingkan
  5. Kembalikan ke 'file:./mastra.db'

Checklist penerimaan:

  • [ ] Skenario A: agent mengingat faktanya
  • [ ] Skenario B: agent tidak mengingatnya — thread berbeda berarti percakapan berbeda
  • [ ] Skenario C: agent tidak mengingatnya
  • [ ] Skenario D dengan penyimpanan file: agent tetap mengingat setelah restart
  • [ ] Skenario D dengan ':memory:': agent lupa setelah restart
  • [ ] Kamu bisa menjelaskan perbedaan peran thread dan resource berdasarkan hasil B dan C

Petunjuk: Skenario B dan C memberi hasil yang sama pada bab ini, dan itu memang seharusnya — message history terikat pada thread. Perbedaan antara keduanya baru terlihat di bab berikutnya, saat working memory yang berlingkup resource mulai bekerja. Simpan skripmu; kamu akan menjalankannya lagi.

Ikhtisar

  • Memory memerlukan storage provider. Untuk lokal, LibSQLStore dengan url: 'file:./mastra.db' sudah cukup — dan id wajib diisi.
  • ':memory:' menyimpan di RAM dan hilang saat proses berhenti; pakai hanya untuk pengujian.
  • Message history diaktifkan dengan memberi memory: new Memory({ options }) pada agent.
  • Thread adalah satu sesi percakapan; resource adalah pemiliknya. Keduanya diberikan lewat opsi { memory: { resource, thread } } saat memanggil agent — Studio mengisinya otomatis.
  • resource harus berasal dari sesi terautentikasi di server, bukan dari nilai yang dikirim klien.
  • lastMessages ikut dikirim di setiap panggilan model, di setiap putaran loop. Menaikkannya bukan cara terbaik untuk ingatan jangka panjang.
  • Dari aplikasi klien, kirim hanya pesan baru. Mengirim seluruh riwayat redundan dan bisa menyebabkan bug urutan pesan.

Lanjut ke mana

Agent-mu kini mengingat percakapan yang sedang berjalan. Tapi ada hal-hal yang harus diingat lebih lama dari satu percakapan — nama, preferensi, tujuan jangka panjang. Itu tugas jenis ingatan berikutnya: 3.2 Working Memory.

Materi belajar mandiri. Bukan dokumentasi resmi Mastra.