quantalogic 0.33.4__py3-none-any.whl → 0.40.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 -362
  3. quantalogic/agent_config.py +260 -28
  4. quantalogic/agent_factory.py +43 -17
  5. quantalogic/coding_agent.py +20 -12
  6. quantalogic/config.py +7 -4
  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 +6 -6
  20. quantalogic/interactive_text_editor.py +100 -73
  21. quantalogic/main.py +36 -23
  22. quantalogic/model_info_list.py +12 -0
  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 +21 -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.33.4.dist-info → quantalogic-0.40.0.dist-info}/METADATA +44 -1
  103. quantalogic-0.40.0.dist-info/RECORD +148 -0
  104. quantalogic-0.33.4.dist-info/RECORD +0 -102
  105. {quantalogic-0.33.4.dist-info → quantalogic-0.40.0.dist-info}/LICENSE +0 -0
  106. {quantalogic-0.33.4.dist-info → quantalogic-0.40.0.dist-info}/WHEEL +0 -0
  107. {quantalogic-0.33.4.dist-info → quantalogic-0.40.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,
@@ -251,3 +287,199 @@ def create_basic_agent(
251
287
  compact_every_n_iterations=compact_every_n_iteration,
252
288
  max_tokens_working_memory=max_tokens_working_memory,
253
289
  )
290
+
291
+
292
+ def create_custom_agent(
293
+ model_name: str,
294
+ vision_model_name: str | None = None,
295
+ no_stream: bool = False,
296
+ compact_every_n_iteration: 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
301
+ ) -> Agent:
302
+ """Create an agent with the specified model and tools.
303
+
304
+ Args:
305
+ model_name (str): Name of the model to use
306
+ vision_model_name (str | None): Name of the vision model to use
307
+ no_stream (bool, optional): If True, the agent will not stream results.
308
+ compact_every_n_iteration (int | None, optional): Frequency of memory compaction.
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.
316
+
317
+ Returns:
318
+ Agent: An agent with the specified model and tools
319
+ """
320
+ storage_dir = os.path.join(os.path.dirname(__file__), "storage", "rag")
321
+ os.makedirs(storage_dir, exist_ok=True)
322
+
323
+ # Rebuild AgentTool to resolve forward references
324
+ AgentTool.model_rebuild()
325
+
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
+ )
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
+
477
+ return Agent(
478
+ model_name=model_name,
479
+ tools=agent_tools,
480
+ event_emitter=event_emitter,
481
+ compact_every_n_iterations=compact_every_n_iteration,
482
+ max_tokens_working_memory=max_tokens_working_memory,
483
+ specific_expertise=specific_expertise,
484
+ memory=memory,
485
+ )
@@ -1,20 +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
11
  )
11
12
  from quantalogic.coding_agent import create_coding_agent
13
+ from quantalogic.memory import AgentMemory
12
14
  from quantalogic.search_agent import create_search_agent # noqa: E402
13
15
 
14
16
 
15
17
  class AgentRegistry:
16
18
  """Registry for managing agent instances by name."""
17
-
19
+
18
20
  _instance = None
19
21
  _agents: Dict[str, Agent] = {}
20
22
 
@@ -26,7 +28,7 @@ class AgentRegistry:
26
28
  @classmethod
27
29
  def register_agent(cls, name: str, agent: Agent) -> None:
28
30
  """Register an agent instance with a name.
29
-
31
+
30
32
  Args:
31
33
  name: Unique name for the agent
32
34
  agent: Agent instance to register
@@ -38,13 +40,13 @@ class AgentRegistry:
38
40
  @classmethod
39
41
  def get_agent(cls, name: str) -> Agent:
40
42
  """Retrieve a registered agent by name.
41
-
43
+
42
44
  Args:
43
45
  name: Name of the agent to retrieve
44
-
46
+
45
47
  Returns:
46
48
  Registered Agent instance
