Intervention humaine (HITL)
Certains Workflows doivent attendre une intervention humaine avant de continuer. Lorsqu'un Workflow est suspendu, il peut renvoyer un message expliquant la raison de la suspension et les informations nécessaires pour poursuivre. Selon la saisie reçue, le Workflow peut ensuite reprendre ou s'arrêter. Cette approche convient aux approbations et rejets manuels, aux décisions soumises à validation ou à toute étape nécessitant une supervision humaine.
Suspendre un Workflow pour une intervention humaineLien direct vers Suspendre un Workflow pour une intervention humaine
La saisie avec intervention humaine fonctionne presque comme la suspension d'un Workflow au moyen de suspend(). La principale différence tient au fait que, lorsqu'une intervention humaine est requise, vous pouvez renvoyer suspend() avec une charge utile qui fournit à l'utilisateur le contexte ou les indications nécessaires pour continuer.

import { createWorkflow, createStep } from '@mastra/core/workflows'
import { z } from 'zod'
const step1 = createStep({
id: 'step-1',
inputSchema: z.object({
userEmail: z.string(),
}),
outputSchema: z.object({
output: z.string(),
}),
resumeSchema: z.object({
approved: z.boolean(),
}),
suspendSchema: z.object({
reason: z.string(),
}),
execute: async ({ inputData, resumeData, suspend }) => {
const { userEmail } = inputData
const { approved } = resumeData ?? {}
if (!approved) {
return await suspend({
reason: 'Human approval required.',
})
}
return {
output: `Email sent to ${userEmail}`,
}
},
})
export const testWorkflow = createWorkflow({
id: 'test-workflow',
inputSchema: z.object({
userEmail: z.string(),
}),
outputSchema: z.object({
output: z.string(),
}),
})
.then(step1)
.commit()
Fournir un retour à l'utilisateurLien direct vers Fournir un retour à l'utilisateur
Lorsqu'un Workflow est suspendu, vous pouvez accéder à la charge utile renvoyée par suspend() en identifiant l'étape suspendue puis en lisant son suspendPayload.
const workflow = mastra.getWorkflow('testWorkflow')
const run = await workflow.createRun()
const result = await run.start({
inputData: {
userEmail: 'alex@example.com',
},
})
if (result.status === 'suspended') {
const suspendStep = result.suspended[0]
const suspendedPayload = result.steps[suspendStep[0]].suspendPayload
console.log(suspendedPayload)
}
Exemple de sortieLien direct vers Exemple de sortie
Les données renvoyées par l'étape peuvent inclure un motif qui aide l'utilisateur à comprendre ce qui est nécessaire pour reprendre le Workflow.
{
reason: 'Confirm to send email.'
}
Reprendre un Workflow avec une saisie humaineLien direct vers Reprendre un Workflow avec une saisie humaine
Comme pour la reprise d'un Workflow, utilisez resume() avec resumeData pour poursuivre un Workflow après avoir reçu une saisie humaine. Le Workflow reprend à l'étape où il a été suspendu.

const workflow = mastra.getWorkflow('testWorkflow')
const run = await workflow.createRun()
await run.start({
inputData: {
userEmail: 'alex@example.com',
},
})
const handleResume = async () => {
const result = await run.resume({
step: 'step-1',
resumeData: { approved: true },
})
}
Gérer un refus humain avec bail()Lien direct vers handling-human-rejection-with-bail
Utilisez bail() pour arrêter l'exécution du Workflow à une étape sans déclencher d'erreur. Cette méthode est utile lorsqu'une personne refuse explicitement une action. Le Workflow se termine avec l'état success et toute logique placée après l'appel à bail() est ignorée.
const step1 = createStep({
execute: async ({ inputData, resumeData, suspend, bail }) => {
const { userEmail } = inputData
const { approved } = resumeData ?? {}
if (approved === false) {
return bail({
reason: 'User rejected the request.',
})
}
if (!approved) {
return await suspend({
reason: 'Human approval required.',
})
}
return {
message: `Email sent to ${userEmail}`,
}
},
})
Intervention humaine en plusieurs toursLien direct vers Intervention humaine en plusieurs tours
Pour les Workflows qui nécessitent une saisie à plusieurs étapes, le modèle de suspension reste identique. Chaque étape définit un resumeSchema ainsi qu'un suspendSchema, généralement assorti d'un motif qui peut servir à fournir un retour à l'utilisateur.
const step1 = createStep({...});
const step2 = createStep({
id: "step-2",
inputSchema: z.object({
message: z.string()
}),
outputSchema: z.object({
output: z.string()
}),
resumeSchema: z.object({
approved: z.boolean()
}),
suspendSchema: z.object({
reason: z.string()
}),
execute: async ({ inputData, resumeData, suspend }) => {
const { message } = inputData;
const { approved } = resumeData ?? {};
if (!approved) {
return await suspend({
reason: "Human approval required."
});
}
return {
output: `${message} - Deleted`
};
}
});
export const testWorkflow = createWorkflow({
id: "test-workflow",
inputSchema: z.object({
userEmail: z.string()
}),
outputSchema: z.object({
output: z.string()
})
})
.then(step1)
.then(step2)
.commit();
Chaque étape doit être reprise dans l'ordre au moyen d'un appel distinct à resume() pour chaque étape suspendue. Cette approche facilite la gestion des approbations en plusieurs étapes, avec un retour cohérent dans l'interface utilisateur et un traitement clair des saisies à chaque stade.
const handleResume = async () => {
const result = await run.resume({
step: 'step-1',
resumeData: { approved: true },
})
}
const handleDelete = async () => {
const result = await run.resume({
step: 'step-2',
resumeData: { approved: true },
})
}