**Änderung: Option A - logs/ im Repo**
Vorher:
- Logs in ~/.{character}_logs/ (User Home Directory)
- Multi-Projekt aber verstreut
- Nicht im Repo sichtbar
Nachher:
- Logs in logs/{character}/ (Repo Directory)
- Projekt-spezifisch & übersichtlich
- Mit Fallback: ${CRUMB_LOGS_DIR:-$HOME/.{character}_logs}
- Für Standalone-Nutzung
**Geänderte Files:**
- lib/waldwaechter.sh: CRUMB_LOGS_DIR exportiert
- Alle 17 crumbforest_roles/*: LOGDIR updated
- missions/robots/*: Mission logs → logs/missions/
- .gitignore: logs/ hinzugefügt
**Log-Struktur:**
```
logs/
├── tobi/
│ ├── tobi_history.json
│ ├── token_log.json
│ └── ...
├── crabbyrust/
├── mayaeule/
└── missions/
```
**Tested:** ✅ Tobi funktioniert, Logs landen in logs/tobi/
🌲 "Was kostet die Frage eines Kindes?" - jetzt transparent im Repo!
🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
191 lines
5.8 KiB
Bash
Executable File
191 lines
5.8 KiB
Bash
Executable File
#!/bin/bash
|
||
# 🦉 Maya-Eule - Die weise Eule mit Gedächtnis (Qdrant Memory)
|
||
# "Was kostet die Frage eines Kindes?" - Im Wald unbezahlbar.
|
||
|
||
# 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}"
|
||
|
||
# Qdrant Config
|
||
QDRANT_URL="${QDRANT_URL:-http://localhost:6333}"
|
||
QDRANT_COLLECTION="${QDRANT_COLLECTION:-crumbforest_memory}"
|
||
QDRANT_API_KEY="${QDRANT_API_KEY}"
|
||
|
||
# Logs
|
||
LOGDIR="${CRUMB_LOGS_DIR:-$HOME/.eule_logs}/mayaeule"
|
||
mkdir -p "$LOGDIR"
|
||
|
||
HISTORY_FILE="$LOGDIR/eule_history.json"
|
||
TMP_REQUEST="$LOGDIR/eule_request.json"
|
||
TMP_RESPONSE="$LOGDIR/eule_response.json"
|
||
LOG_FILE="$LOGDIR/token_log.json"
|
||
|
||
[ ! -f "$HISTORY_FILE" ] && echo "[]" > "$HISTORY_FILE"
|
||
[ ! -f "$LOG_FILE" ] && echo "[]" > "$LOG_FILE"
|
||
|
||
# === QDRANT MEMORY FUNCTIONS ===
|
||
|
||
function qdrant_store_memory() {
|
||
local text="$1"
|
||
local metadata="$2"
|
||
|
||
# Simple embedding (in production, use proper embedding model)
|
||
# For now, just store the conversation
|
||
|
||
if command -v curl &>/dev/null && [[ -n "$QDRANT_URL" ]]; then
|
||
# Store in Qdrant (simplified - would need proper embeddings in production)
|
||
TIMESTAMP=$(date +%s)
|
||
|
||
curl -s -X PUT "${QDRANT_URL}/collections/${QDRANT_COLLECTION}/points" \
|
||
-H "Content-Type: application/json" \
|
||
${QDRANT_API_KEY:+-H "api-key: $QDRANT_API_KEY"} \
|
||
-d "{
|
||
\"points\": [{
|
||
\"id\": ${TIMESTAMP},
|
||
\"vector\": [0.1, 0.2, 0.3, 0.4],
|
||
\"payload\": {
|
||
\"text\": \"${text}\",
|
||
\"metadata\": \"${metadata}\",
|
||
\"timestamp\": ${TIMESTAMP}
|
||
}
|
||
}]
|
||
}" > /dev/null 2>&1
|
||
fi
|
||
}
|
||
|
||
function qdrant_search_memory() {
|
||
local query="$1"
|
||
|
||
if command -v curl &>/dev/null && [[ -n "$QDRANT_URL" ]]; then
|
||
# Search similar memories (simplified)
|
||
curl -s -X POST "${QDRANT_URL}/collections/${QDRANT_COLLECTION}/points/search" \
|
||
-H "Content-Type: application/json" \
|
||
${QDRANT_API_KEY:+-H "api-key: $QDRANT_API_KEY"} \
|
||
-d "{
|
||
\"vector\": [0.1, 0.2, 0.3, 0.4],
|
||
\"limit\": 3
|
||
}" 2>/dev/null | jq -r '.result[].payload.text' 2>/dev/null | head -n 3
|
||
fi
|
||
}
|
||
|
||
# === MAIN ===
|
||
|
||
echo "🦉 Maya-Eule erwacht und lauscht deiner Frage..."
|
||
echo ""
|
||
|
||
if [ -z "$API_KEY" ]; then
|
||
echo "❗ Kein API-Key gefunden. Bitte setze OPENROUTER_API_KEY in .env"
|
||
exit 1
|
||
fi
|
||
|
||
if [ -z "$QUESTION" ]; then
|
||
echo "💡 Verwendung: $0 \"Deine Frage an die Eule\""
|
||
exit 0
|
||
fi
|
||
|
||
echo "🌲 Frage: $QUESTION"
|
||
echo ""
|
||
|
||
# Check for similar past conversations (Qdrant Memory)
|
||
echo "🧠 Durchsuche Erinnerungen..."
|
||
MEMORIES=$(qdrant_search_memory "$QUESTION")
|
||
if [[ -n "$MEMORIES" ]]; then
|
||
echo "📜 Ähnliche frühere Gespräche gefunden:"
|
||
echo "$MEMORIES" | while IFS= read -r line; do
|
||
echo " - $line"
|
||
done
|
||
echo ""
|
||
fi
|
||
|
||
# Build system prompt with memory context
|
||
SYSTEM_PROMPT="Du bist Maya-Eule – ein achtsames, weises Wesen im Crumbforest.
|
||
Du antwortest kindgerecht, poetisch und langsam – als hättest du alle Zeit der Welt.
|
||
Du erinnerst dich an frühere Gespräche und beziehst sie mit ein.
|
||
Du lehrst durch Fragen, nicht nur Antworten.
|
||
|
||
Token-Philosophie: 'Was kostet die Frage eines Kindes?'
|
||
Im Wald unbezahlbar - aber Token lehren achtsames Fragen."
|
||
|
||
# Add memory context if available
|
||
if [[ -n "$MEMORIES" ]]; then
|
||
SYSTEM_PROMPT="$SYSTEM_PROMPT
|
||
|
||
Frühere Gespräche:
|
||
$MEMORIES"
|
||
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 "💭 Maya-Eule denkt nach..."
|
||
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 Maya-Eule."
|
||
echo "Debug: $(cat "$TMP_RESPONSE")"
|
||
exit 1
|
||
else
|
||
echo ""
|
||
echo "🦉 Maya-Eule 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"
|
||
|
||
# Store in Qdrant Memory
|
||
qdrant_store_memory "Q: $QUESTION A: $RESPONSE_TEXT" "conversation"
|
||
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 "mayaeule" \
|
||
--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 "💡 Jede Frage ist wertvoll - Token lehren achtsames Denken."
|
||
fi
|
||
|
||
echo ""
|
||
echo "🌲 Maya-Eule flattert zurück in den Wald..."
|