Tampilan
7.1 Durable Agents
Tujuan bab
Setelah bab ini kamu bisa:
- Menjelaskan apa yang membuat sebuah agent "durable" dan masalah apa yang diselesaikannya
- Membungkus agent biasa dengan
createDurableAgent() - Menjelaskan peran PubSub dalam kemampuan menyambung ulang
- Memutuskan kapan durable agent berlebihan
- Menjelaskan konsep background tasks dan kapan dipakai
Prasyarat
- Bagian 4 selesai
- Storage terpasang
@mastra/coreversi 1.45.0 atau lebih baru
Masalah dengan koneksi yang putus
Bayangkan agent riset yang butuh empat menit untuk menyelesaikan tugasnya. Pengguna membukanya dari ponsel, lalu masuk terowongan. Koneksi putus.
Dengan Agent biasa dan stream(), apa yang terjadi? Stream mati, dan pekerjaannya hilang. Pengguna kembali dari terowongan, membuka aplikasi, dan harus mulai dari awal.
Sekarang skenario lain: server-mu di-deploy ulang di tengah agent bekerja. Hasil yang sama.
Durable agent menyelesaikan keduanya dengan menjalankan agentic loop di dalam sebuah workflow, dan mengalirkan peristiwanya lewat PubSub. Karena keadaan run dipersistensi, ia bertahan melewati restart proses; karena peristiwa mengalir lewat PubSub, klien bisa terputus dan menyambung lagi tanpa kehilangan potongan.
Membungkus agent
ts
// src/mastra/agents/researcher.ts
import { Agent } from '@mastra/core/agent'
import { createDurableAgent } from '@mastra/core/agent/durable'
const agent = new Agent({
id: 'researcher',
name: 'Researcher',
instructions: 'Kamu meneliti topik secara menyeluruh.',
model: 'openai/gpt-5.6-sol',
})
export const durableResearcher = createDurableAgent({ agent })Perhatikan polanya: kamu tidak membuat jenis agent yang berbeda. Kamu membuat Agent biasa seperti di Bagian 1, lalu membungkusnya.
Konsekuensi praktisnya bagus: agent yang sama bisa dipakai dalam dua bentuk — langsung untuk permintaan pendek, dan dibungkus untuk pekerjaan panjang.
Daftarkan dan jalankan:
ts
// src/mastra/index.ts
import { Mastra } from '@mastra/core'
import { durableResearcher } from './agents/researcher.ts'
export const mastra = new Mastra({
agents: { durableResearcher },
})ts
// run.mjs
import { durableResearcher } from './src/mastra/agents/researcher.ts'
const { output, runId, cleanup } = await durableResearcher.stream(
'Teliti perkembangan komputasi kuantum tahun 2025',
)
for await (const chunk of output.fullStream) {
// Proses tiap potongan saat tiba
}
await cleanup()Tiga nilai yang dikembalikan, dan ketiganya penting:
| Nilai | Kegunaan |
|---|---|
output | Stream-nya, dengan fullStream untuk peristiwa |
runId | Pengenal run — simpan ini untuk menyambung ulang |
cleanup | Melepas langganan PubSub dan membersihkan run dari registry |
runId di sini memainkan peran yang sama seperti pada workflow di 4.5: tanpa menyimpannya, kamu tidak bisa kembali ke run itu.
Kapan memakainya
Dokumentasi memberi empat situasi yang jelas:
- Klien bisa terputus dan menyambung di tengah stream — ponsel, jaringan buruk, panggilan yang lama
- Agentic loop bisa berumur lebih panjang dari satu permintaan HTTP — riset latar belakang, pemakaian tool bertingkat
- Kamu butuh API amati/sambung-ulang, di mana klien kedua mengambil alih stream yang dimulai klien pertama
- Kamu ingin eksekusi bertenaga Inngest, dengan memoisasi langkah, retry, dan pemantauan
Dan satu situasi di mana ia berlebihan, yang disebut dokumentasi secara eksplisit:
Untuk panggilan pendek yang tercakup dalam satu permintaan dan kliennya tetap tersambung,
Agentbiasa denganstream()ataugenerate()lebih sederhana.
Ini pola yang berulang di seluruh Bagian 7: kemampuan harness diadopsi saat masalahnya muncul, bukan sebagai default.
Kenapa PubSub
Bagian ini layak dipahami karena menjelaskan kenapa durable agent bisa melakukan apa yang tidak bisa dilakukan stream() biasa.
Agent biasa:
Agent ──stream langsung──▶ Klien
(kalau putus, hilang)
Durable agent:
Agent ──▶ PubSub ──▶ Klien A
│
└──────▶ Klien B (menyambung belakangan)Dengan stream() biasa, ada satu jalur langsung dari agent ke klien. Kalau jalur itu putus, tidak ada apa pun yang bisa disambung.
Dengan PubSub, agent menerbitkan peristiwa ke satu tempat perantara. Klien berlangganan ke tempat itu. Klien boleh pergi, kembali, bahkan digantikan klien lain — peristiwanya tetap mengalir ke perantara.
Ini juga yang memungkinkan skenario "klien kedua mengambil alih stream yang dimulai klien pertama" — misalnya pengguna memulai dari ponsel, lalu melanjutkan memantau dari laptop.
Background tasks
Kemampuan harness kedua yang layak dikenal sekarang: menjalankan tool, workflow, atau subagent yang lambat tanpa memblokir percakapan.
Masalahnya: sebuah tool yang butuh tiga menit membuat agent menggantung selama tiga menit. Pengguna menatap layar.
Dengan background tasks, pekerjaan itu berjalan asinkron dan hasilnya dikembalikan ke agent saat selesai. Percakapan bisa berlanjut sementara itu.
Kamu sudah melihat pintu masuknya di 2.2: properti background pada createTool() adalah konfigurasi background task untuk tool tersebut.
Ada satu detail yang berkaitan dengan streaming, disebut di dokumentasi 1.3: untuk agent yang mengirim background task, pakai stream() dengan opsi untilIdle — misalnya untilIdle: true — supaya stream tetap terbuka sampai task itu selesai dan agent sempat menanggapi hasilnya. Opsi ini memerlukan memory pada agent.
Tanpa itu, stream bisa berakhir sebelum hasil background task tiba, dan agent tidak pernah sempat menanggapinya.
Kesalahan umum
Gejala: Membungkus semua agent dengan createDurableAgent() dan mendapati sistem jadi lebih rumit tanpa manfaat yang terasa. Penyebab: Durable agent membawa serta workflow, PubSub, dan persistensi keadaan run. Untuk permintaan pendek di mana klien tetap tersambung, semua itu adalah biaya tanpa hasil. Perbaikan: Pakai Agent biasa sebagai default. Bungkus hanya agent yang pekerjaannya memang berpotensi melampaui satu permintaan.
Gejala: Stream berakhir sebelum hasil background task tiba, sehingga agent tidak pernah menanggapinya. Penyebab: stream() dipanggil tanpa opsi untilIdle, atau agent tidak punya memory yang dibutuhkan opsi itu. Perbaikan: Pakai untilIdle: true dan pastikan agent punya memory terkonfigurasi.
Coba sendiri
Tantangan: Bangun riset-agent yang melakukan pekerjaan cukup panjang, lalu buktikan bahwa versi durable-nya bertahan terhadap gangguan yang mematikan versi biasa.
Ketentuan:
- Buat
Agentbiasa yang tugasnya butuh waktu — misalnya meneliti sebuah topik lewat beberapa pemanggilan tool berurutan. Tambahkan penundaan buatan di dalam tool agar durasinya bisa diprediksi - Buat dua jalur pemanggilan dari agent yang sama: satu memakai
agent.stream()biasa, satu memakaicreateDurableAgent() - Untuk jalur durable, cetak
runIdsegera setelah stream dimulai - Jalankan jalur biasa, lalu hentikan skrip di tengah dengan Ctrl+C. Catat apa yang terjadi
- Jalankan jalur durable, hentikan skrip di tengah dengan cara yang sama
- Tulis skrip kedua yang menyambung ke run durable itu memakai
runIdyang tercetak, dan amati apakah pekerjaannya berlanjut - Pastikan
cleanup()dipanggil di jalur yang normal selesai
Checklist penerimaan:
- [ ] Kedua jalur memakai objek
Agentyang sama — tidak ada duplikasi definisi agent - [ ] Jalur biasa kehilangan pekerjaannya saat dihentikan
- [ ] Jalur durable bisa disambung kembali lewat
runId - [ ] Kamu bisa menjelaskan peran PubSub dalam perbedaan itu
- [ ]
cleanup()dipanggil, dan kamu bisa menjelaskan apa yang terjadi kalau tidak - [ ] Kamu bisa menyebutkan satu agent di aplikasimu yang tidak layak dibuat durable, beserta alasannya
Petunjuk: Ketentuan 2 adalah bagian yang paling mengajarkan. Godaannya adalah menulis dua agent terpisah, padahal createDurableAgent({ agent }) justru dirancang untuk membungkus yang sudah ada. Kalau kamu mendapati diri menyalin definisi agent, berhenti — bungkus yang pertama.
Ikhtisar
- Durable agent membungkus
Agentbiasa sehingga agentic loop-nya berjalan di dalam workflow, dengan peristiwa mengalir lewat PubSub. - Akibatnya: run bertahan melewati restart proses, dan klien bisa terputus lalu menyambung tanpa kehilangan potongan.
stream()mengembalikanoutput,runId, dancleanup. SimpanrunId; panggilcleanup()saat selesai.- Dipakai saat: klien bisa terputus, loop berumur lebih panjang dari satu permintaan HTTP, butuh sambung-ulang, atau ingin eksekusi bertenaga Inngest.
- Berlebihan untuk panggilan pendek dengan klien yang tetap tersambung —
Agentbiasa lebih sederhana. - Background tasks menjalankan pekerjaan lambat tanpa memblokir. Untuk agent yang memakainya, pakai
stream()denganuntilIdle, yang memerlukan memory. - Fitur di bab ini bertanda Beta — pin versi dan baca catatan rilis.
Lanjut ke mana
Agent-mu kini bisa bertahan. Berikutnya: membuatnya bekerja tanpa diminta — mengejar tujuan sendiri, berjalan terjadwal, dan bereaksi terhadap peristiwa dari luar: 7.2 Goals, Schedules & Signals.