praisonAI 2.3.87__tar.gz → 2.4.0__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.87 → praisonai-2.4.0}/PKG-INFO +64 -10
- {praisonai-2.3.87 → praisonai-2.4.0}/PraisonAI.egg-info/PKG-INFO +64 -10
- {praisonai-2.3.87 → praisonai-2.4.0}/PraisonAI.egg-info/SOURCES.txt +3 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/PraisonAI.egg-info/requires.txt +1 -1
- {praisonai-2.3.87 → praisonai-2.4.0}/README.md +62 -8
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/__init__.py +18 -0
- praisonai-2.4.0/praisonai/cli/features/background.py +296 -0
- praisonai-2.4.0/praisonai/cli/features/checkpoints.py +338 -0
- praisonai-2.4.0/praisonai/cli/features/hooks.py +583 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/deploy.py +1 -1
- praisonai-2.4.0/praisonai/version.py +1 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/pyproject.toml +1 -1
- praisonai-2.3.87/praisonai/version.py +0 -1
- {praisonai-2.3.87 → praisonai-2.4.0}/PraisonAI.egg-info/dependency_links.txt +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/PraisonAI.egg-info/entry_points.txt +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/PraisonAI.egg-info/top_level.txt +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/__init__.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/__main__.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/agent_scheduler.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/agents_generator.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/api/call.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/auto.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/chainlit_ui.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/__init__.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/agent_scheduler.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/agents.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/at_mentions.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/auto_memory.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/autonomy_mode.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/base.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/compare.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/cost_tracker.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/eval.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/external_agents.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/fast_context.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/flow_display.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/git_integration.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/guardrail.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/handoff.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/image.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/interactive_tui.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/knowledge.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/mcp.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/message_queue.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/metrics.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/n8n.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/profile.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/profiling.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/repo_map.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/router.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/sandbox_executor.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/session.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/skills.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/slash_commands.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/telemetry.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/todo.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/tools.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/features/workflow.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/main.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/cli/schedule_cli.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/code/__init__.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/code/agent_tools.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/code/diff/__init__.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/code/diff/diff_strategy.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/code/tools/__init__.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/code/tools/apply_diff.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/code/tools/execute_command.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/code/tools/list_files.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/code/tools/read_file.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/code/tools/search_replace.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/code/tools/write_file.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/code/utils/__init__.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/code/utils/file_utils.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/code/utils/ignore_utils.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/code/utils/text_utils.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/inbuilt_tools/__init__.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/inbuilt_tools/autogen_tools.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/inc/__init__.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/inc/config.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/inc/models.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/integrations/__init__.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/integrations/base.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/integrations/claude_code.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/integrations/codex_cli.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/integrations/cursor_cli.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/integrations/gemini_cli.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/profiler.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/scheduler/__init__.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/scheduler/agent_scheduler.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/scheduler/base.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/scheduler/daemon_manager.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/scheduler/state_manager.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/scheduler/yaml_loader.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/scheduler.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/setup/__init__.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/setup/build.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/setup/post_install.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/setup/setup_conda_env.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/setup.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/test.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/train.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/train_vision.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/ui/agents.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/ui/callbacks.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/ui/chat.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/ui/code.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/ui/colab.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/ui/colab_chainlit.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/ui/components/aicoder.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/ui/context.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/ui/database_config.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/ui/db.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/ui/realtime.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/ui/realtimeclient/__init__.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/ui/realtimeclient/tools.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/ui/sql_alchemy.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/praisonai/upload_vision.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/setup.cfg +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/tests/test.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/tests/test_agents_playbook.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/tests/test_approval_system.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/tests/test_basic.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/tests/test_cli_features.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/tests/test_custom_tools_fix.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/tests/test_double_api_fix.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/tests/test_n8n_integration.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/tests/test_phase2_refactor.py +0 -0
- {praisonai-2.3.87 → praisonai-2.4.0}/tests/test_runner.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PraisonAI
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
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
|
|
@@ -11,7 +11,7 @@ Description-Content-Type: text/markdown
|
|
|
11
11
|
Requires-Dist: rich>=13.7
|
|
12
12
|
Requires-Dist: markdown>=3.5
|
|
13
13
|
Requires-Dist: pyparsing>=3.0.0
|
|
14
|
-
Requires-Dist: praisonaiagents>=0.
|
|
14
|
+
Requires-Dist: praisonaiagents>=0.2.0
|
|
15
15
|
Requires-Dist: python-dotenv>=0.19.0
|
|
16
16
|
Requires-Dist: instructor>=1.3.3
|
|
17
17
|
Requires-Dist: PyYAML>=6.0
|
|
@@ -960,21 +960,75 @@ callbacks:
|
|
|
960
960
|
|
|
961
961
|
### 9. Hooks
|
|
962
962
|
|
|
963
|
-
|
|
963
|
+
Intercept and modify agent behavior at various lifecycle points:
|
|
964
964
|
|
|
965
965
|
```python
|
|
966
|
-
from praisonaiagents.
|
|
966
|
+
from praisonaiagents.hooks import (
|
|
967
|
+
HookRegistry, HookRunner, HookEvent, HookResult,
|
|
968
|
+
BeforeToolInput
|
|
969
|
+
)
|
|
970
|
+
|
|
971
|
+
# Create a hook registry
|
|
972
|
+
registry = HookRegistry()
|
|
967
973
|
|
|
968
|
-
|
|
974
|
+
# Log all tool calls
|
|
975
|
+
@registry.on(HookEvent.BEFORE_TOOL)
|
|
976
|
+
def log_tools(event_data: BeforeToolInput) -> HookResult:
|
|
977
|
+
print(f"Tool: {event_data.tool_name}")
|
|
978
|
+
return HookResult.allow()
|
|
969
979
|
|
|
970
|
-
#
|
|
971
|
-
|
|
980
|
+
# Block dangerous operations
|
|
981
|
+
@registry.on(HookEvent.BEFORE_TOOL)
|
|
982
|
+
def security_check(event_data: BeforeToolInput) -> HookResult:
|
|
983
|
+
if "delete" in event_data.tool_name.lower():
|
|
984
|
+
return HookResult.deny("Delete operations blocked")
|
|
985
|
+
return HookResult.allow()
|
|
972
986
|
|
|
973
987
|
# Execute hooks
|
|
974
|
-
|
|
988
|
+
runner = HookRunner(registry)
|
|
989
|
+
```
|
|
990
|
+
|
|
991
|
+
**CLI Commands:**
|
|
992
|
+
```bash
|
|
993
|
+
praisonai hooks list # List registered hooks
|
|
994
|
+
praisonai hooks test before_tool # Test hooks for an event
|
|
995
|
+
praisonai hooks run "echo test" # Run a command hook
|
|
996
|
+
praisonai hooks validate hooks.json # Validate configuration
|
|
997
|
+
```
|
|
998
|
+
|
|
999
|
+
|
|
1000
|
+
### 10. Shadow Git Checkpoints
|
|
1001
|
+
|
|
1002
|
+
File-level undo/restore using shadow git:
|
|
1003
|
+
|
|
1004
|
+
```python
|
|
1005
|
+
from praisonaiagents.checkpoints import CheckpointService
|
|
1006
|
+
|
|
1007
|
+
service = CheckpointService(workspace_dir="./my_project")
|
|
1008
|
+
await service.initialize()
|
|
1009
|
+
|
|
1010
|
+
# Save checkpoint before changes
|
|
1011
|
+
result = await service.save("Before refactoring")
|
|
1012
|
+
|
|
1013
|
+
# Make changes...
|
|
1014
|
+
|
|
1015
|
+
# Restore if needed
|
|
1016
|
+
await service.restore(result.checkpoint.id)
|
|
1017
|
+
|
|
1018
|
+
# View diff
|
|
1019
|
+
diff = await service.diff()
|
|
975
1020
|
```
|
|
976
1021
|
|
|
977
|
-
|
|
1022
|
+
**CLI Commands:**
|
|
1023
|
+
```bash
|
|
1024
|
+
praisonai checkpoint save "Before changes" # Save checkpoint
|
|
1025
|
+
praisonai checkpoint list # List checkpoints
|
|
1026
|
+
praisonai checkpoint diff # Show changes
|
|
1027
|
+
praisonai checkpoint restore abc123 # Restore to checkpoint
|
|
1028
|
+
```
|
|
1029
|
+
|
|
1030
|
+
|
|
1031
|
+
### 11. Field Names Reference (A-I-G-S)
|
|
978
1032
|
|
|
979
1033
|
PraisonAI accepts both old (agents.yaml) and new (workflow.yaml) field names. Use the **canonical names** for new projects:
|
|
980
1034
|
|
|
@@ -1008,7 +1062,7 @@ steps: # Define steps (not 'tasks')
|
|
|
1008
1062
|
|
|
1009
1063
|
> **Note:** The parser accepts both old and new names. Run `praisonai workflow validate <file.yaml>` to see suggestions for canonical names.
|
|
1010
1064
|
|
|
1011
|
-
###
|
|
1065
|
+
### 12. Extended agents.yaml with Workflow Patterns
|
|
1012
1066
|
|
|
1013
1067
|
**Feature Parity:** Both `agents.yaml` and `workflow.yaml` now support the same features:
|
|
1014
1068
|
- All workflow patterns (route, parallel, loop, repeat)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PraisonAI
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
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
|
|
@@ -11,7 +11,7 @@ Description-Content-Type: text/markdown
|
|
|
11
11
|
Requires-Dist: rich>=13.7
|
|
12
12
|
Requires-Dist: markdown>=3.5
|
|
13
13
|
Requires-Dist: pyparsing>=3.0.0
|
|
14
|
-
Requires-Dist: praisonaiagents>=0.
|
|
14
|
+
Requires-Dist: praisonaiagents>=0.2.0
|
|
15
15
|
Requires-Dist: python-dotenv>=0.19.0
|
|
16
16
|
Requires-Dist: instructor>=1.3.3
|
|
17
17
|
Requires-Dist: PyYAML>=6.0
|
|
@@ -960,21 +960,75 @@ callbacks:
|
|
|
960
960
|
|
|
961
961
|
### 9. Hooks
|
|
962
962
|
|
|
963
|
-
|
|
963
|
+
Intercept and modify agent behavior at various lifecycle points:
|
|
964
964
|
|
|
965
965
|
```python
|
|
966
|
-
from praisonaiagents.
|
|
966
|
+
from praisonaiagents.hooks import (
|
|
967
|
+
HookRegistry, HookRunner, HookEvent, HookResult,
|
|
968
|
+
BeforeToolInput
|
|
969
|
+
)
|
|
970
|
+
|
|
971
|
+
# Create a hook registry
|
|
972
|
+
registry = HookRegistry()
|
|
967
973
|
|
|
968
|
-
|
|
974
|
+
# Log all tool calls
|
|
975
|
+
@registry.on(HookEvent.BEFORE_TOOL)
|
|
976
|
+
def log_tools(event_data: BeforeToolInput) -> HookResult:
|
|
977
|
+
print(f"Tool: {event_data.tool_name}")
|
|
978
|
+
return HookResult.allow()
|
|
969
979
|
|
|
970
|
-
#
|
|
971
|
-
|
|
980
|
+
# Block dangerous operations
|
|
981
|
+
@registry.on(HookEvent.BEFORE_TOOL)
|
|
982
|
+
def security_check(event_data: BeforeToolInput) -> HookResult:
|
|
983
|
+
if "delete" in event_data.tool_name.lower():
|
|
984
|
+
return HookResult.deny("Delete operations blocked")
|
|
985
|
+
return HookResult.allow()
|
|
972
986
|
|
|
973
987
|
# Execute hooks
|
|
974
|
-
|
|
988
|
+
runner = HookRunner(registry)
|
|
989
|
+
```
|
|
990
|
+
|
|
991
|
+
**CLI Commands:**
|
|
992
|
+
```bash
|
|
993
|
+
praisonai hooks list # List registered hooks
|
|
994
|
+
praisonai hooks test before_tool # Test hooks for an event
|
|
995
|
+
praisonai hooks run "echo test" # Run a command hook
|
|
996
|
+
praisonai hooks validate hooks.json # Validate configuration
|
|
997
|
+
```
|
|
998
|
+
|
|
999
|
+
|
|
1000
|
+
### 10. Shadow Git Checkpoints
|
|
1001
|
+
|
|
1002
|
+
File-level undo/restore using shadow git:
|
|
1003
|
+
|
|
1004
|
+
```python
|
|
1005
|
+
from praisonaiagents.checkpoints import CheckpointService
|
|
1006
|
+
|
|
1007
|
+
service = CheckpointService(workspace_dir="./my_project")
|
|
1008
|
+
await service.initialize()
|
|
1009
|
+
|
|
1010
|
+
# Save checkpoint before changes
|
|
1011
|
+
result = await service.save("Before refactoring")
|
|
1012
|
+
|
|
1013
|
+
# Make changes...
|
|
1014
|
+
|
|
1015
|
+
# Restore if needed
|
|
1016
|
+
await service.restore(result.checkpoint.id)
|
|
1017
|
+
|
|
1018
|
+
# View diff
|
|
1019
|
+
diff = await service.diff()
|
|
975
1020
|
```
|
|
976
1021
|
|
|
977
|
-
|
|
1022
|
+
**CLI Commands:**
|
|
1023
|
+
```bash
|
|
1024
|
+
praisonai checkpoint save "Before changes" # Save checkpoint
|
|
1025
|
+
praisonai checkpoint list # List checkpoints
|
|
1026
|
+
praisonai checkpoint diff # Show changes
|
|
1027
|
+
praisonai checkpoint restore abc123 # Restore to checkpoint
|
|
1028
|
+
```
|
|
1029
|
+
|
|
1030
|
+
|
|
1031
|
+
### 11. Field Names Reference (A-I-G-S)
|
|
978
1032
|
|
|
979
1033
|
PraisonAI accepts both old (agents.yaml) and new (workflow.yaml) field names. Use the **canonical names** for new projects:
|
|
980
1034
|
|
|
@@ -1008,7 +1062,7 @@ steps: # Define steps (not 'tasks')
|
|
|
1008
1062
|
|
|
1009
1063
|
> **Note:** The parser accepts both old and new names. Run `praisonai workflow validate <file.yaml>` to see suggestions for canonical names.
|
|
1010
1064
|
|
|
1011
|
-
###
|
|
1065
|
+
### 12. Extended agents.yaml with Workflow Patterns
|
|
1012
1066
|
|
|
1013
1067
|
**Feature Parity:** Both `agents.yaml` and `workflow.yaml` now support the same features:
|
|
1014
1068
|
- All workflow patterns (route, parallel, loop, repeat)
|
|
@@ -31,7 +31,9 @@ praisonai/cli/features/agents.py
|
|
|
31
31
|
praisonai/cli/features/at_mentions.py
|
|
32
32
|
praisonai/cli/features/auto_memory.py
|
|
33
33
|
praisonai/cli/features/autonomy_mode.py
|
|
34
|
+
praisonai/cli/features/background.py
|
|
34
35
|
praisonai/cli/features/base.py
|
|
36
|
+
praisonai/cli/features/checkpoints.py
|
|
35
37
|
praisonai/cli/features/compare.py
|
|
36
38
|
praisonai/cli/features/cost_tracker.py
|
|
37
39
|
praisonai/cli/features/eval.py
|
|
@@ -41,6 +43,7 @@ praisonai/cli/features/flow_display.py
|
|
|
41
43
|
praisonai/cli/features/git_integration.py
|
|
42
44
|
praisonai/cli/features/guardrail.py
|
|
43
45
|
praisonai/cli/features/handoff.py
|
|
46
|
+
praisonai/cli/features/hooks.py
|
|
44
47
|
praisonai/cli/features/image.py
|
|
45
48
|
praisonai/cli/features/interactive_tui.py
|
|
46
49
|
praisonai/cli/features/knowledge.py
|
|
@@ -863,21 +863,75 @@ callbacks:
|
|
|
863
863
|
|
|
864
864
|
### 9. Hooks
|
|
865
865
|
|
|
866
|
-
|
|
866
|
+
Intercept and modify agent behavior at various lifecycle points:
|
|
867
867
|
|
|
868
868
|
```python
|
|
869
|
-
from praisonaiagents.
|
|
869
|
+
from praisonaiagents.hooks import (
|
|
870
|
+
HookRegistry, HookRunner, HookEvent, HookResult,
|
|
871
|
+
BeforeToolInput
|
|
872
|
+
)
|
|
873
|
+
|
|
874
|
+
# Create a hook registry
|
|
875
|
+
registry = HookRegistry()
|
|
870
876
|
|
|
871
|
-
|
|
877
|
+
# Log all tool calls
|
|
878
|
+
@registry.on(HookEvent.BEFORE_TOOL)
|
|
879
|
+
def log_tools(event_data: BeforeToolInput) -> HookResult:
|
|
880
|
+
print(f"Tool: {event_data.tool_name}")
|
|
881
|
+
return HookResult.allow()
|
|
872
882
|
|
|
873
|
-
#
|
|
874
|
-
|
|
883
|
+
# Block dangerous operations
|
|
884
|
+
@registry.on(HookEvent.BEFORE_TOOL)
|
|
885
|
+
def security_check(event_data: BeforeToolInput) -> HookResult:
|
|
886
|
+
if "delete" in event_data.tool_name.lower():
|
|
887
|
+
return HookResult.deny("Delete operations blocked")
|
|
888
|
+
return HookResult.allow()
|
|
875
889
|
|
|
876
890
|
# Execute hooks
|
|
877
|
-
|
|
891
|
+
runner = HookRunner(registry)
|
|
892
|
+
```
|
|
893
|
+
|
|
894
|
+
**CLI Commands:**
|
|
895
|
+
```bash
|
|
896
|
+
praisonai hooks list # List registered hooks
|
|
897
|
+
praisonai hooks test before_tool # Test hooks for an event
|
|
898
|
+
praisonai hooks run "echo test" # Run a command hook
|
|
899
|
+
praisonai hooks validate hooks.json # Validate configuration
|
|
900
|
+
```
|
|
901
|
+
|
|
902
|
+
|
|
903
|
+
### 10. Shadow Git Checkpoints
|
|
904
|
+
|
|
905
|
+
File-level undo/restore using shadow git:
|
|
906
|
+
|
|
907
|
+
```python
|
|
908
|
+
from praisonaiagents.checkpoints import CheckpointService
|
|
909
|
+
|
|
910
|
+
service = CheckpointService(workspace_dir="./my_project")
|
|
911
|
+
await service.initialize()
|
|
912
|
+
|
|
913
|
+
# Save checkpoint before changes
|
|
914
|
+
result = await service.save("Before refactoring")
|
|
915
|
+
|
|
916
|
+
# Make changes...
|
|
917
|
+
|
|
918
|
+
# Restore if needed
|
|
919
|
+
await service.restore(result.checkpoint.id)
|
|
920
|
+
|
|
921
|
+
# View diff
|
|
922
|
+
diff = await service.diff()
|
|
878
923
|
```
|
|
879
924
|
|
|
880
|
-
|
|
925
|
+
**CLI Commands:**
|
|
926
|
+
```bash
|
|
927
|
+
praisonai checkpoint save "Before changes" # Save checkpoint
|
|
928
|
+
praisonai checkpoint list # List checkpoints
|
|
929
|
+
praisonai checkpoint diff # Show changes
|
|
930
|
+
praisonai checkpoint restore abc123 # Restore to checkpoint
|
|
931
|
+
```
|
|
932
|
+
|
|
933
|
+
|
|
934
|
+
### 11. Field Names Reference (A-I-G-S)
|
|
881
935
|
|
|
882
936
|
PraisonAI accepts both old (agents.yaml) and new (workflow.yaml) field names. Use the **canonical names** for new projects:
|
|
883
937
|
|
|
@@ -911,7 +965,7 @@ steps: # Define steps (not 'tasks')
|
|
|
911
965
|
|
|
912
966
|
> **Note:** The parser accepts both old and new names. Run `praisonai workflow validate <file.yaml>` to see suggestions for canonical names.
|
|
913
967
|
|
|
914
|
-
###
|
|
968
|
+
### 12. Extended agents.yaml with Workflow Patterns
|
|
915
969
|
|
|
916
970
|
**Feature Parity:** Both `agents.yaml` and `workflow.yaml` now support the same features:
|
|
917
971
|
- All workflow patterns (route, parallel, loop, repeat)
|
|
@@ -29,6 +29,9 @@ Features:
|
|
|
29
29
|
- at_mentions: @ mention autocomplete for files and directories
|
|
30
30
|
- compare: CLI command comparison feature
|
|
31
31
|
- eval: Agent evaluation framework (accuracy, performance, reliability, criteria)
|
|
32
|
+
- hooks: Hook system for intercepting and modifying agent behavior
|
|
33
|
+
- checkpoints: Shadow git checkpointing for file-level undo/restore
|
|
34
|
+
- background: Background agent task execution and management
|
|
32
35
|
"""
|
|
33
36
|
|
|
34
37
|
# Type hints available for IDE support
|
|
@@ -71,6 +74,12 @@ __all__ = [
|
|
|
71
74
|
'CompareHandler',
|
|
72
75
|
# Agent Skills
|
|
73
76
|
'SkillsHandler',
|
|
77
|
+
# Hooks
|
|
78
|
+
'HooksHandler',
|
|
79
|
+
# Checkpoints
|
|
80
|
+
'CheckpointsHandler',
|
|
81
|
+
# Background
|
|
82
|
+
'BackgroundHandler',
|
|
74
83
|
]
|
|
75
84
|
|
|
76
85
|
def __getattr__(name):
|
|
@@ -170,4 +179,13 @@ def __getattr__(name):
|
|
|
170
179
|
elif name == 'SkillsHandler':
|
|
171
180
|
from .skills import SkillsHandler
|
|
172
181
|
return SkillsHandler
|
|
182
|
+
elif name == 'HooksHandler':
|
|
183
|
+
from .hooks import HooksHandler
|
|
184
|
+
return HooksHandler
|
|
185
|
+
elif name == 'CheckpointsHandler':
|
|
186
|
+
from .checkpoints import CheckpointsHandler
|
|
187
|
+
return CheckpointsHandler
|
|
188
|
+
elif name == 'BackgroundHandler':
|
|
189
|
+
from .background import BackgroundHandler
|
|
190
|
+
return BackgroundHandler
|
|
173
191
|
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Background Agents CLI Feature for PraisonAI.
|
|
3
|
+
|
|
4
|
+
Provides CLI commands for managing background agent tasks.
|
|
5
|
+
|
|
6
|
+
Commands:
|
|
7
|
+
- praisonai background list # List background tasks
|
|
8
|
+
- praisonai background status <id> # Get task status
|
|
9
|
+
- praisonai background cancel <id> # Cancel a task
|
|
10
|
+
- praisonai background clear # Clear completed tasks
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
import asyncio
|
|
15
|
+
from typing import Optional, List
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class BackgroundHandler:
|
|
19
|
+
"""
|
|
20
|
+
Handler for background CLI commands.
|
|
21
|
+
|
|
22
|
+
Provides functionality to:
|
|
23
|
+
- List running and completed background tasks
|
|
24
|
+
- Check task status
|
|
25
|
+
- Cancel running tasks
|
|
26
|
+
- Clear completed tasks
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(self, verbose: bool = False):
|
|
30
|
+
self.verbose = verbose
|
|
31
|
+
self._runner = None
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def feature_name(self) -> str:
|
|
35
|
+
return "background"
|
|
36
|
+
|
|
37
|
+
async def _get_runner(self):
|
|
38
|
+
"""Lazy load the background runner."""
|
|
39
|
+
if self._runner is None:
|
|
40
|
+
from praisonaiagents.background import BackgroundRunner
|
|
41
|
+
self._runner = BackgroundRunner()
|
|
42
|
+
return self._runner
|
|
43
|
+
|
|
44
|
+
async def list_tasks(self, status: Optional[str] = None) -> List[dict]:
|
|
45
|
+
"""
|
|
46
|
+
List all background tasks.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
status: Optional status filter (pending, running, completed, failed)
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
List of task dictionaries
|
|
53
|
+
"""
|
|
54
|
+
runner = await self._get_runner()
|
|
55
|
+
|
|
56
|
+
status_enum = None
|
|
57
|
+
if status:
|
|
58
|
+
from praisonaiagents.background import TaskStatus
|
|
59
|
+
status_map = {
|
|
60
|
+
"pending": TaskStatus.PENDING,
|
|
61
|
+
"running": TaskStatus.RUNNING,
|
|
62
|
+
"completed": TaskStatus.COMPLETED,
|
|
63
|
+
"failed": TaskStatus.FAILED,
|
|
64
|
+
"cancelled": TaskStatus.CANCELLED
|
|
65
|
+
}
|
|
66
|
+
status_enum = status_map.get(status.lower())
|
|
67
|
+
|
|
68
|
+
tasks = runner.list_tasks(status=status_enum)
|
|
69
|
+
|
|
70
|
+
self._print_tasks_table(tasks)
|
|
71
|
+
return tasks
|
|
72
|
+
|
|
73
|
+
def _print_tasks_table(self, tasks: List[dict]):
|
|
74
|
+
"""Print tasks in table format."""
|
|
75
|
+
try:
|
|
76
|
+
from rich.console import Console
|
|
77
|
+
from rich.table import Table
|
|
78
|
+
|
|
79
|
+
console = Console()
|
|
80
|
+
|
|
81
|
+
if not tasks:
|
|
82
|
+
console.print("[yellow]No background tasks[/yellow]")
|
|
83
|
+
return
|
|
84
|
+
|
|
85
|
+
table = Table(title="Background Tasks")
|
|
86
|
+
table.add_column("ID", style="cyan")
|
|
87
|
+
table.add_column("Name", style="green")
|
|
88
|
+
table.add_column("Status", style="yellow")
|
|
89
|
+
table.add_column("Progress", style="blue")
|
|
90
|
+
table.add_column("Duration", style="magenta")
|
|
91
|
+
|
|
92
|
+
for task in tasks:
|
|
93
|
+
status = task.get("status", "unknown")
|
|
94
|
+
status_color = {
|
|
95
|
+
"pending": "dim",
|
|
96
|
+
"running": "yellow",
|
|
97
|
+
"completed": "green",
|
|
98
|
+
"failed": "red",
|
|
99
|
+
"cancelled": "dim"
|
|
100
|
+
}.get(status, "white")
|
|
101
|
+
|
|
102
|
+
progress = f"{task.get('progress', 0) * 100:.0f}%"
|
|
103
|
+
duration = task.get("duration_seconds")
|
|
104
|
+
duration_str = f"{duration:.1f}s" if duration else "-"
|
|
105
|
+
|
|
106
|
+
table.add_row(
|
|
107
|
+
task.get("id", "?"),
|
|
108
|
+
task.get("name", "unnamed"),
|
|
109
|
+
f"[{status_color}]{status}[/{status_color}]",
|
|
110
|
+
progress,
|
|
111
|
+
duration_str
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
console.print(table)
|
|
115
|
+
except ImportError:
|
|
116
|
+
print("Background Tasks:")
|
|
117
|
+
for task in tasks:
|
|
118
|
+
print(f" {task.get('id')} - {task.get('name')} ({task.get('status')})")
|
|
119
|
+
|
|
120
|
+
async def get_status(self, task_id: str) -> Optional[dict]:
|
|
121
|
+
"""
|
|
122
|
+
Get status of a specific task.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
task_id: Task ID
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
Task dictionary or None
|
|
129
|
+
"""
|
|
130
|
+
runner = await self._get_runner()
|
|
131
|
+
task = runner.get_task(task_id)
|
|
132
|
+
|
|
133
|
+
if task is None:
|
|
134
|
+
self._print_error(f"Task not found: {task_id}")
|
|
135
|
+
return None
|
|
136
|
+
|
|
137
|
+
task_dict = task.to_dict()
|
|
138
|
+
self._print_task_details(task_dict)
|
|
139
|
+
return task_dict
|
|
140
|
+
|
|
141
|
+
def _print_task_details(self, task: dict):
|
|
142
|
+
"""Print detailed task information."""
|
|
143
|
+
try:
|
|
144
|
+
from rich.console import Console
|
|
145
|
+
from rich.panel import Panel
|
|
146
|
+
|
|
147
|
+
console = Console()
|
|
148
|
+
|
|
149
|
+
status = task.get("status", "unknown")
|
|
150
|
+
status_color = {
|
|
151
|
+
"pending": "dim",
|
|
152
|
+
"running": "yellow",
|
|
153
|
+
"completed": "green",
|
|
154
|
+
"failed": "red",
|
|
155
|
+
"cancelled": "dim"
|
|
156
|
+
}.get(status, "white")
|
|
157
|
+
|
|
158
|
+
content = f"""
|
|
159
|
+
[bold]ID:[/bold] {task.get('id')}
|
|
160
|
+
[bold]Name:[/bold] {task.get('name')}
|
|
161
|
+
[bold]Status:[/bold] [{status_color}]{status}[/{status_color}]
|
|
162
|
+
[bold]Progress:[/bold] {task.get('progress', 0) * 100:.0f}%
|
|
163
|
+
[bold]Created:[/bold] {task.get('created_at')}
|
|
164
|
+
[bold]Started:[/bold] {task.get('started_at') or '-'}
|
|
165
|
+
[bold]Completed:[/bold] {task.get('completed_at') or '-'}
|
|
166
|
+
[bold]Duration:[/bold] {task.get('duration_seconds', 0):.2f}s
|
|
167
|
+
"""
|
|
168
|
+
if task.get("error"):
|
|
169
|
+
content += f"[bold]Error:[/bold] [red]{task.get('error')}[/red]\n"
|
|
170
|
+
|
|
171
|
+
if task.get("result"):
|
|
172
|
+
result_str = str(task.get("result"))[:200]
|
|
173
|
+
content += f"[bold]Result:[/bold] {result_str}\n"
|
|
174
|
+
|
|
175
|
+
console.print(Panel(content.strip(), title=f"Task: {task.get('name')}"))
|
|
176
|
+
except ImportError:
|
|
177
|
+
print(f"Task: {task.get('name')}")
|
|
178
|
+
print(f" ID: {task.get('id')}")
|
|
179
|
+
print(f" Status: {task.get('status')}")
|
|
180
|
+
print(f" Progress: {task.get('progress', 0) * 100:.0f}%")
|
|
181
|
+
|
|
182
|
+
async def cancel_task(self, task_id: str) -> bool:
|
|
183
|
+
"""
|
|
184
|
+
Cancel a running task.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
task_id: Task ID to cancel
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
True if cancelled
|
|
191
|
+
"""
|
|
192
|
+
runner = await self._get_runner()
|
|
193
|
+
result = await runner.cancel_task(task_id)
|
|
194
|
+
|
|
195
|
+
if result:
|
|
196
|
+
self._print_success(f"Task cancelled: {task_id}")
|
|
197
|
+
else:
|
|
198
|
+
self._print_error(f"Could not cancel task: {task_id}")
|
|
199
|
+
|
|
200
|
+
return result
|
|
201
|
+
|
|
202
|
+
async def clear_completed(self) -> int:
|
|
203
|
+
"""
|
|
204
|
+
Clear all completed tasks.
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
Number of tasks cleared
|
|
208
|
+
"""
|
|
209
|
+
runner = await self._get_runner()
|
|
210
|
+
count = len([t for t in runner.tasks if t.is_completed])
|
|
211
|
+
runner.clear_completed()
|
|
212
|
+
|
|
213
|
+
self._print_success(f"Cleared {count} completed tasks")
|
|
214
|
+
return count
|
|
215
|
+
|
|
216
|
+
def _print_success(self, message: str):
|
|
217
|
+
"""Print success message."""
|
|
218
|
+
try:
|
|
219
|
+
from rich.console import Console
|
|
220
|
+
Console().print(f"[green]✓[/green] {message}")
|
|
221
|
+
except ImportError:
|
|
222
|
+
print(f"✓ {message}")
|
|
223
|
+
|
|
224
|
+
def _print_error(self, message: str):
|
|
225
|
+
"""Print error message."""
|
|
226
|
+
try:
|
|
227
|
+
from rich.console import Console
|
|
228
|
+
Console().print(f"[red]✗[/red] {message}")
|
|
229
|
+
except ImportError:
|
|
230
|
+
print(f"✗ {message}")
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def handle_background_command(args: List[str], verbose: bool = False):
|
|
234
|
+
"""
|
|
235
|
+
Handle background CLI commands.
|
|
236
|
+
|
|
237
|
+
Usage:
|
|
238
|
+
praisonai background list [--status <status>]
|
|
239
|
+
praisonai background status <task_id>
|
|
240
|
+
praisonai background cancel <task_id>
|
|
241
|
+
praisonai background clear
|
|
242
|
+
"""
|
|
243
|
+
handler = BackgroundHandler(verbose=verbose)
|
|
244
|
+
|
|
245
|
+
if not args:
|
|
246
|
+
print("Usage: praisonai background <command> [options]")
|
|
247
|
+
print("\nCommands:")
|
|
248
|
+
print(" list [--status <status>] List background tasks")
|
|
249
|
+
print(" status <task_id> Get task status")
|
|
250
|
+
print(" cancel <task_id> Cancel a task")
|
|
251
|
+
print(" clear Clear completed tasks")
|
|
252
|
+
return
|
|
253
|
+
|
|
254
|
+
command = args[0]
|
|
255
|
+
|
|
256
|
+
if command == "list":
|
|
257
|
+
status = None
|
|
258
|
+
if "--status" in args:
|
|
259
|
+
idx = args.index("--status")
|
|
260
|
+
if idx + 1 < len(args):
|
|
261
|
+
status = args[idx + 1]
|
|
262
|
+
|
|
263
|
+
asyncio.run(handler.list_tasks(status=status))
|
|
264
|
+
|
|
265
|
+
elif command == "status":
|
|
266
|
+
if len(args) < 2:
|
|
267
|
+
print("Usage: praisonai background status <task_id>")
|
|
268
|
+
return
|
|
269
|
+
|
|
270
|
+
asyncio.run(handler.get_status(args[1]))
|
|
271
|
+
|
|
272
|
+
elif command == "cancel":
|
|
273
|
+
if len(args) < 2:
|
|
274
|
+
print("Usage: praisonai background cancel <task_id>")
|
|
275
|
+
return
|
|
276
|
+
|
|
277
|
+
asyncio.run(handler.cancel_task(args[1]))
|
|
278
|
+
|
|
279
|
+
elif command == "clear":
|
|
280
|
+
asyncio.run(handler.clear_completed())
|
|
281
|
+
|
|
282
|
+
elif command == "help" or command == "--help":
|
|
283
|
+
print("Background CLI Commands:")
|
|
284
|
+
print("\n praisonai background list [--status <status>]")
|
|
285
|
+
print(" List all background tasks")
|
|
286
|
+
print(" Status: pending, running, completed, failed, cancelled")
|
|
287
|
+
print("\n praisonai background status <task_id>")
|
|
288
|
+
print(" Get detailed status of a specific task")
|
|
289
|
+
print("\n praisonai background cancel <task_id>")
|
|
290
|
+
print(" Cancel a running task")
|
|
291
|
+
print("\n praisonai background clear")
|
|
292
|
+
print(" Clear all completed tasks from the list")
|
|
293
|
+
|
|
294
|
+
else:
|
|
295
|
+
print(f"Unknown command: {command}")
|
|
296
|
+
print("Use 'praisonai background help' for available commands")
|