quantalogic 0.59.3__py3-none-any.whl → 0.61.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. quantalogic/agent.py +268 -24
  2. quantalogic/agent_config.py +5 -5
  3. quantalogic/agent_factory.py +2 -2
  4. quantalogic/codeact/__init__.py +0 -0
  5. quantalogic/codeact/agent.py +499 -0
  6. quantalogic/codeact/cli.py +232 -0
  7. quantalogic/codeact/constants.py +9 -0
  8. quantalogic/codeact/events.py +78 -0
  9. quantalogic/codeact/llm_util.py +76 -0
  10. quantalogic/codeact/prompts/error_format.j2 +11 -0
  11. quantalogic/codeact/prompts/generate_action.j2 +26 -0
  12. quantalogic/codeact/prompts/generate_program.j2 +39 -0
  13. quantalogic/codeact/prompts/response_format.j2 +11 -0
  14. quantalogic/codeact/tools_manager.py +135 -0
  15. quantalogic/codeact/utils.py +135 -0
  16. quantalogic/coding_agent.py +2 -2
  17. quantalogic/create_custom_agent.py +26 -78
  18. quantalogic/prompts/chat_system_prompt.j2 +10 -7
  19. quantalogic/prompts/code_2_system_prompt.j2 +190 -0
  20. quantalogic/prompts/code_system_prompt.j2 +142 -0
  21. quantalogic/prompts/doc_system_prompt.j2 +178 -0
  22. quantalogic/prompts/legal_2_system_prompt.j2 +218 -0
  23. quantalogic/prompts/legal_system_prompt.j2 +140 -0
  24. quantalogic/prompts/system_prompt.j2 +6 -2
  25. quantalogic/prompts/tools_prompt.j2 +2 -4
  26. quantalogic/prompts.py +23 -4
  27. quantalogic/python_interpreter/__init__.py +23 -0
  28. quantalogic/python_interpreter/assignment_visitors.py +63 -0
  29. quantalogic/python_interpreter/base_visitors.py +20 -0
  30. quantalogic/python_interpreter/class_visitors.py +22 -0
  31. quantalogic/python_interpreter/comprehension_visitors.py +172 -0
  32. quantalogic/python_interpreter/context_visitors.py +59 -0
  33. quantalogic/python_interpreter/control_flow_visitors.py +88 -0
  34. quantalogic/python_interpreter/exception_visitors.py +109 -0
  35. quantalogic/python_interpreter/exceptions.py +39 -0
  36. quantalogic/python_interpreter/execution.py +202 -0
  37. quantalogic/python_interpreter/function_utils.py +386 -0
  38. quantalogic/python_interpreter/function_visitors.py +209 -0
  39. quantalogic/python_interpreter/import_visitors.py +28 -0
  40. quantalogic/python_interpreter/interpreter_core.py +358 -0
  41. quantalogic/python_interpreter/literal_visitors.py +74 -0
  42. quantalogic/python_interpreter/misc_visitors.py +148 -0
  43. quantalogic/python_interpreter/operator_visitors.py +108 -0
  44. quantalogic/python_interpreter/scope.py +10 -0
  45. quantalogic/python_interpreter/visit_handlers.py +110 -0
  46. quantalogic/server/agent_server.py +1 -1
  47. quantalogic/tools/__init__.py +6 -3
  48. quantalogic/tools/action_gen.py +366 -0
  49. quantalogic/tools/duckduckgo_search_tool.py +1 -0
  50. quantalogic/tools/execute_bash_command_tool.py +114 -57
  51. quantalogic/tools/file_tracker_tool.py +49 -0
  52. quantalogic/tools/google_packages/google_news_tool.py +3 -0
  53. quantalogic/tools/image_generation/dalle_e.py +89 -137
  54. quantalogic/tools/python_tool.py +13 -0
  55. quantalogic/tools/rag_tool/__init__.py +2 -9
  56. quantalogic/tools/rag_tool/document_rag_sources_.py +728 -0
  57. quantalogic/tools/rag_tool/ocr_pdf_markdown.py +144 -0
  58. quantalogic/tools/replace_in_file_tool.py +1 -1
  59. quantalogic/tools/{search_definition_names.py → search_definition_names_tool.py} +2 -2
  60. quantalogic/tools/terminal_capture_tool.py +293 -0
  61. quantalogic/tools/tool.py +120 -22
  62. quantalogic/tools/utilities/__init__.py +2 -0
  63. quantalogic/tools/utilities/download_file_tool.py +3 -5
  64. quantalogic/tools/utilities/llm_tool.py +283 -0
  65. quantalogic/tools/utilities/selenium_tool.py +296 -0
  66. quantalogic/tools/utilities/vscode_tool.py +1 -1
  67. quantalogic/tools/web_navigation/__init__.py +5 -0
  68. quantalogic/tools/web_navigation/web_tool.py +145 -0
  69. quantalogic/tools/write_file_tool.py +72 -36
  70. quantalogic/utils/__init__.py +0 -1
  71. quantalogic/utils/test_python_interpreter.py +119 -0
  72. {quantalogic-0.59.3.dist-info → quantalogic-0.61.0.dist-info}/METADATA +7 -2
  73. {quantalogic-0.59.3.dist-info → quantalogic-0.61.0.dist-info}/RECORD +76 -35
  74. quantalogic/tools/rag_tool/document_metadata.py +0 -15
  75. quantalogic/tools/rag_tool/query_response.py +0 -20
  76. quantalogic/tools/rag_tool/rag_tool.py +0 -566
  77. quantalogic/tools/rag_tool/rag_tool_beta.py +0 -264
  78. quantalogic/utils/python_interpreter.py +0 -905
  79. {quantalogic-0.59.3.dist-info → quantalogic-0.61.0.dist-info}/LICENSE +0 -0
  80. {quantalogic-0.59.3.dist-info → quantalogic-0.61.0.dist-info}/WHEEL +0 -0
  81. {quantalogic-0.59.3.dist-info → quantalogic-0.61.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,148 @@
1
+ import ast
2
+ from typing import Any
3
+
4
+ from .interpreter_core import ASTInterpreter
5
+
6
+ async def visit_Global(self: ASTInterpreter, node: ast.Global, wrap_exceptions: bool = True) -> None:
7
+ self.env_stack[-1].setdefault("__global_names__", set()).update(node.names)
8
+
9
+ async def visit_Nonlocal(self: ASTInterpreter, node: ast.Nonlocal, wrap_exceptions: bool = True) -> None:
10
+ self.env_stack[-1].setdefault("__nonlocal_names__", set()).update(node.names)
11
+
12
+ async def visit_Delete(self: ASTInterpreter, node: ast.Delete, wrap_exceptions: bool = True):
13
+ for target in node.targets:
14
+ if isinstance(target, ast.Name):
15
+ del self.env_stack[-1][target.id]
16
+ elif isinstance(target, ast.Subscript):
17
+ obj = await self.visit(target.value, wrap_exceptions=wrap_exceptions)
18
+ key = await self.visit(target.slice, wrap_exceptions=wrap_exceptions)
19
+ del obj[key]
20
+ else:
21
+ raise Exception(f"Unsupported del target: {type(target).__name__}")
22
+
23
+ async def visit_Assert(self: ASTInterpreter, node: ast.Assert, wrap_exceptions: bool = True) -> None:
24
+ test = await self.visit(node.test, wrap_exceptions=wrap_exceptions)
25
+ if not test:
26
+ msg = await self.visit(node.msg, wrap_exceptions=wrap_exceptions) if node.msg else "Assertion failed"
27
+ raise AssertionError(msg)
28
+
29
+ async def visit_Yield(self: ASTInterpreter, node: ast.Yield, wrap_exceptions: bool = True) -> Any:
30
+ value = await self.visit(node.value, wrap_exceptions=wrap_exceptions) if node.value else None
31
+ self.recursion_depth += 1 # Treat yields as recursion for loop detection
32
+ if self.recursion_depth > self.max_recursion_depth:
33
+ raise RecursionError(f"Maximum recursion depth exceeded in yield ({self.max_recursion_depth})")
34
+ self.recursion_depth -= 1
35
+ return value
36
+
37
+ async def visit_YieldFrom(self: ASTInterpreter, node: ast.YieldFrom, wrap_exceptions: bool = True) -> Any:
38
+ iterable = await self.visit(node.value, wrap_exceptions=wrap_exceptions)
39
+ if hasattr(iterable, '__aiter__'):
40
+ async def async_gen():
41
+ async for value in iterable:
42
+ yield value
43
+ return async_gen()
44
+ else:
45
+ def sync_gen():
46
+ for value in iterable:
47
+ yield value
48
+ return sync_gen()
49
+
50
+ async def visit_Match(self: ASTInterpreter, node: ast.Match, wrap_exceptions: bool = True) -> Any:
51
+ subject = await self.visit(node.subject, wrap_exceptions=wrap_exceptions)
52
+ result = None
53
+ base_frame = self.env_stack[-1].copy()
54
+ for case in node.cases:
55
+ self.env_stack.append(base_frame.copy())
56
+ try:
57
+ if await self._match_pattern(subject, case.pattern):
58
+ if case.guard and not await self.visit(case.guard, wrap_exceptions=True):
59
+ continue
60
+ for stmt in case.body[:-1]:
61
+ await self.visit(stmt, wrap_exceptions=wrap_exceptions)
62
+ result = await self.visit(case.body[-1], wrap_exceptions=wrap_exceptions)
63
+ break
64
+ finally:
65
+ self.env_stack.pop()
66
+ return result
67
+
68
+ async def _match_pattern(self: ASTInterpreter, subject: Any, pattern: ast.AST) -> bool:
69
+ if isinstance(pattern, ast.MatchValue):
70
+ value = await self.visit(pattern.value, wrap_exceptions=True)
71
+ return subject == value
72
+ elif isinstance(pattern, ast.MatchSingleton):
73
+ return subject is pattern.value
74
+ elif isinstance(pattern, ast.MatchSequence):
75
+ if not isinstance(subject, (list, tuple)):
76
+ return False
77
+ if len(pattern.patterns) != len(subject) and not any(isinstance(p, ast.MatchStar) for p in pattern.patterns):
78
+ return False
79
+ star_idx = None
80
+ for i, pat in enumerate(pattern.patterns):
81
+ if isinstance(pat, ast.MatchStar):
82
+ if star_idx is not None:
83
+ return False
84
+ star_idx = i
85
+ if star_idx is None:
86
+ for sub, pat in zip(subject, pattern.patterns):
87
+ if not await self._match_pattern(sub, pat):
88
+ return False
89
+ return True
90
+ else:
91
+ before = pattern.patterns[:star_idx]
92
+ after = pattern.patterns[star_idx + 1:]
93
+ if len(before) + len(after) > len(subject):
94
+ return False
95
+ for sub, pat in zip(subject[:len(before)], before):
96
+ if not await self._match_pattern(sub, pat):
97
+ return False
98
+ for sub, pat in zip(subject[len(subject) - len(after):], after):
99
+ if not await self._match_pattern(sub, pat):
100
+ return False
101
+ star_pat = pattern.patterns[star_idx]
102
+ star_count = len(subject) - len(before) - len(after)
103
+ star_sub = subject[len(before):len(before) + star_count]
104
+ if star_pat.name:
105
+ self.set_variable(star_pat.name, star_sub)
106
+ return True
107
+ elif isinstance(pattern, ast.MatchMapping):
108
+ if not isinstance(subject, dict):
109
+ return False
110
+ keys = [await self.visit(k, wrap_exceptions=True) for k in pattern.keys]
111
+ if len(keys) != len(subject) and pattern.rest is None:
112
+ return False
113
+ for k, p in zip(keys, pattern.patterns):
114
+ if k not in subject or not await self._match_pattern(subject[k], p):
115
+ return False
116
+ if pattern.rest:
117
+ remaining = {k: v for k, v in subject.items() if k not in keys}
118
+ self.set_variable(pattern.rest, remaining)
119
+ return True
120
+ elif isinstance(pattern, ast.MatchClass):
121
+ cls = await self.visit(pattern.cls, wrap_exceptions=True)
122
+ if not isinstance(subject, cls):
123
+ return False
124
+ attrs = [getattr(subject, attr) for attr in pattern.attribute_names]
125
+ if len(attrs) != len(pattern.patterns):
126
+ return False
127
+ for attr_val, pat in zip(attrs, pattern.patterns):
128
+ if not await self._match_pattern(attr_val, pat):
129
+ return False
130
+ return True
131
+ elif isinstance(pattern, ast.MatchStar):
132
+ if pattern.name:
133
+ self.set_variable(pattern.name, subject)
134
+ return True
135
+ elif isinstance(pattern, ast.MatchAs):
136
+ if pattern.pattern:
137
+ if not await self._match_pattern(subject, pattern.pattern):
138
+ return False
139
+ if pattern.name:
140
+ self.set_variable(pattern.name, subject)
141
+ return True
142
+ elif isinstance(pattern, ast.MatchOr):
143
+ for pat in pattern.patterns:
144
+ if await self._match_pattern(subject, pat):
145
+ return True
146
+ return False
147
+ else:
148
+ raise Exception(f"Unsupported match pattern: {pattern.__class__.__name__}")
@@ -0,0 +1,108 @@
1
+ import ast
2
+ from typing import Any
3
+
4
+ from .interpreter_core import ASTInterpreter
5
+
6
+ async def visit_BinOp(self: ASTInterpreter, node: ast.BinOp, wrap_exceptions: bool = True) -> Any:
7
+ left: Any = await self.visit(node.left, wrap_exceptions=wrap_exceptions)
8
+ right: Any = await self.visit(node.right, wrap_exceptions=wrap_exceptions)
9
+ op = node.op
10
+ if isinstance(op, ast.Add):
11
+ return left + right
12
+ elif isinstance(op, ast.Sub):
13
+ if isinstance(left, set) and isinstance(right, set):
14
+ return left - right
15
+ return left - right
16
+ elif isinstance(op, ast.Mult):
17
+ return left * right
18
+ elif isinstance(op, ast.Div):
19
+ return left / right
20
+ elif isinstance(op, ast.FloorDiv):
21
+ return left // right
22
+ elif isinstance(op, ast.Mod):
23
+ return left % right
24
+ elif isinstance(op, ast.Pow):
25
+ return left**right
26
+ elif isinstance(op, ast.LShift):
27
+ return left << right
28
+ elif isinstance(op, ast.RShift):
29
+ return left >> right
30
+ elif isinstance(op, ast.BitOr):
31
+ if isinstance(left, set) and isinstance(right, set):
32
+ return left | right
33
+ return left | right
34
+ elif isinstance(op, ast.BitXor):
35
+ return left ^ right
36
+ elif isinstance(op, ast.BitAnd):
37
+ if isinstance(left, set) and isinstance(right, set):
38
+ return left & right
39
+ return left & right
40
+ else:
41
+ raise Exception("Unsupported binary operator: " + str(op))
42
+
43
+ async def visit_UnaryOp(self: ASTInterpreter, node: ast.UnaryOp, wrap_exceptions: bool = True) -> Any:
44
+ operand: Any = await self.visit(node.operand, wrap_exceptions=wrap_exceptions)
45
+ op = node.op
46
+ if isinstance(op, ast.UAdd):
47
+ return +operand
48
+ elif isinstance(op, ast.USub):
49
+ return -operand
50
+ elif isinstance(op, ast.Not):
51
+ return not operand
52
+ elif isinstance(op, ast.Invert):
53
+ return ~operand
54
+ else:
55
+ raise Exception("Unsupported unary operator: " + str(op))
56
+
57
+ async def visit_Compare(self: ASTInterpreter, node: ast.Compare, wrap_exceptions: bool = True) -> bool:
58
+ left: Any = await self.visit(node.left, wrap_exceptions=wrap_exceptions)
59
+ for op, comparator in zip(node.ops, node.comparators):
60
+ right: Any = await self.visit(comparator, wrap_exceptions=wrap_exceptions)
61
+ if isinstance(op, ast.Eq):
62
+ if not (left == right):
63
+ return False
64
+ elif isinstance(op, ast.NotEq):
65
+ if not (left != right):
66
+ return False
67
+ elif isinstance(op, ast.Lt):
68
+ if not (left < right):
69
+ return False
70
+ elif isinstance(op, ast.LtE):
71
+ if not (left <= right):
72
+ return False
73
+ elif isinstance(op, ast.Gt):
74
+ if not (left > right):
75
+ return False
76
+ elif isinstance(op, ast.GtE):
77
+ if not (left >= right):
78
+ return False
79
+ elif isinstance(op, ast.Is):
80
+ if left is not right:
81
+ return False
82
+ elif isinstance(op, ast.IsNot):
83
+ if not (left is not right):
84
+ return False
85
+ elif isinstance(op, ast.In):
86
+ if left not in right:
87
+ return False
88
+ elif isinstance(op, ast.NotIn):
89
+ if not (left not in right):
90
+ return False
91
+ else:
92
+ raise Exception("Unsupported comparison operator: " + str(op))
93
+ left = right
94
+ return True
95
+
96
+ async def visit_BoolOp(self: ASTInterpreter, node: ast.BoolOp, wrap_exceptions: bool = True) -> bool:
97
+ if isinstance(node.op, ast.And):
98
+ for value in node.values:
99
+ if not await self.visit(value, wrap_exceptions=wrap_exceptions):
100
+ return False
101
+ return True
102
+ elif isinstance(node.op, ast.Or):
103
+ for value in node.values:
104
+ if await self.visit(value, wrap_exceptions=wrap_exceptions):
105
+ return True
106
+ return False
107
+ else:
108
+ raise Exception("Unsupported boolean operator: " + str(node.op))
@@ -0,0 +1,10 @@
1
+ # quantalogic/utils/scope.py
2
+ class Scope:
3
+ def __init__(self, env_stack):
4
+ self.env_stack = env_stack
5
+
6
+ def __enter__(self):
7
+ self.env_stack.append({})
8
+
9
+ def __exit__(self, exc_type, exc_value, traceback):
10
+ self.env_stack.pop()
@@ -0,0 +1,110 @@
1
+ from .base_visitors import (
2
+ visit_Module,
3
+ visit_Expr,
4
+ visit_Pass,
5
+ visit_TypeIgnore,
6
+ )
7
+
8
+ from .import_visitors import (
9
+ visit_Import,
10
+ visit_ImportFrom,
11
+ )
12
+
13
+ from .literal_visitors import (
14
+ visit_Constant,
15
+ visit_Name,
16
+ visit_List,
17
+ visit_Tuple,
18
+ visit_Dict,
19
+ visit_Set,
20
+ visit_Attribute,
21
+ visit_Subscript,
22
+ visit_Slice,
23
+ visit_Index,
24
+ visit_Starred,
25
+ visit_JoinedStr,
26
+ visit_FormattedValue,
27
+ )
28
+
29
+ from .operator_visitors import (
30
+ visit_BinOp,
31
+ visit_UnaryOp,
32
+ visit_Compare,
33
+ visit_BoolOp,
34
+ )
35
+
36
+ from .assignment_visitors import (
37
+ visit_Assign,
38
+ visit_AugAssign,
39
+ visit_AnnAssign,
40
+ visit_NamedExpr,
41
+ )
42
+
43
+ from .control_flow_visitors import (
44
+ visit_If,
45
+ visit_While,
46
+ visit_For,
47
+ visit_AsyncFor,
48
+ visit_Break,
49
+ visit_Continue,
50
+ visit_Return,
51
+ visit_IfExp,
52
+ )
53
+
54
+ from .function_visitors import (
55
+ visit_FunctionDef,
56
+ visit_AsyncFunctionDef,
57
+ visit_AsyncGeneratorDef,
58
+ visit_Call,
59
+ visit_Await,
60
+ visit_Lambda,
61
+ )
62
+
63
+ from .comprehension_visitors import (
64
+ visit_ListComp,
65
+ visit_DictComp,
66
+ visit_SetComp,
67
+ visit_GeneratorExp,
68
+ )
69
+
70
+ from .exception_visitors import (
71
+ visit_Try,
72
+ visit_TryStar,
73
+ visit_Raise,
74
+ )
75
+
76
+ from .class_visitors import (
77
+ visit_ClassDef,
78
+ )
79
+
80
+ from .context_visitors import (
81
+ visit_With,
82
+ visit_AsyncWith,
83
+ )
84
+
85
+ from .misc_visitors import (
86
+ visit_Global,
87
+ visit_Nonlocal,
88
+ visit_Delete,
89
+ visit_Assert,
90
+ visit_Yield,
91
+ visit_YieldFrom,
92
+ visit_Match,
93
+ _match_pattern,
94
+ )
95
+
96
+ __all__ = [
97
+ "visit_Import", "visit_ImportFrom", "visit_ListComp", "visit_Module", "visit_Expr",
98
+ "visit_Constant", "visit_Name", "visit_BinOp", "visit_UnaryOp", "visit_Assign",
99
+ "visit_AugAssign", "visit_AnnAssign", "visit_Compare", "visit_BoolOp", "visit_If",
100
+ "visit_While", "visit_For", "visit_Break", "visit_Continue", "visit_FunctionDef",
101
+ "visit_AsyncFunctionDef", "visit_AsyncGeneratorDef", "visit_Call", "visit_Await",
102
+ "visit_Return", "visit_Lambda", "visit_List", "visit_Tuple", "visit_Dict",
103
+ "visit_Set", "visit_Attribute", "visit_Subscript", "visit_Slice", "visit_Index",
104
+ "visit_Starred", "visit_Pass", "visit_TypeIgnore", "visit_Try", "visit_TryStar",
105
+ "visit_Nonlocal", "visit_JoinedStr", "visit_FormattedValue", "visit_GeneratorExp",
106
+ "visit_ClassDef", "visit_With", "visit_AsyncWith", "visit_Raise", "visit_Global",
107
+ "visit_IfExp", "visit_DictComp", "visit_SetComp", "visit_Yield", "visit_YieldFrom",
108
+ "visit_Match", "visit_Delete", "visit_AsyncFor", "visit_Assert", "visit_NamedExpr",
109
+ "_match_pattern",
110
+ ]
@@ -563,7 +563,7 @@ async def event_stream(request: Request, task_id: Optional[str] = None) -> Strea
563
563
  except Empty:
564
564
  # Send keepalive to maintain connection
565
565
  yield ": keepalive\n\n"
566
- await asyncio.sleep(0.1)
566
+ # await asyncio.sleep(0)
567
567
 
568
568
  if server_state.is_shutting_down:
569
569
  yield 'event: shutdown\ndata: {"message": "Server shutting down"}\n\n'
@@ -8,6 +8,7 @@ from .duckduckgo_search_tool import DuckDuckGoSearchTool
8
8
  from .edit_whole_content_tool import EditWholeContentTool
9
9
  from .elixir_tool import ElixirTool
10
10
  from .execute_bash_command_tool import ExecuteBashCommandTool
11
+ from .file_tracker_tool import FileTrackerTool
11
12
  from .grep_app_tool import GrepAppTool
12
13
  from .input_question_tool import InputQuestionTool
13
14
  from .jinja_tool import JinjaTool
@@ -22,14 +23,14 @@ from .read_file_tool import ReadFileTool
22
23
  from .read_html_tool import ReadHTMLTool
23
24
  from .replace_in_file_tool import ReplaceInFileTool
24
25
  from .ripgrep_tool import RipgrepTool
25
- from .safe_python_interpreter_tool import SafePythonInterpreterTool
26
- from .search_definition_names import SearchDefinitionNames
26
+ from .search_definition_names_tool import SearchDefinitionNamesTool
27
27
  from .sequence_tool import SequenceTool
28
28
  from .serpapi_search_tool import SerpApiSearchTool
29
29
  from .sql_query_tool import SQLQueryTool
30
30
  from .task_complete_tool import TaskCompleteTool
31
31
  from .tool import Tool, ToolArgument, create_tool
32
32
  from .unified_diff_tool import UnifiedDiffTool
33
+ from .utils.generate_database_report import generate_database_report
33
34
  from .wikipedia_search_tool import WikipediaSearchTool
34
35
  from .write_file_tool import WriteFileTool
35
36
 
@@ -41,6 +42,7 @@ __all__ = [
41
42
  'EditWholeContentTool',
42
43
  'ElixirTool',
43
44
  'ExecuteBashCommandTool',
45
+ 'generate_database_report',
44
46
  'GrepAppTool',
45
47
  'InputQuestionTool',
46
48
  'JinjaTool',
@@ -56,7 +58,7 @@ __all__ = [
56
58
  'ReplaceInFileTool',
57
59
  'RipgrepTool',
58
60
  'SafePythonInterpreterTool',
59
- 'SearchDefinitionNames',
61
+ 'SearchDefinitionNamesTool',
60
62
  'SequenceTool',
61
63
  'SerpApiSearchTool',
62
64
  'SQLQueryTool',
@@ -66,5 +68,6 @@ __all__ = [
66
68
  'UnifiedDiffTool',
67
69
  'WikipediaSearchTool',
68
70
  'WriteFileTool',
71
+ 'FileTrackerTool',
69
72
  "create_tool"
70
73
  ]