-
Notifications
You must be signed in to change notification settings - Fork 2.1k
added isolated code executor #3225
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
f98c652
b3cdd32
a77b0c2
8fbd73b
9cf3ef0
98e5a83
ff06b44
ba5dbbd
b0f3f6c
1e49154
5d01c91
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,66 @@ | ||||||||||||||||||||||||||||||||||||||||||||||
| from __future__ import annotations | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| from contextlib import redirect_stdout | ||||||||||||||||||||||||||||||||||||||||||||||
| import io | ||||||||||||||||||||||||||||||||||||||||||||||
| import re | ||||||||||||||||||||||||||||||||||||||||||||||
| from typing import Any | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| from pydantic import Field | ||||||||||||||||||||||||||||||||||||||||||||||
| from typing_extensions import override | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| from ..agents.invocation_context import InvocationContext | ||||||||||||||||||||||||||||||||||||||||||||||
| from .base_code_executor import BaseCodeExecutor | ||||||||||||||||||||||||||||||||||||||||||||||
| from .code_execution_utils import CodeExecutionInput | ||||||||||||||||||||||||||||||||||||||||||||||
| from .code_execution_utils import CodeExecutionResult | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| import sys | ||||||||||||||||||||||||||||||||||||||||||||||
| import subprocess | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| #Don't think this is needed anymore but keeping it around just in case. | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| # def _prepare_globals(code: str, globals_: dict[str, Any]) -> None: | ||||||||||||||||||||||||||||||||||||||||||||||
| # """Prepare globals for code execution, injecting __name__ if needed.""" | ||||||||||||||||||||||||||||||||||||||||||||||
| # if re.search(r"if\s+__name__\s*==\s*['\"]__main__['\"]", code): | ||||||||||||||||||||||||||||||||||||||||||||||
| # globals_['__name__'] = '__main__' | ||||||||||||||||||||||||||||||||||||||||||||||
AlexFierro9 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| class IsolatedCodeExecutor(BaseCodeExecutor): | ||||||||||||||||||||||||||||||||||||||||||||||
| """A code executor that safely executes code in an isolated environment through | ||||||||||||||||||||||||||||||||||||||||||||||
| the current local context.""" | ||||||||||||||||||||||||||||||||||||||||||||||
AlexFierro9 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| # Overrides the BaseCodeExecutor attribute: this executor cannot be stateful. | ||||||||||||||||||||||||||||||||||||||||||||||
| stateful: bool = Field(default=False, frozen=True, exclude=True) | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| # Overrides the BaseCodeExecutor attribute: this executor cannot | ||||||||||||||||||||||||||||||||||||||||||||||
| # optimize_data_file. | ||||||||||||||||||||||||||||||||||||||||||||||
| optimize_data_file: bool = Field(default=False, frozen=True, exclude=True) | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| def __init__(self, **data): | ||||||||||||||||||||||||||||||||||||||||||||||
| """Initializes the IsolatedCodeExecutor.""" | ||||||||||||||||||||||||||||||||||||||||||||||
| if 'stateful' in data and data['stateful']: | ||||||||||||||||||||||||||||||||||||||||||||||
| raise ValueError('Cannot set `stateful=True` in IsolatedCodeExecutor.') | ||||||||||||||||||||||||||||||||||||||||||||||
| if 'optimize_data_file' in data and data['optimize_data_file']: | ||||||||||||||||||||||||||||||||||||||||||||||
| raise ValueError( | ||||||||||||||||||||||||||||||||||||||||||||||
| 'Cannot set `optimize_data_file=True` in IsolatedCodeExecutor.' | ||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||
| super().__init__(**data) | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| @override | ||||||||||||||||||||||||||||||||||||||||||||||
| def execute_code( | ||||||||||||||||||||||||||||||||||||||||||||||
| self, | ||||||||||||||||||||||||||||||||||||||||||||||
| invocation_context: InvocationContext, | ||||||||||||||||||||||||||||||||||||||||||||||
| code_execution_input: CodeExecutionInput, | ||||||||||||||||||||||||||||||||||||||||||||||
| ) -> CodeExecutionResult: | ||||||||||||||||||||||||||||||||||||||||||||||
| # Executes code by spawning a new python interpreter process. | ||||||||||||||||||||||||||||||||||||||||||||||
| code = code_execution_input.code | ||||||||||||||||||||||||||||||||||||||||||||||
| process_result = subprocess.run( | ||||||||||||||||||||||||||||||||||||||||||||||
| [sys.executable, "-c", code], | ||||||||||||||||||||||||||||||||||||||||||||||
| capture_output=True, | ||||||||||||||||||||||||||||||||||||||||||||||
| text=True | ||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+48
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider adding a timeout to the Also, it might be useful to capture and log the return code of the subprocess for debugging purposes. process_result = subprocess.run(
[sys.executable, "-c", code],
capture_output=True,
text=True, # Enables decoding of stdout and stderr as text
timeout=30 # Add a timeout to prevent indefinite hanging
)
if process_result.returncode != 0:
print(f"Code execution failed with return code: {process_result.returncode}") |
||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| # Collect the final result. | ||||||||||||||||||||||||||||||||||||||||||||||
| return CodeExecutionResult( | ||||||||||||||||||||||||||||||||||||||||||||||
| stdout=process_result.stdout, | ||||||||||||||||||||||||||||||||||||||||||||||
| stderr=process_result.stderr, | ||||||||||||||||||||||||||||||||||||||||||||||
| output_files=[], | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+55
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's important to handle potential exceptions that might occur during the code execution within the subprocess. For example, the code might raise an exception that isn't properly propagated back to the main process. Consider adding a try-except block around the
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||
AlexFierro9 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.