47
-
49
+
48
50
  Raises:
49
51
  KeyError: If no agent with that name exists
50
52
  """
@@ -53,12 +55,13 @@ class AgentRegistry:
53
55
  @classmethod
54
56
  def list_agents(cls) -> Dict[str, str]:
55
57
  """List all registered agents.
56
-
58
+
57
59
  Returns:
58
60
  Dictionary mapping agent names to their types
59
61
  """
60
62
  return {name: type(agent).__name__ for name, agent in cls._agents.items()}
61
63
 
64
+
62
65
  """Agent factory module for creating different types of agents."""
63
66
 
64
67
 
@@ -66,23 +69,33 @@ def create_agent_for_mode(
66
69
  mode: str,
67
70
  model_name: str,
68
71
  vision_model_name: Optional[str],
72
+ thinking_model_name: Optional[str],
69
73
  no_stream: bool = False,
70
74
  compact_every_n_iteration: Optional[int] = None,
71
- 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
72
80
  ) -> Agent:
73
81
  """Create an agent based on the specified mode.
74
-
82
+
75
83
  Args:
76
84
  mode: The mode of operation for the agent
77
85
  model_name: The name of the language model to use
78
86
  vision_model_name: Optional name of the vision model
87
+ thinking_model_name: Optional name for a thinking model
79
88
  no_stream: Whether to disable streaming mode
80
89
  compact_every_n_iteration: Optional number of iterations before compacting memory
81
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
82
95
 
83
96
  Returns:
84
97
  Agent: The created agent instance
85
-
98
+
86
99
  Raises:
87
100
  ValueError: If an unknown agent mode is specified
88
101
  """
@@ -97,10 +110,11 @@ def create_agent_for_mode(
97
110
  agent = create_coding_agent(
98
111
  model_name,
99
112
  vision_model_name,
113
+ thinking_model_name,
100
114
  basic=False,
101
115
  no_stream=no_stream,
102
116
  compact_every_n_iteration=compact_every_n_iteration,
103
- max_tokens_working_memory=max_tokens_working_memory
117
+ max_tokens_working_memory=max_tokens_working_memory,
104
118
  )
105
119
  return agent
106
120
  if mode == "code-basic":
@@ -110,7 +124,7 @@ def create_agent_for_mode(
110
124
  basic=True,
111
125
  no_stream=no_stream,
112
126
  compact_every_n_iteration=compact_every_n_iteration,
113
- max_tokens_working_memory=max_tokens_working_memory
127
+ max_tokens_working_memory=max_tokens_working_memory,
114
128
  )
115
129
  return agent
116
130
  elif mode == "basic":
@@ -119,7 +133,7 @@ def create_agent_for_mode(
119
133
  vision_model_name,
120
134
  no_stream=no_stream,
121
135
  compact_every_n_iteration=compact_every_n_iteration,
122
- max_tokens_working_memory=max_tokens_working_memory
136
+ max_tokens_working_memory=max_tokens_working_memory,
123
137
  )
124
138
  return agent
125
139
  elif mode == "full":
@@ -128,7 +142,7 @@ def create_agent_for_mode(
128
142
  vision_model_name,
129
143
  no_stream=no_stream,
130
144
  compact_every_n_iteration=compact_every_n_iteration,
131
- max_tokens_working_memory=max_tokens_working_memory
145
+ max_tokens_working_memory=max_tokens_working_memory,
132
146
  )
133
147
  return agent
134
148
  elif mode == "interpreter":
@@ -137,7 +151,7 @@ def create_agent_for_mode(
137
151
  vision_model_name,
138
152
  no_stream=no_stream,
139
153
  compact_every_n_iteration=compact_every_n_iteration,
140
- max_tokens_working_memory=max_tokens_working_memory
154
+ max_tokens_working_memory=max_tokens_working_memory,
141
155
  )
142
156
  return agent
143
157
  elif mode == "search":
@@ -145,7 +159,7 @@ def create_agent_for_mode(
145
159
  model_name,
146
160
  no_stream=no_stream,
147
161
  compact_every_n_iteration=compact_every_n_iteration,
148
- max_tokens_working_memory=max_tokens_working_memory
162
+ max_tokens_working_memory=max_tokens_working_memory,
149
163
  )
150
164
  return agent
151
165
  if mode == "search-full":
@@ -154,7 +168,19 @@ def create_agent_for_mode(
154
168
  mode_full=True,
155
169
  no_stream=no_stream,
156
170
  compact_every_n_iteration=compact_every_n_iteration,
157
- max_tokens_working_memory=max_tokens_working_memory
171
+ max_tokens_working_memory=max_tokens_working_memory,
172
+ )
173
+ return agent
174
+ if mode == "custom":
175
+ agent = create_custom_agent(
176
+ model_name,
177
+ vision_model_name,
178
+ no_stream=no_stream,
179
+ compact_every_n_iteration=compact_every_n_iteration,
180
+ max_tokens_working_memory=max_tokens_working_memory,
181
+ specific_expertise=specific_expertise,
182
+ tools=tools,
183
+ memory=memory
158
184
  )
159
185
  return agent
160
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,18 +24,20 @@ 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,
31
- basic: bool = False,
32
- no_stream: bool = False,
27
+ model_name: str,
28
+ vision_model_name: str | None = None,
29
+ thinking_model_name: str | None = None,
30
+ basic: bool = False,
31
+ no_stream: bool = False,
33
32
  compact_every_n_iteration: int | None = None,
34
- max_tokens_working_memory: int | None = None
33
+ max_tokens_working_memory: int | None = None,
35
34
  ) -> Agent:
36
35
  """Creates and configures a coding agent with a comprehensive set of tools.
