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
.