praisonAI 2.3.76__tar.gz → 2.3.77__tar.gz

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 (123) hide show
  1. {praisonai-2.3.76 → praisonai-2.3.77}/PKG-INFO +1 -1
  2. {praisonai-2.3.76 → praisonai-2.3.77}/PraisonAI.egg-info/PKG-INFO +1 -1
  3. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/at_mentions.py +69 -14
  4. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/eval.py +55 -17
  5. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/fast_context.py +13 -5
  6. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/guardrail.py +7 -1
  7. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/main.py +27 -27
  8. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/deploy.py +1 -1
  9. praisonai-2.3.77/praisonai/version.py +1 -0
  10. praisonai-2.3.76/praisonai/version.py +0 -1
  11. {praisonai-2.3.76 → praisonai-2.3.77}/PraisonAI.egg-info/SOURCES.txt +0 -0
  12. {praisonai-2.3.76 → praisonai-2.3.77}/PraisonAI.egg-info/dependency_links.txt +0 -0
  13. {praisonai-2.3.76 → praisonai-2.3.77}/PraisonAI.egg-info/entry_points.txt +0 -0
  14. {praisonai-2.3.76 → praisonai-2.3.77}/PraisonAI.egg-info/requires.txt +0 -0
  15. {praisonai-2.3.76 → praisonai-2.3.77}/PraisonAI.egg-info/top_level.txt +0 -0
  16. {praisonai-2.3.76 → praisonai-2.3.77}/README.md +0 -0
  17. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/__init__.py +0 -0
  18. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/__main__.py +0 -0
  19. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/agent_scheduler.py +0 -0
  20. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/agents_generator.py +0 -0
  21. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/api/call.py +0 -0
  22. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/auto.py +0 -0
  23. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/chainlit_ui.py +0 -0
  24. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/__init__.py +0 -0
  25. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/__init__.py +0 -0
  26. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/agent_scheduler.py +0 -0
  27. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/auto_memory.py +0 -0
  28. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/autonomy_mode.py +0 -0
  29. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/base.py +0 -0
  30. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/compare.py +0 -0
  31. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/cost_tracker.py +0 -0
  32. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/external_agents.py +0 -0
  33. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/flow_display.py +0 -0
  34. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/git_integration.py +0 -0
  35. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/handoff.py +0 -0
  36. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/image.py +0 -0
  37. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/interactive_tui.py +0 -0
  38. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/knowledge.py +0 -0
  39. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/mcp.py +0 -0
  40. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/message_queue.py +0 -0
  41. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/metrics.py +0 -0
  42. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/n8n.py +0 -0
  43. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/profiling.py +0 -0
  44. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/repo_map.py +0 -0
  45. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/router.py +0 -0
  46. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/sandbox_executor.py +0 -0
  47. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/session.py +0 -0
  48. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/skills.py +0 -0
  49. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/slash_commands.py +0 -0
  50. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/telemetry.py +0 -0
  51. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/todo.py +0 -0
  52. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/tools.py +0 -0
  53. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/features/workflow.py +0 -0
  54. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/cli/schedule_cli.py +0 -0
  55. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/code/__init__.py +0 -0
  56. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/code/agent_tools.py +0 -0
  57. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/code/diff/__init__.py +0 -0
  58. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/code/diff/diff_strategy.py +0 -0
  59. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/code/tools/__init__.py +0 -0
  60. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/code/tools/apply_diff.py +0 -0
  61. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/code/tools/execute_command.py +0 -0
  62. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/code/tools/list_files.py +0 -0
  63. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/code/tools/read_file.py +0 -0
  64. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/code/tools/search_replace.py +0 -0
  65. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/code/tools/write_file.py +0 -0
  66. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/code/utils/__init__.py +0 -0
  67. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/code/utils/file_utils.py +0 -0
  68. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/code/utils/ignore_utils.py +0 -0
  69. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/code/utils/text_utils.py +0 -0
  70. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/inbuilt_tools/__init__.py +0 -0
  71. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/inbuilt_tools/autogen_tools.py +0 -0
  72. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/inc/__init__.py +0 -0
  73. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/inc/config.py +0 -0
  74. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/inc/models.py +0 -0
  75. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/integrations/__init__.py +0 -0
  76. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/integrations/base.py +0 -0
  77. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/integrations/claude_code.py +0 -0
  78. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/integrations/codex_cli.py +0 -0
  79. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/integrations/cursor_cli.py +0 -0
  80. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/integrations/gemini_cli.py +0 -0
  81. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/profiler.py +0 -0
  82. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/scheduler/__init__.py +0 -0
  83. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/scheduler/agent_scheduler.py +0 -0
  84. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/scheduler/base.py +0 -0
  85. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/scheduler/daemon_manager.py +0 -0
  86. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/scheduler/state_manager.py +0 -0
  87. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/scheduler/yaml_loader.py +0 -0
  88. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/scheduler.py +0 -0
  89. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/setup/__init__.py +0 -0
  90. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/setup/build.py +0 -0
  91. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/setup/post_install.py +0 -0
  92. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/setup/setup_conda_env.py +0 -0
  93. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/setup.py +0 -0
  94. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/test.py +0 -0
  95. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/train.py +0 -0
  96. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/train_vision.py +0 -0
  97. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/ui/agents.py +0 -0
  98. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/ui/callbacks.py +0 -0
  99. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/ui/chat.py +0 -0
  100. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/ui/code.py +0 -0
  101. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/ui/colab.py +0 -0
  102. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/ui/colab_chainlit.py +0 -0
  103. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/ui/components/aicoder.py +0 -0
  104. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/ui/context.py +0 -0
  105. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/ui/database_config.py +0 -0
  106. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/ui/db.py +0 -0
  107. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/ui/realtime.py +0 -0
  108. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/ui/realtimeclient/__init__.py +0 -0
  109. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/ui/realtimeclient/tools.py +0 -0
  110. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/ui/sql_alchemy.py +0 -0
  111. {praisonai-2.3.76 → praisonai-2.3.77}/praisonai/upload_vision.py +0 -0
  112. {praisonai-2.3.76 → praisonai-2.3.77}/pyproject.toml +0 -0
  113. {praisonai-2.3.76 → praisonai-2.3.77}/setup.cfg +0 -0
  114. {praisonai-2.3.76 → praisonai-2.3.77}/tests/test.py +0 -0
  115. {praisonai-2.3.76 → praisonai-2.3.77}/tests/test_agents_playbook.py +0 -0
  116. {praisonai-2.3.76 → praisonai-2.3.77}/tests/test_approval_system.py +0 -0
  117. {praisonai-2.3.76 → praisonai-2.3.77}/tests/test_basic.py +0 -0
  118. {praisonai-2.3.76 → praisonai-2.3.77}/tests/test_cli_features.py +0 -0
  119. {praisonai-2.3.76 → praisonai-2.3.77}/tests/test_custom_tools_fix.py +0 -0
  120. {praisonai-2.3.76 → praisonai-2.3.77}/tests/test_double_api_fix.py +0 -0
  121. {praisonai-2.3.76 → praisonai-2.3.77}/tests/test_n8n_integration.py +0 -0
  122. {praisonai-2.3.76 → praisonai-2.3.77}/tests/test_phase2_refactor.py +0 -0
  123. {praisonai-2.3.76 → praisonai-2.3.77}/tests/test_runner.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PraisonAI
