e2b-dev / code-interpreter

Python & JS/TS SDK for adding code interpreting to your AI app
https://e2b.dev
Apache License 2.0
809 stars 51 forks source link

Add support for additional language runtimes #20

Open jakubno opened 3 weeks ago

jakubno commented 3 weeks ago

Support for multiple languages

Description

This feature adds following kernels (= language runtimes) to the Code Interpreter SDK (besides the default Python):

Installation

You need to install a pre-release version of the SDK

Python

pip install e2b-code-interpreter==0.0.10a0

JavaScript/TypeScript

npm i @e2b/code-interpreter@0.0.9-multikernel-code-interpreterer.0

Usage

You can use multiple kernels in a single code interpreter sandbox.

Python

with CodeInterpreter() as sandbox:
    # 1. Set JS kernel - available kernel names: 'r', 'javascript', 'java', 'bash'
    js_id = sandbox.notebook.create_kernel(kernel_name="javascript")
    # 2. Run JS code inside code interpreter!
    execution = sandbox.notebook.exec_cell("console.log('Hello World!')", kernel_id=js_id)
    print(execution)
    # 3. Use Python again
    sandbox.notebook.exec_cell("print('Hello World!')")

JavaScript/TypeScript

const sandbox = await CodeInterpreter.create()

// 1. Set JS kernel - available kernel names: 'r', 'javascript', 'java', 'bash'
const jsID = await sandbox.notebook.createKernel({ kernelName: 'javascript' })
// 2. Run JS code inside code interpreter!
const execution = await sandbox.notebook.execCell("console.log('Hello World!')", { kernelID: jsID })
console.log(execution)
// 3. Use Python again
await sandbox.notebook.execCell('print("Hello World!")')

await sandbox.close()

Customization

If you would like to preinstall some packages or add your own languages, you can do it by copying all files except e2b.toml from the template folder on this branch to the directory where is your e2b.Dockerfile. You can freely edit the files and built your own template by running

e2b template build -c "/home/user/.jupyter/start-up.sh"

You can find more about custom templates in here. In the production release, this process will be significantly simplified.

mlejva commented 1 week ago

The JavaScript runtime doesn't support import. Ideally, we should fix it and import should just work. Less ideally (and the "less" is big here), we need to put a disclaimer here for users.

mlejva commented 1 week ago

Similarly with await. The await doesn't work in the top most scope. Eg running this code

const fs = require('node:fs');
const fetch = require('node-fetch');

console.log('Hello');

const url = 'https://jsonplaceholder.typicode.com/posts/1';

// Fetch data from the API
const response = await fetch(url);
const data = await response.text();
console.log(data);

will produce the following error

ExecutionError {
  name: 'SyntaxError',
  value: 'await is only valid in async functions and the top level bodies of modules',
  tracebackRaw: [
    'evalmachine.<anonymous>:10',
    'const response = await fetch(url);',
    '                 ^^^^^',
    '',
    'SyntaxError: await is only valid in async functions and the top level bodies of modules',
    '    at new Script (node:vm:94:7)',
    '    at createScript (node:vm:250:10)',
    '    at Object.runInThisContext (node:vm:298:10)',
    '    at run ([eval]:1020:15)',
    '    at onRunRequest ([eval]:864:18)',
    '    at onMessage ([eval]:828:13)',
    '    at process.emit (node:events:517:28)',
    '    at emit (node:internal/child_process:944:14)',
    '    at process.processTicksAndRejections (node:internal/process/task_queues:83:21)'
  ]
}
mlejva commented 1 week ago

Deno's Jupyter kernel would tick both boxes (import and top-level await): https://blog.jupyter.org/bringing-modern-javascript-to-the-jupyter-notebook-fc998095081e

We'd need to check if NPM dependencies work out of the box for users

mlejva commented 6 days ago

Imagine a use case where you're using Code Interpreter in a serverless function. You are also using multiple kernels because your AI app can run both Python and R. It's currently hard to know which kernel my sandbox should use because the listKernels() method isn't much useful without also specifying the name of the kernel. Currently all you see is an array of kernel IDs. Following code

const kernels = await sbx.notebook.listKernels()
console.log('Kernels', kernels)

prints this

Kernels [ '044ca206-09a3-4d03-a01f-39c9d9bad7e4' ]

I also can't solve this with adding some metadata to a sandbox because metadata are only able to be set during the creation of the sandbox. This means that I need to save the kernel IDs somewhere in my database which implies a need for a database.