russkiyximik commited on
Commit
138bf3e
·
1 Parent(s): 1765a9a

Overhauled Code Interpreter tool by wrapping it in a new class to make it robust to agent output

Browse files
mycoder/src/inner/config/agents.yaml CHANGED
@@ -6,6 +6,10 @@ coder:
6
  First you plan how the code will work, then you write the code, then you run it and check the output.
7
  You should check schema of uploaded files to understand their structure and proceed with analyses more
8
  efficiently.
 
 
 
 
9
  In some cases, no code generation is required, and you can simply provide the necessary results in markdown format.
10
  backstory: >
11
  You're a seasoned python developer and bioinformatician with a knack for writing clean, efficient code.
 
6
  First you plan how the code will work, then you write the code, then you run it and check the output.
7
  You should check schema of uploaded files to understand their structure and proceed with analyses more
8
  efficiently.
9
+ When you use the Code Interpreter tool, assign the final markdown report to a variable named `result`.
10
+ Do not rely on print statements alone. If you need dataframe info text, capture `df.info()` with `io.StringIO()`.
11
+ If you compute correlations, use numeric-only columns.
12
+ Once code execution succeeds and you have the output you need, stop rerunning the tool and write the final answer.
13
  In some cases, no code generation is required, and you can simply provide the necessary results in markdown format.
14
  backstory: >
15
  You're a seasoned python developer and bioinformatician with a knack for writing clean, efficient code.
mycoder/src/inner/config/tasks.yaml CHANGED
@@ -4,6 +4,8 @@ coding_task:
4
 
5
  Make sure to save any plots generated by code as 'output/plot.png'.
6
  Do not use seaborn for any plots/visualizations.
 
 
7
  expected_output: >
8
  A markdown file that includes the code itself, any comments/explanation,
9
  and the output of the code. Alternatively, if no code generation is required,
 
4
 
5
  Make sure to save any plots generated by code as 'output/plot.png'.
6
  Do not use seaborn for any plots/visualizations.
7
+ If you use Code Interpreter, assign the final markdown report to a variable named `result`.
8
+ Do not rely on print statements alone.
9
  expected_output: >
10
  A markdown file that includes the code itself, any comments/explanation,
11
  and the output of the code. Alternatively, if no code generation is required,
mycoder/src/inner/crew.py CHANGED
@@ -16,9 +16,12 @@ class Coder():
16
 
17
  @agent
18
  def coder(self) -> Agent:
19
- from src.inner.tools.custom_tool import ExtractSchema
20
- from crewai_tools import CodeInterpreterTool
21
- code_interpreter = CodeInterpreterTool(unsafe_mode=True)
 
 
 
22
  return Agent(
23
  config=self.agents_config['coder'],
24
  verbose=True,
 
16
 
17
  @agent
18
  def coder(self) -> Agent:
19
+ from src.inner.tools.custom_tool import (
20
+ ExtractSchema,
21
+ ResultAwareCodeInterpreterTool,
22
+ )
23
+
24
+ code_interpreter = ResultAwareCodeInterpreterTool(unsafe_mode=True)
25
  return Agent(
26
  config=self.agents_config['coder'],
27
  verbose=True,
mycoder/src/inner/tools/custom_tool.py CHANGED
@@ -1,8 +1,12 @@
1
- import pandas as pd
2
- import numpy as np
 
3
 
 
 
4
  from crewai.tools import BaseTool
5
- from typing import Any, Dict, Type
 
6
  from pydantic import BaseModel, Field
7
 
8
 
@@ -32,3 +36,69 @@ class ExtractSchema(BaseTool):
32
  "numeric_cols": df.select_dtypes(include=[np.number]).columns.tolist(),
33
  "categorical_cols": df.select_dtypes(include=['object']).columns.tolist()
34
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import io
2
+ from contextlib import redirect_stderr, redirect_stdout
3
+ from typing import Any, Dict, Type
4
 
5
+ import numpy as np
6
+ import pandas as pd
7
  from crewai.tools import BaseTool
8
+ from crewai_tools import CodeInterpreterTool
9
+ from crewai_tools.tools.code_interpreter_tool.code_interpreter_tool import SandboxPython
10
  from pydantic import BaseModel, Field
11
 
12
 
 
36
  "numeric_cols": df.select_dtypes(include=[np.number]).columns.tolist(),
37
  "categorical_cols": df.select_dtypes(include=['object']).columns.tolist()
38
  }
39
+
40
+
41
+ class ResultAwareCodeInterpreterTool(CodeInterpreterTool):
42
+ """Returns `result` when present and falls back to captured stdout/stderr."""
43
+
44
+ @staticmethod
45
+ def _resolve_execution_output(
46
+ exec_locals: Dict[str, Any],
47
+ stdout_buffer: io.StringIO,
48
+ stderr_buffer: io.StringIO,
49
+ ) -> str:
50
+ result = exec_locals.get("result")
51
+ if result is not None:
52
+ return str(result)
53
+
54
+ stdout_text = stdout_buffer.getvalue().strip()
55
+ stderr_text = stderr_buffer.getvalue().strip()
56
+
57
+ if stdout_text and stderr_text:
58
+ return f"{stdout_text}\n\n[stderr]\n{stderr_text}"
59
+ if stdout_text:
60
+ return stdout_text
61
+ if stderr_text:
62
+ return stderr_text
63
+ return "Code executed successfully, but it did not set `result` or print output."
64
+
65
+ @staticmethod
66
+ def run_code_in_restricted_sandbox(code: str) -> str:
67
+ stdout_buffer = io.StringIO()
68
+ stderr_buffer = io.StringIO()
69
+ exec_locals: Dict[str, Any] = {}
70
+
71
+ try:
72
+ with redirect_stdout(stdout_buffer), redirect_stderr(stderr_buffer):
73
+ SandboxPython.exec(code=code, locals_=exec_locals)
74
+ except Exception as e:
75
+ return f"An error occurred: {e!s}"
76
+
77
+ return ResultAwareCodeInterpreterTool._resolve_execution_output(
78
+ exec_locals,
79
+ stdout_buffer,
80
+ stderr_buffer,
81
+ )
82
+
83
+ @staticmethod
84
+ def run_code_unsafe(code: str, libraries_used: list[str]) -> str:
85
+ stdout_buffer = io.StringIO()
86
+ stderr_buffer = io.StringIO()
87
+
88
+ for library in libraries_used:
89
+ import os
90
+
91
+ os.system(f"pip install {library}") # noqa: S605
92
+
93
+ try:
94
+ exec_locals: Dict[str, Any] = {}
95
+ with redirect_stdout(stdout_buffer), redirect_stderr(stderr_buffer):
96
+ exec(code, {}, exec_locals) # noqa: S102
97
+ except Exception as e:
98
+ return f"An error occurred: {e!s}"
99
+
100
+ return ResultAwareCodeInterpreterTool._resolve_execution_output(
101
+ exec_locals,
102
+ stdout_buffer,
103
+ stderr_buffer,
104
+ )