3
- Version: 2.3.76
3
+ Version: 2.3.77
4
4
  Summary: PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human-agent collaboration.
5
5
  Author: Mervin Praison
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PraisonAI
3
- Version: 2.3.76
3
+ Version: 2.3.77
4
4
  Summary: PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human-agent collaboration.
5
5
  Author: Mervin Praison
6
6
  License: MIT
@@ -105,6 +105,7 @@ class FileSearchService:
105
105
  - Fuzzy match file paths
106
106
  - Cache results with TTL
107
107
  - Respect .gitignore (basic)
108
+ - Support absolute paths (@/Users/...) and home paths (@~/...)
108
109
  """
109
110
 
110
111
  def __init__(
@@ -125,9 +126,10 @@ class FileSearchService:
125
126
  # Cache: query -> (results, timestamp)
126
127
  self._cache: Dict[str, Tuple[List[FileSuggestion], float]] = {}
127
128
 
128
- # File list cache
129
+ # File list cache per directory
129
130
  self._file_list: Optional[List[str]] = None
130
131
  self._file_list_time: float = 0
132
+ self._file_list_dir: Optional[str] = None
131
133
 
132
134
  def _should_ignore(self, name: str) -> bool:
133
135
  """Check if file/dir should be ignored."""
@@ -136,20 +138,23 @@ class FileSearchService:
136
138
  return True
137
139
  return False
138
140
 
139
- def _get_file_list(self) -> List[str]:
141
+ def _get_file_list(self, search_dir: str = None) -> List[str]:
140
142
  """Get list of all files (cached)."""
141
143
  now = time.time()
144
+ target_dir = search_dir or self._root
142
145
 
143
- # Return cached if fresh
144
- if self._file_list is not None and (now - self._file_list_time) < self._cache_ttl:
146
+ # Return cached if fresh and same directory
147
+ if (self._file_list is not None and
148
+ self._file_list_dir == target_dir and
149
+ (now - self._file_list_time) < self._cache_ttl):
145
150
  return self._file_list
146
151
 
147
152
  files = []
148
153
 
149
154
  try:
150
- for root, dirs, filenames in os.walk(self._root):
155
+ for root, dirs, filenames in os.walk(target_dir):
151
156
  # Calculate depth
152
- rel_root = os.path.relpath(root, self._root)
157
+ rel_root = os.path.relpath(root, target_dir)
153
158
  depth = 0 if rel_root == '.' else rel_root.count(os.sep) + 1
154
159
 
155
160
  if depth > self._max_depth:
@@ -161,19 +166,20 @@ class FileSearchService:
161
166
 
162
167
  # Add directories
163
168
  for d in dirs:
164
- rel_path = os.path.relpath(os.path.join(root, d), self._root)
169
+ rel_path = os.path.relpath(os.path.join(root, d), target_dir)
165
170
  files.append(rel_path + os.sep)
166
171
 
167
172
  # Add files
168
173
  for f in filenames:
169
174
  if not self._should_ignore(f):
170
- rel_path = os.path.relpath(os.path.join(root, f), self._root)
175
+ rel_path = os.path.relpath(os.path.join(root, f), target_dir)
171
176
  files.append(rel_path)
172
177
  except OSError:
173
178
  pass
174
179
 
175
180
  self._file_list = files
176
181
  self._file_list_time = now
182
+ self._file_list_dir = target_dir
177
183
  return files
178
184
 
179
185
  def _fuzzy_match(self, text: str, query: str) -> int:
@@ -221,6 +227,11 @@ class FileSearchService:
221
227
  """
