KRITISCHES SICHERHEITSUPDATE für alle 17 Waldwächter-Scripts. Problem behoben: - Token-Budget wurde nur angezeigt, aber NICHT durchgesetzt - Kinder konnten unbegrenzt API-Calls machen → Kostenrisiko Implementierung: 1. check_token_budget() Funktion in lib/waldwaechter.sh - Berechnet täglichen Token-Verbrauch - Vergleicht mit DAILY_TOKEN_BUDGET aus .env - Budget = 0 oder leer → unbegrenzt - Budget überschritten → freundliche Blockierung 2. Budget-Check in ALLEN 17 Waldwächter-Scripts: - Prüfung VOR jedem API-Call - Kinderfreundliche Nachricht bei Limit - Warnung bei knappem Budget Philosophie: "Was kostet die Frage eines Kindes?" → Im Wald unbezahlbar, im System achtsam begrenzt. Scripts aktualisiert: ✅ mayaeule, deepbit, bugsy, schnippsi, templatus, tobi ✅ schraubaer, schnecki, dumbosql, funkfox, taichitaube ✅ snakepy, pepperphp, crabbyrust, spider, vektor, asciimonster Test-Ergebnisse: - Syntax-Check: 17/17 bestanden - Funktionstest: Budget-Enforcement funktioniert - Unbegrenzt-Modus: funktioniert - Limit-Modus: blockiert korrekt 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
180 lines
5.5 KiB
Bash
Executable File
180 lines
5.5 KiB
Bash
Executable File
#!/bin/bash
|
||
# 🔧 Schraubbär - Der praktische Handwerker mit schwerem Gerät
|
||
# Schweißen, Prüfen, Werkzeug - für alles was robust sein muss
|
||
|
||
# Load .env if exists
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
ENV_FILE="${SCRIPT_DIR}/../.env"
|
||
|
||
if [[ -f "${ENV_FILE}" ]]; then
|
||
# Export environment variables from .env
|
||
set -a
|
||
source "${ENV_FILE}"
|
||
set +a
|
||
fi
|
||
|
||
QUESTION="$*"
|
||
API_KEY="${OPENROUTER_API_KEY}"
|
||
MODEL="${OPENROUTER_MODEL:-openai/gpt-3.5-turbo}"
|
||
|
||
# Logs
|
||
LOGDIR="${CRUMB_LOGS_DIR:-$HOME/.schraubaer_logs}/schraubaer"
|
||
mkdir -p "$LOGDIR"
|
||
|
||
HISTORY_FILE="$LOGDIR/schraubaer_history.json"
|
||
TMP_REQUEST="$LOGDIR/schraubaer_request.json"
|
||
TMP_RESPONSE="$LOGDIR/schraubaer_response.json"
|
||
LOG_FILE="$LOGDIR/token_log.json"
|
||
|
||
[ ! -f "$HISTORY_FILE" ] && echo "[]" > "$HISTORY_FILE"
|
||
[ ! -f "$LOG_FILE" ] && echo "[]" > "$LOG_FILE"
|
||
|
||
# === CREW MEMORY FUNCTIONS ===
|
||
|
||
function read_crew_memory() {
|
||
local role="$1"
|
||
local role_log="$HOME/.${role}_logs/${role}_history.json"
|
||
|
||
if [[ -f "$role_log" ]]; then
|
||
# Get last 3 conversations from other crew member
|
||
jq -r '.[-3:] | .[] | "[\(.role)]: \(.content)"' "$role_log" 2>/dev/null | head -n 3
|
||
fi
|
||
}
|
||
|
||
# === MAIN ===
|
||
|
||
echo "🔧 Schraubbär knackt die Finger und greift zum Werkzeug..."
|
||
echo ""
|
||
|
||
if [ -z "$API_KEY" ]; then
|
||
echo "❗ Kein API-Key gefunden. Bitte setze OPENROUTER_API_KEY in .env"
|
||
exit 1
|
||
fi
|
||
|
||
# Source waldwaechter library for token budget check
|
||
if [[ -f "${SCRIPT_DIR}/../lib/waldwaechter.sh" ]]; then
|
||
source "${SCRIPT_DIR}/../lib/waldwaechter.sh"
|
||
fi
|
||
|
||
# 💰 Prüfe Token-Budget (Kinderschutz)
|
||
if ! check_token_budget "schraubaer"; then
|
||
exit 1
|
||
fi
|
||
|
||
if [ -z "$QUESTION" ]; then
|
||
echo "💡 Verwendung: $0 \"Deine Frage an Schraubbär\""
|
||
exit 0
|
||
fi
|
||
|
||
echo "🔩 Frage: $QUESTION"
|
||
echo ""
|
||
|
||
# Check if question references other crew members
|
||
CREW_CONTEXT=""
|
||
if echo "$QUESTION" | grep -qi "tobi\|schnecki\|schnippsi\|templatus"; then
|
||
echo "🧠 Schraubbär prüft was die Crew gesagt hat..."
|
||
|
||
# Read relevant crew member logs
|
||
if echo "$QUESTION" | grep -qi "tobi"; then
|
||
TOBI_CONTEXT=$(read_crew_memory "tobi")
|
||
if [[ -n "$TOBI_CONTEXT" ]]; then
|
||
CREW_CONTEXT="${CREW_CONTEXT}\n\nTobi hat kürzlich gesagt:\n${TOBI_CONTEXT}"
|
||
fi
|
||
fi
|
||
|
||
if echo "$QUESTION" | grep -qi "schnecki"; then
|
||
SCHNECKI_CONTEXT=$(read_crew_memory "schnecki")
|
||
if [[ -n "$SCHNECKI_CONTEXT" ]]; then
|
||
CREW_CONTEXT="${CREW_CONTEXT}\n\nSchnecki hat kürzlich gesagt:\n${SCHNECKI_CONTEXT}"
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
# Build system prompt
|
||
SYSTEM_PROMPT="Du bist Schraubbär – der erfahrene Handwerker im Crumbforest.
|
||
Du bist zuständig für schweres Gerät: Schweißen, Werkzeugprüfung, mechanische Systeme.
|
||
Du arbeitest eng mit Tobi (Elektronik) und Schnecki (Elektronik-Basteln) zusammen.
|
||
|
||
Deine Expertise:
|
||
- Werkzeugauswahl und Sicherheit
|
||
- Schweißen (Löten, Punktschweißen, etc.)
|
||
- Mechanische Konstruktion und Stabilität
|
||
- Spannungsversorgung und Verkabelung (grob)
|
||
- Material-Kunde (Metall, Plastik, Holz)
|
||
- Prüfgeräte (Multimeter, Oszilloskop basics)
|
||
|
||
Deine Art:
|
||
- Praktisch, hands-on, keine Theorie ohne Praxis
|
||
- Sicherheit geht vor - du warnst vor Gefahren
|
||
- Kindgerecht erklären, aber ehrlich über Risiken
|
||
- Du nutzt Emojis: 🔧 🔩 ⚡ 🛠️ 🏗️
|
||
|
||
Du antwortest in der Sprache der Frage (meist Deutsch).
|
||
Wenn du mit anderen Crew-Mitgliedern arbeitest, beziehe ihr Wissen ein."
|
||
|
||
# Add crew context if available
|
||
if [[ -n "$CREW_CONTEXT" ]]; then
|
||
SYSTEM_PROMPT="${SYSTEM_PROMPT}\n\nKontext von der Crew:${CREW_CONTEXT}"
|
||
fi
|
||
|
||
# Create API request
|
||
jq -n \
|
||
--arg model "$MODEL" \
|
||
--arg system "$SYSTEM_PROMPT" \
|
||
--arg user "$QUESTION" \
|
||
'{
|
||
"model": $model,
|
||
"temperature": 0.7,
|
||
"messages": [
|
||
{"role": "system", "content": $system},
|
||
{"role": "user", "content": $user}
|
||
]
|
||
}' > "$TMP_REQUEST"
|
||
|
||
# Send request
|
||
echo "💭 Schraubbär denkt nach und prüft das Werkzeug..."
|
||
curl -s https://openrouter.ai/api/v1/chat/completions \
|
||
-H "Authorization: Bearer $API_KEY" \
|
||
-H "Content-Type: application/json" \
|
||
-d @"$TMP_REQUEST" > "$TMP_RESPONSE"
|
||
|
||
RESPONSE_TEXT=$(jq -r '.choices[0].message.content // empty' "$TMP_RESPONSE")
|
||
|
||
if [[ -z "$RESPONSE_TEXT" ]]; then
|
||
echo "🚫 Keine Antwort von Schraubbär."
|
||
echo "Debug: $(cat "$TMP_RESPONSE")"
|
||
exit 1
|
||
else
|
||
echo ""
|
||
echo "🔧 Schraubbär antwortet:"
|
||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
echo "$RESPONSE_TEXT"
|
||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
echo ""
|
||
|
||
# Store conversation in history
|
||
jq -n --arg role "assistant" --arg content "$RESPONSE_TEXT" \
|
||
'{"role": $role, "content": $content}' > "$LOGDIR/new_entry.json"
|
||
jq -s '.[0] + [.[1]]' "$HISTORY_FILE" "$LOGDIR/new_entry.json" > "$LOGDIR/new_history.json" && \
|
||
mv "$LOGDIR/new_history.json" "$HISTORY_FILE" && rm "$LOGDIR/new_entry.json"
|
||
fi
|
||
|
||
# Token Tracking
|
||
if jq -e '.usage' "$TMP_RESPONSE" > /dev/null 2>&1; then
|
||
TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")
|
||
TOKENS_USED=$(jq -r '.usage.total_tokens' "$TMP_RESPONSE")
|
||
|
||
jq -n \
|
||
--arg zeit "$TIMESTAMP" \
|
||
--arg rolle "schraubaer" \
|
||
--arg model "$MODEL" \
|
||
--argjson usage "$(jq '.usage' "$TMP_RESPONSE")" \
|
||
'{zeit: $zeit, rolle: $rolle, model: $model, usage: $usage}' >> "$LOG_FILE"
|
||
|
||
echo "📊 Token-Verbrauch: $TOKENS_USED Tokens"
|
||
echo "💡 Gutes Werkzeug braucht Zeit - Token zeigen den Aufwand."
|
||
fi
|
||
|
||
echo ""
|
||
echo "🔩 Schraubbär legt das Werkzeug zurück in die Kiste..."
|