e2b-code-interpreter 0.0.8a0__tar.gz → 0.0.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {e2b_code_interpreter-0.0.8a0 → e2b_code_interpreter-0.0.9}/PKG-INFO +1 -1
- {e2b_code_interpreter-0.0.8a0 → e2b_code_interpreter-0.0.9}/e2b_code_interpreter/main.py +106 -177
- {e2b_code_interpreter-0.0.8a0 → e2b_code_interpreter-0.0.9}/e2b_code_interpreter/messaging.py +5 -1
- {e2b_code_interpreter-0.0.8a0 → e2b_code_interpreter-0.0.9}/e2b_code_interpreter/models.py +3 -0
- {e2b_code_interpreter-0.0.8a0 → e2b_code_interpreter-0.0.9}/pyproject.toml +1 -1
- {e2b_code_interpreter-0.0.8a0 → e2b_code_interpreter-0.0.9}/README.md +0 -0
- {e2b_code_interpreter-0.0.8a0 → e2b_code_interpreter-0.0.9}/e2b_code_interpreter/__init__.py +0 -0
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import json
|
|
4
3
|
import logging
|
|
5
4
|
import threading
|
|
6
5
|
import uuid
|
|
@@ -63,9 +62,6 @@ class JupyterExtension:
|
|
|
63
62
|
self._connected_kernels: Dict[str, Future[JupyterKernelWebSocket]] = {}
|
|
64
63
|
self._default_kernel_id: Optional[str] = None
|
|
65
64
|
|
|
66
|
-
def get_default_url(self) -> str:
|
|
67
|
-
return f"https://{self._sandbox.get_hostname(8888)}/doc/tree/RTC:default.ipynb"
|
|
68
|
-
|
|
69
65
|
def exec_cell(
|
|
70
66
|
self,
|
|
71
67
|
code: str,
|
|
@@ -109,47 +105,6 @@ class JupyterExtension:
|
|
|
109
105
|
f"Received result from kernel {kernel_id}, message_id: {message_id}, result: {result}"
|
|
110
106
|
)
|
|
111
107
|
|
|
112
|
-
nb = self._sandbox.filesystem.read(f"/home/user/default.ipynb", timeout=timeout)
|
|
113
|
-
nb_parsed = json.loads(nb)
|
|
114
|
-
cell = {
|
|
115
|
-
"cell_type": "code",
|
|
116
|
-
"metadata": {},
|
|
117
|
-
"source": code,
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
outputs = []
|
|
121
|
-
if result.logs.stdout:
|
|
122
|
-
outputs.append(
|
|
123
|
-
{"output_type": "stream", "name": "stdout", "text": result.logs.stdout}
|
|
124
|
-
)
|
|
125
|
-
if result.logs.stderr:
|
|
126
|
-
outputs.append(
|
|
127
|
-
{"output_type": "stream", "name": "stderr", "text": result.logs.stderr}
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
if result.results:
|
|
131
|
-
outputs = [
|
|
132
|
-
{
|
|
133
|
-
"output_type": (
|
|
134
|
-
"execute_result" if r.is_main_result else "display_data"
|
|
135
|
-
),
|
|
136
|
-
"data": r.raw,
|
|
137
|
-
"metadata": {},
|
|
138
|
-
}
|
|
139
|
-
for r in result.results
|
|
140
|
-
]
|
|
141
|
-
|
|
142
|
-
cell["execution_count"] = result.execution_count
|
|
143
|
-
cell["outputs"] = outputs
|
|
144
|
-
|
|
145
|
-
if nb_parsed["cells"] and not nb_parsed["cells"][-1]["source"]:
|
|
146
|
-
nb_parsed["cells"][-1] = cell
|
|
147
|
-
else:
|
|
148
|
-
nb_parsed["cells"].append(cell)
|
|
149
|
-
|
|
150
|
-
self._sandbox.filesystem.write(
|
|
151
|
-
f"/home/user/default.ipynb", json.dumps(nb_parsed), timeout=timeout
|
|
152
|
-
)
|
|
153
108
|
return result
|
|
154
109
|
|
|
155
110
|
@property
|
|
@@ -164,77 +119,59 @@ class JupyterExtension:
|
|
|
164
119
|
self._default_kernel_id = self._kernel_id_set.result()
|
|
165
120
|
|
|
166
121
|
return self._default_kernel_id
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
# f"{self._sandbox.get_protocol()}://{self._sandbox.get_hostname(8888)}/api/sessions",
|
|
221
|
-
# json=data,
|
|
222
|
-
# timeout=timeout,
|
|
223
|
-
# )
|
|
224
|
-
# if not response.ok:
|
|
225
|
-
# raise KernelException(f"Failed to create kernel: {response.text}")
|
|
226
|
-
#
|
|
227
|
-
# response_data = response.json()
|
|
228
|
-
# kernel_id = response_data["kernel"]["id"]
|
|
229
|
-
# session_id = response_data["id"]
|
|
230
|
-
#
|
|
231
|
-
# logger.debug(f"Created kernel {kernel_id}, session {session_id}")
|
|
232
|
-
#
|
|
233
|
-
# threading.Thread(
|
|
234
|
-
# target=self._connect_to_kernel_ws, args=(kernel_id, session_id, timeout)
|
|
235
|
-
# ).start()
|
|
236
|
-
#
|
|
237
|
-
# return kernel_id
|
|
122
|
+
|
|
123
|
+
def create_kernel(
|
|
124
|
+
self,
|
|
125
|
+
cwd: str = "/home/user",
|
|
126
|
+
kernel_name: Optional[str] = None,
|
|
127
|
+
timeout: Optional[float] = TIMEOUT,
|
|
128
|
+
) -> str:
|
|
129
|
+
"""
|
|
130
|
+
Creates a new kernel, this can be useful if you want to have multiple independent code execution environments.
|
|
131
|
+
|
|
132
|
+
The kernel can be optionally configured to start in a specific working directory and/or
|
|
133
|
+
with a specific kernel name. If no kernel name is provided, the default kernel will be used.
|
|
134
|
+
Once the kernel is created, this method establishes a WebSocket connection to the new kernel for
|
|
135
|
+
real-time communication.
|
|
136
|
+
|
|
137
|
+
:param cwd: Sets the current working directory for the kernel. Defaults to "/home/user".
|
|
138
|
+
:param kernel_name:
|
|
139
|
+
Specifies which kernel should be used, useful if you have multiple kernel types.
|
|
140
|
+
If not provided, the default kernel will be used.
|
|
141
|
+
:param timeout: Timeout for the kernel creation request.
|
|
142
|
+
:return: Kernel id of the created kernel
|
|
143
|
+
"""
|
|
144
|
+
kernel_name = kernel_name or "python3"
|
|
145
|
+
|
|
146
|
+
data = {"path": str(uuid.uuid4()), "kernel": {"name": kernel_name}, "type": "notebook", "name": str(uuid.uuid4())}
|
|
147
|
+
logger.debug(f"Creating kernel with data: {data}")
|
|
148
|
+
|
|
149
|
+
response = requests.post(
|
|
150
|
+
f"{self._sandbox.get_protocol()}://{self._sandbox.get_hostname(8888)}/api/sessions",
|
|
151
|
+
json=data,
|
|
152
|
+
timeout=timeout,
|
|
153
|
+
)
|
|
154
|
+
if not response.ok:
|
|
155
|
+
raise KernelException(f"Failed to create kernel: {response.text}")
|
|
156
|
+
|
|
157
|
+
session_data = response.json()
|
|
158
|
+
session_id = session_data["id"]
|
|
159
|
+
kernel_id = session_data["kernel"]["id"]
|
|
160
|
+
|
|
161
|
+
response = requests.patch(
|
|
162
|
+
f"{self._sandbox.get_protocol()}://{self._sandbox.get_hostname(8888)}/api/sessions/{session_id}",
|
|
163
|
+
json={"path": cwd},
|
|
164
|
+
timeout=timeout,
|
|
165
|
+
)
|
|
166
|
+
if not response.ok:
|
|
167
|
+
raise KernelException(f"Failed to create kernel: {response.text}")
|
|
168
|
+
|
|
169
|
+
logger.debug(f"Created kernel {kernel_id}")
|
|
170
|
+
|
|
171
|
+
threading.Thread(
|
|
172
|
+
target=self._connect_to_kernel_ws, args=(kernel_id, session_id, timeout)
|
|
173
|
+
).start()
|
|
174
|
+
return kernel_id
|
|
238
175
|
|
|
239
176
|
def restart_kernel(
|
|
240
177
|
self, kernel_id: Optional[str] = None, timeout: Optional[float] = TIMEOUT
|
|
@@ -264,51 +201,51 @@ class JupyterExtension:
|
|
|
264
201
|
threading.Thread(
|
|
265
202
|
target=self._connect_to_kernel_ws, args=(kernel_id, None, timeout)
|
|
266
203
|
).start()
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
204
|
+
|
|
205
|
+
def shutdown_kernel(
|
|
206
|
+
self, kernel_id: Optional[str] = None, timeout: Optional[float] = TIMEOUT
|
|
207
|
+
) -> None:
|
|
208
|
+
"""
|
|
209
|
+
Shuts down an existing Jupyter kernel. This method is used to gracefully terminate a kernel's process.
|
|
210
|
+
|
|
211
|
+
:param kernel_id: The unique identifier of the kernel to shutdown. If not provided, the default kernel is shutdown.
|
|
212
|
+
:param timeout: The timeout for the kernel shutdown request.
|
|
213
|
+
"""
|
|
214
|
+
kernel_id = kernel_id or self.default_kernel_id
|
|
215
|
+
logger.debug(f"Shutting down kernel {kernel_id}")
|
|
216
|
+
|
|
217
|
+
self._connected_kernels[kernel_id].result().close()
|
|
218
|
+
del self._connected_kernels[kernel_id]
|
|
219
|
+
logger.debug(f"Closed websocket connection to kernel {kernel_id}")
|
|
220
|
+
|
|
221
|
+
response = requests.delete(
|
|
222
|
+
f"{self._sandbox.get_protocol()}://{self._sandbox.get_hostname(8888)}/api/kernels/{kernel_id}",
|
|
223
|
+
timeout=timeout,
|
|
224
|
+
)
|
|
225
|
+
if not response.ok:
|
|
226
|
+
raise KernelException(f"Failed to shutdown kernel {kernel_id}")
|
|
227
|
+
|
|
228
|
+
logger.debug(f"Shutdown kernel {kernel_id}")
|
|
229
|
+
|
|
230
|
+
def list_kernels(self, timeout: Optional[float] = TIMEOUT) -> List[str]:
|
|
231
|
+
"""
|
|
232
|
+
Lists all available Jupyter kernels.
|
|
233
|
+
|
|
234
|
+
This method fetches a list of all currently available Jupyter kernels from the server. It can be used
|
|
235
|
+
to retrieve the IDs of all kernels that are currently running or available for connection.
|
|
236
|
+
|
|
237
|
+
:param timeout: The timeout for the kernel list request.
|
|
238
|
+
:return: List of kernel ids
|
|
239
|
+
"""
|
|
240
|
+
response = requests.get(
|
|
241
|
+
f"{self._sandbox.get_protocol()}://{self._sandbox.get_hostname(8888)}/api/kernels",
|
|
242
|
+
timeout=timeout,
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
if not response.ok:
|
|
246
|
+
raise KernelException(f"Failed to list kernels: {response.text}")
|
|
247
|
+
|
|
248
|
+
return [kernel["id"] for kernel in response.json()]
|
|
312
249
|
|
|
313
250
|
def close(self):
|
|
314
251
|
"""
|
|
@@ -319,23 +256,16 @@ class JupyterExtension:
|
|
|
319
256
|
ws.result().close()
|
|
320
257
|
|
|
321
258
|
def _connect_to_kernel_ws(
|
|
322
|
-
self,
|
|
323
|
-
kernel_id: str,
|
|
324
|
-
session_id: Optional[str],
|
|
325
|
-
timeout: Optional[float] = TIMEOUT,
|
|
259
|
+
self, kernel_id: str, session_id: Optional[str], timeout: Optional[float] = TIMEOUT
|
|
326
260
|
) -> JupyterKernelWebSocket:
|
|
327
261
|
"""
|
|
328
262
|
Establishes a WebSocket connection to a specified Jupyter kernel.
|
|
329
263
|
|
|
330
264
|
:param kernel_id: Kernel id
|
|
331
|
-
:param session_id: Session id
|
|
332
265
|
:param timeout: The timeout for the kernel connection request.
|
|
333
266
|
|
|
334
267
|
:return: Websocket connection
|
|
335
268
|
"""
|
|
336
|
-
if not session_id:
|
|
337
|
-
session_id = uuid.uuid4()
|
|
338
|
-
|
|
339
269
|
logger.debug(f"Connecting to kernel's ({kernel_id}) websocket")
|
|
340
270
|
future = Future()
|
|
341
271
|
self._connected_kernels[kernel_id] = future
|
|
@@ -343,7 +273,7 @@ class JupyterExtension:
|
|
|
343
273
|
session_id = session_id or str(uuid.uuid4())
|
|
344
274
|
ws = JupyterKernelWebSocket(
|
|
345
275
|
url=f"{self._sandbox.get_protocol('ws')}://{self._sandbox.get_hostname(8888)}/api/kernels/{kernel_id}/channels",
|
|
346
|
-
session_id=session_id
|
|
276
|
+
session_id=session_id
|
|
347
277
|
)
|
|
348
278
|
|
|
349
279
|
ws.connect(timeout=timeout)
|
|
@@ -362,18 +292,17 @@ class JupyterExtension:
|
|
|
362
292
|
logger.debug("Starting to connect to the default kernel")
|
|
363
293
|
|
|
364
294
|
def setup_default_kernel():
|
|
365
|
-
|
|
366
|
-
"/root/.jupyter
|
|
295
|
+
kernel_id = self._sandbox.filesystem.read(
|
|
296
|
+
"/root/.jupyter/kernel_id", timeout=timeout
|
|
367
297
|
)
|
|
368
298
|
|
|
369
|
-
if
|
|
299
|
+
if kernel_id is None and not self._sandbox.is_open:
|
|
370
300
|
return
|
|
371
301
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
session_id = data["id"]
|
|
302
|
+
kernel_id = kernel_id.strip()
|
|
303
|
+
|
|
375
304
|
logger.debug(f"Default kernel id: {kernel_id}")
|
|
376
|
-
self._connect_to_kernel_ws(kernel_id,
|
|
305
|
+
self._connect_to_kernel_ws(kernel_id, None, timeout=timeout)
|
|
377
306
|
self._kernel_id_set.set_result(kernel_id)
|
|
378
307
|
|
|
379
308
|
threading.Thread(target=setup_default_kernel).start()
|
{e2b_code_interpreter-0.0.8a0 → e2b_code_interpreter-0.0.9}/e2b_code_interpreter/messaging.py
RENAMED
|
@@ -161,7 +161,11 @@ class JupyterKernelWebSocket:
|
|
|
161
161
|
|
|
162
162
|
:param data: The message data
|
|
163
163
|
"""
|
|
164
|
-
parent_msg_ig = data["parent_header"]
|
|
164
|
+
parent_msg_ig = data["parent_header"].get("msg_id", None)
|
|
165
|
+
if parent_msg_ig is None:
|
|
166
|
+
logger.warning("Parent message ID not found. %s", data)
|
|
167
|
+
return
|
|
168
|
+
|
|
165
169
|
logger.debug(f"Received message {data['msg_type']} for {parent_msg_ig}")
|
|
166
170
|
|
|
167
171
|
cell = self._cells.get(parent_msg_ig)
|
|
File without changes
|
{e2b_code_interpreter-0.0.8a0 → e2b_code_interpreter-0.0.9}/e2b_code_interpreter/__init__.py
RENAMED
|
File without changes
|