Opérateurs
Un opérateur est un nœud qui exécute une action déterministe : pas de LLM, pas d'aléatoire. Pour chaque entrée donnée, la sortie est prévisible.
Pourquoi les utiliser
Toute logique qui peut être écrite explicitement doit l'être. Un LLM qui « calcule un total » ou « formate une date » est un anti-pattern : il est plus lent, plus cher, et peut se tromper.
Règle pratique : si vous savez écrire la fonction en 5 lignes de Python, c'est un opérateur — pas un agent.
Types disponibles
webhook_action (appel HTTP)
Effectue un appel HTTP sortant. Configuration :
- URL, méthode, headers et paramètres de requête (avec placeholders depuis le contexte)
- Body :
none,json,form,raw,multipart, oumapper(body composé par le langage de mapping, voir ci-dessous) - Authentification :
bearer,basic,api_key_header(header custom) ouoauth2(voir ci-dessous) - Statuts HTTP acceptés, délai maximal, et nombre de réessais (
retry_count, 0 par défaut, backoff exponentiel) - Clé de sortie où la réponse est publiée
database_query / database_manage
database_query lit des lignes dans une base no-code betool ou dans une base externe (Postgres, MySQL, MongoDB) enregistrée dans Applications → Bases de données → Connexions : filtre where, recherche plein texte, limite. database_manage y écrit (create ou update), le contenu étant composé par le langage de mapping.
file_transform
Transforme un fichier. Transformers livrés :
pdf_extract_text— texte sélectionnable d'un PDF (pas d'OCR : un PDF scanné ne rend pas de texte)pdf_split— découpe d'un PDFpdf_to_images— rendu des pages d'un PDF en imagesxlsx_to_json/xls_to_json— lecture d'un classeur Excel en lignes JSONunzip— extraction d'une archive
compute
Calculs déterministes sur les données du contexte. Opérations livrées :
column_stats— par colonne d'une liste de lignes, combien valent une valeur donnée (count,total,pct)compose_text— composition d'un texte à partir d'un gabarit et de valeurs du fluxregex_extract— extraction de valeurs par expression régulièreselect_by_substring— répartition d'une liste en groupes selon des prédicats « contient / ne contient pas »list_compare— cohérence de plusieurs listes par clé pivotmulti_source_compliance— audit de conformité multi-dimensions et multi-sourcescontact_extract— adresses email et numéros de téléphone trouvés dans un texte, avec leur provenancefree_slots— créneaux libres déduits de périodes occupéesurl_expand— composition d'URL à partir de bases et de chemins
Langage de mapping
Ce n'est pas un nœud : c'est le langage qui compose un payload de sortie depuis les données du contexte (fonctions $now, $uuid, $concat…). Il sert au body mapper de webhook_action, au contenu écrit par database_manage et aux variables d'un appel sortant phone_call.
data_to_file
Produit un fichier Excel (.xlsx) à partir de données du contexte — une liste de lignes, une grille, ou plusieurs listes (un onglet chacune). Options : nom du fichier (templatable), nom d'onglet, choix et ordre des colonnes, ligne d'en-tête. Le fichier est rangé dans le stockage de votre organisation, prêt à être envoyé par email ou déposé sur un Drive.
Par sécurité, les cellules qui commencent par =, +, - ou @ sont écrites comme du texte par défaut (pas de formule injectée). Quand les limites d'Excel obligent à couper, le fichier est marqué comme tronqué.
web_fetch
Lit une ou plusieurs pages web et publie leur texte lisible dans le contexte (défaut web.pages). Réglages : nombre de pages, concurrence, délai, taille maximale. Le verdict robots.txt est toujours calculé et rapporté ; il n'est appliqué que si vous l'activez (respect_robots).
Les pages rendues uniquement par JavaScript ne sont pas exécutées : seul le HTML servi est lu. Une page en échec est rapportée dans le résultat, sans faire échouer le pipeline.
Côté agent, deux tools équivalents :
web_scrape.fetch_page— lit une page (titre, texte, liens email et téléphone trouvés).web_search.search— recherche web via un moteur SearXNG auto-hébergé par la plateforme : jusqu'à 5 résultats (titre, URL, extrait).
Toutes les lectures web passent par la même protection anti-SSRF : adresses internes, privées et de métadonnées cloud refusées après résolution DNS, redirections revérifiées à chaque saut.
code_step
Quand une logique déterministe dépasse ce que compute sait faire, une étape de code exécute du code custom en sandbox Starlark — éditable directement, exécuté dès sauvegarde, et borné par une allowlist de tools. Voir Étapes de code.
Authentification & secrets
Les opérateurs qui parlent à un système externe (HTTP, DB) référencent un compte enregistré dans l'organisation. Les credentials ne sont jamais visibles dans le pipeline lui-même — juste un nom de compte.
Conséquence : changer un mot de passe ne nécessite pas de rééditer chaque pipeline.
OAuth2 sortant (client_credentials)
Pour les APIs qui exigent un jeton OAuth2 (cloud d'entreprise, ERP, providers tiers), l'opérateur HTTP supporte le mode oauth2. Vous enregistrez un credential OAuth2 dans l'organisation — token_url, client_id, client_secret, scope — et le nœud n'y référence qu'un identifiant non secret.
Au moment de l'appel, betool obtient un jeton et le réutilise tant qu'il est valide ; il le rafraîchit paresseusement à expiration, sans tâche de fond. Le client_secret n'est jamais renvoyé en lecture par l'API d'administration (seul un indicateur a un secret est exposé), et le jeton obtenu est posé en Authorization: Bearer … sur la requête sortante.
Changer le secret après une rotation côté provider ne demande aucune réédition de pipeline : le prochain appel rafraîchit automatiquement.
Idempotence
Tout opérateur qui produit un effet de bord (POST HTTP, INSERT DB, envoi d'email) doit être pensé idempotent côté cible. Pratique recommandée :
- Inclure un
idempotency_keydans le payload (typiquementexchange_id). - Vérifier côté cible si la clé a déjà été traitée.
En dehors des réessais que vous configurez explicitement sur webhook_action (retry_count), betool ne réessaie pas automatiquement un opérateur qui a échoué : c'est à votre pipeline d'orchestrer la stratégie de retry. webhook_action est de plus protégé contre le double envoi lors d'un re-dispatch interne : une requête déjà livrée avec un statut accepté n'est pas renvoyée.