Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions tools/ui/src/lib/constants/sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ export const SANDBOX_TOOL_DEFINITION: OpenAIToolDefinition = {
type: ToolCallType.FUNCTION,
function: {
name: SANDBOX_TOOL_NAME,
description:
'Execute JavaScript in a sandboxed browser worker (no DOM, no page access). ' +
'Top level await is supported. Use console.log to print intermediate values; ' +
'a top level return statement is captured as the result.',
description: `Execute JS in a sandboxed browser worker (no DOM/page access). Top-level await ok; console.log for intermediates; top-level return is captured as result.
Symbolic/numeric math via \`nerdamer\` (pre-loaded, do not require, use it directly). Object.keys(nerdamer).filter(k=>typeof nerdamer[k]==='function') list functions.
nerdamer('diff(sin(x)/x,x)') or nerdamer.diff('sin(x)/x','x') → Expression; convert with .toString()/.text()/.toTeX(), or .evaluate() (→ still Expression, then .toString()).
nerdamer(expr,{x:2}) substitutes only; chain .evaluate() or pass 'numer' for numeric result.
solve(expr,var)→Symbol[]; solveEquations([eq1,..])→[[var,val],..] pairs.
Functions: simplify/expand/factor(expr), diff(expr,var[,n]), integrate(expr,var), defint(expr,from,to,var), limit(expr,var,to), laplace(expr,t,s), ilt(expr,s,t), gcd/lcm(a,b), roots/coeffs/partfrac(expr,var), pfactor(n), numer/decimals/erf(expr), product/sum(expr,var,from,to), mean/median/stdev/variance(...vals)`,
parameters: {
type: JsonSchemaType.OBJECT,
properties: {
Expand Down
11 changes: 10 additions & 1 deletion tools/ui/src/lib/services/sandbox-harness.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
/**
* nerdamer-prime.js downloaded from https://raw.githubusercontent.com/together-science/nerdamer-prime/refs/heads/main/all.min.js
* Upstream commit for all.min.js: https://github.com/together-science/nerdamer-prime/commit/fffcce3ebd74fefb51fcf90b613f088fcab4fd93
*/
import { NEWLINE } from '$lib/constants';
import WORKER_SHIM from './sandbox-worker.js?raw';
import NERDAMER_JS from '../vendors/nerdamer-prime.js?raw';

/**
* Harness loaded as srcdoc into a sandboxed iframe (allow-scripts only).
* The opaque origin is the security boundary: no access to the app origin,
* its storage or its API. The harness spawns a worker so model code never
* runs on a main thread, which makes the parent timeout enforceable by
* removing the iframe.
*
* nerdamer is preloaded in the worker, exposing the `nerdamer` global for
* symbolic computation (simplify, derivative, integrate, solve, etc.).
*/
export const SANDBOX_HARNESS_HTML = `<!doctype html><script>
const SHIM = ${JSON.stringify(WORKER_SHIM)};
const SHIM = ${JSON.stringify(NERDAMER_JS + NEWLINE + WORKER_SHIM)};
addEventListener('message', (event) => {
const respond = (payload) => parent.postMessage(payload, '*');
let worker;
Expand Down
6 changes: 5 additions & 1 deletion tools/ui/src/lib/services/sandbox-worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ self.onmessage = async (event) => {
const reply = { logs, result: null, error: null };
try {
const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor;
const value = await new AsyncFunction(event.data.code)();
// Inject `nerdamer` (from preloaded nerdamer-prime.js) into the execution context.
// User code can use: nerdamer(expr), nerdamer.solve(), nerdamer.derivative(),
// nerdamer.integrate(), nerdamer.expand(), nerdamer.factor(), nerdamer.simplify(),
// nerdamer.laplace(), nerdamer.limit(), nerdamer.series(), etc.
const value = await new AsyncFunction('nerdamer', event.data.code)(self.nerdamer);
if (value !== undefined) reply.result = fmt(value);
} catch (err) {
reply.error = err instanceof Error ? err.stack || err.message : String(err);
Expand Down
28 changes: 28 additions & 0 deletions tools/ui/src/lib/vendors/nerdamer-prime.js
Comment thread
rankaiyx marked this conversation as resolved.
Resolved

Large diffs are not rendered by default.