Référence SDK
Référence API complète pour le SDK @scrydon/sdk-authoring/extensions/authoring
Installation
bun add -d @scrydon/sdk-authoring zodChemins d'importation
Le SDK utilise des exports de sous-chemins explicites — il n'existe pas d'import barrel racine.
// Helpers de définition (toutes les fonctions define*)
import {
defineExtension, defineToolkit, defineTool, defineBlock, defineTriggerBlock,
defineCapabilityLLM, defineCapabilitySTT, defineCapabilityTTS,
defineCapabilityEmbedding, defineCapabilityVideo, defineCapabilityOCR,
defineCapabilityWebhook, defineCapabilityDiscovery,
} from "@scrydon/sdk-authoring/extensions/authoring/define";
// Types de runtime (utilisés dans les signatures execute())
import type {
PureContext, PureContextAuth, ToolResponse, ExecutorResult,
RealtimeSession, RealtimeMessage,
} from "@scrydon/sdk-authoring/extensions/authoring/context";
// Helpers de filtrage des credentials (lèvent une CredentialKindError en cas de type incompatible)
import {
requireOAuthToken, requireOAuth,
requireApiKey, requireBasicAuth, requireBotToken,
} from "@scrydon/sdk-authoring/extensions/authoring/context";
// Types du manifeste (pour les cas d'usage avancés)
import type { ManifestSchema } from "@scrydon/sdk-authoring/extensions/authoring/manifest";defineExtension(config)
Conteneur de niveau supérieur pour une intégration. L'export par défaut du point d'entrée doit être le résultat d'un appel à defineExtension().
interface VendorInput {
/** Identifiant unique du fournisseur — alphanumérique minuscule + tirets, commence par une lettre */
id: string;
/** Nom d'affichage */
name: string;
/** Version sémantique (ex. "1.0.0") */
version: string;
/** Description courte */
description?: string;
/** Couleur de marque en hexadécimal (ex. "#FF6B35") */
color?: string;
/** Icône SVG sous forme de chaîne */
icon: string;
/** URL du site web du fournisseur */
website?: string;
/** URL de la documentation */
docsUrl?: string;
/** Catégories (ex. ["tools"], ["llm"], ["database"]) */
categories?: string[];
/** Indique si ce fournisseur est activé par défaut pour les nouvelles organisations */
defaultEnabled?: boolean;
/** Indique si ce fournisseur prend en charge le mode système (client_credentials) */
supportsSystemMode?: boolean;
/** Indique si ce fournisseur nécessite une connectivité réseau externe */
connectivity?: "cloud" | "local" | "hybrid";
/** Isolation minimale demandée. Les minimums plateforme et organisation ne peuvent que la renforcer. */
isolation?: "memory" | "microvm";
/** Hôtes HTTPS publics que le code d'outil peut contacter — exacts ou wildcards `*.`. */
toolEgress?: {
httpsHosts: string[];
};
/** Configuration de l'authentification */
auth: AuthConfig;
/** Champs configurables par l'administrateur (ex. URL de base pour les services auto-hébergés) */
configFields?: ConfigFieldInput[];
/** Secrets au niveau de l'extension (résolus par invocation via le Dapr Secret Store) */
secrets?: SecretInput[];
/** Ce que fournit l'extension — au moins un toolkit, une famille de modèles ou un type de contenu */
provides: {
toolkits?: ToolkitDefinition[];
models?: ModelFamilyDefinition[];
};
/** Définitions de protocoles optionnelles */
protocols?: ProtocolDefinition[];
}Isolation et egress des outils
isolation est une demande minimale, pas un sélecteur de backend. Les outils Scrydon exacts et
révisés peuvent utiliser le backend memory approuvé. Tout autre outil livré ou installé par une
organisation a un minimum microvm imposé par la plateforme, même si son manifeste demande
memory ou omet le champ. Une politique d'organisation peut renforcer un outil Scrydon révisé vers
microvm ; aucun réglage ne peut affaiblir le minimum de la plateforme. Si le backend Runtime
Plane attesté est indisponible, l'outil refuse de s'exécuter.
Déclarez chaque nom d'hôte HTTPS public qu'un outil peut contacter :
export default defineExtension({
// ...
toolEgress: {
httpsHosts: ["api.acme.example", "uploads.acme.example"],
},
});Les hôtes doivent être des noms DNS en minuscules, sans schéma, chemin ni port.
Lorsque votre hôte d'API dépend du locataire, préfixez une entrée par *. :
export default defineExtension({
// ...
toolEgress: {
// Couvre acme.my.acme-crm.example et acme--dev.sandbox.my.acme-crm.example
httpsHosts: ["*.my.acme-crm.example"],
},
});Une entrée *. correspond aux sous-domaines à n'importe quelle profondeur mais pas à son
propre apex — déclarez l'apex séparément si vos outils le contactent. Le wildcard doit couvrir au
moins deux labels : *.example est donc refusé, aucun manifeste ne pouvant revendiquer un TLD
entier. Le préfixe *. est la seule forme de wildcard ; un segment variable à l'intérieur d'un
label (*-api.acme.example) n'est pas exprimable — déclarez alors le domaine parent. Préférez des
hôtes exacts partout où l'ensemble des destinations est fixe : un wildcard sert aux hôtes que vous
ne pouvez réellement pas connaître avant l'exécution.
À l'exécution, la plateforme intersecte cette liste avec la politique d'egress de l'organisation ; un wildcard n'élargit jamais ce que l'organisation autorise. Les sockets Bun/Node directs, ports alternatifs, adresses privées, rebinding DNS et sorties par redirection sont refusés à la frontière de la microVM vendeur. La DLP sortante analyse la requête matérialisée qui quitterait la VM, pas seulement les arguments de l'outil.
Configuration de l'authentification
Le champ auth définit les types de credentials pris en charge par votre fournisseur :
auth: {
credentials: {
none: { type: "none" },
},
default: "none",
}Vous pouvez définir plusieurs types de credentials et laisser l'utilisateur choisir :
auth: {
credentials: {
oauth: { type: "oauth", /* ... */ },
apiKey: { type: "apiKey", /* ... */ },
},
default: "oauth", // Lequel afficher en premier
}Champs de configuration
Pour les fournisseurs nécessitant des paramètres configurés par l'administrateur (ex. une URL de base auto-hébergée) :
configFields: [
{
key: "baseUrl",
label: "Base URL",
placeholder: "https://your-instance.example.com",
description: "The base URL of your self-hosted instance",
required: true,
type: "url",
},
],Secrets
Pour les secrets au niveau du fournisseur stockés dans le Dapr Secret Store :
secrets: [
{
key: "WEBHOOK_SIGNING_SECRET",
label: "Webhook Signing Secret",
description: "Used to verify incoming webhook payloads",
required: true,
},
],Les secrets sont référencés à l'exécution via ctx.secrets["WEBHOOK_SIGNING_SECRET"]. Dans le
chemin gouverné d'outil en microVM vendeur, les chaînes de credential et de secret sont des
placeholders limités à l'invocation. Transmettez-les sans modification à ctx.fetch ; le broker
d'egress de confiance remplace la valeur réelle uniquement dans un emplacement de requête autorisé.
Ne les inspectez, transformez, persistez, journalisez ou retournez jamais.
defineToolkit(config)
Regroupe des outils, des déclencheurs et un bloc sous un toolkit pouvant être activé ou désactivé par organisation. Les runtimes de modèles ne se déclarent PAS ici : ils appartiennent à une famille de modèles, voir defineModels() ci-dessous.
interface ToolkitInput {
/** Identifiant unique de l'élément fourni au sein de l'extension */
id: string;
/** Nom d'affichage */
name: string;
/** Description courte */
description?: string;
/** SVG en ligne (utilise le logo de l'extension si absent) */
logo?: string;
/** Référence au credential d'auth.credentials utilisé par ce toolkit */
credentialRef?: string;
/** Scopes OAuth requis par ce toolkit */
credentialScopes?: string[];
/** Outils exécutables */
tools?: ToolDefinition[];
/** Déclencheurs — affichés dans la section « Déclencheurs » de l'éditeur */
triggers?: TriggerDefinition[];
/** Bloc principal du toolkit sur le canevas (absent pour un toolkit sans bloc) */
block?: BlockDefinition;
webhooks?: WebhookCapability;
discovery?: DiscoveryCapability;
webSearch?: WebSearchCapability;
/** Catalogue de ressources ; chaque action déclare séparément ses cibles */
resources?: Array<{
resourceType: string;
displayName: string;
description?: string;
allowMultiple?: boolean;
}>;
/** Dépendances NPM (pour l'évaluation des risques au moment de l'upload) */
dependencies?: Array<{
type: "npm";
package: string;
version: string;
reason?: string;
}>;Le tableau dependencies sert de contexte lisible par un humain — chaque entrée inclut un reason expliquant pourquoi la dépendance est nécessaire. La CLI génère automatiquement un SBOM lisible par machine (meta/sbom.cdx.json) qui capture l'ensemble complet des paquets intégrés avec leurs versions et licences. Les deux sont complémentaires : les dépendances déclarées expliquent l'intention, le SBOM fournit l'inventaire auditables.
/** Configuration du mode système (client_credentials) */
systemMode?: {
supported: boolean;
permissions?: string[];
};
}Extensions de consentement système
Les credentials OAuth peuvent déclarer des points d'extension sûrs pour le manifeste afin de gérer des flux de configuration spécifiques au fournisseur, comme le consentement administrateur Microsoft. Cette logique doit rester dans l'intégration : le manifeste doit décrire la forme de l'URL du fournisseur, les champs de configuration de l'organisation requis, et les paramètres de rappel (callback).
Pour la plupart des fournisseurs, implémentez le consentement système via un modèle de redirection déclaratif. C'est la voie recommandée lorsque la plateforme n'a besoin que de construire une URL à partir de valeurs de runtime :
auth: {
credentials: {
oauth: {
type: "oauth",
label: "Microsoft Account",
authorizationUrl: "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/authorize",
tokenUrl: "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token",
requiredConfig: ["tenantId"],
supportsClientCredentials: true,
clientCredentialScopes: ["https://graph.microsoft.com/.default"],
extensions: {
systemConsent: {
kind: "redirect-template",
urlTemplate: "https://login.microsoftonline.com/{tenantId}/adminconsent",
params: {
client_id: "{clientId}",
redirect_uri: "{redirectUri}",
scope: "{scope}",
state: "{state}",
},
requiredConfig: ["tenantId"],
callback: {
successParam: "admin_consent",
tenantParam: "tenant",
},
},
},
},
},
}La plateforme substitue ces espaces réservés :
| Espace réservé | Valeur |
|---|---|
{clientId} | ID client OAuth résolu pour l'organisation |
{redirectUri} | URL de rappel de consentement administrateur de la plateforme |
{scope} | clientCredentialScopes joints par un espace |
{state} | État CSRF généré par la plateforme |
Toute clé requiredConfig, comme {tenantId} | Valeur de configuration du fournisseur pour l'organisation |
Si un fournisseur ne peut pas être représenté sous forme de modèle d'URL, déclarez une référence de gestionnaire dans le manifeste et implémentez la méthode référencée dans le runtime du fournisseur. La méthode doit être pure : accepter des valeurs de runtime résolues, valider toute configuration spécifique au fournisseur requise, et retourner l'URL de redirection plutôt que de coder en dur la logique du fournisseur dans la plateforme.
extensions: {
systemConsent: {
kind: "handler",
handlerRef: "microsoft.systemConsent.buildUrl",
callback: {
handlerRef: "microsoft.systemConsent.callback",
},
},
}type SystemConsentBuildUrlInput = {
clientId: string;
redirectUri: string;
state?: string;
scopes: string[];
providerConfig: Record<string, string | undefined>;
};
export async function buildUrl(input: SystemConsentBuildUrlInput): Promise<string> {
const tenantId = input.providerConfig.tenantId;
if (!tenantId) {
throw new Error("Microsoft admin consent requires tenantId");
}
const url = new URL(`https://login.microsoftonline.com/${tenantId}/adminconsent`);
url.searchParams.set("client_id", input.clientId);
url.searchParams.set("redirect_uri", input.redirectUri);
url.searchParams.set("scope", input.scopes.join(" "));
if (input.state) {
url.searchParams.set("state", input.state);
}
return url.toString();
}
type SystemConsentCallbackInput = {
query: Record<string, string | undefined>;
providerConfig: Record<string, string | undefined>;
};
export async function callback(input: SystemConsentCallbackInput) {
return {
approved: input.query.admin_consent === "True",
tenantId: input.query.tenant,
};
}Les références de gestionnaire sont des métadonnées du manifeste. Les archives uploadés doivent aujourd'hui utiliser kind: "redirect-template", sauf si l'application hôte a explicitement câblé l'exécution du runtime pour le gestionnaire référencé.
Extensions multi-toolkits
Les extensions comme Google ou Microsoft fournissent plusieurs toolkits. Chaque toolkit dispose de son propre bloc dans l'éditeur de workflow et peut être activé indépendamment :
export default defineExtension({
id: "acme",
// ...
provides: {
toolkits: [
defineToolkit({
id: "acme-crm",
name: "Acme CRM",
tools: [listContacts, createContact],
block: crmBlock,
triggers: [],
}),
defineToolkit({
id: "acme-email",
name: "Acme Email",
tools: [sendEmail, listInbox],
block: emailBlock,
triggers: [],
}),
],
},
});defineTool(config)
Définit la logique de runtime d'un outil. C'est ici que se font vos appels API réels, transformations de données ou calculs.
interface ToolInput<TInput, TOutput> {
/** Identifiant unique de l'outil — convention : {vendor}:{product}:{action} */
id: string;
/** Nom d'affichage */
name: string;
/** Version sémantique */
version: string;
/** Description affichée aux utilisateurs et aux agents LLM */
description?: string;
/** Schéma Zod pour la validation de l'entrée */
input: z.ZodType<TInput>;
/** Schéma Zod pour la validation de la sortie */
output: z.ZodType<TOutput>;
/** Métadonnées des paramètres — contrôle la visibilité dans l'interface et auprès des LLM */
params?: Record<string, ParamDef>;
/** Ressources exactes du produit autorisées avant l'exécution de l'action */
resourceAuthorization?: Array<{
required?: boolean;
oneOf: Array<{
resourceType: string;
source: { kind: "input"; key: string } | { kind: "binding" };
}>;
}>;
/** La fonction exécutée lors de l'invocation de cet outil */
execute: (input: TInput, ctx: PureContext) => Promise<ToolResponse<TOutput>>;
}
interface ParamDef {
type: string;
required?: boolean;
description?: string;
default?: unknown;
/** Contrôle l'endroit où ce paramètre apparaît */
visibility?: "user-only" | "user-or-llm" | "hidden";
}product.resources est un catalogue, pas une exigence d'exécution globale. Déclarez la cible
réelle de chaque action avec resourceAuthorization. Les règles provenant d'une entrée sont
obligatoires ; seule une règle provenant du binding peut utiliser required: false pour conserver
le comportement délégué à la racine du compte, par exemple /me. Les cibles déléguées sont
vérifiées en direct auprès du fournisseur ; les cibles app/système exigent une attribution exacte
du même produit, type et identifiant de ressource dans l'espace de travail.
Visibilité des paramètres
| Visibilité | Qui peut fournir la valeur | Cas d'usage |
|---|---|---|
user-or-llm | L'utilisateur la définit dans l'interface, ou un agent IA la génère | La plupart des paramètres |
user-only | Seul l'utilisateur peut la configurer (masquée du LLM) | Paramètres de connexion, credentials |
hidden | Non affichée dans l'interface ni au LLM — définie par programmation | Identifiants internes, valeurs calculées |
Fonction d'exécution
La fonction execute reçoit l'entrée validée et un PureContext :
import { requireOAuthToken } from "@scrydon/sdk-authoring/extensions/authoring/context";
async execute(input, ctx) {
// Utiliser le logger (visible dans les journaux d'exécution du workflow)
ctx.logger.info(`Processing request for org ${ctx.execution.orgId}`);
// Filtrer sur ctx.auth.kind avant de lire les champs de credential.
// Cet exemple suppose que le fournisseur déclare un credential OAuth —
// requireOAuthToken lève une CredentialKindError si le type ne correspond pas.
const accessToken = requireOAuthToken(ctx.auth);
// Effectuer des appels API authentifiés
const response = await fetch("https://api.example.com/data", {
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify(input),
});
if (!response.ok) {
return {
success: false,
output: { error: `API returned ${response.status}` },
error: `HTTP ${response.status}: ${response.statusText}`,
};
}
const data = await response.json();
return {
success: true,
output: data,
metadata: { requestId: response.headers.get("x-request-id") },
};
},PureContext
L'interface PureContext est la seule interface entre la plateforme et le code de l'archive. Elle est injectée dans chaque appel à execute() au moment de l'exécution :
/**
* Union discriminée de toutes les formes de credentials que la plateforme peut injecter.
* Filtrez toujours sur `kind` avant de lire les champs de credential.
* Importez les helpers de filtrage depuis @scrydon/sdk-authoring/extensions/authoring/context :
* requireOAuthToken(auth) → string (accessToken, lève une erreur en cas d'incompatibilité)
* requireOAuth(auth) → { accessToken, refreshToken?, tokenType?, expiresAt? }
* requireApiKey(auth) → string (apiKey)
* requireBasicAuth(auth) → { username, password }
* requireBotToken(auth) → string (botToken)
* Chaque helper lève une CredentialKindError avec un message actionnable en cas d'incompatibilité.
*/
type PureContextAuth =
| { kind: "oauth"; accessToken: string; refreshToken?: string; tokenType?: string; expiresAt?: number }
| { kind: "apiKey"; apiKey: string }
| { kind: "basicAuth"; username: string; password: string }
| { kind: "botToken"; botToken: string }
| { kind: "none" };
interface PureContext {
/** Credential résolu par la plateforme avant l'invocation */
auth: PureContextAuth;
/** Métadonnées d'exécution pour la journalisation et la corrélation */
execution: {
executionId: string; // Identifiant unique de l'exécution
workflowId?: string; // Identifiant du workflow (si exécuté dans un workflow)
nodeId?: string; // Identifiant du nœud de bloc dans le workflow
orgId: string; // Identifiant de l'organisation
workspaceId?: string; // Identifiant de l'espace de travail
userId?: string; // Utilisateur qui a déclenché l'exécution
};
/** Logger structuré — les appels console sont interceptés dans le sandbox */
logger: {
info(message: string, ...args: unknown[]): void;
warn(message: string, ...args: unknown[]): void;
error(message: string, ...args: unknown[]): void;
debug(message: string, ...args: unknown[]): void;
};
/** Secrets du fournisseur configurés par l'administrateur de l'organisation (résolus par invocation via le Dapr Secret Store) */
secrets: Record<string, string>;
/** Présent lors de l'exécution via un Profil d'intégration — contient les remplacements spécifiques au profil */
profileConfig?: Record<string, unknown>;
}PureContext est importé depuis @scrydon/sdk-authoring/extensions/authoring/context. La plateforme le construit avant chaque invocation d'outil — votre code n'a jamais besoin d'en créer un manuellement. Tous les champs sauf auth et execution peuvent être des objets vides si non applicables. auth est une union discriminée (PureContextAuth) ; filtrez toujours sur auth.kind ou utilisez un helper require* avant d'accéder aux champs spécifiques au credential. Consultez Modes d'authentification pour la référence complète de la forme par mode.
ToolResponse
Chaque execute() doit retourner un ToolResponse :
interface ToolResponse<T = unknown> {
/** Indique si l'exécution de l'outil a réussi */
success: boolean;
/** Les données de sortie typées */
output: T;
/** Message d'erreur (affiché à l'utilisateur si success est false) */
error?: string;
/** Métadonnées optionnelles (journalisées mais non transmises aux blocs en aval) */
metadata?: Record<string, unknown>;
}defineBlock(config)
Définit l'interface utilisateur de l'éditeur de workflow — comment le bloc apparaît, quels champs de formulaire il contient et comment les données le traversent.
interface BlockInput {
/** Type de bloc unique — minuscule avec underscores (ex. "acme_crm") */
type: string;
/** Nom d'affichage dans la palette de blocs */
name: string;
/** Description courte */
description?: string;
/** Catégorie du bloc — utiliser "extension" pour les blocs de archive */
category: string;
/** Couleur de fond en hexadécimal */
bgColor?: string;
/** Mode d'auth : "none", "apiKey", "oauth", "botToken" */
authMode?: string;
/** Champs de formulaire affichés dans le panneau du bloc */
subBlocks?: SubBlockInput[];
/** Les outils que ce bloc peut invoquer */
tools?: {
access: string[];
config?: {
/** Sélection dynamique d'outil en fonction de la saisie de l'utilisateur */
tool: (params: Record<string, any>) => string;
/** Transformation des paramètres avant transmission à l'outil */
params?: (params: Record<string, any>) => any;
};
};
/** Connexions d'entrée depuis les blocs en amont */
inputs?: Record<string, { type: string; description?: string }>;
/** Connexions de sortie vers les blocs en aval */
outputs?: Record<string, { type: string; description?: string }>;
/** Configuration du déclencheur (pour les blocs déclencheurs) */
triggers?: { enabled: boolean; available: string[] };
}Types de SubBlock
Les SubBlocks sont les champs de formulaire qui apparaissent lorsqu'un utilisateur clique sur un bloc :
| Type | Description | Propriétés clés |
|---|---|---|
short-input | Champ de texte sur une ligne | placeholder, password, defaultValue, generatedDefault, readOnly, showCopyButton |
long-input | Zone de texte multiligne | placeholder |
code | Éditeur de code avec coloration syntaxique | placeholder, mode |
dropdown | Menu de sélection | options: [{ label, id }] |
combobox | Liste déroulante avec recherche | options, fetchOptions |
slider | Curseur de plage | min, max, step |
switch | Interrupteur à bascule | defaultValue |
oauth-input | Sélecteur de credential OAuth | serviceId, requiredScopes |
Définition de SubBlock
interface SubBlockInput {
/** Identifiant unique du champ dans le bloc */
id: string;
/** Libellé du champ */
title?: string;
/** Type de SubBlock */
type: string;
/** Disposition : "full" (par défaut) ou "half" */
layout?: "full" | "half";
/** Indique si ce champ est obligatoire */
required?: boolean;
/** Texte d'espace réservé */
placeholder?: string;
/** Masquer la saisie en points de mot de passe */
password?: boolean;
/** Valeur par défaut */
defaultValue?: unknown;
/** Générer une nouvelle valeur une fois lors de la création de chaque bloc */
generatedDefault?: "uuid";
/** Options pour liste déroulante/combobox */
options?: Array<{ label: string; id: string }>;
/** Texte d'aide affiché sous le champ */
description?: string;
/** Visibilité conditionnelle basée sur la valeur d'un autre champ */
condition?: { field: string; value: string };
/** Indique si le champ est en lecture seule */
readOnly?: boolean;
/** Afficher un bouton de copie dans le presse-papiers */
showCopyButton?: boolean;
/** Masquer ce champ dans l'interface */
hidden?: boolean;
}Utilisez generatedDefault: "uuid" lorsque chaque nouveau bloc doit recevoir
sa propre valeur initiale, par exemple un secret de webhook. Ce marqueur
déclaratif traverse la frontière JSON du manifeste d'intégration ; l'UUID
généré est enregistré comme valeur ordinaire du champ et n'est pas régénéré au
chargement du workflow.
Sélection dynamique d'outil
Lorsqu'un bloc dispose de plusieurs outils, utilisez tools.config.tool pour sélectionner lequel s'exécute :
defineBlock({
// ...
subBlocks: [
{
id: "operation",
title: "Operation",
type: "dropdown",
options: [
{ label: "Create", id: "create" },
{ label: "Read", id: "read" },
{ label: "Update", id: "update" },
{ label: "Delete", id: "delete" },
],
},
// ... autres champs
],
tools: {
access: ["acme_create", "acme_read", "acme_update", "acme_delete"],
config: {
tool: (params) => `acme_${params.operation}`,
},
},
});Visibilité conditionnelle
Afficher ou masquer des champs en fonction des valeurs d'autres champs :
subBlocks: [
{
id: "authType",
title: "Auth Type",
type: "dropdown",
options: [
{ label: "API Key", id: "apiKey" },
{ label: "Username/Password", id: "basic" },
],
},
{
id: "apiKey",
title: "API Key",
type: "short-input",
password: true,
condition: { field: "authType", value: "apiKey" },
},
{
id: "username",
title: "Username",
type: "short-input",
condition: { field: "authType", value: "basic" },
},
{
id: "password",
title: "Password",
type: "short-input",
password: true,
condition: { field: "authType", value: "basic" },
},
],defineTriggerBlock(config)
Définit un bloc déclencheur — un membre de workflow à part entière qui s'affiche dans la section latérale « Triggers » et porte des métadonnées de runtime décrivant comment il se déclenche (webhook, polling, ou les deux). La valeur de category est automatiquement définie à "trigger".
interface TriggerBlockInput {
/** Type de bloc unique */
type: string;
/** Nom d'affichage */
name: string;
/** Description */
description?: string;
/** Couleur de fond en hexadécimal */
bgColor?: string;
/** Mode d'auth : "none", "apiKey", "oauth", "botToken" */
authMode?: string;
/** Champs de formulaire pour la configuration du déclencheur */
subBlocks?: SubBlockInput[];
/** Les outils que ce bloc déclencheur peut invoquer */
tools?: {
access: string[];
config?: {
tool?: (params: Record<string, any>) => string;
params?: (params: Record<string, any>) => any;
};
};
/** Connexions d'entrée */
inputs?: Record<string, { type: string; description?: string }>;
/** Schéma de sortie — données émises par le déclencheur */
outputs?: Record<string, { type: string; description?: string }>;
/** Identifiant du fournisseur */
provider?: string;
/** Version sémantique */
version?: string;
/** Configuration de runtime — comment les événements atteignent le moteur de workflow */
runtime?: {
webhook?: {
method?: "POST" | "GET" | "PUT" | "DELETE";
headers?: Record<string, string>;
};
polling?: PollingProvider;
};
}Gestion des secrets
Les fournisseurs peuvent déclarer des secrets chiffrés au repos et résolus par invocation. Les secrets sont limités à l'organisation et au fournisseur, de sorte que chaque organisation dispose de son propre jeu de credentials isolé.
Déclaration des secrets
Définissez les exigences en matière de secrets dans defineExtension() via le tableau secrets :
export default defineExtension({
id: "acme",
name: "Acme",
version: "1.0.0",
logo: acmeIcon,
auth: { credentials: { apiKey: { type: "apiKey", label: "API Key", identityScope: "application" } }, default: "apiKey" },
secrets: [
{
key: "WEBHOOK_SIGNING_SECRET",
label: "Webhook Signing Secret",
description: "Used to verify incoming webhook payloads",
required: true,
},
{
key: "ENCRYPTION_KEY",
label: "Encryption Key",
description: "AES key for encrypting sensitive payloads",
required: false,
},
],
provides: { toolkits: [/* ... */] },
});Chaque SecretInput a la forme suivante :
interface SecretInput {
/** Clé unique au sein du fournisseur — doit correspondre à ^[a-zA-Z0-9_-]+$ */
key: string;
/** Libellé lisible affiché dans l'interface d'administration */
label: string;
/** Texte d'aide décrivant l'utilisation de ce secret */
description?: string;
/** Indique si l'intégration nécessite ce secret pour fonctionner */
required: boolean;
}Les clés de secret ne peuvent contenir que des caractères alphanumériques, des tirets et des underscores (^[a-zA-Z0-9_-]+$). Les clés ne correspondant pas à ce format sont rejetées lors de l'enregistrement.
Format des clés de secret
Les secrets sont stockés avec une clé structurée qui les rattache à l'organisation et au fournisseur :
extension:{orgId}:{extensionId}:{key}Par exemple, un secret avec la clé WEBHOOK_SIGNING_SECRET pour le fournisseur acme dans l'organisation org_abc123 est stocké sous :
extension:org_abc123:acme:WEBHOOK_SIGNING_SECRETCela garantit une isolation complète entre les organisations et entre les fournisseurs au sein d'une même organisation.
Chiffrement au repos
Toutes les valeurs de secret sont chiffrées avec AES-256-GCM avant d'être persistées. La stratégie de clé de chiffrement est configurée par organisation — LOCAL, BYOK ou HYOK. Les valeurs de secret ne sont jamais stockées en clair. Consultez Sécurité → Gestion des secrets pour le modèle complet.
Accès aux secrets au moment de l'exécution
ctx.secrets est un Record<string, string> plat contenant les clés configurées. Dans le chemin
gouverné en microVM vendeur, chaque valeur est un placeholder limité à l'invocation et adossé à un
grant scellé du broker :
import { defineTool } from "@scrydon/sdk-authoring/extensions/authoring/define";
import { z } from "zod";
export const verifyWebhook = defineTool({
id: "acme:webhooks:verify",
name: "Verify Webhook",
version: "1.0.0",
input: z.object({ payload: z.string(), signature: z.string() }),
output: z.object({ valid: z.boolean() }),
async execute(input, ctx) {
const signingSecret = ctx.secrets["WEBHOOK_SIGNING_SECRET"];
if (!signingSecret) {
return { success: false, output: { valid: false }, error: "Webhook signing secret not configured" };
}
const response = await ctx.fetch("https://api.acme.example/webhooks/verify", {
method: "POST",
headers: {
"content-type": "application/json",
"x-acme-signing-secret": signingSecret,
},
body: JSON.stringify(input),
});
return { success: true, output: { valid: response.ok } };
},
});Transmettez les placeholders sans modification à ctx.fetch. Le broker de confiance remplace la
valeur réutilisable après l'autorisation de destination et avant que la DLP sortante analyse la
requête réelle. Le guest, le système de fichiers, le modèle, le plan, les logs, les traces et la
réponse de l'outil ne reçoivent jamais la valeur réutilisable.
L'objet ne contient que les clés définies par l'administrateur de l'organisation ; une valeur absente reste absente. Les opérations locales qui doivent inspecter ou transformer un secret réutilisable, comme une signature HMAC dans le code d'un outil Agent non-Scrydon, sont intentionnellement indisponibles sur cette frontière.
Interface d'administration
Les administrateurs d'organisation configurent les secrets sous Paramètres > Plateforme > Extensions, dans la fiche du fournisseur. L'interface affiche les champs de secret déclarés dans le tableau secrets du fournisseur.
Les valeurs de secret sont en écriture seule — une fois une valeur enregistrée, elle n'est plus jamais affichée. L'interface indique uniquement quelles clés ont été configurées (avec un indicateur masqué) et permet aux administrateurs de les mettre à jour ou de les supprimer.
Points de terminaison API
La plateforme expose trois points de terminaison internes pour la gestion des secrets :
| Point de terminaison | Objectif |
|---|---|
/extensions/authoring/admin/archive-secret-set | Créer ou mettre à jour une valeur de secret |
/extensions/authoring/admin/archive-secret-delete | Supprimer un secret |
/extensions/authoring/admin/archive-secret-list | Lister les clés de secret configurées (les valeurs ne sont jamais retournées) |
Ces points de terminaison sont internes (service à service) et nécessitent que l'appelant soit un service interne autorisé. Ils ne sont pas directement accessibles depuis les applications clientes.
CLI de build
# Construire une archive
sdk-authoring extension build [--entry src/index.ts] [--outDir dist]
# Tester une archive
sdk-authoring extension test [--level static|sandbox|live] [--tool <id>]Résultat du build
my-vendor-1.0.0.archive.tar.gz
├── manifest.json # Métadonnées auto-générées (JSON Schemas, définitions UI)
├── dist/
│ └── index.js # ESM compilé et minifié (toutes les dépendances intégrées via esbuild)
├── meta/
│ ├── sbom.cdx.json # SBOM CycloneDX 1.6 (auto-généré)
│ └── metafile.json # Graphe de dépendances esbuild
└── assets/ # Icônes optionnelles
└── icon.svgLa CLI de build intègre toutes les dépendances npm dans le fichier dist/index.js unique et génère automatiquement un SBOM CycloneDX 1.6 dans meta/sbom.cdx.json. Il n'y a pas de npm install au moment de l'exécution — l'archive est entièrement autonome et déterministe.
Règles des identifiants de fournisseur
- Caractères alphanumériques minuscules et tirets uniquement
- Doit commencer par une lettre
- Format :
/^[a-z][a-z0-9-]*$/ - Exemples :
acme,my-vendor,hello-world
Convention des identifiants d'outil
Les identifiants d'outil utilisent le format complet {extensionId}:{providedId}:{action} au moment de l'exécution :
hello-world:hello-world:say-hellogoogle:sheets:readslack:messaging:send-message
Forme abrégée : Dans le code d'authoring, vous pouvez utiliser uniquement la partie action (ex. "say-hello", "read"). Le SDK qualifie automatiquement les identifiants courts en ajoutant {extensionId}:{providedId}: lors de l'appel à defineExtension(). Toutes les intégrations natives utilisent la forme courte. Si vous utilisez la forme complète, le préfixe vendor/product doit correspondre — la CLI de build valide cela.
Helpers de capacités
Les helpers de capacités encapsulent les configurations de runtime avec une balise de type afin que l'extracteur de manifeste puisse les identifier. Chaque helper retourne sa configuration avec une balise _capability utilisée en interne lors du build.
| Helper | Balise | Objectif |
|---|---|---|
defineCapabilityLLM(config) | llm | Fournisseur LLM complet (chat, complétion, streaming) |
defineCapabilitySTT(config) | stt | Reconnaissance vocale (batch et temps réel) |
defineCapabilityTTS(config) | tts | Synthèse vocale (batch et temps réel) |
defineCapabilityEmbedding(config) | embedding | Génération d'embeddings vectoriels |
defineCapabilityVideo(config) | video | Génération vidéo |
defineCapabilityOCR(config) | ocr | Analyse de documents / reconnaissance optique de caractères |
defineCapabilityWebhook(config) | webhook | Gestion des webhooks spécifiques au fournisseur |
defineCapabilityDiscovery(config) | discovery | Navigation dans les ressources, sélecteurs, portées d'accès |
Tous les helpers sont importés depuis @scrydon/sdk-authoring/extensions/authoring/define :
import {
defineCapabilityLLM,
defineCapabilitySTT,
defineCapabilityTTS,
defineCapabilityEmbedding,
defineCapabilityVideo,
defineCapabilityOCR,
defineCapabilityWebhook,
defineCapabilityDiscovery,
} from "@scrydon/sdk-authoring/extensions/authoring/define";Les configurations de capacités de modèle sont placées dans defineModels({ family: "<famille>", runtime: { ... } }), une famille par entrée de provides.models ; webSearch est en revanche un membre du toolkit. L'extracteur de manifeste convertit les fonctions de runtime en indicateurs booléens et extrait les métadonnées des modèles (dimensions, benchmarks, tarification) dans le champ capabilityMeta du manifeste. Consultez Capacités pour des exemples d'utilisation complets de chaque helper.
Schéma du manifeste
La CLI de build génère automatiquement manifest.json à partir de votre appel à defineExtension(). Le manifeste est un instantané sérialisable en JSON des métadonnées de votre fournisseur, sans les fonctions de runtime. Il suit l'unique forme prise en charge manifestVersion: 1. Toute autre version est rejetée.
Structure de niveau supérieur
{
"$schema": "...", // URL optionnelle du JSON Schema
"manifestVersion": 1, // Toujours 1
"version": "1.0.0", // Version du fournisseur (issue de defineExtension)
"vendor": { ... }, // Métadonnées du fournisseur
"auth": { ... }, // Configuration de l'authentification
"products": [ ... ], // Définitions des produits
"protocols": [ ... ], // Définitions de protocoles (optionnel)
"llm": { ... } // Configuration du fournisseur LLM (optionnel)
}Section fournisseur
Contient les métadonnées d'affichage. Le code de runtime est exclu.
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
id | string | Oui | Identifiant du fournisseur (/^[a-z][a-z0-9-]*$/) |
name | string | Oui | Nom d'affichage |
description | string | Non | Description courte |
color | string | Non | Couleur de marque en hexadécimal |
icon | string | Oui | Icône SVG sous forme de chaîne |
website | string | Non | URL du site web du fournisseur |
docsUrl | string | Non | URL de la documentation |
categories | string[] | Non | Étiquettes de catégorie |
defaultEnabled | boolean | Non | Activation automatique pour les nouvelles organisations (par défaut : false) |
supportsSystemMode | boolean | Non | Prend en charge client_credentials (par défaut : false) |
connectivity | "cloud" | "local" | "hybrid" | Non | Exigences réseau |
configFields | ConfigField[] | Non | Champs configurables par l'administrateur |
secrets | Secret[] | Non | Secrets au niveau du fournisseur |
Section produit
Chaque produit dans le tableau products contient :
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
id | string | Oui | Identifiant du produit |
name | string | Oui | Nom d'affichage |
capabilities.tools | Tool[] | Non | Définitions d'outils avec JSON Schema entrée/sortie |
capabilities.triggers | Trigger[] | Non | Définitions de déclencheurs |
capabilities.runtimes | object | Non | Indicateurs booléens pour llm, stt, tts, embedding, video, ocr |
capabilities.capabilityMeta | object | Non | Métadonnées de modèles extraites (dimensions d'embedding, modèles STT/TTS, benchmarks) |
capabilities.webhooks | boolean | Non | Indique si le produit gère les webhooks |
capabilities.discovery | boolean | Non | Indique si le produit prend en charge la découverte de ressources |
workflow.block | Block | Non | Définition du bloc de l'éditeur de workflow |
workflow.triggers | TriggerBlock[] | Non | Blocs déclencheurs du workflow |
resources | Resource[] | Non | Catalogue de ressources, jamais une règle globale pour toutes les actions |
dependencies | Dependency[] | Non | Dépendances NPM déclarées avec leurs raisons |
systemMode.permissions | string[] | Non | Permissions de consentement app/système |
Comment le code de runtime devient des données de manifeste
La CLI de build transforme les définitions de runtime en JSON sûr pour le manifeste :
| Source (defineToolkit) | Sortie du manifeste |
|---|---|
runtimes.llm (avec fonction executeRequest) | runtimes.llm: true |
runtimes.embedding (avec fonction embed, modèles avec dimension) | runtimes.embedding: true + capabilityMeta.embeddingModels |
runtimes.stt (avec fonction transcribe, modèles) | runtimes.stt: true + capabilityMeta.sttModels |
runtimes.tts (avec fonction synthesize, modèles) | runtimes.tts: true + capabilityMeta.ttsModels |
input/output d'un outil (schémas Zod) | Objets JSON Schema |
Fonction execute d'un outil | Omise (non sérialisable) |
Fonction tools.config.tool d'un bloc | Omise (sérialisée séparément) |
Le manifeste est lu au démarrage pour alimenter le catalogue d'intégrations. Il ne contient aucun code exécutable, uniquement des métadonnées, des JSON Schemas et des définitions UI. L'archive exécutable est chargé à la demande par le backend canonique. Les capacités et outils approuvés peuvent utiliser le backend de compatibilité Worker Thread ; un outil statique non-Scrydon sélectionné par un Agent isolé exige la microVM fournisseur épinglée à la source et validée par preuve.
Sessions continues de transcription
Une extension STT qui déclare des modèles en streaming doit implémenter
createStreamingSession(request) et openStreamingSession(request, context).
La compilation vérifie cette association. streaming.protocol est un identifiant
propre à l’extension : ajouter un fournisseur ne nécessite aucun adaptateur dans
l’application d’enregistrement.
Les types SttSession, SttSessionContext et SttStreamingSessionRequest sont
exportés par @scrydon/sdk-authoring/extensions/capabilities/stt-streaming.
SttSession expose sendAudio(Uint8Array), finalize(), close(),
onTranscript(handler), onError(handler) et onClose(handler).
L’audio reçu est du PCM16 mono continu à 16 kHz. L’extension gère l’authentification,
le rééchantillonnage, le protocole, le renouvellement des identifiants et le SDK du
fournisseur. Utilisez les interfaces fetch et WebSocket contrôlées par le
sandbox ; les modules réseau natifs ne peuvent pas contourner ces contrôles.
Les champs context.auth, context.secrets et context.profileConfig reprennent
le contexte standard des extensions ; l’authentification n’est pas limitée aux
clés API. Respectez context.signal, libérez les ressources à la fermeture et traitez tout
l’audio accepté avant de terminer finalize().
Les résultats ont la forme { text, isFinal, startMs?, endMs?, confidence?, speakerId? }.
Les temps sont exprimés en millisecondes depuis le début audio de la session.
N’inventez pas de temps ni d’attribution manquants. Les identifiants de locuteur ne
sont valables que dans la session continue concernée ; ils n’identifient pas un
membre de l’organisation ni une personne dans une autre requête STT.
La plateforme fournit aux clients média une autorisation scrydon-stt-v1.
Les endpoints et identifiants du fournisseur restent dans l’extension, y compris
les valeurs direct et proxied de createStreamingSession.
Les sessions continues nécessitent actuellement du code d’extension revu, admis sur le backend worker. Si la politique exige un processus géré ou une microVM, le streaming est refusé avant l’émission du ticket : ces backends prennent en charge les appels requête/réponse. La transcription par lots conserve ses niveaux d’exécution habituels. Ne réduisez pas les exigences d’isolation pour contourner cette limite.
Lors de la mise à niveau, recompilez et réinstallez les extensions de streaming
avec le SDK d’authoring mis à jour. Les anciens bundles qui émettent uniquement
des tickets ne possèdent pas le nouveau hook de session. Déployez ensemble la
plateforme et le client média : celui-ci exige scrydon-stt-v1 et ne rétablit pas
les adaptateurs fournisseur dans l’application.
Modèles vocaux OpenAI de première partie
L’extension OpenAI utilise le même contrat de session que les autres extensions. Configurez sa connexion par clé API OpenAI, puis choisissez un modèle pour la capacité STT :
| Modèle | Entrée | Horodatage et locuteurs |
|---|---|---|
gpt-live-transcribe | Session en direct | Limites des tours via VAD serveur ; aucun horodatage par mot ni locuteur fourni |
gpt-transcribe | Fichier / énoncé | Texte et langues détectées ; aucun horodatage inventé |
gpt-4o-transcribe, gpt-4o-mini-transcribe | Fichier / énoncé | Texte sans horodatage par mot |
gpt-4o-transcribe-diarize | Fichier / énoncé | Segments horodatés avec locuteurs propres à la requête |
whisper-1 | Fichier / énoncé | Horodatage par mot ou segment ; traduction vers l’anglais |
Le modèle par défaut reste whisper-1. Les modèles en direct et sur fichier sont
séparés : un modèle réservé au direct ne peut pas traiter la transcription finale
d’un fichier. L’extension utilise le socket contrôlé par la plateforme, convertit
le PCM de 16 kHz à 24 kHz dans chaque session et attend les transcriptions finales
avant de terminer finalize(). Elle déclare la limite fournisseur de 60 minutes
pour le mécanisme de rotation existant. Le suivi des locuteurs reste indépendant
du STT ; les labels d’une requête ne constituent pas des identités entre requêtes.
Les fichiers conservent leur format audio, y compris les fenêtres FLAC de Recording
Studio, et sont limités à 25 Mo. La diarisation utilise diarized_json avec
chunking_strategy=auto, sans prompt ni option d’horodatage par mot non pris en charge.
L’accès aux modèles dépend du compte OpenAI configuré. Reconstruisez et réinstallez
l’extension OpenAI pour disposer des nouveaux modèles et du contrat de session.
Références fournisseur : transcription de fichiers, transcription en direct et cycle de vie des sessions.