mirror of
https://github.com/MervinPraison/PraisonAI.git
synced 2026-11-09 17:31:52 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c735a60b2 | ||
|
|
2f5f2f1c13 | ||
|
|
0253073c68 |
No files matched your search
@@ -1246,62 +1246,19 @@ praisonai "Complex task" --metrics --planning
|
||||
|
||||
### Scheduler CLI:
|
||||
|
||||
Run agents 24/7 with built-in safety features. Two modes available:
|
||||
|
||||
**Direct Prompt Mode (Simple):**
|
||||
```bash
|
||||
# No YAML needed - just provide your task
|
||||
praisonai schedule "Check AI news and summarize" --interval hourly
|
||||
|
||||
# With options
|
||||
praisonai schedule "Monitor server logs" \
|
||||
--interval "*/30m" \
|
||||
--timeout 120 \
|
||||
--max-cost 2.00 \
|
||||
--verbose
|
||||
praisonai schedule start <name> "task" --interval hourly
|
||||
praisonai schedule list
|
||||
praisonai schedule logs <name> [--follow]
|
||||
praisonai schedule stop <name>
|
||||
praisonai schedule restart <name>
|
||||
praisonai schedule delete <name>
|
||||
praisonai schedule describe <name>
|
||||
praisonai schedule save <name> [file.yaml]
|
||||
praisonai schedule "task" --interval hourly # foreground mode
|
||||
praisonai schedule agents.yaml # foreground mode
|
||||
```
|
||||
|
||||
**YAML Mode (Advanced):**
|
||||
```bash
|
||||
# Use agents.yaml for complex configurations
|
||||
praisonai schedule agents.yaml
|
||||
|
||||
# With overrides
|
||||
praisonai schedule agents.yaml \
|
||||
--interval "*/15m" \
|
||||
--timeout 60 \
|
||||
--max-cost 1.00
|
||||
|
||||
# Stop: Press Ctrl+C
|
||||
```
|
||||
|
||||
**agents.yaml with schedule:**
|
||||
```yaml
|
||||
framework: praisonai
|
||||
|
||||
agents:
|
||||
- name: "AI News Monitor"
|
||||
instructions: "Search and summarize AI news"
|
||||
tools:
|
||||
- search_tool
|
||||
|
||||
task: "Search for latest AI news"
|
||||
|
||||
schedule:
|
||||
interval: "hourly" # hourly, daily, */30m, */6h
|
||||
max_retries: 3 # Retry on failure
|
||||
run_immediately: true # Run once on start
|
||||
timeout: 60 # Max 60s per execution
|
||||
max_cost: 1.00 # Stop after $1.00 spent
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- ⏱️ Timeout protection (prevent runaway executions)
|
||||
- 💰 Cost monitoring with budget limits
|
||||
- 📊 Real-time statistics (success rate, cost, runtime)
|
||||
- 🔄 Automatic retry with exponential backoff
|
||||
- 🛡️ Auto-stops when budget reached
|
||||
|
||||
### Image Processing CLI:
|
||||
```bash
|
||||
# Process images with vision-based tasks
|
||||
|
||||
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
|
||||
# Install Python packages (using latest versions)
|
||||
RUN pip install --no-cache-dir \
|
||||
praisonai_tools \
|
||||
"praisonai>=2.3.67" \
|
||||
"praisonai>=2.3.70" \
|
||||
"praisonai[chat]" \
|
||||
"embedchain[github,youtube]"
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ RUN mkdir -p /root/.praison
|
||||
# Install Python packages (using latest versions)
|
||||
RUN pip install --no-cache-dir \
|
||||
praisonai_tools \
|
||||
"praisonai>=2.3.67" \
|
||||
"praisonai>=2.3.70" \
|
||||
"praisonai[ui]" \
|
||||
"praisonai[chat]" \
|
||||
"praisonai[realtime]" \
|
||||
|
||||
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
|
||||
# Install Python packages (using latest versions)
|
||||
RUN pip install --no-cache-dir \
|
||||
praisonai_tools \
|
||||
"praisonai>=2.3.67" \
|
||||
"praisonai>=2.3.70" \
|
||||
"praisonai[ui]" \
|
||||
"praisonai[crewai]"
|
||||
|
||||
|
||||
+10
-53
@@ -1246,62 +1246,19 @@ praisonai "Complex task" --metrics --planning
|
||||
|
||||
### Scheduler CLI:
|
||||
|
||||
Run agents 24/7 with built-in safety features. Two modes available:
|
||||
|
||||
**Direct Prompt Mode (Simple):**
|
||||
```bash
|
||||
# No YAML needed - just provide your task
|
||||
praisonai schedule "Check AI news and summarize" --interval hourly
|
||||
|
||||
# With options
|
||||
praisonai schedule "Monitor server logs" \
|
||||
--interval "*/30m" \
|
||||
--timeout 120 \
|
||||
--max-cost 2.00 \
|
||||
--verbose
|
||||
praisonai schedule start <name> "task" --interval hourly
|
||||
praisonai schedule list
|
||||
praisonai schedule logs <name> [--follow]
|
||||
praisonai schedule stop <name>
|
||||
praisonai schedule restart <name>
|
||||
praisonai schedule delete <name>
|
||||
praisonai schedule describe <name>
|
||||
praisonai schedule save <name> [file.yaml]
|
||||
praisonai schedule "task" --interval hourly # foreground mode
|
||||
praisonai schedule agents.yaml # foreground mode
|
||||
```
|
||||
|
||||
**YAML Mode (Advanced):**
|
||||
```bash
|
||||
# Use agents.yaml for complex configurations
|
||||
praisonai schedule agents.yaml
|
||||
|
||||
# With overrides
|
||||
praisonai schedule agents.yaml \
|
||||
--interval "*/15m" \
|
||||
--timeout 60 \
|
||||
--max-cost 1.00
|
||||
|
||||
# Stop: Press Ctrl+C
|
||||
```
|
||||
|
||||
**agents.yaml with schedule:**
|
||||
```yaml
|
||||
framework: praisonai
|
||||
|
||||
agents:
|
||||
- name: "AI News Monitor"
|
||||
instructions: "Search and summarize AI news"
|
||||
tools:
|
||||
- search_tool
|
||||
|
||||
task: "Search for latest AI news"
|
||||
|
||||
schedule:
|
||||
interval: "hourly" # hourly, daily, */30m, */6h
|
||||
max_retries: 3 # Retry on failure
|
||||
run_immediately: true # Run once on start
|
||||
timeout: 60 # Max 60s per execution
|
||||
max_cost: 1.00 # Stop after $1.00 spent
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- ⏱️ Timeout protection (prevent runaway executions)
|
||||
- 💰 Cost monitoring with budget limits
|
||||
- 📊 Real-time statistics (success rate, cost, runtime)
|
||||
- 🔄 Automatic retry with exponential backoff
|
||||
- 🛡️ Auto-stops when budget reached
|
||||
|
||||
### Image Processing CLI:
|
||||
```bash
|
||||
# Process images with vision-based tasks
|
||||
|
||||
@@ -3,8 +3,8 @@ class Praisonai < Formula
|
||||
|
||||
desc "AI tools for various AI applications"
|
||||
homepage "https://github.com/MervinPraison/PraisonAI"
|
||||
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.3.67.tar.gz"
|
||||
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.3.67.tar.gz | shasum -a 256`.split.first
|
||||
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.3.70.tar.gz"
|
||||
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.3.70.tar.gz | shasum -a 256`.split.first
|
||||
license "MIT"
|
||||
|
||||
depends_on "[email protected]"
|
||||
|
||||
@@ -43,8 +43,14 @@ class AgentSchedulerHandler:
|
||||
return AgentSchedulerHandler._handle_restart(unknown_args, state_manager, daemon_manager)
|
||||
elif subcommand == "delete":
|
||||
return AgentSchedulerHandler._handle_delete(unknown_args, state_manager)
|
||||
elif subcommand == "describe":
|
||||
return AgentSchedulerHandler._handle_describe(unknown_args, state_manager, daemon_manager)
|
||||
elif subcommand == "save":
|
||||
return AgentSchedulerHandler._handle_save(unknown_args, state_manager)
|
||||
else:
|
||||
print(f"Unknown subcommand: {subcommand}")
|
||||
print(f"❌ Unknown subcommand: {subcommand}")
|
||||
print("\nAvailable commands:")
|
||||
print(" start, list, stop, logs, restart, delete, describe, save")
|
||||
return 1
|
||||
|
||||
@staticmethod
|
||||
@@ -120,7 +126,8 @@ class AgentSchedulerHandler:
|
||||
print(f" Logs: ~/.praisonai/logs/{name}.log")
|
||||
print(f"\nManage:")
|
||||
print(f" praisonai schedule list")
|
||||
print(f" praisonai schedule logs {name} -f")
|
||||
print(f" praisonai schedule describe {name}")
|
||||
print(f" praisonai schedule logs {name} --follow")
|
||||
print(f" praisonai schedule stop {name}")
|
||||
|
||||
return 0
|
||||
@@ -286,6 +293,128 @@ class AgentSchedulerHandler:
|
||||
print(f"❌ Error: Scheduler '{name}' not found")
|
||||
return 1
|
||||
|
||||
@staticmethod
|
||||
def _handle_describe(unknown_args, state_manager, daemon_manager) -> int:
|
||||
"""Handle 'schedule describe' command."""
|
||||
from datetime import datetime
|
||||
|
||||
if not unknown_args:
|
||||
print("❌ Error: Please provide scheduler name")
|
||||
print("\nUsage: praisonai schedule describe <name>")
|
||||
return 1
|
||||
|
||||
name = unknown_args[0]
|
||||
state = state_manager.load_state(name)
|
||||
|
||||
if not state:
|
||||
print(f"❌ Error: Scheduler '{name}' not found")
|
||||
print("\nList schedulers with: praisonai schedule list")
|
||||
return 1
|
||||
|
||||
# Get process status
|
||||
pid = state.get('pid', 0)
|
||||
is_alive = state_manager.is_process_alive(pid)
|
||||
status = "🟢 running" if is_alive else "🔴 stopped"
|
||||
|
||||
# Calculate uptime
|
||||
started_at = state.get('started_at')
|
||||
uptime = "N/A"
|
||||
if started_at:
|
||||
try:
|
||||
start_time = datetime.fromisoformat(started_at)
|
||||
uptime_delta = datetime.now() - start_time
|
||||
hours = int(uptime_delta.total_seconds() // 3600)
|
||||
minutes = int((uptime_delta.total_seconds() % 3600) // 60)
|
||||
uptime = f"{hours}h {minutes}m"
|
||||
except:
|
||||
pass
|
||||
|
||||
# Display detailed info
|
||||
print(f"\n{'='*60}")
|
||||
print(f"📋 Scheduler Details: {name}")
|
||||
print(f"{'='*60}")
|
||||
print(f"Status: {status}")
|
||||
print(f"PID: {pid}")
|
||||
print(f"Uptime: {uptime}")
|
||||
print(f"Task: {state.get('task', 'N/A')}")
|
||||
print(f"Interval: {state.get('interval', 'N/A')}")
|
||||
print(f"Max Retries: {state.get('max_retries', 'N/A')}")
|
||||
|
||||
if state.get('timeout'):
|
||||
print(f"Timeout: {state['timeout']}s")
|
||||
|
||||
if state.get('max_cost'):
|
||||
print(f"Budget: ${state['max_cost']}")
|
||||
|
||||
print(f"Executions: {state.get('executions', 0)}")
|
||||
print(f"Total Cost: ${state.get('cost', 0.0):.4f}")
|
||||
print(f"Started: {started_at or 'N/A'}")
|
||||
|
||||
# Log file location
|
||||
log_file = daemon_manager.log_dir / f"{name}.log"
|
||||
print(f"Logs: {log_file}")
|
||||
|
||||
print(f"{'='*60}\n")
|
||||
|
||||
return 0
|
||||
|
||||
@staticmethod
|
||||
def _handle_save(unknown_args, state_manager) -> int:
|
||||
"""Handle 'schedule save' command."""
|
||||
import yaml
|
||||
|
||||
if not unknown_args:
|
||||
print("❌ Error: Please provide scheduler name")
|
||||
print("\nUsage: praisonai schedule save <name> [output.yaml]")
|
||||
return 1
|
||||
|
||||
name = unknown_args[0]
|
||||
output_file = unknown_args[1] if len(unknown_args) > 1 else f"{name}.yaml"
|
||||
|
||||
state = state_manager.load_state(name)
|
||||
|
||||
if not state:
|
||||
print(f"❌ Error: Scheduler '{name}' not found")
|
||||
return 1
|
||||
|
||||
# Create YAML config from state
|
||||
yaml_config = {
|
||||
'framework': 'praisonai',
|
||||
'agents': [{
|
||||
'name': name,
|
||||
'role': 'Task Executor',
|
||||
'goal': state.get('task', ''),
|
||||
'instructions': state.get('task', ''),
|
||||
'verbose': True
|
||||
}],
|
||||
'task': state.get('task', ''),
|
||||
'schedule': {
|
||||
'interval': state.get('interval', 'hourly'),
|
||||
'max_retries': state.get('max_retries', 3),
|
||||
'run_immediately': True
|
||||
}
|
||||
}
|
||||
|
||||
# Add optional fields
|
||||
if state.get('timeout'):
|
||||
yaml_config['schedule']['timeout'] = state['timeout']
|
||||
|
||||
if state.get('max_cost'):
|
||||
yaml_config['schedule']['max_cost'] = state['max_cost']
|
||||
|
||||
# Write to file
|
||||
try:
|
||||
with open(output_file, 'w') as f:
|
||||
yaml.dump(yaml_config, f, default_flow_style=False, sort_keys=False)
|
||||
|
||||
print(f"✅ Configuration saved to: {output_file}")
|
||||
print(f"\nRun with:")
|
||||
print(f" praisonai schedule {output_file}")
|
||||
return 0
|
||||
except Exception as e:
|
||||
print(f"❌ Error saving configuration: {e}")
|
||||
return 1
|
||||
|
||||
@staticmethod
|
||||
def handle_schedule_command(args, unknown_args=None) -> int:
|
||||
"""
|
||||
|
||||
@@ -236,7 +236,7 @@ class PraisonAI:
|
||||
# Check for subcommands (start, list, stop, logs, restart)
|
||||
subcommand = unknown_args[0] if unknown_args and not unknown_args[0].startswith('-') else None
|
||||
|
||||
if subcommand in ['start', 'list', 'stop', 'logs', 'restart', 'delete']:
|
||||
if subcommand in ['start', 'list', 'stop', 'logs', 'restart', 'delete', 'describe', 'save']:
|
||||
exit_code = AgentSchedulerHandler.handle_daemon_command(subcommand, args, unknown_args[1:] if len(unknown_args) > 1 else [])
|
||||
else:
|
||||
# Legacy mode: direct scheduling (foreground)
|
||||
|
||||
@@ -57,7 +57,7 @@ class CloudDeployer:
|
||||
file.write("FROM python:3.11-slim\n")
|
||||
file.write("WORKDIR /app\n")
|
||||
file.write("COPY . .\n")
|
||||
file.write("RUN pip install flask praisonai==2.3.67 gunicorn markdown\n")
|
||||
file.write("RUN pip install flask praisonai==2.3.70 gunicorn markdown\n")
|
||||
file.write("EXPOSE 8080\n")
|
||||
file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
|
||||
|
||||
|
||||
@@ -172,6 +172,43 @@ class AgentScheduler:
|
||||
"cost_per_execution": round(self._total_cost / self._execution_count, 4) if self._execution_count > 0 else 0
|
||||
}
|
||||
|
||||
def _update_state_if_daemon(self):
|
||||
"""Update state file with execution stats if running as daemon."""
|
||||
try:
|
||||
import os
|
||||
# Check if we're running as a daemon by looking for state file
|
||||
state_dir = os.path.expanduser("~/.praisonai/schedulers")
|
||||
if not os.path.exists(state_dir):
|
||||
return
|
||||
|
||||
# Try to find our state file by checking all state files for matching PID
|
||||
current_pid = os.getpid()
|
||||
for state_file in os.listdir(state_dir):
|
||||
if not state_file.endswith('.json'):
|
||||
continue
|
||||
|
||||
state_path = os.path.join(state_dir, state_file)
|
||||
try:
|
||||
import json
|
||||
with open(state_path, 'r') as f:
|
||||
state = json.load(f)
|
||||
|
||||
# Check if this is our state file
|
||||
if state.get('pid') == current_pid:
|
||||
# Update execution stats
|
||||
state['executions'] = self._execution_count
|
||||
state['cost'] = round(self._total_cost, 4)
|
||||
|
||||
# Write back
|
||||
with open(state_path, 'w') as f:
|
||||
json.dump(state, f, indent=2)
|
||||
break
|
||||
except Exception:
|
||||
continue
|
||||
except Exception as e:
|
||||
# Silently fail - don't break scheduler if state update fails
|
||||
logger.debug(f"Failed to update state: {e}")
|
||||
|
||||
def _run_schedule(self, interval: int, max_retries: int):
|
||||
"""Internal method to run scheduled agent executions."""
|
||||
while not self._stop_event.is_set():
|
||||
|
||||
@@ -95,15 +95,16 @@ class DaemonManager:
|
||||
Returns:
|
||||
Process ID
|
||||
"""
|
||||
# Build command
|
||||
# Build command - use praisonai CLI to run scheduler in foreground
|
||||
command = [
|
||||
sys.executable,
|
||||
"-m",
|
||||
"praisonai.cli.main",
|
||||
"schedule",
|
||||
task,
|
||||
f'"{task}"', # Quote the task
|
||||
"--interval", interval,
|
||||
"--max-retries", str(max_retries)
|
||||
"--max-retries", str(max_retries),
|
||||
"--verbose" # Enable verbose to see output
|
||||
]
|
||||
|
||||
if timeout:
|
||||
|
||||
@@ -1 +1 @@
|
||||
__version__ = "2.3.67"
|
||||
__version__ = "2.3.70"
|
||||
Reference in new issue
Block a user