Passer au contenu principal
Les étapes humaines interrompent un workflow pour attendre une décision manuelle ou un complément d’information. Déclarez-les via createHuman et réutilisez-les dans plusieurs pipelines.
import { createHuman, createStep, createWorkflow } from "@ai_kit/core";
import { z } from "zod";

const fetchDraftApplication = createStep<
  { applicantId: string },
  { applicantId: string; amount: number; history: string[] }
>({
  id: "fetch-draft-application",
  description: "Charge un dossier à valider",
  inputSchema: z.object({ applicantId: z.string().min(1) }),
  handler: async ({ input }) => ({
    applicantId: input.applicantId,
    amount: 4200,
    history: ["2019: ouverture", "2023: mise à jour"],
  }),
});

export const manualReview = createHuman<
  { applicantId: string; amount: number; history: string[] },
  { decision: string; commentaire: string }
>({
  id: "manual-review",
  output: ({ current }) => ({
    dossier: {
      id: current.applicantId,
      montant: current.amount,
      historique: current.history,
    },
  }),
  input: ({ ask }) =>
    ask.form({
      title: "Validation manuelle du dossier",
      fields: [
        ask.text({ id: "commentaire", label: "Commentaire" }),
        ask.select({
          id: "decision",
          label: "Décision",
          options: ["approve", "reject"],
        }),
      ],
    }),
});

const finalizeDecision = createStep<
  { decision: string; commentaire: string },
  { status: string }
>({
  id: "finalize-decision",
  handler: ({ input, context }) => ({
    status: `${context.initialInput.applicantId}:${input.decision}:${input.commentaire}`,
  }),
});

export const onboardingWorkflow = createWorkflow({ id: "onboarding" })
  .then(fetchDraftApplication)
  .human(manualReview)
  .then(finalizeDecision)
  .commit();
  • La sortie de fetchDraftApplication est injectée dans manualReview (output.current) et renvoyée via pendingHuman.output.
  • L’entrée humaine devient l’entrée de finalizeDecision, qui accède aussi aux données initiales via context.initialInput.

Cycle d’exécution

const run = onboardingWorkflow.createRun();
const { stream, final } = await run.stream({ inputData: { applicantId: "app-123" } });

for await (const event of stream) {
  if (event.type === "step:human:requested") {
    const { form, output } = event.data;
    ui.displayReviewForm(form, output.dossier);
  }
}

const pending = await final;

if (pending.status === "waiting_human") {
  await run.resumeWithHumanInput({
    stepId: "manual-review",
    data: { decision: "approve", commentaire: "RAS" },
  });
}
run.resumeWithHumanInput valide la réponse selon le schéma de l’étape humaine puis relance l’exécution jusqu’à complétion.

Bonnes pratiques

  • Utilisez des identifiants stables pour vos étapes humaines (ils servent lors de la reprise).
  • Exposez des métadonnées utiles dans output pour simplifier l’affichage côté front (résumés, liens, stats).
  • Journalisez les événements step:human:* afin de mesurer les temps de traitement.