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.
- {praisonai-2.3.76 → praisonai-2.3.78}/PKG-INFO +1 -1
- {praisonai-2.3.76 → praisonai-2.3.78}/PraisonAI.egg-info/PKG-INFO +1 -1
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/at_mentions.py +69 -14
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/compare.py +49 -8
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/eval.py +55 -17
- praisonai-2.3.78/praisonai/cli/features/fast_context.py +374 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/guardrail.py +7 -1
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/handoff.py +3 -3
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/main.py +39 -27
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/deploy.py +1 -1
- praisonai-2.3.78/praisonai/version.py +1 -0
- praisonai-2.3.76/praisonai/cli/features/fast_context.py +0 -189
- praisonai-2.3.76/praisonai/version.py +0 -1
- {praisonai-2.3.76 → praisonai-2.3.78}/PraisonAI.egg-info/SOURCES.txt +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/PraisonAI.egg-info/dependency_links.txt +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/PraisonAI.egg-info/entry_points.txt +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/PraisonAI.egg-info/requires.txt +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/PraisonAI.egg-info/top_level.txt +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/README.md +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/__init__.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/__main__.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/agent_scheduler.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/agents_generator.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/api/call.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/auto.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/chainlit_ui.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/__init__.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/__init__.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/agent_scheduler.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/auto_memory.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/autonomy_mode.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/base.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/cost_tracker.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/external_agents.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/flow_display.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/git_integration.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/image.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/interactive_tui.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/knowledge.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/mcp.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/message_queue.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/metrics.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/n8n.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/profiling.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/repo_map.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/router.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/sandbox_executor.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/session.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/skills.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/slash_commands.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/telemetry.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/todo.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/tools.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/features/workflow.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/cli/schedule_cli.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/__init__.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/agent_tools.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/diff/__init__.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/diff/diff_strategy.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/tools/__init__.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/tools/apply_diff.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/tools/execute_command.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/tools/list_files.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/tools/read_file.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/tools/search_replace.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/tools/write_file.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/utils/__init__.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/utils/file_utils.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/utils/ignore_utils.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/code/utils/text_utils.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/inbuilt_tools/__init__.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/inbuilt_tools/autogen_tools.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/inc/__init__.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/inc/config.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/inc/models.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/integrations/__init__.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/integrations/base.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/integrations/claude_code.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/integrations/codex_cli.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/integrations/cursor_cli.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/integrations/gemini_cli.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/profiler.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/scheduler/__init__.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/scheduler/agent_scheduler.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/scheduler/base.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/scheduler/daemon_manager.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/scheduler/state_manager.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/scheduler/yaml_loader.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/scheduler.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/setup/__init__.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/setup/build.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/setup/post_install.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/setup/setup_conda_env.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/setup.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/test.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/train.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/train_vision.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/agents.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/callbacks.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/chat.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/code.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/colab.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/colab_chainlit.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/components/aicoder.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/context.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/database_config.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/db.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/realtime.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/realtimeclient/__init__.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/realtimeclient/tools.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/ui/sql_alchemy.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/praisonai/upload_vision.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/pyproject.toml +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/setup.cfg +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/tests/test.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/tests/test_agents_playbook.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/tests/test_approval_system.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/tests/test_basic.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/tests/test_cli_features.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/tests/test_custom_tools_fix.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/tests/test_double_api_fix.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/tests/test_n8n_integration.py +0 -0
- {praisonai-2.3.76 → praisonai-2.3.78}/tests/test_phase2_refactor.py +0 -0
- {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.
|
|
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.
|
|
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
|
|
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(
|
|
155
|
+
for root, dirs, filenames in os.walk(target_dir):
|
|
151
156
|
# Calculate depth
|
|
152
|
-
rel_root = os.path.relpath(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),
|
|
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),
|
|
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"{
|
|
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,
|
|
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=
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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',
|
|
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',
|
|
414
|
-
accuracy_parser.add_argument('--
|
|
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')
|