Merge branch 'main' of github.com:huggingface/agents
This commit is contained in:
		
						commit
						00b9a71453
					
				|  | @ -13,13 +13,147 @@ outputs | ||||||
| # VS Code | # VS Code | ||||||
| .vscode | .vscode | ||||||
| 
 | 
 | ||||||
|  | # Byte-compiled / optimized / DLL files | ||||||
|  | __pycache__/ | ||||||
|  | *.py[cod] | ||||||
|  | *$py.class | ||||||
|  | 
 | ||||||
|  | # C extensions | ||||||
|  | *.so | ||||||
|  | 
 | ||||||
|  | # Distribution / packaging | ||||||
|  | .Python | ||||||
|  | build/ | ||||||
|  | develop-eggs/ | ||||||
|  | dist/ | ||||||
|  | downloads/ | ||||||
|  | eggs/ | ||||||
|  | .eggs/ | ||||||
|  | lib/ | ||||||
|  | lib64/ | ||||||
|  | parts/ | ||||||
|  | sdist/ | ||||||
|  | var/ | ||||||
|  | wheels/ | ||||||
|  | share/python-wheels/ | ||||||
|  | *.egg-info/ | ||||||
|  | .installed.cfg | ||||||
|  | *.egg | ||||||
|  | MANIFEST | ||||||
|  | 
 | ||||||
|  | # PyInstaller | ||||||
|  | *.manifest | ||||||
|  | *.spec | ||||||
|  | 
 | ||||||
|  | # Installer logs | ||||||
|  | pip-log.txt | ||||||
|  | pip-delete-this-directory.txt | ||||||
|  | 
 | ||||||
|  | # Unit test / coverage reports | ||||||
|  | htmlcov/ | ||||||
|  | .tox/ | ||||||
|  | .nox/ | ||||||
|  | .coverage | ||||||
|  | .coverage.* | ||||||
|  | .cache | ||||||
|  | nosetests.xml | ||||||
|  | coverage.xml | ||||||
|  | *.cover | ||||||
|  | *.py,cover | ||||||
|  | .hypothesis/ | ||||||
|  | .pytest_cache/ | ||||||
|  | cover/ | ||||||
|  | 
 | ||||||
|  | # Translations | ||||||
|  | *.mo | ||||||
|  | *.pot | ||||||
|  | 
 | ||||||
|  | # Django stuff: | ||||||
|  | *.log | ||||||
|  | local_settings.py | ||||||
|  | db.sqlite3 | ||||||
|  | db.sqlite3-journal | ||||||
|  | 
 | ||||||
|  | # Flask stuff: | ||||||
|  | instance/ | ||||||
|  | .webassets-cache | ||||||
|  | 
 | ||||||
|  | # Scrapy stuff: | ||||||
|  | .scrapy | ||||||
|  | 
 | ||||||
|  | # Sphinx documentation | ||||||
|  | docs/_build/ | ||||||
|  | 
 | ||||||
|  | # PyBuilder | ||||||
|  | .pybuilder/ | ||||||
|  | target/ | ||||||
|  | 
 | ||||||
|  | # Jupyter Notebook | ||||||
|  | .ipynb_checkpoints | ||||||
|  | 
 | ||||||
|  | # IPython | ||||||
|  | profile_default/ | ||||||
|  | ipython_config.py | ||||||
|  | 
 | ||||||
|  | # pyenv | ||||||
|  | # .python-version | ||||||
|  | 
 | ||||||
|  | # pipenv | ||||||
|  | #Pipfile.lock | ||||||
|  | 
 | ||||||
|  | # UV | ||||||
|  | #uv.lock | ||||||
|  | 
 | ||||||
|  | # poetry | ||||||
|  | #poetry.lock | ||||||
|  | 
 | ||||||
|  | # pdm | ||||||
|  | .pdm.toml | ||||||
|  | .pdm-python | ||||||
|  | .pdm-build/ | ||||||
|  | 
 | ||||||
|  | # PEP 582 | ||||||
|  | __pypackages__/ | ||||||
|  | 
 | ||||||
|  | # Celery stuff | ||||||
|  | celerybeat-schedule | ||||||
|  | celerybeat.pid | ||||||
|  | 
 | ||||||
|  | # SageMath parsed files | ||||||
|  | *.sage.py | ||||||
|  | 
 | ||||||
| # Environments | # Environments | ||||||
| .env | .env | ||||||
| .venv | .venv | ||||||
| env/ | env/ | ||||||
| venv/ | venv/ | ||||||
|  | ENV/ | ||||||
| env.bak/ | env.bak/ | ||||||
| venv.bak/ | venv.bak/ | ||||||
| 
 | 
 | ||||||
| # Jupyter Notebook | # Spyder project settings | ||||||
| .ipynb_checkpoints | .spyderproject | ||||||
|  | .spyproject | ||||||
|  | 
 | ||||||
|  | # Rope project settings | ||||||
|  | .ropeproject | ||||||
|  | 
 | ||||||
|  | # mkdocs documentation | ||||||
|  | /site | ||||||
|  | 
 | ||||||
|  | # mypy | ||||||
|  | .mypy_cache/ | ||||||
|  | .dmypy.json | ||||||
|  | dmypy.json | ||||||
|  | 
 | ||||||
|  | # Pyre type checker | ||||||
|  | .pyre/ | ||||||
|  | 
 | ||||||
