chore: nettoyage .gitignore - retrait venv, __pycache__, .env, data, logs, modèles du tracking

This commit is contained in:
Lowei 2026-06-16 20:40:37 +02:00
parent 7333a22bcd
commit 604a5affe0
9231 changed files with 1244 additions and 1601201 deletions

15
.env
View file

@ -1,15 +0,0 @@
DISCORD_TOKEN=MTM3MDcxNjU1MTQ4NTA2NzMwNA.GJHUjY.YrzGaD2yXj0-UwYZ0ut7RA_tSeI5ji1nD5iLTY
GUILD_ID=1370716551485067304
# --- CONFIGURATION BÊTA ---
# IDs des Administrateurs (Séparés par des virgules)
ADMIN_IDS=971446412690722826,1324439906046574693
# IDs du Staff (Assets Primaires), séparés par des virgules
PRIMARY_ASSETS_IDS=971446412690722826
# Channel d'Introspection (Log Stream de Bêta)
INTROSPECTION_CHANNEL_ID=1461107327381016629
# Modèle Ollama (local, pas de clé API nécessaire)
OLLAMA_MODEL=gpt-oss:20b
OLLAMA_BASE_URL=http://localhost:11434

75
.gitignore vendored Normal file
View file

@ -0,0 +1,75 @@
# ============================
# Environment & Secrets
# ============================
.env
.env.*
!.env.example
# ============================
# Python
# ============================
__pycache__/
*.py[cod]
*$py.class
*.so
*.egg-info/
*.egg
dist/
build/
*.whl
# ============================
# Virtual Environment
# ============================
venv/
.venv/
env/
ENV/
# ============================
# IDE / Editor
# ============================
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store
Thumbs.db
# ============================
# Logs
# ============================
*.log
logs/
# ============================
# Data (runtime / dynamic)
# ============================
data/
*.db
*.sqlite
*.sqlite3
# ============================
# AI Models (fichiers volumineux)
# ============================
model/
*.gguf
*.bin
*.onnx
*.pt
*.pth
*.h5
# ============================
# OS
# ============================
.DS_Store
Thumbs.db
desktop.ini
# ============================
# Ollama
# ============================
Modelfile

View file

@ -1,16 +0,0 @@
FROM ../model/gpt-oss-20b-mxfp4.gguf
# Set the context size (32k like we wanted)
PARAMETER num_ctx 32768
PARAMETER temperature 0.5
PARAMETER repeat_penalty 1.35
PARAMETER stop "<|eot_id|>"
PARAMETER stop "<|end_of_text|>"
TEMPLATE """<|begin_of_text|><|start_header_id|>system<|end_header_id|>
{{ .System }}<|eot_id|><|start_header_id|>user<|end_header_id|>
{{ .Prompt }}<|eot_id|><|start_header_id|>assistant<|end_header_id|>
"""

234
README.md
View file

