JS Runtime
Safe execution of model generated JavaScript code in the browser.
The JavaScript runtime opens up a lot of capabilities and opportunities.
- Data transformation and orchestration
- Charting and visualizations
- Executing a series of tasks on the client
- Reduce errors and hallucinations, especially for mathematical operations
- Agentic user interfaces
How it Works
We use QuickJS, a small and embeddable JavaScript engine, compiled to a WebAssembly module using emscripten. This enables you to safely execute code in a sandbox environment.
- Define a runtime.
- Provide async functions using the
function that the model can execute in order to follow instructions and respond to a prompt. - Hashbrown generates instructions and TypeScript definitions for each function to inform the model of the function signature.
- Provide the runtime to the model using the
function. - Add the JavaScript runtime to the
toolsavailable to the model.
The createRuntime() Function
import { createRuntime } from '@hashbrownai/angular';
runtime = createRuntime({
functions: [],
});
- We define a
runtimeusingcreateRuntime(), which takes a list of functions. - We'll learn about defining functions below.
Running Code in the Runtime
With the runtime created, you can run JavaScript inside of the runtime:
const result = await this.runtime.run('2 + 2', AbortSignal.timeout(1_000));
console.log(result);
- The runtime is asynchronous by default, and may take an arbitrary amount of time to complete.
- We use the
awaitkeyword to await the result. - We must pass in an abort signal as the second parameter. We recommend using
AbortSignal.timeoutto control how long the provided script may run. - The
runmethod will return a promise of whatever the evaluation result is.
The createRuntimeFunction() Function
Define functions using the
| Option | Type | Description |
|---|---|---|
name |
string |
The name of the function that will be called in the JS runtime. |
description |
string |
A description of the function, which will be used in the LLM prompt. |
args |
Schema |
The input schema for the function (optional). Used to validate the input arguments. |
result |
Schema |
The result schema for the function (optional). Used to validate the return value. |
handler |
Function |
The function that will be executed in the JS runtime. Can be async and accepts an optional AbortSignal. |
Create Runtime with Functions
Next, let's define several functions that are executable within the JS runtime.
import { createRuntime, createRuntimeFunction } from '@hashbrownai/angular';
// 1. Create the runtime
runtime = createRuntime({
// 2. Define the functions
functions: [
// 3. Create a runtime function that returns application state
createRuntimeFunction({
name: 'getLights',
description: 'Get the current lights',
args: s.array(
'The lights',
s.object('A light', {
id: s.string('The id of the light'),
brightness: s.number('The brightness of the light'),
}),
),
handler: () => this.smartHomeService.loadLights(),
}),
// 4. Create a runtime function that mutates application state
createRuntimeFunction({
name: 'addLight',
description: 'Add a light',
args: s.object('Add light input', {
name: s.string('The name of the light'),
brightness: s.number('The brightness of the light'),
}),
result: s.object('The light', {
id: s.string('The id of the light'),
brightness: s.number('The brightness of the light'),
}),
handler: async (input) => {
const light = await this.smartHomeService.addLight(input);
return light;
},
}),
],
});
- We import
and from @hashbrownai/angular. - We define a
runtime. Each function is defined usingcreateRuntimeFunction(), which includes:name: The name of the function.description: A description of what the function does.args: The input schema for the function (optional).result: The output schema for the function (optional).handler: The function that will be executed in the JS runtime, which can be async and accepts an optionalAbortSignal.
- The
handlerfunction is executed within the JS runtime, allowing you to run JavaScript code safely. - The
resultschema describes the function return signature. - The
argsschema describes the input arguments passed to thehandlerfunction. - The
handlerfunction is executed synchronously within the JS runtime, allowing for procedural code execution.
The createToolJavaScript() Function
Provide the runtime to the tools collection using the
import { createToolJavaScript } from '@hashbrownai/angular';
chat = uiChatResource({
tools: [
createToolJavaScript({
runtime,
}),
],
});
- Use the
function to create a JavaScript tool with the runtime. - The model will use the JavaScript tool to follow instructions and respond to prompts.
Synchronous Execution
It's important to note that the handler functions are async when defined, but are executed synchronously within the runtime itself.
This enables the model to write procedural code that we believe improves the sucess rate of the model-generated code.
Next Steps
Get structured data from models
Use Skillet schema to describe model responses.
Generate user interfaces
Expose Angular components to the LLM for generative UI.