Skip to content
This page is a translation of the authoritative Chinese source and may lag behind.View the original

Scripting API reference

GateLLM ships a JavaScript script engine (QuickJS-based) for custom transforms on request and response JSON bodies. Scripts run in a sandbox with strict resource limits — safe and controllable.

This chapter is the API reference. For an intro see Write your first script transform; for config see Scripting config.

Basic structure

Each script defines a transform function that receives body and context, and must return body:

javascript
function transform(body, context) {
    // read and modify body
    // read context for metadata (read-only)
    return body;  // required!
}
ParameterMutableDescription
bodyyesJSON request body or response body
contextnoRequest/response metadata (model name, headers, etc.)

The Context object

context provides metadata of the current request/response, read-only:

Available in both request and response phases

FieldTypeDescription
context.clientModelstringThe model name the client sees
context.upstreamModelstringThe model ID sent to the upstream
context.upstreamNamestringThe upstream group name
context.sourceProtocolstringThe client protocol (e.g. "OpenAIChatCompletions")
context.targetProtocolstringThe upstream protocol (e.g. "Anthropic")
context.streambooleanWhether it's a streaming request
context.headersobjectRequest headers (sensitive headers filtered out)
context.queryobjectURL query parameters
context.requestIdstringUnique request ID
context.clientIpstringClient IP
context.accessKeyNamestringAccess key name
context.accessKeyGroupstringAccess key group

Available in the response phase only

FieldTypeDescription
context.responseStatusnumberUpstream HTTP status code
context.responseHeadersobjectUpstream response headers
context.elapsedMsnumberElapsed time (milliseconds)

Security: sensitive headers like authorization, cookie, x-api-key are removed before scripts can see them.

context.useModel route switching

javascript
context.useModel("model-name");

Full route switch: base_url, protocol, and credentials change together. body.model = "X" only changes the request body's field, not the route — use context.useModel to switch across endpoints/protocols.

The two request-script slots (before / after)

Request-side scripts are no longer one script plus a position switch, but two independent slots, each optionally empty and configurable together:

SlotFieldRun timingBody seenuseModel capability
After translationrequest_transform_afterafter protocol translationupstream protocol formatsame-protocol switch only
Before translationrequest_transform_beforebefore protocol translationclient original formatsupports cross-protocol switch
  • request_transform_after: runs after protocol translation, the body is already in upstream format. Suitable for simple field edits and upstream-dialect rewrites.
  • request_transform_before: runs before protocol translation, the body is the client's original format. Suitable for detecting client input (images, search, plan-mode markers) and switching routes.
  • Both slots can be configured together: before and after of the same route merge independently (model overrides upstream), and both scripts run — before runs first (can trigger a cross-protocol immediate useModel switch), after runs later. Note: once the before slot triggers an immediate useModel route switch, the original route's after slot no longer runs (the whole pipeline switches to the target route's); the after slot's declared useModel is a same-protocol deferred switch. response_transform has no slot concept and stays a single field.

Execution order

The before and after slots each run independently; when both are configured for the same route, before runs first in the pre-translation phase and after in the post-translation phase. Below are the positions of the two slots in the pipeline.

Request side — after slot (post-translation)

text
client request → protocol translation → auto normalization → request_payload rules → upstream script → model script → cache injection → send to upstream

Request side — before slot (pre-translation)

text
client request → upstream script → model script → (useModel swap) → protocol translation → auto normalization → request_payload rules → cache injection → send to upstream

Response side (non-streaming only)

text
upstream response → response script → reverse protocol translation → return to client

Response scripts for streaming requests are not supported yet.

Built-in functions

JSON Path operations

javascript
// read a nested value
const temp = json_path(body, "generation_config.temperature");

// set a value (auto-creates intermediate objects)
set_path(body, "generation_config.max_output_tokens", 4096);

// remove a field
remove_path(body, "deprecated_field");

// add only when the field doesn't exist
add_if_absent_path(body, "temperature", 1.0);

// append to an array
append_path(body, "messages", { role: "system", content: "Be concise." });

String functions

javascript
str_len("Hello, 世界!");           // 9 (character count, not bytes)
str_contains("hello world", "world"); // true
str_replace("foo-bar", "-", "_");    // "foo_bar"
str_starts_with("hello", "he");     // true
str_trim("  hello  ");              // "hello"

Regular expressions

javascript
regex_match("abc123", "[0-9]+");     // true
regex_replace("foo123bar", "[0-9]+", "N");  // "fooNbar"
regex_extract("a=1 b=2", "([a-z]+)=");  // ["a", "b"]

Encoding and hashing

javascript
base64_encode("hello");    // "aGVsbG8="
base64_decode("aGVsbG8="); // "hello"
sha256("hello");           // "2cf24dba5fb0..."
json_encode(body.messages); // serialize to string
json_parse(jsonStr);        // parse from string

Array functions

javascript
array_sort([3, 1, 2]);                // [1, 2, 3]
array_unique([1, 2, 2, 3]);           // [1, 2, 3]
array_filter_by(items, "active", true); // keep elements with active=true
array_find(users, "name", "alice");    // find the first element with name=alice
array_pluck(users, "name");           // extract all name fields
array_sum([1.5, 2.5, 3.0]);           // 7.0

Deep copy and merge

javascript
const backup = deep_clone(body);  // independent copy
const merged = deep_merge(defaults, overrides);  // recursive merge

UUID and time

javascript
uuid();    // "550e8400-e29b-41d4-a716-..."
now();     // 1748620800 (second-level timestamp)
now_ms();  // millisecond-level
format_time(now(), "%Y-%m-%d %H:%M:%S");  // "2025-05-31 00:00:00"

Runtime limits, error handling, and testing

The sandbox capability boundaries (what scripts can/can't do), the resource-limit table (operation count, heap cap, concurrent execution slots, lazy-projection semantics), script_error_mode error handling, common errors and troubleshooting, the test endpoint (POST /console/api/scripts/test), and performance advice are all in Script runtime limits and configuration — that is the single authoritative page for script config and limits; this page does not repeat them.

FAQ

Q: The script changed body.model, but the route didn't change.body.model only changes the request body's field, not the route. To switch routes use context.useModel("model-name").

Q: Does a response script work for streaming requests? Streaming-response scripts are not supported yet. Request scripts work for streaming requests, but response scripts only take effect for non-streaming.

Q: How do I choose between Before and After script positions?

  • Only changing fields of the upstream-format body → After (default)
  • Needing to detect the client's original format (e.g. different protocols have different image fields) and the judgment exceeds what switch-route can express → Before
  • Pure routing decisions like "detect image/web-search → switch model" (including cross-protocol) → prefer the native switch-route rule, see Route image-bearing requests to a vision model

Next: Write your first script transform for the intro structure; Fix protocol translation with scripts and Redact responses with a script for real examples; Script runtime limits and configuration for the sandbox, resource limits, error handling, and testing.