Process Flows
Créer des Process Flows avec le SDK — étapes, tâches, personas, modèles d'actions et déclencheurs vocaux — et les distribuer sous forme d'extensions
Cet artefact est distribué dans une extension. Pour le cycle de vie partagé — installation, extension build, upload — voir Extensions & SDK d'authoring.
Un Process Flow est un workflow structuré et reproductible avec des étapes, des tâches et des personas — lancements de projets, audits, onboarding, revues de due-diligence. Vous le créez une fois comme Process Flow avec ce SDK et le distribuez dans un .scrydon-extension.tar.gz ; la plateforme l'instancie à chaque exécution comme un Process Flow.
Le SDK et l'extension sont le seul chemin d'authoring. Les Process Flows sont définis en code avec ce SDK et installés via le téléversement Paramètres → Plateforme → Extensions → Sources de la plateforme. Il n'y a pas d'éditeur in-app. Une fois une extension installée, les administrateurs d'espace de travail activent le modèle pour un environnement depuis Extensions, le rendant instanciable dans les Process Flows.
Vous ne voulez pas écrire ce code à la main ? Voir Créer une extension avec un agent de codage IA — décrivez les étapes, tâches et approbations en langage courant et laissez un outil comme Claude Code, Cursor ou GitHub Copilot faire le travail avec le SDK.
Les archives de process flow sont des données pures. L'archive est du JSON — aucun code exécutable ne figure jamais dans l'archive. La logique personnalisée est référencée par ID contre des workflows système ou organisationnels.
Scrydon extension archives. Les process flows sont distribués sous forme d'archives .scrydon-extension.tar.gz qui regroupent le flow avec son ontologie (et, dans les prochaines versions, les seeds KB et les block extensions). L'extension s'importe atomiquement — installation de l'ontologie, rebind slug → class ID tenant, matérialisation du process flow, le tout en une seule transaction. Construisez avec bunx @scrydon/sdk-authoring extension build ; inspectez avec bunx @scrydon/sdk-authoring extension inspect. Voir la spec et packages/sdk-authoring/src/extensions/container/examples/ai-boardroom/ pour un exemple fonctionnel.
Installation
bun add -d @scrydon/sdk-authoring zodnpm install --save-dev @scrydon/sdk-authoring zodimport {
defineProcessFlow,
defineStage,
defineTask,
defineAction,
definePersona,
defineVoiceTrigger,
} from '@scrydon/sdk-authoring/process-flows'Anatomie d'un modèle
| Élément | Rôle |
|---|---|
| Package | Identité de l'archive : id, name, version |
| Template | Le flow lui-même — vue par défaut, configuration d'exécution, métadonnées |
| Persona | Rôles auxquels une tâche peut être assignée (one, many ou system) |
| Attribute | Un fait typé et classifié que porte chaque exécution — l’e-mail d’un client, une référence de dossier |
| Stage | Une phase ordonnée. Les transitions sont manual, automatic ou approval |
| Task Template | Éléments de travail à l'intérieur des étapes. Portent des actions, des dépendances, des attributs par défaut |
| Action Template | Ce que la tâche demande à l'utilisateur de faire — checklist, document, approval, workflow, entity_link, file_upload, distribution, voice_trigger, map, form, destruction, persona_assignment |
| Voice Trigger | Bloc d'enrichissement vocal optionnel délimité à un chemin |
Un exemple complet
import {
defineProcessFlow,
defineStage,
defineTask,
defineAction,
definePersona,
} from '@scrydon/sdk-authoring/process-flows'
export default defineProcessFlow({
manifestVersion: 1,
package: {
id: 'acme-kickoff',
name: 'Acme Customer Kickoff',
version: '1.0.0',
},
template: {
slug: 'acme-kickoff',
name: 'Customer Kickoff',
description: 'Standard onboarding flow for new enterprise customers',
version: '1.0.0',
defaultView: 'wizard',
executionConfig: {
stageFlow: 'sequential',
taskFlow: 'parallel',
allowRuntimeTaskCreation: true,
},
metadata: {
icon: 'rocket',
color: '#2563eb',
tags: ['onboarding', 'sales'],
},
personas: [
definePersona({ slug: 'csm', displayName: 'Customer Success Manager', cardinality: 'one' }),
definePersona({ slug: 'champion', displayName: 'Customer Champion', cardinality: 'one' }),
definePersona({ slug: 'system', displayName: 'System', cardinality: 'system' }),
],
stages: [
defineStage({
slug: 'discovery',
name: 'Discovery',
transitionMode: 'manual',
estimatedDuration: { value: 5, unit: 'days' },
}),
defineStage({
slug: 'rollout',
name: 'Rollout',
transitionMode: 'approval',
}),
],
taskTemplates: [
defineTask({
slug: 'collect-stakeholders',
stageSlug: 'discovery',
name: 'Collect stakeholders',
defaultAssignedRoleSlug: 'csm',
actions: [
defineAction({
name: 'Stakeholder list',
actionType: 'document',
isRequired: true,
metadata: { persona: 'csm' },
}),
],
}),
defineTask({
slug: 'kickoff-call',
stageSlug: 'discovery',
name: 'Kickoff call',
dependsOnTaskSlugs: ['collect-stakeholders'],
actions: [
defineAction({
name: 'Record kickoff call',
actionType: 'voice_trigger',
isRequired: true,
metadata: { triggerPath: '/kickoff/' },
}),
defineAction({
name: 'Capture summary to KB',
actionType: 'workflow',
isRequired: false,
workflowId: 'system.summarize-meeting',
metadata: { promoteToCorpus: 'summary' },
}),
],
}),
defineTask({
slug: 'rollout-plan',
stageSlug: 'rollout',
name: 'Approve rollout plan',
dependsOnTaskSlugs: ['kickoff-call'],
actions: [
defineAction({
name: 'Approve plan',
actionType: 'approval',
isRequired: true,
metadata: { persona: 'champion' },
}),
],
}),
],
voiceTriggers: [],
},
})Types d'actions
| Type d'action | Utiliser pour |
|---|---|
checklist | Une tâche simple que l'utilisateur marque comme terminée |
document | Un document que l'utilisateur doit produire ou joindre |
approval | Une porte d'approbation — assignée à un persona, bloque les tâches en aval jusqu'à l'accord. Rejeter la porte (le bouton Rejeter) arrête le flow : la tâche de la porte reste ouverte et aucune étape en aval ne se débloque, que l'action d'approbation soit marquée comme obligatoire ou non, jusqu'à ce que la porte soit redécidée en approuvée, ou ignorée en tant que dérogation explicite |
workflow | Référencer un workflow exécutable — soit par workflowId (un workflow système ou org déjà existant dans le tenant) soit par workflowSlug (un workflow distribué dans la même extension — voir Workflows). Les deux sont mutuellement exclusifs |
entity_link | Lier la tâche à une instance d'objet typé via l'ontologie |
file_upload | Un dépôt de fichier — les octets sont ingérés dans la KB de l'instance |
distribution | Envoyer vers un canal (email, cortex, slack, teams) ; supporte le quorum, fire-and-forget, all-acknowledged |
voice_trigger | Capturer de l'audio contre un chemin — le STT s'exécute et la transcription alimente la KB |
map | Afficher une couche géographique gouvernée et enregistrer une classification d'opérateur par élément |
form | Recueillir des réponses typées et les transmettre sans les conserver — seul l'envoi est enregistré |
destruction | Supprimer les copies, détenues par la plateforme, des fichiers qu'une tâche précédente a recueillis (ou attester une suppression ailleurs) et enregistrer le résultat : verified, attested ou failed |
persona_assignment | L'assigné choisit qui tient un persona (metadata.assignsPersona) — one remplace le titulaire, many en ajoute ; les tâches qui dépendent de l'étape restent verrouillées jusqu'au choix |
Voir Types d'actions pour une analyse approfondie par type avec des exemples prêts à copier-coller, des notes sur l'UX à l'exécution, et les champs de métadonnées que chaque type lit.
Qui est prévenu d'une tâche
Le defaultAssignedRoleSlug (son persona) et l’échéance (dueOffsetDays ou due) de chaque modèle de tâche pilotent la liste de travail de la plateforme et ses notifications :
- À la création d'une instance, sa distribution est d'abord constituée : les affectations de personas de l'instance la plus récente du même flux dans l'environnement y sont copiées. Toute persona encore vide est pourvue à partir du rôle fonctionnel qu'elle déclare.
- Toute personne qu'une tâche de la première étape attend (affectée nommément, ou à une persona qu'elle détient) reçoit ensuite une seule notification
process.instance_created. Elle liste les tâches de la première étape qui l'attendent, avec leurs échéances. Un modèle qui ouvre huit tâches d'un coup envoie un seul message à chaque participant, pas neuf. Faire partie de la distribution ne suffit pas : une personne dont le travail vient plus tard est prévenue à l'ouverture de sa tâche, pas au démarrage. Les administrateurs de l'organisation sont prévenus que le flux a démarré sans personne pour faire le travail lorsque la distribution est vide, ou lorsqu'une tâche de la première étape attend une persona que personne ne détient. - Quand une tâche s'ouvre plus tard (dépendance terminée, passage dans une étape, tâche ajoutée ou (ré)affectation), les personnes qu'elle attend reçoivent
process.task_assigned, une fois chacune. Il s'agit de la personne affectée, ou des titulaires de sa persona sur cette instance. Une personne nouvellement affectée à une persona est informée des tâches ouvertes qui l'attendent déjà. Une personne qui la détenait déjà n'est pas relancée lorsque la distribution est modifiée. - Quand une tâche ouverte dépasse son échéance, ces mêmes personnes reçoivent
process.task_sla_breached, une fois. Le journal d'activité du flux enregistre le dépassement.
La même règle détermine ce que « Needs me » liste sur le tableau de bord Flows et ce qu'affiche la liste de travail Home de Horizon : une tâche assignée à personne et revendiquée par aucun persona n'apparaît pour personne — la page de l'instance le signale et propose d'assigner le persona.
Chacune de ces notifications arrive dans la boîte de réception de l'application et par e-mail. L'e-mail contient un bouton qui ouvre la tâche, ou le flux lorsque plusieurs tâches sont listées.
Pourvoir une persona depuis l'organigramme
Une persona peut nommer le rôle fonctionnel de l'organigramme qui l'occupe normalement. Une instance que personne n'a pourvue, ce qui est le cas par défaut de toute instance démarrée par un déclencheur, pourvoit alors cette persona depuis l'organigramme :
definePersona({
slug: 'approver',
displayName: 'Access Approver',
cardinality: 'one',
functionalRole: {
slug: 'access-approver',
// Facultatif : un chemin pointé dans le contexte de l'instance, contenant un slug de département.
departmentFromContext: 'request.department',
},
}),| Champ | Type | Description |
|---|---|---|
functionalRole.slug | string (slug) | Le rôle fonctionnel dont les titulaires pourvoient cette persona. |
functionalRole.departmentFromContext | string (chemin pointé), facultatif | L'endroit du contexte de l'instance qui contient le département à interroger. Les titulaires propres au département sont utilisés en premier. S'il n'en a aucun, les titulaires à l'échelle de l'organisation les remplacent. Sans ce champ, ce sont les titulaires à l'échelle de l'organisation qui sont utilisés. |
Les règles :
- Le choix d'un opérateur prime. Une persona qui a déjà un titulaire, reporté de l'exécution précédente ou affecté à la main, n'est jamais modifiée.
- Pourvoir, c'est affecter. Les titulaires du rôle sont enregistrés comme affectations de la persona, marquées comme faites par
system:functional-roledans le journal d'activité de l'instance. Ils peuvent donc agir, y compris approuver une porte routée vers cette persona, et peuvent être remplacés depuis la fenêtre des personas comme n'importe qui. - Une persona
cardinality: 'one'n'est jamais devinée. Si le rôle a plusieurs titulaires à ce niveau, personne n'est affecté et la persona apparaît comme non pourvue. - Un département inconnu n'est pas élargi. Si le contexte nomme un département que l'organisation n'a pas, personne n'est affecté : il n'y a pas de repli sur l'organisation.
- Une persona
systemne peut pas déclarer de rôle fonctionnel.
Quand une étape atteint une persona encore vide, la plateforme interroge à nouveau le rôle. Cela couvre un rôle qui n'avait pas de titulaire au démarrage de l'instance. Les destinataires suivent alors cet ordre : les titulaires de la persona, puis le rôle fonctionnel déclaré, puis un rôle d'organisation portant le même slug que la persona, et enfin les administrateurs de l'organisation. Les administrateurs joints de cette façon ne reçoivent qu'un avis de dotation. Ils ne reçoivent ni le contenu ni le droit d'approuver.
Qui peut terminer une étape
Terminer une étape (soumettre un formulaire ou une décision cartographique, modifier ou approuver une action, exécuter son workflow, choisir une persona, approuver ou rejeter une transition d'étape) est permis :
- à un administrateur ou propriétaire de l'espace de travail ;
- à la personne qui a créé l'instance ;
- à la personne assignée à la tâche : l'utilisateur à qui la tâche est assignée, ou un titulaire de la persona de la tâche sur cette instance. Elle doit être membre de l'espace de travail. C'est ce qui permet aux personnes qu'une instance démarrée par un déclencheur pourvoit depuis l'organigramme d'agir : une telle instance est créée par la plateforme, personne d'autre ne la détient.
Une personne assignée ne peut terminer que sa propre tâche. Elle ne peut pas terminer une autre tâche de la même instance, ni annuler ou relancer une étape, déplacer une tâche, renvoyer une carte en arrière, ou terminer ou rouvrir l'instance ; cela reste réservé aux administrateurs, aux propriétaires et au créateur. Une porte d'approbation qui nomme une persona exige aussi d'en être titulaire.
Routage des portes d'approbation
Lorsqu'une étape a transitionMode: "approval", la plateforme notifie les bonnes personnes dès qu'une tâche atteint la porte. Trois champs de defineStage déterminent qui est notifié et combien d'approbations sont requises :
| Champ | Type | Valeur par défaut | Description |
|---|---|---|---|
approverPersona | string (slug) | les administrateurs de l'organisation | La persona dont les membres actuels reçoivent la notification de demande d'approbation. Lorsque personne ne détient la persona, elle se replie sur un rôle d'organisation portant le même slug, puis sur les administrateurs de l'organisation. Seule une personne affectée à la persona peut réellement approuver : ce repli prévient quelqu'un qui peut la pourvoir, il n'accorde pas le droit d'approuver. |
resolutionMode | "first_claim" | "all_must_approve" | "quorum" | "first_claim" | Lorsque plusieurs approbateurs sont notifiés, détermine la règle de décision. first_claim — n'importe quel approbateur peut décider. all_must_approve — chaque utilisateur notifié doit approuver. quorum — au moins quorumN approbateurs doivent approuver. |
quorumN | number (entier ≥ 1) | — | Obligatoire lorsque resolutionMode: "quorum". Le nombre minimal d'approbations nécessaires. |
Lorsque la porte est atteinte, la plateforme envoie une notification process.approval_requested à chaque utilisateur résolu et affiche « Approval request sent · N notified · sent <date> » dans le panneau de la tâche d'approbation.
Exemple — porte juridique avec quorum :
defineStage({
slug: 'legal-review',
name: 'Legal review',
transitionMode: 'approval',
approverPersona: 'legal-reviewer',
resolutionMode: 'quorum',
quorumN: 2,
})Le flow s'arrête à la porte jusqu'à ce que le quorum soit atteint. Rejeter la porte arrête le flow quel que soit le nombre d'approbations — un seul rejet est toujours définitif.
Ancrer une étape IA dans les documents de l’espace de travail (metadata.retrieval)
La direction inverse : une action workflow qui exécute un agent — un agent intégré
@system/* ou un workflow d'extension/canvas (inline ou frère) — peut être
ancrée dans un ou plusieurs documents téléversés plus tôt dans le flow, de sorte que l’agent raisonne sur des entrées réelles plutôt que sur le nom de la tâche seul. Déclarez-le avec
metadata.retrieval sur l'action :
defineAction({
name: "AI Qualification Assessment",
actionType: "workflow",
isRequired: false,
executionMode: "automatic", // run when the stage is entered
workflowId: "@system/agent-project-qualifier",
metadata: {
aiAgent: "project-qualifier",
// Where the agent result lands, by target ACTION TYPE (see below):
// an assessment on this workflow step itself, and an advisory banner
// on the flow's human approval action.
outputSurface: [
{
kind: "workflow",
contentType: "project_qualification_assessment",
pageTitle: "AI Qualification Assessment",
},
{
kind: "approval",
targetTaskSlug: "go-no-go-decision",
advisorySource: "ai-qualification",
},
],
retrieval: {
// The document(s) the agent must judge. `fromTask` is the slug of an
// earlier task: its completed document action's page, its file_upload
// action's ingested documents, and/or its workflow (agent) action's
// assessment page are resolved as stable, source-level entries.
inputs: [{ fromTask: "upload-source", mode: "full" }],
// Maximum optionnel par source. Le budget exact du bloc rendu partagé
// peut attribuer moins après comptage des titres, états et marqueurs.
// Valeur omise → full : 24 000 ; summary : 4 000.
inputDocMaxChars: 60_000,
},
// Maximum optionnel par défaut pour la réponse que cette étape PRODUIT.
// En mots, pas en pages : « une page » n'a pas de sens en Markdown, et une
// limite ne vaut la peine d'être déclarée que si quelque chose la vérifie.
// Fixez une valeur basse sur les étapes dont la sortie est diffusée ; laissez-la
// vide sur les documents de travail internes.
maxWords: 800,
},
})| Champ | Signification |
|---|---|
retrieval.inputs[] | { fromTask, mode }. Charge les documents sources produits à fromTask (un slug de tâche) : page de l'action document, pages issues de ses téléversements file_upload et/ou page d'évaluation de son action workflow agent. Les emplacements connus de la tâche font autorité ; la sélection lexicale dans la KB n'est utilisée qu'en l'absence d'emplacement déterministe et porte la mention Documents pertinents sélectionnés, sans prétendre représenter l'inventaire complet. Une étape agent amont doit déclarer outputSurface: "workflow" pour créer la page que l'étape aval peut charger. mode: "full" (par défaut) livre un préfixe textuel fidèle et n'est jamais résumé. mode: "summary" condense chaque source trop longue séparément ; en cas d'absence, d'échec, de capacité épuisée ou de délai dépassé du résumé, un extrait local clairement marqué est utilisé. Les entrées sont lues sous l'identité de la personne assignée à l'étape, sinon de celle qui tient son persona, à son habilitation. Une étape IA que personne ne prend en charge les lit sous l'identité de son appel au modèle : le compte Run As de son workflow, qui exige Knowledge (Read) et l'appartenance à l'espace de travail, sinon la personne qui a créé l'instance. Une instance créée par le workflow d'une extension n'a pas de créateur sous lequel lire : sans Run As, ses entrées sont signalées comme illisibles. |
retrieval.inputDocMaxChars | Entier positif optionnel (maximum 200 000). Il s'agit d'un maximum par source : plafond du préfixe fidèle en mode full, ou cible de condensation en mode summary. Le budget partagé, adapté à la fenêtre du modèle, compte le bloc rendu exact — titre de section, état de couverture, titres des sources, séparateurs, corps et marqueurs de troncature — ; une source peut donc recevoir moins que ce maximum. Valeur omise → summary : 4 000 ; full : si la fenêtre du modèle est connue, la plus grande valeur entre 24 000 et une part égale du budget répartie entre les sources full de l'étape (un modèle à grande fenêtre reçoit donc les sources entières au lieu de les condenser), sinon 24 000. Si la fenêtre du modèle est inconnue, l'interface signale une estimation opérationnelle fixe sans affirmer que l'invite entière tient. |
maxWords | Entier positif optionnel, entre 50 et 20 000. Nombre maximal de mots par défaut pour la réponse que produit cette étape. C'est le pendant de retrieval.inputDocMaxChars, qui ne borne que ce qui entre. L'étape le transmet à la plateforme sous la forme outputConstraints: { maxWords } à chaque complétion de modèle qu'elle effectue, si bien que la limite est appliquée de la même façon pour tout appelant de ai.llm.complete (voir SDK TypeScript → outputConstraints). La plateforme insère la limite dans l'invite, compte les mots de la réponse et condense une seule fois une réponse trop longue. Si elle dépasse encore après ce passage, elle est publiée en entier et l'étape signale le dépassement au lieu de jeter le travail. Une réponse condensée est signalée à côté de la sortie par son nombre de mots et la mention raccourci, pour ne jamais la confondre avec une réponse qui tenait du premier coup. Un mot est un segment séparé par des espaces contenant une lettre ou un chiffre ; la syntaxe Markdown (##, barres de tableau, ---) ne compte pas. La personne qui exécute le flux peut remplacer ou effacer la limite d'une étape à l'exécution, et sa valeur l'emporte. Cela vaut pour toutes les étapes IA : les agents @system/*, y compris ceux qui répondent en JSON, et les workflows canvas. Pour une réponse JSON, seules les valeurs de type chaîne sont comptées, et la version condensée doit garder exactement les mêmes clés, de sorte qu'un verdict reste lisible par la machine. Sur un workflow canvas, la limite s'applique à la complétion de chaque bloc Agent de cette exécution ; elle n'est pas transmise à un workflow enfant appelé par le canvas. Définir une limite sur une étape qui n'exécute aucun agent est refusé (output-word-cap-unsupported, HTTP 400) plutôt que stocké là où rien ne la lit. |
outputSurface | Optionnel. Une sélection ou un tableau. Le kind de chaque sélection est le type d'action cible sur lequel le résultat atterrit, plus la configuration par surface. kind: "workflow" écrit l'évaluation sur l'étape agent elle-même ET comme page plafonnée par habilitation dans la KB d'instance (contentType, pageTitle) : une réponse au format verdict (JSON {verdict, confidence, rationale, …}) rend la mise en page verdict ; toute autre réponse (prose, autres schémas JSON) rend le texte propre de l'agent comme corps de page. kind: "approval" fusionne un conseil d'une ligne sur l'action de décision de la tâche nommée par targetTaskSlug (advisorySource étiquette sa provenance). Les candidates sont les actions de décision propres à cette tâche plus celles de chaque étape (les actions d'étape sont apposées sur une tâche lorsqu'elle entre dans l'étape). Pour en choisir une, donnez un slug d'action à la porte et ajoutez targetActionSlug. Sans lui, l'unique porte propre de la tâche le reçoit ; plusieurs portes propres → la première dans l'ordre de la tâche ; aucune porte propre → l'unique porte d'étape, ou rien s'il y en a plusieurs. Plusieurs portes propres comme plusieurs portes d'étape émettent un avertissement à la construction et le journal nomme les candidats ; un targetActionSlug qui ne correspond à aucune action de décision fait échouer la construction (détails). Les autres types d'action sont réservés pour les futures surfaces. Les surfaces ne sont jamais implicites — une étape agent sans outputSurface n'écrit aucune page d'évaluation. |
mode: "summary" entraîne des pertes : ne l'utilisez pas pour une notation
critique de conformité. Ce mode est optimisé pour la lisibilité et pour tenir
dans la fenêtre de contexte du LLM ; il ne garantit pas une représentation sans
perte de chaque fait. Pour les tâches critiques de conformité — évaluation stricte
d'appel d'offres, notation juridique ou contractuelle — combinez mode: "full" avec
le canal de lecture à la demande (<start.processFlow.knowledgeBaseId> et les
outils RAG de connaissance), afin que l'agent puisse récupérer à la demande les
critères déterminants pour la décision. Le mode
full peut lui aussi être tronqué ou omis par la capacité partagée exacte ; toute
perte est explicitement signalée.
Le panneau Invite & Contexte affiche une ligne pour chaque source connue et stable, y compris les documents homonymes. Il distingue les sources représentées, omises faute de capacité, illisibles et livrées par extrait après échec du résumé ; seules les sources dont du contenu a été livré contribuent aux références de sortie. La préparation est limitée à 500 sources inventoriées, 1 Mo par corps chargé, 8 Mo pour l'ensemble des entrées déclarées, 24 appels de résumé avec une concurrence de 6 et 60 secondes. Si l'inventaire autorisé ne peut pas être achevé dans sa limite de sources ou de temps, la préparation s'arrête avec une erreur générique avant l'exécution du modèle agent. Une fois l'inventaire achevé, l'expiration du délai de résumé utilise le repli local et clairement marqué décrit ci-dessus.
Aujourd'hui workflow (évaluation sur l'étape) et approval (conseil sur une action d'approbation cible) sont les surfaces de sortie implémentées. La spécification retrieval elle-même est générique et fonctionne pour toute étape workflow portant un agent nécessitant un ancrage — les agents intégrés @system/* reçoivent automatiquement le contexte assemblé comme message utilisateur, tandis que les workflows d'extension/canvas doivent en plus référencer <start.processFlowContext> dans un bloc pour le recevoir (voir Recevoir le contexte du process flow — sans cette référence, le contexte assemblé est perdu).
Une base de connaissances pour chaque exécution (knowledge.scope)
Par défaut, chaque exécution d'un process flow obtient sa propre base de
connaissances. Définissez knowledge.scope: "template" et chaque exécution de
ce flow dans un environnement d'espace de travail écrit alors dans une seule
base de connaissances partagée :
template: {
// …
knowledge: { scope: "template" },
}- La base partagée est créée lors de la première exécution du flow dans un environnement et apparaît dans la liste des bases de connaissances de l'espace de travail, avec le badge Process flow.
- Chaque exécution possède un dossier,
instances/<date>-<run name>-<id>/, qui contient ses téléversements, documents, transcriptions et résumé de clôture. Les étapes IA lisent le dossier de leur propre exécution ainsi que tout ce qui se trouve en dehors deinstances/— le matériel de référence téléversé à la racine de la base par les membres est donc disponible pour toutes les exécutions. - Les exécutions précédentes déjà terminées servent d'ancrage aux exécutions suivantes via leurs propres dossiers.
- Supprimer une exécution ne supprime que son dossier ; supprimer la base depuis la page de connaissances est autorisé et l'exécution suivante en provisionne une nouvelle.
- Les exécutions démarrées avant que le flow ne déclare
templateconservent leur propre base.
Si vos workflows adressent directement la base. Une étape canvas qui lit
<start.processFlow.knowledgeBaseId> obtient la base partagée avec
scope: "template" : elle voit donc le dossier de chaque exécution, sauf si
elle se restreint elle-même. Le chemin du dossier propre à l'exécution est
exposé sous la forme <start.processFlow.knowledgeBaseFolder>. La valeur est
instances/<date>-<run name>-<id>, le dossier auquel ou sous lequel se trouve
chaque page de l'exécution : elle peut être collée telle quelle dans le
Folder (path scope) du bloc Knowledge, qui restreint à la fois Search et
Add Data (Knowledge). L'outil de connaissance d'un agent
n'est pas restreint pour vous : pour une étape d'IA, préférez l'ancrage par
entrées déclarées (metadata.retrieval), qui est délimité au dossier pour
vous. Un workflow qui démarre une exécution avec create_process_instance
obtient ces deux mêmes valeurs dans les sorties knowledgeBaseId et
knowledgeBaseFolder de ce bloc
(Blocs plateforme).
scope: "instance" (la valeur par défaut) conserve le comportement actuel.
Reprendre les exécutions précédentes (knowledge.priorCycles)
Une nouvelle exécution peut s'appuyer sur ce que les exécutions précédentes du même flow ont décidé. Par défaut, elle reprend les cinq exécutions terminées les plus récentes du même environnement d'espace de travail :
- ses étapes IA reçoivent les extraits pertinents de ces exécutions, et
- les conversations partagées de ses étapes reçoivent le résumé de clôture de chaque exécution et peuvent rechercher dans leurs pages ; une question comme « qu'avons-nous décidé la dernière fois ? » reçoit une réponse fondée sur ces exécutions, qui les cite.
Définissez le nombre par flow :
template: {
// …
knowledge: {
scope: "template",
priorCycles: { maxCycles: 3 },
},
}maxCyclesest un entier de0à10;0désactive la reprise.- Omettez
priorCyclespour suivre la valeur par défaut de la plateforme (actuellement 5). - La valeur est figée dans chaque exécution à son démarrage : publier une nouvelle version de l'extension ne modifie pas une exécution en cours.
- Une étape IA peut toujours la remplacer avec
metadata.priorCycles.maxCycles, ou s'en exclure avecexcludeContext: ["priorCycles"]. - Fonctionne avec les deux valeurs de
scope. Les exécutions en cours, les exécutions annulées et les pages classifiées au-dessus de l'habilitation du lecteur ne sont jamais reprises.
Attributs d’instance (template.attributes)
Déclarez une seule fois, sur le modèle, les faits que porte chaque exécution du flow — qui est le client, de quel dossier il s’agit. Chaque attribut est une propriété d’ontologie : un slug, un nom d’affichage, un type, une cardinalité et une classification.
import { defineAttribute } from "@scrydon/sdk-authoring/process-flows";
template: {
// …
attributes: [
defineAttribute({
slug: "customerEmail",
displayName: "Customer email",
scalarType: "string",
cardinality: "required",
classification: "confidential",
piiFlags: ["email"],
}),
defineAttribute({
slug: "caseReference",
displayName: "Case reference",
scalarType: "string",
cardinality: "optional",
classification: "internal",
}),
],
}- Les types sont les types scalaires de l’ontologie :
string,int,float,bool,uuid,timestamp,date,json,bytes.cardinality: "many"accepte une liste. - Les valeurs sont vérifiées à l’écriture — au démarrage d’une exécution (y
compris la valeur initiale d’un bloc
create_process_instance) et quand un opérateur les modifie. Un attribut obligatoire absent ou une valeur du mauvais type est refusé avec le code HTTP422et le codeinvalid_instance_attributes, qui liste chaque problème. Les clés non déclarées restent acceptées : les flows écrits avant les attributs continuent de fonctionner. - La classification décide qui voit une valeur.
public,internal,confidentialetrestrictedcorrespondent, dans cet ordre, aux niveaux d’habilitationUNCLASSIFIED,RESTRICTED,CONFIDENTIALetSECRET. Une étape IA ne reçoit qu’un attribut couvert par son habilitation ; les autres apparaissent comme retenus dans le panneau Prompt & Context de l’étape. Sans classification, l’attribut est traité commeUNCLASSIFIED—extension validateavertit lorsqu’un tel attribut porte despiiFlags. - La classification limite ce qu’une personne voit, comme ce qu’un modèle
voit. Le détail de l’exécution (
GET /api/process-flows/:id) ne renvoie danscontextque les attributs couverts par l’habilitation du lecteur : un attributrestrictedest absent pour un lecteur en dessous de SECRET, et un membre sans habilitation lit au rang le plus bas. Quand un opérateur enregistrecontext, un attribut qu’il ne voyait pas et n’a pas envoyé garde sa valeur. La liste des exécutions d’un environnement (GET /api/process-flows) ne renvoie aucune valeur d’attribut.
Lire un attribut
| Où | Comment |
|---|---|
Une étape IA @system | Automatiquement : le prompt de l’étape reçoit un bloc Instance Attributes avec chaque valeur qu’elle peut voir. |
| Une étape de workflow canvas | <start.processFlow.attributes.customerEmail> |
| Les destinataires externes d’une distribution | externalRecipients.recipients: [{ kind: "attribute", key: "customerEmail" }] — voir Types d’actions |
Une valeur absente, retenue ou non conforme à sa déclaration n’est jamais
remplacée par une chaîne vide. Dans une étape canvas, la référence reste du
texte littéral, et le panneau Prompt & Context liste l’attribut avec la raison.
Une référence canvas vers un attribut que le modèle ne déclare pas y est aussi
signalée. Une étape IA peut s’en exclure avec excludeContext: ["attributes"].
Le contexte initial, et ce que les agents en voient
Le context d’une exécution est ce avec quoi elle a démarré, par exemple le
context du bloc create_process_instance qui l’a ouverte. La page de
l’instance l’affiche en lecture seule sous Contexte de l’exécution, replié
par défaut avec le nombre de valeurs. Les clés qui commencent par _ sont des
données internes de la plateforme et ne sont pas listées, et un attribut
au-dessus de votre habilitation est absent, comme dans l’API.
Les agents ne reçoivent que les clés que le modèle déclare dans
attributes. Une clé injectée sans être déclarée est enregistrée et affichée
sur la page de l’instance, mais elle n’atteint jamais un agent : ni le bloc
Instance Attributes d’une étape IA, ni une référence
<start.processFlow.attributes.*>. Pour transmettre l’objet et le corps d’une
réclamation aux agents du flow, déclarez les deux :
attributes: [
defineAttribute({
slug: "subject",
displayName: "Subject",
scalarType: "string",
cardinality: "required",
classification: "internal",
}),
defineAttribute({
slug: "body",
displayName: "Message body",
scalarType: "string",
cardinality: "optional",
classification: "internal",
}),
],Injectez-les ensuite sous les mêmes clés, { "subject": "<start.body.subject>", "body": "<start.body.message>" }. Une référence placée dans une chaîne JSON
est insérée échappée : les sauts de ligne et les guillemets que contient
presque toujours le corps d’un e-mail restent dans la valeur
(Injecter du texte libre dans context).
Comme pour tout attribut, une étape IA ne reçoit une valeur que si son
habilitation couvre la classification de l’attribut.
Valeurs autorisées (oneOf)
Un attribut peut lister les seules valeurs qu’il accepte. Une valeur hors de la
liste est refusée à l’écriture, comme une valeur du mauvais type (422,
invalid_instance_attributes). Les conditions s’appuient sur cette liste pour
vérifier que chaque branche peut être atteinte.
defineAttribute({
slug: "workMode",
displayName: "Work mode",
scalarType: "string",
oneOf: ["remote", "hybrid", "office"],
});oneOf s’utilise avec les attributs string, int, float, bool, uuid,
date et timestamp. Chaque entrée doit correspondre au type de l’attribut, et
la liste ne peut pas répéter une valeur. extension validate signale un problème de
liste avec le code invalid_attribute_one_of.
Tâches conditionnelles (condition)
Certaines tâches ne concernent que certaines exécutions. Par exemple, on
n’envoie un ordinateur qu’à une recrue en télétravail, ou on ne demande une
seconde approbation qu’au-delà d’un seuil. Donnez à une telle tâche une
condition. C’est une expression booléenne sur les attributs d’instance de
l’exécution (voir ci-dessus) :
taskTemplates: [
{ slug: "ship-laptop", stageSlug: "onboard", name: "Ship laptop",
condition: 'workMode == "remote"' },
{ slug: "issue-badge", stageSlug: "onboard", name: "Issue badge",
condition: 'workMode != "remote"' },
{ slug: "legal-review", stageSlug: "review", name: "Legal review",
condition: "contractValue >= 50000 && needsVisa == false" },
{ slug: "wrap-up", stageSlug: "onboard", name: "Wrap up",
dependsOnTaskSlugs: ["ship-laptop", "issue-badge"] },
]Le langage d’expression est réduit :
- les slugs d’attributs comme noms
- des littéraux chaîne, nombre et booléen
- les comparaisons (
==,!=,<,<=,>,>=) &&,||et!- quelques méthodes de valeur, comme
["a","b"].includes(region)
Il s’exécute dans un interpréteur isolé, jamais comme du code. Un slug contenant
- se lit comme une soustraction : donnez aux attributs utilisés dans une
condition un slug sans trait d’union.
Comment une exécution traite une tâche conditionnelle :
| La condition est… | La tâche… |
|---|---|
| vraie | se déroule normalement. |
| fausse | est ignorée (skipped). Elle apparaît comme Ignorée dans toutes les vues, et personne ne peut traiter ses actions. Pour son étape et pour les tâches qui en dépendent, une tâche ignorée compte comme terminée : une branche que l’exécution ne prend pas ne la bloque jamais. |
| pas encore décidable (un attribut qu’elle lit n’a pas de valeur) | reste verrouillée. Elle n’est ni ignorée ni ouverte tant qu’une écriture d’attribut ne l’a pas décidée. |
- Les tâches obligatoires de la branche prise restent exigées. Seules les tâches dont la condition est fausse cessent de compter.
- Les conditions sont réévaluées à chaque modification d’attribut. Une tâche qui n’est pas terminée suit les nouvelles valeurs : une tâche ouverte peut devenir ignorée, et une tâche ignorée revient dans le flux. Effacer une valeur ne décide rien, donc rien ne change.
- Un travail terminé n’est jamais annulé. Une valeur qui change après la fin d’une tâche laisse cette tâche terminée.
- Une étape close reste close. Si l’étape d’une tâche ignorée est déjà
terminée, une modification ultérieure qui rend sa condition vraie ne rouvre
pas l’étape. Le journal d’activité de l’exécution l’enregistre comme
task_revival_refused. Rouvrez l’étape pour la refaire. - Le retour d’une tâche ne reverrouille pas le travail déjà commencé. Les tâches déverrouillées parce qu’une dépendance était ignorée restent ouvertes quand cette dépendance revient.
- Un déplacement manuel est une dérogation. Déplacer une tâche ignorée sur le tableau la remet dans le flux, comme un déplacement ouvre une tâche verrouillée.
extension validate vérifie chaque condition :
| Code | Gravité | Signification |
|---|---|---|
invalid_task_condition | erreur | L’expression ne s’analyse pas, ou échoue pour une valeur autorisée. |
undeclared_condition_attribute | erreur | Elle lit un nom que template.attributes ne déclare pas. |
unreachable_task_condition | erreur | Aucune valeur autorisée ne la rend vraie : la tâche ne pourrait jamais s’exécuter. |
task_condition_always_true | avertissement | Toute valeur autorisée la rend vraie : elle n’ignore jamais la tâche. |
task_condition_discloses_classified_attribute | avertissement | Elle lit un attribut confidential ou restricted. Quiconque voit le flux voit si la tâche a été ignorée. |
L’atteignabilité ne peut être vérifiée que sur des valeurs que le validateur
peut énumérer : les attributs bool et les attributs avec oneOf (jusqu’à 256
combinaisons). Une condition sur un nombre ou une chaîne sans liste, comme
contractValue >= 50000, n’est vérifiée que pour sa syntaxe et ses noms
déclarés.
Échéances (due)
dueOffsetDays: 5 signifie « cinq jours après le démarrage de l’exécution ».
Quand le calendrier s’organise autour d’une date que l’exécution porte — la
date d’arrivée d’un nouveau collaborateur, la signature d’un contrat, un délai
légal — déclarez cette date comme
attribut d’instance et ancrez la
tâche (ou l’action) dessus avec due :
template: {
timezone: "Europe/Brussels", // facultatif — voir ci-dessous
attributes: [
defineAttribute({
slug: "startDate",
displayName: "Date d’arrivée",
scalarType: "date",
cardinality: "required",
classification: "internal",
}),
],
taskTemplates: [
{
name: "Préparer le bureau",
due: {
anchor: { kind: "attribute", key: "startDate" },
offset: { value: -1, unit: "days" }, // la VEILLE de la date d’arrivée
time: "10:00", // à 10:00, heure locale
},
},
{
name: "Appel de lancement",
due: { anchor: { kind: "instance_start" }, offset: { value: 2, unit: "hours" } },
},
],
}- Ancre —
{ kind: "attribute", key }désigne un attribut déclaré de typedateoutimestampà valeur unique ;{ kind: "instance_start" }est le moment où l’exécution a démarré.extension validaterefuse une ancre sur un attribut non déclaré, d’un autre type oumany, ainsi qu’un modèle qui déclare à la foisdueetdueOffsetDays. - Décalage — signé : une valeur négative désigne un travail avant
l’ancre.
daysetweeksdéplacent la date du calendrier en conservant l’heure locale, même lors d’un changement d’heure ;hoursetminutessont du temps écoulé. Sans décalage, la tâche est due à l’ancre. Dix ans au maximum de part et d’autre. - Heure —
"HH:MM", locale, et uniquement avec un décalagedays/weeks(ou aucun). Une ancredatesanstimeest due à la fin de ce jour : une tâche due « le jour de l’arrivée » n’est pas en retard à minuit une. - Fuseau horaire — le calcul se fait dans
template.timezone(un nom IANA commeEurope/Brussels). À défaut, l’exécution utilise le fuseau horaire de l’organisation (Paramètres → Organisation → Fuseau horaire), puisUTC. Le fuseau est figé au démarrage : modifier ensuite celui de l’organisation ne déplace pas les échéances d’une exécution en cours. - Une ancre absente est refusée. Démarrer une exécution sans l’attribut
d’ancrage, ou avec une valeur qui n’est pas une date, échoue en HTTP
422, codeinvalid_instance_attributes, avec un problèmedue_anchor_unresolvedqui nomme l’attribut — même si l’attribut estoptional. Aucune exécution n’est créée. - Une ancre dans le passé est respectée. Une date d’arrivée de la semaine dernière rend la tâche immédiatement en retard ; l’échéance n’est jamais ramenée à « maintenant ».
- Modifier l’ancre déplace l’échéance. Quand un opérateur modifie l’attribut d’un flux en cours, chaque tâche et action ouverte ancrée dessus est redatée. Les tâches terminées ou archivées, et les actions terminées ou ignorées, gardent leur date. Une tâche ignorée par sa condition est redatée elle aussi : elle porte l’échéance actuelle si une modification ultérieure la fait revenir, et tant qu’elle reste ignorée, sa date ne notifie personne. Une échéance déplacée est une nouvelle échéance : si elle est dépassée, les personnes concernées sont notifiées à nouveau.
dueOffsetDays fonctionne toujours à l’identique et reste mesuré en UTC à
partir du démarrage de l’exécution.
Chronomètre du dossier (caseClock)
Pour un flux soumis à un délai serré (« de l’alerte au rapport transmis en
60 minutes »), l’en-tête du dossier peut montrer quelle part du temps cible
s’est écoulée. Marquez un seul modèle de tâche avec caseClock: true, à
côté d’un due ancré sur le démarrage du dossier :
{
slug: "release",
name: "Release the report",
due: { anchor: { kind: "instance_start" }, offset: { value: 60, unit: "minutes" } },
caseClock: true,
actions: [{ name: "Approve the release", actionType: "approval", isRequired: true }],
}Aucun composant ni bloc n’est nécessaire. La plateforme compte depuis le
démarrage du dossier (startedAt, à défaut createdAt) vers l’échéance de
cette tâche, et affiche le résultat dans l’en-tête du dossier uniquement, pour
ce flux uniquement :
- Il tourne jusqu’au premier de ces deux événements : la tâche marquée est terminée (pour une approbation, approuvée), ou le flux se termine (terminé, clôturé comme refusé, ou annulé). Un rejet qui renvoie le travail à une étape antérieure ne l’arrête pas. Un flux mis en pause ne l’arrête pas non plus.
- Il s’arrête quand les actions obligatoires de la tâche marquée sont terminées. L’instant d’arrêt est celui où la dernière d’entre elles s’est achevée. Les actions facultatives ne comptent pas : en terminer une plus tard ne déplace pas l’arrêt. Terminer de nouveau une action obligatoire déjà terminée déplace son heure de fin, et l’arrêt du chronomètre se déplace à ce moment plus tardif.
- Couleurs et mots — vert (« Dans l’objectif ») sous 75 % de la cible, orange (« Proche de l’objectif ») de 75 % jusqu’à 100 % inclus, rouge (« Objectif dépassé ») au-delà. L’état est écrit à côté du temps : il ne dépend pas de la couleur.
- Une fois arrêté, il affiche le temps final, en vert s’il s’est arrêté dans la cible et en rouge au-delà.
- Les longues cibles se lisent en heures et en jours : une cible de 48 heures
s’affiche
2d 0h, et non en minutes. - Un dossier rouvert continue de compter depuis son démarrage d’origine. Le chronomètre mesure la durée totale du dossier, temps de clôture compris.
- Une étape marquée qu’une condition de tâche saute n’est jamais terminée : le chronomètre ne s’arrête alors qu’à la fin du flux.
- Un dossier annulé s’arrête à l’instant de son annulation. Un dossier annulé avant que cet instant soit enregistré n’affiche aucun chronomètre.
extension validate refuse un flux avec plus d’une tâche caseClock, une tâche
caseClock dont le due est ancré sur un attribut plutôt que sur
instance_start (l’ancien dueOffsetDays compte comme instance_start), et une
tâche caseClock sans action obligatoire (isRequired: true). La tâche marquée
reçoit aussi une échéance ordinaire : la liste de travail l’affiche donc en
retard lorsqu’elle la dépasse.
L'objet sur lequel porte une tâche (entityType)
Un modèle de tâche peut déclarer le type d'objet d'ontologie sur lequel il
porte avec entityType, défini sur le nom d'API d'un Object Type :
{ name: "Configure FI", entityType: "sap_module", actions: [/* … */] }entityType ne nomme que le type. Le démarrage d'une exécution ne lie
aucun objet : chaque tâche créée à partir du modèle conserve entityType et
démarre sans objet lié, car la plateforme ne devine jamais un objet à partir du
nom de la tâche.
Une personne de l'exécution lie l'objet depuis la section Linked Entity de la tâche : elle choisit un Object Type lié (le type déclaré est présélectionné), puis recherche l'un de ses objets par nom ou par ID. La tâche enregistre alors l'ID de l'objet, son type, son libellé et l'ontologie dont il provient. Unlink entity retire l'objet et conserve le type déclaré.
Une fois la tâche liée :
- Open in Ontology Designer ouvre l'objet dans le graphe d'instances d'Analytics, sélectionné, avec ses voisins chargés. Si vous ne pouvez pas voir l'objet, le graphe l'indique.
GET /api/process-flows/{id}/tasks/{taskId}/related-instancesliste les autres exécutions dont une tâche est liée au même objet : le même type et le même ID. Une tâche sans objet lié n'en liste aucune.- Un workflow intégré lit l'objet sous la forme
<start.processFlow.entity.*>(voir Workflows intégrés).
L'API de mise à jour des tâches applique la même règle : un entityRef envoyé
sans son entityType est refusé avec HTTP 400, de même que l'effacement
d'entityType lorsqu'un entityRef subsiste.
Validation du DAG de tâches
Les tâches peuvent déclarer :
dependsOnTaskSlugs— d'autres tâches qui doivent d'abord se terminerunlockAfterTaskSlug+unlockDelay— une porte douce qui s'ouvre N jours/semaines après la fin d'un prédécesseur
Une tâche assortie d'un unlockDelay devient active à l'échéance prévue, que
quelqu'un ouvre le flux ou non. Un balayage de fond s'exécute toutes les heures :
il active chaque tâche dont le délai est écoulé, déclenche ses actions
automatic et notifie l'approbateur lorsque la tâche porte une étape
d'approbation.
C'est déterminant en fin de flux, là où vivent la plupart des tâches différées : un point à J+7 ou une revue à J+30 est en général la dernière tâche de son instance — aucune tâche ultérieure ne peut la déclencher, et personne n'a de raison de rouvrir un flux dont le travail visible est terminé. Comptez au plus une heure après l'échéance.
Le CLI inspect exécute la détection de cycle DFS (BLANC/GRIS/NOIR) et échoue fermement sur tout cycle. Codes d'erreur stables :
| Code | Signification |
|---|---|
task_cycle | Une arête de dépendance participe à un cycle |
unknown_dep_slug | dependsOnTaskSlugs référence un slug de tâche inconnu |
stage_unknown | taskTemplates[].stageSlug ne correspond à aucune étape |
Extensions nécessaires à un flux
Vous ne listez pas les extensions dont dépend un flux : la plateforme les
déduit. Chaque type de bloc utilisé par les workflows du flux compte : un
bloc posé sur le canevas (microsoft-teams) et chaque outil qu’un bloc agent
peut appeler (sa liste d’outils). Cela inclut les workflows que le flux atteint
sans les définir en ligne — ceux livrés comme contenu workflow distinct de la
même extension.
Chaque type de bloc déduit qui appartient à une extension est vérifié dans l’espace de travail où le flux est activé. Il peut être inutilisable pour trois raisons :
| Raison | Signification | Action de l’administrateur |
|---|---|---|
not_installed | L’extension qui fournit le bloc n’est pas installée dans l’organisation | L’installer depuis Paramètres → Plateforme → Extensions |
not_connected | Elle est installée, mais aucun compte n’y est connecté | Connecter un compte dans l’onglet Connexions de l’extension |
not_entitled | Elle est installée et connectée, mais pas activée pour cet espace de travail | L’activer pour l’espace de travail |
Un bloc que la plateforme exécute sans aucune connexion n’est jamais signalé : celui d’une extension activée par défaut qui n’exige ni identifiant ni paramètre obligatoire — la plupart des blocs Scrydon intégrés. Cela vaut jusqu’à ce qu’un administrateur ajoute une connexion pour lui ; dès lors, cette connexion est vérifiée comme toute autre.
Le résultat dépend du moment de la vérification :
- L’activation d’un flux dans un espace de travail est refusée. Activer dans Extensions échoue avec un message qui nomme chaque bloc et sa raison, et le flux reste désactivé. Corrigez ce qui est nommé, puis réactivez-le. L’installation d’une extension à l’échelle de l’organisation n’est jamais refusée : il n’y a encore aucun espace de travail à vérifier.
- La mise à jour ou la réparation d’un flux ne fait que signaler. Un flux déjà activé dans un espace de travail continue d’être mis à jour vers une version plus récente, et d’être réparé, même lorsqu’un bloc est inutilisable. Refuser l’une ou l’autre n’empêcherait pas le flux d’échouer à cette étape ; cela bloquerait seulement la correction. Le manque est tout de même vérifié et journalisé. La suppression d’un flux n’est jamais vérifiée.
- Le démarrage d’une exécution ne fait qu’avertir. Un compte peut être
déconnecté après l’activation du flux. L’exécution démarre quand même ; la
vérification inscrit une entrée
extension_requirements_unmetdans le journal d’activité de l’exécution, qui nomme chaque bloc et sa raison, et la page de l’exécution affiche un avertissement compact au-dessus du tableau qui les liste, avec un lien vers Paramètres → Plateforme → Extensions, où un administrateur de l’organisation corrige chacune, afin que l’étape qui échouera plus tard ait déjà son explication. L’avertissement reflète ce qui manquait au démarrage de l’exécution : corriger l’extension permet aux étapes suivantes de réussir, mais l’avis reste sur cette exécution comme trace.
template.requirements.integrations ne pilote pas la vérification : c’est
l’ensemble déduit qui le fait. Conservez-le comme note pour les lecteurs, en
nommant des extensions (microsoft) et non des canaux de distribution.
extension build échoue lorsqu’une entrée est un canal
(extension_is_distribution_channel : slack, email, configurés par action
distribution) ou lorsque le modèle n’atteint aucun workflow
(extension_unreachable_no_workflows), de sorte que rien de ce qu’il déclare ne
peut servir. L’installation d’une archive construite avant l’existence de ces
vérifications ne fait qu’avertir avec le même code : une extension qui
s’installait auparavant continue de s’installer, et la construction suivante
échoue tant que l’entrée n’est pas corrigée.
Les opérateurs peuvent désactiver le refus avec la valeur Helm
auth.enforceProcessFlowRequirements: false (elle définit
SCRYDON_PROCESS_FLOW_REQUIREMENTS_ENFORCE=false sur api-platform ; voir la
référence Helm). La vérification s’exécute
toujours et journalise ce qu’elle aurait refusé.
Déduire l’ensemble vous-même
La déduction exécutée par la plateforme est exportée, de sorte qu’un script de construction ou une vérification CI peut montrer ce qui sera vérifié pour un flux avant son téléversement :
import {
collectBlockTypesFromWorkflowDefinition,
deriveRequiredBlockTypes,
} from "@scrydon/sdk-authoring/process-flows/derive-block-types";
deriveRequiredBlockTypes(manifest); // types de blocs triés et dédupliqués des workflows en ligne
collectBlockTypesFromWorkflowDefinition(workflow.definition); // un workflow, p. ex. un contenu workflow distinctLes deux sont purs : aucun réseau, aucun état de la plateforme. Ils renvoient des
types de blocs (microsoft-teams), pas des extensions ; la plateforme fait
correspondre chaque type de bloc à l’extension qui le fournit lors de la
vérification.
Stabilité. @scrydon/sdk-authoring/process-flows/derive-block-types fait
partie de la surface publique du SDK et suit le semver du paquet : le sous-chemin,
les noms des deux fonctions et leurs signatures ne changent que dans une version
majeure. L’ensemble renvoyé peut s’agrandir dans une version mineure lorsque le
schéma de workflow gagne un nouvel endroit où nommer un type de bloc, car il doit
continuer à correspondre à ce que la plateforme vérifie.
Capacités de la plateforme nécessaires à un flux
Les extensions sont déduites ; les capacités de la plateforme — un modèle de
langage IA, la reconnaissance vocale, la recherche web — sont déclarées.
Listez-les dans template.requirements :
requirements: {
// Le flux ne peut pas faire son travail sans elles : son activation est refusée.
capabilities: ["stt"],
// Les étapes qui les utilisent sont facultatives : le flux s’exécute sans elles.
optionalCapabilities: ["llm"],
},| Champ | Lorsqu’elle n’est pas disponible |
|---|---|
capabilities | L’activation du flux est refusée, comme pour une extension inutilisable. Le démarrage d’une exécution ne fait qu’avertir. |
optionalCapabilities | Rien n’est refusé. La page de l’exécution affiche un avis d’information : les étapes qui l’utilisent ne peuvent pas produire de résultat, mais elles sont facultatives et ne bloquent donc pas l’exécution. |
Ne déclarez une capacité comme requise que lorsqu’une étape requise en
dépend — par exemple une étape IA avec isRequired: true. Si toutes les étapes
IA sont facultatives, placez llm dans optionalCapabilities, sinon le flux est
refusé dans des espaces de travail qui pourraient exécuter toutes les étapes
dont il a besoin.
Les noms sont les capacités de la plateforme : llm, embedding, stt, tts,
image, video, ocr, moderation, webSearch, geo. extension build
échoue sur tout autre nom (unknown_capability_requirement) ; l’installation
d’une archive construite avant cette vérification ne fait qu’avertir, et la
plateforme ignore un nom qu’elle ne connaît pas.
Une capacité est vérifiée exactement comme une étape l’utiliserait : le flux est prêt lorsque la plateforme choisirait un fournisseur pour elle dans cet espace de travail et cet environnement. Elle peut être indisponible pour trois raisons :
| Raison | Signification | Ce que fait un administrateur |
|---|---|---|
not_configured | Aucune extension installée ne la fournit avec une connexion utilisable, et aucune valeur par défaut n’est définie | Définir une valeur par défaut dans Paramètres → Extensions → Models & defaults |
not_entitled | Un fournisseur existe pour l’organisation, mais aucun n’est activé pour cet espace de travail | Activer un fournisseur pour l’espace de travail |
disabled_by_policy | L’organisation a désactivé la capacité | La réactiver dans Models & defaults, si c’est voulu |
Le même message de refus nomme les deux types — les extensions par bloc, les
capacités en toutes lettres (« Modèle de langage IA (aucune valeur par défaut
configurée) ») — et renvoie vers Models & defaults. Le commutateur
auth.enforceProcessFlowRequirements ci-dessus couvre aussi les capacités. Si la
plateforme ne peut pas vérifier une capacité (par exemple en cas de panne
passagère), le flux n’est pas refusé pour elle.
Dépannage : « Flux refusé : configurez un LLM par défaut »
Activer échoue avec Modèle de langage IA (aucune valeur par défaut
configurée). Le flux déclare llm dans requirements.capabilities et rien dans
l’organisation n’en fournit un pour cet espace de travail.
- Un administrateur de l’organisation ouvre Paramètres → Extensions → Models & defaults (le lien du message y mène).
- Installez ou connectez un fournisseur de modèles, puis choisissez-le comme valeur par défaut LLM. Si la ligne indique que la capacité est désactivée, l’organisation l’a désactivée volontairement : ne la réactivez que si c’est voulu.
- Si une valeur par défaut existe mais que la raison est non activée pour cet espace de travail, activez le fournisseur pour l’espace de travail.
- Activez à nouveau le flux.
Si vous créez le flux et que toutes ses étapes IA sont facultatives, déplacez
plutôt llm vers optionalCapabilities : le flux s’active alors partout, et là
où aucun modèle n’est configuré, ces étapes facultatives ne produisent pas de
résultat sans bloquer l’exécution.
Construire, inspecter, téléverser
bunx @scrydon/sdk-authoring extension validate src/extension.tsbunx @scrydon/sdk-authoring extension build src/extension.ts --outDir dist
# → dist/<package.id>-<package.version>.scrydon-extension.tar.gzbunx @scrydon/sdk-authoring extension inspect dist/acme-kickoff-1.0.0.scrydon-extension.tar.gzConnectez-vous en tant qu'administrateur de l'organisation et ouvrez Paramètres → Plateforme → Extensions → Sources dans l'application plateforme. Cliquez sur Téléverser une extension (ponctuel) et déposez votre .scrydon-extension.tar.gz. Quand l'extension contient un workflow, la boîte de dialogue vous demandera de choisir un environnement d'espace de travail — les définitions de workflow s'installent dans cet environnement. Le contenu ontologie et process-flow s'installe au niveau organisation quel que soit le sélecteur.
Le flux de téléversement de la plateforme est le point d'entrée canonique pour tous les types de contenu d'extension depuis l'ADR 2026-05-21 Unified extension upload surface.
Après l'installation de l'extension, un administrateur d'espace de travail ouvre Extensions dans la barre latérale agentic et clique sur Activer sur la ligne Process Flow pour le rendre disponible dans cet environnement. Une fois activé, tout membre de l'espace de travail peut démarrer un nouveau Process Flow depuis Flows dans Horizon, où les flows sont exploités. Voir Extensions.
Pour l'automatisation, la route agentic sous-jacente accepte toujours les téléversements. Passez workspaceEnvironmentId uniquement si l'extension contient du contenu workflow ; sinon c'est optionnel.
curl -X POST "$AGENTIC_URL/api/extensions/import?organizationId=$ORG_ID&workspaceEnvironmentId=$ENV_ID" \
-H "Cookie: $SESSION_COOKIE" \
-F "file=@dist/acme-kickoff-1.0.0.scrydon-extension.tar.gz"Structure de l'extension
<extension>.scrydon-extension.tar.gz
├── extension.json # top-level extension manifest (ExtensionArchiveManifestSchema)
├── ontology/
│ └── manifest.json # OntologyManifestSchema — may be empty for flow-only extensions
├── workflow-<slug>/ # optional — zero or more workflow subdirs
│ └── manifest.json # WorkflowManifestSchema
└── process-flow/
├── manifest.json # ProcessFlowManifestSchema
├── assets/ # optional — JSON / image assets referenced by the flow
│ ├── icon.svg
│ └── preview.png
└── meta/ # optional — non-functional metadata (e.g. sbom.cdx.json)Chaque sous-répertoire fait l'aller-retour comme un artefact autonome valide. Extensions d'assets autorisées : .json, .svg, .png, .jpg, .jpeg, .gif, .md. Les liens symboliques, liens durs, chemins absolus et traversées de chemin (..) sont rejetés par l'inspecteur.
Quand une extension contient des workflows, l'importateur les exécute dans leur propre phase avant l'installation du process-flow — de cette façon, chaque workflowSlug sur un modèle d'action se résout en un workflowId matérialisé avant que le process flow atterrisse dans la base de données. Voir Workflows pour le contrat de rebind de slug.
Limites de sécurité
L'inspecteur runtime lit l'archive en mode streaming (analyseur tar.list uniquement — n'extrait jamais sur disque) et applique des limites strictes :
| Limite | Seuil | Code d'échec |
|---|---|---|
| Archive compressée | 5 Mo | archive_too_large |
| Total non compressé | 10 Mo | total_size_exceeded |
| Taille par fichier | 5 Mo | file_too_large |
| Nombre de fichiers | 200 | too_many_files |
| Lien symbolique / lien dur | n/a | symlink_rejected |
| Chemin absolu | n/a | absolute_path_rejected |
| Traversée de chemin | n/a | path_traversal_rejected |
| Répertoire de niveau supérieur non autorisé | n/a | disallowed_path |
| Extension non autorisée | n/a | disallowed_extension |
La route /import retourne 413 pour les violations de taille et 400 pour les violations de structure ou de graphe.
Pourquoi pas de code exécutable
Les process flows sont déclaratifs. La logique personnalisée est référencée — par workflowId (un workflow déjà présent dans le tenant) ou par workflowSlug (un workflow distribué avec le modèle dans la même extension) — pas archivée. Même quand une extension distribue des workflows dans des sous-répertoires workflow-<slug>/, la représentation sur disque est du JSON pur ; le catalogue de blocs runtime réside dans la plateforme. Cela rend la surface déterministe, reproductible et téléversable par des auteurs non-ingénieurs.
Où aller ensuite
Référence par type — une page par actionType avec des exemples, des champs de métadonnées et l'UX runtime.
Après l'installation d'une extension, les administrateurs d'espace de travail activent des Process Flows pour un environnement et déploient des Workflows depuis Extensions.
Téléchargez des archives de process-flow prêtes à l'emploi — Revue trimestrielle ISO, Revue annuelle ISO.
Les process flows produisent des instances typées contre l'ontologie — créez d'abord le système de types.
Distribuez des actions actionType: workflow et les workflows qu'elles référencent dans la même extension via workflowSlug.
Les workflows référencés par actionType: workflow sont construits à partir de blocs — dont beaucoup proviennent d'extensions.