praisonAI 2.3.63__tar.gz → 2.3.65__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.63 → praisonai-2.3.65}/PKG-INFO +33 -1
- {praisonai-2.3.63 → praisonai-2.3.65}/PraisonAI.egg-info/PKG-INFO +33 -1
- {praisonai-2.3.63 → praisonai-2.3.65}/PraisonAI.egg-info/SOURCES.txt +7 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/README.md +32 -0
- praisonai-2.3.65/praisonai/agent_scheduler.py +337 -0
- praisonai-2.3.65/praisonai/cli/features/agent_scheduler.py +182 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/main.py +10 -1
- praisonai-2.3.65/praisonai/cli/schedule_cli.py +54 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/deploy.py +1 -1
- praisonai-2.3.65/praisonai/scheduler/__init__.py +36 -0
- praisonai-2.3.65/praisonai/scheduler/agent_scheduler.py +348 -0
- praisonai-2.3.65/praisonai/scheduler/base.py +124 -0
- praisonai-2.3.65/praisonai/scheduler/yaml_loader.py +197 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/scheduler.py +22 -43
- praisonai-2.3.65/praisonai/version.py +1 -0
- praisonai-2.3.63/praisonai/version.py +0 -1
- {praisonai-2.3.63 → praisonai-2.3.65}/PraisonAI.egg-info/dependency_links.txt +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/PraisonAI.egg-info/entry_points.txt +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/PraisonAI.egg-info/requires.txt +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/PraisonAI.egg-info/top_level.txt +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/__init__.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/__main__.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/agents_generator.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/api/call.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/auto.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/chainlit_ui.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/__init__.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/__init__.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/at_mentions.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/auto_memory.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/autonomy_mode.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/base.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/cost_tracker.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/external_agents.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/fast_context.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/flow_display.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/git_integration.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/guardrail.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/handoff.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/image.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/interactive_tui.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/knowledge.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/mcp.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/message_queue.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/metrics.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/n8n.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/repo_map.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/router.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/sandbox_executor.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/session.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/slash_commands.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/telemetry.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/todo.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/tools.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/cli/features/workflow.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/code/__init__.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/code/agent_tools.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/code/diff/__init__.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/code/diff/diff_strategy.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/code/tools/__init__.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/code/tools/apply_diff.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/code/tools/execute_command.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/code/tools/list_files.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/code/tools/read_file.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/code/tools/search_replace.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/code/tools/write_file.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/code/utils/__init__.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/code/utils/file_utils.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/code/utils/ignore_utils.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/code/utils/text_utils.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/inbuilt_tools/__init__.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/inbuilt_tools/autogen_tools.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/inc/__init__.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/inc/config.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/inc/models.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/integrations/__init__.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/integrations/base.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/integrations/claude_code.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/integrations/codex_cli.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/integrations/cursor_cli.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/integrations/gemini_cli.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/profiler.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/setup/__init__.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/setup/build.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/setup/post_install.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/setup/setup_conda_env.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/setup.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/test.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/train.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/train_vision.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/ui/agents.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/ui/callbacks.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/ui/chat.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/ui/code.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/ui/colab.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/ui/colab_chainlit.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/ui/components/aicoder.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/ui/context.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/ui/database_config.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/ui/db.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/ui/realtime.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/ui/realtimeclient/__init__.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/ui/realtimeclient/tools.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/ui/sql_alchemy.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/praisonai/upload_vision.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/pyproject.toml +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/setup.cfg +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/tests/test.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/tests/test_agents_playbook.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/tests/test_approval_system.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/tests/test_basic.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/tests/test_cli_features.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/tests/test_custom_tools_fix.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/tests/test_double_api_fix.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/tests/test_n8n_integration.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/tests/test_phase2_refactor.py +0 -0
- {praisonai-2.3.63 → praisonai-2.3.65}/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.65
|
|
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
|
|
@@ -363,6 +363,8 @@ npm install praisonai
|
|
|
363
363
|
| ↳ Interactive TUI | [Example](examples/python/cli/interactive_tui_example.py) | [📖](https://docs.praison.ai/docs/cli/interactive-tui) |
|
|
364
364
|
| ↳ Git Integration | [Example](examples/python/cli/git_integration_example.py) | [📖](https://docs.praison.ai/docs/cli/git-integration) |
|
|
365
365
|
| ↳ Sandbox Execution | [Example](examples/python/cli/sandbox_execution_example.py) | [📖](https://docs.praison.ai/docs/cli/sandbox-execution) |
|
|
366
|
+
| **⏰ 24/7 Scheduling** | | |
|
|
367
|
+
| ↳ Agent Scheduler | [Example](examples/python/scheduled_agents/news_checker_live.py) | [📖](https://docs.praison.ai/docs/cli/scheduler) |
|
|
366
368
|
|
|
367
369
|
---
|
|
368
370
|
|
|
@@ -1339,6 +1341,36 @@ praisonai "Analyze this data" --metrics
|
|
|
1339
1341
|
praisonai "Complex task" --metrics --planning
|
|
1340
1342
|
```
|
|
1341
1343
|
|
|
1344
|
+
### Scheduler CLI:
|
|
1345
|
+
```bash
|
|
1346
|
+
# Schedule an agent using agents.yaml
|
|
1347
|
+
praisonai schedule agents.yaml
|
|
1348
|
+
|
|
1349
|
+
# Override interval from CLI
|
|
1350
|
+
praisonai schedule agents.yaml --interval "*/30m"
|
|
1351
|
+
|
|
1352
|
+
# With verbose logging
|
|
1353
|
+
praisonai schedule agents.yaml --verbose
|
|
1354
|
+
```
|
|
1355
|
+
|
|
1356
|
+
**agents.yaml with schedule:**
|
|
1357
|
+
```yaml
|
|
1358
|
+
framework: praisonai
|
|
1359
|
+
|
|
1360
|
+
agents:
|
|
1361
|
+
- name: "AI News Monitor"
|
|
1362
|
+
instructions: "Search and summarize AI news"
|
|
1363
|
+
tools:
|
|
1364
|
+
- search_tool
|
|
1365
|
+
|
|
1366
|
+
task: "Search for latest AI news"
|
|
1367
|
+
|
|
1368
|
+
schedule:
|
|
1369
|
+
interval: "hourly" # hourly, daily, */30m, */6h
|
|
1370
|
+
max_retries: 3
|
|
1371
|
+
run_immediately: true
|
|
1372
|
+
```
|
|
1373
|
+
|
|
1342
1374
|
### Image Processing CLI:
|
|
1343
1375
|
```bash
|
|
1344
1376
|
# Process images with vision-based tasks
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PraisonAI
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.65
|
|
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
|
|
@@ -363,6 +363,8 @@ npm install praisonai
|
|
|
363
363
|
| ↳ Interactive TUI | [Example](examples/python/cli/interactive_tui_example.py) | [📖](https://docs.praison.ai/docs/cli/interactive-tui) |
|
|
364
364
|
| ↳ Git Integration | [Example](examples/python/cli/git_integration_example.py) | [📖](https://docs.praison.ai/docs/cli/git-integration) |
|
|
365
365
|
| ↳ Sandbox Execution | [Example](examples/python/cli/sandbox_execution_example.py) | [📖](https://docs.praison.ai/docs/cli/sandbox-execution) |
|
|
366
|
+
| **⏰ 24/7 Scheduling** | | |
|
|
367
|
+
| ↳ Agent Scheduler | [Example](examples/python/scheduled_agents/news_checker_live.py) | [📖](https://docs.praison.ai/docs/cli/scheduler) |
|
|
366
368
|
|
|
367
369
|
---
|
|
368
370
|
|
|
@@ -1339,6 +1341,36 @@ praisonai "Analyze this data" --metrics
|
|
|
1339
1341
|
praisonai "Complex task" --metrics --planning
|
|
1340
1342
|
```
|
|
1341
1343
|
|
|
1344
|
+
### Scheduler CLI:
|
|
1345
|
+
```bash
|
|
1346
|
+
# Schedule an agent using agents.yaml
|
|
1347
|
+
praisonai schedule agents.yaml
|
|
1348
|
+
|
|
1349
|
+
# Override interval from CLI
|
|
1350
|
+
praisonai schedule agents.yaml --interval "*/30m"
|
|
1351
|
+
|
|
1352
|
+
# With verbose logging
|
|
1353
|
+
praisonai schedule agents.yaml --verbose
|
|
1354
|
+
```
|
|
1355
|
+
|
|
1356
|
+
**agents.yaml with schedule:**
|
|
1357
|
+
```yaml
|
|
1358
|
+
framework: praisonai
|
|
1359
|
+
|
|
1360
|
+
agents:
|
|
1361
|
+
- name: "AI News Monitor"
|
|
1362
|
+
instructions: "Search and summarize AI news"
|
|
1363
|
+
tools:
|
|
1364
|
+
- search_tool
|
|
1365
|
+
|
|
1366
|
+
task: "Search for latest AI news"
|
|
1367
|
+
|
|
1368
|
+
schedule:
|
|
1369
|
+
interval: "hourly" # hourly, daily, */30m, */6h
|
|
1370
|
+
max_retries: 3
|
|
1371
|
+
run_immediately: true
|
|
1372
|
+
```
|
|
1373
|
+
|
|
1342
1374
|
### Image Processing CLI:
|
|
1343
1375
|
```bash
|
|
1344
1376
|
# Process images with vision-based tasks
|
|
@@ -8,6 +8,7 @@ PraisonAI.egg-info/requires.txt
|
|
|
8
8
|
PraisonAI.egg-info/top_level.txt
|
|
9
9
|
praisonai/__init__.py
|
|
10
10
|
praisonai/__main__.py
|
|
11
|
+
praisonai/agent_scheduler.py
|
|
11
12
|
praisonai/agents_generator.py
|
|
12
13
|
praisonai/auto.py
|
|
13
14
|
praisonai/chainlit_ui.py
|
|
@@ -23,7 +24,9 @@ praisonai/version.py
|
|
|
23
24
|
praisonai/api/call.py
|
|
24
25
|
praisonai/cli/__init__.py
|
|
25
26
|
praisonai/cli/main.py
|
|
27
|
+
praisonai/cli/schedule_cli.py
|
|
26
28
|
praisonai/cli/features/__init__.py
|
|
29
|
+
praisonai/cli/features/agent_scheduler.py
|
|
27
30
|
praisonai/cli/features/at_mentions.py
|
|
28
31
|
praisonai/cli/features/auto_memory.py
|
|
29
32
|
praisonai/cli/features/autonomy_mode.py
|
|
@@ -77,6 +80,10 @@ praisonai/integrations/claude_code.py
|
|
|
77
80
|
praisonai/integrations/codex_cli.py
|
|
78
81
|
praisonai/integrations/cursor_cli.py
|
|
79
82
|
praisonai/integrations/gemini_cli.py
|
|
83
|
+
praisonai/scheduler/__init__.py
|
|
84
|
+
praisonai/scheduler/agent_scheduler.py
|
|
85
|
+
praisonai/scheduler/base.py
|
|
86
|
+
praisonai/scheduler/yaml_loader.py
|
|
80
87
|
praisonai/setup/__init__.py
|
|
81
88
|
praisonai/setup/build.py
|
|
82
89
|
praisonai/setup/post_install.py
|
|
@@ -266,6 +266,8 @@ npm install praisonai
|
|
|
266
266
|
| ↳ Interactive TUI | [Example](examples/python/cli/interactive_tui_example.py) | [📖](https://docs.praison.ai/docs/cli/interactive-tui) |
|
|
267
267
|
| ↳ Git Integration | [Example](examples/python/cli/git_integration_example.py) | [📖](https://docs.praison.ai/docs/cli/git-integration) |
|
|
268
268
|
| ↳ Sandbox Execution | [Example](examples/python/cli/sandbox_execution_example.py) | [📖](https://docs.praison.ai/docs/cli/sandbox-execution) |
|
|
269
|
+
| **⏰ 24/7 Scheduling** | | |
|
|
270
|
+
| ↳ Agent Scheduler | [Example](examples/python/scheduled_agents/news_checker_live.py) | [📖](https://docs.praison.ai/docs/cli/scheduler) |
|
|
269
271
|
|
|
270
272
|
---
|
|
271
273
|
|
|
@@ -1242,6 +1244,36 @@ praisonai "Analyze this data" --metrics
|
|
|
1242
1244
|
praisonai "Complex task" --metrics --planning
|
|
1243
1245
|
```
|
|
1244
1246
|
|
|
1247
|
+
### Scheduler CLI:
|
|
1248
|
+
```bash
|
|
1249
|
+
# Schedule an agent using agents.yaml
|
|
1250
|
+
praisonai schedule agents.yaml
|
|
1251
|
+
|
|
1252
|
+
# Override interval from CLI
|
|
1253
|
+
praisonai schedule agents.yaml --interval "*/30m"
|
|
1254
|
+
|
|
1255
|
+
# With verbose logging
|
|
1256
|
+
praisonai schedule agents.yaml --verbose
|
|
1257
|
+
```
|
|
1258
|
+
|
|
1259
|
+
**agents.yaml with schedule:**
|
|
1260
|
+
```yaml
|
|
1261
|
+
framework: praisonai
|
|
1262
|
+
|
|
1263
|
+
agents:
|
|
1264
|
+
- name: "AI News Monitor"
|
|
1265
|
+
instructions: "Search and summarize AI news"
|
|
1266
|
+
tools:
|
|
1267
|
+
- search_tool
|
|
1268
|
+
|
|
1269
|
+
task: "Search for latest AI news"
|
|
1270
|
+
|
|
1271
|
+
schedule:
|
|
1272
|
+
interval: "hourly" # hourly, daily, */30m, */6h
|
|
1273
|
+
max_retries: 3
|
|
1274
|
+
run_immediately: true
|
|
1275
|
+
```
|
|
1276
|
+
|
|
1245
1277
|
### Image Processing CLI:
|
|
1246
1278
|
```bash
|
|
1247
1279
|
# Process images with vision-based tasks
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent Scheduler for PraisonAI - Run agents periodically 24/7.
|
|
3
|
+
|
|
4
|
+
This module provides scheduling capabilities for running PraisonAI agents
|
|
5
|
+
at regular intervals, enabling 24/7 autonomous agent operations.
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
# Run news checker every hour
|
|
9
|
+
from praisonai.agent_scheduler import AgentScheduler
|
|
10
|
+
from praisonai_agents import Agent
|
|
11
|
+
|
|
12
|
+
agent = Agent(
|
|
13
|
+
name="NewsChecker",
|
|
14
|
+
instructions="Check latest AI news and summarize",
|
|
15
|
+
tools=[search_tool]
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
scheduler = AgentScheduler(agent, task="Check latest AI news")
|
|
19
|
+
scheduler.start(schedule_expr="hourly")
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
import threading
|
|
23
|
+
import time
|
|
24
|
+
import logging
|
|
25
|
+
from datetime import datetime
|
|
26
|
+
from typing import Optional, Dict, Any, Callable
|
|
27
|
+
from abc import ABC, abstractmethod
|
|
28
|
+
|
|
29
|
+
logger = logging.getLogger(__name__)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ScheduleParser:
|
|
33
|
+
"""Parse schedule expressions into intervals."""
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def parse(schedule_expr: str) -> int:
|
|
37
|
+
"""
|
|
38
|
+
Parse schedule expression and return interval in seconds.
|
|
39
|
+
|
|
40
|
+
Supported formats:
|
|
41
|
+
- "daily" -> 86400 seconds
|
|
42
|
+
- "hourly" -> 3600 seconds
|
|
43
|
+
- "*/30m" -> 1800 seconds (every 30 minutes)
|
|
44
|
+
- "*/1h" -> 3600 seconds (every 1 hour)
|
|
45
|
+
- "60" -> 60 seconds (plain number)
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
schedule_expr: Schedule expression string
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
Interval in seconds
|
|
52
|
+
|
|
53
|
+
Raises:
|
|
54
|
+
ValueError: If schedule format is not supported
|
|
55
|
+
"""
|
|
56
|
+
schedule_expr = schedule_expr.strip().lower()
|
|
57
|
+
|
|
58
|
+
if schedule_expr == "daily":
|
|
59
|
+
return 86400
|
|
60
|
+
elif schedule_expr == "hourly":
|
|
61
|
+
return 3600
|
|
62
|
+
elif schedule_expr.isdigit():
|
|
63
|
+
return int(schedule_expr)
|
|
64
|
+
elif schedule_expr.startswith("*/"):
|
|
65
|
+
interval_part = schedule_expr[2:]
|
|
66
|
+
if interval_part.endswith("m"):
|
|
67
|
+
minutes = int(interval_part[:-1])
|
|
68
|
+
return minutes * 60
|
|
69
|
+
elif interval_part.endswith("h"):
|
|
70
|
+
hours = int(interval_part[:-1])
|
|
71
|
+
return hours * 3600
|
|
72
|
+
elif interval_part.endswith("s"):
|
|
73
|
+
return int(interval_part[:-1])
|
|
74
|
+
else:
|
|
75
|
+
return int(interval_part)
|
|
76
|
+
else:
|
|
77
|
+
raise ValueError(f"Unsupported schedule format: {schedule_expr}")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class AgentExecutorInterface(ABC):
|
|
81
|
+
"""Abstract interface for agent execution."""
|
|
82
|
+
|
|
83
|
+
@abstractmethod
|
|
84
|
+
def execute(self, task: str) -> Any:
|
|
85
|
+
"""Execute the agent with given task."""
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class PraisonAgentExecutor(AgentExecutorInterface):
|
|
90
|
+
"""Executor for PraisonAI agents."""
|
|
91
|
+
|
|
92
|
+
def __init__(self, agent):
|
|
93
|
+
"""
|
|
94
|
+
Initialize executor with a PraisonAI agent.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
agent: PraisonAI Agent instance
|
|
98
|
+
"""
|
|
99
|
+
self.agent = agent
|
|
100
|
+
|
|
101
|
+
def execute(self, task: str) -> Any:
|
|
102
|
+
"""
|
|
103
|
+
Execute the agent with given task.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
task: Task description for the agent
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
Agent execution result
|
|
110
|
+
"""
|
|
111
|
+
try:
|
|
112
|
+
result = self.agent.start(task)
|
|
113
|
+
return result
|
|
114
|
+
except Exception as e:
|
|
115
|
+
logger.error(f"Agent execution failed: {e}")
|
|
116
|
+
raise
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class AgentScheduler:
|
|
120
|
+
"""
|
|
121
|
+
Scheduler for running PraisonAI agents periodically.
|
|
122
|
+
|
|
123
|
+
Features:
|
|
124
|
+
- Interval-based scheduling (hourly, daily, custom)
|
|
125
|
+
- Thread-safe operation
|
|
126
|
+
- Automatic retry on failure
|
|
127
|
+
- Execution logging and monitoring
|
|
128
|
+
- Graceful shutdown
|
|
129
|
+
|
|
130
|
+
Example:
|
|
131
|
+
scheduler = AgentScheduler(agent, task="Check news")
|
|
132
|
+
scheduler.start(schedule_expr="hourly", max_retries=3)
|
|
133
|
+
# Agent runs every hour automatically
|
|
134
|
+
scheduler.stop() # Stop when needed
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
def __init__(
|
|
138
|
+
self,
|
|
139
|
+
agent,
|
|
140
|
+
task: str,
|
|
141
|
+
config: Optional[Dict[str, Any]] = None,
|
|
142
|
+
on_success: Optional[Callable] = None,
|
|
143
|
+
on_failure: Optional[Callable] = None
|
|
144
|
+
):
|
|
145
|
+
"""
|
|
146
|
+
Initialize agent scheduler.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
agent: PraisonAI Agent instance
|
|
150
|
+
task: Task description to execute
|
|
151
|
+
config: Optional configuration dict
|
|
152
|
+
on_success: Callback function on successful execution
|
|
153
|
+
on_failure: Callback function on failed execution
|
|
154
|
+
"""
|
|
155
|
+
self.agent = agent
|
|
156
|
+
self.task = task
|
|
157
|
+
self.config = config or {}
|
|
158
|
+
self.on_success = on_success
|
|
159
|
+
self.on_failure = on_failure
|
|
160
|
+
|
|
161
|
+
self.is_running = False
|
|
162
|
+
self._stop_event = threading.Event()
|
|
163
|
+
self._thread = None
|
|
164
|
+
self._executor = PraisonAgentExecutor(agent)
|
|
165
|
+
self._execution_count = 0
|
|
166
|
+
self._success_count = 0
|
|
167
|
+
self._failure_count = 0
|
|
168
|
+
|
|
169
|
+
def start(
|
|
170
|
+
self,
|
|
171
|
+
schedule_expr: str,
|
|
172
|
+
max_retries: int = 3,
|
|
173
|
+
run_immediately: bool = False
|
|
174
|
+
) -> bool:
|
|
175
|
+
"""
|
|
176
|
+
Start scheduled agent execution.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
schedule_expr: Schedule expression (e.g., "hourly", "*/1h", "3600")
|
|
180
|
+
max_retries: Maximum retry attempts on failure
|
|
181
|
+
run_immediately: If True, run agent immediately before starting schedule
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
True if scheduler started successfully
|
|
185
|
+
"""
|
|
186
|
+
if self.is_running:
|
|
187
|
+
logger.warning("Scheduler is already running")
|
|
188
|
+
return False
|
|
189
|
+
|
|
190
|
+
try:
|
|
191
|
+
interval = ScheduleParser.parse(schedule_expr)
|
|
192
|
+
self.is_running = True
|
|
193
|
+
self._stop_event.clear()
|
|
194
|
+
|
|
195
|
+
logger.info(f"Starting agent scheduler: {self.agent.name if hasattr(self.agent, 'name') else 'Agent'}")
|
|
196
|
+
logger.info(f"Task: {self.task}")
|
|
197
|
+
logger.info(f"Schedule: {schedule_expr} ({interval}s interval)")
|
|
198
|
+
logger.info(f"Max retries: {max_retries}")
|
|
199
|
+
|
|
200
|
+
# Run immediately if requested
|
|
201
|
+
if run_immediately:
|
|
202
|
+
logger.info("Running agent immediately before starting schedule...")
|
|
203
|
+
self._execute_with_retry(max_retries)
|
|
204
|
+
|
|
205
|
+
self._thread = threading.Thread(
|
|
206
|
+
target=self._run_schedule,
|
|
207
|
+
args=(interval, max_retries),
|
|
208
|
+
daemon=True
|
|
209
|
+
)
|
|
210
|
+
self._thread.start()
|
|
211
|
+
|
|
212
|
+
logger.info("Agent scheduler started successfully")
|
|
213
|
+
return True
|
|
214
|
+
|
|
215
|
+
except Exception as e:
|
|
216
|
+
logger.error(f"Failed to start scheduler: {e}")
|
|
217
|
+
self.is_running = False
|
|
218
|
+
return False
|
|
219
|
+
|
|
220
|
+
def stop(self) -> bool:
|
|
221
|
+
"""
|
|
222
|
+
Stop the scheduler gracefully.
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
True if stopped successfully
|
|
226
|
+
"""
|
|
227
|
+
if not self.is_running:
|
|
228
|
+
logger.info("Scheduler is not running")
|
|
229
|
+
return True
|
|
230
|
+
|
|
231
|
+
logger.info("Stopping agent scheduler...")
|
|
232
|
+
self._stop_event.set()
|
|
233
|
+
|
|
234
|
+
if self._thread and self._thread.is_alive():
|
|
235
|
+
self._thread.join(timeout=10)
|
|
236
|
+
|
|
237
|
+
self.is_running = False
|
|
238
|
+
logger.info("Agent scheduler stopped")
|
|
239
|
+
logger.info(f"Execution stats - Total: {self._execution_count}, Success: {self._success_count}, Failed: {self._failure_count}")
|
|
240
|
+
return True
|
|
241
|
+
|
|
242
|
+
def get_stats(self) -> Dict[str, Any]:
|
|
243
|
+
"""
|
|
244
|
+
Get execution statistics.
|
|
245
|
+
|
|
246
|
+
Returns:
|
|
247
|
+
Dictionary with execution stats
|
|
248
|
+
"""
|
|
249
|
+
return {
|
|
250
|
+
"is_running": self.is_running,
|
|
251
|
+
"total_executions": self._execution_count,
|
|
252
|
+
"successful_executions": self._success_count,
|
|
253
|
+
"failed_executions": self._failure_count,
|
|
254
|
+
"success_rate": (self._success_count / self._execution_count * 100) if self._execution_count > 0 else 0
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
def _run_schedule(self, interval: int, max_retries: int):
|
|
258
|
+
"""Internal method to run scheduled agent executions."""
|
|
259
|
+
while not self._stop_event.is_set():
|
|
260
|
+
logger.info(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Starting scheduled agent execution")
|
|
261
|
+
|
|
262
|
+
self._execute_with_retry(max_retries)
|
|
263
|
+
|
|
264
|
+
# Wait for next scheduled time
|
|
265
|
+
logger.info(f"Next execution in {interval} seconds ({interval/3600:.1f} hours)")
|
|
266
|
+
self._stop_event.wait(interval)
|
|
267
|
+
|
|
268
|
+
def _execute_with_retry(self, max_retries: int):
|
|
269
|
+
"""Execute agent with retry logic."""
|
|
270
|
+
self._execution_count += 1
|
|
271
|
+
success = False
|
|
272
|
+
|
|
273
|
+
for attempt in range(max_retries):
|
|
274
|
+
try:
|
|
275
|
+
logger.info(f"Attempt {attempt + 1}/{max_retries}")
|
|
276
|
+
result = self._executor.execute(self.task)
|
|
277
|
+
|
|
278
|
+
logger.info(f"Agent execution successful on attempt {attempt + 1}")
|
|
279
|
+
logger.info(f"Result: {result}")
|
|
280
|
+
|
|
281
|
+
self._success_count += 1
|
|
282
|
+
success = True
|
|
283
|
+
|
|
284
|
+
if self.on_success:
|
|
285
|
+
self.on_success(result)
|
|
286
|
+
|
|
287
|
+
break
|
|
288
|
+
|
|
289
|
+
except Exception as e:
|
|
290
|
+
logger.error(f"Agent execution failed on attempt {attempt + 1}: {e}")
|
|
291
|
+
|
|
292
|
+
if attempt < max_retries - 1:
|
|
293
|
+
wait_time = 30 * (attempt + 1) # Exponential backoff
|
|
294
|
+
logger.info(f"Waiting {wait_time}s before retry...")
|
|
295
|
+
time.sleep(wait_time)
|
|
296
|
+
|
|
297
|
+
if not success:
|
|
298
|
+
self._failure_count += 1
|
|
299
|
+
logger.error(f"Agent execution failed after {max_retries} attempts")
|
|
300
|
+
|
|
301
|
+
if self.on_failure:
|
|
302
|
+
self.on_failure(f"Failed after {max_retries} attempts")
|
|
303
|
+
|
|
304
|
+
def execute_once(self) -> Any:
|
|
305
|
+
"""
|
|
306
|
+
Execute agent immediately (one-time execution).
|
|
307
|
+
|
|
308
|
+
Returns:
|
|
309
|
+
Agent execution result
|
|
310
|
+
"""
|
|
311
|
+
logger.info("Executing agent once")
|
|
312
|
+
try:
|
|
313
|
+
result = self._executor.execute(self.task)
|
|
314
|
+
logger.info(f"One-time execution successful: {result}")
|
|
315
|
+
return result
|
|
316
|
+
except Exception as e:
|
|
317
|
+
logger.error(f"One-time execution failed: {e}")
|
|
318
|
+
raise
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def create_agent_scheduler(
|
|
322
|
+
agent,
|
|
323
|
+
task: str,
|
|
324
|
+
config: Optional[Dict[str, Any]] = None
|
|
325
|
+
) -> AgentScheduler:
|
|
326
|
+
"""
|
|
327
|
+
Factory function to create agent scheduler.
|
|
328
|
+
|
|
329
|
+
Args:
|
|
330
|
+
agent: PraisonAI Agent instance
|
|
331
|
+
task: Task description
|
|
332
|
+
config: Optional configuration
|
|
333
|
+
|
|
334
|
+
Returns:
|
|
335
|
+
Configured AgentScheduler instance
|
|
336
|
+
"""
|
|
337
|
+
return AgentScheduler(agent, task, config)
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent Scheduler CLI Feature.
|
|
3
|
+
|
|
4
|
+
Provides CLI commands for scheduling agents to run 24/7 at regular intervals.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AgentSchedulerHandler:
|
|
13
|
+
"""Handler for agent scheduler CLI commands."""
|
|
14
|
+
|
|
15
|
+
@staticmethod
|
|
16
|
+
def handle_schedule_command(args) -> int:
|
|
17
|
+
"""
|
|
18
|
+
Handle the schedule command for running agents periodically.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
args: Parsed command-line arguments
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
Exit code (0 for success, 1 for error)
|
|
25
|
+
"""
|
|
26
|
+
try:
|
|
27
|
+
from praisonai.scheduler import AgentScheduler
|
|
28
|
+
except ImportError:
|
|
29
|
+
print("Error: praisonai.scheduler module not found")
|
|
30
|
+
print("Please ensure PraisonAI is properly installed")
|
|
31
|
+
return 1
|
|
32
|
+
|
|
33
|
+
# Get YAML file path (default to agents.yaml)
|
|
34
|
+
yaml_path = getattr(args, 'schedule_yaml', None) or 'agents.yaml'
|
|
35
|
+
|
|
36
|
+
# Get overrides from CLI
|
|
37
|
+
interval_override = getattr(args, 'schedule_interval', None)
|
|
38
|
+
max_retries_override = getattr(args, 'schedule_max_retries', None)
|
|
39
|
+
verbose = getattr(args, 'verbose', False)
|
|
40
|
+
|
|
41
|
+
# Set up logging
|
|
42
|
+
if verbose:
|
|
43
|
+
logging.basicConfig(
|
|
44
|
+
level=logging.INFO,
|
|
45
|
+
format='[%(asctime)s] %(levelname)s - %(message)s',
|
|
46
|
+
datefmt='%Y-%m-%d %H:%M:%S'
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
# Create scheduler from YAML
|
|
51
|
+
print(f"🤖 Loading agent configuration from: {yaml_path}")
|
|
52
|
+
scheduler = AgentScheduler.from_yaml(
|
|
53
|
+
yaml_path=yaml_path,
|
|
54
|
+
interval_override=interval_override,
|
|
55
|
+
max_retries_override=max_retries_override
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# Display configuration
|
|
59
|
+
agent_name = getattr(scheduler.agent, 'name', 'Agent')
|
|
60
|
+
print(f"\n{'='*60}")
|
|
61
|
+
print(f"🤖 Starting 24/7 {agent_name}")
|
|
62
|
+
print(f"{'='*60}")
|
|
63
|
+
print(f"Task: {scheduler.task[:80]}{'...' if len(scheduler.task) > 80 else ''}")
|
|
64
|
+
|
|
65
|
+
# Get schedule info
|
|
66
|
+
schedule_config = scheduler._yaml_schedule_config
|
|
67
|
+
interval = interval_override or schedule_config.get('interval', 'hourly')
|
|
68
|
+
max_retries = max_retries_override or schedule_config.get('max_retries', 3)
|
|
69
|
+
|
|
70
|
+
print(f"Schedule: {interval}")
|
|
71
|
+
print(f"Max Retries: {max_retries}")
|
|
72
|
+
print(f"{'='*60}\n")
|
|
73
|
+
|
|
74
|
+
# Start scheduler
|
|
75
|
+
print("⏰ Starting scheduler... (Press Ctrl+C to stop)\n")
|
|
76
|
+
scheduler.start_from_yaml_config()
|
|
77
|
+
|
|
78
|
+
# Keep running until interrupted
|
|
79
|
+
try:
|
|
80
|
+
while scheduler.is_running:
|
|
81
|
+
import time
|
|
82
|
+
time.sleep(1)
|
|
83
|
+
except KeyboardInterrupt:
|
|
84
|
+
print("\n\n🛑 Stopping scheduler...")
|
|
85
|
+
scheduler.stop()
|
|
86
|
+
|
|
87
|
+
# Display final stats
|
|
88
|
+
stats = scheduler.get_stats()
|
|
89
|
+
print("\n📊 Final Statistics:")
|
|
90
|
+
print(f" Total Executions: {stats['total_executions']}")
|
|
91
|
+
print(f" Successful: {stats['successful_executions']}")
|
|
92
|
+
print(f" Failed: {stats['failed_executions']}")
|
|
93
|
+
print(f" Success Rate: {stats['success_rate']:.1f}%")
|
|
94
|
+
print("\n✅ Agent stopped successfully\n")
|
|
95
|
+
|
|
96
|
+
return 0
|
|
97
|
+
|
|
98
|
+
except FileNotFoundError as e:
|
|
99
|
+
print(f"❌ Error: {e}")
|
|
100
|
+
print(f"\nMake sure {yaml_path} exists in the current directory.")
|
|
101
|
+
print("\nExample agents.yaml structure:")
|
|
102
|
+
print("""
|
|
103
|
+
framework: praisonai
|
|
104
|
+
|
|
105
|
+
agents:
|
|
106
|
+
- name: "AI News Monitor"
|
|
107
|
+
role: "News Analyst"
|
|
108
|
+
instructions: "Search and summarize AI news"
|
|
109
|
+
tools:
|
|
110
|
+
- search_tool
|
|
111
|
+
|
|
112
|
+
task: "Search for latest AI news"
|
|
113
|
+
|
|
114
|
+
schedule:
|
|
115
|
+
interval: "hourly"
|
|
116
|
+
max_retries: 3
|
|
117
|
+
run_immediately: true
|
|
118
|
+
""")
|
|
119
|
+
return 1
|
|
120
|
+
|
|
121
|
+
except ValueError as e:
|
|
122
|
+
print(f"❌ Configuration Error: {e}")
|
|
123
|
+
return 1
|
|
124
|
+
|
|
125
|
+
except Exception as e:
|
|
126
|
+
print(f"❌ Error: {e}")
|
|
127
|
+
if verbose:
|
|
128
|
+
import traceback
|
|
129
|
+
traceback.print_exc()
|
|
130
|
+
return 1
|
|
131
|
+
|
|
132
|
+
@staticmethod
|
|
133
|
+
def add_schedule_arguments(subparsers):
|
|
134
|
+
"""
|
|
135
|
+
Add schedule subcommand and arguments to parser.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
subparsers: Subparsers object from argparse
|
|
139
|
+
"""
|
|
140
|
+
schedule_parser = subparsers.add_parser(
|
|
141
|
+
'schedule',
|
|
142
|
+
help='Schedule an agent to run continuously at regular intervals'
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
schedule_parser.add_argument(
|
|
146
|
+
'schedule_yaml',
|
|
147
|
+
nargs='?',
|
|
148
|
+
default='agents.yaml',
|
|
149
|
+
help='Path to agents.yaml file (default: agents.yaml)'
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
schedule_parser.add_argument(
|
|
153
|
+
'--interval',
|
|
154
|
+
dest='schedule_interval',
|
|
155
|
+
type=str,
|
|
156
|
+
help='Override schedule interval (e.g., "hourly", "*/30m", "daily")'
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
schedule_parser.add_argument(
|
|
160
|
+
'--max-retries',
|
|
161
|
+
dest='schedule_max_retries',
|
|
162
|
+
type=int,
|
|
163
|
+
help='Override maximum retry attempts (default: from YAML or 3)'
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
schedule_parser.add_argument(
|
|
167
|
+
'--verbose', '-v',
|
|
168
|
+
action='store_true',
|
|
169
|
+
help='Enable verbose logging'
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
schedule_parser.set_defaults(func=AgentSchedulerHandler.handle_schedule_command)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def setup_scheduler_cli(subparsers):
|
|
176
|
+
"""
|
|
177
|
+
Setup scheduler CLI commands.
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
subparsers: Subparsers object from argparse
|
|
181
|
+
"""
|
|
182
|
+
AgentSchedulerHandler.add_schedule_arguments(subparsers)
|