quantalogic 0.35.0__py3-none-any.whl → 0.50.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 (107) hide show
  1. quantalogic/__init__.py +0 -4
  2. quantalogic/agent.py +603 -363
  3. quantalogic/agent_config.py +233 -46
  4. quantalogic/agent_factory.py +34 -22
  5. quantalogic/coding_agent.py +16 -14
  6. quantalogic/config.py +2 -1
  7. quantalogic/console_print_events.py +4 -8
  8. quantalogic/console_print_token.py +2 -2
  9. quantalogic/docs_cli.py +15 -10
  10. quantalogic/event_emitter.py +258 -83
  11. quantalogic/flow/__init__.py +23 -0
  12. quantalogic/flow/flow.py +595 -0
  13. quantalogic/flow/flow_extractor.py +672 -0
  14. quantalogic/flow/flow_generator.py +89 -0
  15. quantalogic/flow/flow_manager.py +407 -0
  16. quantalogic/flow/flow_manager_schema.py +169 -0
  17. quantalogic/flow/flow_yaml.md +419 -0
  18. quantalogic/generative_model.py +109 -77
  19. quantalogic/get_model_info.py +5 -5
  20. quantalogic/interactive_text_editor.py +100 -73
  21. quantalogic/main.py +17 -21
  22. quantalogic/model_info_list.py +3 -3
  23. quantalogic/model_info_litellm.py +14 -14
  24. quantalogic/prompts.py +2 -1
  25. quantalogic/{llm.py → quantlitellm.py} +29 -39
  26. quantalogic/search_agent.py +4 -4
  27. quantalogic/server/models.py +4 -1
  28. quantalogic/task_file_reader.py +5 -5
  29. quantalogic/task_runner.py +20 -20
  30. quantalogic/tool_manager.py +10 -21
  31. quantalogic/tools/__init__.py +98 -68
  32. quantalogic/tools/composio/composio.py +416 -0
  33. quantalogic/tools/{generate_database_report_tool.py → database/generate_database_report_tool.py} +4 -9
  34. quantalogic/tools/database/sql_query_tool_advanced.py +261 -0
  35. quantalogic/tools/document_tools/markdown_to_docx_tool.py +620 -0
  36. quantalogic/tools/document_tools/markdown_to_epub_tool.py +438 -0
  37. quantalogic/tools/document_tools/markdown_to_html_tool.py +362 -0
  38. quantalogic/tools/document_tools/markdown_to_ipynb_tool.py +319 -0
  39. quantalogic/tools/document_tools/markdown_to_latex_tool.py +420 -0
  40. quantalogic/tools/document_tools/markdown_to_pdf_tool.py +623 -0
  41. quantalogic/tools/document_tools/markdown_to_pptx_tool.py +319 -0
  42. quantalogic/tools/duckduckgo_search_tool.py +2 -4
  43. quantalogic/tools/finance/alpha_vantage_tool.py +440 -0
  44. quantalogic/tools/finance/ccxt_tool.py +373 -0
  45. quantalogic/tools/finance/finance_llm_tool.py +387 -0
  46. quantalogic/tools/finance/google_finance.py +192 -0
  47. quantalogic/tools/finance/market_intelligence_tool.py +520 -0
  48. quantalogic/tools/finance/technical_analysis_tool.py +491 -0
  49. quantalogic/tools/finance/tradingview_tool.py +336 -0
  50. quantalogic/tools/finance/yahoo_finance.py +236 -0
  51. quantalogic/tools/git/bitbucket_clone_repo_tool.py +181 -0
  52. quantalogic/tools/git/bitbucket_operations_tool.py +326 -0
  53. quantalogic/tools/git/clone_repo_tool.py +189 -0
  54. quantalogic/tools/git/git_operations_tool.py +532 -0
  55. quantalogic/tools/google_packages/google_news_tool.py +480 -0
  56. quantalogic/tools/grep_app_tool.py +123 -186
  57. quantalogic/tools/{dalle_e.py → image_generation/dalle_e.py} +37 -27
  58. quantalogic/tools/jinja_tool.py +6 -10
  59. quantalogic/tools/language_handlers/__init__.py +22 -9
  60. quantalogic/tools/list_directory_tool.py +131 -42
  61. quantalogic/tools/llm_tool.py +45 -15
  62. quantalogic/tools/llm_vision_tool.py +59 -7
  63. quantalogic/tools/markitdown_tool.py +17 -5
  64. quantalogic/tools/nasa_packages/models.py +47 -0
  65. quantalogic/tools/nasa_packages/nasa_apod_tool.py +232 -0
  66. quantalogic/tools/nasa_packages/nasa_neows_tool.py +147 -0
  67. quantalogic/tools/nasa_packages/services.py +82 -0
  68. quantalogic/tools/presentation_tools/presentation_llm_tool.py +396 -0
  69. quantalogic/tools/product_hunt/product_hunt_tool.py +258 -0
  70. quantalogic/tools/product_hunt/services.py +63 -0
  71. quantalogic/tools/rag_tool/__init__.py +48 -0
  72. quantalogic/tools/rag_tool/document_metadata.py +15 -0
  73. quantalogic/tools/rag_tool/query_response.py +20 -0
  74. quantalogic/tools/rag_tool/rag_tool.py +566 -0
  75. quantalogic/tools/rag_tool/rag_tool_beta.py +264 -0
  76. quantalogic/tools/read_html_tool.py +24 -38
  77. quantalogic/tools/replace_in_file_tool.py +10 -10
  78. quantalogic/tools/safe_python_interpreter_tool.py +10 -24
  79. quantalogic/tools/search_definition_names.py +2 -2
  80. quantalogic/tools/sequence_tool.py +14 -23
  81. quantalogic/tools/sql_query_tool.py +17 -19
  82. quantalogic/tools/tool.py +39 -15
  83. quantalogic/tools/unified_diff_tool.py +1 -1
  84. quantalogic/tools/utilities/csv_processor_tool.py +234 -0
  85. quantalogic/tools/utilities/download_file_tool.py +179 -0
  86. quantalogic/tools/utilities/mermaid_validator_tool.py +661 -0
  87. quantalogic/tools/utils/__init__.py +1 -4
  88. quantalogic/tools/utils/create_sample_database.py +24 -38
  89. quantalogic/tools/utils/generate_database_report.py +74 -82
  90. quantalogic/tools/wikipedia_search_tool.py +17 -21
  91. quantalogic/utils/ask_user_validation.py +1 -1
  92. quantalogic/utils/async_utils.py +35 -0
  93. quantalogic/utils/check_version.py +3 -5
  94. quantalogic/utils/get_all_models.py +2 -1
  95. quantalogic/utils/git_ls.py +21 -7
  96. quantalogic/utils/lm_studio_model_info.py +9 -7
  97. quantalogic/utils/python_interpreter.py +113 -43
  98. quantalogic/utils/xml_utility.py +178 -0
  99. quantalogic/version_check.py +1 -1
  100. quantalogic/welcome_message.py +7 -7
  101. quantalogic/xml_parser.py +0 -1
  102. {quantalogic-0.35.0.dist-info → quantalogic-0.50.0.dist-info}/METADATA +40 -1
  103. quantalogic-0.50.0.dist-info/RECORD +148 -0
  104. quantalogic-0.35.0.dist-info/RECORD +0 -102
  105. {quantalogic-0.35.0.dist-info → quantalogic-0.50.0.dist-info}/LICENSE +0 -0
  106. {quantalogic-0.35.0.dist-info → quantalogic-0.50.0.dist-info}/WHEEL +0 -0
  107. {quantalogic-0.35.0.dist-info → quantalogic-0.50.0.dist-info}/entry_points.txt +0 -0
