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

Script runtime limits and configuration

This chapter covers the script engine's environment variables, limits and safety, and the script testing entry. For the API reference see Scripting API reference; for an intro see Write your first script transform.

VariableDefaultPurpose
SCRIPT_MAX_OPERATIONS2000Maximum operations per script execution
SCRIPT_MEMORY_LIMIT_MB64Interpreter heap cap (MB)
SCRIPT_LAZY_BODYtrueWhether to lazily project the request/response body; false takes the legacy whole-materialization branch

These three control the operation cap and memory; other resource limits (string size, array elements, stack size, etc.) are hardcoded by the sandbox and not configurable. Environment-variable changes require a container restart to take effect. The full env-var list is in Environment variable reference.

Resource limits

LimitValueConfigurable
Max operations2,000SCRIPT_MAX_OPERATIONS
Interpreter heap cap64 MBSCRIPT_MEMORY_LIMIT_MB (a runtime-creation-time constraint; changes require restart)
Concurrent execution slots4server.script_pool_size (a TOML field, not an env var; the number of scripts running concurrently, each slot's heap bounded by SCRIPT_MEMORY_LIMIT_MB)
body lazy projectiononSCRIPT_LAZY_BODY (default true; false takes the legacy whole-materialization branch; rollback is by explicitly switching back; changes require restart)
Max string10 MBfixed
Max array/object elements10,000fixed
Regex cache256 entries, 5-minute TTLfixed
Stack size1024 framesfixed

ℹ️ body view semantics: with SCRIPT_LAZY_BODY=true, body is a lazy-projection view that materializes on access; the whole body doesn't enter the JS heap, and JS heap usage only tracks the fields the script accesses. The view is consistent with a real object under standard checks like Array.isArray / instanceof / typeof / Object.keys / destructuring / spread / JSON.stringify / array methods. Known boundary: body.x === body.x is false (the shell isn't cached); scripts relying on same-path reference equality must compare by value instead.

Sandbox limits

What scripts can do

  • Read and modify body
  • Read context metadata
  • Use all built-in functions (json_path, str_, regex_, array_*, etc.)
  • Define helper functions
  • Use standard JavaScript (loops, conditionals, closures, destructuring, etc.)

What scripts cannot do

ForbiddenReason
console.log / printPrevent information leakage
File I/ONo filesystem access
Network / fetchNo network access
import / requireCannot load external code
eval / FunctionCannot dynamically execute code
globalThis mutationThe global object is frozen

Error handling

script_error_mode

ModeBehaviorUse case
log-and-continue (default)On script error, logs a warn and continues the request with the original bodyScript failure shouldn't block requests
log-and-rejectOn script error, rejects the request and returns a gateway errorScript correctness is critical (e.g. security redaction)

Common errors

ErrorCauseFix
transform() must return a valueSome return path forgot to return bodyEvery return must return body
TooManyOperationsExceeded the operation cap (default 2000)Optimize loops
TypeErrorAccessing a property of null/undefinedCheck with json_path() or the in operator
ReferenceErrorUsing an undefined variable or functionCheck spelling

Early returns must return body

javascript
function transform(body, context) {
    // ✅ correct
    if (!body.messages) return body;

    // ❌ wrong: returning no value → the script silently fails
    if (!body.messages) return;

    body.messages[0].content = "modified";
    return body;
}

Script testing

Test scripts before deploying. The test endpoint POST /console/api/scripts/test needs console auth — pass it via the $CONSOLE_TOKEN environment variable (it is not the upstream access key; it's the console API credential). Get it either of two ways:

Getting CONSOLE_TOKEN

Way 1: configure CONSOLE_SECRET_KEY (recommended for scripts / CI) — set the CONSOLE_SECRET_KEY environment variable; the console uses it as a Bearer token, long-lived and never expires:

bash
# inject at gateway startup
docker run -d -e CONSOLE_SECRET_KEY="my-secret-key-xxx" ... <image>

# pass it when testing scripts
export CONSOLE_TOKEN="my-secret-key-xxx"

Way 2: log in with a console account to get a session token — use this path when CONSOLE_SECRET_KEY isn't configured. POST /console/api/login logs in with account/password; the returned token field is the session token (valid 24 hours by default; calls slide-renew it):

bash
export CONSOLE_TOKEN=$(curl -s http://localhost:7890/console/api/login \
  -H "Content-Type: application/json" \
  -d '{"username":"protoflux","password":"your-password"}' | jq -r .token)

CONSOLE_SECRET_KEY and the login password (CONSOLE_PASSWORD) are independent; you can configure only one. See Console login and roles.

bash
curl -X POST http://localhost:7890/console/api/scripts/test \
  -H "Authorization: Bearer $CONSOLE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "script": "function transform(body, context) { body.model = context.upstreamModel; return body; }",
    "body": {"model": "gpt-4o", "messages": []},
    "context": {
      "clientModel": "gpt-4o",
      "upstreamModel": "gpt-4o-2024-05-13",
      "upstreamName": "openai",
      "sourceProtocol": "OpenAIChatCompletions",
      "targetProtocol": "OpenAIChatCompletions",
      "stream": false
    }
  }'

Response:

json
{
  "result_body": {"model": "gpt-4o-2024-05-13", "messages": []},
  "execution_time_ms": 0.12
}

Performance advice

Performance and memory

Script overhead mainly comes from JSON serialization; latency grows linearly with the body. For the after-slot large-body OOM anti-pattern, latency references, and writing advice, see Script performance and memory.

FAQ

Q: Where do I configure scripts in the console UI? Both the upstream detail page and the model detail page have "Request script" and "Response script" input boxes. You can also set them directly via the Console API.

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: The script errored but the request passed normally? In the default log-and-continue mode, script errors don't block requests. Check the warn log for the error reason. If the script must succeed, switch to log-and-reject.

Q: Why is there no Authorization in context.headers? Security design: sensitive headers like authorization, cookie, x-api-key are removed before scripts can see them, to prevent credential leakage.

Q: How do I raise the operation cap?SCRIPT_MAX_OPERATIONS is tunable. But optimize the script first — TooManyOperations usually means loop complexity is too high.

Next: Scripting API reference for the full built-in function table; Write your first script transform for the intro structure; Environment variable reference for all environment variables; Audit and security configuration for other security settings.