# Code interpreter The `code-interpreter` template turns `run_code` into a stateful session, like a notebook: every call executes in a persistent Python interpreter, so variables, imports and dataframes carry over between calls, and results come back rich - text, HTML tables, PNG charts and parsed chart data - instead of flat stdout. It ships Python 3.12 with pandas, NumPy and matplotlib preinstalled, on top of everything the `python-3.12` base has. **Python:** ```python from orkestr import Sandbox sbx = Sandbox.create(template="code-interpreter") # Each run_code call executes in the SAME interpreter: variables, # imports and figures persist between calls. sbx.run_code("import pandas as pd; df = pd.read_csv('sales.csv')") execution = sbx.run_code("df.describe()") print(execution.text) # text rendering of the last expression table = execution.results[0] # the same result also carries .html ``` > **Sessions survive pause and resume** > > The interpreter lives inside the sandbox, so pausing snapshots it along with everything else. Resume - hours later, or automatically on the next call with auto-resume - and your dataframes are exactly where you left them. Nothing to reload, no session to rebuild. ## Rich results Each execution returns a `results` list - one item per displayed value (the final expression, plus anything explicitly displayed). Every item carries all the representations the interpreter produced, and `type` names the richest one: | Parameter | Type | Description | | --- | --- | --- | | text | string | Plain-text rendering. Always present. | | html | string | HTML rendering, when the value has one - pandas DataFrames arrive as ready-to-render tables. | | png | string (base64) | The rendered image, for matplotlib figures. | | chart | object | Parsed chart data (type, title, axis labels, series values) for bar, line, pie and scatter figures - re-render the chart natively instead of embedding pixels. | | json | object | Structured application/json output, when emitted. | ## Charts, twice A matplotlib figure comes back as both the picture and the numbers: the PNG for showing, the chart data for anything programmatic - feeding a charting library, asserting on values in a test, or letting an agent read the result without vision. **Python:** ```python execution = sbx.run_code(""" import matplotlib.pyplot as plt df.groupby('region')['sales'].sum().plot.bar(title='Sales by region') plt.show() """) result = execution.results[0] with open("chart.png", "wb") as fh: fh.write(result.png_bytes()) # the rendered PNG print(result.chart) # {'type': 'bar', 'title': 'Sales by region', # 'x_tick_labels': ['fsn1', 'hel1', 'rbx'], # 'elements': [{'label': 'fsn1', 'value': 202.5}, ...]} ``` ## Streaming For long cells - model training, big joins - stream the output as it happens instead of waiting for the cell to finish: `run_code_stream` / `runCodeStream` yields one event per output burst and per result, ending with a `done` event that carries the same execution summary a buffered call returns. ```python for event in sbx.run_code_stream("train(df, epochs=50)", timeout_seconds=600): if event.kind == "stream": print(event.text, end="") # output as it happens elif event.kind == "result": handle(event.result) # rich results as they appear elif event.kind == "done": summary = event.execution # same shape as buffered run_code ``` ## Isolated contexts A sandbox starts with one default context. Create more when you need interpreters that cannot see each other's variables - one per user, one per conversation thread, one per experiment: **Python:** ```python ctx = sbx.create_code_context() ctx.run_code("x = 1") sbx.run_code("print(x)") # NameError - default context has no x sbx.run_code("print(x)", context_id=ctx.id) # 1 ctx.restart() # same id, fresh namespace ctx.remove() # shut the interpreter down ``` ## Errors and timeouts A raising cell is a normal response, not a transport error: the HTTP call succeeds and the exception arrives as structured data, exactly like a notebook shows a traceback. ```python execution = sbx.run_code("1 / 0") execution.error.name # "ZeroDivisionError" execution.error.value # "division by zero" execution.error.traceback # list of traceback lines # The exception did not reset anything - state up to the raise is kept: sbx.run_code("print(df.shape)") # still works ``` - **Timeouts interrupt, they do not destroy.** When a call exceeds `timeout_seconds` the running code is interrupted and the response has `interrupted: true` - but the context's variables survive, so the next call continues where you were. - **`restarted: true`** means the context's interpreter had died (for example, out of memory) and was restarted transparently for this call - its previous variables are gone. Check it when you depend on long-lived state. - **`truncated`** lists any outputs cut by size caps (very large stdout or results). Empty means nothing was dropped. ## When to use exec instead `run_code` is for Python that thinks in sessions. Shell commands, builds, servers and one-shot scripts belong to `exec` - and both work in the same sandbox. On templates without the interpreter runtime, `run_code` raises `InterpreterUnavailable` (HTTP 409 with `code: "interpreter_unavailable"`) - create the sandbox from `code-interpreter` or a [custom template](https://orkestr.eu/docs/sandboxes/templates) built on it. See the [REST API reference](https://orkestr.eu/docs/sandboxes/api-reference) for the raw endpoints, and [Base images](https://orkestr.eu/docs/sandboxes/base-images) for what the template ships.