Human-in-the-loop für Mastra

Menschliche Entscheidungen für Mastra-Agenten und -Workflows.

Dein Mastra-Agent stoppt, bevor ein riskantes Tool läuft. Dein Nutzer gibt es auf dem Handy frei.

Was Mastra mitbringt

suspend() und run.resume()

Ein Workflow-Schritt kann pausieren; dein Code ruft später run.resume() auf. Ein Agenten-Tool kann requireApproval setzen, wodurch der Lauf vor der Tool-Ausführung pausiert. Für Wartezeiten über die Prozesslaufzeit hinaus brauchst du persistenten Mastra-Speicher und die gespeicherte Lauf-ID. Prüfe resumeData, bevor damit etwas ausgeführt werden darf.

nativ
const approval = createStep({
  id: "approval",
  inputSchema: z.object({}),
  outputSchema: z.object({ approved: z.boolean() }),
  resumeSchema: z.object({ approved: z.boolean() }),
  execute: async ({ suspend, resumeData }) => {
    if (!resumeData) return await suspend({})
    return { approved: resumeData.approved }
  },
})

Wo es nicht weitergeht

  • Ein pausierter Schritt bleibt still. Der Speicher weiß, dass der Lauf wartet; ein Mensch erfährt es nicht.
  • Irgendetwas muss run.resume() aufrufen. Du baust die Route, die die Antwort empfängt und die passende runId findet.
  • Der Snapshot enthält den Workflow-Zustand. Er dokumentiert nicht, wer freigegeben oder was die Person gesehen hat.

Die Lösung

Pushary holt die Antwort deines Nutzers ein.

Mastra kann einen Lauf vor der Tool-Ausführung pausieren, benachrichtigt aber niemanden. Pushary schickt jeden pausierten Aufruf auf das Handy deines Nutzers und genehmigt oder verwirft ihn in Mastra.

issueRefund setzt Mastras eigenes requireApproval. Der Lauf pausiert deshalb vor der Ausführung. resolvePusharyApprovals fragt deinen Nutzer und genehmigt oder verwirft den Aufruf in Mastra. Bei Ablehnung oder keiner rechtzeitigen Antwort wird die Erstattung nie ausgeführt. Deckt eine deiner Pushary-Regeln die Erstattung ab, antwortet die Regel zuerst.

bash
npm install @pushary/mastra @mastra/core zod
Freigabe am riskanten Tool
import { createTool } from "@mastra/core/tools"
import { resolvePusharyApprovals } from "@pushary/mastra"
import { z } from "zod"

export const issueRefund = createTool({
  id: "issue-refund",
  description: "Refund an order",
  inputSchema: z.object({ orderId: z.string(), amount: z.number().positive() }),
  requireApproval: true,
  execute: async (input) => refundOrder(input),
})

const output = await agent.generate("Refund order 1234", {
  memory: { thread: conversation.id, resource: user.id },
})
if (output.finishReason === "suspended") {
  // Your user taps Approve or Deny. No answer means declined.
  const outcome = await resolvePusharyApprovals({ externalId: user.id }, { agent, resourceId: user.id })
  await handlePendingRuns(outcome.pending)
}

Nutze im Workflow den Freigabeschritt

pusharyApprovalStep erstellt die Anfrage, pausiert den Workflow und kehrt sofort zurück. Pushary schickt die Antwort als signierten Webhook an deine Callback-URL. Deine Route prüft sie und ruft run.resume() auf. Ein späterer Schritt prüft approved, bevor die riskante Aktion läuft.

Workflow-Schritt
import { createWorkflow } from "@mastra/core/workflows"
import { pusharyApprovalStep, pusharyApprovalStepInputSchema, pusharyAnswerSchema } from "@pushary/mastra"

const config = { apiKey: process.env.PUSHARY_API_KEY! }
const review = pusharyApprovalStep(config, { callbackUrl, externalId: user.id })

const workflow = createWorkflow({
  id: "customer-review",
  inputSchema: pusharyApprovalStepInputSchema,
  outputSchema: pusharyAnswerSchema,
}).then(review).commit()

So funktioniert es

Von der Installation zur ersten Antwort

Verbinde deinen Nutzer einmal. Sichere den riskanten Schritt mit einer Freigabe ab. Pushary schickt die Frage, wartet auf die Antwort und speichert sie.

  1. 01

    Adapter installieren

    Führe npm install @pushary/mastra @mastra/core zod aus und speichere deinen API-Schlüssel in PUSHARY_API_KEY. Richte für spätere Antworten persistenten Speicher für Mastra ein.

  2. 02

    Nutzer einmal verbinden

    connect() liefert einen Link. Zeige ihn in deinem Produkt an. Dein Nutzer öffnet ihn mit der kostenlosen Pushary-App auf seinem Handy. Kein Konto, keine Zahlung.

  3. 03

    Das riskante Tool mit einer Freigabe absichern

    Setze requireApproval: true am Tool. Ergänze in einem Workflow pusharyApprovalStep. Für eine einfache Frage, die das Modell nach eigenem Ermessen stellen darf, ergänzt du createPusharyAskTool.

  4. 04

    Auf die Antwort reagieren

    resolvePusharyApprovals genehmigt oder verwirft den pausierten Aufruf und setzt den Lauf fort. Im Workflow ruft deine Callback-Route run.resume() auf. Bei Nein, Ablauf oder fehlender Antwort läuft die Aktion nie.

Eine Frage kann ein Ja oder Nein verlangen, eine Auswahl aus einer Liste oder eine Texteingabe. Jede Antwort wird gespeichert.

