// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import path from 'node:path'; import util from 'node:util'; import Fuse from 'fuse.js'; import ts from 'typescript'; import { WorkerOutput } from './code-tool-types'; import { SGPClient, ClientOptions } from 'scale-gp'; async function tseval(code: string) { return import('data:application/typescript;charset=utf-8;base64,' + Buffer.from(code).toString('base64')); } function getRunFunctionSource(code: string): { type: 'declaration' | 'expression'; client: string | undefined; code: string; } | null { const sourceFile = ts.createSourceFile('code.ts', code, ts.ScriptTarget.Latest, true); const printer = ts.createPrinter(); for (const statement of sourceFile.statements) { // Check for top-level function declarations if (ts.isFunctionDeclaration(statement)) { if (statement.name?.text === 'run') { return { type: 'declaration', client: statement.parameters[0]?.name.getText(), code: printer.printNode(ts.EmitHint.Unspecified, statement.body!, sourceFile), }; } } // Check for variable declarations: const run = () => {} or const run = function() {} if (ts.isVariableStatement(statement)) { for (const declaration of statement.declarationList.declarations) { if ( ts.isIdentifier(declaration.name) && declaration.name.text === 'run' && // Check if it's initialized with a function declaration.initializer && (ts.isFunctionExpression(declaration.initializer) || ts.isArrowFunction(declaration.initializer)) ) { return { type: 'expression', client: declaration.initializer.parameters[0]?.name.getText(), code: printer.printNode(ts.EmitHint.Unspecified, declaration.initializer, sourceFile), }; } } } } return null; } function getTSDiagnostics(code: string): string[] { const functionSource = getRunFunctionSource(code)!; const codeWithImport = [ 'import { SGPClient } from "scale-gp";', functionSource.type === 'declaration' ? `async function run(${functionSource.client}: SGPClient)` : `const run: (${functionSource.client}: SGPClient) => Promise =`, functionSource.code, ].join('\n'); const sourcePath = path.resolve('code.ts'); const ast = ts.createSourceFile(sourcePath, codeWithImport, ts.ScriptTarget.Latest, true); const options = ts.getDefaultCompilerOptions(); options.target = ts.ScriptTarget.Latest; options.module = ts.ModuleKind.NodeNext; options.moduleResolution = ts.ModuleResolutionKind.NodeNext; const host = ts.createCompilerHost(options, true); const newHost: typeof host = { ...host, getSourceFile: (...args) => { if (path.resolve(args[0]) === sourcePath) { return ast; } return host.getSourceFile(...args); }, readFile: (...args) => { if (path.resolve(args[0]) === sourcePath) { return codeWithImport; } return host.readFile(...args); }, fileExists: (...args) => { if (path.resolve(args[0]) === sourcePath) { return true; } return host.fileExists(...args); }, }; const program = ts.createProgram({ options, rootNames: [sourcePath], host: newHost, }); const diagnostics = ts.getPreEmitDiagnostics(program, ast); return diagnostics.map((d) => { const message = ts.flattenDiagnosticMessageText(d.messageText, '\n'); if (!d.file || !d.start) return `- ${message}`; const { line: lineNumber } = ts.getLineAndCharacterOfPosition(d.file, d.start); const line = codeWithImport.split('\n').at(lineNumber)?.trim(); return line ? `- ${message}\n ${line}` : `- ${message}`; }); } const fuse = new Fuse( [ 'client.responses.create', 'client.completions.create', 'client.chat.completions.create', 'client.chat.completions.models', 'client.inference.create', 'client.questions.archive', 'client.questions.create', 'client.questions.list', 'client.questions.restore', 'client.questions.retrieve', 'client.questions.update', 'client.files.create', 'client.files.delete', 'client.files.importFromCloud', 'client.files.list', 'client.files.retrieve', 'client.files.update', 'client.files.content.retrieve', 'client.models.create', 'client.models.delete', 'client.models.list', 'client.models.retrieve', 'client.models.update', 'client.datasets.archive', 'client.datasets.create', 'client.datasets.list', 'client.datasets.retrieve', 'client.datasets.update', 'client.datasetItems.archive', 'client.datasetItems.batchCreate', 'client.datasetItems.list', 'client.datasetItems.retrieve', 'client.datasetItems.update', 'client.evaluations.archive', 'client.evaluations.create', 'client.evaluations.filter', 'client.evaluations.list', 'client.evaluations.retrieve', 'client.evaluations.retrieveSchema', 'client.evaluations.retrieveTaxonomy', 'client.evaluations.update', 'client.evaluationItems.export', 'client.evaluationItems.list', 'client.evaluationItems.retrieve', 'client.rubrics.archive', 'client.rubrics.create', 'client.rubrics.list', 'client.rubrics.retrieve', 'client.rubrics.update', 'client.rubrics.criteria.create', 'client.rubrics.criteria.listVersions', 'client.rubrics.criteria.update', 'client.evaluationGroups.archive', 'client.evaluationGroups.create', 'client.evaluationGroups.list', 'client.evaluationGroups.replace', 'client.evaluationGroups.retrieve', 'client.evaluationGroups.retrieveSchema', 'client.evaluationGroups.update', 'client.evaluationDashboards.archive', 'client.evaluationDashboards.create', 'client.evaluationDashboards.list', 'client.evaluationDashboards.retrieve', 'client.evaluationDashboards.update', 'client.evaluationDashboards.widgets.create', 'client.evaluationDashboards.widgets.remove', 'client.evaluationDashboards.widgets.update', 'client.spans.batch', 'client.spans.create', 'client.spans.retrieve', 'client.spans.search', 'client.spans.update', 'client.spans.upsertBatch', 'client.spanAssessments.create', 'client.spanAssessments.delete', 'client.spanAssessments.list', 'client.spanAssessments.retrieve', 'client.spanAssessments.update', 'client.credentials.create', 'client.credentials.decrypt', 'client.credentials.decryptByName', 'client.credentials.delete', 'client.credentials.list', 'client.credentials.retrieve', 'client.credentials.retrieveByName', 'client.credentials.update', 'client.build.cancel', 'client.build.create', 'client.build.list', 'client.build.logs', 'client.build.retrieve', 'client.deploy.create', 'client.deploy.list', 'client.deploy.logs', 'client.deploy.retrieve', 'client.vectorStores.configure', 'client.vectorStores.count', 'client.vectorStores.create', 'client.vectorStores.delete', 'client.vectorStores.drop', 'client.vectorStores.list', 'client.vectorStores.query', 'client.vectorStores.retrieve', 'client.vectorStores.upsert', 'client.vectorStores.vectors.list', 'client.vectorStores.vectors.retrieve', ], { threshold: 1, shouldSort: true }, ); function getMethodSuggestions(fullyQualifiedMethodName: string): string[] { return fuse .search(fullyQualifiedMethodName) .map(({ item }) => item) .slice(0, 5); } const proxyToObj = new WeakMap(); const objToProxy = new WeakMap(); type ClientProxyConfig = { path: string[]; isBelievedBad?: boolean; }; function makeSdkProxy(obj: T, { path, isBelievedBad = false }: ClientProxyConfig): T { let proxy: T = objToProxy.get(obj); if (!proxy) { proxy = new Proxy(obj, { get(target, prop, receiver) { const propPath = [...path, String(prop)]; const value = Reflect.get(target, prop, receiver); if (isBelievedBad || (!(prop in target) && value === undefined)) { // If we're accessing a path that doesn't exist, it will probably eventually error. // Let's proxy it and mark it bad so that we can control the error message. // We proxy an empty class so that an invocation or construction attempt is possible. return makeSdkProxy(class {}, { path: propPath, isBelievedBad: true }); } if (value !== null && (typeof value === 'object' || typeof value === 'function')) { return makeSdkProxy(value, { path: propPath, isBelievedBad }); } return value; }, apply(target, thisArg, args) { if (isBelievedBad || typeof target !== 'function') { const fullyQualifiedMethodName = path.join('.'); const suggestions = getMethodSuggestions(fullyQualifiedMethodName); throw new Error( `${fullyQualifiedMethodName} is not a function. Did you mean: ${suggestions.join(', ')}`, ); } return Reflect.apply(target, proxyToObj.get(thisArg) ?? thisArg, args); }, construct(target, args, newTarget) { if (isBelievedBad || typeof target !== 'function') { const fullyQualifiedMethodName = path.join('.'); const suggestions = getMethodSuggestions(fullyQualifiedMethodName); throw new Error( `${fullyQualifiedMethodName} is not a constructor. Did you mean: ${suggestions.join(', ')}`, ); } return Reflect.construct(target, args, newTarget); }, }); objToProxy.set(obj, proxy); proxyToObj.set(proxy, obj); } return proxy; } function parseError(code: string, error: unknown): string | undefined { if (!(error instanceof Error)) return; const cause = error.cause instanceof Error ? `: ${error.cause.message}` : ''; const message = error.name ? `${error.name}: ${error.message}${cause}` : `${error.message}${cause}`; try { // Deno uses V8; the first ":LINE:COLUMN" is the top of stack. const lineNumber = error.stack?.match(/:([0-9]+):[0-9]+/)?.[1]; // -1 for the zero-based indexing const line = lineNumber && code .split('\n') .at(parseInt(lineNumber, 10) - 1) ?.trim(); return line ? `${message}\n at line ${lineNumber}\n ${line}` : message; } catch { return message; } } const fetch = async (req: Request): Promise => { const { opts, code } = (await req.json()) as { opts: ClientOptions; code: string }; const runFunctionSource = code ? getRunFunctionSource(code) : null; if (!runFunctionSource) { const message = code ? 'The code is missing a top-level `run` function.' : 'The code argument is missing. Provide one containing a top-level `run` function.'; return Response.json( { is_error: true, result: `${message} Write code within this template:\n\n\`\`\`\nasync function run(client) {\n // Fill this out\n}\n\`\`\``, log_lines: [], err_lines: [], } satisfies WorkerOutput, { status: 400, statusText: 'Code execution error' }, ); } const diagnostics = getTSDiagnostics(code); if (diagnostics.length > 0) { return Response.json( { is_error: true, result: `The code contains TypeScript diagnostics:\n${diagnostics.join('\n')}`, log_lines: [], err_lines: [], } satisfies WorkerOutput, { status: 400, statusText: 'Code execution error' }, ); } const client = new SGPClient({ ...opts, }); const log_lines: string[] = []; const err_lines: string[] = []; const originalConsole = globalThis.console; globalThis.console = { ...originalConsole, log: (...args: unknown[]) => { log_lines.push(util.format(...args)); }, error: (...args: unknown[]) => { err_lines.push(util.format(...args)); }, }; try { let run_ = async (client: any) => {}; run_ = (await tseval(`${code}\nexport default run;`)).default; const result = await run_(makeSdkProxy(client, { path: ['client'] })); return Response.json({ is_error: false, result, log_lines, err_lines, } satisfies WorkerOutput); } catch (e) { return Response.json( { is_error: true, result: parseError(code, e), log_lines, err_lines, } satisfies WorkerOutput, { status: 400, statusText: 'Code execution error' }, ); } finally { globalThis.console = originalConsole; } }; export default { fetch };