Skip to Content
DocumentationBuilding with LoopstackοΈβš™οΈ WorkflowsCreating Workflows

Creating Workflows

Workflows are the core building blocks of automation in Loopstack. They define a sequence of states and transitions that execute tools to accomplish specific tasks, from simple data processing to complex multi-step business processes.

Creating a Workflow

A workflow is created by extending the WorkflowBase class and decorating it with @BlockConfig. State is defined using the @WithState decorator with a Zod schema, and tools are injected using the @Tool decorator. The workflow logic is defined in a separate YAML configuration file.

Basic Workflow Definition

import { WorkflowBase } from '@loopstack/core'; import { BlockConfig, Tool, WithState } from '@loopstack/common'; import { z } from 'zod'; import { AiGenerateText } from '@loopstack/ai-module'; import { CreateDocument } from '@loopstack/core-ui-module'; @BlockConfig({ configFile: __dirname + '/chat.workflow.yaml', }) @WithState(z.object({ llmResponse: z.any(), })) export class ChatWorkflow extends WorkflowBase { @Tool() createDocument: CreateDocument; @Tool() aiGenerateText: AiGenerateText; }

Key Components

@BlockConfig Decorator

  • Marks a class as a Loopstack block
  • Links the workflow class to its YAML configuration via configFile

@WithState Decorator

  • Defines the workflow’s state schema using Zod
  • Makes state properties accessible in YAML templates via ${ propertyName }
  • Enables the assign feature in YAML transitions to store results

@Tool Decorator

  • Injects tool dependencies into the workflow
  • Tools decorated with @Tool() become available for use in YAML transitions
  • Tool names in YAML correspond to the property names in the class

YAML Configuration

  • title and description: Metadata for the workflow
  • ui.actions: Defines custom UI actions that can trigger transitions
  • transitions: Define the flow of states and the tools executed at each step
  • call: Specifies tool calls triggered in a transition
  • assign: Assigns the result to a workflow state property for later use

Defining State

State is defined using the @WithState decorator with a Zod schema. This approach provides type safety and validation for your workflow’s state.

@WithState(z.object({ llmResponse: z.any(), messageCount: z.number().default(0), conversationHistory: z.array(z.any()).default([]), })) export class MyWorkflow extends WorkflowBase { // ... }

State properties can be accessed in YAML using template syntax:

  • ${ llmResponse } - Access the llmResponse state property
  • ${ result.data } - Access the result of the current tool call (used in assign)

Injecting Tools

Tools are injected using the @Tool decorator. Each tool must be a valid Loopstack tool class.

export class MyWorkflow extends WorkflowBase { @Tool() createDocument: CreateDocument; @Tool() aiGenerateText: AiGenerateText; @Tool() sendEmail: SendEmail; }

The property name becomes the tool identifier used in YAML:

call: - tool: createDocument # Matches @Tool() createDocument args: # ...

UI Actions

The ui.actions section allows you to define custom UI controls that trigger transitions manually.

ui: actions: - type: custom transition: user_message # The transition to trigger widget: prompt-input # The UI widget type enabledWhen: # States where this action is available - ready - waiting_for_user options: label: Send Message # Display label for the action

Transition Configuration

Basic Transition

transitions: - id: my_transition from: state_a to: state_b call: - tool: myTool args: param1: value1 param2: ${ stateProperty }

Manual Triggers

Transitions can be triggered manually by users through UI actions:

- id: user_message from: waiting_for_user to: ready trigger: manual call: - tool: createDocument args: document: aiMessageDocument update: content: role: user parts: - type: text text: ${ transition.payload }

The transition.payload provides access to data passed from the UI action.

Assigning Results

Use assign to store tool results in workflow state:

- id: prompt from: ready to: prompt_executed call: - id: execute_prompt tool: aiGenerateText args: llm: provider: openai model: gpt-4o messagesSearchTag: message assign: llmResponse: ${ result.data }

Complete Example: Chat Assistant

Here’s a complete example of a chat workflow with a system persona:

import { WorkflowBase } from '@loopstack/core'; import { BlockConfig, Tool, WithState } from '@loopstack/common'; import { z } from 'zod'; import { AiGenerateText } from '@loopstack/ai-module'; import { CreateDocument } from '@loopstack/core-ui-module'; @BlockConfig({ configFile: __dirname + '/chat.workflow.yaml', }) @WithState(z.object({ llmResponse: z.any(), })) export class ChatWorkflow extends WorkflowBase { @Tool() createDocument: CreateDocument; @Tool() aiGenerateText: AiGenerateText; }

Registering the Workflow

Add your workflow as a module provider and import it in your workspace to make it available for execution.

@Module({ imports: [LoopCoreModule], providers: [ ChatWorkflow, // ... other providers ], }) export class MyModule {}

Using Your Workflow

Once registered in a workspace, your workflow can be manually executed:

  1. Navigate to your workspace in the Loopstack Studio
  2. Click Run to create a new execution
  3. Select the workflow from the available workflows
Last updated on