Skip to content

2.1 Tool Pertama

Tujuan bab

Setelah bab ini kamu bisa:

  • Membuat tool dengan createTool() dan menjelaskan keempat properti wajibnya
  • Menulis fungsi execute dengan signature yang benar
  • Menyambungkan satu atau beberapa tool ke agent
  • Menjelaskan kenapa mendefinisikan tool sebagai objek biasa akan gagal tanpa pesan error
  • Membagikan satu tool ke beberapa agent

Prasyarat

  • Bagian 1 selesai
  • Paket @mastra/core dan zod terpasang

Bentuk dasar

ts
// src/mastra/tools/weather-tool.ts
import { createTool } from '@mastra/core/tools'
import { z } from 'zod'

export const weatherTool = createTool({
  id: 'get-weather',
  description: 'Ambil cuaca terkini untuk sebuah kota',
  inputSchema: z.object({
    location: z.string().describe('Nama kota'),
  }),
  outputSchema: z.object({
    location: z.string(),
    temperatureCelsius: z.number(),
    conditions: z.string(),
  }),
  execute: async ({ location }) => {
    return { location, temperatureCelsius: 21, conditions: 'cerah' }
  },
})

Empat properti yang membentuk sebuah tool:

PropertiPerannyaPembacanya
idPengenal unik toolRuntime Mastra
descriptionPenjelasan tool ini untuk apaModel, untuk memutuskan kapan memanggilnya
inputSchemaBentuk argumen yang diterimaModel (untuk menyusun panggilan) dan runtime (untuk memvalidasi)
outputSchemaBentuk hasil yang dikembalikanRuntime, dan menjadi kontrak bagi pemakai tool

Perhatikan kolom "pembacanya". Dua dari empat properti itu dibaca oleh model, bukan hanya oleh mesin. description adalah satu-satunya dasar model memutuskan apakah tool ini relevan untuk pertanyaan yang sedang dihadapi. Deskripsi yang malas menghasilkan tool yang tidak pernah dipanggil, atau dipanggil di saat yang salah — dan ini dibahas tuntas di 2.2.

Signature execute

Ini bagian yang paling sering salah, karena banyak contoh lama di internet memakai bentuk berbeda. Dokumentasi resmi menyatakannya tanpa ruang tafsir: execute punya tepat satu signature.

ts
execute: async (inputData, context) => { /* ... */ }
  • Parameter pertama adalah input yang sudah divalidasi terhadap inputSchema. Kamu bisa langsung memakainya, dan tipenya sudah terinfer dari schema.
  • Parameter kedua adalah konteks eksekusi, yang selalu disediakan runtime. Isinya antara lain requestContext, tracingContext, dan abortSignal.

Parameter kedua boleh dihilangkan kalau tidak dipakai — itu sebabnya contoh di atas hanya menulis async ({ location }) => ....

Bentuk lama yang sudah tidak berlaku

Kalau kamu menemukan contoh yang menulis execute: async ({ context }) => ... dan mengambil argumen dari context.location, itu pola lama. Dokumentasi resmi menyebutnya secara eksplisit: "If you've seen a different execute shape elsewhere, it's outdated."

Ini salah satu alasan kenapa menyalin kode Mastra dari hasil pencarian atau dari ingatan model bahasa berisiko — pola v0 masih tersebar luas.

Contoh dengan parameter kedua dipakai:

ts
// src/mastra/tools/profil-tool.ts
import { createTool } from '@mastra/core/tools'
import { z } from 'zod'

export const profilTool = createTool({
  id: 'get-profil',
  description: 'Ambil profil pengguna yang sedang login',
  inputSchema: z.object({}),
  outputSchema: z.object({
    userId: z.string(),
    nama: z.string(),
  }),
  execute: async (_input, { requestContext }) => {
    const userId = requestContext.get('userId') as string
    return { userId, nama: 'Budi' }
  },
})

Pola ini penting untuk keamanan: identitas pengguna diambil dari requestContext yang diisi server, bukan dari argumen yang dikirim model. Kalau userId masuk lewat inputSchema, model bisa mengarangnya — dan agent akan dengan senang hati mengambil data pengguna lain.

Menyambungkan ke agent

ts
// src/mastra/agents/weather-agent.ts
import { Agent } from '@mastra/core/agent'
import { weatherTool } from '../tools/weather-tool.ts'