37
36
 
38
37
  Args:
39
38
  model_name (str): Name of the language model to use for the agent's core capabilities
40
39
  vision_model_name (str | None): Name of the vision model to use for the agent's core capabilities
40
+ thinking_model_name (str | None): Name of the thinking model to use for the agent's core capabilities
41
41
  basic (bool, optional): If True, the agent will be configured with a basic set of tools.
42
42
  no_stream (bool, optional): If True, the agent will not stream results.
43
43
  compact_every_n_iteration (int | None, optional): Frequency of memory compaction.
@@ -82,10 +82,20 @@ def create_coding_agent(
82
82
  GrepAppTool(),
83
83
  # SafePythonInterpreterTool(allowed_modules=["math", "numpy","decimal"])
84
84
  ]
85
-
86
-
85
+
87
86
  if vision_model_name:
88
- tools.append(LLMVisionTool(model_name=vision_model_name, on_token=console_print_token if not no_stream else None))
87
+ tools.append(
88
+ LLMVisionTool(model_name=vision_model_name, on_token=console_print_token if not no_stream else None)
89
+ )
90
+
91
+ if thinking_model_name:
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
+ )
89
99
 
90
100
  if not basic:
91
101
  tools.append(
@@ -115,8 +125,6 @@ def create_coding_agent(
115
125
  on_token=console_print_token if not no_stream else None,
116
126
  )
117
127
  )
118
-
119
-
120
128
 
121
129
  return Agent(
122
130
  model_name=model_name,
quantalogic/config.py CHANGED
@@ -1,15 +1,18 @@
1
1
  from dataclasses import dataclass
2
+ from typing import Optional
2
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
10
12
  log: str
11
- vision_model_name: str | None
13
+ vision_model_name: Optional[str]
12
14
  max_iterations: int
13
- compact_every_n_iteration: int | None
14
- max_tokens_working_memory: int | None
15
- no_stream: bool
15
+ compact_every_n_iteration: Optional[int]
16
+ max_tokens_working_memory: Optional[int]
17
+ no_stream: bool
18
+ thinking_model_name: str