generateBuildJsWrapper function

String generateBuildJsWrapper(
  1. List<Map<String, dynamic>> codeModeTools
)

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();
  }''';
}