mirror of
https://github.com/bendtherules/ask262.git
synced 2026-08-18 13:21:55 +00:00
153 lines
5.0 KiB
TypeScript
153 lines
5.0 KiB
TypeScript
/**
|
|
* Evaluate JavaScript code in engine262 and capture spec section marks.
|
|
* Executes code in the engine262 JavaScript engine and returns the captured
|
|
* ECMAScript spec section marks as JSON.
|
|
*/
|
|
|
|
import { DynamicStructuredTool } from "@langchain/core/tools";
|
|
import { z } from "zod";
|
|
|
|
const evaluateSchema = z.object({
|
|
code: z.string().describe("JavaScript code to execute in engine262"),
|
|
});
|
|
|
|
// Type definitions for engine262 module
|
|
interface MarkData {
|
|
readonly sectionIds: string[];
|
|
readonly fileRelativePath: string;
|
|
readonly lineNumber: number;
|
|
readonly important: boolean;
|
|
}
|
|
|
|
// biome-ignore lint/suspicious/noExplicitAny: engine262 is an external module without TypeScript types
|
|
let engine262Module: any = null;
|
|
|
|
/**
|
|
* Lazy load engine262 module
|
|
*/
|
|
async function loadEngine262() {
|
|
if (!engine262Module) {
|
|
// Dynamic import of engine262 from local path
|
|
engine262Module = await import("../../engine262/lib/engine262.mjs");
|
|
}
|
|
return engine262Module;
|
|
}
|
|
|
|
/**
|
|
* Creates the evaluateInEngine262 tool.
|
|
* Executes JavaScript code in engine262 and captures spec section marks.
|
|
* @returns The evaluate_in_engine262 tool instance
|
|
*/
|
|
export function createEvaluateInEngine262Tool() {
|
|
return new DynamicStructuredTool({
|
|
name: "ask262_evaluate_in_engine262",
|
|
description:
|
|
"Executes JavaScript code in the engine262 JavaScript engine and captures which ECMAScript specification sections are hit during execution. " +
|
|
"Returns the full marks array as JSON. Useful for understanding how specific JavaScript operations map to the ECMAScript spec. " +
|
|
"ask262Debug is available globally in the execution context (no import needed). " +
|
|
"Use ask262Debug.startImportant() and ask262Debug.stopImportant() to mark important sections. " +
|
|
"Example: ask262Debug.startImportant(); let x = 1 + 2; ask262Debug.stopImportant();",
|
|
schema: evaluateSchema,
|
|
func: async ({ code }) => {
|
|
try {
|
|
const engine = await loadEngine262();
|
|
const ask262Debug = engine.ask262Debug as {
|
|
marks: MarkData[];
|
|
startTrace: () => void;
|
|
stopTrace: () => void;
|
|
startImportant: () => void;
|
|
stopImportant: () => void;
|
|
};
|
|
const Agent = engine.Agent;
|
|
const ManagedRealm = engine.ManagedRealm;
|
|
const setSurroundingAgent = engine.setSurroundingAgent;
|
|
const OrdinaryObjectCreate = engine.OrdinaryObjectCreate;
|
|
const CreateBuiltinFunction = engine.CreateBuiltinFunction;
|
|
const CreateDataProperty = engine.CreateDataProperty;
|
|
const Value = engine.Value;
|
|
const skipDebugger = engine.skipDebugger;
|
|
|
|
// Reset marks from previous runs
|
|
ask262Debug.marks = [];
|
|
|
|
// Set up agent and realm
|
|
const agent = new Agent();
|
|
setSurroundingAgent(agent);
|
|
const realm = new ManagedRealm();
|
|
|
|
// Expose ask262Debug controls to the evaluated code
|
|
realm.scope(() => {
|
|
const debugObj = OrdinaryObjectCreate(
|
|
agent.intrinsic("%Object.prototype%"),
|
|
);
|
|
skipDebugger(
|
|
CreateDataProperty(
|
|
realm.GlobalObject,
|
|
Value("ask262Debug"),
|
|
debugObj,
|
|
),
|
|
);
|
|
|
|
const startImportant = CreateBuiltinFunction(
|
|
() => {
|
|
ask262Debug.startImportant();
|
|
return Value.undefined;
|
|
},
|
|
0,
|
|
Value("startImportant"),
|
|
[],
|
|
);
|
|
skipDebugger(
|
|
CreateDataProperty(
|
|
debugObj,
|
|
Value("startImportant"),
|
|
startImportant,
|
|
),
|
|
);
|
|
|
|
const stopImportant = CreateBuiltinFunction(
|
|
() => {
|
|
ask262Debug.stopImportant();
|
|
return Value.undefined;
|
|
},
|
|
0,
|
|
Value("stopImportant"),
|
|
[],
|
|
);
|
|
skipDebugger(
|
|
CreateDataProperty(debugObj, Value("stopImportant"), stopImportant),
|
|
);
|
|
});
|
|
|
|
// Start tracing
|
|
ask262Debug.startTrace();
|
|
|
|
// Execute the code
|
|
realm.evaluateScript(code);
|
|
|
|
// Stop tracing
|
|
ask262Debug.stopTrace();
|
|
|
|
// Get captured marks
|
|
const marks = ask262Debug.marks;
|
|
|
|
// Filter and group marks by important flag
|
|
const importantMarks = marks.filter((m) => m.important);
|
|
const otherMarks = marks.filter((m) => !m.important);
|
|
|
|
// Extract sectionIds, remove fileRelativePath and lineNumber
|
|
const result = {
|
|
importantSections: importantMarks.map((m) => m.sectionIds),
|
|
otherSections: otherMarks.map((m) => m.sectionIds),
|
|
};
|
|
|
|
// Return compressed JSON
|
|
return JSON.stringify(result);
|
|
} catch (error) {
|
|
console.error(`[Tool: ask262_evaluate_in_engine262] Error: ${error}`);
|
|
return `Error executing code in engine262: ${error instanceof Error ? error.message : String(error)}`;
|
|
}
|
|
},
|
|
});
|
|
}
|