scalebox-sdk 0.1.15__py3-none-any.whl → 0.1.17__py3-none-any.whl

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.
@@ -1,369 +1,370 @@
1
- import logging
2
- from typing import Dict, Literal, Optional, Union, overload
3
-
4
- import aiohttp
5
- import httpx
6
- from aiohttp import TCPConnector
7
- from httpx import AsyncClient
8
-
9
- from ..connection_config import ConnectionConfig
10
- from ..exceptions import InvalidArgumentException
11
- from ..generated import api_pb2, api_pb2_connect
12
- from ..sandbox_async.main import AsyncSandbox as BaseAsyncSandbox
13
- from .constants import DEFAULT_TEMPLATE, DEFAULT_TIMEOUT, JUPYTER_PORT
14
- from .exceptions import format_execution_timeout_error, format_request_timeout_error
15
- from .models import (
16
- Context,
17
- Execution,
18
- ExecutionError,
19
- OutputHandler,
20
- OutputMessage,
21
- Result,
22
- aextract_exception,
23
- parse_output,
24
- )
25
-
26
- logger = logging.getLogger(__name__)
27
-
28
-
29
- class AsyncSandbox(BaseAsyncSandbox):
30
- """
31
- Scalebox cloud sandbox is a secure and isolated cloud environment.
32
-
33
- The sandbox allows you to:
34
- - Access Linux OS
35
- - Create, list, and delete files and directories
36
- - Run commands
37
- - Run isolated code
38
- - Access the internet
39
-
40
- Check docs for more information.
41
-
42
- Use the `AsyncSandbox.create()` to create a new sandbox.
43
-
44
- Example:
45
- ```python
46
- from scalebox.code_interpreter import AsyncSandbox
47
- sandbox = await AsyncSandbox.create()
48
- ```
49
- """
50
-
51
- default_template = DEFAULT_TEMPLATE
52
-
53
- @property
54
- def _jupyter_url(self) -> str:
55
- return f"{'http' if self.connection_config.debug else 'https'}://{self.get_host(JUPYTER_PORT)}"
56
-
57
- @property
58
- def _client(self) -> AsyncClient:
59
- return AsyncClient(transport=self._transport)
60
-
61
- @overload
62
- async def run_code(
63
- self,
64
- code: str,
65
- language: Union[Literal["python"], None] = None,
66
- on_stdout: Optional[OutputHandler[OutputMessage]] = None,
67
- on_stderr: Optional[OutputHandler[OutputMessage]] = None,
68
- on_result: Optional[OutputHandler[Result]] = None,
69
- on_error: Optional[OutputHandler[ExecutionError]] = None,
70
- envs: Optional[Dict[str, str]] = None,
71
- timeout: Optional[float] = None,
72
- request_timeout: Optional[float] = None,
73
- ) -> Execution:
74
- """
75
- Runs the code as Python.
76
-
77
- Specify the `language` or `context` option to run the code as a different language or in a different `Context`.
78
-
79
- You can reference previously defined variables, imports, and functions in the code.
80
-
81
- :param code: Code to execute
82
- :param language: Language to use for code execution. If not defined, the default Python context is used.
83
- :param on_stdout: Callback for stdout messages
84
- :param on_stderr: Callback for stderr messages
85
- :param on_result: Callback for the `Result` object
86
- :param on_error: Callback for the `ExecutionError` object
87
- :param envs: Custom environment variables
88
- :param timeout: Timeout for the code execution in **seconds**
89
- :param request_timeout: Timeout for the request in **seconds**
90
-
91
- :return: `Execution` result object
92
- """
93
- ...
94
-
95
- @overload
96
- async def run_code(
97
- self,
98
- code: str,
99
- language: Optional[str] = "python",
100
- on_stdout: Optional[OutputHandler[OutputMessage]] = None,
101
- on_stderr: Optional[OutputHandler[OutputMessage]] = None,
102
- on_result: Optional[OutputHandler[Result]] = None,
103
- on_error: Optional[OutputHandler[ExecutionError]] = None,
104
- envs: Optional[Dict[str, str]] = None,
105
- timeout: Optional[float] = None,
106
- request_timeout: Optional[float] = None,
107
- ) -> Execution:
108
- """
109
- Runs the code for the specified language.
110
-
111
- Specify the `language` or `context` option to run the code as a different language or in a different `Context`.
112
- If no language is specified, Python is used.
113
-
114
- You can reference previously defined variables, imports, and functions in the code.
115
-
116
- :param code: Code to execute
117
- :param language: Language to use for code execution. If not defined, the default Python context is used.
118
- :param on_stdout: Callback for stdout messages
119
- :param on_stderr: Callback for stderr messages
120
- :param on_result: Callback for the `Result` object
121
- :param on_error: Callback for the `ExecutionError` object
122
- :param envs: Custom environment variables
123
- :param timeout: Timeout for the code execution in **seconds**
124
- :param request_timeout: Timeout for the request in **seconds**
125
-
126
- :return: `Execution` result object
127
- """
128
- ...
129
-
130
- @overload
131
- async def run_code(
132
- self,
133
- code: str,
134
- context: Optional[Context] = None,
135
- on_stdout: Optional[OutputHandler[OutputMessage]] = None,
136
- on_stderr: Optional[OutputHandler[OutputMessage]] = None,
137
- on_result: Optional[OutputHandler[Result]] = None,
138
- on_error: Optional[OutputHandler[ExecutionError]] = None,
139
- envs: Optional[Dict[str, str]] = None,
140
- timeout: Optional[float] = None,
141
- request_timeout: Optional[float] = None,
142
- ) -> Execution:
143
- """
144
- Runs the code in the specified context, if not specified, the default context is used.
145
-
146
- Specify the `language` or `context` option to run the code as a different language or in a different `Context`.
147
-
148
- You can reference previously defined variables, imports, and functions in the code.
149
-
150
- :param code: Code to execute
151
- :param context: Concrete context to run the code in. If not specified, the default context for the language is used. It's mutually exclusive with the language.
152
- :param on_stdout: Callback for stdout messages
153
- :param on_stderr: Callback for stderr messages
154
- :param on_result: Callback for the `Result` object
155
- :param on_error: Callback for the `ExecutionError` object
156
- :param envs: Custom environment variables
157
- :param timeout: Timeout for the code execution in **seconds**
158
- :param request_timeout: Timeout for the request in **seconds**
159
-
160
- :return: `Execution` result object
161
- """
162
- ...
163
-
164
- async def run_code(
165
- self,
166
- code: str,
167
- language: Optional[str] = None,
168
- context: Optional[Context] = None,
169
- on_stdout: Optional[OutputHandler[OutputMessage]] = None,
170
- on_stderr: Optional[OutputHandler[OutputMessage]] = None,
171
- on_result: Optional[OutputHandler[Result]] = None,
172
- on_error: Optional[OutputHandler[ExecutionError]] = None,
173
- envs: Optional[Dict[str, str]] = None,
174
- timeout: Optional[float] = None,
175
- request_timeout: Optional[float] = None,
176
- ) -> Execution:
177
- logger.debug(f"Executing code {code}")
178
-
179
- """
180
- Execute code in the sandbox and return the execution result.
181
- """
182
- logger.debug(f"Executing code: {code}")
183
-
184
- if context and language:
185
- raise Exception(
186
- "You can provide context or language, but not both at the same time."
187
- )
188
-
189
- # timeout = None if timeout == 0 else (timeout or 30)
190
- request_timeout = request_timeout or self._connection_config.request_timeout
191
- context_id = context.id if context else None
192
-
193
- # Ensure session exists
194
- if not self._session or self._session.closed:
195
- connector = aiohttp.TCPConnector(
196
- limit=100,
197
- limit_per_host=20,
198
- keepalive_timeout=30,
199
- enable_cleanup_closed=True,
200
- ssl=False,
201
- )
202
- self._session = aiohttp.ClientSession(
203
- connector=connector,
204
- timeout=aiohttp.ClientTimeout(total=request_timeout),
205
- )
206
-
207
- # Set headers
208
- # headers = {
209
- # "Authorization": "Bearer root",
210
- # }
211
-
212
- try:
213
- # Create client and execute request
214
- client = api_pb2_connect.AsyncExecutionServiceClient(
215
- http_client=self._session,
216
- base_url=self.envd_api_url,
217
- )
218
-
219
- # Build request
220
- request = api_pb2.ExecuteRequest(
221
- code=code,
222
- language=language or "",
223
- context_id=context_id or "",
224
- env_vars=envs or {},
225
- )
226
-
227
- # Execute request and get response stream
228
- responses = client.execute(
229
- req=request,
230
- extra_headers=self.connection_config.headers,
231
- timeout_seconds=request_timeout,
232
- )
233
-
234
- execution = Execution()
235
-
236
- # Process response stream
237
- async for response in responses:
238
- parse_output(
239
- execution,
240
- response,
241
- on_stdout=on_stdout,
242
- on_stderr=on_stderr,
243
- on_result=on_result,
244
- on_error=on_error,
245
- )
246
-
247
- return execution
248
-
249
- except Exception as e:
250
- # Handle exception
251
- logger.error(f"Error executing code: {e}")
252
- raise
253
- finally:
254
- # Don't close session here, let context manager handle it
255
- pass
256
-
257
- async def create_code_context(
258
- self,
259
- cwd: Optional[str] = None,
260
- language: Optional[str] = None,
261
- request_timeout: Optional[float] = None,
262
- ) -> Context:
263
- """
264
- Creates a new context to run code in.
265
-
266
- :param cwd: Set the current working directory for the context, defaults to `/home/user`
267
- :param language: Language of the context. If not specified, defaults to Python
268
- :param request_timeout: Timeout for the request in **milliseconds**
269
-
270
- :return: Context object
271
- """
272
- logger.debug(f"Creating new {language} context")
273
-
274
- request_timeout = request_timeout or self._connection_config.request_timeout
275
-
276
- # Ensure session exists
277
- if not self._session or self._session.closed:
278
- connector = aiohttp.TCPConnector(
279
- limit=100,
280
- limit_per_host=20,
281
- keepalive_timeout=30,
282
- enable_cleanup_closed=True,
283
- ssl=False,
284
- )
285
- self._session = aiohttp.ClientSession(
286
- connector=connector,
287
- timeout=aiohttp.ClientTimeout(total=request_timeout),
288
- )
289
-
290
- data = {}
291
- if language:
292
- data["language"] = language
293
- if cwd:
294
- data["cwd"] = cwd
295
-
296
- try:
297
- client = api_pb2_connect.AsyncContextServiceClient(
298
- http_client=self._session,
299
- base_url=self.envd_api_url,
300
- )
301
- # headers = {
302
- # "Authorization": "Bearer root",
303
- # }
304
-
305
- # Build request
306
- request = api_pb2.CreateContextRequest(
307
- language=language or "",
308
- cwd=cwd or "",
309
- )
310
-
311
- # Execute request and get response stream
312
- response = await client.create_context(
313
- req=request,
314
- extra_headers=self.connection_config.headers,
315
- )
316
- return Context.from_json(
317
- {
318
- "id": response.id,
319
- "language": response.language,
320
- "cwd": response.cwd,
321
- }
322
- )
323
- except Exception as e:
324
- logger.error(f"Error create_code_context: {e}")
325
- raise e
326
- finally:
327
- # Don't close session here, let context manager handle it
328
- pass
329
-
330
- async def destroy_context(self, context: Context) -> None:
331
- """
332
- Destroys a context.
333
-
334
- :param context: Context to destroy
335
- """
336
- logger.debug(f"Destroying context {context.id}")
337
-
338
- request_timeout = self._connection_config.request_timeout
339
-
340
- # Ensure session exists
341
- if not self._session or self._session.closed:
342
- connector = aiohttp.TCPConnector(
343
- limit=100,
344
- limit_per_host=20,
345
- keepalive_timeout=30,
346
- enable_cleanup_closed=True,
347
- ssl=False,
348
- )
349
- self._session = aiohttp.ClientSession(
350
- connector=connector,
351
- timeout=aiohttp.ClientTimeout(total=request_timeout),
352
- )
353
-
354
- # Create destroy context request
355
- destroy_context_request = api_pb2.DestroyContextRequest(
356
- context_id=context.id,
357
- )
358
-
359
- try:
360
- client = api_pb2_connect.AsyncContextServiceClient(
361
- base_url=self.envd_api_url,
362
- http_client=self._session,
363
- )
364
- # headers = {
365
- # "Authorization": "Bearer root",
366
- # }
367
- await client.destroy_context(destroy_context_request,extra_headers=self.connection_config.headers)
368
- except Exception as e:
369
- logger.warning(f"Failed to destroy context {context.id}: {e}")
1
+ import logging
2
+ from typing import Dict, Literal, Optional, Union, overload
3
+
4
+ import aiohttp
5
+ import httpx
6
+ from aiohttp import TCPConnector
7
+ from httpx import AsyncClient
8
+
9
+ from ..connection_config import ConnectionConfig
10
+ from ..exceptions import InvalidArgumentException
11
+ from ..generated import api_pb2, api_pb2_connect
12
+ from ..sandbox_async.main import AsyncSandbox as BaseAsyncSandbox
13
+ from .constants import DEFAULT_TEMPLATE, DEFAULT_TIMEOUT, JUPYTER_PORT
14
+ from .exceptions import format_execution_timeout_error, format_request_timeout_error
15
+ from .models import (
16
+ Context,
17
+ Execution,
18
+ ExecutionError,
19
+ OutputHandler,
20
+ OutputMessage,
21
+ Result,
22
+ aextract_exception,
23
+ parse_output,
24
+ )
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+
29
+ class AsyncSandbox(BaseAsyncSandbox):
30
+ """
31
+ Scalebox cloud sandbox is a secure and isolated cloud environment.
32
+
33
+ The sandbox allows you to:
34
+ - Access Linux OS
35
+ - Create, list, and delete files and directories
36
+ - Run commands
37
+ - Run isolated code
38
+ - Access the internet
39
+
40
+ Check docs for more information.
41
+
42
+ Use the `AsyncSandbox.create()` to create a new sandbox.
43
+
44
+ Example:
45
+ ```python
46
+ from scalebox.code_interpreter import AsyncSandbox
47
+ sandbox = await AsyncSandbox.create()
48
+ ```
49
+ """
50
+
51
+ default_template = DEFAULT_TEMPLATE
52
+
53
+ @property
54
+ def _jupyter_url(self) -> str:
55
+ return f"{'http' if self.connection_config.debug else 'https'}://{self.get_host(JUPYTER_PORT)}"
56
+
57
+ @property
58
+ def _client(self) -> AsyncClient:
59
+ return AsyncClient(transport=self._transport)
60
+
61
+ @overload
62
+ async def run_code(
63
+ self,
64
+ code: str,
65
+ language: Union[Literal["python"], None] = None,
66
+ on_stdout: Optional[OutputHandler[OutputMessage]] = None,
67
+ on_stderr: Optional[OutputHandler[OutputMessage]] = None,
68
+ on_result: Optional[OutputHandler[Result]] = None,
69
+ on_error: Optional[OutputHandler[ExecutionError]] = None,
70
+ envs: Optional[Dict[str, str]] = None,
71
+ timeout: Optional[float] = None,
72
+ request_timeout: Optional[float] = None,
73
+ ) -> Execution:
74
+ """
75
+ Runs the code as Python.
76
+
77
+ Specify the `language` or `context` option to run the code as a different language or in a different `Context`.
78
+
79
+ You can reference previously defined variables, imports, and functions in the code.
80
+
81
+ :param code: Code to execute
82
+ :param language: Language to use for code execution. If not defined, the default Python context is used.
83
+ :param on_stdout: Callback for stdout messages
84
+ :param on_stderr: Callback for stderr messages
85
+ :param on_result: Callback for the `Result` object
86
+ :param on_error: Callback for the `ExecutionError` object
87
+ :param envs: Custom environment variables
88
+ :param timeout: Timeout for the code execution in **seconds**
89
+ :param request_timeout: Timeout for the request in **seconds**
90
+
91
+ :return: `Execution` result object
92
+ """
93
+ ...
94
+
95
+ @overload
96
+ async def run_code(
97
+ self,
98
+ code: str,
99
+ language: Optional[str] = "python",
100
+ on_stdout: Optional[OutputHandler[OutputMessage]] = None,
101
+ on_stderr: Optional[OutputHandler[OutputMessage]] = None,
102
+ on_result: Optional[OutputHandler[Result]] = None,
103
+ on_error: Optional[OutputHandler[ExecutionError]] = None,
104
+ envs: Optional[Dict[str, str]] = None,
105
+ timeout: Optional[float] = None,
106
+ request_timeout: Optional[float] = None,
107
+ ) -> Execution:
108
+ """
109
+ Runs the code for the specified language.
110
+
111
+ Specify the `language` or `context` option to run the code as a different language or in a different `Context`.
112
+ If no language is specified, Python is used.
113
+
114
+ You can reference previously defined variables, imports, and functions in the code.
115
+
116
+ :param code: Code to execute
117
+ :param language: Language to use for code execution. If not defined, the default Python context is used.
118
+ :param on_stdout: Callback for stdout messages
119
+ :param on_stderr: Callback for stderr messages
120
+ :param on_result: Callback for the `Result` object
121
+ :param on_error: Callback for the `ExecutionError` object
122
+ :param envs: Custom environment variables
123
+ :param timeout: Timeout for the code execution in **seconds**
124
+ :param request_timeout: Timeout for the request in **seconds**
125
+
126
+ :return: `Execution` result object
127
+ """
128
+ ...
129
+
130
+ @overload
131
+ async def run_code(
132
+ self,
133
+ code: str,
134
+ context: Optional[Context] = None,
135
+ on_stdout: Optional[OutputHandler[OutputMessage]] = None,
136
+ on_stderr: Optional[OutputHandler[OutputMessage]] = None,
137
+ on_result: Optional[OutputHandler[Result]] = None,
138
+ on_error: Optional[OutputHandler[ExecutionError]] = None,
139
+ envs: Optional[Dict[str, str]] = None,
140
+ timeout: Optional[float] = None,
141
+ request_timeout: Optional[float] = None,
142
+ ) -> Execution:
143
+ """
144
+ Runs the code in the specified context, if not specified, the default context is used.
145
+
146
+ Specify the `language` or `context` option to run the code as a different language or in a different `Context`.
147
+
148
+ You can reference previously defined variables, imports, and functions in the code.
149
+
150
+ :param code: Code to execute
151
+ :param context: Concrete context to run the code in. If not specified, the default context for the language is used. It's mutually exclusive with the language.
152
+ :param on_stdout: Callback for stdout messages
153
+ :param on_stderr: Callback for stderr messages
154
+ :param on_result: Callback for the `Result` object
155
+ :param on_error: Callback for the `ExecutionError` object
156
+ :param envs: Custom environment variables
157
+ :param timeout: Timeout for the code execution in **seconds**
158
+ :param request_timeout: Timeout for the request in **seconds**
159
+
160
+ :return: `Execution` result object
161
+ """
162
+ ...
163
+
164
+ async def run_code(
165
+ self,
166
+ code: str,
167
+ language: Optional[str] = None,
168
+ context: Optional[Context] = None,
169
+ on_stdout: Optional[OutputHandler[OutputMessage]] = None,
170
+ on_stderr: Optional[OutputHandler[OutputMessage]] = None,
171
+ on_result: Optional[OutputHandler[Result]] = None,
172
+ on_error: Optional[OutputHandler[ExecutionError]] = None,
173
+ envs: Optional[Dict[str, str]] = None,
174
+ timeout: Optional[float] = None,
175
+ request_timeout: Optional[float] = None,
176
+ ) -> Execution:
177
+ logger.debug(f"Executing code {code}")
178
+
179
+ """
180
+ Execute code in the sandbox and return the execution result.
181
+ """
182
+ logger.debug(f"Executing code: {code}")
183
+
184
+ if context and language:
185
+ raise Exception(
186
+ "You can provide context or language, but not both at the same time."
187
+ )
188
+ if language is None and context is None:
189
+ language = "python"
190
+ # timeout = None if timeout == 0 else (timeout or 30)
191
+ request_timeout = request_timeout or self._connection_config.request_timeout
192
+ context_id = context.id if context else None
193
+
194
+ # Ensure session exists
195
+ if not self._session or self._session.closed:
196
+ connector = aiohttp.TCPConnector(
197
+ limit=100,
198
+ limit_per_host=20,
199
+ keepalive_timeout=30,
200
+ enable_cleanup_closed=True,
201
+ ssl=False,
202
+ )
203
+ self._session = aiohttp.ClientSession(
204
+ connector=connector,
205
+ timeout=aiohttp.ClientTimeout(total=request_timeout),
206
+ )
207
+
208
+ # Set headers
209
+ # headers = {
210
+ # "Authorization": "Bearer root",
211
+ # }
212
+
213
+ try:
214
+ # Create client and execute request
215
+ client = api_pb2_connect.AsyncExecutionServiceClient(
216
+ http_client=self._session,
217
+ base_url=self.envd_api_url,
218
+ )
219
+
220
+ # Build request
221
+ request = api_pb2.ExecuteRequest(
222
+ code=code,
223
+ language=language or "",
224
+ context_id=context_id or "",
225
+ env_vars=envs or {},
226
+ )
227
+
228
+ # Execute request and get response stream
229
+ responses = client.execute(
230
+ req=request,
231
+ extra_headers=self.connection_config.headers,
232
+ timeout_seconds=request_timeout,
233
+ )
234
+
235
+ execution = Execution()
236
+
237
+ # Process response stream
238
+ async for response in responses:
239
+ parse_output(
240
+ execution,
241
+ response,
242
+ on_stdout=on_stdout,
243
+ on_stderr=on_stderr,
244
+ on_result=on_result,
245
+ on_error=on_error,
246
+ )
247
+
248
+ return execution
249
+
250
+ except Exception as e:
251
+ # Handle exception
252
+ logger.error(f"Error executing code: {e}")
253
+ raise
254
+ finally:
255
+ # Don't close session here, let context manager handle it
256
+ pass
257
+
258
+ async def create_code_context(
259
+ self,
260
+ cwd: Optional[str] = None,
261
+ language: Optional[str] = None,
262
+ request_timeout: Optional[float] = None,
263
+ ) -> Context:
264
+ """
265
+ Creates a new context to run code in.
266
+
267
+ :param cwd: Set the current working directory for the context, defaults to `/home/user`
268
+ :param language: Language of the context. If not specified, defaults to Python
269
+ :param request_timeout: Timeout for the request in **milliseconds**
270
+
271
+ :return: Context object
272
+ """
273
+ logger.debug(f"Creating new {language} context")
274
+
275
+ request_timeout = request_timeout or self._connection_config.request_timeout
276
+
277
+ # Ensure session exists
278
+ if not self._session or self._session.closed:
279
+ connector = aiohttp.TCPConnector(
280
+ limit=100,
281
+ limit_per_host=20,
282
+ keepalive_timeout=30,
283
+ enable_cleanup_closed=True,
284
+ ssl=False,
285
+ )
286
+ self._session = aiohttp.ClientSession(
287
+ connector=connector,
288
+ timeout=aiohttp.ClientTimeout(total=request_timeout),
289
+ )
290
+
291
+ data = {}
292
+ if language:
293
+ data["language"] = language
294
+ if cwd:
295
+ data["cwd"] = cwd
296
+
297
+ try:
298
+ client = api_pb2_connect.AsyncContextServiceClient(
299
+ http_client=self._session,
300
+ base_url=self.envd_api_url,
301
+ )
302
+ # headers = {
303
+ # "Authorization": "Bearer root",
304
+ # }
305
+
306
+ # Build request
307
+ request = api_pb2.CreateContextRequest(
308
+ language=language or "",
309
+ cwd=cwd or "",
310
+ )
311
+
312
+ # Execute request and get response stream
313
+ response = await client.create_context(
314
+ req=request,
315
+ extra_headers=self.connection_config.headers,
316
+ )
317
+ return Context.from_json(
318
+ {
319
+ "id": response.id,
320
+ "language": response.language,
321
+ "cwd": response.cwd,
322
+ }
323
+ )
324
+ except Exception as e:
325
+ logger.error(f"Error create_code_context: {e}")
326
+ raise e
327
+ finally:
328
+ # Don't close session here, let context manager handle it
329
+ pass
330
+
331
+ async def destroy_context(self, context: Context) -> None:
332
+ """
333
+ Destroys a context.
334
+
335
+ :param context: Context to destroy
336
+ """
337
+ logger.debug(f"Destroying context {context.id}")
338
+
339
+ request_timeout = self._connection_config.request_timeout
340
+
341
+ # Ensure session exists
342
+ if not self._session or self._session.closed:
343
+ connector = aiohttp.TCPConnector(
344
+ limit=100,
345
+ limit_per_host=20,
346
+ keepalive_timeout=30,
347
+ enable_cleanup_closed=True,
348
+ ssl=False,
349
+ )
350
+ self._session = aiohttp.ClientSession(
351
+ connector=connector,
352
+ timeout=aiohttp.ClientTimeout(total=request_timeout),
353
+ )
354
+
355
+ # Create destroy context request
356
+ destroy_context_request = api_pb2.DestroyContextRequest(
357
+ context_id=context.id,
358
+ )
359
+
360
+ try:
361
+ client = api_pb2_connect.AsyncContextServiceClient(
362
+ base_url=self.envd_api_url,
363
+ http_client=self._session,
364
+ )
365
+ # headers = {
366
+ # "Authorization": "Bearer root",
367
+ # }
368
+ await client.destroy_context(destroy_context_request,extra_headers=self.connection_config.headers)
369
+ except Exception as e:
370
+ logger.warning(f"Failed to destroy context {context.id}: {e}")