export const weatherAgent = new Agent({
  id: 'weather-agent',
  name: 'Weather Agent',
  instructions: `
    Kamu asisten cuaca yang membantu.
    Pakai weatherTool untuk mengambil data cuaca terkini.`,
  model: 'openai/gpt-5.6-sol',
  tools: { weatherTool },
})

Dua hal yang layak diperhatikan.

Pertama, tools adalah objek, bukan array. Key-nya menjadi nama yang dikenal model.

Kedua, instruksinya menyebut nama tool secara eksplisit. Ini bukan formalitas. Menyebut "Pakai weatherTool untuk mengambil data cuaca terkini" di instruksi meningkatkan kemungkinan tool dipakai pada situasi yang tepat. Dokumentasi resmi menyebut bahwa keputusan agent didasarkan pada pesan pengguna, instruksi agent, serta deskripsi dan schema tool — jadi instruksi adalah salah satu dari tiga tuas yang kamu punya.

Beberapa tool sekaligus

ts
// src/mastra/agents/weather-agent.ts
import { Agent } from '@mastra/core/agent'
import { weatherTool } from '../tools/weather-tool.ts'
import { hazardsTool } from '../tools/hazards-tool.ts'

export const weatherAgent = new Agent({
  id: 'weather-agent',
  name: 'Weather Agent',
  instructions: `
    Kamu asisten cuaca yang membantu.
    Pakai weatherTool untuk mengambil data cuaca terkini.
    Pakai hazardsTool untuk memberi informasi potensi bahaya cuaca.`,
  model: 'openai/gpt-5.6-sol',
  tools: { weatherTool, hazardsTool },
})

Perhatikan polanya: satu baris instruksi per tool, menjelaskan kapan masing-masing dipakai. Saat jumlah tool bertambah, kebiasaan ini yang menjaga agent tetap memilih dengan tepat.

Berbagi tool antar agent

Kalau satu tool dipakai beberapa agent, cara yang disarankan dokumentasi adalah yang paling sederhana: impor langsung di masing-masing agent.

ts
// src/mastra/agents/weather-agent.ts
import { Agent } from '@mastra/core/agent'
import { weatherTool } from '../tools/weather-tool.ts'

export const weatherAgent = new Agent({
  id: 'weather-agent',
  name: 'Weather Agent',
  instructions: 'Jawab pertanyaan tentang cuaca saat ini.',
  model: 'openai/gpt-5.6-sol',
  tools: { weatherTool },
})
ts
// src/mastra/agents/travel-agent.ts
import { Agent } from '@mastra/core/agent'
import { weatherTool } from '../tools/weather-tool.ts'

export const travelAgent = new Agent({
  id: 'travel-agent',
  name: 'Travel Agent',
  instructions: 'Bantu pengguna merencanakan perjalanan, termasuk cuaca tujuan.',
  model: 'openai/gpt-5.6-sol',
  tools: { weatherTool },
})

Keuntungannya, sebagaimana disebut dokumentasi: dependensi tetap eksplisit dan tiap agent bisa dipakai secara independen. Tidak ada registry tersembunyi yang harus kamu telusuri untuk tahu agent ini sebenarnya bisa apa.

Bukan hanya fungsi yang bisa jadi tool

Dua konfigurasi lain mengubah komponen Mastra menjadi tool secara otomatis:

ts
// Agent lain sebagai tool → menjadi tool bernama agent-<key>
export const supervisor = new Agent({
  id: 'supervisor',
  name: 'Supervisor',
  instructions: 'Koordinasikan penulis untuk menghasilkan konten.',
  model: 'openai/gpt-5.6-sol',
  agents: { writer },
})
ts
// Workflow sebagai tool → menjadi tool bernama workflow-<key>
export const researchAgent = new Agent({
  id: 'research-agent',
  name: 'Research Agent',
  instructions: 'Kamu asisten riset.',
  model: 'openai/gpt-5.6-sol',
  workflows: { researchWorkflow },
})

Untuk keduanya, sertakan description pada agent atau workflow yang didelegasikan — itulah yang dibaca pemanggilnya untuk tahu kapan harus mendelegasikan. Pola ini dibahas lebih dalam di 4.4 dan 7.3.

Kesalahan umum

