In Inferable context, workflows provide a powerful “Workflow as Code” approach to orchestrating complex, multi-step AI agent interactions within the platform. Workflows are the bedrock of all AI interactions in Inferable.

Workflow Definition

Workflows are defined in your own codebase and run in your own compute environment. The control plane “discovers” your workflow when you register it, making it callable by any other machine that has access to your Inferable cluster.

import { Inferable } from "inferable";

const inferable = new Inferable({
  apiSecret: require("./cluster.json").apiKey,
});

const workflow = inferable.workflows.create({
  name: "simple",
  inputSchema: z.object({
    executionId: z.string(),
    url: z.string(),
  }),
});

workflow.version(1).define(async (ctx, input) => {
  const text = await fetch(input.url).then((res) => res.text());

  const { menuItems, hours } = ctx.llm.structured({
    input: text,
    schema: z.object({
      menuItems: z.array(
        z.object({
          name: z.string(),
          price: z.number(),
        }),
      ),
      hours: z.object({
        saturday: z.string(),
        sunday: z.string(),
      }),
    }),
  });

  return { menuItems, hours };
});

// This will register the workflow with the Inferable control-plane at api.inferable.ai
workflow.listen().then(() => {
  console.log("Workflow listening");
});

Execution ID

When you trigger a workflow, you must specify an executionId. Inferable will use this executionId as an idempotency key.

If you trigger the same workflow with the same executionId, only the first execution will be executed, and the subsequent executions will no-op.

curl -XPOST https://api.inferable.ai/clusters/$CLUSTER_ID/workflows/simple/executions \
  -d '{"executionId": "ticket-123", "data": "..."}' \
  -H "Authorization: Bearer $API_SECRET"

# Workflow starts executing

curl -XPOST https://api.inferable.ai/clusters/$CLUSTER_ID/workflows/simple/executions \
  -d '{"executionId": "ticket-123", "data": "..."}' \
  -H "Authorization: Bearer $API_SECRET"

# ... this will be a no-op

Workflow Context

Every workflow definition receives a context object. This context object is used to access the Inferable SDK and other services.

For example, you can use the llm object to interact with an LLM.

workflow.version(1).define(async (ctx, input) => {
  const result = await ctx.llm.structured({ input: "..." });
});

Context Services

  • ctx.llm - Interacting with LLMs
  • ctx.agents - Interacting with agents
  • ctx.memo - Memoizing intermediate results
  • ctx.log - Logging for workflow observability

Inputs and Outputs

The workflow input is defined when you trigger the workflow. It is passed in as a JSON object.

curl -XPOST https://api.inferable.ai/clusters/$CLUSTER_ID/workflows/simple/executions \
  -d '{"executionId": "ticket-123", "data": {"url": "https://example.com"}}' \
  -H "Authorization: Bearer $API_SECRET"
workflow.version(1).define(async (ctx, input) => {
  console.log(input); // { url: "https://example.com" }
});

The workflow output is the output of the workflow. It is returned as a JSON object.

workflow.version(1).define(async (ctx, input) => {
  return { result: "..." };
});

Versioning

Versioning allows you to evolve your workflow over time in a backwards compatible way. Workflow executions are always executed against the latest version of the workflow.

Workflow executions maintain a version affinity. If a workflow version is updated while an execution is in progress, the execution will continue to use the old version until it completes.

When you register a workflow, you can specify a version.

workflow.version(1).define(async (ctx, input) => {});

When your workflow evolves, you can register a new version.

workflow.version(2).define(async (ctx, input) => {});

Durability

Workflows are durable and fault-tolerant by default. The Inferable control plane automatically keeps track of workflow executions, their health to ensure that they are reliable and resilient.

Fault Tolerance

If a workflow fails due to a network issue or a machine failure, the control plane will automatically retry the workflow on another machine up to 3 times.

By default, the control plane will detect a workflow as stalled if it doesn’t complete within 5 minutes. In which case it will be retried on another machine up to 3 times.

You can customize this behavior by changing the workflow configuration.

const workflow = inferable.workflows.create({
  // ... other workflow options
  config: {
    timeoutSeconds: 60, // max duration of a workflow
    retryCountOnStall: 3, // max retries on stall
  },
});

Pause and Resume

Workflows can also pause indefinitely and resume later on. This is especially useful if you are waiting for a long running process to complete. In inferable, there are two main ways that a workflow can pause:

  1. Human in the Loop - The workflow pauses when waiting for human input. More on this on Human in the Loop
  2. Agentic Pause - The workflow pauses when waiting for an agent loop to complete. More on this on Agents