Skip to main content

Workflow

Captured during the Phase 7 re-audit from designer module:

export const WORKFLOW_DESIGNER_MODULE = 's01-workflow-designer/22.19.1';

The module version is recorded as a constant because the catalogs below are a snapshot of one build of one module. Pinning the version makes the snapshot falsifiable: if a later capture disagrees, the module version tells you whether that is drift or a contradiction.

Triggers​

export type WorkflowTriggerKind = 'manual' | 'recurrence' | 'event' | 'agent';

export interface WorkflowTriggerDefinition {
kind: WorkflowTriggerKind;
label: string;
description: string;
}
kindLabelRuns when
manualManuallyA person starts it from the designer.
recurrenceOn a scheduleA configured recurrence fires.
eventWhen an event occursAn external event arrives.
agentWhen an agent calls itAn agent invokes it as a tool.

agent is the one that connects the two halves of this documentation. A workflow with that trigger appears in the Workflows tab of the add-tool flyout and becomes callable by the orchestrator - the workflow is a tool. See Tools.

Nodes​

export interface WorkflowNodeDefinition {
kind: WorkflowNodeKind;
pickerLabel: string;
description: string;
isContainer: boolean;
isTerminal: boolean;
}

Thirteen entries in WORKFLOW_NODES:

kindpickerLabelContainerTerminal
agentAgentnono
classifyClassifynono
m365CopilotMicrosoft 365 Copilotnono
humanReviewHuman reviewnono
connectorConnectornono
functionFunctionnono
variableVariablenono
ifElseIf/Elseyesno
loopLoopyesno
noteNotenono
switchSwitchyesno
scopeScopeyesno
endEndnoyes

Four containers, one terminal.

pickerLabel is the automation contract​

pickerLabel holds the exact accessible name the picker renders, because that string is what a role-based locator matches:

await page.getByRole('button', { name: `Select action: ${def.pickerLabel}` }).click();

Element refs from an accessibility snapshot go stale the moment the DOM re-renders, which the picker does on every open. Role plus accessible name survives. Keeping the exact label in the model means automation can be driven from the catalog rather than from hand-written strings.

Microsoft 365 Copilot is the label that punishes guessing - the kind is m365Copilot, and a locator built from the kind will not match.

isContainer and isTerminal​

Two booleans rather than one nodeCategory union, because they are independent properties and the combinations are not mutually exclusive in principle. They drive WorkflowNode:

export interface WorkflowNode extends Evidenced {
id: string;
kind: WorkflowNodeKind;
displayName?: string;
next?: string[];
children?: WorkflowNode[];
}

children is populated only for container kinds. next is absent on terminal kinds - an end node hands control nowhere. Neither rule is enforced by the type; both are documented invariants, because enforcing them would require a discriminated union over thirteen kinds to express two facts already available from WORKFLOW_NODE_BY_KIND.

Connector and Function are pickers, not nodes​

This is the most important correction in the catalog, and the one an inventory built from the picker list alone gets wrong.

Selecting Connector or Function does not place a node. Both open a secondary catalog and place nothing until a specific action or function is chosen. Every other entry in the list places a node immediately.

Treating all thirteen as node types is therefore wrong about two of them. The model keeps them in WorkflowNodeKind because they are genuine entries in the picker with genuine accessible names - the catalog describes the picker faithfully - but a consumer generating a node palette should know that two of the thirteen are doorways.

The Function catalog behind that doorway holds five groups:

GroupFunctions
Data Operations7
Date Time6
HTTP3
Schedule2
Request1

Ten in the palette, thirteen in the dialog​

The left-hand Add palette shows ten nodes. The Add dialog additionally exposes switch, scope, and end. The catalog is the union of both, which is why a palette screenshot and this table disagree on count. See Workflow node capture.

Lookup helper​

export const WORKFLOW_NODE_BY_KIND: Record<WorkflowNodeKind, WorkflowNodeDefinition>;

Built with Object.fromEntries over WORKFLOW_NODES. The Record key type is the union, so the lookup is total - WORKFLOW_NODE_BY_KIND[kind] needs no undefined check, and adding a kind without adding its definition is a compile error.

import { WORKFLOW_NODE_BY_KIND } from '@raybot/object-model';

WORKFLOW_NODE_BY_KIND.m365Copilot.pickerLabel; // 'Microsoft 365 Copilot'
WORKFLOW_NODE_BY_KIND.scope.isContainer; // true

Workflow​

export interface Workflow extends Evidenced {
name: string;
trigger: WorkflowTriggerKind;
nodes: WorkflowNode[];
designerModule?: string;
}

designerModule on the instance mirrors the package constant so a serialised workflow carries the module version it was captured against, independently of whatever version the reading package was built from.

No concrete Workflow instance ships in the package. The re-audit captured the catalogs, not a built workflow - each node was placed on a fresh canvas, screenshotted, and discarded. Shipping a fixture would mean inventing one.