| 89 | |
| 90 | @override |
| 91 | async def run_async( |
| 92 | self, *, args: dict[str, Any], tool_context: ToolContext |
| 93 | ) -> Any: |
| 94 | command = args.get('command', '') |
| 95 | if not command: |
| 96 | return {'status': 'error', 'error': '`command` is required.'} |
| 97 | |
| 98 | logger.debug('Execute command: %s', command) |
| 99 | try: |
| 100 | execution_result: ExecutionResult = await self._environment.execute( |
| 101 | command, timeout=DEFAULT_TIMEOUT |
| 102 | ) |
| 103 | logger.debug( |
| 104 | 'Execute result: exit_code=%d, stdout=%r, stderr=%r, timed_out=%r', |
| 105 | execution_result.exit_code, |
| 106 | execution_result.stdout[:200] if execution_result.stdout else '', |
| 107 | execution_result.stderr[:200] if execution_result.stderr else '', |
| 108 | execution_result.timed_out, |
| 109 | ) |
| 110 | except Exception as e: |
| 111 | logger.exception('Execute failed: %s', e) |
| 112 | return {'status': 'error', 'error': str(e)} |
| 113 | |
| 114 | result: dict[str, Any] = {'status': 'ok'} |
| 115 | if execution_result.stdout: |
| 116 | result['stdout'] = _truncate( |
| 117 | execution_result.stdout, |
| 118 | limit=self._max_output_chars, |
| 119 | ) |
| 120 | if execution_result.stderr: |
| 121 | result['stderr'] = _truncate( |
| 122 | execution_result.stderr, |
| 123 | limit=self._max_output_chars, |
| 124 | ) |
| 125 | if execution_result.exit_code != 0: |
| 126 | result['status'] = 'error' |
| 127 | result['exit_code'] = execution_result.exit_code |
| 128 | if execution_result.timed_out: |
| 129 | result['status'] = 'error' |
| 130 | result['error'] = f'Command timed out after {DEFAULT_TIMEOUT}s.' |
| 131 | return result |
| 132 | |
| 133 | def _detect_error_in_response(self, response: Any) -> Optional[str]: |
| 134 | """Telemetry hook: returns an error type if the response indicates an error.""" |