From 6b05056a7c18a1b655f85dfa738c5b0066ac43bc Mon Sep 17 00:00:00 2001 From: erikkaum Date: Tue, 17 Dec 2024 17:01:34 +0100 Subject: [PATCH] another example --- Dockerfile | 5 ++-- examples/docker_example.py | 31 +++++++++++++++++++-- examples/dummytool.py | 14 ++++++++++ server.py | 46 ++++++++++++++++++++++++++++++++ src/agents/docker_alternative.py | 22 ++++++++------- 5 files changed, 104 insertions(+), 14 deletions(-) create mode 100644 examples/dummytool.py create mode 100644 server.py diff --git a/Dockerfile b/Dockerfile index 758e0da..321f455 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,5 +23,6 @@ RUN pip install --no-cache-dir -r requirements.txt # Install the package RUN pip install -e . -# Command to run when container starts -CMD ["python"] +COPY server.py /app/server.py + +CMD ["python", "/app/server.py"] diff --git a/examples/docker_example.py b/examples/docker_example.py index 0db5b53..f229bb9 100644 --- a/examples/docker_example.py +++ b/examples/docker_example.py @@ -1,12 +1,39 @@ from agents.search import DuckDuckGoSearchTool from agents.docker_alternative import DockerPythonInterpreter + +test = """ +from agents.tools import Tool + +class DummyTool(Tool): + name = "echo" + description = '''Perform a web search based on your query (think a Google search) then returns the top search results as a list of dict elements. + Each result has keys 'title', 'href' and 'body'.''' + inputs = { + "cmd": {"type": "string", "description": "The search query to perform."} + } + output_type = "any" + + def forward(self, cmd: str) -> str: + return cmd + +""" + container = DockerPythonInterpreter() -tools = [DuckDuckGoSearchTool] +output = container.execute("x = 5") +print(f"first output: {output}") +output = container.execute("print(x)") +print(f"second output: {output}") -output = container.execute("res = web_search(query='whats the capital of Cambodia?'); print(res)", tools=tools) +breakpoint() +print("---------") + +output = container.execute(test) +print(output) + +output = container.execute("res = DummyTool(cmd='echo this'); print(res)") print(output) container.stop() diff --git a/examples/dummytool.py b/examples/dummytool.py new file mode 100644 index 0000000..75edfd9 --- /dev/null +++ b/examples/dummytool.py @@ -0,0 +1,14 @@ +from agents.tools import Tool + + +class DummyTool(Tool): + name = "echo" + description = """Perform a web search based on your query (think a Google search) then returns the top search results as a list of dict elements. + Each result has keys 'title', 'href' and 'body'.""" + inputs = { + "cmd": {"type": "string", "description": "The search query to perform."} + } + output_type = "any" + + def forward(self, cmd: str) -> str: + return cmd \ No newline at end of file diff --git a/server.py b/server.py new file mode 100644 index 0000000..ebdc61d --- /dev/null +++ b/server.py @@ -0,0 +1,46 @@ +import socket +import sys +import traceback +import io + +exec_globals = {} +exec_locals = {} + +def execute_code(code): + stdout = io.StringIO() + stderr = io.StringIO() + sys.stdout = stdout + sys.stderr = stderr + + try: + exec(code, exec_globals, exec_locals) + except Exception as e: + traceback.print_exc(file=stderr) + + output = stdout.getvalue() + error = stderr.getvalue() + + # Restore original stdout and stderr + sys.stdout = sys.__stdout__ + sys.stderr = sys.__stderr__ + + return output + error + +def start_server(host='0.0.0.0', port=65432): + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.bind((host, port)) + s.listen() + print(f"Server listening on {host}:{port}") + while True: + conn, addr = s.accept() + with conn: + print(f"Connected by {addr}") + data = conn.recv(1024) + if not data: + break + code = data.decode('utf-8') + output = execute_code(code) + conn.sendall(output.encode('utf-8')) + +if __name__ == "__main__": + start_server() \ No newline at end of file diff --git a/src/agents/docker_alternative.py b/src/agents/docker_alternative.py index 6fd11e8..b035c7e 100644 --- a/src/agents/docker_alternative.py +++ b/src/agents/docker_alternative.py @@ -1,6 +1,7 @@ import docker from typing import List, Optional import warnings +import socket from agents.tools import Tool @@ -18,7 +19,7 @@ class DockerPythonInterpreter: try: self.container = self.client.containers.run( "pyrunner:latest", - "tail -f /dev/null", + ports={'65432/tcp': 65432}, detach=True, remove=True, ) @@ -37,10 +38,11 @@ class DockerPythonInterpreter: """ Execute Python code in the container and return stdout and stderr """ - - tool_instance = tools[0]() - import_code = f""" + if tools != None: + tool_instance = tools[0]() + + import_code = f""" module_path = '{tool_instance.__class__.__module__}' class_name = '{tool_instance.__class__.__name__}' @@ -50,14 +52,14 @@ module = importlib.import_module(module_path) web_search = getattr(module, class_name)() """ - full_code = import_code + "\n" + code + code = import_code + "\n" + code try: - exec_command = self.container.exec_run( - cmd=["python", "-c", full_code], - ) - output = exec_command.output - return output.decode('utf-8') + # Connect to the server running inside the container + with socket.create_connection(('localhost', 65432)) as sock: + sock.sendall(code.encode('utf-8')) + output = sock.recv(4096) + return output.decode('utf-8') except Exception as e: return f"Error executing code: {str(e)}"