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
@@ -24,54 +24,65 @@ class InputHistoryManager:
24
24
  return True
25
25
  return False
26
26
 
27
+
27
28
  class CommandRegistry:
28
29
  def __init__(self):
29
30
  self.commands = {}
30
-
31
+
31
32
  def register(self, name: str, help_text: str = "") -> callable:
32
33
  def decorator(func: callable) -> callable:
33
- self.commands[name] = {
34
- "handler": func,
35
- "help": func.__doc__ or help_text
36
- }
34
+ self.commands[name] = {"handler": func, "help": func.__doc__ or help_text}
37
35
  return func
36
+
38
37
  return decorator
39
38
 
39
+
40
40
  registry = CommandRegistry()
41
41
 
42
+
42
43
  @registry.register("/help", "Show available commands")
43
- def handle_help_command(lines: List[str], args: List[str], console: Console,
44
- session: PromptSession, history_manager: InputHistoryManager) -> None:
44
+ def handle_help_command(
45
+ lines: List[str], args: List[str], console: Console, session: PromptSession, history_manager: InputHistoryManager
46
+ ) -> None:
45
47
  """Display auto-generated help from registered commands."""
46
48
  help_content = "\n".join([f" {name}: {cmd['help']}" for name, cmd in registry.commands.items()])
47
49
  console.print(Panel(f"Available commands:\n{help_content}", title="Help Menu", border_style="green"))
48
50
 
51
+
49
52
  @registry.register("/date", "Show current date/time")
50
- def handle_date_command(lines: List[str], args: List[str], console: Console,
51
- session: PromptSession, history_manager: InputHistoryManager) -> None:
53
+ def handle_date_command(
54
+ lines: List[str], args: List[str], console: Console, session: PromptSession, history_manager: InputHistoryManager
55
+ ) -> None:
52
56
  """Display current date and time."""
53
57
  from datetime import datetime
58
+
54
59
  console.print(f"[bold #ffaa00]Current datetime: {datetime.now().isoformat()}[/bold #ffaa00]")
55
60
 
61
+
56
62
  @registry.register("/edit", "Edit specific line: /edit <line_number>")
57
- def handle_edit_command(lines: List[str], args: List[str], console: Console,
58
- session: PromptSession, history_manager: InputHistoryManager) -> None:
63
+ def handle_edit_command(
64
+ lines: List[str], args: List[str], console: Console, session: PromptSession, history_manager: InputHistoryManager
65
+ ) -> None:
59
66
  """Edit a specific line in the input buffer."""
60
67
  try:
61
68
  edit_line_num = int(args[0]) - 1
62
69
  if 0 <= edit_line_num < len(lines):
63
- console.print(f"[bold #1d3557]Editing Line {edit_line_num + 1}:[/bold #1d3557] {lines[edit_line_num]}") # Dark blue
70
+ console.print(
71
+ f"[bold #1d3557]Editing Line {edit_line_num + 1}:[/bold #1d3557] {lines[edit_line_num]}"
72
+ ) # Dark blue
64
73
  new_line = session.prompt("New content: ")
65
74
  history_manager.push_state(lines)
66
75
  lines[edit_line_num] = new_line
67
76
  else:
68
77
  console.print("[bold #ff4444]Invalid line number.[/bold #ff4444]")
69
78
  except (ValueError, IndexError):
70
- console.print("[bold #ff4444]Invalid edit command. Usage: /edit <line_number>[/bold #ff4444]")
79
+ console.print("[bold #ff4444]Invalid edit command. Usage: /edit <line_number>[/bold #ff4444]")
80
+
71
81
 
72
82
  @registry.register("/delete", "Delete specific line: /delete <line_number>")
73
- def handle_delete_command(lines: List[str], args: List[str], console: Console,
74
- session: PromptSession, history_manager: InputHistoryManager) -> None:
83
+ def handle_delete_command(
84
+ lines: List[str], args: List[str], console: Console, session: PromptSession, history_manager: InputHistoryManager
85
+ ) -> None:
75
86
  """Delete a specific line from the input buffer."""
76
87
  try:
77
88
  delete_line_num = int(args[0]) - 1