Vor der Veröffentlichung

Stolperfallen bei Mastra

Ein Frage-Tool erzwingt keine Freigabe
createPusharyAskTool ist ein Tool, dessen Aufruf das Modell selbst wählt. Es erzwingt keine Freigabe vor einem anderen Tool. Auch ein Prompt mit „erst fragen“ tut das nicht. Setze requireApproval direkt am riskanten Tool.
Du brauchst eine Zuordnung von correlationId zu runId
Die Antwort erreicht deinen Webhook mit Bezug zur Anfrage, nicht zu deinem Workflow. Speichere die Zuordnung beim Pausieren. Sonst hast du eine Antwort, weißt aber nicht, zu welchem pausierten Lauf sie gehört.
Beim ersten Durchlauf ist resumeData undefined
Die execute-Funktion des Schritts läuft einmal zum Pausieren und erneut zum Fortsetzen. Vergisst du den undefined-Fall beim ersten Durchlauf, löst sie einen Fehler aus, bevor sie überhaupt pausiert.

Der Partner-Tarif

Dein Agent fragt deine Nutzer, nicht nur dich

Stelle deinen Nutzern deinen Agenten bereit. Jeder gibt dessen riskante Aktionen vom eigenen Handy aus frei, unter deiner Marke.

$99/ Monat, alle Frameworks enthalten
Start free

Deine Nutzer brauchen kein Pushary-Konto und zahlen nichts an uns.

Deine Nutzer antworten auf ihren eigenen Handys

Verbinde jeden Nutzer einmal über einen Link. Er installiert die kostenlose Pushary-App und antwortet vom Sperrbildschirm aus, ohne eigenes Konto.

Keine Antwort heißt Nein

Führe die Aktion nur nach einer ausdrücklichen Freigabe aus. Eine wartende, abgelaufene oder abgebrochene Anfrage zählt nie als Ja. Pushary behält jede Anfrage, damit dein Code sie nach einem Neustart wieder aufnehmen kann.

Erreicht sie auf dem Handy

Die App kommt zuerst, denn nur sie zeigt „Genehmigen“ und „Ablehnen“ auf dem Sperrbildschirm. Browser-Benachrichtigungen folgen danach. Du musst kein Zustellsystem bauen.

Jede Antwort gespeichert

Zu jeder Antwort wird gespeichert, wer wann geantwortet hat. Du kannst sie durchsuchen und exportieren. Mit einer Callback-URL geht jede Antwort außerdem als signierter Webhook an deinen Server.

FAQ

Fragen und Antworten

Gibt es ein Mastra-Paket für Pushary?
Ja. @pushary/mastra ist auf npm verfügbar. Es bietet resolvePusharyApprovals für Mastras requireApproval, aufgeschobene Prüfungen für spätere Antworten, pusharyApprovalStep für Workflows und createPusharyAskTool für Fragen. Es braucht Mastra 1.59 oder neuer und Node.js 22.13 oder neuer.
Sollte ich das Tool oder den Workflow-Schritt verwenden?
Nutze requireApproval am Tool, wenn ein Agent über die Aktion entscheidet, und pusharyApprovalStep bei einem Workflow. Nutze createPusharyAskTool nur für kurze Fragen, die das Modell optional stellen darf. Für spätere Antworten verwendest du die Hilfsfunktionen für aufgeschobene Prüfungen mit persistentem Speicher und ordnest jede Antwort ihrem gespeicherten Lauf zu.
Was passiert, wenn niemand antwortet?
Die Aktion läuft nicht. Keine Antwort ist niemals ein Ja. Der Aufruf wird deshalb nach Ende der Wartezeit verworfen. Unterscheide zwischen „niemand hat geantwortet“ und „dein Nutzer hat Nein gesagt“. Pushary behält die Anfrage, aber eine gespeicherte Antwort kann einen Mastra-Lauf nicht selbst neu starten.
Kann jeder meiner Endnutzer auf seinem eigenen Handy freigeben?
Ja. Dein Code bestimmt anhand deiner eigenen Nutzer-ID, wer antwortet. Diese Person installiert die kostenlose Pushary-App und öffnet einmal deinen Verbindungslink. Sie braucht weder API-Schlüssel noch kostenpflichtigen Tarif. Die Person, die eine Aktion anfordert, ist nicht immer diejenige, die sie freigeben sollte.
Übersteht die Wartezeit einen Neustart oder ein Deployment?
Ein pausierter Lauf ja, eine blockierende Frage nein. Mit persistentem Mastra-Speicher, gespeicherter Lauf-ID und deinem eigenen Fortsetzungscode läuft der Vorgang nach einem Neustart weiter. Teste Neustarts und doppelte Antworten mit deinem echten Speicher. Eine gespeicherte Antwort beweist nicht, dass die Erstattung selbst durchgeführt wurde.
Wann sollte ich suspend() statt eines blockierenden Frage-Tools verwenden?
Nutze suspend(), wenn dein Nutzer erst antworten könnte, nachdem die Anfrage oder der Worker beendet ist. Richte Mastra-Speicher ein und speichere die Lauf-ID, bevor du wartest. Dein Code prüft die Antwort und ruft resume auf. Eine Callback-URL allein erledigt das nicht.

Lass deinen Mastra-Agenten fragen, bevor er handelt.

Verbinde einen Nutzer einmal, frage mit einem Aufruf und führe die Aktion nur bei einem Ja aus. Jede Antwort wird gespeichert.

Start free

Partner-Tarif, $99 im Monat. Deine Nutzer brauchen kein Pushary-Konto und zahlen nichts an uns.