Function setupArvoMachine

  • Establishes the foundation for creating Arvo-compatible state machines.

    This function configures the core elements of an Arvo state machine, including built-in actions like enqueueArvoEvent, and enforces Arvo-specific constraints to ensure compatibility with the Arvo event-driven system.

    Type Parameters

    • TContext extends MachineContext
    • TSelfContract extends VersionedArvoContract<any, any>
    • TServiceContracts extends Record<string, VersionedArvoContract<any, any>>
    • TActions extends Record<string, NonReducibleUnknown> = {}
    • TGuards extends Record<string, NonReducibleUnknown> = {}
    • TTag extends string = string
    • TMeta extends MetaObject = MetaObject

    Parameters

    • param: {
          actions?: {
              [K in string | number | symbol]: ActionFunction<TContext, {
                  [K in string | number | symbol]: InferEmittableEventsFromVersionedArvoContract<TServiceContracts[K]>
              }[keyof TServiceContracts], {
                  [K in string | number | symbol]: InferEmittableEventsFromVersionedArvoContract<TServiceContracts[K]>
              }[keyof TServiceContracts], TActions[K], never, ToParameterizedObject<TActions>, ToParameterizedObject<TGuards>, never, {
                  [K in string | number | symbol]: EnqueueArvoEventActionParam<input<(...)[(...)]["accepts"]["schema"]>, TServiceContracts[K]["accepts"]["type"], Record<string,
                      | null
                      | string
                      | number
                      | boolean>>
              }[keyof TServiceContracts]>
          };
          contracts: {
              self: TSelfContract;
              services: TServiceContracts;
          };
          guards?: {
              [K in string | number | symbol]: ((args: {
                  context: TContext;
                  event: {
                      [K in string | number | symbol]: InferEmittableEventsFromVersionedArvoContract<TServiceContracts[K]>
                  }[keyof TServiceContracts];
              }, params: TGuards[K]) => boolean)
          };
          schemas?: unknown;
          types?: Omit<SetupTypes<TContext, {
              [K in string | number | symbol]: InferEmittableEventsFromVersionedArvoContract<TServiceContracts[K]>
          }[keyof TServiceContracts], {}, TTag, InferZodSchema<TSelfContract["accepts"]["schema"]>, {
              [K in string]: InferArvoEvent<ArvoEvent<InferZodSchema<(...)[(...)]>, Record<string, any>, K>>
          }[`arvo.orc.${ExtractOrchestratorType<TSelfContract["accepts"]["type"]>}.done`]["data"], {
              [K in string | number | symbol]: EnqueueArvoEventActionParam<input<(...)[(...)]["accepts"]["schema"]>, TServiceContracts[K]["accepts"]["type"], Record<string,
                  | null
                  | string
                  | number
                  | boolean>>
          }[keyof TServiceContracts], TMeta>,
              | "output"
              | "emitted"
              | "input"
              | "children">;
      }

      Configuration object for the machine setup

      • Optionalactions?: {
            [K in string | number | symbol]: ActionFunction<TContext, {
                [K in string | number | symbol]: InferEmittableEventsFromVersionedArvoContract<TServiceContracts[K]>
            }[keyof TServiceContracts], {
                [K in string | number | symbol]: InferEmittableEventsFromVersionedArvoContract<TServiceContracts[K]>
            }[keyof TServiceContracts], TActions[K], never, ToParameterizedObject<TActions>, ToParameterizedObject<TGuards>, never, {
                [K in string | number | symbol]: EnqueueArvoEventActionParam<input<(...)[(...)]["accepts"]["schema"]>, TServiceContracts[K]["accepts"]["type"], Record<string,
                    | null
                    | string
                    | number
                    | boolean>>
            }[keyof TServiceContracts]>
        }
      • contracts: {
            self: TSelfContract;
            services: TServiceContracts;
        }
      • Optionalguards?: {
            [K in string | number | symbol]: ((args: {
                context: TContext;
                event: {
                    [K in string | number | symbol]: InferEmittableEventsFromVersionedArvoContract<TServiceContracts[K]>
                }[keyof TServiceContracts];
            }, params: TGuards[K]) => boolean)
        }
      • Optionalschemas?: unknown
      • Optionaltypes?: Omit<SetupTypes<TContext, {
            [K in string | number | symbol]: InferEmittableEventsFromVersionedArvoContract<TServiceContracts[K]>
        }[keyof TServiceContracts], {}, TTag, InferZodSchema<TSelfContract["accepts"]["schema"]>, {
            [K in string]: InferArvoEvent<ArvoEvent<InferZodSchema<(...)[(...)]>, Record<string, any>, K>>
        }[`arvo.orc.${ExtractOrchestratorType<TSelfContract["accepts"]["type"]>}.done`]["data"], {
            [K in string | number | symbol]: EnqueueArvoEventActionParam<input<(...)[(...)]["accepts"]["schema"]>, TServiceContracts[K]["accepts"]["type"], Record<string,
                | null
                | string
                | number
                | boolean>>
        }[keyof TServiceContracts], TMeta>,
            | "output"
            | "emitted"
            | "input"
            | "children">

    Returns {
        createMachine: (<const TConfig>(config: TConfig & {
            id: string;
            version?: TSelfContract["version"];
        }) => ArvoMachine<string, TSelfContract["version"], TSelfContract, TServiceContracts, StateMachine<TContext, {
            [K in string | number | symbol]: InferEmittableEventsFromVersionedArvoContract<TServiceContracts[K]>
        }[keyof TServiceContracts], {}, never, ToParameterizedObject<TActions & {
            enqueueArvoEvent: EnqueueArvoEventActionParam;
        }>, ToParameterizedObject<TGuards>, never, {} | {} | {}, TTag, InferZodSchema<TSelfContract["accepts"]["schema"]>, {
            [K in string]: InferArvoEvent<ArvoEvent<InferZodSchema<(...)[(...)]>, Record<string, any>, K>>
        }[`arvo.orc.${ExtractOrchestratorType<TSelfContract["accepts"]["type"]>}.done`]["data"], {
            [K in string | number | symbol]: EnqueueArvoEventActionParam<input<(...)[(...)]["accepts"]["schema"]>, TServiceContracts[K]["accepts"]["type"], Record<string,
                | null
                | string
                | number
                | boolean>>
        }[keyof TServiceContracts], TMeta, any>>);
    }

    An object containing the createMachine function

    • createMachine: (<const TConfig>(config: TConfig & {
          id: string;
          version?: TSelfContract["version"];
      }) => ArvoMachine<string, TSelfContract["version"], TSelfContract, TServiceContracts, StateMachine<TContext, {
          [K in string | number | symbol]: InferEmittableEventsFromVersionedArvoContract<TServiceContracts[K]>
      }[keyof TServiceContracts], {}, never, ToParameterizedObject<TActions & {
          enqueueArvoEvent: EnqueueArvoEventActionParam;
      }>, ToParameterizedObject<TGuards>, never, {} | {} | {}, TTag, InferZodSchema<TSelfContract["accepts"]["schema"]>, {
          [K in string]: InferArvoEvent<ArvoEvent<InferZodSchema<(...)[(...)]>, Record<string, any>, K>>
      }[`arvo.orc.${ExtractOrchestratorType<TSelfContract["accepts"]["type"]>}.done`]["data"], {
          [K in string | number | symbol]: EnqueueArvoEventActionParam<input<(...)[(...)]["accepts"]["schema"]>, TServiceContracts[K]["accepts"]["type"], Record<string,
              | null
              | string
              | number
              | boolean>>
      }[keyof TServiceContracts], TMeta, any>>)
        • <const TConfig>(config): ArvoMachine<string, TSelfContract["version"], TSelfContract, TServiceContracts, StateMachine<TContext, {
              [K in string | number | symbol]: InferEmittableEventsFromVersionedArvoContract<TServiceContracts[K]>
          }[keyof TServiceContracts], {}, never, ToParameterizedObject<TActions & {
              enqueueArvoEvent: EnqueueArvoEventActionParam;
          }>, ToParameterizedObject<TGuards>, never, {} | {} | {}, TTag, InferZodSchema<TSelfContract["accepts"]["schema"]>, {
              [K in string]: InferArvoEvent<ArvoEvent<InferZodSchema<(...)[(...)]>, Record<string, any>, K>>
          }[`arvo.orc.${ExtractOrchestratorType<TSelfContract["accepts"]["type"]>}.done`]["data"], {
              [K in string | number | symbol]: EnqueueArvoEventActionParam<input<(...)[(...)]["accepts"]["schema"]>, TServiceContracts[K]["accepts"]["type"], Record<string,
                  | null
                  | string
                  | number
                  | boolean>>
          }[keyof TServiceContracts], TMeta, any>>
        • Creates an Arvo-compatible XState machine.

          Type Parameters

          • const TConfig extends Omit<StateNodeConfig<DoNotInfer<TContext>, DoNotInfer<{
                [K in string | number | symbol]: InferEmittableEventsFromVersionedArvoContract<TServiceContracts[K]>
            }[keyof TServiceContracts]>, never, DoNotInfer<ToParameterizedObject<TActions & {
                enqueueArvoEvent: EnqueueArvoEventActionParam;
            }>>, DoNotInfer<ToParameterizedObject<TGuards>>, never, DoNotInfer<TTag>, DoNotInfer<input<TSelfContract["emits"][`arvo.orc.${ExtractOrchestratorType<(...)[(...)]>}.done`]>>, DoNotInfer<{
                [K in string | number | symbol]: EnqueueArvoEventActionParam<input<(...)[(...)]>, (...)[(...)]["type"], Record<string,
                    | (...)
                    | (...)
                    | (...)
                    | (...)
                    | (...)>>
            }[keyof TServiceContracts]>, DoNotInfer<TMeta>>, "output"> & ({ version?: string | undefined; output?: input<TSelfContract["emits"][`arvo.orc.${ExtractOrchestratorType<TSelfContract["accepts"]["type"]>}.done`]> | Mapper<TContext, DoneStateEvent<unknown>, input<TSelfContract["emits"][`arvo.orc.${ExtractOrchestratorType<TSelfContract["accepts"]["type"]>}.done`]>, { [K in keyof TServiceContracts]: InferEmittableEventsFromVersionedArvoContract<TServiceContracts[K]>; }[keyof TServiceContracts]> | undefined; } & ({ context?: InitialContext<LowInfer<TContext>, never, InferArvoEvent<ArvoEvent<InferZodSchema<TSelfContract["accepts"]["schema"]>, Record<string, string | number | boolean | null>, TSelfContract["accepts"]["type"]>>, { [K in keyof TServiceContracts]: InferEmittableEventsFromVersionedArvoContract<TServiceContracts[K]>; }[keyof TServiceContracts]> | undefined; } | { context: InitialContext<LowInfer<TContext>, never, InferArvoEvent<ArvoEvent<InferZodSchema<TSelfContract["accepts"]["schema"]>, Record<string, string | number | boolean | null>, TSelfContract["accepts"]["type"]>>, { [K in keyof TServiceContracts]: InferEmittableEventsFromVersionedArvoContract<TServiceContracts[K]>; }[keyof TServiceContracts]>; }))

          Parameters

          • config: TConfig & {
                id: string;
                version?: TSelfContract["version"];
            }

            The configuration object for the machine

          Returns ArvoMachine<string, TSelfContract["version"], TSelfContract, TServiceContracts, StateMachine<TContext, {
              [K in string | number | symbol]: InferEmittableEventsFromVersionedArvoContract<TServiceContracts[K]>
          }[keyof TServiceContracts], {}, never, ToParameterizedObject<TActions & {
              enqueueArvoEvent: EnqueueArvoEventActionParam;
          }>, ToParameterizedObject<TGuards>, never, {} | {} | {}, TTag, InferZodSchema<TSelfContract["accepts"]["schema"]>, {
              [K in string]: InferArvoEvent<ArvoEvent<InferZodSchema<(...)[(...)]>, Record<string, any>, K>>
          }[`arvo.orc.${ExtractOrchestratorType<TSelfContract["accepts"]["type"]>}.done`]["data"], {
              [K in string | number | symbol]: EnqueueArvoEventActionParam<input<(...)[(...)]["accepts"]["schema"]>, TServiceContracts[K]["accepts"]["type"], Record<string,
                  | null
                  | string
                  | number
                  | boolean>>
          }[keyof TServiceContracts], TMeta, any>>

          An ArvoMachine instance

          Error if 'invoke' or 'after' configurations are used

          This function creates a state machine based on the provided configuration. It performs additional checks to ensure the machine adheres to Arvo's constraints, such as disallowing 'invoke' and 'after' configurations which could introduce asynchronous behavior.

          
          

    If 'actors', 'delays', or reserved action names are used in the configuration

    setupArvoMachine is a crucial function in the Arvo ecosystem, designed to create synchronous state machine orchestrations for Arvo's event-driven architecture. It builds upon XState, providing a tailored implementation that:

    1. Enforces synchronous behavior to maintain predictable state transitions
    2. Implements Arvo-specific constraints and features

    Key features:

    • Synchronous execution: Ensures deterministic behavior in event-driven systems
    • Built-in actions: Includes enqueueArvoEvent for Arvo event handling
    • Constraint checking: Prevents usage of asynchronous features like 'actors' or 'delays'

    While setupArvoMachine is based on XState's setup and createMachine functions, it includes Arvo-specific modifications and restrictions. For a deeper understanding of the underlying XState concepts, refer to the official XState documentation:

    Here's a comprehensive example demonstrating how to use setupArvoMachine:

    import { setupArvoMachine } from 'arvo-xstate'
    import { createArvoOrchestratorContract, ArvoErrorSchema, createArvoContract } from 'arvo-core'
    import { z } from 'zod'

    // Define the LLM orchestrator contract
    const llmContract = createArvoOrchestratorContract({
    uri: `#/orchestrators/llm/`,
    type: 'llm',
    versions: {
    '0.0.1': {
    init: z.object({
    request: z.string(),
    llm: z.enum(['gpt-4', 'gpt-4o']),
    }),
    complete: z.object({
    response: z.string(),
    })
    }
    }
    })

    // Define the OpenAI service contract
    const openAiContract = createArvoContract({
    uri: `#/services/openai`,
    type: 'com.openai.completions',
    versions: {
    '0.0.1': {
    accepts: z.object({
    request: z.string()
    }),
    emits: {
    'evt.openai.completions.success': z.object({
    response: z.string(),
    })
    }
    }
    }
    })

    const machineId = 'machineV100'

    // Set up the Arvo machine
    const llmMachine = setupArvoMachine({
    contracts: {
    self: llmContract.version('0.0.1'),
    services: {
    openAiContract.version('0.0.1'),
    }
    },
    types: {
    context: {} as {
    request: string,
    llm: string,
    response: string | null,
    errors: z.infer<typeof ArvoErrorSchema>[]
    },
    tags: {} as 'pending' | 'success' | 'error',
    },
    actions: {
    log: ({context, event}) => console.log({context, event})
    },
    guards: {
    isValid: ({context, event}) => Boolean(context.request)
    }
    }).createMachine({
    id: machineId,
    context: ({input}) => ({
    request: input.request,
    llm: input.llm,
    response: null,
    errors: [],
    }),
    initial: 'validate',
    states: {
    validate: {
    always: [
    {
    guard: 'isValid',
    target: 'llm',
    },
    {
    target: 'error',
    }
    ]
    },
    llm: {
    entry: [
    {
    type: 'log',
    },
    emit(({context}) => ({
    type: 'com.openai.completions',
    data: {
    request: context.request,
    },
    }))
    ],
    on: {
    'evt.openai.completions.success': {
    actions: [
    assign({response: ({event}) => event.response})
    ],
    target: 'done'
    },
    'sys.com.openai.completions.error': {
    actions: [
    assign({errors: ({context, event}) => [...context.errors, event.body]})
    ],
    target: 'error'
    }
    }
    },
    done: {
    type: 'final'
    },
    error: {
    type: 'final'
    },
    }
    });

    This example demonstrates:

    1. Defining Arvo contracts for the orchestrator and a service
    2. Setting up an Arvo machine with contracts, types, actions, and guards
    3. Creating a machine with states for validation, LLM interaction, and error handling
    4. Using XState features like emit bound with Arvo contracts for event emitting and event handling via transitions