@@ -3,24 +3,51 @@
3
3
  # Standard library imports
4
4
 
5
5
  # Local application imports
6
+ import logging
7
+ import os
8
+ from typing import Any
9
+
6
10
  from dotenv import load_dotenv
7
11
 
8
12
  from quantalogic.agent import Agent
9
13
  from quantalogic.console_print_token import console_print_token
14
+ from quantalogic.event_emitter import EventEmitter
15
+ from quantalogic.memory import AgentMemory
10
16
  from quantalogic.tools import (
11
17
  AgentTool,
18
+ BitbucketCloneTool,
19
+ BitbucketOperationsTool,
20
+ CloneRepoTool,
21
+ ComposioTool,
22
+ CSVProcessorTool,
12
23
  DownloadHttpFileTool,
13
24
  DuckDuckGoSearchTool,
14
25
  EditWholeContentTool,
15
26
  ExecuteBashCommandTool,
27
+ GitOperationsTool,
28
+ GoogleNewsTool,
16
29
  InputQuestionTool,
17
30
  ListDirectoryTool,
18
31
  LLMImageGenerationTool,
19
32
  LLMTool,
20
33
  LLMVisionTool,
34
+ MarkdownToDocxTool,
35
+ MarkdownToEpubTool,
36
+ MarkdownToHtmlTool,
37
+ MarkdownToIpynbTool,
38
+ MarkdownToLatexTool,
39
+ MarkdownToPdfTool,
40
+ MarkdownToPptxTool,
21
41
  MarkitdownTool,
42
+ MermaidValidatorTool,
43
+ NasaApodTool,
44
+ NasaNeoWsTool,
22
45
  NodeJsTool,
46
+ PrepareDownloadTool,
47
+ PresentationLLMTool,
48
+ ProductHuntTool,
23
49
  PythonTool,
50
+ RagTool,
24
51
  ReadFileBlockTool,
25
52
  ReadFileTool,
26
53
  ReadHTMLTool,
@@ -28,6 +55,9 @@ from quantalogic.tools import (
28
55
  RipgrepTool,
29
56
  SafePythonInterpreterTool,
30
57
  SearchDefinitionNames,
58
+ SequenceTool,
59
+ SQLQueryTool,
60
+ SQLQueryToolAdvanced,
31
61
  TaskCompleteTool,
32
62
  WikipediaSearchTool,
33
63
  WriteFileTool,
@@ -37,21 +67,24 @@ load_dotenv()
37
67
 
38
68
  MODEL_NAME = "deepseek/deepseek-chat"
39
69
 
70
+ logger = logging.getLogger(__name__)
40
71
 
41
72
  _current_model_name: str = ""
42
73
 
74
+
43
75
  def get_current_model() -> str:
44
76
  """Retrieve the currently active model name."""
45
77
  if not _current_model_name:
46
78
  raise ValueError("No model initialized")
47
79
  return _current_model_name
48
80
 
81
+
49
82
  def create_agent(
50
- model_name: str,
51
- vision_model_name: str | None,
52
- no_stream: bool = False,
83
+ model_name: str,
84
+ vision_model_name: str | None,
85
+ no_stream: bool = False,
53
86
  compact_every_n_iteration: int | None = None,
54
- max_tokens_working_memory: int | None = None
87
+ max_tokens_working_memory: int | None = None,
55
88
  ) -> Agent:
56
89
  global _current_model_name
57
90
  _current_model_name = model_name
@@ -81,18 +114,18 @@ def create_agent(
81
114
  SearchDefinitionNames(),
82
115
  MarkitdownTool(),
83
116
  LLMTool(model_name=model_name, on_token=console_print_token if not no_stream else None),
84
- DownloadHttpFileTool(),
117
+ DownloadHttpFileTool(),
85
118
  LLMImageGenerationTool(
86
- provider="dall-e",
87
- model_name="openai/dall-e-3",
88
- on_token=console_print_token if not no_stream else None
89
- ),
119
+ provider="dall-e", model_name="openai/dall-e-3", on_token=console_print_token if not no_stream else None
120
+ ),
90
121
  ReadHTMLTool(),
91
122
  # SafePythonInterpreterTool(allowed_modules=["math", "numpy"])
92
123
  ]
93
124
 
94
125
  if vision_model_name:
95
- tools.append(LLMVisionTool(model_name=vision_model_name, on_token=console_print_token if not no_stream else None))
126
+ tools.append(
127
+ LLMVisionTool(model_name=vision_model_name, on_token=console_print_token if not no_stream else None)
128
+ )
96
129
 
97
130
  return Agent(
98
131
  model_name=model_name,
@@ -103,11 +136,11 @@ def create_agent(
103
136
 
104
137
 
105
138
  def create_interpreter_agent(
106
- model_name: str,
107
- vision_model_name: str | None,
108
- no_stream: bool = False,
139
+ model_name: str,
140
+ vision_model_name: str | None,
141
+ no_stream: bool = False,
109
142
  compact_every_n_iteration: int | None = None,
110
- max_tokens_working_memory: int | None = None
143
+ max_tokens_working_memory: int | None = None,
111
144
  ) -> Agent:
112
145
  """Create an interpreter agent with the specified model and tools.
113
146
 
@@ -141,7 +174,7 @@ def create_interpreter_agent(
141
174
  ReadHTMLTool(),
142
175
  ]
143
176
  return Agent(
144
- model_name=model_name,
177
+ model_name=model_name,
145
178
  tools=tools,
146
179
  compact_every_n_iterations=compact_every_n_iteration,
147
180
  max_tokens_working_memory=max_tokens_working_memory,
@@ -149,11 +182,11 @@ def create_interpreter_agent(
149
182
 
150
183
 
151
184
  def create_full_agent(
152
- model_name: str,
153
- vision_model_name: str | None,
154
- no_stream: bool = False,
185
+ model_name: str,
186
+ vision_model_name: str | None,
187
+ no_stream: bool = False,
155
188
  compact_every_n_iteration: int | None = None,
156
- max_tokens_working_memory: int | None = None
189
+ max_tokens_working_memory: int | None = None,
157
190
  ) -> Agent:
158
191
  """Create an agent with the specified model and many tools.
159
192
 
@@ -188,11 +221,13 @@ def create_full_agent(
188
221
  WikipediaSearchTool(),
189
222
  DuckDuckGoSearchTool(),
190
223
  ReadHTMLTool(),
191
- # SafePythonInterpreterTool(allowed_modules=["math", "numpy"])
224
+ # SafePythonInterpreterTool(allowed_modules=["math", "numpy"])
192
225
  ]
193
226
 
194
227
  if vision_model_name:
195
- tools.append(LLMVisionTool(model_name=vision_model_name,on_token=console_print_token if not no_stream else None))
228
+ tools.append(
229
+ LLMVisionTool(model_name=vision_model_name, on_token=console_print_token if not no_stream else None)
230
+ )
196
231
 
197
232
  return Agent(
198
233
  model_name=model_name,
@@ -203,11 +238,11 @@ def create_full_agent(
203
238
 
204
239
 
205
240
  def create_basic_agent(
206
- model_name: str,
207
- vision_model_name: str | None = None,
208
- no_stream: bool = False,
241
+ model_name: str,
242
+ vision_model_name: str | None = None,
243
+ no_stream: bool = False,
209
244
  compact_every_n_iteration: int | None = None,
210
- max_tokens_working_memory: int | None = None
245
+ max_tokens_working_memory: int | None = None,
211
246
  ) -> Agent:
212
247
  """Create an agent with the specified model and tools.
213
248
 
@@ -224,7 +259,6 @@ def create_basic_agent(
224
259
  # Rebuild AgentTool to resolve forward references
225
260
  AgentTool.model_rebuild()
226
261
 
227
-
228
262
  tools = [
229
263
  TaskCompleteTool(),
230
264
  ListDirectoryTool(),
@@ -239,11 +273,13 @@ def create_basic_agent(
239
273
  ExecuteBashCommandTool(),
240
274
  LLMTool(model_name=model_name, on_token=console_print_token if not no_stream else None),
241
275
  ReadHTMLTool(),
242
- # SafePythonInterpreterTool(allowed_modules=["math", "numpy"])
276
+ # SafePythonInterpreterTool(allowed_modules=["math", "numpy"])
243
277
  ]
244
278
 
245
279
  if vision_model_name:
246
- tools.append(LLMVisionTool(model_name=vision_model_name, on_token=console_print_token if not no_stream else None))
280
+ tools.append(
281
+ LLMVisionTool(model_name=vision_model_name, on_token=console_print_token if not no_stream else None)
282
+ )
247
283
 
248
284
  return Agent(
249
285
  model_name=model_name,
@@ -252,12 +288,16 @@ def create_basic_agent(
252
288
  max_tokens_working_memory=max_tokens_working_memory,
253
289
  )
254
290
 
255
- def create_minimal_agent(
291
+
292
+ def create_custom_agent(
256
293
  model_name: str,
257
294
  vision_model_name: str | None = None,
258
295
  no_stream: bool = False,
259
296
  compact_every_n_iteration: int | None = None,
260
- max_tokens_working_memory: int | None = None
297
+ max_tokens_working_memory: int | None = None,
298
+ specific_expertise: str = "",
299
+ tools: list[Any] | None = None,
300
+ memory: AgentMemory | None = None
261
301
  ) -> Agent:
262
302
  """Create an agent with the specified model and tools.
263
303
 
@@ -267,32 +307,179 @@ def create_minimal_agent(
267
307
  no_stream (bool, optional): If True, the agent will not stream results.
268
308
  compact_every_n_iteration (int | None, optional): Frequency of memory compaction.
269
309
  max_tokens_working_memory (int | None, optional): Maximum tokens for working memory.
310
+ specific_expertise (str, optional): Specific expertise of the agent.
311
+ tools (list[Any], optional): List of tool configurations to add to the agent.
312
+ Each tool config should have:
313
+ - type: str - The type of tool
314
+ - parameters: dict - The parameters required for the tool
315
+ memory (AgentMemory, optional): Memory object to use for the agent.
270
316
 
271
317
  Returns:
272
318
  Agent: An agent with the specified model and tools
273
319
  """
320
+ storage_dir = os.path.join(os.path.dirname(__file__), "storage", "rag")
321
+ os.makedirs(storage_dir, exist_ok=True)
322
+
274
323
  # Rebuild AgentTool to resolve forward references
275
324
  AgentTool.model_rebuild()
276
325
 
277
- tools = [
278
- LLMTool(model_name=model_name, on_token=console_print_token if not no_stream else None),
279
- DownloadHttpFileTool(),
280
- WikipediaSearchTool(),
281
- DuckDuckGoSearchTool(),
282
- ReadHTMLTool(),
283
- SearchDefinitionNames(),
284
- ReadFileBlockTool(),
285
- WriteFileTool(),
286
- ReadFileTool(),
287
- TaskCompleteTool(),
288
- ]
289
-
290
- if vision_model_name:
291
- tools.append(LLMVisionTool(model_name=vision_model_name, on_token=console_print_token if not no_stream else None))
326
+ # Create event emitter
327
+ event_emitter = EventEmitter()
328
+
329
+ # Define tool mapping with their parameter requirements
330
+ tool_mapping = {
331
+ "llm": lambda params: LLMTool(
332
+ model_name=params.get("model_name", model_name),
333
+ on_token=console_print_token if not no_stream else None,
334
+ event_emitter=event_emitter
335
+ ),
336
+ "llm_vision": lambda params: LLMVisionTool(
337
+ model_name=params.get("vision_model_name") or vision_model_name,
338
+ on_token=console_print_token if not no_stream else None,
339
+ event_emitter=event_emitter
340
+ ),
341
+ "llm_image_generation": lambda params: LLMImageGenerationTool(
342
+ # provider=params.get("provider", "dall-e"),
343
+ provider="dall-e",
344
+ # model_name=params.get("model_name", "openai/dall-e-3"),
345
+ model_name="openai/dall-e-3",
346
+ on_token=console_print_token if not no_stream else None,
347
+ # event_emitter=event_emitter
348
+ ),
349
+ "download_http_file": lambda params: DownloadHttpFileTool(),
350
+ "duck_duck_go_search": lambda params: DuckDuckGoSearchTool(),
351
+ "edit_whole_content": lambda params: EditWholeContentTool(),
352
+ "execute_bash_command": lambda params: ExecuteBashCommandTool(),
353
+ "input_question": lambda params: InputQuestionTool(),
354
+ "list_directory": lambda params: ListDirectoryTool(),
355
+ "markitdown": lambda params: MarkitdownTool(),
356
+ "nodejs": lambda params: NodeJsTool(),
357
+ "python": lambda params: PythonTool(),
358
+ "read_file_block": lambda params: ReadFileBlockTool(),
359
+ "read_file": lambda params: ReadFileTool(),
360
+ "read_html": lambda params: ReadHTMLTool(),
361
+ "replace_in_file": lambda params: ReplaceInFileTool(),
362
+ "ripgrep": lambda params: RipgrepTool(),
363
+ "safe_python_interpreter": lambda params: SafePythonInterpreterTool(),
364
+ "search_definition_names": lambda params: SearchDefinitionNames(),
365
+ "wikipedia_search": lambda params: WikipediaSearchTool(),
366
+ "write_file": lambda params: WriteFileTool(),
367
+ "google_news": lambda params: GoogleNewsTool(
368
+ # model_name=params.get("model_name", model_name),
369
+ # on_token=console_print_token if not no_stream else None,
370
+ # event_emitter=event_emitter
371
+ ),
372
+ "presentation_llm": lambda params: PresentationLLMTool(
373
+ model_name=params.get("model_name", model_name),
374
+ additional_info=params.get("additional_info", ""),
375
+ on_token=console_print_token if not no_stream else None,
376
+ event_emitter=event_emitter
377
+ ),
378
+ "sequence": lambda params: SequenceTool(
379
+ model_name=params.get("model_name", model_name),
380
+ on_token=console_print_token if not no_stream else None,
381
+ # event_emitter=event_emitter
382
+ ),
383
+ "sql_query": lambda params: SQLQueryTool(
384
+ connection_string=params.get("connection_string", ""),
385
+ model_name=params.get("model_name", model_name),
386
+ on_token=console_print_token if not no_stream else None,
387
+ # event_emitter=event_emitter
388
+ ),
389
+ "sql_query_advanced": lambda params: SQLQueryToolAdvanced(
390
+ connection_string=params.get("connection_string", ""),
391
+ model_name=params.get("model_name", model_name),
392
+ on_token=console_print_token if not no_stream else None,
393
+ # event_emitter=event_emitter
394
+ ),
395
+ "clone_repo_tool": lambda params: CloneRepoTool(auth_token=params.get("auth_token", "")),
396
+ "bitbucket_clone_repo_tool": lambda params: BitbucketCloneTool(access_token=params.get("access_token", "")),
397
+ "bitbucket_operations_tool": lambda params: BitbucketOperationsTool(access_token=params.get("access_token", "")),
398
+ "git_operations_tool": lambda params: GitOperationsTool(auth_token=params.get("auth_token", "")),
399
+ "markdown_to_pdf": lambda params: MarkdownToPdfTool(),
400
+ "markdown_to_pptx": lambda params: MarkdownToPptxTool(),
401
+ "markdown_to_html": lambda params: MarkdownToHtmlTool(),
402
+ "markdown_to_epub": lambda params: MarkdownToEpubTool(),
403
+ "markdown_to_ipynb": lambda params: MarkdownToIpynbTool(),
404
+ "markdown_to_latex": lambda params: MarkdownToLatexTool(),
405
+ "markdown_to_docx": lambda params: MarkdownToDocxTool(),
406
+ "csv_processor": lambda params: CSVProcessorTool(),
407
+ "mermaid_validator_tool": lambda params: MermaidValidatorTool(),
408
+ "download_file_tool": lambda params: PrepareDownloadTool(),
409
+ "email_tool": lambda params: ComposioTool(
410
+ action="GMAIL_SEND_EMAIL",
411
+ name="email_tool",
412
+ description="Send emails via Gmail",
413
+ need_validation=False
414
+ ),
415
+ "callendar_tool": lambda params: ComposioTool(
416
+ action="GOOGLECALENDAR_CREATE_EVENT",
417
+ name="callendar_tool",
418
+ description="Create events in Google Calendar",
419
+ need_validation=False
420
+ ),
421
+ "weather_tool": lambda params: ComposioTool(
422
+ action="WEATHERMAP_WEATHER",
423
+ name="weather_tool",
424
+ description="Get weather information for a location"
425
+ ),
426
+ "nasa_neows_tool": lambda params: NasaNeoWsTool(),
427
+ "nasa_apod_tool": lambda params: NasaApodTool(),
428
+ "product_hunt_tool": lambda params : ProductHuntTool(),
429
+ "rag_tool": lambda params: RagTool(
430
+ vector_store=params.get("vector_store", "chroma"),
431
+ embedding_model=params.get("embedding_model", "openai"),
432
+ persist_dir=storage_dir,
433
+ document_paths=params.get("document_paths", [])
434
+ )
435
+ }
436
+
437
+ # Define write tools that should trigger automatic download tool addition
438
+ write_tools = {"write_file", "edit_whole_content", "replace_in_file"}
439
+
440
+ agent_tools = []
441
+ has_write_tool = any(
442
+ tool_config.get("type") in write_tools
443
+ for tool_config in (tools or [])
444
+ )
292
445
 
446
+ # Add tools only if they are provided
447
+ if tools:
448
+ for tool_config in tools:
449
+ tool_type = tool_config.get("type")
450
+ logger.debug(f"Processing tool type: {tool_type}")
451
+
452
+ if tool_type in tool_mapping:
453
+ try:
454
+ # Get tool parameters or empty dict if not provided
455
+ tool_params = tool_config.get("parameters", {})
456
+
457
+ # Create tool instance with parameters
458
+ tool = tool_mapping[tool_type](tool_params)
459
+ logger.debug(f"Created tool instance: {tool}")
460
+
461
+ if tool: # Some tools (like llm_vision) might return None
462
+ agent_tools.append(tool)
463
+ logger.info(f"Added tool: {tool_type}")
464
+ except Exception as e:
465
+ logger.error(f"Failed to create tool {tool_type}: {str(e)}")
466
+
467
+ # If any write tool was added, also add the download tool
468
+ if has_write_tool:
469
+ try:
470
+ agent_tools.append(PrepareDownloadTool())
471
+ logger.info("Added download tool automatically")
472
+ except Exception as e:
473
+ logger.error(f"Failed to add download tool: {str(e)}")
474
+
475
+ agent_tools.append(TaskCompleteTool())
476
+
293
477
  return Agent(
294
478
  model_name=model_name,
295
- tools=tools,
479
+ tools=agent_tools,
480
+ event_emitter=event_emitter,
296
481
  compact_every_n_iterations=compact_every_n_iteration,
297
482
  max_tokens_working_memory=max_tokens_working_memory,
483
+ specific_expertise=specific_expertise,
484
+ memory=memory,
298
485
  )
@@ -1,21 +1,22 @@
1
- from typing import Dict, Optional
1
+ from typing import Any, Dict, List, Optional
2
2
 
3
3
  from loguru import logger
4
4
 
5
5
  from quantalogic.agent import Agent
6
6
  from quantalogic.agent_config import (
7
7
  create_basic_agent,
8
+ create_custom_agent,
8
9
  create_full_agent,
9
10
  create_interpreter_agent,
10
- create_minimal_agent,
11
11
  )
12
12
  from quantalogic.coding_agent import create_coding_agent
13
+ from quantalogic.memory import AgentMemory
13
14
  from quantalogic.search_agent import create_search_agent # noqa: E402
14
15
 
15
16
 
16
17
  class AgentRegistry:
17
18
  """Registry for managing agent instances by name."""
18
-
19
+
19
20
  _instance = None
20
21
  _agents: Dict[str, Agent] = {}
21
22
 
@@ -27,7 +28,7 @@ class AgentRegistry:
27
28
  @classmethod
28
29
  def register_agent(cls, name: str, agent: Agent) -> None:
29
30
  """Register an agent instance with a name.
30
-
31
+
31
32
  Args:
32
33
  name: Unique name for the agent
33
34
  agent: Agent instance to register
@@ -39,13 +40,13 @@ class AgentRegistry:
39
40
  @classmethod
40
41
  def get_agent(cls, name: str) -> Agent:
41
42
  """Retrieve a registered agent by name.
42
-
43
+
43
44
  Args:
44
45
  name: Name of the agent to retrieve
45
-
46
+
46
47
  Returns:
47
48
  Registered Agent instance
48
-
49
+
49
50
  Raises:
50
51
  KeyError: If no agent with that name exists
51
52
  """
@@ -54,12 +55,13 @@ class AgentRegistry:
54
55
  @classmethod
55
56
  def list_agents(cls) -> Dict[str, str]:
56
57
  """List all registered agents.
57
-
58
+
58
59
  Returns:
59
60
  Dictionary mapping agent names to their types
60
61
  """
61
62
  return {name: type(agent).__name__ for name, agent in cls._agents.items()}
62
63
 
64
+
63
65
  """Agent factory module for creating different types of agents."""
64
66
 
65
67
 
@@ -70,10 +72,14 @@ def create_agent_for_mode(
70
72
  thinking_model_name: Optional[str],
71
73
  no_stream: bool = False,
72
74
  compact_every_n_iteration: Optional[int] = None,
73
- max_tokens_working_memory: Optional[int] = None
75
+ max_tokens_working_memory: Optional[int] = None,
76
+ tools: Optional[List[Any]] = None,
77
+ event_emitter: Any = None,
78
+ specific_expertise: str = "",
79
+ memory: AgentMemory | None = None
74
80
  ) -> Agent:
75
81
  """Create an agent based on the specified mode.
76
-
82
+
77
83
  Args:
78
84
  mode: The mode of operation for the agent
79
85
  model_name: The name of the language model to use
@@ -82,10 +88,14 @@ def create_agent_for_mode(
82
88
  no_stream: Whether to disable streaming mode
83
89
  compact_every_n_iteration: Optional number of iterations before compacting memory
84
90
  max_tokens_working_memory: Optional maximum tokens for working memory
91
+ tools: Optional list of tools to include in the agent
92
+ event_emitter: Optional event emitter to use in the agent
93
+ specific_expertise: Optional specific expertise for the agent
94
+ memory: Optional AgentMemory instance to use in the agent
85
95
 
86
96
  Returns:
87
97
  Agent: The created agent instance
88
-
98
+
89
99
  Raises:
90
100
  ValueError: If an unknown agent mode is specified
91
101
  """
@@ -104,18 +114,17 @@ def create_agent_for_mode(
104
114
  basic=False,
105
115
  no_stream=no_stream,
106
116
  compact_every_n_iteration=compact_every_n_iteration,
107
- max_tokens_working_memory=max_tokens_working_memory
117
+ max_tokens_working_memory=max_tokens_working_memory,
108
118
  )
109
119
  return agent
110
120
  if mode == "code-basic":
111
121
  agent = create_coding_agent(
112
122
  model_name,
113
123
  vision_model_name,
114
-
115
124
  basic=True,
116
125
  no_stream=no_stream,
117
126
  compact_every_n_iteration=compact_every_n_iteration,
118
- max_tokens_working_memory=max_tokens_working_memory
127
+ max_tokens_working_memory=max_tokens_working_memory,
119
128
  )
120
129
  return agent
121
130
  elif mode == "basic":
@@ -124,7 +133,7 @@ def create_agent_for_mode(
124
133
  vision_model_name,
125
134
  no_stream=no_stream,
126
135
  compact_every_n_iteration=compact_every_n_iteration,
127
- max_tokens_working_memory=max_tokens_working_memory
136
+ max_tokens_working_memory=max_tokens_working_memory,
128
137
  )
129
138
  return agent
130
139
  elif mode == "full":
@@ -133,7 +142,7 @@ def create_agent_for_mode(
133
142
  vision_model_name,
134
143
  no_stream=no_stream,
135
144
  compact_every_n_iteration=compact_every_n_iteration,
136
- max_tokens_working_memory=max_tokens_working_memory
145
+ max_tokens_working_memory=max_tokens_working_memory,
137
146
  )
138
147
  return agent
139
148
  elif mode == "interpreter":
@@ -142,7 +151,7 @@ def create_agent_for_mode(
142
151
  vision_model_name,
143
152
  no_stream=no_stream,
144
153
  compact_every_n_iteration=compact_every_n_iteration,
145
- max_tokens_working_memory=max_tokens_working_memory
154
+ max_tokens_working_memory=max_tokens_working_memory,
146
155
  )
147
156
  return agent
148
157
  elif mode == "search":
@@ -150,7 +159,7 @@ def create_agent_for_mode(
150
159
  model_name,
151
160
  no_stream=no_stream,
152
161
  compact_every_n_iteration=compact_every_n_iteration,
153
- max_tokens_working_memory=max_tokens_working_memory
162
+ max_tokens_working_memory=max_tokens_working_memory,
154
163
  )
155
164
  return agent
156
165
  if mode == "search-full":
@@ -159,16 +168,19 @@ def create_agent_for_mode(
159
168
  mode_full=True,
160
169
  no_stream=no_stream,
161
170
  compact_every_n_iteration=compact_every_n_iteration,
162
- max_tokens_working_memory=max_tokens_working_memory
171
+ max_tokens_working_memory=max_tokens_working_memory,
163
172
  )
164
173
  return agent
165
- if mode == "minimal":
166
- agent = create_minimal_agent(
174
+ if mode == "custom":
175
+ agent = create_custom_agent(
167
176
  model_name,
168
177
  vision_model_name,
169
178
  no_stream=no_stream,
170
179
  compact_every_n_iteration=compact_every_n_iteration,
171
- max_tokens_working_memory=max_tokens_working_memory
180
+ max_tokens_working_memory=max_tokens_working_memory,
181
+ specific_expertise=specific_expertise,
182
+ tools=tools,
183
+ memory=memory
172
184
  )
173
185
  return agent
174
186
  else:
@@ -15,9 +15,7 @@ from quantalogic.tools import (
15
15
  ReadHTMLTool,
16
16
  ReplaceInFileTool,
17
17
  RipgrepTool,
18
- SafePythonInterpreterTool,
19
18
  SearchDefinitionNames,
20
- SequenceTool,
21
19
  TaskCompleteTool,
22
20
  WriteFileTool,
23
21
  )
@@ -26,13 +24,13 @@ from quantalogic.utils.get_quantalogic_rules_content import get_quantalogic_rule
26
24
 
27
25
 
28
26
  def create_coding_agent(
29
- model_name: str,
30
- vision_model_name: str | None = None,
27
+ model_name: str,
28
+ vision_model_name: str | None = None,
31
29
  thinking_model_name: str | None = None,
32
- basic: bool = False,
33
- no_stream: bool = False,
30
+ basic: bool = False,
31
+ no_stream: bool = False,
34
32
  compact_every_n_iteration: int | None = None,
35
- max_tokens_working_memory: int | None = None
33
+ max_tokens_working_memory: int | None = None,
36
34
  ) -> Agent:
37
35
  """Creates and configures a coding agent with a comprehensive set of tools.
38
36
 
@@ -84,14 +82,20 @@ def create_coding_agent(
84
82
  GrepAppTool(),
85
83
  # SafePythonInterpreterTool(allowed_modules=["math", "numpy","decimal"])
86
84
  ]
87
-
88
-
89
- if vision_model_name:
90
- tools.append(LLMVisionTool(model_name=vision_model_name, on_token=console_print_token if not no_stream else None))
91
85
 
86
+ if vision_model_name:
87
+ tools.append(
88
+ LLMVisionTool(model_name=vision_model_name, on_token=console_print_token if not no_stream else None)
89
+ )
92
90
 
93
91
  if thinking_model_name:
94
- tools.append(LLMTool(model_name=thinking_model_name,name="smartest_code_expert", on_token=console_print_token if not no_stream else None))
92
+ tools.append(
93
+ LLMTool(
94
+ model_name=thinking_model_name,
95
+ name="smartest_code_expert",
96
+ on_token=console_print_token if not no_stream else None,
97
+ )
98
+ )
95
99
 
96
100
  if not basic:
97
101
  tools.append(
@@ -121,8 +125,6 @@ def create_coding_agent(
121
125
  on_token=console_print_token if not no_stream else None,
122
126
  )
123
127
  )
124
-
125
-
126
128
 
127
129
  return Agent(
128
130
  model_name=model_name,
quantalogic/config.py CHANGED
@@ -1,9 +1,11 @@
1
1
  from dataclasses import dataclass
2
2
  from typing import Optional
3
3
 
4
+
4
5
  @dataclass
5
6
  class QLConfig:
6
7
  """Central configuration for QuantaLogic agent parameters."""
8
+
7
9
  model_name: str
8
10
  verbose: bool
9
11
  mode: str
@@ -14,4 +16,3 @@ class QLConfig:
14
16
  max_tokens_working_memory: Optional[int]
15
17
  no_stream: bool
16
18
  thinking_model_name: str
17
-