Définition de Workflow dynamique
Les Workflows dynamiques sont en bêta. Des changements cassants peuvent survenir sans incrément de version majeure tant que l’API n’est pas stable.
Une définition de Workflow dynamique est un DynamicWorkflowGraph compatible JSON accepté par Mastra.addDynamicWorkflow(), les routes de serveur de Workflows stockés et l’API Workflows du SDK client.
Consultez Workflows dynamiques pour un exemple complet de configuration et d’utilisation.
Champs de définitionLien direct vers Champs de définition
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
id | string | Oui | ID unique du Workflow. Il sert également à récupérer et exécuter le Workflow. |
description | string | Non | Description lisible par l’utilisateur |
inputSchema | JsonSchema | Oui | JSON Schema de l’entrée du Workflow |
outputSchema | JsonSchema | Oui | JSON Schema de la sortie du Workflow |
stateSchema | JsonSchema | Non | JSON Schema de l’état partagé du Workflow |
requestContextSchema | JsonSchema | Non | JSON Schema des valeurs lues depuis le contexte de requête |
metadata | Record<string, unknown> | Non | Métadonnées JSON arbitraires conservées via le stockage |
graph | SerializedStepFlowEntry[] | Oui | Entrées d’étapes qui composent le Workflow |
Les schémas utilisent JSON Schema plutôt que Zod afin que la définition puisse effectuer un aller-retour via JSON. Mastra convertit chaque schéma en Zod lors de l’enregistrement du Workflow.
{
"id": "greeting-workflow",
"description": "Returns a greeting for the supplied name",
"inputSchema": {
"type": "object",
"properties": { "name": { "type": "string" } },
"required": ["name"]
},
"outputSchema": {
"type": "object",
"properties": { "message": { "type": "string" } },
"required": ["message"]
},
"graph": [
{
"type": "mapping",
"id": "create-greeting",
"mapConfig": "{\"message\":{\"template\":\"Hello, ${initData.name}!\"}}"
}
]
}
Entrées de grapheLien direct vers Entrées de graphe
Les entrées du graph s’exécutent dans l’ordre. Chaque entrée reçoit la sortie de l’entrée précédente, et la première entrée reçoit l’entrée du Workflow.
| Type d’entrée | Description |
|---|---|
agent | Appeler un Agent enregistré |
tool | Appeler un Tool enregistré |
mapping | Restructurer les données entre les étapes |
workflow | Appeler un Workflow enregistré comme étape imbriquée |
parallel | Exécuter plusieurs étapes simultanément et fusionner leurs sorties |
conditional | Exécuter simultanément chaque branche dont le prédicat est vrai |
foreach | Exécuter une étape pour chaque élément d’une entrée tableau |
loop | Répéter une étape tant qu’un prédicat est vrai ou jusqu’à ce qu’il soit vrai |
sleep | Suspendre pendant une durée fixe |
sleepUntil | Suspendre jusqu’à une date fixe |
Les Workflows définis dans le code qui utilisent .agent() et .tool() produisent les mêmes entrées déclaratives lorsqu’ils sont sérialisés.
Étapes d’AgentLien direct vers Étapes d’Agent
Une entrée agent appelle un Agent enregistré par ID. Les étapes d’Agent acceptent { prompt: string } comme entrée et renvoient { text: string } par défaut.
{
"type": "agent",
"id": "summarize",
"agentId": "support-agent"
}
L’id identifie ce site d’appel dans le Workflow. Les étapes ultérieures accèdent au résultat sous la forme stepResults.summarize, quel que soit l’ID propre à l’Agent.
Ajoutez un outputSchema pour demander une sortie structurée à l’Agent :
{
"type": "agent",
"id": "extract-subtopics",
"agentId": "support-agent",
"outputSchema": {
"type": "array",
"items": {
"type": "object",
"properties": { "title": { "type": "string" } },
"required": ["title"]
}
}
}
Utilisez une entrée mapping avant un Agent pour construire son entrée { prompt } à partir des données du Workflow.
Les entrées d’Agent acceptent une description facultative et un objet options :
{
"type": "agent",
"id": "summarize",
"agentId": "support-agent",
"description": "Summarize the incoming request",
"options": { "retries": 2, "metadata": { "team": "support" } }
}
Seuls retries et metadata sont conservés. Les options dont la valeur est une fonction, telles que onFinish et un toolChoice fonctionnel, sont rejetées lors du stockage d’un Workflow défini dans le code. Les autres options d’appel d’Agent ne sont pas conservées.
Étapes de ToolLien direct vers Étapes de Tool
Une entrée tool appelle un Tool par sa clé d’enregistrement dans l’objet tools de Mastra. Mastra résout les schémas d’entrée et de sortie du Tool depuis le registre lors de l’enregistrement du Workflow.
{
"type": "tool",
"id": "lookup",
"toolId": "lookup-customer"
}
Les entrées de Tool acceptent les mêmes champs description et options facultatifs que les entrées d’Agent. Seuls retries et metadata sont conservés.
Étapes de mappingLien direct vers Étapes de mapping
Une entrée mapping restructure des données. Son mapConfig est une chaîne JSON qui encode un objet. Chaque clé devient une clé dans la sortie de l’étape, et chaque descripteur définit une source.
| Descripteur | Description |
|---|---|
{ "value": ... } | Valeur JSON constante |
{ "template": "..." } | Chaîne construite à partir d’espaces réservés ${...} |
{ "initData": true, "path": "a.b" } | Valeur provenant de l’entrée du Workflow |
{ "step": "step-id", "path": "a.b" } | Valeur provenant de la sortie d’une étape précédente |
{ "requestContextPath": "a.b" } | Valeur provenant du contexte de requête |
La source step accepte également un tableau d’ID d’étapes :
{ "step": ["escalate", "auto-reply"], "path": "text" }
La première étape répertoriée ayant un résultat non vide fournit la valeur. Cela peut sélectionner la branche qui s’est exécutée après une entrée conditional.
Les modèles résolvent les espaces réservés à partir de initData, inputData, state, requestContext et stepResults.<step-id> :
{
"type": "mapping",
"id": "build-prompt",
"mapConfig": "{\"prompt\":{\"template\":\"Summarize this request: ${initData.request}\"}}"
}
Les objets et tableaux résolus par un modèle sont convertis en chaînes JSON. Une valeur null au sein d’un résultat présent est rendue sous la forme d’une chaîne vide. Un modèle qui référence une étape sans sortie réussie fait échouer l’exécution.
Les entrées de mapping doivent être des entrées de graphe de premier niveau. Elles ne peuvent pas être placées dans des conteneurs parallel, conditional, foreach ou loop.
Étapes de Workflow imbriquéLien direct vers Étapes de Workflow imbriqué
Une entrée workflow appelle un autre Workflow enregistré. La cible peut être définie dans le code ou stockée.
{
"type": "workflow",
"id": "lookup-first",
"workflowId": "lookup-customer-workflow"
}
L’id identifie le site d’appel. Le même Workflow imbriqué peut apparaître plusieurs fois sous différents ID de site d’appel, et les étapes ultérieures accèdent à chaque résultat sous la forme stepResults.<id>. Une entrée workflow accepte également une description facultative.
Entrées parallelLien direct vers Entrées parallel
Une entrée parallel exécute simultanément plusieurs étapes simples et fusionne leurs sorties dans un objet indexé par ID d’étape.
{
"type": "parallel",
"steps": [
{ "type": "tool", "id": "first", "toolId": "lookup-customer" },
{ "type": "tool", "id": "second", "toolId": "lookup-customer" }
]
}
Chaque enfant doit être une entrée agent, tool ou workflow. Tous les enfants reçoivent directement l’entrée de l’entrée parallel.
Entrées conditionnellesLien direct vers Entrées conditionnelles
Une entrée conditional associe chaque étape à un prédicat déclaratif et exécute chaque branche dont le prédicat est vrai.
{
"type": "conditional",
"steps": [
{ "type": "agent", "id": "escalate", "agentId": "support-agent" },
{ "type": "agent", "id": "auto-reply", "agentId": "support-agent" }
],
"predicates": [
{ "op": "eq", "left": { "path": "inputData.priority" }, "right": { "literal": "urgent" } },
{ "op": "ne", "left": { "path": "inputData.priority" }, "right": { "literal": "urgent" } }
]
}
Chaque enfant doit être une entrée agent, tool ou workflow, et chaque enfant nécessite un prédicat. Tous les enfants reçoivent directement l’entrée de l’entrée conditionnelle.
PrédicatsLien direct vers Prédicats
Les entrées conditionnelles et les boucles utilisent un DSL de prédicats JSON. Les opérandes sont des références { "path": "..." } ou des valeurs { "literal": ... }. Les chemins sont résolus à partir de initData, inputData, stepResults et state.
| Opérateur | Forme |
|---|---|
eq, ne, lt, lte, gt, gte | { "op": "eq", "left": ..., "right": ... } |
in, notIn | { "op": "in", "value": ..., "set": [...] } |
exists, notExists | { "op": "exists", "path": "..." } |
truthy, falsy | { "op": "truthy", "value": ... } |
and, or | { "op": "and", "args": [...] } |
not | { "op": "not", "arg": ... } |
Les chemins manquants ne lèvent pas d’erreur. Les opérateurs fondés sur un chemin renvoient false lorsque le chemin ne peut pas être résolu. Utilisez exists ou notExists pour distinguer une valeur manquante d’une valeur falsy.
Entrées foreachLien direct vers Entrées foreach
Une entrée foreach exécute son corps une fois pour chaque élément d’une entrée tableau. L’entrée précédente doit produire un tableau brut. Les résultats préservent l’ordre d’entrée et la concurrence vaut 1 par défaut.
{
"type": "foreach",
"step": { "type": "workflow", "id": "write-blurb", "workflowId": "blurb-workflow" },
"opts": { "concurrency": 3 }
}
Le corps peut être une entrée agent, tool ou workflow, mais pas une entrée mapping.
Entrées de boucleLien direct vers Entrées de boucle
Une entrée loop répète une étape tant qu’un prédicat est vrai (dowhile) ou jusqu’à ce qu’un prédicat soit vrai (dountil).
{
"type": "loop",
"loopType": "dountil",
"step": { "type": "tool", "id": "poll", "toolId": "check-status" },
"predicate": {
"op": "eq",
"left": { "path": "inputData.status" },
"right": { "literal": "done" }
}
}
Le corps de la boucle doit être une seule étape, et les boucles stockées exigent un prédicat déclaratif.
Entrées sleepLien direct vers Entrées sleep
Une entrée sleep suspend pendant un nombre fixe de millisecondes. Une entrée sleepUntil suspend jusqu’à une date fixe représentée par une chaîne de date ISO. Les définitions stockées exigent des valeurs littérales.
{ "type": "sleep", "id": "wait", "duration": 5000 }
{ "type": "sleepUntil", "id": "wait-for-launch", "date": "2027-01-01T00:00:00.000Z" }
Utilisez un Workflow défini dans le code lorsque la durée ou la date doit être calculée au moment de l’exécution.
ValidationLien direct vers Validation
Mastra valide les définitions avant de les conserver ou de les enregistrer :
- Structure : formes des entrées et champs obligatoires, y compris les règles de placement telles que les mappings uniquement de premier niveau.
- Références : chaque
agentIdetworkflowIddoit être résolu dans les registres actifs ou le même bundle. UntoolIddoit correspondre à une clé d’enregistrement de Tool. - Flux de schéma : l’entrée de chaque entrée doit être compatible avec la sortie précédente, y compris les sorties de mapping inférées.
Les erreurs de validation incluent un chemin par points, tel que graph.2.steps.0, qui identifie l’entrée non valide.