generateBuildJsWrapper function
Generates the _buildJsWrapper method that constructs the JS sandbox script.
Implementation
String generateBuildJsWrapper(List<Map<String, dynamic>> codeModeTools) {
final externalFunctions = codeModeTools
.map((t) {
final name = t['name'] as String;
return ' sb.writeln("async function external_$name(args) { return call_tool(\'$name\', args); }");';
})
.join('\n');
return '''
String _buildJsWrapper(String userCode) {
final sb = StringBuffer();
sb.writeln('// Code Mode Sandbox - IPC Layer');
sb.writeln('const __pending = {};');
sb.writeln('let __callId = 0;');
sb.writeln("let __buffer = '';");
sb.writeln();
sb.writeln("process.stdin.on('data', (chunk) => {");
sb.writeln(' __buffer += chunk.toString();');
sb.writeln(" const lines = __buffer.split('\\\\n');");
sb.writeln(' __buffer = lines.pop();');
sb.writeln(' for (const line of lines) {');
sb.writeln(" if (!line.trim()) continue;");
sb.writeln(' try {');
sb.writeln(' const msg = JSON.parse(line);');
sb.writeln(" if (msg.type === 'result' && __pending[msg.callId]) {");
sb.writeln(' const { resolve, reject } = __pending[msg.callId];');
sb.writeln(' if (msg.error) { reject(new Error(msg.error)); }');
sb.writeln(' else { resolve(msg.data); }');
sb.writeln(' delete __pending[msg.callId];');
sb.writeln(' }');
sb.writeln(' } catch (e) {}');
sb.writeln(' }');
sb.writeln('});');
sb.writeln();
sb.writeln('function __send(msg) {');
sb.writeln(" process.stdout.write(JSON.stringify(msg) + '\\\\n');");
sb.writeln('}');
sb.writeln();
sb.writeln('async function __externalCall(tool, args) {');
sb.writeln(' const callId = String(++__callId);');
sb.writeln(' return new Promise((resolve, reject) => {');
sb.writeln(' __pending[callId] = { resolve, reject };');
sb.writeln(" __send({ type: 'call', callId, tool, args: args || {} });");
sb.writeln(' });');
sb.writeln('}');
sb.writeln();
sb.writeln('// Generic tool invocation function');
sb.writeln('async function call_tool(name, params) {');
sb.writeln(' return __externalCall(name, params || {});');
sb.writeln('}');
sb.writeln();
sb.writeln('// External Tool Functions (convenience wrappers)');
$externalFunctions
sb.writeln();
sb.writeln('// Execute user code');
sb.writeln('(async () => {');
sb.writeln(' try {');
sb.writeln(' const __result = await (async () => {');
// Auto-return expression-like code (IIFE or bare await) so the LLM
// doesn't need to remember an explicit return for single-expression snippets.
final trimmedCode = userCode.trim();
final isExpressionLike = trimmedCode.startsWith('(') || trimmedCode.startsWith('await ');
final alreadyHasReturn = trimmedCode.startsWith('return ');
final codeToRun = (isExpressionLike && !alreadyHasReturn) ? 'return ' + userCode : userCode;
sb.writeln(codeToRun);
sb.writeln(' })();');
sb.writeln(" __send({ type: 'done', result: __result });");
sb.writeln(' } catch (e) {');
sb.writeln(" __send({ type: 'error', message: e.message || String(e) });");
sb.writeln(' }');
sb.writeln('})();');
return sb.toString();
}''';
}