|  | # pytype static type analyzer | ||||||
|  | .pytype/ | ||||||
|  | 
 | ||||||
|  | # Cython debug symbols | ||||||
|  | cython_debug/ | ||||||
|  | 
 | ||||||
|  | # PyCharm | ||||||
|  | #.idea/ | ||||||
|  | @ -0,0 +1,28 @@ | ||||||
|  | # Base Python image | ||||||
|  | FROM python:3.12-slim | ||||||
|  | 
 | ||||||
|  | # Set working directory | ||||||
|  | WORKDIR /app | ||||||
|  | 
 | ||||||
|  | # Install build dependencies | ||||||
|  | RUN apt-get update && apt-get install -y \ | ||||||
|  |     build-essential \ | ||||||
|  |     gcc \ | ||||||
|  |     g++ \ | ||||||
|  |     zlib1g-dev \ | ||||||
|  |     libjpeg-dev \ | ||||||
|  |     libpng-dev \ | ||||||
|  |     && rm -rf /var/lib/apt/lists/* | ||||||
|  | 
 | ||||||
|  | # Copy package files | ||||||
|  | COPY . /app/ | ||||||
|  | 
 | ||||||
|  | # Install dependencies | ||||||
|  | RUN pip install --no-cache-dir -r requirements.txt | ||||||
|  | 
 | ||||||
|  | # Install the package | ||||||
|  | RUN pip install -e . | ||||||
|  | 
 | ||||||
|  | COPY server.py /app/server.py | ||||||
|  | 
 | ||||||
|  | CMD ["python", "/app/server.py"] | ||||||
|  | @ -0,0 +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() | ||||||
|  | 
 | ||||||
|  | output = container.execute("x = 5") | ||||||
|  | print(f"first output: {output}") | ||||||
|  | output = container.execute("print(x)") | ||||||
|  | print(f"second output: {output}") | ||||||
|  | 
 | ||||||
|  | breakpoint() | ||||||
|  | 
 | ||||||
|  | print("---------") | ||||||
|  | 
 | ||||||
|  | output = container.execute(test) | ||||||
|  | print(output) | ||||||
|  | 
 | ||||||
|  | output = container.execute("res = DummyTool(cmd='echo this'); print(res)") | ||||||
|  | print(output) | ||||||
|  | 
 | ||||||
|  | container.stop() | ||||||
|  | @ -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  | ||||||
|  | @ -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()  | ||||||
|  | @ -0,0 +1,68 @@ | ||||||
|  | import docker | ||||||
|  | from typing import List, Optional  | ||||||
|  | import warnings | ||||||
|  | import socket | ||||||
|  | 
 | ||||||
|  | from agents.tools import Tool | ||||||
|  | 
 | ||||||
|  | class DockerPythonInterpreter: | ||||||
|  |     def __init__(self):  | ||||||
|  |         self.container = None | ||||||
|  |         try: | ||||||
|  |             self.client = docker.from_env() | ||||||
|  |             self.client.ping() | ||||||
|  |         except docker.errors.DockerException: | ||||||
|  |             raise RuntimeError( | ||||||
|  |                 "Could not connect to Docker daemon. Please ensure Docker is installed and running." | ||||||
|  |             ) | ||||||
|  |          | ||||||
|  |         try:             | ||||||
|  |             self.container = self.client.containers.run( | ||||||
|  |                 "pyrunner:latest", | ||||||
|  |                 ports={'65432/tcp': 65432}, | ||||||
|  |                 detach=True, | ||||||
|  |                 remove=True, | ||||||
|  |            ) | ||||||
|  |         except docker.errors.DockerException as e: | ||||||
|  |             raise RuntimeError(f"Failed to create Docker container: {e}") | ||||||
|  | 
 | ||||||
|  |     def stop(self): | ||||||
|  |         """Cleanup: Stop and remove container when object is destroyed""" | ||||||
|  |         if self.container: | ||||||
|  |             try: | ||||||
|  |                 self.container.kill() # can consider .stop(), but this is faster | ||||||
|  |             except Exception as e: | ||||||
|  |                 warnings.warn(f"Failed to stop Docker container: {e}") | ||||||
|  | 
 | ||||||
|  |     def execute(self, code: str, tools: Optional[List[Tool]] = None) -> str: | ||||||
|  |         """ | ||||||
|  |         Execute Python code in the container and return stdout and stderr | ||||||
|  |         """ | ||||||
|  | 
 | ||||||
|  |         if tools != None:         | ||||||
|  |             tool_instance = tools[0]() | ||||||
|  | 
 | ||||||
|  |             import_code = f""" | ||||||
|  | module_path = '{tool_instance.__class__.__module__}' | ||||||
|  | class_name = '{tool_instance.__class__.__name__}' | ||||||
|  | 
 | ||||||
|  | import importlib | ||||||
|  | 
 | ||||||
|  | module = importlib.import_module(module_path) | ||||||
|  | web_search = getattr(module, class_name)() | ||||||
|  | """ | ||||||
|  | 
 | ||||||
|  |             code = import_code + "\n" + code | ||||||
|  | 
 | ||||||
|  |         try: | ||||||
|  |             # 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)}" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | __all__ = ["DockerPythonInterpreter"] | ||||||
		Loading…
	
		Reference in New Issue