222
228
  Search for files matching query.
223
229
 
230
+ Supports:
231
+ - Relative paths: @file.txt, @src/main.py
232
+ - Home paths: @~/Documents, @~/.config
233
+ - Absolute paths: @/Users/name/file.txt, @/etc/hosts
234
+
224
235
  Args:
225
236
  query: Search query (fuzzy matched)
226
237
  max_results: Maximum results to return
@@ -228,8 +239,51 @@ class FileSearchService:
228
239
  Returns:
229
240
  List of FileSuggestion sorted by score
230
241
  """
242
+ # Determine search directory based on query
243
+ search_dir = self._root
244
+ search_query = query
245
+ prefix = ""
246
+
247
+ # Handle home directory paths (@~/)
248
+ if query.startswith('~'):
249
+ expanded = os.path.expanduser(query)
250
+ # Find the directory part and filename part
251
+ if os.path.isdir(expanded):
252
+ search_dir = expanded
253
+ search_query = ""
254
+ prefix = query.rstrip('/') + '/'
255
+ else:
256
+ parent = os.path.dirname(expanded)
257
+ if os.path.isdir(parent):
258
+ search_dir = parent
259
+ search_query = os.path.basename(expanded)
260
+ prefix = os.path.dirname(query).rstrip('/') + '/'
261
+ else:
262
+ # Just expand ~ and search from home
263
+ search_dir = os.path.expanduser('~')
264
+ search_query = query[2:] if query.startswith('~/') else query[1:]
265
+ prefix = "~/"
266
+
267
+ # Handle absolute paths (@/Users/..., @/etc/...)
268
+ elif query.startswith('/'):
269
+ if os.path.isdir(query):
270
+ search_dir = query
271
+ search_query = ""
272
+ prefix = query.rstrip('/') + '/'
273
+ else:
274
+ parent = os.path.dirname(query)
275
+ if os.path.isdir(parent):
276
+ search_dir = parent
277
+ search_query = os.path.basename(query)
278
+ prefix = parent.rstrip('/') + '/'
279
+ else:
280
+ # Search from root with the query
281
+ search_dir = '/'
282
+ search_query = query[1:]
283
+ prefix = "/"
284
+
231
285
  # Check cache
232
- cache_key = f"{query}:{max_results}"
286
+ cache_key = f"{search_dir}:{search_query}:{max_results}"
233
287
  now = time.time()
234
288
 
235
289
  if cache_key in self._cache:
@@ -237,25 +291,26 @@ class FileSearchService:
237
291
  if (now - cached_time) < self._cache_ttl:
238
292
  return results
239
293
 
240
- # Get all files
241
- all_files = self._get_file_list()
294
+ # Get all files from the appropriate directory
295
+ all_files = self._get_file_list(search_dir)
242
296
 
243
297
  # Score and filter
244
298
  scored: List[Tuple[int, str]] = []
245
299
  for path in all_files:
246
- score = self._fuzzy_match(path, query)
300
+ score = self._fuzzy_match(path, search_query)
247
301
  if score > 0:
248
302
  scored.append((score, path))
249
303
 
250
304
  # Sort by score descending
251
305
  scored.sort(key=lambda x: (-x[0], x[1]))
252
306
 
253
- # Build results
307
+ # Build results with proper prefix
254
308
  results = []
255
309
  for score, path in scored[:max_results]:
256
310
  file_type = "directory" if path.endswith(os.sep) else "file"
311
+ display_path = prefix + path if prefix else path
257
312
  results.append(FileSuggestion(
258
- path=path,
313
+ path=display_path,
259
314
  file_type=file_type,
260
315
  score=score
261
316
  ))
@@ -26,42 +26,68 @@ class EvalHandler:
26
26
 
27
27
  def run_accuracy(
28
28
  self,
29
- agent_file: str,
30
- input_text: str,
31
- expected_output: str,
29
+ agent_file: Optional[str] = None,
30
+ input_text: str = "",
31
+ expected_output: str = "",
32
32
  iterations: int = 1,
33
33
  model: Optional[str] = None,
34
- output_file: Optional[str] = None
34
+ output_file: Optional[str] = None,
35
+ prompt: Optional[str] = None,
36
+ llm: Optional[str] = None
35
37
  ) -> Dict[str, Any]:
36
38
  """
