fabric/graph/definition

Typed graph authoring. Binding a native operation to a node retains its input and output codecs inside the node, so different node types compose without a universal application value or provider-shaped chat messages.

Definitions contain deployed code; execution records contain data. Bump the graph or operation version when changing its meaning or codecs. The structural manifest detects topology and declared contract changes, not arbitrary changes to callback implementations.

let review = definition.node_id("review")
let assert Ok(graph) =
  definition.new(
    run.DefinitionId("publishing", 1),
    entry: review,
    nodes: [definition.node(review, check, select:, accept:, destinations: [])],
    state: draft_codec,
    answer: codec.string(),
  )
  |> definition.with_max_activations(20)
  |> definition.build

build checks the graph and the settings of every operation, and reports every problem at once. A graph runs at most 100 activations by default.

Types

Why build refused a graph. This union may grow: match the variants you handle and keep a catch-all, or use describe_build_error.

pub type BuildError {
  InvalidNodeId(name: String)
  InvalidIdentity(run.DefinitionId)
  InvalidLimit(
    limit: Limit,
    value: Int,
    minimum: Int,
    maximum: Int,
  )
  DuplicateNode(NodeId)
  MissingEntry(NodeId)
  UnknownDestination(source: NodeId, destination: NodeId)
  InvalidOperation(
    node: NodeId,
    problem: operation.ConfigurationError,
  )
}

Constructors

  • InvalidNodeId(name: String)

    A node id is empty or only whitespace.

  • InvalidIdentity(run.DefinitionId)

    The graph’s or an operation’s name is empty or its version is not positive.

  • InvalidLimit(
      limit: Limit,
      value: Int,
      minimum: Int,
      maximum: Int,
    )

    A bound is outside minimum..maximum (both included), as for agent.InvalidLimit.

  • DuplicateNode(NodeId)
  • MissingEntry(NodeId)
  • UnknownDestination(source: NodeId, destination: NodeId)
  • InvalidOperation(
      node: NodeId,
      problem: operation.ConfigurationError,
    )

    A setting of the operation of the node node.

pub type Command(state, answer) {
  Continue(state, NodeId)
  Finish(state, answer)
}

Constructors

  • Continue(state, NodeId)
  • Finish(state, answer)

A built graph. Build one with build.

pub type Definition(context, state, answer) =
  @internal Definition(context, state, answer, Error)
pub type Error {
  InputSelectionFailed(String)
  OperationRejected(operation.Error)
  TransitionFailed(String)
  DestinationNotAllowed(NodeId)
  StateEncodingFailed(codec.EncodeError)
  StateDecodingFailed(String)
  AnswerEncodingFailed(codec.EncodeError)
  AnswerDecodingFailed(String)
  NodeMissing(NodeId)
  DefinitionChanged
  OperationChanged(NodeId)
  EntryChanged
  InvalidRecord(String)
}

Constructors

  • InputSelectionFailed(String)
  • OperationRejected(operation.Error)
  • TransitionFailed(String)
  • DestinationNotAllowed(NodeId)
  • StateEncodingFailed(codec.EncodeError)
  • StateDecodingFailed(String)
  • AnswerEncodingFailed(codec.EncodeError)
  • AnswerDecodingFailed(String)
  • NodeMissing(NodeId)
  • DefinitionChanged
  • OperationChanged(NodeId)
  • EntryChanged
  • InvalidRecord(String)

A bound of a graph that build checks, named after its setter. This union may grow.

pub type Limit {
  MaxActivations
}

Constructors

  • MaxActivations

    with_max_activations, at least 1.

pub opaque type Node(context, state, answer)
pub opaque type NodeId

A graph’s description, checked by build. Build one with new.

pub opaque type Spec(context, state, answer)

Values

pub fn build(
  spec: Spec(context, state, answer),
) -> Result(
  @internal Definition(context, state, answer, Error),
  List(BuildError),
)

Checks spec, and the settings of every node’s operation, and reports every problem at once.

pub fn describe_build_error(error: BuildError) -> String

One line naming the problem.

pub fn describe_build_errors(errors: List(BuildError)) -> String

One line for every problem build reported, in its order, joined with "; ".

pub fn new(
  identity: run.DefinitionId,
  entry entry: NodeId,
  nodes nodes: List(Node(context, state, answer)),
  state state: codec.Codec(state),
  answer answer: codec.Codec(answer),
) -> Spec(context, state, answer)

A graph named by identity, starting at entry, over nodes, whose state and answer state and answer encode, with at most 100 activations per run. A stored run records the identity and continues only under the same name, version and structure.

pub fn node(
  id: NodeId,
  op: @internal Operation(
    context,
    input,
    output,
    operation.Kind,
    operation.Recovery,
    operation.Invocation,
    operation.Error,
  ),
  select select: fn(state) -> Result(input, String),
  accept accept: fn(state, output) -> Result(
    Command(state, answer),
    String,
  ),
  destinations destinations: List(NodeId),
) -> Node(context, state, answer)

Selection and acceptance are pure callbacks. External effects belong to the operation body, where the runner applies policy and the start fence.

pub fn node_id(name: String) -> NodeId

The node named name. build refuses an empty or blank one (InvalidNodeId); an acceptance callback that routes to a name no node has is refused (DestinationNotAllowed).

pub fn node_name(id: NodeId) -> String
pub fn with_max_activations(
  spec: Spec(context, state, answer),
  limit: Int,
) -> Spec(context, state, answer)

At most limit activations per run, retries and node revisits included (at least 1; build reports another value as InvalidLimit(MaxActivations, ..)). A run that would start one more ends graph.Exhausted. The limit is part of the graph’s stored structure.

✨ Search Document