@@ -82,11 +93,13 @@ def handle_delete_command(lines: List[str], args: List[str], console: Console,
82
93
  else:
83
94
  console.print("[red]Invalid line number.[/red]")
84
95
  except (ValueError, IndexError):
85
- console.print("[bold #ff4444]Invalid delete command. Usage: /delete <line_number>[/bold #ff4444]")
96
+ console.print("[bold #ff4444]Invalid delete command. Usage: /delete <line_number>[/bold #ff4444]")
97
+
86
98
 
87
99
  @registry.register("/replace", "Search and replace: /replace <search> <replace>")
88
- def handle_replace_command(lines: List[str], args: List[str], console: Console,
89
- session: PromptSession, history_manager: InputHistoryManager) -> None:
100
+ def handle_replace_command(
101
+ lines: List[str], args: List[str], console: Console, session: PromptSession, history_manager: InputHistoryManager
102
+ ) -> None:
90
103
  try:
91
104
  search_str = args[0]
92
105
  replace_str = args[1]
@@ -95,12 +108,17 @@ def handle_replace_command(lines: List[str], args: List[str], console: Console,
95
108
  lines[i] = lines[i].replace(search_str, replace_str)
96
109
  console.print("[bold #00cc66]Search and replace completed.[/bold #00cc66]")
97
110
  except (ValueError, IndexError):
98
- console.print("[bold #ff4444]Invalid replace command. Usage: /replace <search_str> <replace_str>[/bold #ff4444]")
111
+ console.print(
112
+ "[bold #ff4444]Invalid replace command. Usage: /replace <search_str> <replace_str>[/bold #ff4444]"
113
+ )
114
+
99
115
 
100
- @registry.register("/model", "Show current AI model")
101
- def handle_model_command(lines: List[str], args: List[str], console: Console,
102
- session: PromptSession, history_manager: InputHistoryManager) -> None:
116
+ @registry.register("/model", "Show current AI model")
117
+ def handle_model_command(
118
+ lines: List[str], args: List[str], console: Console, session: PromptSession, history_manager: InputHistoryManager
119
+ ) -> None:
103
120
  from quantalogic.agent_factory import AgentRegistry
121
+
104
122
  try:
105
123
  current_agent = AgentRegistry.get_agent("main_agent")
106
124
  if current_agent:
@@ -108,17 +126,20 @@ def handle_model_command(lines: List[str], args: List[str], console: Console,
108
126
  else:
109
127
  console.print("[bold #ffaa00]No active agent found.[/bold #ffaa00]")
110
128
  except ValueError as e:
111
- console.print(f"[bold #ff4444]Error: {str(e)}[/bold #ff4444]")
129
+ console.print(f"[bold #ff4444]Error: {str(e)}[/bold #ff4444]")
130
+
112
131
 
113
132
  @registry.register("/setmodel", "Set AI model name: /setmodel <name>")
114
- def handle_set_model_command(lines: List[str], args: List[str], console: Console,
115
- session: PromptSession, history_manager: InputHistoryManager) -> None:
133
+ def handle_set_model_command(
134
+ lines: List[str], args: List[str], console: Console, session: PromptSession, history_manager: InputHistoryManager
135
+ ) -> None:
116
136
  from quantalogic.agent_factory import AgentRegistry
137
+
117
138
  try:
118
139
  if len(args) < 1:
119
140
  console.print("[bold #ff4444]Error: Model name required. Usage: /setmodel <name>[/bold #ff4444]")
120
141
  return
121
-
142
+
122
143
  model_name = args[0]
123
144
  current_agent = AgentRegistry.get_agent("main_agent")
124
145
  if current_agent:
@@ -129,29 +150,32 @@ def handle_set_model_command(lines: List[str], args: List[str], console: Console
129
150
  except ValueError as e:
130
151
  console.print(f"[red]Error: {str(e)}[/red]")
131
152
 
153
+
132
154
  @registry.register("/models", "List all available AI models")
133
- def handle_models_command(lines: List[str], args: List[str], console: Console,
134
- session: PromptSession, history_manager: InputHistoryManager) -> None:
155
+ def handle_models_command(
156
+ lines: List[str], args: List[str], console: Console, session: PromptSession, history_manager: InputHistoryManager
157
+ ) -> None:
135
158
  """Display all available AI models supported by the system."""
136
159
  from quantalogic.utils.get_all_models import get_all_models
160
+
137
161
  try:
138
162
  models = get_all_models()
139
163
  if models:
140
164
  # Group models by provider
141
165
  provider_groups = {}
142
166
  for model in models:
143
- provider = model.split('/')[0] if '/' in model else 'default'
167
+ provider = model.split("/")[0] if "/" in model else "default"
144
168
  if provider not in provider_groups:
145
169
  provider_groups[provider] = []
146
170
  provider_groups[provider].append(model)
147
-
171
+
148
172
  # Create formatted output
149
173
  output = "[bold #00cc66]Available AI Models:[/bold #00cc66]\n"
150
174
  for provider, model_list in provider_groups.items():
151
175
  output += f"\n[bold #ffaa00]{provider.upper()}[/bold #ffaa00]\n"
152
176
  for model in sorted(model_list):
153
177
  output += f" • {model}\n"
154
-
178
+
155
179
  console.print(Panel(output, border_style="green"))
156
180
  else:
157
181
  console.print("[yellow]No models available.[/yellow]")
@@ -163,8 +187,7 @@ def get_multiline_input(console: Console) -> str:
163
187
  """Get multiline input with slash command support."""
164
188
  console.print(
165
189
  Panel(
166
- "Enter your task. Press [bold]Enter[/bold] twice to submit.\n"
167
- "Type /help for available commands",
190
+ "Enter your task. Press [bold]Enter[/bold] twice to submit.\n" "Type /help for available commands",
168
191
  title="Multi-line Input",
169
192
  border_style="blue",
170
193
  )
@@ -182,16 +205,15 @@ def get_multiline_input(console: Console) -> str:
182
205
  if history_manager.undo(lines):
183
206
  console.print("[bold #00cc66]Undo successful.[/bold #00cc66]")
184
207
 
185
-
186
208
  from prompt_toolkit.completion import Completer, Completion
187
209
  from prompt_toolkit.styles import Style
188
-
210
+
189
211
  class CommandCompleter(Completer):
190
212
  def get_completions(self, document, complete_event):
191
213
  text = document.text_before_cursor
192
214
  line_parts = text.split()
193
-
194
- if len(line_parts) == 0 or (len(line_parts) == 1 and text.endswith(' ')):
215
+
216
+ if len(line_parts) == 0 or (len(line_parts) == 1 and text.endswith(" ")):
195
217
  for cmd, details in registry.commands.items():
196
218
  yield Completion(
197
219
  cmd,
@@ -203,9 +225,8 @@ def get_multiline_input(console: Console) -> str:
203
225
  cmd = registry.commands[line_parts[0]]
204
226
  arg_index = len(line_parts) - 1
205
227
  if arg_index == 1:
206
- doc = cmd['handler'].__doc__ or ""
207
- args_hint = next((line.split(':')[1].strip() for line in doc.split('\n')
208
- if 'Args:' in line), "")
228
+ doc = cmd["handler"].__doc__ or ""
229
+ args_hint = next((line.split(":")[1].strip() for line in doc.split("\n") if "Args:" in line), "")
209
230
  if args_hint:
210
231
  yield Completion(
211
232
  f"<{args_hint}>",
@@ -214,42 +235,43 @@ def get_multiline_input(console: Console) -> str:
214
235
  display=f"Expected argument: {args_hint}",
215
236
  )
216
237
  else:
217
- if text.startswith('/'):
218
- partial = text[1:].lstrip('/')
238
+ if text.startswith("/"):
239
+ partial = text[1:].lstrip("/")
219
240
  exact_matches = []
220
241
  prefix_matches = []
221
-
242
+
222
243
  for cmd in registry.commands:
223
244
  cmd_without_slash = cmd[1:]
224
245
  if cmd_without_slash.lower() == partial.lower():
225
246
  exact_matches.append(cmd)
226
247
  elif cmd_without_slash.lower().startswith(partial.lower()):
227
248
  prefix_matches.append(cmd)
228
-
249
+
229
250
  # Prioritize exact matches first
230
251
  for match in exact_matches:
231
- remaining = match[len('/' + partial):]
252
+ remaining = match[len("/" + partial) :]
232
253
  yield Completion(
233
254
  remaining,
234
255
  start_position=0, # Corrected from -len(partial)
235
256
  display=f"{match} - {registry.commands[match]['help']}",
236
257
  style="fg:ansiyellow bold",
237
258
  )
238
-
259
+
239
260
  # Then prefix matches
240
261
  for match in prefix_matches:
241
- remaining = match[len('/' + partial):]
262
+ remaining = match[len("/" + partial) :]
242
263
  yield Completion(
243
264
  remaining,
244
265
  start_position=0, # Corrected from -len(partial)
245
266
  display=f"{match} - {registry.commands[match]['help']}",
246
267
  style="fg:ansiyellow bold",
247
268
  )
269
+
248
270
  def get_completions(self, document, complete_event):
249
271
  text = document.text_before_cursor
250
272
  line_parts = text.split()
251
-
252
- if len(line_parts) == 0 or (len(line_parts) == 1 and text.endswith(' ')):
273
+
274
+ if len(line_parts) == 0 or (len(line_parts) == 1 and text.endswith(" ")):
253
275
  for cmd, details in registry.commands.items():
254
276
  yield Completion(
255
277
  cmd,
@@ -261,9 +283,10 @@ def get_multiline_input(console: Console) -> str:
261
283
  cmd = registry.commands[line_parts[0]]
262
284
  arg_index = len(line_parts) - 1
263
285
  if arg_index == 1:
264
- doc = cmd['handler'].__doc__ or ""
265
- args_hint = next((line.split(':')[1].strip() for line in doc.split('\n')
266
- if 'Args:' in line), "")
286
+ doc = cmd["handler"].__doc__ or ""
287
+ args_hint = next(
288
+ (line.split(":")[1].strip() for line in doc.split("\n") if "Args:" in line), ""
289
+ )
267
290
  if args_hint:
268
291
  yield Completion(
269
292
  f"<{args_hint}>",
@@ -272,29 +295,29 @@ def get_multiline_input(console: Console) -> str:
272
295
  display=f"Expected argument: {args_hint}",
273
296
  )
274
297
  else:
275
- if text.startswith('/'):
276
- partial = text[1:].lstrip('/')
298
+ if text.startswith("/"):
299
+ partial = text[1:].lstrip("/")
277
300
  exact_matches = []
278
301
  prefix_matches = []
279
-
302
+
280
303
  for cmd in registry.commands:
281
304
  cmd_without_slash = cmd[1:]
282
305
  if cmd_without_slash.lower() == partial.lower():
283
306
  exact_matches.append(cmd)
284
307
  elif cmd_without_slash.lower().startswith(partial.lower()):
285
308
  prefix_matches.append(cmd)
286
-
309
+
287
310
  for match in exact_matches:
288
- remaining = match[len('/' + partial):]
311
+ remaining = match[len("/" + partial) :]
289
312
  yield Completion(
290
313
  remaining,
291
314
  start_position=-len(partial),
292
315
  display=f"{match} - {registry.commands[match]['help']}",
293
316
  style="fg:ansiyellow bold",
294
317
  )
295
-
318
+
296
319
  for match in prefix_matches:
297
- remaining = match[len('/' + partial):]
320
+ remaining = match[len("/" + partial) :]
298
321
  yield Completion(
299
322
  remaining,
300
323
  start_position=-len(partial),
@@ -303,20 +326,22 @@ def get_multiline_input(console: Console) -> str:
303
326
  )
304
327
 
305
328
  command_completer = CommandCompleter()
306
-
329
+
307
330
  def get_command_help(cmd_name: str) -> str:
308
331
  """Get formatted help text for a command"""
309
332
  if cmd := registry.commands.get(cmd_name):
310
333
  return f"[bold]{cmd_name}[/bold]: {cmd['help']}\n{cmd['handler'].__doc__ or ''}"
311
334
  return ""
312
335
 
313
- custom_style = Style.from_dict({
314
- 'completion-menu.completion': 'bg:#005577 #ffffff',
315
- 'completion-menu.completion.current': 'bg:#007799 #ffffff bold',
316
- 'scrollbar.background': 'bg:#6699aa',
317
- 'scrollbar.button': 'bg:#444444',
318
- 'documentation': 'bg:#003366 #ffffff',
319
- })
336
+ custom_style = Style.from_dict(
337
+ {
338
+ "completion-menu.completion": "bg:#005577 #ffffff",
339
+ "completion-menu.completion.current": "bg:#007799 #ffffff bold",
340
+ "scrollbar.background": "bg:#6699aa",
341
+ "scrollbar.button": "bg:#444444",
342
+ "documentation": "bg:#003366 #ffffff",
343
+ }
344
+ )
320
345
 
321
346
  session = PromptSession(
322
347
  history=InMemoryHistory(),
@@ -325,9 +350,11 @@ def get_multiline_input(console: Console) -> str:
325
350
  completer=command_completer,
326
351
  complete_while_typing=True,
327
352
  style=custom_style,
328
- bottom_toolbar=lambda: get_command_help(session.default_buffer.document.text.split()[0][1:]
329
- if session.default_buffer.document.text.startswith('/')
330
- else ""),
353
+ bottom_toolbar=lambda: get_command_help(
354
+ session.default_buffer.document.text.split()[0][1:]
355
+ if session.default_buffer.document.text.startswith("/")
356
+ else ""
357
+ ),
331
358
  )
332
359
 
333
360
  try:
@@ -335,11 +362,11 @@ def get_multiline_input(console: Console) -> str:
335
362
  prompt_text = f"{line_number:>3}: "
336
363
  line = session.prompt(prompt_text, rprompt="Press Enter twice to submit")
337
364
 
338
- if line.strip().startswith('/'):
365
+ if line.strip().startswith("/"):
339
366
  cmd_parts = line.strip().split()
340
367
  cmd_name = cmd_parts[0].lower()
341
368
  args = cmd_parts[1:]
342
-
369
+
343
370
  if cmd_handler := registry.commands.get(cmd_name):
344
371
  try:
345
372
  cmd_handler["handler"](lines, args, console, session, history_manager)
@@ -365,4 +392,4 @@ def get_multiline_input(console: Console) -> str:
365
392
  console.print("\n[bold]Input cancelled by user.[/bold]")
366
393
  return ""
367
394
 
368
- return "\n".join(lines)
395
+ return "\n".join(lines)
quantalogic/main.py CHANGED
@@ -33,7 +33,7 @@ from quantalogic.utils.get_all_models import get_all_models # noqa: E402
33
33
 
34
34
  # Platform-specific imports
35
35
  try:
36
- if sys.platform == 'win32':
36
+ if sys.platform == "win32":
37
37
  import msvcrt # Built-in Windows module
38
38
  else:
39
39
  import termios
@@ -50,7 +50,7 @@ AGENT_MODES = ["code", "basic", "interpreter", "full", "code-basic", "search", "
50
50
 
51
51
  def setup_terminal():
52
52
  """Configure terminal settings based on platform."""
53
- if sys.platform == 'win32':
53
+ if sys.platform == "win32":
54
54
  if msvcrt:
55
55
  return None # Windows terminal is already configured
56
56
  logger.warning("msvcrt module not available on Windows")
@@ -70,7 +70,7 @@ def setup_terminal():
70
70
 
71
71
  def restore_terminal(old_settings):
72
72
  """Restore terminal settings based on platform."""
73
- if sys.platform != 'win32' and termios and old_settings:
73
+ if sys.platform != "win32" and termios and old_settings:
74
74
  try:
75
75
  termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, old_settings)
76
76
  except (termios.error, AttributeError) as e:
@@ -88,14 +88,14 @@ def restore_terminal(old_settings):
88
88
  @click.option(
89
89
  "--model-name",
90
90
  default=MODEL_NAME,
91
- help='Specify the model to use (litellm format). Examples:\n'
92
- ' - openai/gpt-4o-mini\n'
93
- ' - openai/gpt-4o\n'
94
- ' - anthropic/claude-3.5-sonnet\n'
95
- ' - deepseek/deepseek-chat\n'
96
- ' - deepseek/deepseek-reasoner\n'
97
- ' - openrouter/deepseek/deepseek-r1\n'
98
- ' - openrouter/openai/gpt-4o',
91
+ help="Specify the model to use (litellm format). Examples:\n"
92
+ " - openai/gpt-4o-mini\n"
93
+ " - openai/gpt-4o\n"
94
+ " - anthropic/claude-3.5-sonnet\n"
95
+ " - deepseek/deepseek-chat\n"
96
+ " - deepseek/deepseek-reasoner\n"
97
+ " - openrouter/deepseek/deepseek-r1\n"
98
+ " - openrouter/openai/gpt-4o",
99
99
  )
100
100
  @click.option(
101
101
  "--log",
@@ -281,29 +281,25 @@ def task(
281
281
  @click.option("--search", type=str, help="Fuzzy search for models containing the given string.")
282
282
  def list_models(search: Optional[str] = None):
283
283
  """List supported LiteLLM models with optional fuzzy search.
284
-
284
+
285
285
  If a search term is provided, it will return models that closely match the term.
286
286
  """
287
287
  console = Console()
288
288
  all_models = get_all_models()
289
-
289
+
290
290
  if search:
291
291
  # Perform fuzzy matching
292
292
  matched_models = process.extractBests(search, all_models, limit=None, score_cutoff=70)
293
293
  models = [model for model, score in matched_models]
294
294
  else:
295
295
  models = all_models
296
-
297
- console.print(Panel(
298
- f"Total Models: {len(models)} "
299
- f"({len(all_models)} total)",
300
- title="Supported LiteLLM Models"
301
- ))
302
-
296
+
297
+ console.print(Panel(f"Total Models: {len(models)} " f"({len(all_models)} total)", title="Supported LiteLLM Models"))
298
+
303
299
  if not models:
304
300
  console.print(f"[yellow]No models found matching '[bold]{search}[/bold]'[/yellow]")
305
301
  return
306
-
302
+
307
303
  for model in sorted(models):
308
304
  console.print(f"- {model}")
309
305
 
@@ -61,12 +61,12 @@ model_info = {
61
61
  model_name="gemini/gemini-2.0-flash",
62
62
  max_input_tokens=1000000,
63
63
  max_output_tokens=8 * 1024,
64
- input_cost_per_token=0.0000001
64
+ input_cost_per_token=0.0000001,
65
65
  ),
66
66
  "openrouter/google/gemini-2.0-flash-001": ModelInfo(
67
67
  model_name="openrouter/google/gemini-2.0-flash-001",
68
68
  max_input_tokens=1000000,
69
69
  max_output_tokens=8 * 1024,
70
- input_cost_per_token=0.0000001
71
- )
70
+ input_cost_per_token=0.0000001,
71
+ ),
72
72
  }
@@ -6,18 +6,18 @@ import litellm
6
6
  @functools.lru_cache(maxsize=32)
7
7
  def litellm_get_model_info(model_name: str) -> dict | None:
8
8
  """Get model information with prefix fallback logic using only litellm.
9
-
9
+
10
10
  Args:
11
11
  model_name: The model identifier to get information for
12
-
12
+
13
13
  Returns:
14
14
  Dictionary containing model information
15
-
15
+
16
16
  Raises:
17
17
  ValueError: If model info cannot be found after prefix fallbacks
18
18
  """
19
19
  tried_models = [model_name]
20
-
20
+
21
21
  while True:
22
22
  try:
23
23
  # Attempt to get model info through litellm
@@ -26,45 +26,45 @@ def litellm_get_model_info(model_name: str) -> dict | None:
26
26
  return info
27
27
  except Exception:
28
28
  pass
29
-
29
+
30
30
  # Try removing one prefix level
31
31
  parts = model_name.split("/")
32
32
  if len(parts) <= 1:
33
33
  break
34
-
34
+
35
35
  model_name = "/".join(parts[1:])
36
36
  tried_models.append(model_name)
37
37
 
38
- return None
38
+ return None
39
39
 
40
40
 
41
41
  def litellm_get_model_max_input_tokens(model_name: str) -> int | None:
42
42
  """Get maximum input tokens for a model using litellm.
43
-
43
+
44
44
  Args:
45
45
  model_name: The model identifier
46
-
46
+
47
47
  Returns:
48
48
  Maximum input tokens or None if not found
49
49
  """
50
50
  try:
51
51
  info = litellm_get_model_info(model_name)
52
52
  return info.get("max_input_tokens", 8192)
53
- except Exception as e:
53
+ except Exception:
54
54
  return 8192 # Default for many modern models
55
55
 
56
56
 
57
57
  def litellm_get_model_max_output_tokens(model_name: str) -> int | None:
58
58
  """Get maximum output tokens for a model using litellm.
59
-
59
+
60
60
  Args:
61
61
  model_name: The model identifier
62
-
62
+
63
63
  Returns:
64
64
  Maximum output tokens or None if not found
65
65
  """
66
66
  try:
67
67
  info = litellm_get_model_info(model_name)
68
68
  return info.get("max_output_tokens", 4096)
69
- except Exception as e:
70
- return 4096 # Conservative default
69
+ except Exception:
70
+ return 4096 # Conservative default
quantalogic/prompts.py CHANGED
@@ -93,5 +93,6 @@ Task Format: <task>task_description</task>
93
93
  5. 🔍 Monitor and validate each action's impact
94
94
  6. 🛑 Fail fast and adapt when encountering blockers
95
95
  7. ✅ Verify completion criteria rigorously
96
- """
96
+ 8. ✅ Return complete, full and usable results.
97
97
 
98
+ """