37
39
  Run accuracy evaluation on an agent.
38
40
 
39
41
  Args:
40
- agent_file: Path to agents.yaml file
42
+ agent_file: Path to agents.yaml file (optional if prompt is provided)
41
43
  input_text: Input to provide to the agent
42
44
  expected_output: Expected output to compare against
43
45
  iterations: Number of evaluation iterations
44
46
  model: LLM model for judging
45
47
  output_file: Path to save results
48
+ prompt: Direct prompt (alternative to agent_file)
49
+ llm: LLM model for the agent (when using prompt)
46
50
 
47
51
  Returns:
48
52
  Evaluation result dictionary
49
53
  """
50
54
  try:
51
55
  from praisonaiagents.eval import AccuracyEvaluator
52
- from praisonai.agents_generator import AgentsGenerator
56
+ from praisonaiagents import Agent
53
57
  except ImportError as e:
54
58
  logger.error(f"Failed to import evaluation modules: {e}")
55
59
  return {"error": str(e)}
56
60
 
57
61
  try:
58
- generator = AgentsGenerator(agent_file)
59
- agents = generator.generate_agents()
60
-
61
- if not agents:
62
- return {"error": "No agents found in configuration"}
63
-
64
- agent = agents[0] if isinstance(agents, list) else agents
62
+ # Create agent either from file or from prompt
63
+ if prompt:
64
+ # Direct prompt mode - create agent on the fly
65
+ agent = Agent(
66
+ name="EvalAgent",
67
+ role="Assistant",
68
+ goal="Complete the given task",
69
+ backstory="You are a helpful assistant.",
70
+ llm=llm or model or "gpt-4o-mini",
71
+ verbose=False
72
+ )
73
+ # Use prompt as input if input_text not provided
74
+ if not input_text:
75
+ input_text = prompt
76
+ elif agent_file:
77
+ # Load from agents.yaml
78
+ try:
79
+ from praisonai.agents_generator import AgentsGenerator
80
+ generator = AgentsGenerator(agent_file)
81
+ agents = generator.generate_agents()
82
+
83
+ if not agents:
84
+ return {"error": "No agents found in configuration"}
85
+
86
+ agent = agents[0] if isinstance(agents, list) else agents
87
+ except Exception as e:
88
+ return {"error": f"Failed to load agents from {agent_file}: {e}"}
89
+ else:
90
+ return {"error": "Either --agent or --prompt must be provided"}
65
91
 
66
92
  evaluator = AccuracyEvaluator(
67
93
  agent=agent,
@@ -331,8 +357,16 @@ def handle_eval_command(args) -> None:
331
357
  handler = EvalHandler(verbose=getattr(args, 'verbose', False))
332
358
 
333
359
  eval_type = getattr(args, 'eval_type', 'accuracy')
334
- agent_file = getattr(args, 'agent', 'agents.yaml')
360
+ agent_file = getattr(args, 'agent', None)
335
361
  output_file = getattr(args, 'output', None)
362
+ prompt = getattr(args, 'prompt', None)
363
+ llm = getattr(args, 'llm', None)
364
+
365
+ # If no agent file and no prompt, check if agents.yaml exists
366
+ if not agent_file and not prompt:
367
+ import os
368
+ if os.path.exists('agents.yaml'):
369
+ agent_file = 'agents.yaml'
336
370
 
337
371
  if eval_type == 'accuracy':
338
372
  result = handler.run_accuracy(
@@ -341,7 +375,9 @@ def handle_eval_command(args) -> None:
341
375
  expected_output=getattr(args, 'expected', ''),
342
376
  iterations=getattr(args, 'iterations', 1),
343
377
  model=getattr(args, 'model', None),
344
- output_file=output_file
378
+ output_file=output_file,
379
+ prompt=prompt,
380
+ llm=llm
345
381
  )
346
382
  elif eval_type == 'performance':
347
383
  result = handler.run_performance(
@@ -410,8 +446,10 @@ def add_eval_parser(subparsers) -> None:
410
446
  'accuracy',
411
447
  help='Run accuracy evaluation'
412
448
  )
413
- accuracy_parser.add_argument('--agent', '-a', default='agents.yaml', help='Agent config file')
414
- accuracy_parser.add_argument('--input', '-i', required=True, help='Input text')
449
+ accuracy_parser.add_argument('--agent', '-a', help='Agent config file (optional if --prompt used)')
450
+ accuracy_parser.add_argument('--prompt', '-p', help='Direct prompt (alternative to --agent)')
451
+ accuracy_parser.add_argument('--llm', help='LLM model for agent (when using --prompt)')
452
+ accuracy_parser.add_argument('--input', '-i', help='Input text (defaults to --prompt if not provided)')
415
453
  accuracy_parser.add_argument('--expected', '-e', required=True, help='Expected output')
416
454
  accuracy_parser.add_argument('--iterations', '-n', type=int, default=1, help='Number of iterations')
417
455
  accuracy_parser.add_argument('--model', '-m', help='Judge model')
@@ -69,6 +69,9 @@ class FastContextHandler(FlagHandler):
69
69
  query: Search query
70
70
  path: Path to search
71
71
  **kwargs: Additional search options
72
+ - use_llm: Use LLM for intelligent search (slower, default: False)
73
+ - max_turns: Max search turns for LLM mode
74
+ - model: LLM model for intelligent search
72
75
 
73
76
  Returns:
74
77
  List of matching results
@@ -86,15 +89,20 @@ class FastContextHandler(FlagHandler):
86
89
  try:
87
90
  from praisonaiagents import FastContext
88
91
 
92
+ # Use fast non-LLM search by default for better performance
93
+ use_llm = kwargs.get('use_llm', False)
94
+
89
95
  fc = FastContext(
90
- path=path,
96
+ workspace_path=path,
91
97
  model=kwargs.get('model', 'gpt-4o-mini'),
92
- max_turns=kwargs.get('max_turns', 4),
93
- parallelism=kwargs.get('parallelism', 8),
94
- timeout=kwargs.get('timeout', 30.0)
98
+ max_turns=kwargs.get('max_turns', 2), # Reduced from 4 for speed
99
+ max_parallel=kwargs.get('parallelism', 8),
100
+ timeout=kwargs.get('timeout', 15.0), # Reduced timeout
101
+ verbose=self.verbose
95
102
  )
96
103
 
97
- result = fc.search(query)
104
+ # Use non-LLM search by default (much faster)
105
+ result = fc.search(query, use_llm=use_llm)
98
106
 
99
107
  # Convert to list of dicts
100
108
  matches = []
@@ -75,7 +75,7 @@ class GuardrailHandler(FlagHandler):
75
75
 
76
76
  Args:
77
77
  description: Natural language description of validation criteria
78
- llm: Optional LLM instance for validation
78
+ llm: Optional LLM instance for validation (defaults to gpt-4o-mini)
79
79
 
80
80
  Returns:
81
81
  LLMGuardrail instance or None if unavailable
@@ -87,6 +87,12 @@ class GuardrailHandler(FlagHandler):
87
87
  )
88
88
  return None
89
89
 
90
+ # Provide default LLM if none specified
91
+ if llm is None:
92
+ import os
93
+ # Try to get from environment or use default
94
+ llm = os.environ.get('OPENAI_MODEL_NAME', 'gpt-4o-mini')
95
+
90
96
  return LLMGuardrail(description=description, llm=llm)
91
97
 
92
98
  def validate_output(self, output: str, description: str, llm: Any = None) -> Tuple[bool, str]:
@@ -4741,16 +4741,14 @@ Provide a concise summary (max 200 words):"""
4741
4741
 
