praisonAI 2.3.76__tar.gz → 2.3.78__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 (124) hide show
  1. {praisonai-2.3.76 → praisonai-2.3.78}/PKG-INFO +1 -1
  2. {praisonai-2.3.76 → praisonai-2.3.78}/PraisonAI.egg-info/PKG-INFO +1 -1
  3. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/at_mentions.py +69 -14
  4. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/compare.py +49 -8
  5. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/eval.py +55 -17
  6. praisonai-2.3.78/praisonai/cli/features/fast_context.py +374 -0
  7. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/guardrail.py +7 -1
  8. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/handoff.py +3 -3
  9. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/main.py +39 -27
  10. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/deploy.py +1 -1
  11. praisonai-2.3.78/praisonai/version.py +1 -0
  12. praisonai-2.3.76/praisonai/cli/features/fast_context.py +0 -189
  13. praisonai-2.3.76/praisonai/version.py +0 -1
  14. {praisonai-2.3.76 → praisonai-2.3.78}/PraisonAI.egg-info/SOURCES.txt +0 -0
  15. {praisonai-2.3.76 → praisonai-2.3.78}/PraisonAI.egg-info/dependency_links.txt +0 -0
  16. {praisonai-2.3.76 → praisonai-2.3.78}/PraisonAI.egg-info/entry_points.txt +0 -0
  17. {praisonai-2.3.76 → praisonai-2.3.78}/PraisonAI.egg-info/requires.txt +0 -0
  18. {praisonai-2.3.76 → praisonai-2.3.78}/PraisonAI.egg-info/top_level.txt +0 -0
  19. {praisonai-2.3.76 → praisonai-2.3.78}/README.md +0 -0
  20. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/__init__.py +0 -0
  21. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/__main__.py +0 -0
  22. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/agent_scheduler.py +0 -0
  23. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/agents_generator.py +0 -0
  24. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/api/call.py +0 -0
  25. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/auto.py +0 -0
  26. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/chainlit_ui.py +0 -0
  27. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/__init__.py +0 -0
  28. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/__init__.py +0 -0
  29. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/agent_scheduler.py +0 -0
  30. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/auto_memory.py +0 -0
  31. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/autonomy_mode.py +0 -0
  32. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/base.py +0 -0
  33. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/cost_tracker.py +0 -0
  34. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/external_agents.py +0 -0
  35. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/flow_display.py +0 -0
  36. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/git_integration.py +0 -0
  37. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/image.py +0 -0
  38. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/interactive_tui.py +0 -0
  39. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/knowledge.py +0 -0
  40. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/mcp.py +0 -0
  41. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/message_queue.py +0 -0
  42. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/metrics.py +0 -0
  43. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/n8n.py +0 -0
  44. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/profiling.py +0 -0
  45. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/repo_map.py +0 -0
  46. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/router.py +0 -0
  47. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/sandbox_executor.py +0 -0
  48. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/session.py +0 -0
  49. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/skills.py +0 -0
  50. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/slash_commands.py +0 -0
  51. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/telemetry.py +0 -0
  52. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/todo.py +0 -0
  53. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/tools.py +0 -0
  54. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/workflow.py +0 -0
  55. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/schedule_cli.py +0 -0
  56. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/__init__.py +0 -0
  57. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/agent_tools.py +0 -0
  58. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/diff/__init__.py +0 -0
  59. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/diff/diff_strategy.py +0 -0
  60. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/tools/__init__.py +0 -0
  61. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/tools/apply_diff.py +0 -0
  62. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/tools/execute_command.py +0 -0
  63. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/tools/list_files.py +0 -0
  64. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/tools/read_file.py +0 -0
  65. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/tools/search_replace.py +0 -0
  66. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/tools/write_file.py +0 -0
  67. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/utils/__init__.py +0 -0
  68. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/utils/file_utils.py +0 -0
  69. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/utils/ignore_utils.py +0 -0
  70. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/utils/text_utils.py +0 -0
  71. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/inbuilt_tools/__init__.py +0 -0
  72. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/inbuilt_tools/autogen_tools.py +0 -0
  73. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/inc/__init__.py +0 -0
  74. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/inc/config.py +0 -0
  75. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/inc/models.py +0 -0
  76. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/integrations/__init__.py +0 -0
  77. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/integrations/base.py +0 -0
  78. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/integrations/claude_code.py +0 -0
  79. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/integrations/codex_cli.py +0 -0
  80. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/integrations/cursor_cli.py +0 -0
  81. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/integrations/gemini_cli.py +0 -0
  82. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/profiler.py +0 -0
  83. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/scheduler/__init__.py +0 -0
  84. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/scheduler/agent_scheduler.py +0 -0
  85. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/scheduler/base.py +0 -0
  86. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/scheduler/daemon_manager.py +0 -0
  87. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/scheduler/state_manager.py +0 -0
  88. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/scheduler/yaml_loader.py +0 -0
  89. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/scheduler.py +0 -0
  90. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/setup/__init__.py +0 -0
  91. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/setup/build.py +0 -0
  92. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/setup/post_install.py +0 -0
  93. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/setup/setup_conda_env.py +0 -0
  94. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/setup.py +0 -0
  95. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/test.py +0 -0
  96. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/train.py +0 -0
  97. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/train_vision.py +0 -0
  98. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/agents.py +0 -0
  99. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/callbacks.py +0 -0
  100. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/chat.py +0 -0
  101. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/code.py +0 -0
  102. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/colab.py +0 -0
  103. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/colab_chainlit.py +0 -0
  104. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/components/aicoder.py +0 -0
  105. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/context.py +0 -0
  106. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/database_config.py +0 -0
  107. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/db.py +0 -0
  108. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/realtime.py +0 -0
  109. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/realtimeclient/__init__.py +0 -0
  110. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/realtimeclient/tools.py +0 -0
  111. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/sql_alchemy.py +0 -0
  112. {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/upload_vision.py +0 -0
  113. {praisonai-2.3.76 → praisonai-2.3.78}/pyproject.toml +0 -0
  114. {praisonai-2.3.76 → praisonai-2.3.78}/setup.cfg +0 -0
  115. {praisonai-2.3.76 → praisonai-2.3.78}/tests/test.py +0 -0
  116. {praisonai-2.3.76 → praisonai-2.3.78}/tests/test_agents_playbook.py +0 -0
  117. {praisonai-2.3.76 → praisonai-2.3.78}/tests/test_approval_system.py +0 -0
  118. {praisonai-2.3.76 → praisonai-2.3.78}/tests/test_basic.py +0 -0
  119. {praisonai-2.3.76 → praisonai-2.3.78}/tests/test_cli_features.py +0 -0
  120. {praisonai-2.3.76 → praisonai-2.3.78}/tests/test_custom_tools_fix.py +0 -0
  121. {praisonai-2.3.76 → praisonai-2.3.78}/tests/test_double_api_fix.py +0 -0
  122. {praisonai-2.3.76 → praisonai-2.3.78}/tests/test_n8n_integration.py +0 -0
  123. {praisonai-2.3.76 → praisonai-2.3.78}/tests/test_phase2_refactor.py +0 -0
  124. {praisonai-2.3.76 → praisonai-2.3.78}/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.78
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.78
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
  ))
