Source code for council.skills.python.python_code_execution_skill
import os
import subprocess
from typing import Mapping, Optional
from council.contexts import ChatMessage, SkillContext
from council.skills import SkillBase
from .llm_helper import extract_code_block
[docs]
class PythonCodeExecutionSkill(SkillBase):
"""
Skills that execute python code and provides the results.
The python code is retrieved from the message content from `context.try_last_message`,
looking for a markdown `python` code block.
The return message data contains a dictionary with the status code, stdout and stderr.
"""
[docs]
def __init__(self, env_var: Optional[Mapping[str, str]] = None, decode_stdout: bool = True):
"""
Initialize a new instance
Args:
env_var: Optional list of environment variable to be set for the code execution
decode_stdout: either or not the stdout should be returns as a string (`True`), or as a bytes (`False`)
"""
super().__init__("python code runner")
self._env_var = os.environ.copy() | (env_var or {})
self._decode_stdout = decode_stdout
[docs]
def execute(self, context: SkillContext) -> ChatMessage:
last_message = context.try_last_message.unwrap("last message")
python_code = extract_code_block(last_message.message, "python")
context.logger.debug(f"running python code: \n {python_code}")
execution = subprocess.run(["python", "-c", python_code], capture_output=True, env=self._env_var)
return_code = execution.returncode
stdout_bytes = execution.stdout
stderr = execution.stderr.decode()
data = {
"return_code": return_code,
"stderr": stderr,
}
context.logger.debug(f"process completed with code: {return_code}")
context.logger.debug(f"std err: \n{stderr}")
if self._decode_stdout:
stdout = stdout_bytes.decode()
data["stdout"] = stdout
context.logger.debug(f"std out: \n{stdout}")
else:
data["stdout_bytes"] = stdout_bytes
context.logger.debug(f"std out is {len(stdout_bytes)} bytes")
if return_code == 0:
return self.build_success_message("Python code execution succeeded", data=data)
context.logger.debug(f"Python code execution failed:\n{stderr}")
return self.build_error_message(f"Python code execution failed:\n{stderr}", data=data)