4742
4742
  def _process_interactive_prompt_async(self, prompt, tools_list, console, session_state=None):
4743
4743
  """
4744
- Process a prompt asynchronously with live status display.
4744
+ Process a prompt asynchronously with non-blocking status display.
4745
4745
 
4746
- Shows real-time status (tools, commands) while processing in background.
4746
+ Shows status updates without blocking user input.
4747
4747
  Allows user to queue more messages while processing.
4748
4748
  """
4749
4749
  import threading
4750
4750
  import time
4751
- from rich.live import Live
4752
- from rich.panel import Panel
4753
- from rich.text import Text
4751
+ import sys
4754
4752
  from praisonai.cli.features.message_queue import ProcessingState
4755
4753
 
4756
4754
  state_manager = session_state['state_manager']
@@ -4762,8 +4760,11 @@ Provide a concise summary (max 200 words):"""
4762
4760
  live_status.clear()
4763
4761
  live_status.update_status("Thinking...")
4764
4762
 
4763
+ # Print initial status (non-blocking - user can still type)
4764
+ console.print(f"[dim cyan]⏳ {live_status.current_status}[/dim cyan]")
4765
+
4765
4766
  # Result container for thread communication
4766
- result_container = {'response': None, 'error': None, 'done': False}
4767
+ result_container = {'response': None, 'error': None, 'done': False, 'last_status': ''}
4767
4768
 
4768
4769
  def process_in_background():
4769
4770
  """Run agent processing in background thread."""
@@ -4809,37 +4810,36 @@ Provide a concise summary (max 200 words):"""
4809
4810
  bg_thread = threading.Thread(target=process_in_background, daemon=True)
