Code Execution

You can execute code using the notebook module, using the execCell method. The method takes a string of code as an argument and returns an object with the results of the execution.

import { CodeInterpreter } from '@e2b/code-interpreter'

const code = 'print("Hello, World!")'

const sandbox = CodeInterpreter.create()
const execution = await sandbox.notebook.execCell(code)

The execCell method also accepts following optional arguments:

  • kernel id: The ID of the kernel to execute the code on. If not provided, the default kernel is used. See here for more info on kernels.
  • on stdout: A callback function to handle standard output messages from the code execution.
  • on_stderr: A callback function to handle standard error messages from the code execution.
  • on_result: A callback function to handle the result and display calls of the code execution.

Streaming response

You can use the on_* callbacks to handle the output of the code execution as it happens. This is useful for long-running code. You can stream the output to the user as it is generated.

Execution object

The object returned by the exec cell method is little bit more complex, it's based on Jupyter. Here's an detailed explanation in the Jupyter documentation.

It contains the following fields:

  • results: A list containing result of the cell (interactively interpreted last line) and display calls (e.g. matplotlib plots).
  • logs: Logs printed to stdout and stderr during execution.
  • error: An error message, if there was an error during execution of the cell. It works only for Python code, not for system (! e.g !pip install e2b) commands.

Result object

This object can be created in two different ways:

  • Evaluation of the last line: If the last line of the code is an expression, the result is the value of that expression. As you would expect in REPL environments.
  • Display calls: Calls to display functions, which can be used to display rich output in the notebook. E.g. img.show(), display(img), etc.

Represents the data to be displayed as a result of executing a cell in a Jupyter notebook. The result is similar to the structure returned by ipython kernel

The result can contain multiple types of data, such as text, images, plots, etc. Each type of data is represented as a string, and the result can contain multiple types of data. The display calls don't have to have text representation, it's always present for the actual result, the other representations are optional.

The result has those basic data types:

Text types:

  • text: text representation of the result
  • html: html representation of the result
  • markdown: markdown representation of the result
  • latex: latex representation of the result

Image types:

  • png: "base64 encoded png image",
  • jpeg: "base64 encoded jpeg image",
  • svg": "svg image",

Other types:

  • json: "json representation",
  • javascript: "javascript representation",
  • pdf: "base64 encoded pdf"

Logs object

Logs printed to stdout and stderr during execution. Examples of logs are print statements, warnings, subprocess output, etc.

It contains two fields:

  • stdout: List of strings, each string is a line printed to stdout.
  • stderr: List of strings, each string is a line printed to stderr.

Error object

An error message, if there was an error during execution of the cell.

It contains three fields:

  • name: Name of the error, e.g. NameError, ValueError, etc.
  • value: Value of the error, e.g. name 'non_existent_variable' is not defined, etc.
  • traceback: Traceback of the error.

Example how to interpret the results to LLM

Here's an example how to return the results to LLM:

const code = '<CODE GENERATED BY LLM>'
const execution = await sandbox.notebook.execCell(code)

// There was an error during execution, return the error and its traceback
if (execution.error) {
  return `There was an error during execution: ${execution.error.name}: ${execution.error.value}.\n
  ${execution.error.traceback}`
}

// The execution has some result, summarize to LLM, what are the results
if (execution.results.length > 0) {
  let message = 'These are results of the execution:\n'
  let counter = 1
  for (const result of execution.results) {
    message += `Result ${counter++}:\n`
    if (result.isMainResult) {
      message += `[Main result]: ${result.text}\n`
    } else {
      message += `[Display data]: ${result.text}\n`
    }
    if (result.formats().length > 0) {
      message += `It has following formats: ${result.formats()}\n`
    }
  }

  return message
}

// There were no results, check if there was something is stdout/err
if (
  execution.logs.stdout.length > 0 ||
  execution.logs.stderr.length > 0
) {
  let message = 'There was no result of the execution, but here are the logs:\n'
  if (execution.logs.stdout.length > 0) {
    message += `Stdout: ${execution.logs.stdout.join('\n')}\n`
  }
  if (execution.logs.stderr.length > 0) {
    message += `Stderr: ${execution.logs.stderr.join('\n')}\n`
  }

  return message
}

return 'There was no output of the execution.'