-
Notifications
You must be signed in to change notification settings - Fork 2.8k
fix(code_executors): Fix JSON field mismatches in AgentEngineSandboxCodeExecutor #4261
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 all commits
7444ff9
132028a
3c1f18f
f21a690
72a23b3
3aaff64
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 |
|---|---|---|
|
|
@@ -28,7 +28,7 @@ | |
| from .code_execution_utils import CodeExecutionResult | ||
| from .code_execution_utils import File | ||
|
|
||
| logger = logging.getLogger('google_adk.' + __name__) | ||
| logger = logging.getLogger("google_adk." + __name__) | ||
|
|
||
|
|
||
| class AgentEngineSandboxCodeExecutor(BaseCodeExecutor): | ||
|
|
@@ -63,8 +63,8 @@ def __init__( | |
| **data: Additional keyword arguments to be passed to the base class. | ||
| """ | ||
| super().__init__(**data) | ||
| sandbox_resource_name_pattern = r'^projects/([a-zA-Z0-9-_]+)/locations/([a-zA-Z0-9-_]+)/reasoningEngines/(\d+)/sandboxEnvironments/(\d+)$' | ||
| agent_engine_resource_name_pattern = r'^projects/([a-zA-Z0-9-_]+)/locations/([a-zA-Z0-9-_]+)/reasoningEngines/(\d+)$' | ||
| sandbox_resource_name_pattern = r"^projects/([a-zA-Z0-9-_]+)/locations/([a-zA-Z0-9-_]+)/reasoningEngines/(\d+)/sandboxEnvironments/(\d+)$" | ||
| agent_engine_resource_name_pattern = r"^projects/([a-zA-Z0-9-_]+)/locations/([a-zA-Z0-9-_]+)/reasoningEngines/(\d+)$" | ||
|
|
||
| if sandbox_resource_name is not None: | ||
| self.sandbox_resource_name = sandbox_resource_name | ||
|
|
@@ -84,17 +84,17 @@ def __init__( | |
| # @TODO - Add TTL for sandbox creation after it is available | ||
| # in SDK. | ||
| operation = self._get_api_client().agent_engines.sandboxes.create( | ||
| spec={'code_execution_environment': {}}, | ||
| spec={"code_execution_environment": {}}, | ||
| name=agent_engine_resource_name, | ||
| config=types.CreateAgentEngineSandboxConfig( | ||
| display_name='default_sandbox' | ||
| display_name="default_sandbox" | ||
| ), | ||
| ) | ||
| self.sandbox_resource_name = operation.response.name | ||
| else: | ||
| raise ValueError( | ||
| 'Either sandbox_resource_name or agent_engine_resource_name must be' | ||
| ' set.' | ||
| "Either sandbox_resource_name or agent_engine_resource_name must be" | ||
| " set." | ||
| ) | ||
|
|
||
| @override | ||
|
|
@@ -105,14 +105,14 @@ def execute_code( | |
| ) -> CodeExecutionResult: | ||
| # Execute the code. | ||
| input_data = { | ||
| 'code': code_execution_input.code, | ||
| "code": code_execution_input.code, | ||
| } | ||
| if code_execution_input.input_files: | ||
| input_data['files'] = [ | ||
| input_data["files"] = [ | ||
| { | ||
| 'name': f.name, | ||
| 'contents': f.content, | ||
| 'mimeType': f.mime_type, | ||
| "name": f.name, | ||
| "content": f.content, | ||
|
Contributor
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. thanks for fixing this. |
||
| "mime_type": f.mime_type, | ||
| } | ||
| for f in code_execution_input.input_files | ||
| ] | ||
|
|
@@ -123,27 +123,39 @@ def execute_code( | |
| input_data=input_data, | ||
| ) | ||
| ) | ||
| logger.debug('Executed code:\n```\n%s\n```', code_execution_input.code) | ||
| logger.debug("Executed code:\n```\n%s\n```", code_execution_input.code) | ||
| saved_files = [] | ||
| stdout = '' | ||
| stderr = '' | ||
| stdout = "" | ||
| stderr = "" | ||
| for output in code_execution_response.outputs: | ||
| if output.mime_type == 'application/json' and ( | ||
| if output.mime_type == "application/json" and ( | ||
| output.metadata is None | ||
| or output.metadata.attributes is None | ||
| or 'file_name' not in output.metadata.attributes | ||
| or "file_name" not in output.metadata.attributes | ||
| ): | ||
| json_output_data = json.loads(output.data.decode('utf-8')) | ||
| stdout = json_output_data.get('stdout', '') | ||
| stderr = json_output_data.get('stderr', '') | ||
| json_output_data = json.loads(output.data.decode("utf-8")) | ||
| if isinstance(json_output_data, dict): | ||
| # Primary fields returned by the API are msg_out/msg_err. | ||
| # Fall back to stdout/stderr for backward compatibility. | ||
| stdout = json_output_data.get("msg_out") | ||
| if stdout is None: | ||
| stdout = json_output_data.get("stdout", "") | ||
| stderr = json_output_data.get("msg_err") | ||
| if stderr is None: | ||
| stderr = json_output_data.get("stderr", "") | ||
|
Comment on lines
+140
to
+145
Contributor
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. The current fallback logic for if "msg_out" in json_output_data:
stdout = json_output_data.get("msg_out") or ""
else:
stdout = json_output_data.get("stdout", "")
if "msg_err" in json_output_data:
stderr = json_output_data.get("msg_err") or ""
else:
stderr = json_output_data.get("stderr", "") |
||
| else: | ||
| logger.warning( | ||
| "Received non-dict JSON output from sandbox: %s", | ||
| json_output_data, | ||
| ) | ||
| else: | ||
| file_name = '' | ||
| file_name = "" | ||
| if ( | ||
| output.metadata is not None | ||
| and output.metadata.attributes is not None | ||
| ): | ||
| file_name = output.metadata.attributes.get('file_name', b'').decode( | ||
| 'utf-8' | ||
| file_name = output.metadata.attributes.get("file_name", b"").decode( | ||
| "utf-8" | ||
| ) | ||
| mime_type = output.mime_type | ||
| if not mime_type: | ||
|
|
@@ -183,6 +195,6 @@ def _get_project_id_and_location_from_resource_name( | |
| match = re.fullmatch(pattern, resource_name) | ||
|
|
||
| if not match: | ||
| raise ValueError(f'resource name {resource_name} is not valid.') | ||
| raise ValueError(f"resource name {resource_name} is not valid.") | ||
|
|
||
| return match.groups()[0], match.groups()[1] | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove all unrelated changes(single to double quotes) from this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1