CEL expressions

CEL expressions

Agentgateway uses the CEL expression language throughout the project to enable flexibility. CEL allows writing simple expressions based on the request context that evaluate to some result.

Example expressions

Below shows some example expressions that can be used in logs, traces, etc:

# Include logs where there was no response or there was an error
filter: |
   !has(response) || response.code > 299   
fields:
  add:
    user.agent: 'request.headers["user-agent"]'
    # A static string. Note the expression is a string, and it returns a string, hence the double quotes.
    span.name: '"openai.chat"'
    gen_ai.usage.prompt_tokens: 'llm.input_tokens'
    # Parse the JSON request body, and conditionally log...
    # * If `type` is sum, val1+val2
    # * Else, val3
    # Example JSON request: `{"type":"sum","val1":2,"val2":3,"val4":"hello"}`
    json.field: |
      json(request.body).with(b,
         b.type == "sum" ?
           b.val1 + b.val2 :
           b.val3
      )      

Some example authorization policies:

mcpAuthorization:
  rules:
  # Allow anyone to call 'echo'
  - 'mcp.tool.name == "echo"'
  # Only the test-user can call 'add'
  - 'jwt.sub == "test-user" && mcp.tool.name == "add"'
  # Any authenticated user with the claim `nested.key == value` can access 'printEnv'
  - 'mcp.tool.name == "printEnv" && jwt.nested.key == "value"'

Some example rate limiting rules:

remoteRateLimit:
   descriptors:
   # Rate limit requests based on a header, whether the user is authenticated, and a static value (used to match a specific rate limit rule on the rate limit server)
   - entries:
      - key: some-static-value
        value: '"something"'
      - key: organization
        value: 'request.headers["x-organization"]'
      - key: authenticated
        value: 'has(jwt.sub)'

Context reference

When using CEL, various variables and functions are provided, listed below:

Field Description
request request contains attributes about the incoming HTTP request
request.method The HTTP method of the request.
request.uri The URI of the request.
request.path The path of the request URI.
request.headers The headers of the request.
request.body The body of the request. Warning: accessing the body will cause the body to be buffered.
response response contains attributes about the HTTP response
response.code The HTTP status code of the response.
jwt jwt contains the claims from a verified JWT token. This is only present if the JWT policy is enabled.
llm llm contains attributes about an LLM request or response. This is only present when using an ai backend.
llm.streaming Whether the LLM response is streamed.
llm.requestModel The model requested for the LLM request. This may differ from the actual model used.
llm.responseModel The model that actually served the LLM response.
llm.provider The provider of the LLM.
llm.inputTokens The number of tokens in the input/prompt.
llm.outputTokens The number of tokens in the output/completion.
llm.totalTokens The total number of tokens for the request.
llm.prompt The prompt sent to the LLM. Warning: accessing this has some performance impacts for large prompts.
llm.prompt[].role
llm.prompt[].content
llm.completion The completion from the LLM. Warning: accessing this has some performance impacts for large responses.
llm.params The parameters for the LLM request.
llm.params.temperature
llm.params.top_p
llm.params.frequency_penalty
llm.params.presence_penalty
llm.params.seed
llm.params.max_tokens
source source contains attributes about the source of the request.
source.address The IP address of the downstream connection.
source.port The port of the downstream connection.
source.identity The (Istio SPIFFE) identity of the downstream connection, if available.
source.identity.trustDomain The trust domain of the identity.
source.identity.namespace The namespace of the identity.
source.identity.serviceAccount The service account of the identity.
mcp mcp contains attributes about the MCP request.
mcp.(any)(1)tool
mcp.(any)(1)tool.target The target of the resource
mcp.(any)(1)tool.name The name of the resource
mcp.(any)(1)prompt
mcp.(any)(1)prompt.target The target of the resource
mcp.(any)(1)prompt.name The name of the resource
mcp.(any)(1)resource
mcp.(any)(1)resource.target The target of the resource
mcp.(any)(1)resource.name The name of the resource

Certain fields will only be populated if they are referenced in a CEL expression. This avoids, for example, expensive buffering of request bodies if no CEL expression depends on the body.

Depending on the policy, different fields will be accessible based on when in the request processing they are applied

Policy Available Variables
Transformation source, request, jwt
Remote Rate Limit source, request, jwt
HTTP Authorization source, request, jwt
MCP Authorization source, request, jwt, mcp
Logging source, request, jwt, mcp, response, llm
Tracing source, request, jwt, mcp, response, llm
Metrics source, request, jwt, mcp, response, llm

The following functions are available, and can be used in all policy types:

Function Purpose
json Parse a string or bytes as JSON. Example: json(request.body).some_field.
with CEL does not allow variable bindings. with allows doing this. Example: json(request.body).with(b, b.field_a + b.field_b)
variables variables exposes all of the variables available as a value. CEL otherwise does not allow accessing all variables without knowing them ahead of time. Warning: this automatically enables all fields to be captured.
map_values map_values applies a function to all values in a map. map in CEL only applies to map keys.
flatten Usable only for logging and tracing. flatten will flatten a list or struct into many fields. For example, defining headers: 'flatten(request.headers)' would log many keys like headers.user-agent: "curl", etc.
flatten_recursive Usable only for logging and tracing. Like flatten but recursively flattens multiple levels.
base64_encode Encodes a string to a base64 string. Example: base64_encode("hello").
base64_decode Decodes a string in base64 format. Example: string(base64_decode("aGVsbG8K")). Warning: this returns bytes, not a String. Various parts of agentgateway will display bytes in base64 format, which may appear like the function does nothing if not converted to a string.
random Generates a number float from 0.0-1.0

Additionally, the following standard functions are available:

  • contains, size, has, map, filter, all, max, startsWith, endsWith, string, bytes, double, exists, exists_one, int, uint, matches.
  • Duration/time functions: duration, timestamp, getFullYear, getMonth, getDayOfYear, getDayOfMonth, getDate, getDayOfWeek, getHours, getMinutes, getSeconds, getMilliseconds.
  • From the strings extension: charAt, indexOf, join, lastIndexOf, lowerAscii, upperAscii, trim, replace, split, substring.