@ -7,7 +7,7 @@ Bot Discord IA d'assistance et de modération avancée, utilisant **Ollama** pou
- **IA conversationnelle** : Répond aux questions et exécute des actions sur Discord via JSON
- **Modération silencieuse** : Scan de toxicité de chaque message via LLM en arrière-plan
- **Gestion vocale** : Transcription Whisper en temps réel + détection de mots-clés
- **Mémoire utilisateur** : Historique par utilisateur avec résumé automatique
- **Mémoire utilisateur** : Historique par utilisateur avec résumé automatique (via LLM)
- **Dispatch d'insights** : Coordination staff avec boutons d'acceptation Discord
- **RGPD** : Purge automatique des données > 30 jours
@ -15,7 +15,7 @@ Bot Discord IA d'assistance et de modération avancée, utilisant **Ollama** pou
### Prérequis
- Python 3.9+
- Python 3.10+
- **Ollama** installé et en cours d'exécution (https://ollama.com)
- Modèle `gpt-oss:20b` disponible dans Ollama
@ -41,8 +41,9 @@ Créer un fichier `.env` à la racine du dossier `beta/` :
DISCORD_TOKEN=your_discord_bot_token
GUILD_ID=your_guild_id
# LLM
# LLM (Ollama)
OLLAMA_MODEL=gpt-oss:20b
OLLAMA_BASE_URL=http://localhost:11434
# Staff
ADMIN_IDS=123456789,987654321
@ -69,172 +70,91 @@ Le bot va :
```
beta/
├── main.py # Point d'entrée
├── main.py # Point d'entrée
├── core/
│ ├── bot.py # Classe principale Superviseur
│ ├── llm.py # Gestionnaire LLM (Ollama API)
│ ├── action_router.py # Routage des actions IA → Discord
│ ├── dispatcher.py # Dispatch d'insights vers staff
│ ├── voice.py # Gestion vocale + Whisper
│ ├── tasks.py # Tâches de fond
│ ├── messaging.py # Envoi de messages
│ └── permissions.py # Whitelist et permissions
│ ├── bot.py # Classe Beta (événements, orchestration)
│ ├── llm.py # Gestionnaire LLM (Ollama API)
│ ├── action_executor.py # Routage des actions IA → Discord
│ ├── action_router.py # (legacy, redirige vers action_executor)
│ ├── response_handler.py # Nettoyage, parsing JSON, envoi réponses
│ ├── log_parser.py # Parsing des logs d'actions
│ ├── content.py # Préparation du contenu pour le LLM
│ ├── context_builder.py # Construction du contexte serveur
│ ├── dispatcher.py # Dispatch d'insights vers staff
│ ├── voice.py # Gestion vocale + Whisper
│ ├── task_manager.py # Tâches de fond
│ ├── messaging.py # Envoi de messages
│ └── permissions.py # Whitelist et permissions
├── brain/
│ ├── memoire.py # Mémoire utilisateur (JSON/Redis)
│ ├── moderation.py # Modération IA + SQLite
│ └── infos_serveurs.py # Infos serveur
│ ├── memory.py # Mémoire utilisateur (wrapper)
│ ├── memoire.py # Mémoire utilisateur (implémentation, JSON/Redis + cache)
│ ├── moderation.py # Modération IA + SQLite
│ └── infos_serveurs.py # Infos serveur
├── commandes/
│ ├── security/ # kick, ban, mute, warn, purge...
│ ├── salons/ # Créer, supprimer, modifier salons
│ ├── roles/ # Créer, supprimer, modifier rôles
│ └── autres/ # Config, status, ping, etc.
├── data/ # Logs, DB SQLite
└── memoires/ # Historique utilisateur (JSON)
│ ├── security/ # kick, ban, mute, warn, purge...
│ ├── salons/ # Créer, supprimer, modifier salons
│ ├── roles/ # Créer, supprimer, modifier rôles
│ ├── categories/ # Créer, supprimer, modifier catégories
│ └── autres/ # Config, status, ping, etc.
├── data/ # Logs, DB SQLite
└── memoires/ # Historique utilisateur (JSON, par guild)
```
## Actions IA
Le bot peut exécuter les actions suivantes via LLM :
- `CREATE_CHANNEL`, `DELETE_CHANNEL`, `MODIFY_CHANNEL`
- `CREATE_ROLE`, `DELETE_ROLE`, `ADD_ROLE_TO_USER`
- `KICK`, `BAN`, `UNBAN`, `MUTE`, `TIMEOUT`, `WARN`, `PURGE`
- `CREATE_CHANNEL`, `DELETE_CHANNEL`, `MODIFY_CHANNEL`, `RENAME_CHANNEL`, `MOVE_CHANNEL`
- `CREATE_ROLE`, `DELETE_ROLE`, `ADD_ROLE_TO_USER`, `REMOVE_ROLE_FROM_USER`
- `CREATE_CATEGORY`, `DELETE_CATEGORY`, `MODIFY_CATEGORY`, `RENAME_CATEGORY`
- `KICK`, `BAN`, `UNBAN`, `MUTE`, `UNMUTE`, `TIMEOUT`, `WARN`, `PURGE`
- `JOIN_VOICE`, `LEAVE_VOICE`
- `ALERT`, `INSIGHT`, `FORGET_USER`, `READ_LOGS`
- `SEND_MESSAGE`, `HELP`, `STATUS`
## Variables d'environnement
| Variable | Description | Défaut |
|----------|-------------|--------|
| `DISCORD_TOKEN` | Token du bot Discord | *requis* |
| `GUILD_ID` | ID du serveur principal | *requis* |
| `OLLAMA_MODEL` | Nom du modèle Ollama | `gpt-oss:20b` |
| `OLLAMA_BASE_URL` | URL de l'API Ollama | `http://localhost:11434` |
| `ADMIN_IDS` | IDs des administrateurs (virgule) | — |
| `PRIMARY_ASSETS_IDS` | IDs du staff (virgule) | — |
| `INTROSPECTION_CHANNEL_ID` | Channel de logs internes | — |
| `TIMEZONE` | Fuseau horaire | `Europe/Paris` |
| `SUPERVISEUR_MAX_CONCURRENT` | Requêtes LLM simultanées max | `4` |
| `SUPERVISEUR_MEM_DIR` | Répertoire des mémoires | `memoires` |
| `SUPERVISEUR_MAX_RECENT` | Messages avant résumé | `20` |
| `SUPERVISEUR_REDIS_URL` | URL Redis (optionnel) | — |
| `LOG_LEVEL` | Niveau de log | `INFO` |
## Tests
```bash
# Tests unitaires
pytest test_bot.py -v
# Tests mémoire
python -m brain.memoire
```
## Monitoring
Le bot inclut des métriques intégrées :
- Nombre de requêtes LLM (succès/échecs)
- Temps de réponse moyen
- Métriques mémoire (hits/misses cache, lectures/écritures)
## Sécurité
- **Local uniquement** : Pas d'appels réseau externes
- **RGPD** : Purge automatique des données > 30 jours
- **Permissions** : Vérification admin pour les actions destructrices
- **Whitelist** : Système de niveaux de permissions
## Support
1. Vérifier les logs dans `data/bot.log`
2. Activer le mode debug : `LOG_LEVEL=DEBUG`
3. Vérifier qu'Ollama est actif : `ollama list`
python test_llama_integration.py
```
This will test:
- Model loading
- LLMManager functionality
- Text generation
- JSON extraction
- Performance
## Performance
### Expected Performance
With the 120B model and optimized parameters:
- **Context**: 4096 tokens
- **Threads**: 16 CPU threads
- **Memory**: ~64GB RAM usage
- **Response time**: 5-15 seconds for typical queries
- **Concurrency**: 4 simultaneous requests
### Performance Tips
1. **Use mlock**: Prevents swapping to disk
2. **Optimize threads**: Match your CPU core count
3. **Monitor memory**: Ensure sufficient RAM
4. **Batch size**: Adjust based on your system
### Monitoring
The bot includes built-in metrics:
- LLM request counts
- Success/failure rates
- Response times
- Memory usage
Enable metrics server with `METRICS_ENABLED=1`.
## Troubleshooting
### Common Issues
1. **Model not found**
- Check `MODEL_PATH` in `.env`
- Verify model file exists
- Check file permissions
2. **Memory errors**
- Ensure sufficient RAM
- Reduce `n_ctx` or `n_threads`
- Disable `use_mlock` for testing
3. **Slow responses**
- Check CPU usage
- Verify model is in RAM
- Reduce `n_threads` if CPU is overloaded
4. **Import errors**
- Install `llama-cpp-python` with proper backend
- Check Python version compatibility
### Debug Mode
Enable verbose logging by setting:
```bash
LOG_LEVEL=DEBUG
```
### Model Loading Issues
If model loading fails:
1. Check model file integrity
2. Verify GGUF format compatibility
3. Try with `use_mlock=False`
4. Reduce model size for testing
## Migration Notes
### From Ollama
If you were previously using Ollama:
1. **Remove Ollama**: No longer needed
2. **Update configuration**: Remove Ollama URLs
3. **Install llama-cpp-python**: Add to requirements
4. **Test thoroughly**: Verify all functionality
### Code Changes
Key files modified:
- `beta.py`: Main entry point with model loading
- `superviseur/llm.py`: LLMManager with llama-cpp-python
- `superviseur/bot.py`: Bot integration
- `requirements.txt`: Updated dependencies
## Security
### Data Privacy
- No external network calls
- All processing local
- GDPR compliance maintained
- Memory management for sensitive data
### Model Security
- Local model storage
- No external dependencies
- Controlled access
- Proper cleanup
## Support
For issues or questions:
1. Check the troubleshooting section
2. Run the test script
3. Enable debug logging
4. Check system resources
5. Verify model compatibility
## Contributing
When contributing to this project:
1. Test with the test script
2. Verify performance
3. Update documentation
4. Follow existing code patterns
5. Ensure backward compatibility
## License
This project is licensed under the same license as the original Superviseur bot.
3. Vérifier qu'Ollama est actif : `ollama list`

Binary file not shown.

Binary file not shown.

View file

@ -253,17 +253,72 @@ async def save_user_memory_async(user_id: int | str, data: Dict[str, Any], guild
logger.debug(f"Mémoire marquée dirty pour utilisateur {user_id} (guild {guild_id})")
# Référence globale au LLM manager (set par le bot au démarrage)
_llm_manager = None
def set_llm_manager(llm_manager) -> None:
"""Enregistre le LLM manager pour les résumés."""
global _llm_manager
_llm_manager = llm_manager
async def summarize_messages(messages: List[Dict[str, Any]]) -> str:
"""
Fonction de résumé améliorée. Utilise une extraction de mots-clés et de phrases clés
pour un résumé plus intelligent. Placeholder pour intégration IA future.
Cette fonction est `async` pour faciliter un remplacement par un appel réseau/IA.
Résume une liste de messages via le LLM.
Fallback sur l'extraction de mots-clés si le LLM n'est pas disponible.
"""
if not messages:
return ""
# Extraire tous les textes utilisateur et bot
# Construire le transcript à résumer
transcript_lines = []
for m in messages:
um = m.get("user_message", "").strip()
bm = m.get("bot_message", "").strip()
if um:
transcript_lines.append(f"Utilisateur: {um}")
if bm:
transcript_lines.append(f"Bot: {bm}")
transcript = "\n".join(transcript_lines)
# Tronquer le transcript pour éviter les appels trop longs
if len(transcript) > 4000:
transcript = transcript[-4000:]
# Essayer d'utiliser le LLM pour un vrai résumé
if _llm_manager is not None:
try:
prompt = (
"Tu es un assistant spécialisé dans la synthèse de conversations.\n"
"Résume les échanges suivants de manière concise et factuelle.\n"
"Extrais les sujets abordés, les décisions prises, et les informations importantes.\n"
"Le résumé ne doit PAS dépasser 500 caractères.\n\n"
f"CONVERSATION À RÉSUMER :\n{transcript}\n\n"
"RÉSUMÉ :"
)
payload = _llm_manager.build_payload(
prompt=prompt,
system_prompt="Tu es un assistant de synthèse. Sois concis et factuel.",
force_json=False
)
summary = await _llm_manager.call_llama(payload)
if summary and len(summary.strip()) > 10:
# Nettoyer le résumé
summary = summary.strip()
if len(summary) > 1500:
summary = summary[:1497] + "..."
return summary
except Exception as e:
logger.warning(f"Erreur résumé LLM, fallback extractif: {e}")
# Fallback : extraction de mots-clés et phrases clés
return _extractive_summary(messages)
def _extractive_summary(messages: List[Dict[str, Any]]) -> str:
"""Résumé extractif basé sur les mots-clés et phrases clés (fallback)."""
all_texts = []
for m in messages:
um = m.get("user_message", "")
@ -272,7 +327,7 @@ async def summarize_messages(messages: List[Dict[str, Any]]) -> str:
combined_text = " ".join(all_texts)
# Extraction simple de mots-clés (mots fréquents, >3 chars)
# Extraction de mots-clés (mots fréquents, >3 chars)
words = re.findall(r'\b\w{4,}\b', combined_text.lower())
word_freq = {}
for word in words:
@ -282,28 +337,25 @@ async def summarize_messages(messages: List[Dict[str, Any]]) -> str:
top_keywords = sorted(word_freq.items(), key=lambda x: x[1], reverse=True)[:10]
keywords_str = ", ".join([kw for kw, _ in top_keywords])
# Extraire phrases clés (premières phrases des messages importants)
# Extraire phrases clés
key_phrases = []
for m in messages:
um = m.get("user_message", "").strip()
bm = m.get("bot_message", "").strip()
if um:
sentences = re.split(r'[.!?]', um)[:1] # première phrase
sentences = re.split(r'[.!?]', um)[:1]
key_phrases.extend(sentences)
if bm:
sentences = re.split(r'[.!?]', bm)[:1]
key_phrases.extend(sentences)
phrases_str = " | ".join(key_phrases[:5]) # limiter à 5 phrases
phrases_str = " | ".join(key_phrases[:5])
# Construire le résumé
summary = f"Mots-clés: {keywords_str}\nPhrases clés: {phrases_str}"
# Tronquer si trop long
if len(summary) > 1500:
summary = summary[:1497] + "..."
await asyncio.sleep(0) # point d'await pour remplacer par un vrai appel
return summary
@ -444,12 +496,32 @@ def list_memory_files() -> List[str]:
return files
def delete_user_memory(user_id: int | str) -> None:
path = _user_filepath(user_id)
def delete_user_memory(user_id: int | str, guild_id: str | None = None) -> None:
"""Supprime la mémoire d'un utilisateur, optionnellement pour un guild spécifique."""
path = _user_filepath(user_id, guild_id)
try:
os.remove(path)
except FileNotFoundError:
pass
# Si aucun guild_id spécifique, supprimer aussi tous les fichiers de mémoire pour cet utilisateur
if guild_id is None:
_ensure_memory_dir()
user_str = str(user_id)
for root, dirs, files in os.walk(MEMORY_DIR):
for name in files:
if name == f"{user_str}.json" or name == f"{user_id}.json":
full_path = os.path.join(root, name)
if full_path != path: # Éviter double suppression
try:
os.remove(full_path)
except FileNotFoundError:
pass
# Nettoyer le cache
key_no_guild = f"_{user_id}" if guild_id is None else f"{guild_id}_{user_id}"
memory_cache.pop(key_no_guild, None)
_dirty.pop(key_no_guild, None)
# Fonction pour obtenir les métriques

16
brain/memory.py Normal file
View file

@ -0,0 +1,16 @@
"""User memory management - JSON/Redis with in-memory cache."""
# Renamed from memoire.py for consistency (English naming)
from .memoire import ( # noqa: F401
add_interaction,
build_context_for_model,
flush_all,
MEMORY_DIR,
set_llm_manager,
delete_user_memory,
purge_old_memories,
get_metrics,
_extractive_summary,
load_user_memory_async,
save_user_memory_async,
)

View file

@ -3,7 +3,7 @@ import datetime
import logging
from typing import Optional
logger = logging.getLogger('Superviseur')
logger = logging.getLogger('Beta')
DB_PATH = 'data/mod.db'

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

7
core/action_executor.py Normal file
View file

@ -0,0 +1,7 @@
"""Action execution - routes AI actions to Discord commands."""
# Renamed from action_router.py for clarity
from .action_router import ActionExecutor # noqa: F401
# Backward compatibility
ActionRouter = ActionExecutor

View file

@ -2,16 +2,16 @@ import discord
import logging
from typing import Dict
logger = logging.getLogger('Superviseur')
logger = logging.getLogger('Beta')
class ActionRouter:
"""Routs generated AI semantic actions to the physical Discord moderative or administrative commands."""
class ActionExecutor:
"""Routes generated AI semantic actions to Discord administrative commands."""
def __init__(self, bot):
self.bot = bot
self._module_cache = {}
async def execute_action(self, action: str, params: Dict, message: discord.Message) -> (bool, str):
async def execute(self, action: str, params: Dict, message: discord.Message) -> (bool, str):
"""Execute an action from LLM response."""
# Normalize action name: replace spaces with underscores, uppercase
@ -82,8 +82,12 @@ class ActionRouter:
# --- PRIVACY ACTIONS ---
if action == 'FORGET_USER':
from brain.memoire import delete_user_memory
delete_user_memory(message.author.id)
from brain.memory import delete_user_memory
guild_name = message.guild.name if message.guild else None
if guild_name:
from .utils import sanitize_guild_name
guild_name = sanitize_guild_name(guild_name)
delete_user_memory(message.author.id, guild_name)
return True, None
# --- PERMISSION ENFORCEMENT (ADMIN ONLY) ---

File diff suppressed because it is too large Load diff

37
core/content.py Normal file
View file

@ -0,0 +1,37 @@
"""Content preparation for LLM input."""
import logging
logger = logging.getLogger('Beta')
def prepare_message_content(message) -> str:
"""Prepare message content for LLM by normalizing mentions and attachments."""
if not message:
return ""
content = message.content
# Replace channel mentions <#123> -> #general
for channel in message.channel_mentions:
content = content.replace(f'<#{channel.id}>', f'#{channel.name}')
# Replace role mentions <@&123> -> @admin
for role in message.role_mentions:
content = content.replace(f'<@&{role.id}>', f'@{role.name}')
# Replace user mentions <@123> or <@!123> -> @User
for mention in message.mentions:
content = content.replace(f'<@{mention.id}>', f'@{mention.display_name}')
content = content.replace(f'<@!{mention.id}>', f'@{mention.display_name}')
# Handle attachments
if message.attachments:
for attachment in message.attachments:
if attachment.content_type and attachment.content_type.startswith('image/'):
label = f"[Image: {attachment.filename}]"
else:
label = f"[Fichier: {attachment.filename}]"
content = f"{content} {label}".strip() if content else label
return content.strip()

4
core/context_builder.py Normal file
View file

@ -0,0 +1,4 @@
"""Context building for LLM prompts."""
# Renamed from context.py for clarity
from .context import build_context_for_message # noqa: F401

View file

@ -22,7 +22,6 @@ class LLMManager:
self.model_name = model_name
self.base_url = base_url or os.environ.get("OLLAMA_BASE_URL", "http://localhost:11434")
self.temperature = temperature
self._lock = asyncio.Lock()
def build_payload(
self,
@ -51,60 +50,59 @@ class LLMManager:
async def call_llama(self, payload: Dict[str, Any]) -> str:
"""Call Ollama Generate API and stream response."""
async with self._lock:
try:
# Automatic payload conversion for legacy compatibility (e.g. from moderation.py)
ollama_payload = {
"model": payload.get("model", self.model_name),
"prompt": payload["prompt"],
"system": payload.get("system", payload.get("system_prompt", "Tu es une IA serviable.")),
"stream": True, # Streaming pour voir la réponse en direct
"think": False, # Désactive le reasoning GPT-OSS
"format": "",
"options": {
"temperature": payload.get("temperature", self.temperature),
"num_ctx": payload.get("n_ctx", 16384),
"num_predict": payload.get("max_tokens") or payload.get("num_predict", 8192),
"repeat_penalty": payload.get("repeat_penalty") or payload.get("repeat_last_n", 1.2),
"stop": payload.get("stop", [])
}
try:
# Automatic payload conversion for legacy compatibility (e.g. from moderation.py)
ollama_payload = {
"model": payload.get("model", self.model_name),
"prompt": payload["prompt"],
"system": payload.get("system", payload.get("system_prompt", "Tu es une IA serviable.")),
"stream": True, # Streaming pour voir la réponse en direct
"think": False, # Désactive le reasoning GPT-OSS
"format": "",
"options": {
"temperature": payload.get("temperature", self.temperature),
"num_ctx": payload.get("n_ctx", 16384),
"num_predict": payload.get("max_tokens") or payload.get("num_predict", 8192),
"repeat_penalty": payload.get("repeat_penalty") or payload.get("repeat_last_n", 1.2),
"stop": payload.get("stop", [])
}
}
accumulated_reply = ""
api_url = f"{self.base_url}/api/generate"
accumulated_reply = ""
api_url = f"{self.base_url}/api/generate"
# Build headers with optional API key
headers = {}
api_key = os.environ.get("OLLAMA_API_KEY", "")
if api_key:
headers["Authorization"] = f"Bearer {api_key}"
async with aiohttp.ClientSession() as session:
async with session.post(api_url, json=ollama_payload, headers=headers) as response:
if response.status != 200:
err_text = await response.text()
logger.error(f"Ollama API Error ({response.status}): {err_text}")
return ""
# Streaming en direct dans le terminal
async for line in response.content:
if line:
try:
chunk = json.loads(line)
resp = chunk.get("response", "")
if resp:
accumulated_reply += resp
print(resp, end="", flush=True)
if chunk.get("done"):
break
except json.JSONDecodeError:
continue
print()
return accumulated_reply.strip()
# Build headers with optional API key
headers = {}
api_key = os.environ.get("OLLAMA_API_KEY", "")
if api_key:
headers["Authorization"] = f"Bearer {api_key}"
async with aiohttp.ClientSession() as session:
async with session.post(api_url, json=ollama_payload, headers=headers) as response:
if response.status != 200:
err_text = await response.text()
logger.error(f"Ollama API Error ({response.status}): {err_text}")
return ""
# Streaming en direct dans le terminal
async for line in response.content:
if line:
try:
chunk = json.loads(line)
resp = chunk.get("response", "")
if resp:
accumulated_reply += resp
print(resp, end="", flush=True)
if chunk.get("done"):
break
except json.JSONDecodeError:
continue
print()
return accumulated_reply.strip()
except Exception as e:
logger.error(f"Error calling Ollama: {e}")
return ""
except Exception as e:
logger.error(f"Error calling Ollama: {e}")
return ""
async def close_session(self):
pass

83
core/log_parser.py Normal file
View file

@ -0,0 +1,83 @@
"""Action log parsing for context building."""
import os
import json
import logging
logger = logging.getLogger('Beta')
def get_recent_logs(limit: int = 15) -> str:
"""Read and format recent action logs for context."""
log_path = "data/actions.log"
if not os.path.exists(log_path):
return ""
try:
with open(log_path, 'r', encoding='utf-8') as f:
lines = f.readlines()
last_lines = lines[-limit:]
formatted_logs = []
for line in last_lines:
if "ACTION:" not in line:
continue
try:
parts = line.split("ACTION:", 1)
if len(parts) <= 1:
continue
json_str = parts[1].strip()
data = json.loads(json_str)
timestamp = data.get("timestamp", "").split("T")[1].split(".")[0]
action = data.get("action", "UNKNOWN")
user = data.get("user", "System")
params = data.get("params", {})
success = data.get("success", True)
details = _format_action_details(action, params)
status = "\u2705" if success else "\u274c"
formatted_logs.append(f"[{timestamp}] {status} {action} {details} by {user}")
except Exception:
continue
if not formatted_logs:
return ""
return "\n[M\u00c9MOIRE DES ACTIONS R\u00c9CENTES (V\u00c9RIT\u00c9)]\n" + "\n".join(formatted_logs) + "\n"
except Exception as e:
logger.error(f"Error reading actions log: {e}")
return ""
def _format_action_details(action: str, params: dict) -> str:
"""Format action-specific details for log display."""
if action == 'SEND_MESSAGE':
target = params.get('channel_id') or params.get('user_id')
content = params.get('content', '')[:20]
return f"(to: {target}, content: {content}...)"
if 'CHANNEL' in action:
items = params.get('channels', [])
if items:
names = [i.get('channel_name', 'unknown') for i in items]
return f"(channels: {', '.join(names)})"
if 'ROLE' in action:
items = params.get('roles', [])
if items:
names = [i.get('role_name', 'unknown') for i in items]
return f"(roles: {', '.join(names)})"
if action in ('KICK', 'BAN', 'WARN', 'MUTE', 'TIMEOUT'):
target = params.get('user_id', 'unknown')
reason = params.get('reason', 'no reason')
return f"(target: {target}, reason: {reason})"
if action == 'PURGE':
purges = params.get('purges', [])
if purges:
p = purges[0]
return f"(channel: {p.get('channel_name')}, amount: {p.get('amount')})"
return ""

75
core/response_handler.py Normal file
View file

@ -0,0 +1,75 @@
"""Response processing: cleaning, JSON parsing, and reply sending."""
import re
import json
import logging
from typing import Optional, List, Tuple
logger = logging.getLogger('Beta')
def clean_response_text(raw_reply: str, json_str: Optional[str]) -> str:
"""Nettoie le texte de réponse LLM en supprimant les artefacts JSON et techniques."""
clean = raw_reply
# Retirer le bloc JSON identifié
if json_str:
clean = clean.replace(json_str, "").strip()
# Suppression des balises hallucinées (<|channel|>, thought, etc.)
clean = re.sub(r'<[^>]+?>', '', clean)
# Nettoyage des résidus de formatage
clean = clean.replace('```json', '').replace('```', '').strip()
# Suppression des clés orphelines si le modèle a foiré le JSON
orphan_pattern = (
r'[\u201c\u201d\u2018\u2019"\'](thought|action|response)'
r'[\u201c\u201d\u2018\u2019"\']\s*:\s*'
r'[\u201c\u201d\u2018\u2019"\'].*?'
r'[\u201c\u201d\u2018\u2019"\'],?'
)
clean = re.sub(orphan_pattern, '', clean, flags=re.DOTALL | re.IGNORECASE)
# Retrait ultime des accolades
if clean.strip().startswith('{') or clean.strip().endswith('}'):
clean = clean.strip('{}').strip()
return clean.strip()
def parse_json_actions(json_str: Optional[str]) -> Tuple[list, list, bool]:
"""Parse le JSON extrait et retourne (actions_list, responses_list, is_explicit_none)."""
if not json_str:
return [], [], False
try:
# Normalisation JSON (guillemets typographiques)
json_str_norm = (
json_str
.replace('\u201c', '"')
.replace('\u201d', '"')
.replace('\u2018', "'")
.replace('\u2019', "'")
)
data = json.loads(json_str_norm)
actions_list = data if isinstance(data, list) else [data]
responses = []
is_explicit_none = False
for action_data in actions_list:
norm_data = {k.lower(): v for k, v in action_data.items()}
if norm_data.get('action', '').upper() == 'NONE' and not norm_data.get('response'):
is_explicit_none = True
if norm_data.get('response'):
resp_text = re.sub(r'<[^>]+?>', '', str(norm_data.get('response'))).strip()
if resp_text:
responses.append(resp_text)
return actions_list, responses, is_explicit_none
except Exception as e:
logger.debug(f"JSON parsing error: {e}")
return [], [], False

4
core/task_manager.py Normal file
View file

@ -0,0 +1,4 @@
"""Background task management."""
# Renamed from tasks.py for clarity
from .tasks import TaskManager # noqa: F401

View file

@ -5,7 +5,7 @@ import time
import os
import discord
logger = logging.getLogger('Superviseur')
logger = logging.getLogger('Beta')
class TaskManager:
"""Handles global background tasks, scheduled loops and reporting."""
@ -29,10 +29,17 @@ class TaskManager:
async def _voice_evaluation_loop(self):
"""Periodic check for tactical voice connections."""
await self.bot.wait_until_ready()
auto_join = os.environ.get("AUTO_JOIN_VOICE", "true").lower() in ("true", "1", "yes")
if not auto_join:
logger.info("Auto-join vocal désactivé (AUTO_JOIN_VOICE=false)")
return
while not self.bot.is_closed():
for guild in self.bot.guilds:
await self.bot.voice_manager.evaluate_and_connect(guild)
await asyncio.sleep(30) # Reduit à 30s pour plus de réactivité en tâche de fond
try:
await self.bot.voice_manager.evaluate_and_connect(guild)
except Exception as e:
logger.debug(f"Voice evaluation skipped: {e}")
await asyncio.sleep(30)
async def _introspection_report_loop(self):
"""Periodic broadcast of system health metrics."""

View file

@ -6,7 +6,7 @@ import time
from typing import Dict, Optional, List, Any
from .whisper_worker import WhisperWorker
logger = logging.getLogger('Superviseur')
logger = logging.getLogger('Beta')
# Note: This requires discord-ext-voice-recv for actual audio capture.
try:
@ -116,12 +116,7 @@ class VoiceManager:
me = channel.guild.me
perms = channel.permissions_for(me)
if not perms.connect or not perms.view_channel:
logger.error(f"◈ REJECTION: Missing permissions for '{channel.name}' (CONNECT: {perms.connect}, VIEW: {perms.view_channel})")
await self.bot.introspection_log(
"DEPLOYMENT FAILURE",
f"Permissions insuffisantes pour `{channel.name}`. Système incapable de se déployer.",
discord.Color.red()
)
logger.info(f"Permissions vocales insuffisantes pour '{channel.name}' (CONNECT: {perms.connect}, VIEW: {perms.view_channel}). Skip.")
return
active_vc = channel.guild.voice_client
@ -150,7 +145,7 @@ class VoiceManager:
# Utilisation du client spécialisé pour la réception audio
connect_cls = voice_recv.VoiceRecvClient if HAS_VOICE_RECV else discord.VoiceClient
vc = await channel.connect(cls=connect_cls)
vc = await channel.connect(cls=connect_cls, timeout=10)
self.active_connections[channel.guild.id] = vc
self.current_channel = channel
@ -164,7 +159,14 @@ class VoiceManager:
self._monitoring_task = self.bot.loop.create_task(self._start_listening(vc))
except Exception as e:
logger.error(f"Failed to join voice channel: {e}")
error_str = str(e)
# Erreurs connues de Discord (permissions, region, etc.) → logger proprement
if "4017" in error_str or "403" in error_str or "Permission" in error_str:
logger.info(f"Connexion vocale impossible sur '{channel.name}': {error_str.split(chr(10))[0]}")
elif "4049" in error_str or "No audio" in error_str:
logger.debug(f"Voice connection issue on '{channel.name}': {error_str[:100]}")
else:
logger.warning(f"Échec connexion vocale '{channel.name}': {error_str[:200]}")
async def _start_listening(self, vc):
"""Internal loop to capture and transcribe audio chunks."""

View file

@ -1,348 +0,0 @@
2026-04-25 19:14:39,564 - INFO - ACTION: {"timestamp": "2026-04-25T19:14:39.564412", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "Projet devenir riche", "params": {"thought": "User requested to create a channel named 'test'.", "action": "CREATE_CHANNEL", "response": "Création du salon 'test'…", "channel_name": "test", "channel_type": "textuel"}, "success": true, "error": null}
2026-06-13 15:23:06,604 - INFO - ACTION: {"timestamp": "2026-06-13T13:23:06.604924", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Analyser la requête", "action": "CREATE_CHANNEL", "channel_name": "test", "response": "Le salon \"test\" a été créé avec succès."}, "success": true, "error": null}
2026-06-13 15:25:12,801 - INFO - ACTION: {"timestamp": "2026-06-13T13:25:12.801407", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Supprimer tous les salons sauf #🌐・api-rest et #💬・général", "action": "DELETE_CHANNEL", "channel_name": "🔑・authentication"}, "success": true, "error": null}
2026-06-13 15:29:43,431 - INFO - ACTION: {"timestamp": "2026-06-13T13:29:43.431879", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Delete channel 🔍・audit", "action": "DELETE_CHANNEL", "channel_name": "🤋・audit"}, "success": true, "error": null}
2026-06-13 15:35:15,987 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:15.987673", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "🔌・audit"}, "success": true, "error": null}
2026-06-13 15:35:16,616 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:16.616185", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "🔗・e2e-tests"}, "success": true, "error": null}
2026-06-13 15:35:16,935 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:16.935804", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "🢉・ui-kit"}, "success": true, "error": null}
2026-06-13 15:35:17,156 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:17.156034", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "🎼・metrics"}, "success": true, "error": null}
2026-06-13 15:35:17,441 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:17.441031", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "🔳・docker"}, "success": true, "error": null}
2026-06-13 15:35:22,058 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:22.058691", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "💫・changelog"}, "success": true, "error": null}
2026-06-13 15:35:22,372 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:22.372347", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "⛱⃣・architecture"}, "success": true, "error": null}
2026-06-13 15:35:22,683 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:22.683675", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "⚔・vulnerabilities"}, "success": true, "error": null}
2026-06-13 15:35:22,912 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:22.912145", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "🎊・analytics"}, "success": true, "error": null}
2026-06-13 15:35:23,168 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:23.168622", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "⚡・performance"}, "success": true, "error": null}
2026-06-13 15:35:23,385 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:23.385080", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "⏲⃣・uptime"}, "success": true, "error": null}
2026-06-13 15:35:28,426 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:28.426475", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "🎂・random"}, "success": true, "error": null}
2026-06-13 15:35:28,691 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:28.691419", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "🐐・schemas"}, "success": true, "error": null}
2026-06-13 15:35:28,962 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:28.962701", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "💼・api-graphql"}, "success": true, "error": null}
2026-06-13 15:35:29,192 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:29.192857", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "ἳC・nosql"}, "success": true, "error": null}
2026-06-13 15:35:29,457 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:29.457513", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "🦐・css-scss"}, "success": true, "error": null}
2026-06-13 15:35:29,707 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:29.706946", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "ὩA・migrations"}, "success": true, "error": null}
2026-06-13 15:35:34,897 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:34.897650", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "🥛・bug-reports"}, "success": true, "error": null}
2026-06-13 15:35:35,173 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:35.173276", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "⛈・jenkins"}, "success": true, "error": null}
2026-06-13 15:35:35,504 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:35.504408", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "⚒⃣・miscellaneous"}, "success": true, "error": null}
2026-06-13 15:35:35,979 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:35.979169", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "💼・logs"}, "success": true, "error": null}
2026-06-13 15:35:36,473 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:36.473445", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "Ὂ0・suggestions"}, "success": true, "error": null}
2026-06-13 15:35:36,768 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:36.768245", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "⛈・github-actions"}, "success": true, "error": null}
2026-06-13 15:35:41,151 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:41.151434", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "🏥・announcements"}, "success": true, "error": null}
2026-06-13 15:35:41,356 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:41.356379", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "🗲・roadmap"}, "success": true, "error": null}
2026-06-13 15:35:41,826 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:41.826179", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "⚛・react"}, "success": true, "error": null}
2026-06-13 15:35:42,209 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:42.209667", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "♾・accessibility"}, "success": true, "error": null}
2026-06-13 15:35:42,549 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:42.549949", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "🍕・api-docs"}, "success": true, "error": null}
2026-06-13 15:35:42,847 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:42.847028", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "ὋE・backup-restore"}, "success": true, "error": null}
2026-06-13 15:35:47,494 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:47.494856", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "🤊・apireference"}, "success": true, "error": null}
2026-06-13 15:35:47,955 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:47.955252", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "⛆・microservices"}, "success": true, "error": null}
2026-06-13 15:35:48,194 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:48.194886", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "⚔⃣・unit-tests"}, "success": true, "error": null}
2026-06-13 15:35:48,501 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:48.501408", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "Ὠ0・deployments"}, "success": true, "error": null}
2026-06-13 15:35:48,734 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:48.734719", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "🏎・backlog"}, "success": true, "error": null}
2026-06-13 15:35:49,259 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:49.259567", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "ce-quil-peut-faire"}, "success": true, "error": null}
2026-06-13 15:35:53,930 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:53.930040", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "☀・kubernetes"}, "success": true, "error": null}
2026-06-13 15:35:54,254 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:54.254659", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "⚡・alerts"}, "success": true, "error": null}
2026-06-13 15:35:54,538 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:54.538191", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "🤨・incidents"}, "success": true, "error": null}
2026-06-13 15:35:54,790 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:54.790002", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "🍙・code-comments"}, "success": true, "error": null}
2026-06-13 15:35:54,992 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:54.992727", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "ὑ2・secrets"}, "success": true, "error": null}
2026-06-13 15:35:55,202 - INFO - ACTION: {"timestamp": "2026-06-13T13:35:55.202753", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "⚥⃣・reviews-retro"}, "success": true, "error": null}
2026-06-13 15:36:00,204 - INFO - ACTION: {"timestamp": "2026-06-13T13:36:00.204782", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "⚒・outilsdev"}, "success": true, "error": null}
2026-06-13 15:36:00,610 - INFO - ACTION: {"timestamp": "2026-06-13T13:36:00.610860", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "Test pipus (vocal)"}, "success": true, "error": null}
2026-06-13 15:36:00,964 - INFO - ACTION: {"timestamp": "2026-06-13T13:36:00.964373", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "🤛・general-dev"}, "success": true, "error": null}
2026-06-13 15:36:01,309 - INFO - ACTION: {"timestamp": "2026-06-13T13:36:01.309302", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "🍏・onboarding"}, "success": true, "error": null}
2026-06-13 15:36:01,548 - INFO - ACTION: {"timestamp": "2026-06-13T13:36:01.548885", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "❓・faq"}, "success": true, "error": null}
2026-06-13 15:36:01,879 - INFO - ACTION: {"timestamp": "2026-06-13T13:36:01.879089", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "ᾚ8・sprints"}, "success": true, "error": null}
2026-06-13 15:36:06,641 - INFO - ACTION: {"timestamp": "2026-06-13T13:36:06.641590", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "✅・qa-checklist"}, "success": true, "error": null}
2026-06-13 15:36:06,641 - ERROR - ACTION: {"timestamp": "2026-06-13T13:36:06.641792", "action": "DELETE CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE CHANNEL", "channel_name": "🏦・guides"}, "success": false, "error": "Unknown action: DELETE CHANNEL"}
2026-06-13 15:36:07,252 - INFO - ACTION: {"timestamp": "2026-06-13T13:36:07.252834", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "🄥・meetings"}, "success": true, "error": null}
2026-06-13 15:36:07,518 - INFO - ACTION: {"timestamp": "2026-06-13T13:36:07.518633", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "ἰ5・daily-standup"}, "success": true, "error": null}
2026-06-13 15:36:08,070 - INFO - ACTION: {"timestamp": "2026-06-13T13:36:08.070466", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "🭋・compliance"}, "success": true, "error": null}
2026-06-13 15:36:08,359 - INFO - ACTION: {"timestamp": "2026-06-13T13:36:08.359765", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "⛆・performance-tests"}, "success": true, "error": null}
2026-06-13 15:36:12,865 - INFO - ACTION: {"timestamp": "2026-06-13T13:36:12.865476", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_name": "὚0・vue-angular"}, "success": true, "error": null}
2026-06-13 15:44:54,123 - ERROR - ACTION: {"timestamp": "2026-06-13T13:44:54.123716", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analysis", "action": "DELETE_CHANNEL", "channel_id": 1461107370775285907}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:44:54,434 - ERROR - ACTION: {"timestamp": "2026-06-13T13:44:54.434233", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107320908943544}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:44:54,747 - ERROR - ACTION: {"timestamp": "2026-06-13T13:44:54.747916", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107377662333150}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:44:55,022 - ERROR - ACTION: {"timestamp": "2026-06-13T13:44:55.022787", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107343671689279}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:44:55,367 - ERROR - ACTION: {"timestamp": "2026-06-13T13:44:55.367101", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107367113654437}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:44:55,835 - ERROR - ACTION: {"timestamp": "2026-06-13T13:44:55.835844", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107332078637188}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:00,507 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:00.507400", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107369315668254}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:01,033 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:01.033322", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107381457911940}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:01,604 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:01.604916", "action": "DELETE CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE CHANNEL", "channel_id": 1461107338755707117}, "success": false, "error": "Unknown action: DELETE CHANNEL"}
2026-06-13 15:45:01,858 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:01.858115", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107382473199637}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:02,235 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:02.235879", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107387552239868}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:02,502 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:02.502634", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107335131959363}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:06,798 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:06.798327", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107328458948638}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:07,063 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:07.063278", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107341247250463}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:07,394 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:07.394539", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107322431471812}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:07,661 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:07.661649", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107337652732119}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:08,201 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:08.201600", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107354035552411}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:08,744 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:08.744539", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107347383390221}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:13,177 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:13.177681", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1465459182793916601}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:13,480 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:13.479977", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107378899517534}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:13,787 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:13.787176", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107390673059945}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:14,123 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:14.123401", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107346255384649}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:14,420 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:14.420705", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1456784303995228344}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:14,701 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:14.701740", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107308435079199}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:19,481 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:19.481780", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107327381016629}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:19,846 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:19.846933", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107324209987779}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:20,164 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:20.164962", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107361493029100}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:20,708 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:20.708700", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107339548692716}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:21,123 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:21.123079", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1465740847109767257}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:21,406 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:21.406065", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107329226510388}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:25,983 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:25.983378", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107351175037041}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:26,245 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:26.245165", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107348771836201}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:26,731 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:26.731252", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107309500698689}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:27,006 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:27.006347", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107345097494730}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:27,537 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:27.537022", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107380430307513}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:27,854 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:27.853995", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107374688571638}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:32,359 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:32.359508", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107362554449981}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:32,673 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:32.673014", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107372339495033}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:33,166 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:33.166728", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107315402080523}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:33,497 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:33.497280", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1465740845088247828}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:34,309 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:34.309115", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1466003361496174643}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:34,626 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:34.626112", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107384993710205}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:34,910 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:34.910457", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1465740853766000765}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:39,699 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:39.699780", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107366358679736}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:39,939 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:39.939414", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107311043936474}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:40,494 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:40.494426", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107363816669496}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:40,834 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:40.834789", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107389142007962}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:41,100 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:41.100920", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107313359196414}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 15:45:41,348 - ERROR - ACTION: {"timestamp": "2026-06-13T13:45:41.348083", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"action": "DELETE_CHANNEL", "channel_id": 1461107373270630483}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:17:03,561 - INFO - ACTION: {"timestamp": "2026-06-13T14:17:03.561373", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyzing channels", "action": "DELETE_CHANNEL", "channel_id": "1461107370775285907"}, "success": true, "error": null}
2026-06-13 16:25:49,099 - INFO - ACTION: {"timestamp": "2026-06-13T14:25:49.099834", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🔍・audit", "action": "DELETE_CHANNEL", "channel_id": "1461107370775285907"}, "success": true, "error": null}
2026-06-13 16:25:49,583 - INFO - ACTION: {"timestamp": "2026-06-13T14:25:49.583452", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🎨・ui-kit", "action": "DELETE_CHANNEL", "channel_id": "1461107320908943544"}, "success": true, "error": null}
2026-06-13 16:25:50,324 - INFO - ACTION: {"timestamp": "2026-06-13T14:25:50.324922", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 📊・metrics", "action": "DELETE_CHANNEL", "channel_id": "1461107377662333150"}, "success": true, "error": null}
2026-06-13 16:25:50,777 - INFO - ACTION: {"timestamp": "2026-06-13T14:25:50.777452", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🐳・docker", "action": "DELETE_CHANNEL", "channel_id": "1461107343671689279"}, "success": true, "error": null}
2026-06-13 16:25:51,493 - INFO - ACTION: {"timestamp": "2026-06-13T14:25:51.493942", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 📋・changelog", "action": "DELETE_CHANNEL", "channel_id": "1461107367113654437"}, "success": true, "error": null}
2026-06-13 16:25:51,940 - INFO - ACTION: {"timestamp": "2026-06-13T14:25:51.940937", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🏗・architecture", "action": "DELETE_CHANNEL", "channel_id": "1461107332078637188"}, "success": true, "error": null}
2026-06-13 16:25:52,475 - INFO - ACTION: {"timestamp": "2026-06-13T14:25:52.475258", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🛡・vulnerabilities", "action": "DELETE_CHANNEL", "channel_id": "1461107369315668254"}, "success": true, "error": null}
2026-06-13 16:25:57,265 - INFO - ACTION: {"timestamp": "2026-06-13T14:25:57.265585", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleteting channel 📈・analytics", "action": "DELETE_CHANNEL", "channel_id": "1461107381457911940"}, "success": true, "error": null}
2026-06-13 16:25:57,898 - INFO - ACTION: {"timestamp": "2026-06-13T14:25:57.898843", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel ⚡・performance", "action": "DELETE_CHANNEL", "channel_id": "1461107338755707117"}, "success": true, "error": null}
2026-06-13 16:25:58,521 - INFO - ACTION: {"timestamp": "2026-06-13T14:25:58.521299", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel ⏱・uptime", "action": "DELETE_CHANNEL", "channel_id": "1461107382473199637"}, "success": true, "error": null}
2026-06-13 16:25:59,209 - INFO - ACTION: {"timestamp": "2026-06-13T14:25:59.209618", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🎲・random", "action": "DELETE_CHANNEL", "channel_id": "1461107387552239868"}, "success": true, "error": null}
2026-06-13 16:25:59,862 - INFO - ACTION: {"timestamp": "2026-06-13T14:25:59.862839", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 📐・schemas", "action": "DELETE_CHANNEL", "channel_id": "1461107335131959363"}, "success": true, "error": null}
2026-06-13 16:26:00,625 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:00.625402", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 📊・api-graphql", "action": "DELETE_CHANNEL", "channel_id": "1461107328458948638"}, "success": true, "error": null}
2026-06-13 16:26:01,090 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:01.090880", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🍃・nosql", "action": "DELETE_CHANNEL", "channel_id": "1461107341247250463"}, "success": true, "error": null}
2026-06-13 16:26:01,545 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:01.545714", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🎀・css-scss", "action": "DELETE_CHANNEL", "channel_id": "1461107322431471812"}, "success": true, "error": null}
2026-06-13 16:26:02,172 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:02.172858", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🚚・migrations", "action": "DELETE_CHANNEL", "channel_id": "1461107337652732119"}, "success": true, "error": null}
2026-06-13 16:26:02,990 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:02.990183", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🐛・bug-reports", "action": "DELETE_CHANNEL", "channel_id": "1461107354035552411"}, "success": true, "error": null}
2026-06-13 16:26:07,892 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:07.892046", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🔨・jenkins", "action": "DELETE_CHANNEL", "channel_id": "1461107347383390221"}, "success": true, "error": null}
2026-06-13 16:26:08,311 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:08.310976", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🛠・miscellaneous", "action": "DELETE_CHANNEL", "channel_id": "1465459182793916601"}, "success": true, "error": null}
2026-06-13 16:26:08,943 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:08.943593", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 📄・logs", "action": "DELETE_CHANNEL", "channel_id": "1461107378899517534"}, "success": true, "error": null}
2026-06-13 16:26:09,418 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:09.418152", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 💡・suggestions", "action": "DELETE_CHANNEL", "channel_id": "1461107390673059945"}, "success": true, "error": null}
2026-06-13 16:26:10,110 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:10.109969", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🔄・github-actions", "action": "DELETE_CHANNEL", "channel_id": "1461107346255384649"}, "success": true, "error": null}
2026-06-13 16:26:10,543 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:10.543208", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 📢・announcements", "action": "DELETE_CHANNEL", "channel_id": "1461107392141066292"}, "success": true, "error": null}
2026-06-13 16:26:11,470 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:11.469971", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 📍・roadmap", "action": "DELETE_CHANNEL", "channel_id": "1461107308435079199"}, "success": true, "error": null}
2026-06-13 16:26:12,057 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:12.057565", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel ♿・accessibility", "action": "DELETE_CHANNEL", "channel_id": "1461107324209987779"}, "success": true, "error": null}
2026-06-13 16:26:12,714 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:12.714536", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 📖・api-docs", "action": "DELETE_CHANNEL", "channel_id": "1461107361493029100"}, "success": true, "error": null}
2026-06-13 16:26:17,357 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:17.357844", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 💾・backup-restore", "action": "DELETE_CHANNEL", "channel_id": "1461107339548692716"}, "success": true, "error": null}
2026-06-13 16:26:17,928 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:17.928219", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 📚・apireference", "action": "DELETE_CHANNEL", "channel_id": "1465740847109767257"}, "success": true, "error": null}
2026-06-13 16:26:18,413 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:18.413908", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🔀・microservices", "action": "DELETE_CHANNEL", "channel_id": "1461107329226510388"}, "success": true, "error": null}
2026-06-13 16:26:19,052 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:19.052099", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🧪・unit-tests", "action": "DELETE_CHANNEL", "channel_id": "1461107351175037041"}, "success": true, "error": null}
2026-06-13 16:26:19,592 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:19.592482", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🚀・deployments", "action": "DELETE_CHANNEL", "channel_id": "1461107348771836201"}, "success": true, "error": null}
2026-06-13 16:26:20,258 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:20.258114", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 📦・backlog", "action": "DELETE_CHANNEL", "channel_id": "1461107309500698689"}, "success": true, "error": null}
2026-06-13 16:26:21,043 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:21.043891", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel ☸・kubernetes", "action": "DELETE_CHANNEL", "channel_id": "1461107345097494730"}, "success": true, "error": null}
2026-06-13 16:26:21,506 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:21.506198", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel ⚠・alerts", "action": "DELETE_CHANNEL", "channel_id": "1461107380430307513"}, "success": true, "error": null}
2026-06-13 16:26:22,359 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:22.359121", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🚨・incidents", "action": "DELETE_CHANNEL", "channel_id": "1461107374688571638"}, "success": true, "error": null}
2026-06-13 16:26:22,985 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:22.985216", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 💬・code-comments", "action": "DELETE_CHANNEL", "channel_id": "1461107362554449981"}, "success": true, "error": null}
2026-06-13 16:26:27,837 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:27.837414", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🔒・secrets", "action": "DELETE_CHANNEL", "channel_id": "1461107372339495033"}, "success": true, "error": null}
2026-06-13 16:26:28,407 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:28.407702", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🔍・reviews-retro", "action": "DELETE_CHANNEL", "channel_id": "1461107315402080523"}, "success": true, "error": null}
2026-06-13 16:26:28,812 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:28.812830", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting voice Test pipus", "action": "DELETE_CHANNEL", "channel_id": "1466003361496174643"}, "success": true, "error": null}
2026-06-13 16:26:29,298 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:29.298836", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting text 💻・general-dev", "action": "DELETE_CHANNEL", "channel_id": "1461107384993710205"}, "success": true, "error": null}
2026-06-13 16:26:30,072 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:30.072142", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🗂・onboarding", "action": "DELETE_CHANNEL", "channel_id": "1465740853766000765"}, "success": true, "error": null}
2026-06-13 16:26:30,619 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:30.619719", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel ❓・faq", "action": "DELETE_CHANNEL", "channel_id": "1461107366358679736"}, "success": true, "error": null}
2026-06-13 16:26:31,348 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:31.348699", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🏃・sprints", "action": "DELETE_CHANNEL", "channel_id": "1461107311043936474"}, "success": true, "error": null}
2026-06-13 16:26:32,160 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:32.160222", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 📑・guides", "action": "DELETE_CHANNEL", "channel_id": "1461107363816669496"}, "success": true, "error": null}
2026-06-13 16:26:32,656 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:32.656240", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 📅・meetings", "action": "DELETE_CHANNEL", "channel_id": "1461107389142007962"}, "success": true, "error": null}
2026-06-13 16:26:37,315 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:37.315634", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🌅・daily-standup", "action": "DELETE_CHANNEL", "channel_id": "1461107313359196414"}, "success": true, "error": null}
2026-06-13 16:26:38,009 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:38.009301", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 📜・compliance", "action": "DELETE_CHANNEL", "channel_id": "1461107373270630483"}, "success": true, "error": null}
2026-06-13 16:26:38,477 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:38.477889", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 📈・performance-tests", "action": "DELETE_CHANNEL", "channel_id": "1461107358477582580"}, "success": true, "error": null}
2026-06-13 16:26:38,991 - INFO - ACTION: {"timestamp": "2026-06-13T14:26:38.991397", "action": "DELETE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting channel 🅰・vue-angular", "action": "DELETE_CHANNEL", "channel_id": "1461107319088873740"}, "success": true, "error": null}
2026-06-13 16:32:00,596 - ERROR - ACTION: {"timestamp": "2026-06-13T14:32:00.596866", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "deleting category ⚙️ | Développement Backend", "action": "DELETE_CATEGORY", "category_id": "1461107292660568084"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:32:00,911 - ERROR - ACTION: {"timestamp": "2026-06-13T14:32:00.911698", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "deleting category 💬 | Communication", "action": "DELETE_CATEGORY", "category_id": "1465740850465341604"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:32:01,414 - ERROR - ACTION: {"timestamp": "2026-06-13T14:32:01.414142", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "deleting category 📚 | Documentation", "action": "DELETE_CATEGORY", "category_id": "1461107299048226889"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:32:01,697 - ERROR - ACTION: {"timestamp": "2026-06-13T14:32:01.697788", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "deleting category 🎨 | Développement Frontend", "action": "DELETE_CATEGORY", "category_id": "1461107291053887712"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:32:02,327 - ERROR - ACTION: {"timestamp": "2026-06-13T14:32:02.326960", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "deleting category 🚀 | DevOps & CI/CD", "action": "DELETE_CATEGORY", "category_id": "1461107295814684703"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:32:02,809 - ERROR - ACTION: {"timestamp": "2026-06-13T14:32:02.809491", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "deleting category 🔐 | Sécurité", "action": "DELETE_CATEGORY", "category_id": "1461107300696723518"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:32:03,082 - ERROR - ACTION: {"timestamp": "2026-06-13T14:32:03.082622", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "deleting category 📈 | Monitoring & Analytics", "action": "DELETE_CATEGORY", "category_id": "1461107301715804221"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:32:08,041 - ERROR - ACTION: {"timestamp": "2026-06-13T14:32:08.041578", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "deleting category Vocaux", "action": "DELETE_CATEGORY", "category_id": "1466003189907193876"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:32:08,365 - ERROR - ACTION: {"timestamp": "2026-06-13T14:32:08.365944", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "deleting category 💬 | Collaboration", "action": "DELETE_CATEGORY", "category_id": "1461107302701469932"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:32:08,618 - ERROR - ACTION: {"timestamp": "2026-06-13T14:32:08.618354", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "deleting category 🗃️ | Base de Données", "action": "DELETE_CATEGORY", "category_id": "1461107295017635932"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:32:08,938 - ERROR - ACTION: {"timestamp": "2026-06-13T14:32:08.938258", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "deleting category 🧪 | Qualité & Tests", "action": "DELETE_CATEGORY", "category_id": "1461107297446269130"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:32:58,069 - ERROR - ACTION: {"timestamp": "2026-06-13T14:32:58.069659", "action": "WARN", "user": "pipusfr", "guild": "BETA", "params": {"thought": "analysis", "action": "WARN", "response": "Votre commentaire contient de la haine envers un groupe protégé, ce qui est contraire aux règles communautaires du serveur."}, "success": false, "error": "'Superviseur' object has no attribute 'ollama_api_url'"}
2026-06-13 16:34:17,604 - ERROR - ACTION: {"timestamp": "2026-06-13T14:34:17.603968", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting ⚙️ | Développement Backend", "action": "DELETE_CATEGORY", "category_id": "1461107292660568084"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:34:18,031 - ERROR - ACTION: {"timestamp": "2026-06-13T14:34:18.031450", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting 💬 | Communication", "action": "DELETE_CATEGORY", "category_id": "1465740850465341604"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:34:18,293 - ERROR - ACTION: {"timestamp": "2026-06-13T14:34:18.293384", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting 📚 | Documentation", "action": "DELETE_CATEGORY", "category_id": "1461107299048226889"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:34:18,794 - ERROR - ACTION: {"timestamp": "2026-06-13T14:34:18.794802", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting 🎨 | Développement Frontend", "action": "DELETE_CATEGORY", "category_id": "1461107291053887712"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:34:19,148 - ERROR - ACTION: {"timestamp": "2026-06-13T14:34:19.148324", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting 🚀 | DevOps & CI/CD", "action": "DELETE_CATEGORY", "category_id": "1461107295814684703"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:34:19,494 - ERROR - ACTION: {"timestamp": "2026-06-13T14:34:19.494177", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting 🔐 | Sécurité", "action": "DELETE_CATEGORY", "category_id": "1461107300696723518"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:34:23,927 - ERROR - ACTION: {"timestamp": "2026-06-13T14:34:23.927547", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting 📈 | Monitoring & Analytics", "action": "DELETE_CATEGORY", "category_id": "1461107301715804221"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:34:24,242 - ERROR - ACTION: {"timestamp": "2026-06-13T14:34:24.242495", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting Vocaux category", "action": "DELETE_CATEGORY", "category_id": "1466003189907193876"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:34:24,643 - ERROR - ACTION: {"timestamp": "2026-06-13T14:34:24.642993", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting 💬 | Collaboration", "action": "DELETE_CATEGORY", "category_id": "1461107302701469932"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:34:25,048 - ERROR - ACTION: {"timestamp": "2026-06-13T14:34:25.048495", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting 🗃️ | Base de Données", "action": "DELETE_CATEGORY", "category_id": "1461107295017635932"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:34:25,361 - ERROR - ACTION: {"timestamp": "2026-06-13T14:34:25.361597", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting 🧪 | Qualité & Tests", "action": "DELETE_CATEGORY", "category_id": "1461107297446269130"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 16:36:58,684 - INFO - ACTION: {"timestamp": "2026-06-13T14:36:58.684310", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting category", "action": "DELETE_CATEGORY", "category_id": "1461107291053887712"}, "success": true, "error": null}
2026-06-13 16:36:59,396 - INFO - ACTION: {"timestamp": "2026-06-13T14:36:59.395980", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting category", "action": "DELETE_CATEGORY", "category_id": "1461107292660568084"}, "success": true, "error": null}
2026-06-13 16:36:59,887 - INFO - ACTION: {"timestamp": "2026-06-13T14:36:59.886974", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting category", "action": "DELETE_CATEGORY", "category_id": "1461107295017635932"}, "success": true, "error": null}
2026-06-13 16:37:00,694 - INFO - ACTION: {"timestamp": "2026-06-13T14:37:00.694289", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting category", "action": "DELETE_CATEGORY", "category_id": "1461107295814684703"}, "success": true, "error": null}
2026-06-13 16:37:01,404 - INFO - ACTION: {"timestamp": "2026-06-13T14:37:01.404352", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting category", "action": "DELETE_CATEGORY", "category_id": "1461107297446269130"}, "success": true, "error": null}
2026-06-13 16:37:02,167 - INFO - ACTION: {"timestamp": "2026-06-13T14:37:02.167168", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting category", "action": "DELETE_CATEGORY", "category_id": "1461107299048226889"}, "success": true, "error": null}
2026-06-13 16:37:02,805 - INFO - ACTION: {"timestamp": "2026-06-13T14:37:02.805834", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting category", "action": "DELETE_CATEGORY", "category_id": "1461107300696723518"}, "success": true, "error": null}
2026-06-13 16:37:03,461 - INFO - ACTION: {"timestamp": "2026-06-13T14:37:03.461046", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting category", "action": "DELETE_CATEGORY", "category_id": "1461107301715804221"}, "success": true, "error": null}
2026-06-13 16:37:03,914 - INFO - ACTION: {"timestamp": "2026-06-13T14:37:03.914550", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting category", "action": "DELETE_CATEGORY", "category_id": "1461107302701469932"}, "success": true, "error": null}
2026-06-13 16:37:08,715 - INFO - ACTION: {"timestamp": "2026-06-13T14:37:08.715273", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting category", "action": "DELETE_CATEGORY", "category_id": "1465740850465341604"}, "success": true, "error": null}
2026-06-13 16:37:09,167 - INFO - ACTION: {"timestamp": "2026-06-13T14:37:09.167802", "action": "DELETE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Deleting category", "action": "DELETE_CATEGORY", "category_id": "1466003189907193876"}, "success": true, "error": null}
2026-06-13 16:43:49,858 - ERROR - ACTION: {"timestamp": "2026-06-13T14:43:49.858939", "action": "WARN", "user": "pipusfr", "guild": "BETA", "params": {"thought": "analysis", "action": "WARN", "member": "@! ~ 𝒜𝓁𝓈𝓉𝓸r ~", "reason": "sexism", "response": "⚠️ J'ai averti @! ~ 𝒜𝓁𝓇~ pour son comportement sexiste."}, "success": false, "error": "'NoneType' object has no attribute 'startswith'"}
2026-06-13 19:32:50,948 - INFO - ACTION: {"timestamp": "2026-06-13T17:32:50.948797", "action": "CREATE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Créer la catégorie Annonces", "action": "CREATE_CATEGORY", "category_name": "📢 Annonces"}, "success": true, "error": null}
2026-06-13 19:32:51,608 - INFO - ACTION: {"timestamp": "2026-06-13T17:32:51.608802", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon annonces dans 📢 Annonces", "action": "CREATE_CHANNEL", "channel_name": "annonces", "type": "text", "parent_category": "📢 Annonces"}, "success": true, "error": null}
2026-06-13 19:32:52,085 - INFO - ACTION: {"timestamp": "2026-06-13T17:32:52.085578", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon événements dans 📢 Annonces", "action": "CREATE_CHANNEL", "channel_name": "événements", "type": "text", "parent_category": "📢 Annonces"}, "success": true, "error": null}
2026-06-13 19:32:52,481 - INFO - ACTION: {"timestamp": "2026-06-13T17:32:52.481251", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon règlement dans 📢 Annonces", "action": "CREATE_CHANNEL", "channel_name": "règlement", "type": "text", "parent_category": "📢 Annonces"}, "success": true, "error": null}
2026-06-13 19:32:52,980 - INFO - ACTION: {"timestamp": "2026-06-13T17:32:52.980224", "action": "CREATE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Créer la catégorie Général", "action": "CREATE_CATEGORY", "category_name": "💬 Général"}, "success": true, "error": null}
2026-06-13 19:32:53,794 - INFO - ACTION: {"timestamp": "2026-06-13T17:32:53.794069", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon général-chat dans 💬 Général", "action": "CREATE_CHANNEL", "channel_name": "général-chat", "type": "text", "parent_category": "💬 Général"}, "success": true, "error": null}
2026-06-13 19:32:54,371 - INFO - ACTION: {"timestamp": "2026-06-13T17:32:54.371723", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon présentations dans 💬 Général", "action": "CREATE_CHANNEL", "channel_name": "présentations", "type": "text", "parent_category": "💬 Général"}, "success": true, "error": null}
2026-06-13 19:32:54,779 - INFO - ACTION: {"timestamp": "2026-06-13T17:32:54.779728", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon off-topic dans 💬 Général", "action": "CREATE_CHANNEL", "channel_name": "off-topic", "type": "text", "parent_category": "💬 Général"}, "success": true, "error": null}
2026-06-13 19:32:59,685 - INFO - ACTION: {"timestamp": "2026-06-13T17:32:59.685019", "action": "CREATE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Créer la catégorie Guides & Ressources", "action": "CREATE_CATEGORY", "category_name": "🛠️ Guides & Ressources"}, "success": true, "error": null}
2026-06-13 19:33:00,193 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:00.193523", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon recettes-de-crafting dans 🛠️ Guides & Ressources", "action": "CREATE_CHANNEL", "channel_name": "recettes-de-crafting", "type": "text", "parent_category": "🛠️ Guides & Ressources"}, "success": true, "error": null}
2026-06-13 19:33:00,983 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:00.983029", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon build-tips dans 🛠️ Guides & Ressources", "action": "CREATE_CHANNEL", "channel_name": "build-tips", "type": "text", "parent_category": "🛠️ Guides & Ressources"}, "success": true, "error": null}
2026-06-13 19:33:01,588 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:01.588431", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon mods-et-plugins dans 🛠️ Guides & Ressources", "action": "CREATE_CHANNEL", "channel_name": "mods-et-plugins", "type": "text", "parent_category": "🛠️ Guides & Ressources"}, "success": true, "error": null}
2026-06-13 19:33:02,040 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:02.040914", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon faq-minecraft dans 🛠️ Guides & Ressources", "action": "CREATE_CHANNEL", "channel_name": "faq-minecraft", "type": "text", "parent_category": "🛠️ Guides & Ressources"}, "success": true, "error": null}
2026-06-13 19:33:02,647 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:02.647704", "action": "CREATE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Créer la catégorie Serveurs", "action": "CREATE_CATEGORY", "category_name": "🏰 Serveurs"}, "success": true, "error": null}
2026-06-13 19:33:03,121 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:03.121194", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon serveur-1-info dans 🏰 Serveurs", "action": "CREATE_CHANNEL", "channel_name": "serveur-1-info", "type": "text", "parent_category": "🏰 Serveurs"}, "success": true, "error": null}
2026-06-13 19:33:03,630 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:03.630931", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon serveur-2-info dans 🏰 Serveurs", "action": "CREATE_CHANNEL", "channel_name": "serveur-2-info", "type": "text", "parent_category": "🏰 Serveurs"}, "success": true, "error": null}
2026-06-13 19:33:04,152 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:04.152584", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon serveur-3-info dans 🏰 Serveurs", "action": "CREATE_CHANNEL", "channel_name": "serveur-3-info", "type": "text", "parent_category": "🏰 Serveurs"}, "success": true, "error": null}
2026-06-13 19:33:09,105 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:09.105244", "action": "CREATE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Créer la catégorie Jeux & Compétitions", "action": "CREATE_CATEGORY", "category_name": "🎮 Jeux & Compétitions"}, "success": true, "error": null}
2026-06-13 19:33:09,643 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:09.643064", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon tournament-rules dans 🎮 Jeux & Compétitions", "action": "CREATE_CHANNEL", "channel_name": "tournament-rules", "type": "text", "parent_category": "🎮 Jeux & Compétitions"}, "success": true, "error": null}
2026-06-13 19:33:10,203 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:10.203528", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon match-schedule dans 🎮 Jeux & Compétitions", "action": "CREATE_CHANNEL", "channel_name": "match-schedule", "type": "text", "parent_category": "🎮 Jeux & Compétitions"}, "success": true, "error": null}
2026-06-13 19:33:10,759 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:10.759727", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon leaderboards dans 🎮 Jeux & Compétitions", "action": "CREATE_CHANNEL", "channel_name": "leaderboards", "type": "text", "parent_category": "🎮 Jeux & Compétitions"}, "success": true, "error": null}
2026-06-13 19:33:11,300 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:11.299968", "action": "CREATE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Créer la catégorie Support Technique", "action": "CREATE_CATEGORY", "category_name": "🔧 Support Technique"}, "success": true, "error": null}
2026-06-13 19:33:11,758 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:11.758015", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon questions-techniques dans 🔧 Support Technique", "action": "CREATE_CHANNEL", "channel_name": "questions-techniques", "type": "text", "parent_category": "🔧 Support Technique"}, "success": true, "error": null}
2026-06-13 19:33:12,504 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:12.504337", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon bug-report dans 🔧 Support Technique", "action": "CREATE_CHANNEL", "channel_name": "bug-report", "type": "text", "parent_category": "🔧 Support Technique"}, "success": true, "error": null}
2026-06-13 19:33:12,938 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:12.938165", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon suggestions dans 🔧 Support Technique", "action": "CREATE_CHANNEL", "channel_name": "suggestions", "type": "text", "parent_category": "🔧 Support Technique"}, "success": true, "error": null}
2026-06-13 19:33:17,664 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:17.664388", "action": "CREATE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Créer la catégorie Media", "action": "CREATE_CATEGORY", "category_name": "📸 Media"}, "success": true, "error": null}
2026-06-13 19:33:18,176 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:18.176840", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon screenshots dans 📸 Media", "action": "CREATE_CHANNEL", "channel_name": "screenshots", "type": "text", "parent_category": "📸 Media"}, "success": true, "error": null}
2026-06-13 19:33:18,909 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:18.909138", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon videos dans 📸 Media", "action": "CREATE_CHANNEL", "channel_name": "videos", "type": "text", "parent_category": "📸 Media"}, "success": true, "error": null}
2026-06-13 19:33:19,611 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:19.611270", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon streamers dans 📸 Media", "action": "CREATE_CHANNEL", "channel_name": "streamers", "type": "text", "parent_category": "📸 Media"}, "success": true, "error": null}
2026-06-13 19:33:20,047 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:20.047910", "action": "CREATE_CATEGORY", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Créer la catégorie Voice (optionnel)", "action": "CREATE_CATEGORY", "category_name": "🎤 Voice"}, "success": true, "error": null}
2026-06-13 19:33:20,650 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:20.650552", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon general-voice en voix dans 🎤 Voice", "action": "CREATE_CHANNEL", "channel_name": "general-voice", "type": "voice", "parent_category": "🎤 Voice"}, "success": true, "error": null}
2026-06-13 19:33:21,107 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:21.107332", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon build-chat en voix dans 🎤 Voice", "action": "CREATE_CHANNEL", "channel_name": "build-chat", "type": "voice", "parent_category": "🎤 Voice"}, "success": true, "error": null}
2026-06-13 19:33:21,600 - INFO - ACTION: {"timestamp": "2026-06-13T17:33:21.600232", "action": "CREATE_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Ajouter le salon pvp-arena en voix dans 🎤 Voice", "action": "CREATE_CHANNEL", "channel_name": "pvp-arena", "type": "voice", "parent_category": "🎤 Voice"}, "success": true, "error": null}
2026-06-13 19:36:21,082 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:21.082357", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer 💬・général dans la catégorie Général", "action": "MODIFY_CHANNEL", "channel_id": "1456784303995228344", "category_id": "1515408630839509114"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:21,579 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:21.579595", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer annonces vers Annonces", "action": "MODIFY_CHANNEL", "channel_id": "1515408624627744859", "category_id": "1515408621020905483"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:22,018 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:22.018705", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer événements vers Annonnes", "action": "MODIFY_CHANNEL", "channel_id": "1515408627538853908", "category_id": "1515408621020905483"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:22,518 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:22.518284", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer règlement vers Annonces", "action": "MODIFY_CHANNEL", "channel_id": "1515408629438877776", "category_id": "1515408621020905483"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:23,044 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:23.043972", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer général-chat dans Général", "action": "MODIFY_CHANNEL", "channel_id": "1515408633381261584", "category_id": "1515408630839509114"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:23,399 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:23.399853", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer présentations vers Général", "action": "MODIFY_CHANNEL", "channel_id": "1515408636787032135", "category_id": "1515408630839509114"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:23,639 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:23.639594", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer off-topic dans Général", "action": "MODIFY_CHANNEL", "channel_id": "1515408639006081065", "category_id": "1515408630839509114"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:28,369 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:28.369572", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer recettes-de-crafting vers Guides & Ressources", "action": "MODIFY_CHANNEL", "channel_id": "1515408661361459240", "category_id": "1515408640750915634"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:28,647 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:28.647611", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer build-tips dans Guides & Ressources", "action": "MODIFY_CHANNEL", "channel_id": "1515408663152693321", "category_id": "1515408640750915634"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:29,095 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:29.095182", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer mods-et-plugins vers Guides & Ressources", "action": "MODIFY_CHANNEL", "channel_id": "1515408666956796086", "category_id": "1515408640750915634"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:29,424 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:29.424077", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer faq-minecraft dans Guides & Ressources", "action": "MODIFY_CHANNEL", "channel_id": "1515408669473378344", "category_id": "1515408640750915634"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:29,671 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:29.671764", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer serveur-1-info vers Serveurs", "action": "MODIFY_CHANNEL", "channel_id": "1515408673755889815", "category_id": "1515408671377588324"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:29,998 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:29.998647", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer serveur-2-info dans Serveurs", "action": "MODIFY_CHANNEL", "channel_id": "1515408675630743665", "category_id": "1515408671377588324"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:34,620 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:34.620347", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer serveur-3-info vers Serveurs", "action": "MODIFY_CHANNEL", "channel_id": "1515408678101057707", "category_id": "1515408671377588324"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:34,870 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:34.870176", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer tournament-rules dans Jeux & Compétitions", "action": "MODIFY_CHANNEL", "channel_id": "1515408700876128287", "category_id": "1515408680391278602"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:35,287 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:35.287508", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer match-schedule vers Jeux & Compétitions", "action": "MODIFY_CHANNEL", "channel_id": "1515408703287722064", "category_id": "1515408680391278602"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:35,551 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:35.551925", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer leaderboards dans Jeux & Compétitions", "action": "MODIFY_CHANNEL", "channel_id": "1515408705414500534", "category_id": "1515408680391278602"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:35,936 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:35.936326", "action": "MODIFY CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer questions-techniques vers Support Technique", "action": "MODIFY CHANNEL", "channel_id": "1515408710032298065", "category_id": "1515408707507196050"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:36,296 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:36.296546", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer bug-report dans Support Technique", "action": "MODIFY_CHANNEL", "channel_id": "1515408712007684167", "category_id": "1515408707507196050"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:40,930 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:40.930387", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer suggestions vers Support Technique", "action": "MODIFY_CHANNEL", "channel_id": "1515408714922852535", "category_id": "1515408707507196050"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:41,312 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:41.312831", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer screenshots dans Media", "action": "MODIFY_CHANNEL", "channel_id": "1515408736565592178", "category_id": "1515408716948705300"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:41,568 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:41.568110", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer videos vers Media", "action": "MODIFY_CHANNEL", "channel_id": "1515408739040235681", "category_id": "1515408716948705300"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:36:41,996 - ERROR - ACTION: {"timestamp": "2026-06-13T17:36:41.995981", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "déplacer streamers dans Media", "action": "MODIFY_CHANNEL", "channel_id": "1515408741980438620", "category_id": "1515408716948705300"}, "success": false, "error": "'NoneType' object has no attribute 'casefold'"}
2026-06-13 19:53:02,778 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:02.778449", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408712007684167, "new_category_id": 1515408707507196050}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:03,203 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:03.203815", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408736565592178, "new_category_id": 1515408716948705300}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:03,725 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:03.725719", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408678101057707, "new_category_id": 1515408671377588324}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:04,971 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:04.971198", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408673755889815, "new_category_id": 1515408671377588324}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:05,554 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:05.554073", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408633381261584, "new_category_id": 1515408630839509114}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:07,597 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:07.597101", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408666956796086, "new_category_id": 1515408640750915634}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:08,023 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:08.023012", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408627538853908, "new_category_id": 1515408621020905483}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:08,461 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:08.461560", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408700876128287, "new_category_id": 1515408680391278602}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:08,975 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:08.975549", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408669473378344, "new_category_id": 1515408640750915634}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:09,499 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:09.499606", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408663152693321, "new_category_id": 1515408640750915634}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:09,980 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:09.980189", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1461107327381016629, "new_category_id": 1515408707507196050}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:10,452 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:10.452829", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408751220490340, "new_category_id": 1515408680391278602}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:15,316 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:15.316956", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408739040235681, "new_category_id": 1515408716948705300}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:15,737 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:15.737399", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408749261750435, "new_category_id": 1515408640750915634}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:16,366 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:16.366462", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408624627744859, "new_category_id": 1515408621020905483}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:16,968 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:16.967993", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408703287722064, "new_category_id": 1515408680391278602}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:17,432 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:17.432795", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408710032298065, "new_category_id": 1515408707507196050}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:17,981 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:17.981658", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408636787032135, "new_category_id": 1515408630839509114}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:18,597 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:18.597432", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408741980438620, "new_category_id": 1515408716948705300}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:19,012 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:19.012166", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408629438877776, "new_category_id": 1515408621020905483}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:23,794 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:23.793971", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408705414500534, "new_category_id": 1515408680391278602}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:24,383 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:24.383361", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408714922852535, "new_category_id": 1515408707507196050}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:53:24,872 - ERROR - ACTION: {"timestamp": "2026-06-13T17:53:24.872794", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analyze", "action": "MODIFY_CHANNEL", "channel_id": 1515408661361459240, "new_category_id": 1515408640750915634}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 19:59:22,202 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:22.202760", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move bug-report", "action": "MODIFY_CHANNEL", "channel_id": "1515408712007684167", "new_category_id": "1515408707507196050"}, "success": true, "error": null}
2026-06-13 19:59:22,674 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:22.674601", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move screenshots", "action": "MODIFY_CHANNEL", "channel_id": "1515408736565592178", "new_category_id": "1515408716948705300"}, "success": true, "error": null}
2026-06-13 19:59:23,111 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:23.111869", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move serveur-3-info", "action": "MODIFY_CHANNEL", "channel_id": "1515408678101057707", "new_category_id": "1515408671377588324"}, "success": true, "error": null}
2026-06-13 19:59:23,550 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:23.550918", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move serveur-1-info", "action": "MODIFY_CHANNEL", "channel_id": "1515408673755889815", "new_category_id": "1515408671377588324"}, "success": true, "error": null}
2026-06-13 19:59:23,962 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:23.962966", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move général-chat", "action": "MODIFY_CHANNEL", "channel_id": "1515408633381261584", "new_category_id": "1515408630839509114"}, "success": true, "error": null}
2026-06-13 19:59:24,378 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:24.378574", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move mods-et-plugins", "action": "MODIFY_CHANNEL", "channel_id": "1515408666956796086", "new_category_id": "1515408640750915634"}, "success": true, "error": null}
2026-06-13 19:59:29,205 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:29.205830", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move événements", "action": "MODIFY_CHANNEL", "channel_id": "1515408627538853908", "new_category_id": "1515408621020905483"}, "success": true, "error": null}
2026-06-13 19:59:29,616 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:29.616781", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move tournament-rules", "action": "MODIFY_CHANNEL", "channel_id": "1515408700876128287", "new_category_id": "1515408680391278602"}, "success": true, "error": null}
2026-06-13 19:59:30,664 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:30.664877", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move faq-minecraft", "action": "MODIFY_CHANNEL", "channel_id": "1515408669473378344", "new_category_id": "1515408640750915634"}, "success": true, "error": null}
2026-06-13 19:59:31,119 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:31.119108", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move build-tips", "action": "MODIFY_CHANNEL", "channel_id": "1515408663152693321", "new_category_id": "1515408640750915634"}, "success": true, "error": null}
2026-06-13 19:59:31,514 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:31.514282", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move pvp-arena", "action": "MODIFY_CHANNEL", "channel_id": "1515408751220490340", "new_category_id": "1515408680391278602"}, "success": true, "error": null}
2026-06-13 19:59:32,278 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:32.278056", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move videos", "action": "MODIFY_CHANNEL", "channel_id": "1515408739040235681", "new_category_id": "1515408716948705300"}, "success": true, "error": null}
2026-06-13 19:59:32,794 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:32.794935", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move build-chat", "action": "MODIFY_CHANNEL", "channel_id": "1515408749261750435", "new_category_id": "1515408680391278602"}, "success": true, "error": null}
2026-06-13 19:59:33,195 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:33.195770", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move annonces channel", "action": "MODIFY_CHANNEL", "channel_id": "1515408624627744859", "new_category_id": "1515408621020905483"}, "success": true, "error": null}
2026-06-13 19:59:37,764 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:37.763974", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move match-schedule", "action": "MODIFY_CHANNEL", "channel_id": "1515408703287722064", "new_category_id": "1515408680391278602"}, "success": true, "error": null}
2026-06-13 19:59:38,261 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:38.261792", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move questions-techniques", "action": "MODIFY_CHANNEL", "channel_id": "1515408710032298065", "new_category_id": "1515408707507196050"}, "success": true, "error": null}
2026-06-13 19:59:38,873 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:38.873842", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move general-voice to voice category", "action": "MODIFY_CHANNEL", "channel_id": "1515408746627469506", "new_category_id": "1515408744937295893"}, "success": true, "error": null}
2026-06-13 19:59:40,359 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:40.359111", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move recettes-de-crafting", "action": "MODIFY_CHANNEL", "channel_id": "1515408661361459240", "new_category_id": "1515408640750915634"}, "success": true, "error": null}
2026-06-13 19:59:40,951 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:40.951742", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move serveur-2-info", "action": "MODIFY_CHANNEL", "channel_id": "1515408675630743665", "new_category_id": "1515408671377588324"}, "success": true, "error": null}
2026-06-13 19:59:41,578 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:41.578341", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move off-topic", "action": "MODIFY_CHANNEL", "channel_id": "1515408639006081065", "new_category_id": "1515408630839509114"}, "success": true, "error": null}
2026-06-13 19:59:42,059 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:42.059073", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move 💬・général to Général category", "action": "MODIFY_CHANNEL", "channel_id": "1456784303995228344", "new_category_id": "1515408630839509114"}, "success": true, "error": null}
2026-06-13 19:59:42,707 - INFO - ACTION: {"timestamp": "2026-06-13T17:59:42.707133", "action": "MODIFY_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "move streamers channel", "action": "MODIFY_CHANNEL", "channel_id": "1515408741980438620", "new_category_id": "1515408716948705300"}, "success": true, "error": null}
2026-06-13 20:01:47,813 - ERROR - ACTION: {"timestamp": "2026-06-13T18:01:47.813558", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon bug-report", "action": "RENAME_CHANNEL", "channel_id": "1515408712007684167", "new_channel_name": "🐛 Bug Reports"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:01:48,349 - ERROR - ACTION: {"timestamp": "2026-06-13T18:01:48.348969", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon screenshots", "action": "RENAME_CHANNEL", "channel_id": "1515408736565592178", "new_channel_name": "📸 Screenshots & Media"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:01:48,922 - ERROR - ACTION: {"timestamp": "2026-06-13T18:01:48.922645", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon serveur-3-info", "action": "RENAME_CHANNEL", "channel_id": "1515408678101057707", "new_channel_name": "🌍 Server3 Info"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:01:49,687 - ERROR - ACTION: {"timestamp": "2026-06-13T18:01:49.687849", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon serveur-1-info", "action": "RENAME_CHANNEL", "channel_id": "1515408673755889815", "new_channel_name": "🌎 Server1 Info"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:01:50,188 - ERROR - ACTION: {"timestamp": "2026-06-13T18:01:50.188925", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon général-chat", "action": "RENAME_CHANNEL", "channel_id": "1515408633381261584", "new_channel_name": "💬 General Chat"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:01:51,541 - ERROR - ACTION: {"timestamp": "2026-06-13T18:01:51.541530", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon mods-et-plugins", "action": "RENAME_CHANNEL", "channel_id": "1515408666956796086", "new_channel_name": "🔧 Mods & Plugins"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:01:52,080 - ERROR - ACTION: {"timestamp": "2026-06-13T18:01:52.080425", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon événements", "action": "RENAME_CHANNEL", "channel_id": "1515408627538853908", "new_channel_name": "🎉 Events"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:01:52,733 - ERROR - ACTION: {"timestamp": "2026-06-13T18:01:52.733652", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon tournament-rules", "action": "RENAME_CHANNEL", "channel_id": "1515408700876128287", "new_channel_name": "🏆 Tournament Rules"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:01:53,300 - ERROR - ACTION: {"timestamp": "2026-06-13T18:01:53.300944", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon faq-minecraft", "action": "RENAME_CHANNEL", "channel_id": "1515408669473378344", "new_channel_name": "❓ Minecraft FAQ"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:01:53,860 - ERROR - ACTION: {"timestamp": "2026-06-13T18:01:53.860536", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon build-tips", "action": "RENAME_CHANNEL", "channel_id": "1515408663152693321", "new_channel_name": "⚒️ Build Tips"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:01:54,310 - ERROR - ACTION: {"timestamp": "2026-06-13T18:01:54.310830", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon pvp-arena", "action": "RENAME_CHANNEL", "channel_id": "1515408751220490340", "new_channel_name": "🤺 PvP Arena"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:01:59,282 - ERROR - ACTION: {"timestamp": "2026-06-13T18:01:59.282046", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon videos", "action": "RENAME_CHANNEL", "channel_id": "1515408739040235681", "new_channel_name": "📹 Videos"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:01:59,807 - ERROR - ACTION: {"timestamp": "2026-06-13T18:01:59.807432", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon build-chat", "action": "RENAME_CHANNEL", "channel_id": "1515408749261750435", "new_channel_name": "💬 Build Chat"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:02:00,677 - ERROR - ACTION: {"timestamp": "2026-06-13T18:02:00.677162", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon annonces", "action": "RENAME_CHANNEL", "channel_id": "1515408624627744859", "new_channel_name": "🔔 Announcements"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:02:01,110 - ERROR - ACTION: {"timestamp": "2026-06-13T18:02:01.110809", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon match-schedule", "action": "RENAME_CHANNEL", "channel_id": "1515408703287722064", "new_channel_name": "⌚ Match Schedule"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:02:01,746 - ERROR - ACTION: {"timestamp": "2026-06-13T18:02:01.746413", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon questions-techniques", "action": "RENAME_CHANNEL", "channel_id": "1515408710032298065", "new_channel_name": "🛠️ Tech Questions"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:02:02,250 - ERROR - ACTION: {"timestamp": "2026-06-13T18:02:02.250808", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon general-voice (text)", "action": "RENAME_CHANNEL", "channel_id": "1515408746627469506", "new_channel_name": "🎤 Voice Text"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:02:02,680 - ERROR - ACTION: {"timestamp": "2026-06-13T18:02:02.680260", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon présentations", "action": "RENAME_CHANNEL", "channel_id": "1515408636787032135", "new_channel_name": "🌟 Presentations"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:02:03,179 - ERROR - ACTION: {"timestamp": "2026-06-13T18:02:03.179930", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon streamers", "action": "RENAME_CHANNEL", "channel_id": "1515408741980438620", "new_channel_name": "📺 Streamer Spot"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:02:07,831 - ERROR - ACTION: {"timestamp": "2026-06-13T18:02:07.831059", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon règlement", "action": "RENAME_CHANNEL", "channel_id": "1515408629438877776", "new_channel_name": "⚖️ Rules & Regulations"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:02:08,348 - ERROR - ACTION: {"timestamp": "2026-06-13T18:02:08.348831", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon leaderboards", "action": "RENAME_CHANNEL", "channel_id": "1515408705414500534", "new_channel_name": "📊 Leaderboards"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:02:08,837 - ERROR - ACTION: {"timestamp": "2026-06-13T18:02:08.837203", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon suggestions", "action": "RENAME_CHANNEL", "channel_id": "1515408714922852535", "new_channel_name": "💡 Suggestions"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:02:09,353 - ERROR - ACTION: {"timestamp": "2026-06-13T18:02:09.353962", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon recettes-de-crafting", "action": "RENAME_CHANNEL", "channel_id": "1515408661361459240", "new_channel_name": "🍲 Crafting Recipes"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:02:09,824 - ERROR - ACTION: {"timestamp": "2026-06-13T18:02:09.824573", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon serveur-2-info", "action": "RENAME_CHANNEL", "channel_id": "1515408675630743665", "new_channel_name": "🗺️ Server2 Info"}, "success": false, "error": "400 Bad Request (error code: 50035): Invalid Form Body\nIn name: This field is required"}
2026-06-13 20:05:39,538 - INFO - ACTION: {"timestamp": "2026-06-13T18:05:39.538243", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon bug-report", "action": "RENAME_CHANNEL", "channel_id": "1515408712007684167", "new_name": "🐞 Bug Report"}, "success": true, "error": null}
2026-06-13 20:05:39,969 - INFO - ACTION: {"timestamp": "2026-06-13T18:05:39.969547", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon screenshots", "action": "RENAME_CHANNEL", "channel_id": "1515408736565592178", "new_name": "📸 Screenshots & Media"}, "success": true, "error": null}
2026-06-13 20:05:40,427 - INFO - ACTION: {"timestamp": "2026-06-13T18:05:40.427387", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon serveur-3-info", "action": "RENAME_CHANNEL", "channel_id": "1515408678101057707", "new_name": "🌍 Server 3 Info"}, "success": true, "error": null}
2026-06-13 20:05:40,949 - INFO - ACTION: {"timestamp": "2026-06-13T18:05:40.949473", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon serveur-1-info", "action": "RENAME_CHANNEL", "channel_id": "1515408673755889815", "new_name": "🌍 Server 1 Info"}, "success": true, "error": null}
2026-06-13 20:05:41,355 - INFO - ACTION: {"timestamp": "2026-06-13T18:05:41.355830", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon général-chat", "action": "RENAME_CHANNEL", "channel_id": "1515408633381261584", "new_name": "💬 General Chat"}, "success": true, "error": null}
2026-06-13 20:05:41,913 - INFO - ACTION: {"timestamp": "2026-06-13T18:05:41.913252", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon mods-et-plugins", "action": "RENAME_CHANNEL", "channel_id": "1515408666956796086", "new_name": "🔧 Mods & Plugins"}, "success": true, "error": null}
2026-06-13 20:05:46,563 - INFO - ACTION: {"timestamp": "2026-06-13T18:05:46.563916", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon événements", "action": "RENAME_CHANNEL", "channel_id": "1515408627538853908", "new_name": "🎉 Events"}, "success": true, "error": null}
2026-06-13 20:05:46,983 - INFO - ACTION: {"timestamp": "2026-06-13T18:05:46.983799", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon tournament-rules", "action": "RENAME_CHANNEL", "channel_id": "1515408700876128287", "new_name": "🏆 Tournament Rules"}, "success": true, "error": null}
2026-06-13 20:05:47,494 - INFO - ACTION: {"timestamp": "2026-06-13T18:05:47.494022", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon faq-minecraft", "action": "RENAME_CHANNEL", "channel_id": "1515408669473378344", "new_name": "❓ Minecraft FAQ"}, "success": true, "error": null}
2026-06-13 20:05:48,015 - INFO - ACTION: {"timestamp": "2026-06-13T18:05:48.015873", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon build-tips", "action": "RENAME_CHANNEL", "channel_id": "1515408663152693321", "new_name": "✨ Build Tips"}, "success": true, "error": null}
2026-06-13 20:05:48,450 - INFO - ACTION: {"timestamp": "2026-06-13T18:05:48.450022", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon pvp-arena", "action": "RENAME_CHANNEL", "channel_id": "1515408751220490340", "new_name": "⚔️ PvP Arena"}, "success": true, "error": null}
2026-06-13 20:05:48,886 - INFO - ACTION: {"timestamp": "2026-06-13T18:05:48.886697", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon videos", "action": "RENAME_CHANNEL", "channel_id": "1515408739040235681", "new_name": "📹 Videos"}, "success": true, "error": null}
2026-06-13 20:05:49,297 - INFO - ACTION: {"timestamp": "2026-06-13T18:05:49.297326", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon build-chat", "action": "RENAME_CHANNEL", "channel_id": "1515408749261750435", "new_name": "💬 Build Chat"}, "success": true, "error": null}
2026-06-13 20:05:53,948 - INFO - ACTION: {"timestamp": "2026-06-13T18:05:53.948396", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon annonces", "action": "RENAME_CHANNEL", "channel_id": "1515408624627744859", "new_name": "🚀 Announcements"}, "success": true, "error": null}
2026-06-13 20:05:54,332 - INFO - ACTION: {"timestamp": "2026-06-13T18:05:54.332344", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon match-schedule", "action": "RENAME_CHANNEL", "channel_id": "1515408703287722064", "new_name": "🗓️ Match Schedule"}, "success": true, "error": null}
2026-06-13 20:05:54,749 - INFO - ACTION: {"timestamp": "2026-06-13T18:05:54.749792", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon questions-techniques", "action": "RENAME_CHANNEL", "channel_id": "1515408710032298065", "new_name": "🛠️ Tech Q&A"}, "success": true, "error": null}
2026-06-13 20:05:55,382 - INFO - ACTION: {"timestamp": "2026-06-13T18:05:55.382210", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon general-voice (textuel)", "action": "RENAME_CHANNEL", "channel_id": "1515408746627469506", "new_name": "🎤 Voice Channels"}, "success": true, "error": null}
2026-06-13 20:05:55,777 - INFO - ACTION: {"timestamp": "2026-06-13T18:05:55.777464", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon présentations", "action": "RENAME_CHANNEL", "channel_id": "1515408636787032135", "new_name": "📣 Presentations"}, "success": true, "error": null}
2026-06-13 20:05:56,169 - INFO - ACTION: {"timestamp": "2026-06-13T18:05:56.169257", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon streamers", "action": "RENAME_CHANNEL", "channel_id": "1515408741980438620", "new_name": "🎥 Streamers"}, "success": true, "error": null}
2026-06-13 20:05:56,613 - INFO - ACTION: {"timestamp": "2026-06-13T18:05:56.613529", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon règlement", "action": "RENAME_CHANNEL", "channel_id": "1515408629438877776", "new_name": "⚖️ Rules"}, "success": true, "error": null}
2026-06-13 20:06:01,556 - INFO - ACTION: {"timestamp": "2026-06-13T18:06:01.556686", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon leaderboards", "action": "RENAME_CHANNEL", "channel_id": "1515408705414500534", "new_name": "🏅 Leaderboards"}, "success": true, "error": null}
2026-06-13 20:06:01,950 - INFO - ACTION: {"timestamp": "2026-06-13T18:06:01.950088", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon suggestions", "action": "RENAME_CHANNEL", "channel_id": "1515408714922852535", "new_name": "🤔 Suggestions"}, "success": true, "error": null}
2026-06-13 20:06:02,436 - INFO - ACTION: {"timestamp": "2026-06-13T18:06:02.436742", "action": "RENAME_CHANNEL", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "Renommer le salon recettes-de-crafting", "action": "RENAME_CHANNEL", "channel_id": "1515408661361459240", "new_name": "🍽️ Crafting Recipes"}, "success": true, "error": null}
2026-06-13 20:09:42,554 - ERROR - ACTION: {"timestamp": "2026-06-13T18:09:42.554226", "action": "JOIN_VOICE", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "joining", "action": "JOIN_VOICE", "channel_id": 1515417670592495657, "response": "Je me suis joint au salon vocal 'test'."}, "success": false, "error": "Vous n'êtes pas dans un salon vocal identifiable par le système."}
2026-06-13 20:10:14,684 - INFO - ACTION: {"timestamp": "2026-06-13T18:10:14.684174", "action": "JOIN_VOICE", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "joining", "action": "JOIN_VOICE", "channel_id": 1515417670592495657, "response": "Je me suis joint au salon vocal 'test'."}, "success": true, "error": "Connecté à test"}
2026-06-13 20:20:25,073 - ERROR - ACTION: {"timestamp": "2026-06-13T18:20:25.073619", "action": "CREATE_ROLE", "user": "natsu_2106", "guild": "Omega Kube", "params": {"thought": "analyse", "action": "CREATE_ROLE", "role_name": "RÔLE: SUJET"}, "success": false, "error": "Cette opération est réservée aux administrateurs."}
2026-06-13 20:20:25,911 - ERROR - ACTION: {"timestamp": "2026-06-13T18:20:25.911348", "action": "ADD_ROLE_TO_USER", "user": "natsu_2106", "guild": "Omega Kube", "params": {"action": "ADD_ROLE_TO_USER", "user_id": 1370716551485067304, "role_name": "RÔLE: SUJET", "response": "J'ai créé le rôle \"RÔLE: SUJET\" et l'ai attribué à <@1370716551485067304>."}, "success": false, "error": "Cette opération est réservée aux administrateurs."}
2026-06-13 20:23:02,959 - ERROR - ACTION: {"timestamp": "2026-06-13T18:23:02.959686", "action": "ADD_ROLE_TO_USER", "user": "natsu_2106", "guild": "Omega Kube", "params": {"thought": "analysis", "action": "ADD_ROLE_TO_USER", "role_name": "RÔLE: SUJET", "user_id": "<@ͷὶϰϝἱϰ gaming>", "response": "Le rôle 'RÔLE: SUJET' a été attribué à @ͷὶϰϝἱϰ gaming."}, "success": false, "error": "Cette opération est réservée aux administrateurs."}
2026-06-13 20:30:15,626 - INFO - ACTION: {"timestamp": "2026-06-13T18:30:15.626871", "action": "INSIGHT", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "explain 9/11 events", "action": "INSIGHT", "response": "Le 11 septembre 2001 (souvent appelé le« 911 ») est une date marquante de l'histoire moderne, caractérisée par des attaques terroristes coordonnées contre les États-Unis. Voici un résumé succinct :\n\n• **Contexte** Le groupe extrémiste islamique al-Qaïda, dirigé à l'époque par Oussama ben Laden, avait planifié depuis plusieurs années une série d'attaques visant à semer la peur et à affaiblir les États-Unis.\n\n• **Les attaques**\n - *Deux avions* (American Airlines vol11 et United Airlines vol175) ont été détournés et écrasés de façon délibérée dans le **TorrejonNord** du World Trade Center à New York. Le bâtiment s'est effondré après l'impact, causant la mort d'environ 2977 personnes.\n - *Un troisième avion* (American Airlines vol77) a été détourné et déposé sur le **Pentagone**, siège de la Défense américaine, tuant plus de 300 militaires et civils.\n - Le *quatrième avion*, United Airlines vol93, s'est écrasé dans un champ en Pennsylvanie après que les passagers aient tenté d'affronter les détournés. Tous à bord sont décédés.\n\n• **Conséquences immédiates** Au total, près de 3000 personnes ont perdu la vie et des milliers d'autres furent blessées ou traumatisées.\n\n• **Réponses politiques et militaires**\n - Les États-Unis déclarèrent une « guerre contre le terrorisme », lançant l'invasion du *Afghanistan* en octobre 2001 pour renverser les talibans qui abritaient alQaïda.\n - En 2003, la guerre en *Irak* fut justifiée par des allégations (falsifiées) de possession d'armes de destruction massive et le soutien présumé du régime iraquien à Al-Qaïda. Cette décision a eu un impact durable sur l'équilibre géopolitique moyenoriental.\n\n• **Impact sociétal** Le 9/11 a profondément changé la perception mondiale de la sécurité, entraînant des mesures renforcées en matière d'aérien (sûreté accrue), une surveillance élargie et un changement dans les politiques étrangères. Il s'est également transformé en symbole durable du terrorisme international.\n\nEn résumé, le 9/11 a été l'une des attaques terroristes les plus meurtrières de l'histoire moderne, déclenchant une série d'événements géopolitiques qui continuent à influencer la politique mondiale aujourd'hui."}, "success": true, "error": null}
2026-06-13 20:33:45,321 - INFO - ACTION: {"timestamp": "2026-06-13T18:33:45.321004", "action": "PURGE", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "User requested purging ~200 messages from #💬・général", "action": "PURGE", "channel_id": "1456784303995228344", "amount": 200, "response": "Les 200 derniers messages du salon #💬・général ont été supprimés."}, "success": true, "error": null}
2026-06-13 20:34:34,945 - INFO - ACTION: {"timestamp": "2026-06-13T18:34:34.945454", "action": "PURGE", "user": "_.radi0dem0n._", "guild": "BETA", "params": {"thought": "analysis", "action": "PURGE", "channel_id": "1456784303995228344", "count": 10000, "response": "Les 10000 derniers messages du salon #💬・général ont été supprimés."}, "success": true, "error": null}

View file

@ -1,11 +0,0 @@
{
"task_1781375415": {
"asset_id": 971446412690722826,
"content": "Pas de contenu",
"importance": 2,
"created_at": 1781375415.1465554,
"deadline": 1781378115.1465554,
"guild_id": 1434226877652013100,
"status": "PENDING"
}
}

File diff suppressed because it is too large Load diff

Binary file not shown.

View file

@ -1,47 +0,0 @@
{
"1277303870657400882": {
"914118793918312480": [
{
"reason": "Mots inappropriés détectés: putain",
"timestamp": "2026-01-21T17:04:00.196873",
"issued_by": "AUTOMATIC_MODERATION"
}
]
},
"1493915688295727204": {
"979680383174066267": [
{
"reason": "Mots inappropriés détectés: fuck",
"timestamp": "2026-04-15T14:37:43.989883",
"issued_by": "AUTOMATIC_MODERATION"
}
],
"1324439906046574693": [
{
"reason": "Mots inappropriés détectés: fuck",
"timestamp": "2026-04-15T14:37:50.862846",
"issued_by": "AUTOMATIC_MODERATION"
},
{
"reason": "Mots inappropriés détectés: nul",
"timestamp": "2026-04-16T09:44:42.349167",
"issued_by": "AUTOMATIC_MODERATION"
},
{
"reason": "Mots inappropriés détectés: salope",
"timestamp": "2026-04-16T09:44:55.968030",
"issued_by": "AUTOMATIC_MODERATION"
},
{
"reason": "Mots inappropriés détectés: nul",
"timestamp": "2026-04-16T09:48:01.003922",
"issued_by": "AUTOMATIC_MODERATION"
},
{
"reason": "Mots inappropriés détectés: nul",
"timestamp": "2026-04-16T17:59:47.309121",
"issued_by": "AUTOMATIC_MODERATION"
}
]
}
}

13
main.py
View file

@ -8,7 +8,7 @@ import discord
from dotenv import load_dotenv
# Import our modular components
from core.bot import Superviseur
from core.bot import Bot
from core.llm import LLMManager
# Setup Logging
@ -20,7 +20,7 @@ logging.basicConfig(
logging.StreamHandler(sys.stdout)
]
)
logger = logging.getLogger('Superviseur')
logger = logging.getLogger('Beta')
# Load environment
load_dotenv()
@ -39,6 +39,10 @@ if not GUILD_ID:
# Ollama model name (from .env)
MODEL_NAME = os.getenv("OLLAMA_MODEL", "gpt-oss:20b")
# Favorite users (special personality)
fav_env = os.getenv("FAVORITE_IDS", "")
FAVORITE_IDS = [int(i.strip()) for i in fav_env.split(",") if i.strip().isdigit()]
async def main():
"""Main startup sequence."""
logger.info("◈ SYSTEM: Initializing Superviseur with Ollama Backend...")
@ -67,12 +71,13 @@ async def main():
intents.members = True
intents.voice_states = True
bot = Superviseur(
bot = Bot(
llama_model=llm,
command_prefix="!",
guild_id=int(GUILD_ID),
system_prompt=SYSTEM_PROMPT,
intents=intents
intents=intents,
favorite_ids=FAVORITE_IDS
)
try:

View file

@ -1,4 +0,0 @@
nohup: ignoring input
time=2026-06-13T12:52:15.776Z level=INFO source=routes.go:1919 msg="server config" env="map[CUDA_VISIBLE_DEVICES: GGML_VK_VISIBLE_DEVICES: GPU_DEVICE_ORDINAL: HIP_VISIBLE_DEVICES:-1 HSA_OVERRIDE_GFX_VERSION: HTTPS_PROXY: HTTP_PROXY: LLAMA_ARG_FIT: LLAMA_ARG_FIT_TARGET: NO_PROXY: OLLAMA_CONTEXT_LENGTH:8192 OLLAMA_DEBUG:INFO OLLAMA_DEBUG_LOG_REQUESTS:false OLLAMA_EDITOR: OLLAMA_FLASH_ATTENTION:false OLLAMA_GO_TEMPLATE:true OLLAMA_GPU_OVERHEAD:0 OLLAMA_HOST:http://0.0.0.0:11434 OLLAMA_IGPU_ENABLE:1 OLLAMA_KEEP_ALIVE:5m0s OLLAMA_KV_CACHE_TYPE: OLLAMA_LLM_LIBRARY: OLLAMA_LOAD_TIMEOUT:5m0s OLLAMA_MAX_LOADED_MODELS:0 OLLAMA_MAX_QUEUE:512 OLLAMA_MAX_TRANSFER_STREAMS:4 OLLAMA_MODELS:/home/lowei/.ollama/models OLLAMA_NOHISTORY:false OLLAMA_NOPRUNE:false OLLAMA_NO_CLOUD:false OLLAMA_NUM_PARALLEL:1 OLLAMA_ORIGINS:[* http://localhost https://localhost http://localhost:* https://localhost:* http://127.0.0.1 https://127.0.0.1 http://127.0.0.1:* https://127.0.0.1:* http://0.0.0.0 https://0.0.0.0 http://0.0.0.0:* https://0.0.0.0:* app://* file://* tauri://* vscode-webview://* vscode-file://*] OLLAMA_REMOTES:[ollama.com] OLLAMA_SCHED_SPREAD:false OLLAMA_VULKAN:true ROCR_VISIBLE_DEVICES:-1 http_proxy: https_proxy: no_proxy:]"
time=2026-06-13T12:52:15.776Z level=INFO source=routes.go:1921 msg="Ollama cloud disabled: false"
Error: mkdir /home/lowei/.ollama: permission denied: ensure path elements are traversable

View file

@ -1,89 +1,479 @@
#!/usr/bin/env python3
"""Simple test to verify the bot can be initialized without errors."""
"""Tests unitaires pour Superviseur Bot."""
import sys
import os
import json
import asyncio
import tempfile
import shutil
import logging
# Add the project root to the path
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
# Setup logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler("data/test_bot.log"),
logging.StreamHandler(sys.stdout)
]
)
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('TestBot')
# ==================== Tests d'import ====================
def test_imports():
"""Test that all required modules can be imported."""
try:
from core.bot import Superviseur
from core.llm import LLMManager
from dotenv import load_dotenv
import discord
logger.info("✓ All imports successful")
return True
except Exception as e:
logger.error(f"✗ Import failed: {e}")
return False
"""Test que tous les modules principaux peuvent être importés."""
from core.bot import Bot
from core.llm import LLMManager
from core.action_executor import ActionExecutor
from brain.memory import (
add_interaction, build_context_for_model, flush_all,
delete_user_memory, set_llm_manager, _extractive_summary
)
from brain.moderation import init_db, log_infraction
from dotenv import load_dotenv
import discord
logger.info("✓ Tous les imports réussis")
def test_llm_manager():
"""Test LLMManager initialization."""
try:
from core.llm import LLMManager
llm = LLMManager(model_name="beta-20b")
logger.info("✓ LLMManager initialized successfully")
return True
except Exception as e:
logger.error(f"✗ LLMManager failed: {e}")
return False
def test_bot_initialization():
"""Test Superviseur bot initialization."""
def test_llm_manager_init():
"""Test l'initialisation du LLMManager."""
from core.llm import LLMManager
llm = LLMManager(model_name="test-model")
assert llm.model_name == "test-model"
assert llm.temperature == 0.5
assert "localhost" in llm.base_url
logger.info("✓ LLMManager initialisé correctement")
def test_bot_init():
"""Test l'initialisation du bot Beta."""
from core.bot import Bot
from core.llm import LLMManager
import discord
llm = LLMManager(model_name="test-model")
intents = discord.Intents.default()
intents.message_content = True
bot = Bot(
llama_model=llm,
command_prefix="!",
guild_id=123456789,
system_prompt="Test prompt",
intents=intents
)
assert bot.guild_id == 123456789
assert bot.system_name == "Bêta"
logger.info("✓ Bot Superviseur initialisé correctement")
# ==================== Tests LLM (JSON Extraction) ====================
def test_extract_json_simple_object():
"""Test extraction JSON simple."""
from core.llm import LLMManager
llm = LLMManager()
text = 'Voici mon analyse : {"thought": "test", "action": "NONE", "response": "Salut !"}'
result = llm.extract_json_actions(text)
assert result is not None
data = json.loads(result)
assert data["action"] == "NONE"
assert data["response"] == "Salut !"
logger.info("✓ Extraction JSON simple OK")
def test_extract_json_array():
"""Test extraction JSON tableau."""
from core.llm import LLMManager
llm = LLMManager()
text = 'Actions : [{"action": "CREATE_CHANNEL", "channel_name": "test"}, {"action": "CREATE_ROLE", "role_name": "mod"}]'
result = llm.extract_json_actions(text)
assert result is not None
data = json.loads(result)
assert isinstance(data, list)
assert len(data) == 2
assert data[0]["action"] == "CREATE_CHANNEL"
logger.info("✓ Extraction JSON tableau OK")
def test_extract_json_with_comments():
"""Test extraction JSON avec commentaires GPT-OSS."""
from core.llm import LLMManager
llm = LLMManager()
text = '''Voici la réponse :
// Ceci est un commentaire
{"action": "KICK", "user_id": "123", "reason": "spam"}
// Autre commentaire'''
result = llm.extract_json_actions(text)
assert result is not None
data = json.loads(result)
assert data["action"] == "KICK"
logger.info("✓ Extraction JSON avec commentaires OK")
def test_extract_json_none():
"""Test extraction quand pas de JSON."""
from core.llm import LLMManager
llm = LLMManager()
text = "Salut, comment ça va ? Pas de JSON ici."
result = llm.extract_json_actions(text)
assert result is None
logger.info("✓ Absence de JSON détectée correctement")
def test_extract_json_empty():
"""Test extraction avec texte vide."""
from core.llm import LLMManager
llm = LLMManager()
assert llm.extract_json_actions("") is None
assert llm.extract_json_actions(None) is None
logger.info("✓ Texte vide géré correctement")
def test_extract_json_nested_braces():
"""Test extraction avec accolades imbriquées."""
from core.llm import LLMManager
llm = LLMManager()
text = 'Analyse : {"action": "SEND_MESSAGE", "channel_id": "123", "response": "Contenu avec {des} accolades"}'
result = llm.extract_json_actions(text)
assert result is not None
data = json.loads(result)
assert data["action"] == "SEND_MESSAGE"
logger.info("✓ Extraction JSON avec accolades imbriquées OK")
# ==================== Tests LLM (Payload) ====================
def test_build_payload():
"""Test la construction de payload Ollama."""
from core.llm import LLMManager
llm = LLMManager(model_name="test-model", temperature=0.3)
payload = llm.build_payload(
prompt="Test prompt",
system_prompt="Test system"
)
assert payload["model"] == "test-model"
assert payload["prompt"] == "Test prompt"
assert payload["system"] == "Test system"
assert payload["options"]["temperature"] == 0.3
assert payload["options"]["num_ctx"] == 16384
logger.info("✓ Payload Ollama construit correctement")
# ==================== Tests Mémoire ====================
def _run_async(coro):
"""Helper pour exécuter du code async dans les tests sync."""
return asyncio.get_event_loop().run_until_complete(coro)
def test_memory_save_load():
"""Test sauvegarde et chargement mémoire."""
import brain.memoire as mem
test_dir = tempfile.mkdtemp()
original_dir = mem.MEMORY_DIR
mem.MEMORY_DIR = test_dir
mem.memory_cache.clear()
mem._dirty.clear()
try:
from core.bot import Superviseur
import discord
from core.llm import LLMManager
uid = "test_user_123"
data = {"resume_global": "Test résumé", "historique_recent": []}
_run_async(mem.save_user_memory_async(uid, data, persist_immediately=True))
loaded = _run_async(mem.load_user_memory_async(uid))
assert loaded == data, f"Load/save failed: {loaded} != {data}"
logger.info("✓ Sauvegarde/chargement mémoire OK")
finally:
mem.MEMORY_DIR = original_dir
mem.memory_cache.clear()
shutil.rmtree(test_dir)
def test_memory_add_interaction():
"""Test ajout d'interaction."""
import brain.memoire as mem
test_dir = tempfile.mkdtemp()
original_dir = mem.MEMORY_DIR
mem.MEMORY_DIR = test_dir
mem.memory_cache.clear()
mem._dirty.clear()
try:
uid = "test_user_456"
_run_async(mem.add_interaction(uid, 111, "Hello", "Hi there!"))
loaded = _run_async(mem.load_user_memory_async(uid))
assert len(loaded["historique_recent"]) == 1
assert loaded["historique_recent"][0]["user_message"] == "Hello"
assert loaded["historique_recent"][0]["bot_message"] == "Hi there!"
logger.info("✓ Ajout d'interaction OK")
finally:
mem.MEMORY_DIR = original_dir
mem.memory_cache.clear()
shutil.rmtree(test_dir)
def test_memory_build_context():
"""Test construction du contexte pour le modèle."""
import brain.memoire as mem
test_dir = tempfile.mkdtemp()
original_dir = mem.MEMORY_DIR
mem.MEMORY_DIR = test_dir
mem.memory_cache.clear()
mem._dirty.clear()
try:
uid = "test_user_789"
_run_async(mem.add_interaction(uid, 111, "Question?", "Réponse!"))
ctx = _run_async(mem.build_context_for_model(uid))
assert "Question?" in ctx
assert "Réponse!" in ctx
logger.info("✓ Construction contexte OK")
finally:
mem.MEMORY_DIR = original_dir
mem.memory_cache.clear()
shutil.rmtree(test_dir)
def test_memory_delete():
"""Test suppression mémoire avec guild_id."""
import brain.memoire as mem
test_dir = tempfile.mkdtemp()
original_dir = mem.MEMORY_DIR
mem.MEMORY_DIR = test_dir
mem.memory_cache.clear()
mem._dirty.clear()
try:
uid = "test_user_del"
_run_async(mem.add_interaction(uid, 111, "Test", "Response", guild_id="TestGuild"))
# Create a mock LLMManager
llm = LLMManager(model_name="beta-20b")
# Forcer la sauvegarde immédiate (add_interaction schedule en background)
_run_async(asyncio.sleep(0.5))
# Create minimal intents
intents = discord.Intents.default()
intents.message_content = True
intents.members = True
intents.voice_states = True
# Vérifier que le fichier existe
path = mem._user_filepath(uid, "TestGuild")
assert os.path.exists(path), f"Fichier non trouvé: {path}"
# Try to initialize the bot (without actually connecting)
bot = Superviseur(
llama_model=llm,
command_prefix="!",
guild_id=123456789,
system_prompt="Test system prompt",
intents=intents
)
logger.info("✓ Superviseur bot initialized successfully")
return True
except Exception as e:
logger.error(f"✗ Bot initialization failed: {e}")
return False
# Supprimer
mem.delete_user_memory(uid, "TestGuild")
# Vérifier suppression (recharger crée un fichier vide)
mem.memory_cache.clear()
loaded = _run_async(mem.load_user_memory_async(uid, "TestGuild"))
assert loaded["historique_recent"] == []
logger.info("✓ Suppression mémoire avec guild_id OK")
finally:
mem.MEMORY_DIR = original_dir
mem.memory_cache.clear()
shutil.rmtree(test_dir)
def test_memory_extractive_summary():
"""Test le résumé extractif (fallback)."""
from brain.memoire import _extractive_summary
messages = [
{"user_message": "Salut, comment configurer le bot ?", "bot_message": "Tu peux utiliser la commande !config."},
{"user_message": "Merci beaucoup !", "bot_message": "De rien, n'hésite pas."},
]
summary = _extractive_summary(messages)
assert len(summary) > 0
assert "Mots-clés:" in summary
logger.info("✓ Résumé extractif OK")
def test_memory_flush_all():
"""Test flush de toutes les mémoires dirty."""
import brain.memoire as mem
test_dir = tempfile.mkdtemp()
original_dir = mem.MEMORY_DIR
mem.MEMORY_DIR = test_dir
mem.memory_cache.clear()
mem._dirty.clear()
try:
# Créer quelques entrées
_run_async(mem.add_interaction("user_a", 111, "Test A", "Response A"))
_run_async(mem.add_interaction("user_b", 222, "Test B", "Response B"))
# Marquer dirty
assert any(mem._dirty.values())
# Flush
_run_async(mem.flush_all())
# Vérifier que tout est clean
assert not any(mem._dirty.values())
logger.info("✓ Flush mémoire OK")
finally:
mem.MEMORY_DIR = original_dir
mem.memory_cache.clear()
shutil.rmtree(test_dir)
# ==================== Tests Bot (Response Cleaning) ====================
def test_clean_response_text():
"""Test le nettoyage de texte de réponse."""
from core.response_handler import clean_response_text
# Test nettoyage basique
clean = clean_response_text("Salut ! Voici ma r\u00e9ponse.", None)
assert clean == "Salut ! Voici ma r\u00e9ponse."
# Test nettoyage avec JSON extrait
clean = clean_response_text('Texte avant {"action": "NONE"} texte apr\u00e8s', '{"action": "NONE"}')
assert "NONE" not in clean
assert "avant" in clean
assert "apr\u00e8s" in clean
# Test nettoyage balises
clean = clean_response_text("R\u00e9ponse <|channel|> normale", None)
assert "<|channel|>" not in clean
logger.info("OK Nettoyage r\u00e9ponse")
def test_parse_json_actions():
"""Test le parsing des actions JSON."""
from core.response_handler import parse_json_actions
# Test parsing valide
actions, responses, is_none = parse_json_actions(
'{"action": "KICK", "response": "Utilisateur kick\u00e9"}'
)
assert len(actions) == 1
assert actions[0]["action"] == "KICK"
assert "kick\u00e9" in responses[0]
assert not is_none
# Test parsing NONE
actions, responses, is_none = parse_json_actions(
'{"action": "NONE"}'
)
assert is_none
# Test parsing tableau
actions, responses, is_none = parse_json_actions(
'[{"action": "A", "response": "R1"}, {"action": "B", "response": "R2"}]'
)
assert len(actions) == 2
assert len(responses) == 2
# Test parsing None
actions, responses, is_none = parse_json_actions(None)
assert actions == []
assert responses == []
assert not is_none
logger.info("OK Parsing actions JSON")
# ==================== Tests Action Router ====================
def test_action_executor_init():
"""Test l'initialisation de l'ActionExecutor."""
from core.action_executor import ActionExecutor
from core.bot import Bot
from core.llm import LLMManager
import discord
llm = LLMManager()
intents = discord.Intents.default()
bot = Bot(
llama_model=llm, command_prefix="!", guild_id=123,
system_prompt="Test", intents=intents
)
executor = ActionExecutor(bot)
logger.info("✓ ActionExecutor initialisé OK")
# ==================== Tests Modération ====================
def test_moderation_db_init():
"""Test l'initialisation de la DB de modération."""
import tempfile
import brain.moderation as mod
from brain import moderation
original_path = mod.DB_PATH
test_dir = tempfile.mkdtemp()
mod.DB_PATH = os.path.join(test_dir, "test_mod.db")
try:
mod.init_db()
# Vérifier que la table existe
import sqlite3
conn = sqlite3.connect(mod.DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='infractions'")
assert cursor.fetchone() is not None
conn.close()
logger.info("✓ Initialisation DB modération OK")
finally:
mod.DB_PATH = original_path
shutil.rmtree(test_dir)
# ==================== Point d'entrée ====================
if __name__ == "__main__":
logger.info("Testing bot initialization...")
logger.info("=" * 50)
logger.info("Tests Superviseur Bot")
logger.info("=" * 50)
success = True
success &= test_imports()
success &= test_llm_manager()
success &= test_bot_initialization()
tests = [
test_imports,
test_llm_manager_init,
test_bot_init,
test_extract_json_simple_object,
test_extract_json_array,
test_extract_json_with_comments,
test_extract_json_none,
test_extract_json_empty,
test_extract_json_nested_braces,
test_build_payload,
test_memory_save_load,
test_memory_add_interaction,
test_memory_build_context,
test_memory_delete,
test_memory_extractive_summary,
test_memory_flush_all,
test_clean_response_text,
test_parse_json_actions,
test_action_executor_init,
test_moderation_db_init,
]
if success:
logger.info("✓ All tests passed! Bot should be able to run.")
sys.exit(0)
else:
logger.error("✗ Some tests failed.")
sys.exit(1)
passed = 0
failed = 0
for test in tests:
try:
test()
passed += 1
except Exception as e:
import traceback
logger.error(f"{test.__name__}: {e}")
traceback.print_exc()
failed += 1
logger.info("=" * 50)
logger.info(f"Résultats: {passed}/{passed + failed} tests réussis")
logger.info("=" * 50)
sys.exit(0 if failed == 0 else 1)

View file

@ -1,247 +0,0 @@
<#
.Synopsis
Activate a Python virtual environment for the current PowerShell session.
.Description
Pushes the python executable for a virtual environment to the front of the
$Env:PATH environment variable and sets the prompt to signify that you are
in a Python virtual environment. Makes use of the command line switches as
well as the `pyvenv.cfg` file values present in the virtual environment.
.Parameter VenvDir
Path to the directory that contains the virtual environment to activate. The
default value for this is the parent of the directory that the Activate.ps1
script is located within.
.Parameter Prompt
The prompt prefix to display when this virtual environment is activated. By
default, this prompt is the name of the virtual environment folder (VenvDir)
surrounded by parentheses and followed by a single space (ie. '(.venv) ').
.Example
Activate.ps1
Activates the Python virtual environment that contains the Activate.ps1 script.
.Example
Activate.ps1 -Verbose
Activates the Python virtual environment that contains the Activate.ps1 script,
and shows extra information about the activation as it executes.
.Example
Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv
Activates the Python virtual environment located in the specified location.
.Example
Activate.ps1 -Prompt "MyPython"
Activates the Python virtual environment that contains the Activate.ps1 script,
and prefixes the current prompt with the specified string (surrounded in
parentheses) while the virtual environment is active.
.Notes
On Windows, it may be required to enable this Activate.ps1 script by setting the
execution policy for the user. You can do this by issuing the following PowerShell
command:
PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
For more information on Execution Policies:
https://go.microsoft.com/fwlink/?LinkID=135170
#>
Param(
[Parameter(Mandatory = $false)]
[String]
$VenvDir,
[Parameter(Mandatory = $false)]
[String]
$Prompt
)
<# Function declarations --------------------------------------------------- #>
<#
.Synopsis
Remove all shell session elements added by the Activate script, including the
addition of the virtual environment's Python executable from the beginning of
the PATH variable.
.Parameter NonDestructive
If present, do not remove this function from the global namespace for the
session.
#>
function global:deactivate ([switch]$NonDestructive) {
# Revert to original values
# The prior prompt:
if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) {
Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt
Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT
}
# The prior PYTHONHOME:
if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) {
Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME
Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME
}
# The prior PATH:
if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) {
Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH
Remove-Item -Path Env:_OLD_VIRTUAL_PATH
}
# Just remove the VIRTUAL_ENV altogether:
if (Test-Path -Path Env:VIRTUAL_ENV) {
Remove-Item -Path env:VIRTUAL_ENV
}
# Just remove VIRTUAL_ENV_PROMPT altogether.
if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) {
Remove-Item -Path env:VIRTUAL_ENV_PROMPT
}
# Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether:
if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) {
Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force
}
# Leave deactivate function in the global namespace if requested:
if (-not $NonDestructive) {
Remove-Item -Path function:deactivate
}
}
<#
.Description
Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the
given folder, and returns them in a map.
For each line in the pyvenv.cfg file, if that line can be parsed into exactly
two strings separated by `=` (with any amount of whitespace surrounding the =)
then it is considered a `key = value` line. The left hand string is the key,
the right hand is the value.
If the value starts with a `'` or a `"` then the first and last character is
stripped from the value before being captured.
.Parameter ConfigDir
Path to the directory that contains the `pyvenv.cfg` file.
#>
function Get-PyVenvConfig(
[String]
$ConfigDir
) {
Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg"
# Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue).
$pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue
# An empty map will be returned if no config file is found.
$pyvenvConfig = @{ }
if ($pyvenvConfigPath) {
Write-Verbose "File exists, parse `key = value` lines"
$pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath
$pyvenvConfigContent | ForEach-Object {
$keyval = $PSItem -split "\s*=\s*", 2
if ($keyval[0] -and $keyval[1]) {
$val = $keyval[1]
# Remove extraneous quotations around a string value.
if ("'""".Contains($val.Substring(0, 1))) {
$val = $val.Substring(1, $val.Length - 2)
}
$pyvenvConfig[$keyval[0]] = $val
Write-Verbose "Adding Key: '$($keyval[0])'='$val'"
}
}
}
return $pyvenvConfig
}
<# Begin Activate script --------------------------------------------------- #>
# Determine the containing directory of this script
$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
$VenvExecDir = Get-Item -Path $VenvExecPath
Write-Verbose "Activation script is located in path: '$VenvExecPath'"
Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)"
Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)"
# Set values required in priority: CmdLine, ConfigFile, Default
# First, get the location of the virtual environment, it might not be
# VenvExecDir if specified on the command line.
if ($VenvDir) {
Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values"
}
else {
Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir."
$VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/")
Write-Verbose "VenvDir=$VenvDir"
}
# Next, read the `pyvenv.cfg` file to determine any required value such
# as `prompt`.
$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir
# Next, set the prompt from the command line, or the config file, or
# just use the name of the virtual environment folder.
if ($Prompt) {
Write-Verbose "Prompt specified as argument, using '$Prompt'"
}
else {
Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value"
if ($pyvenvCfg -and $pyvenvCfg['prompt']) {
Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'"
$Prompt = $pyvenvCfg['prompt'];
}
else {
Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)"
Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'"
$Prompt = Split-Path -Path $venvDir -Leaf
}
}
Write-Verbose "Prompt = '$Prompt'"
Write-Verbose "VenvDir='$VenvDir'"
# Deactivate any currently active virtual environment, but leave the
# deactivate function in place.
deactivate -nondestructive
# Now set the environment variable VIRTUAL_ENV, used by many tools to determine
# that there is an activated venv.
$env:VIRTUAL_ENV = $VenvDir
if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) {
Write-Verbose "Setting prompt to '$Prompt'"
# Set the prompt to include the env name
# Make sure _OLD_VIRTUAL_PROMPT is global
function global:_OLD_VIRTUAL_PROMPT { "" }
Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT
New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt
function global:prompt {
Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
_OLD_VIRTUAL_PROMPT
}
$env:VIRTUAL_ENV_PROMPT = $Prompt
}
# Clear PYTHONHOME
if (Test-Path -Path Env:PYTHONHOME) {
Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME
Remove-Item -Path Env:PYTHONHOME
}
# Add the venv to the PATH
Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH
$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH"

