Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 0 additions & 105 deletions crypto-pilot-builder/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

96 changes: 74 additions & 22 deletions crypto-pilot-builder/python/mcp_client/api_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class AgentConfig(db.Model):
user_id = db.Column(UUID(as_uuid=True), db.ForeignKey('users.id'), nullable=False)

# Configuration IA
provider = db.Column(db.String(50), nullable=False, default='openai')
selected_model = db.Column(db.String(100), nullable=False)
api_key = db.Column(db.Text, nullable=False) # Chiffré en production

Expand Down Expand Up @@ -156,6 +157,28 @@ def validate_openai_api_key(api_key):

return True

def validate_libertai_api_key(api_key):
"""LibertAI API key validation"""
if not api_key or not isinstance(api_key, str):
return False

if len(api_key) < 10 or len(api_key) > 200:
return False
allowed_pattern = r'^[A-Za-z0-9._-]+$'
if not re.match(allowed_pattern, api_key):
return False

return True

def validate_api_key(api_key, provider):
"""Validate API key based on provider"""
if provider.lower() == "openai":
return validate_openai_api_key(api_key)
elif provider.lower() == "libertai":
return validate_libertai_api_key(api_key)
else:
return False

with app.app_context():
try:
db.create_all()
Expand Down Expand Up @@ -321,6 +344,7 @@ def create_agent_config():
'message': 'Configuration sauvegardée avec succès',
'config': {
'id': config.id,
'provider': config.provider,
'selectedModel': config.selected_model,
'apiKey': config.api_key[-4:] + '...' if config.api_key else '', # Masquer la clé
'modules': config.modules_config,
Expand Down Expand Up @@ -350,6 +374,7 @@ def get_agent_config():
return jsonify({
'config': {
'id': config.id,
'provider': config.provider,
'selectedModel': config.selected_model,
'apiKey': config.api_key, # Retourner la clé complète pour l'utilisation
'modules': config.modules_config,
Expand Down Expand Up @@ -389,12 +414,20 @@ def update_partial_config():
db.session.add(config)

# Mettre à jour les champs fournis
if 'provider' in data:
config.provider = data['provider']
if 'selectedModel' in data:
config.selected_model = data['selectedModel']
if 'apiKey' in data:
# Validation du format de l'API key si elle est fournie
# if not validate_openai_api_key(data['apiKey']):
# return jsonify({'error': 'Format de clé API OpenAI invalide. La clé doit commencer par "sk-" et contenir uniquement des caractères alphanumériques, tirets et underscores.'}), 400
# Validate API key based on provider
provider = data.get('provider', config.provider or 'openai')
if not validate_api_key(data['apiKey'], provider):
if provider.lower() == 'openai':
return jsonify({'error': 'Format de clé API OpenAI invalide. La clé doit commencer par "sk-" et contenir uniquement des caractères alphanumériques, tirets et underscores.'}), 400
elif provider.lower() == 'libertai':
return jsonify({'error': 'Format de clé API LibertAI invalide. Vérifiez que votre clé est correcte.'}), 400
else:
return jsonify({'error': f'Format de clé API invalide pour le provider {provider}.'}), 400
config.api_key = data['apiKey']
if 'modules' in data:
config.modules_config = data['modules']
Expand Down Expand Up @@ -496,6 +529,25 @@ async def do_list():
except Exception as e:
return jsonify({"error": str(e)}), 500

@app.route('/mcp/providers', methods=['GET'])
def list_available_providers():
"""List available AI providers"""
try:
# Import here to avoid circular imports
import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'mcp_serveur'))
from agent_factory import AgentFactory

providers = AgentFactory.get_available_providers()
return jsonify({
"providers": providers,
"current": "openai",
"note": "Currently only OpenAI is fully implemented"
})
except Exception as e:
return jsonify({"error": f"Failed to get providers: {str(e)}"}), 500

@app.route('/crypto/price', methods=['POST'])
def get_crypto_price():
"""Get cryptocurrency price via MCP tool"""
Expand Down Expand Up @@ -573,18 +625,23 @@ def chat():
message_id = session_manager.add_message(session_id, "user", user_input)

# NOUVELLE FONCTIONNALITÉ: Extraction automatique d'informations importantes
try:
memory_extractions = user_memory_manager.process_user_message(
user_id=user_id,
message=user_input,
openai_api_key=config.api_key,
message_id=message_id
)

if memory_extractions > 0:
logger.info(f"💾 {memory_extractions} information(s) extraite(s) et stockée(s) pour l'utilisateur {user_id}")
except Exception as e:
logger.warning(f"⚠️ Erreur lors de l'extraction de mémoire (continuer sans): {e}")
# IMPORTANT NOTE NOA: Only usable with OpenAI for now
memory_extractions = 0
if config.provider == 'openai':
try:
memory_extractions = user_memory_manager.process_user_message(
user_id=user_id,
message=user_input,
openai_api_key=config.api_key,
message_id=message_id
)

if memory_extractions > 0:
logger.info(f"💾 {memory_extractions} information(s) extraite(s) et stockée(s) pour l'utilisateur {user_id}")
except Exception as e:
logger.warning(f"⚠️ Erreur lors de l'extraction de mémoire (continuer sans): {e}")
else:
logger.info(f"📝 Extraction de mémoire désactivée pour le provider {config.provider} (uniquement OpenAI supporté)")

# Build conversation context with user config ET mémoire utilisateur
conversation_history = session_manager.get_context(session_id)
Expand All @@ -601,6 +658,7 @@ def chat():
'user_memory': user_memory_summary, # Nouvelle clé pour la mémoire utilisateur
'wallet_address': wallet_address, # Adresse du wallet pour les swaps
'agent_config': {
'provider': config.provider,
'model': config.selected_model,
'prompt': config.prompt,
'modules': config.modules_config
Expand Down Expand Up @@ -890,10 +948,4 @@ def get_wallet_address():
}), 200

except Exception as e:
return jsonify({'error': f'Failed to get wallet address: {str(e)}'}), 500

# ===== AUTOWALLET ROUTES =====

# Importer et créer les routes d'autowallet
from .autowallet_routes import create_autowallet_routes
create_autowallet_routes(app)
return jsonify({'error': f'Failed to get wallet address: {str(e)}'}), 500
4 changes: 2 additions & 2 deletions crypto-pilot-builder/python/mcp_client/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
DEBUG = True

# MCP configuration
MCP_SERVER_COMMAND = "python"
MCP_SERVER_ARGS = [str(SERVER_DIR / SERVER_SCRIPT)]
MCP_SERVER_COMMAND = "python3"
MCP_SERVER_ARGS = ["-u", str(SERVER_DIR / SERVER_SCRIPT)]

# OpenAI configuration (via .env)
OPENAI_MODEL = "gpt-4o-mini"
Expand Down
1 change: 1 addition & 0 deletions crypto-pilot-builder/python/mcp_client/mcp_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ async def chat_with_config(self, message: str, context: Dict[str, Any], api_key:
"message": message,
"context": json.dumps(context),
"api_key": api_key,
"provider": agent_config.get('provider', 'openai'),
"model": agent_config.get('model', 'gpt-4o-mini'),
"system_prompt": system_prompt,
"modules": json.dumps(agent_config.get('modules', {}))
Expand Down
39 changes: 39 additions & 0 deletions crypto-pilot-builder/python/mcp_serveur/agent_factory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env python3
"""
Factory for creating AI agents based on provider
"""
import sys
import os
sys.path.append(os.path.dirname(__file__))
from base_agent import BaseAgent

class AgentFactory:
"""Factory for creating AI agents"""

@staticmethod
def create_agent(provider: str = "openai") -> BaseAgent:
"""
Create an AI agent based on the provider

Args:
provider (str): The AI provider to use (default: "openai")

Returns:
BaseAgent: An instance of the appropriate agent
"""
if provider.lower() == "openai":
from mcp_server_sdk import OpenAIAgent
return OpenAIAgent()
elif provider.lower() == "libertai":
from libertai_agent import LibertAIAgent
return LibertAIAgent()
else:
# Fallback to OpenAI for now
print(f"⚠️ Provider '{provider}' not yet implemented, falling back to OpenAI")
from mcp_server_sdk import OpenAIAgent
return OpenAIAgent()

@staticmethod
def get_available_providers() -> list:
"""Get list of available providers"""
return ["openai", "libertai"]
Loading
Loading