Workflows et tâches
Le moteur (workflow-engine.js) enchaine des tâches. Une tâche accepte des paramètres et s'exécute sans écran. C'est la condition pour qu'un enchainement se déroule sans intervention, et la raison pour laquelle les tâches sont déclarées à part au lieu d'être devinées parmi les commandes. Les mêmes tâches constituent les outils de l'assistant IA.
Déclarer une tâche
| Champ | Forme | Description |
|---|---|---|
| entrees | Tableau d'objets | {nom, type, requis, defaut, libelle}. Converti en JSON Schema pour l'assistant. |
| sorties | Tableau d'objets | {nom, type}. Sert à l'enchainement et au résumé. |
| executer | function | (args, ctx) vers une promesse d'objet de sorties. Aucune modale. |
| notice | string | Lu par tool-schema.js et transmis au modèle comme description d'outil. Voir l'encadré. |
Une tâche invalide (sans id ou sans executer) est refusée avec une erreur en console, et le jeton rendu est inerte. Toute mutation émet workflow.tasks.changed.
Un workflow
| Champ d'étape | Effet |
|---|---|
| id | Les sorties de l'étape sont rangées sous cet identifiant dans le contexte. |
| tache | Identifiant de la tâche à exécuter. |
| args | Arguments, avec substitution ${etape.sortie}. |
| si | Chemin d'une variable. L'étape est sautée si la valeur est fausse. |
| continuerSiEchec | L'échec ou l'absence de la tâche n'interrompt pas la chaine. |
Substitution des variables
Il n'y a pas d'eval. Un workflow circule sous forme de fichier et peut arriver par courriel ; évaluer une expression qu'il contient reviendrait à exécuter du code venu de l'extérieur. Une substitution littérale suffit à tout ce qu'un enchainement doit faire.
| Forme | Résultat |
|---|---|
| "${e1.lignes}", référence exacte | La valeur, pas sa représentation textuelle. Un tableau reste un tableau. |
| "Campagne ${e1.nom} terminée", référence incluse | Une chaine, avec la valeur convertie en texte. Une valeur absente devient une chaine vide. |
Ce qui est délibérément absent
L'enchainement est linéaire, avec des conditions mais sans retour arrière. Aucune boucle n'est possible. Un moteur plus complet conduirait à écrire des programmes dans une interface graphique, où ils sont difficiles à relire, à éprouver et à suivre en version.
Exécution
| Règle | Détail |
|---|---|
| Un seul workflow à la fois | Un second lancement est rejeté, avec le nom de celui qui tourne. |
| Tâche inconnue | État absente, et non échec : c'est un workflow écrit pour une autre installation, ou pour un plugin qui n'est pas là. Le dire ainsi évite de chercher un bogue là où il n'y a qu'une dépendance manquante. |
| Annulation | Lève un drapeau, n'interrompt pas. Une tâche en vol qui écrit dans la base doit finir son écriture : la couper au milieu laisserait la base dans un état que le registre ne saurait pas décrire. |
États d'une étape
encours, ok, sautee (condition si fausse), absente, echec. Le passage lui-même vaut encours, ok, annule ou echec.
Évènements
| Évènement | Charge utile |
|---|---|
| workflow.started | {passage} |
| workflow.step | {passage, etape}, émis à l'entrée et à la sortie de chaque étape |
| workflow.finished | {passage}, y compris en échec ou annulation |
| workflow.changed | {id}, à l'enregistrement ou la suppression d'un flux |
| workflow.tasks.changed | {id}, à la déclaration ou au retrait d'une tâche |
Un workflow enregistré devient une commande
K.workflows.enregistrer(def) persiste le flux sous isofind_workflows et inscrit une commande workflow.<id>, catégorie workflow. Elle apparait donc dans la palette, dans le panneau Actions, et peut recevoir un raccourci.
Paramètres
Un workflow enregistré peut déclarer des paramètres. Ils entrent dans le contexte initial du passage et se réfèrent comme n'importe quelle sortie d'étape, par ${param.nom}. Rejouer un passage réutilise ses paramètres, et le menu d'un passage permet de les copier tels quels.
Imbrication
Une tâche core.workflow lance un autre workflow et attend qu'il finisse. Ses sorties se rangent sous l'identifiant de l'étape, comme pour toute autre tâche. Le nom est accepté autant que l'identifiant : obliger à retrouver wf-lx8k2 dans le stockage local rendrait la composition impraticable.
La tâche core.workflow est déclarée en écriture par précaution : le workflow appelé peut écrire, et cette tâche ne sait pas ce qu'il fait. La déclarer en lecture ouvrirait, en mode conversation, un chemin indirect vers toutes les écritures que le modèle n'a pas le droit d'appeler directement.
Mode simulation
K.workflows.simuler(flux, params) exécute un passage sans écrire. Les tâches en lecture s'exécutent normalement ; les tâches en écriture rapportent ce qu'elles feraient sans le faire. Un passage de simulation est marqué comme tel dans l'historique, et le rejouer depuis un menu relance une simulation, jamais une écriture réelle : sans cette règle, rejouer un passage depuis l'historique déclencherait des écritures que l'utilisateur n'attendait pas.
Déclencheurs et automatisation
Un workflow enregistré peut déclarer un déclencheur, mais un déclencheur déclaré ne suffit pas : il faut encore armer le workflow. La séparation est délibérée. Importer un workflow qui déclare un horaire ne doit pas le faire partir tout seul la nuit suivante sur la machine de celui qui l'a reçu.
| Type | Déclaration | Déclenchement |
|---|---|---|
| Horaire | { type: 'horaire', heure, jours } | À l'heure dite, les jours retenus (ou tous les jours si la liste est vide). |
| Évènement | { evenement, si } | Après lims.pull.done, lims.pull.error ou workflow.finished, sous réserve de la condition si. |
| Manuel | Aucun déclencheur | Ne part que sur action de l'utilisateur. |
L'écran d'aperçu, avant d'armer
Avant d'armer un workflow, en particulier un workflow reçu d'un tiers, un écran d'aperçu énonce ce qu'il fait. L'écran indique d'abord le nombre d'étapes qui écrivent dans la base, sous le nom de l'utilisateur, dans le registre signé, chacune nommée. Un workflow en lecture seule le dit aussi, tout aussi clairement.
Les workflows peuvent se partager en documents signés. Un workflow reçu porte son signataire, vérifié contre le carnet de clés. Quelques semaines plus tard, rien ne distingue à l'écran un workflow reçu d'un workflow écrit sur place, et cette information ne se retrouve pas autrement.
Inspection par l'assistant
L'assistant IA dispose de tâches d'inspection en lecture seule pour diagnostiquer l'automatisation sans jamais la modifier : core.workflow_liste, core.workflow_detail, core.workflow_passages et core.workflow_simuler. Il peut expliquer pourquoi un workflow a échoué cette nuit ; il ne peut ni l'armer, ni le lancer, ni le modifier.
Le workflow est un agent
Chaque tâche reçoit dans son contexte d'exécution un champ agent, valorisé à workflow: <nom>. Le registre signé distingue l'acteur, qui décide, de l'agent, qui exécute.
Devant une correction appliquée à quarante échantillons, la première question posée en audit est de savoir s'il s'agit d'un geste répété ou d'une règle automatique, les deux n'engageant pas la même responsabilité. Les champs acteur et agent portent cette distinction dans chaque entrée.
Tâches du noyau
| Tâche | Rôle |
|---|---|
| core.sql | Requête en lecture. Rend lignes, colonnes, nombre de lignes. |
| core.inventaire | Comptage par élément, matériau ou rapport isotopique sur toute la base, sans exiger d'élément en entrée. |
| core.echantillons | Sélection d'échantillons. Gère explicitement le résultat vide. |
| core.resume | n, moyenne, 2SD, min, max par groupe, calculés sur la totalité des lignes. |
| core.analyses | Une valeur agrégée par échantillon, 2SD des réplicats en barre d'erreur. |
| core.graphique | bar, line, scatter, histogram. Dégradé continu, barres d'erreur, unités. |
| core.correspondance | Recherche de correspondances. Les noms sont résolus en identifiants dans le code. |
| core.carte | Carte rendue dans une iframe cloisonnée. |
| core.formules | Découverte du catalogue de 24 formules géochimiques. |
| core.calcul | Application d'une formule. Paramètres en chaine texte. |
| core.rapport_modeles / core.rapport | Modèles disponibles, puis génération. Refuse un rapport partiel. |
Aucune tâche du noyau ne supprime de données. La surface d'automatisation, et donc la surface exposée à l'assistant IA, est exactement la liste des tâches déclarées.