View file

@ -1,70 +0,0 @@
# This file must be used with "source bin/activate" *from bash*
# You cannot run it directly
deactivate () {
# reset old environment variables
if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
PATH="${_OLD_VIRTUAL_PATH:-}"
export PATH
unset _OLD_VIRTUAL_PATH
fi
if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
export PYTHONHOME
unset _OLD_VIRTUAL_PYTHONHOME
fi
# Call hash to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
hash -r 2> /dev/null
if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
PS1="${_OLD_VIRTUAL_PS1:-}"
export PS1
unset _OLD_VIRTUAL_PS1
fi
unset VIRTUAL_ENV
unset VIRTUAL_ENV_PROMPT
if [ ! "${1:-}" = "nondestructive" ] ; then
# Self destruct!
unset -f deactivate
fi
}
# unset irrelevant variables
deactivate nondestructive
# on Windows, a path can contain colons and backslashes and has to be converted:
if [ "${OSTYPE:-}" = "cygwin" ] || [ "${OSTYPE:-}" = "msys" ] ; then
# transform D:\path\to\venv to /d/path/to/venv on MSYS
# and to /cygdrive/d/path/to/venv on Cygwin
export VIRTUAL_ENV=$(cygpath /home/pi/Beta/beta/venv)
else
# use the path as-is
export VIRTUAL_ENV=/home/pi/Beta/beta/venv
fi
_OLD_VIRTUAL_PATH="$PATH"
PATH="$VIRTUAL_ENV/"bin":$PATH"
export PATH
# unset PYTHONHOME if set
# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
# could use `if (set -u; : $PYTHONHOME) ;` in bash
if [ -n "${PYTHONHOME:-}" ] ; then
_OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
unset PYTHONHOME
fi
if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
_OLD_VIRTUAL_PS1="${PS1:-}"
PS1='(venv) '"${PS1:-}"
export PS1
VIRTUAL_ENV_PROMPT='(venv) '
export VIRTUAL_ENV_PROMPT
fi
# Call hash to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
hash -r 2> /dev/null

