C3 AI Documentation Home

Use Expression Functions

You can define logic for access controls and function behavior using functions from ExpressionEngineFunction and Ann.Call. Once you define expressions on your Types and make method calls that use those Types, the Expr Type evaluates the expression and determines behavior.

The following sections provide examples on how to use ExpressionEngineFunction in various ways.

Use expression functions in access controls

You can use expressions in AclPrivilege objects to define who has access to a Type.

Consider the example AclPrivilege object:

JSON
{
  "id" : "Foo_AclPrivilege",
  "typeName" : "Foo",
  "canUpdate" : "true",
  "canRemove" : "true",
  "canModifyAcl" : "false",
  "acl" : {
    "expr" : "intersects('<UserGroup>', _context.accessControlEntities.id)"
  }
}

The expression intersects('<UserGroup>', _context.accessControlEntities.id) specifies the following:

  • intersects: A function from ExpressionEngineFunction that checks for overlap between two sets or collections.
  • '<UserGroup>': A specific user group name.
  • _context.accessControlEntities.id: The collection of access control entity IDs that the current user belongs to. This includes their user groups, roles, and other access control entities. See ActionCtxFilter#accessControlEntities.

This expression uses the ExpressionEngineFunction#intersects function to check if the current user is a member of the specified user group. In other words, if there is an intersection between the specified group and the user's access control entities, the expression grants the user access to the object.

See Add Access Controls to a Type Using AclEnabled and Add Access Controls to a Role using Data Permissions to learn how to add access controls to a Type or role.

Use expression functions with Ann.Call

You can use Ann.Call expressions to indicate where functions run when they are called. The following examples use the Ann.Call#nodePool expression to determine which node pool the function runs on.

Model name example

Consider the dispatchToModel function:

JavaScript
  
  @call(nodePool='modelName') // Where modelName is nodePool
  dispatchToModel: function(modelName: !string, function: !lambda)

The @call annotation contains the expression (nodePool='modelName'), which specifies the node pool where the function runs. In this example, the dispatchToModel function runs on the node pool that matches the modelName parameter.

If a user calls the function, the Expr Type evaluates (nodePool='modelName') where ModelName is GPT4:

JavaScript
dispatchToModel("GPT4", () => { <model_logic> })

This example might be useful if you have multiple AI models running on different node pools, and need to route function calls to specific infrastructure based on the model name.

Random function example

Consider the distributeToNodePool function:

JavaScript
  @call(nodePool='random(1,10)') // Randomly dispatch each call to node pools named "1" through "10" to load balance calls
  distributeToNodePool: function(function: !lambda)  

The @call annotation contains the expression (nodePool='random(1,10)'), which uses the ExpressionEngineFunction#random function to generate a random number between 1 and 10. Each time the function is called, the Expr Type evaluates the function to a random number between 1 and 10 and randomly assigns the call to one of 10 different node pools named "1" through "10".

The randomization provides a statistically-likely even distribution across your infrastructure. This function is a simple example of how you can distribute function calls among multiple node pools.

See Understanding Action Engines to learn more about action engines and the @call annotation.

Was this page helpful?