@@ -16,7 +16,7 @@ logger = logging.getLogger(__name__)
16
16
 
17
17
  COMPARE_MODES = {
18
18
  "basic": {},
19
- "tools": {"tools": "internet_search"},
19
+ "tools": {"tools": "calculator,internet_search"},
20
20
  "research": {"research": True},
21
21
  "planning": {"planning": True},
22
22
  "memory": {"memory": True},
@@ -407,13 +407,7 @@ class CompareHandler:
407
407
  from praisonaiagents.tools import internet_search
408
408
  tools.append(internet_search)
409
409
  elif name == "calculator":
410
- def calculator(expression: str) -> str:
411
- """Evaluate a mathematical expression."""
412
- try:
413
- return str(eval(expression))
414
- except Exception as e:
415
- return f"Error: {e}"
416
- tools.append(calculator)
410
+ tools.append(_calculator_tool)
417
411
  except ImportError:
418
412
  logger.warning(f"Could not load tool: {name}")
419
413
 
@@ -466,3 +460,50 @@ class CompareHandler:
466
460
  print(f"[red]Failed to save results to: {output_path}[/red]")
467
461
 
468
462
  return result
463
+
464
+
465
+ def _calculator_tool(expression: str) -> str:
466
+ """
467
+ Evaluate a mathematical expression safely.
468
+
469
+ Args:
470
+ expression: Mathematical expression to evaluate (e.g., "2+2", "15*3", "100/4")
471
+
472
+ Returns:
473
+ The result of the calculation as a string
474
+ """
475
+ import ast
476
+ import operator
477
+
478
+ # Safe operators
479
+ operators = {
480
+ ast.Add: operator.add,
481
+ ast.Sub: operator.sub,
482
+ ast.Mult: operator.mul,
483
+ ast.Div: operator.truediv,
484
+ ast.Pow: operator.pow,
485
+ ast.USub: operator.neg,
486
+ ast.UAdd: operator.pos,
487
+ ast.Mod: operator.mod,
488
+ ast.FloorDiv: operator.floordiv,
489
+ }
490
+
491
+ def _eval(node):
492
+ if isinstance(node, ast.Constant):
493
+ return node.value
494
+ elif isinstance(node, ast.BinOp):
495
+ left = _eval(node.left)
496
+ right = _eval(node.right)
497
+ return operators[type(node.op)](left, right)
498
+ elif isinstance(node, ast.UnaryOp):
499
+ operand = _eval(node.operand)
500
+ return operators[type(node.op)](operand)
501
+ else:
502
+ raise ValueError(f"Unsupported operation: {type(node)}")
503
+
504
+ try:
505
+ tree = ast.parse(expression, mode='eval')
506
+ result = _eval(tree.body)
507
+ return str(result)
508
+ except Exception as e:
509
+ return f"Error evaluating '{expression}': {e}"
@@ -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')