Skip to main content

QuickJs and WASM Functions

The Otoroshi LLM extension supports two WASM-based backends for tool functions: QuickJs (JavaScript in WASM) and WasmPlugin (full WASM plugins).

QuickJs backend

The QuickJs backend executes JavaScript code inside a WASM-based QuickJS runtime. This is the simplest way to create tool functions — write JavaScript that processes the tool arguments and returns a result.

JavaScript code format

Your JavaScript code must export a tool_call function:

'inline module';

exports.tool_call = function(args) {
const parsedArgs = JSON.parse(args);
// Process the arguments...
return JSON.stringify({
result: "your result here"
});
}

The function receives the tool arguments as a JSON string and must return a JSON string.

JavaScript source options

The jsPath option supports multiple sources:

SourceFormatDescription
InlineStart with 'inline module';JavaScript code embedded directly in the entity
URLhttps://... or http://...Fetched from a remote URL (cached for 120s)
Filefile:///path/to/script.jsLoaded from local filesystem
S3s3://bucket/path/script.jsLoaded from an S3-compatible storage

QuickJs entity configuration

{
"name": "my_tool",
"description": "Description of what the tool does",
"strict": true,
"parameters": {
"param1": {
"type": "string",
"description": "First parameter"
}
},
"required": ["param1"],
"backend": {
"kind": "QuickJs",
"options": {
"jsPath": "'inline module';\n\nexports.tool_call = function(args) {\n return JSON.stringify({ result: 'hello' });\n}"
}
}
}

The JavaScript runtime has HTTP access enabled, so your tool functions can make HTTP calls to external APIs.


WasmPlugin backend

The WasmPlugin backend executes a full WASM plugin registered in Otoroshi. This is useful for more complex tool functions or when you want to use compiled languages (Rust, Go, etc.).

WasmPlugin entity configuration

{
"name": "my_wasm_tool",
"description": "A tool backed by a WASM plugin",
"strict": true,
"parameters": {
"input": {
"type": "string",
"description": "The input"
}
},
"required": ["input"],
"backend": {
"kind": "WasmPlugin",
"options": {
"wasmPlugin": "wasm-plugin-entity-id"
}
}
}

The WASM plugin must expose a function (defaults to tool_call) that receives the arguments as a string and returns the result as a string.


Example: next_flight function

In this example, we create a QuickJs tool function named next_flight that takes two IATA airport codes and returns flight information.

Function configuration

'inline module';

exports.tool_call = function(args) {
const formattedArguments = JSON.parse(args);
return JSON.stringify({
nextflight: `flight ${parseInt(Math.random() * 10000)} from ${formattedArguments["departure"]} to ${formattedArguments["arrival"]} is taking off in ${parseInt(Math.random() * 10)} hours`
})
}

Function parameters:

{
"departure": {
"type": "string",
"description": "The departure airport (IATA airport Code)"
},
"arrival": {
"type": "string",
"description": "The arrival airport (IATA airport Code)"
}
}

Request

curl --request POST \
--url http://wasm-tool-function.oto.tools:8080/ \
--header 'content-type: application/json' \
--data '{
"messages": [
{
"role": "user",
"content": "Could you give me the next flight from CDG to DXB please ?"
}
]
}'

Response

The LLM processes the tool call transparently and returns the final answer:

{
"id": "chatcmpl-FzOsLwlxF7cgTkpBfSPfhYEEvw53X274",
"object": "chat.completion",
"created": 1743519776,
"model": "gpt-4o-mini",
"system_fingerprint": "fp-Jz72gmHTIAQw2xYamDRy3Q8kMSPUsMb0",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "The next flight from CDG (Charles de Gaulle Airport) to DXB (Dubai International Airport) is flight 3755, which is taking off in 9 hours."
},
"logprobs": null,
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 209,
"completion_tokens": 37,
"total_tokens": 246,
"completion_tokens_details": {
"reasoning_tokens": 0
}
}
}

Full entity configuration

{
"id": "tool-function_f6562221-1c0f-4f8e-aae6-279beb0144dd",
"name": "next_flight",
"description": "This function returns the next flight.",
"strict": true,
"parameters": {
"departure": {
"type": "string",
"description": "The departure airport (IATA airport Code)"
},
"arrival": {
"type": "string",
"description": "The arrival airport (IATA airport Code)"
}
},
"required": null,
"backend": {
"kind": "QuickJs",
"options": {
"jsPath": "'inline module';\n\nexports.tool_call = function(args) {\n const formattedArguments = JSON.parse(args);\n return JSON.stringify({\n nextflight: `flight ${parseInt(Math.random() * 10000)} from ${formattedArguments[\"departure\"]} to ${formattedArguments[\"arrival\"]} is taking off in ${parseInt(Math.random() * 10)} hours`\n })\n}"
}
}
}

Provider configuration

Reference the tool function in the provider's wasm_tools array:

{
"id": "provider_6699f127-34d1-4fef-b3ad-6bcf592ed9c6",
"name": "OpenAI provider + tool wasm function",
"provider": "openai",
"connection": {
"base_url": "https://api.openai.com/v1",
"token": "${vault://local/openai-token}",
"timeout": 30000
},
"options": {
"model": "gpt-4o-mini",
"wasm_tools": [
"tool-function_f6562221-1c0f-4f8e-aae6-279beb0144dd"
],
"mcp_connectors": [],
"allow_config_override": true
}
}