- Reset master to upstream/main (16,697 commits) - Overlay 2,271 local-only files (skills, tools, workspace, configs, apps) - Restore IDENTITY.md and USER.md templates - Build verified, gateway running, Discord working Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
179 lines
5.5 KiB
Bash
179 lines
5.5 KiB
Bash
#!/usr/bin/env bash
|
|
# Jarvis Error Daemon - Kontinuerlig overvågning af agent sessions med auto-healing
|
|
# Inspireret af Reddit self-healing loop mellem Claude Code og OpenClaw
|
|
|
|
set -euo pipefail
|
|
|
|
REPO_ROOT="/home/alex/clawd"
|
|
LOG_DIR="/home/alex/clawd/logs"
|
|
ERROR_LOG="$LOG_DIR/jarvis-errors.log"
|
|
HEALING_LOG="$LOG_DIR/jarvis-healing.log"
|
|
SESSION_DIR="$HOME/.openclaw/agents/free/sessions"
|
|
CHECK_INTERVAL=30 # Tjek hver 30 sekunder
|
|
MAX_RETRIES=3
|
|
|
|
# Healing agent configuration (Claude Sonnet for troubleshooting)
|
|
HEALING_AGENT="sonnet"
|
|
HEALING_TIMEOUT=300 # 5 min for troubleshooting
|
|
|
|
mkdir -p "$LOG_DIR"
|
|
|
|
log() {
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$ERROR_LOG"
|
|
}
|
|
|
|
healing_log() {
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$HEALING_LOG"
|
|
}
|
|
|
|
# Extract error bundle from session log
|
|
extract_error_bundle() {
|
|
local session_file="$1"
|
|
|
|
# Find last error/failure in session
|
|
local error_context=$(tail -100 "$session_file" | grep -A 10 -B 10 -E "(Error:|Exception:|failed|ELIFECYCLE|Command failed)" || echo "")
|
|
|
|
if [[ -z "$error_context" ]]; then
|
|
return 1
|
|
fi
|
|
|
|
# Extract task context (first 50 lines of session)
|
|
local task_context=$(head -50 "$session_file")
|
|
|
|
# Build error bundle
|
|
cat <<EOF
|
|
## Error Bundle
|
|
|
|
### Task Context
|
|
$task_context
|
|
|
|
### Error Details
|
|
$error_context
|
|
|
|
### Full Session Path
|
|
$session_file
|
|
EOF
|
|
}
|
|
|
|
# Spawn healing agent to diagnose and fix
|
|
heal_error() {
|
|
local session_file="$1"
|
|
local task_id="$2"
|
|
local retry_count="$3"
|
|
|
|
healing_log "🔧 Healing session: $session_file (retry $retry_count/$MAX_RETRIES)"
|
|
|
|
# Extract error bundle
|
|
local error_bundle=$(extract_error_bundle "$session_file")
|
|
if [[ -z "$error_bundle" ]]; then
|
|
healing_log "⚠️ No clear error found in session"
|
|
return 1
|
|
fi
|
|
|
|
# Build healing prompt
|
|
local healing_prompt="**Self-Healing Error Analysis**
|
|
|
|
You are debugging an OpenClaw agent task that failed. Analyze the error bundle below and:
|
|
|
|
1. **Diagnose** the root cause
|
|
2. **Propose** a fix (code change, dependency, config, or retry strategy)
|
|
3. **Apply** the fix if possible (edit files, install deps, etc.)
|
|
4. **Verify** the fix would work
|
|
|
|
$error_bundle
|
|
|
|
**Your goal:** Make this task succeed. Be specific about what needs to change."
|
|
|
|
# Spawn healing agent
|
|
healing_log "🤖 Spawning healing agent ($HEALING_AGENT)..."
|
|
local healing_result=$(cd "$REPO_ROOT" && pnpm -s openclaw agent \
|
|
--local \
|
|
--json \
|
|
--agent "$HEALING_AGENT" \
|
|
--timeout "$HEALING_TIMEOUT" \
|
|
--message "$healing_prompt" 2>&1) || true
|
|
|
|
healing_log "📋 Healing result: $healing_result"
|
|
|
|
# Check if healing agent suggested a retry
|
|
if echo "$healing_result" | grep -qi "retry\|re-run\|try again"; then
|
|
healing_log "✅ Healing agent suggests retry"
|
|
return 0
|
|
else
|
|
healing_log "⚠️ Healing agent did not suggest retry"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Monitor sessions and trigger healing
|
|
monitor_sessions() {
|
|
log "🚀 Starting Jarvis Error Daemon (check interval: ${CHECK_INTERVAL}s)"
|
|
|
|
# Track failed sessions to avoid duplicate healing
|
|
declare -A failed_sessions
|
|
declare -A retry_counts
|
|
|
|
while true; do
|
|
# Find recent session files (last 1 hour)
|
|
while IFS= read -r -d '' session_file; do
|
|
local session_id=$(basename "$session_file" .jsonl)
|
|
|
|
# Skip if already processed
|
|
if [[ -n "${failed_sessions[$session_id]:-}" ]]; then
|
|
continue
|
|
fi
|
|
|
|
# Check for errors in session
|
|
if grep -qE "(Error:|Exception:|failed|ELIFECYCLE|Command failed)" "$session_file"; then
|
|
log "🚨 Error detected in session: $session_id"
|
|
|
|
# Mark as failed
|
|
failed_sessions[$session_id]=1
|
|
retry_counts[$session_id]=0
|
|
|
|
# Extract task ID if available
|
|
local task_id=$(grep -oP '(?<=task:)\d+' "$session_file" | head -1 || echo "unknown")
|
|
|
|
# Attempt healing
|
|
if heal_error "$session_file" "$task_id" "${retry_counts[$session_id]}"; then
|
|
# Retry the task
|
|
retry_counts[$session_id]=$((${retry_counts[$session_id]} + 1))
|
|
|
|
if [[ ${retry_counts[$session_id]} -le $MAX_RETRIES ]]; then
|
|
healing_log "🔄 Retry $retry_count/$MAX_RETRIES for task $task_id"
|
|
|
|
# Re-run task (implement actual retry logic here)
|
|
# This would call jarvis-delegate.sh or delegate-with-healing.sh
|
|
# For now, just log
|
|
healing_log "TODO: Re-run task $task_id"
|
|
else
|
|
healing_log "❌ Max retries exceeded for task $task_id"
|
|
fi
|
|
fi
|
|
fi
|
|
done < <(find "$SESSION_DIR" -name "*.jsonl" -mmin -60 -print0 2>/dev/null)
|
|
|
|
sleep "$CHECK_INTERVAL"
|
|
done
|
|
}
|
|
|
|
# Main
|
|
case "${1:-monitor}" in
|
|
monitor)
|
|
monitor_sessions
|
|
;;
|
|
test)
|
|
log "🧪 Testing error detection..."
|
|
if [[ -n "${2:-}" ]]; then
|
|
extract_error_bundle "$2"
|
|
else
|
|
echo "Usage: $0 test <session-file>"
|
|
exit 1
|
|
fi
|
|
;;
|
|
*)
|
|
echo "Usage: $0 {monitor|test <session-file>}"
|
|
exit 1
|
|
;;
|
|
esac
|