4810
4811
  bg_thread.start()
4811
4812
 
4812
- # Show live status while processing
4813
- try:
4814
- with Live(console=console, refresh_per_second=4, transient=True) as live:
4815
- while not result_container['done']:
4816
- # Build status display
4817
- status_text = Text()
4818
- status_text.append("⏳ ", style="cyan")
4819
- status_text.append(live_status.current_status or "Processing...", style="dim")
4820
-
4821
- # Show queued messages if any
4822
- queue_count = message_queue.count
4823
- if queue_count > 0:
4824
- status_text.append(f"\n📋 Queued: {queue_count}", style="dim yellow")
4825
-
4826
- live.update(Panel(status_text, border_style="dim"))
4827
- time.sleep(0.1)
4828
- except KeyboardInterrupt:
4829
- console.print("\n[dim]Processing interrupted[/dim]")
4813
+ # Wait for completion with periodic status updates (non-blocking style)
4814
+ start_time = time.time()
4815
+ last_status_update = ""
4816
+ while not result_container['done']:
4817
+ time.sleep(0.2)
4818
+ current_status = live_status.current_status
4819
+ # Only print status if it changed
4820
+ if current_status != last_status_update:
4821
+ # Use carriage return to update in place
4822
+ elapsed = time.time() - start_time
4823
+ queue_count = message_queue.count
4824
+ queue_info = f" | 📋 Queued: {queue_count}" if queue_count > 0 else ""
4825
+ sys.stdout.write(f"\r[dim cyan]⏳ {current_status} ({elapsed:.1f}s){queue_info}[/dim cyan]")
4826
+ sys.stdout.flush()
4827
+ last_status_update = current_status
4828
+
4829
+ # Clear the status line
4830
+ sys.stdout.write("\r" + " " * 80 + "\r")
4831
+ sys.stdout.flush()
4830
4832
 