View file

@ -1,27 +0,0 @@
# This file must be used with "source bin/activate.csh" *from csh*.
# You cannot run it directly.
# Created by Davide Di Blasi <davidedb@gmail.com>.
# Ported to Python 3.3 venv by Andrew Svetlov <andrew.svetlov@gmail.com>
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate'
# Unset irrelevant variables.
deactivate nondestructive
setenv VIRTUAL_ENV /home/pi/Beta/beta/venv
set _OLD_VIRTUAL_PATH="$PATH"
setenv PATH "$VIRTUAL_ENV/"bin":$PATH"
set _OLD_VIRTUAL_PROMPT="$prompt"
if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
set prompt = '(venv) '"$prompt"
setenv VIRTUAL_ENV_PROMPT '(venv) '
endif
alias pydoc python -m pydoc
rehash

View file

@ -1,69 +0,0 @@
# This file must be used with "source <venv>/bin/activate.fish" *from fish*
# (https://fishshell.com/). You cannot run it directly.
function deactivate -d "Exit virtual environment and return to normal shell environment"
# reset old environment variables
if test -n "$_OLD_VIRTUAL_PATH"
set -gx PATH $_OLD_VIRTUAL_PATH
set -e _OLD_VIRTUAL_PATH
end
if test -n "$_OLD_VIRTUAL_PYTHONHOME"
set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME
set -e _OLD_VIRTUAL_PYTHONHOME
end
if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
set -e _OLD_FISH_PROMPT_OVERRIDE
# prevents error when using nested fish instances (Issue #93858)
if functions -q _old_fish_prompt
functions -e fish_prompt
functions -c _old_fish_prompt fish_prompt
functions -e _old_fish_prompt
end
end
set -e VIRTUAL_ENV
set -e VIRTUAL_ENV_PROMPT
if test "$argv[1]" != "nondestructive"
# Self-destruct!
functions -e deactivate
end
end
# Unset irrelevant variables.
deactivate nondestructive
set -gx VIRTUAL_ENV /home/pi/Beta/beta/venv
set -gx _OLD_VIRTUAL_PATH $PATH
set -gx PATH "$VIRTUAL_ENV/"bin $PATH
# Unset PYTHONHOME if set.
if set -q PYTHONHOME
set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
set -e PYTHONHOME
end
if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
# fish uses a function instead of an env var to generate the prompt.
# Save the current fish_prompt function as the function _old_fish_prompt.
functions -c fish_prompt _old_fish_prompt
# With the original prompt function renamed, we can override with our own.
function fish_prompt
# Save the return status of the last command.
set -l old_status $status
# Output the venv prompt; color taken from the blue of the Python logo.
printf "%s%s%s" (set_color 4B8BBE) '(venv) ' (set_color normal)
# Restore the return status of the previous command.
echo "exit $old_status" | .
# Output the original/"old" prompt.
_old_fish_prompt
end
set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
set -gx VIRTUAL_ENV_PROMPT '(venv) '
end

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from ctranslate2.converters.fairseq import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from ctranslate2.converters.marian import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from ctranslate2.converters.openai_gpt2 import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from ctranslate2.converters.opennmt_py import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from ctranslate2.converters.opennmt_tf import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from ctranslate2.converters.opus_mt import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from ctranslate2.converters.transformers import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from dotenv.__main__ import cli
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(cli())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from numpy.f2py.f2py2e import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from fastapi.cli import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from huggingface_hub.cli.hf import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from httpx import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from huggingface_hub.cli.deprecated_cli import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from idna.cli import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from markdown_it.cli.parse import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from numpy._configtool import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from onnxruntime.tools.onnxruntime_test import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pip._internal.cli.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pip._internal.cli.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pip._internal.cli.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pytest import console_main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(console_main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from av.__main__ import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pygments.cmdline import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pytest import console_main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(console_main())

View file

@ -1 +0,0 @@
python3

View file

@ -1 +0,0 @@
/usr/bin/python3

View file

@ -1 +0,0 @@
python3

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from huggingface_hub.inference._mcp.cli import app
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(app())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from tqdm.cli import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View file

@ -1,8 +0,0 @@
#!/home/pi/Beta/beta/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from typer.cli import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

Some files were not shown because too many files have changed in this diff Show more