Gejala: Tool tidak pernah dipanggil. Tidak ada error, tidak ada peringatan — agent hanya menjawab seolah tool itu tidak ada. Penyebab: Tool didefinisikan sebagai objek biasa, bukan lewat createTool(). Dokumentasi menyatakan bahwa definisi tool berbentuk objek polos gagal secara diam-diam. Karena tidak ada yang dilempar, kesalahan ini bisa memakan waktu lama untuk ditemukan. Perbaikan: Pastikan setiap tool dibuat lewat createTool() dengan id, description, inputSchema, dan execute.

Gejala: Error tipe di dalam execute saat mengakses argumen, atau argumen selalu bernilai undefined. Penyebab: Memakai signature lama async ({ context }) => ... lalu mengambil nilai dari context. Pada versi sekarang, parameter pertama adalah input yang sudah tervalidasi; context adalah parameter kedua dan isinya metadata eksekusi, bukan argumen tool. Perbaikan: Ubah menjadi async ({ location }) => ... untuk mengambil argumen, dan pakai parameter kedua hanya saat butuh requestContext, abortSignal, atau metadata lain.

Coba sendiri

Tantangan: Bangun agent perpustakaan bernama pustaka-agent dengan dua tool yang bekerja atas data buku dalam memori (array biasa di dalam kode, belum perlu database).

Tool yang harus dibuat:

  1. cari-buku — menerima kata kunci, mengembalikan daftar buku yang cocok beserta ketersediaannya
  2. cek-denda — menerima nomor anggota, mengembalikan total denda dan daftar buku yang terlambat

Ketentuan:

  1. Keduanya dibuat dengan createTool(), lengkap dengan inputSchema dan outputSchema
  2. Instruksi agent menyebut kedua tool dan kapan masing-masing dipakai
  3. Sediakan minimal enam buku dan tiga anggota sebagai data
  4. Uji lewat Studio dengan empat pesan: pencarian yang menemukan hasil, pencarian yang tidak menemukan apa pun, pengecekan denda, dan satu pesan yang butuh kedua tool sekaligus
  5. Amati di Studio berapa kali tool dipanggil untuk pesan keempat

Checklist penerimaan:

  • [ ] Kedua tool muncul dan benar-benar dipanggil, terlihat di Studio
  • [ ] Pencarian tanpa hasil menghasilkan jawaban yang jujur, bukan buku karangan
  • [ ] Pesan keempat memicu dua pemanggilan tool dalam satu giliran
  • [ ] outputSchema kedua tool mendeskripsikan bentuk hasil yang sebenarnya dikembalikan — bukan sekadar z.any() atau z.string()
  • [ ] Kamu bisa menunjukkan di Studio urutan: tool dipanggil, hasil kembali, lalu jawaban disusun

Petunjuk: Ketentuan 4 poin terakhir adalah yang paling menarik. Kalau agent hanya memanggil satu tool padahal pertanyaannya butuh dua, periksa dua hal sebelum menyalahkan model: apakah description tiap tool cukup jelas membedakan keduanya, dan apakah instruksi agent menyebutkan bahwa keduanya boleh dipakai bersamaan.

Ikhtisar

  • Tool dibuat dengan createTool() — objek polos akan gagal diam-diam, tanpa error apa pun.
  • Empat properti wajib: id, description, inputSchema, execute. description dan inputSchema dibaca model, bukan hanya mesin.
  • execute punya tepat satu signature: (inputData, context). Parameter pertama adalah input yang sudah tervalidasi; parameter kedua berisi requestContext, abortSignal, dan metadata lain, dan boleh dihilangkan.
  • Data identitas seperti userId sebaiknya diambil dari requestContext, bukan dari inputSchema — supaya model tidak bisa mengarangnya.
  • tools pada agent adalah objek, dan menyebut nama tool di instructions meningkatkan ketepatan pemanggilan.
  • Berbagi tool antar agent dilakukan dengan impor langsung, supaya dependensi tetap eksplisit.
  • Agent lain (agents) dan workflow (workflows) otomatis menjadi tool dengan nama agent-<key> dan workflow-<key>.

Lanjut ke mana

Tool-mu sudah jalan. Sekarang bagian yang menentukan apakah ia dipanggil pada saat yang tepat — dan itu hampir seluruhnya soal schema: 2.2 Schema yang Baik.

Materi belajar mandiri. Bukan dokumentasi resmi Mastra.