4831
4833
  # Wait for thread to finish
4832
4834
  bg_thread.join(timeout=1.0)
4833
4835
 
4834
4836
  # Handle result
4835
4837
  if result_container['error']:
4836
- console.print(f"\n[red]Error: {result_container['error']}[/red]")
4838
+ console.print(f"[red]Error: {result_container['error']}[/red]")
4837
4839
  elif result_container['response']:
4838
4840
  # Print response with streaming effect
4839
- console.print()
4840
4841
  response_str = result_container['response']
4841
4842
  words = response_str.split()
4842
- import sys
4843
4843
  for i, word in enumerate(words):
4844
4844
  console.print(word + " ", end="")
4845
4845
  sys.stdout.flush()
@@ -57,7 +57,7 @@ class CloudDeployer:
57
57
  file.write("FROM python:3.11-slim\n")
58
58
  file.write("WORKDIR /app\n")
59
59
  file.write("COPY . .\n")
60
- file.write("RUN pip install flask praisonai==2.3.76 gunicorn markdown\n")
60
+ file.write("RUN pip install flask praisonai==2.3.77 gunicorn markdown\n")
61
61
  file.write("EXPOSE 8080\n")
62
62
  file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
63
63
 
@@ -0,0 +1 @@
1
+ __version__ = "2.3.77"
@@ -1 +0,0 @@
1
- __version__ = "2.3.76"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes