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
tools
available to the model.
The createRuntime()
Function
import { createRuntime } from '@hashbrownai/angular';
runtime = createRuntime({
functions: [],
});
- We define a
runtime
usingcreateRuntime()
, 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
await
keyword to await the result. - We must pass in an abort signal as the second parameter. We recommend using
AbortSignal.timeout
to control how long the provided script may run. - The
run
method 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
handler
function is executed within the JS runtime, allowing you to run JavaScript code safely. - The
result
schema describes the function return signature. - The
args
schema describes the input arguments passed to thehandler
function. - The
handler
function 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.