Application systématique et méthodique de tous les patches historiques. ## ✅ FICHIERS SYNCHRONISÉS (19 fichiers) ### Core & Infrastructure: - server.js (14 patches) - Lazy loading ModeManager, SIGINT hard kill, timing logs - ModeManager.js (4 patches) - Instrumentation complète avec timing détaillé ### Pipeline System: - PipelineDefinition.js (6 patches) - Source unique getLLMProvidersList() - pipeline-builder.js (8 patches) - Standardisation LLM providers - pipeline-runner.js (6 patches) - Affichage résultats structurés + debug console - pipeline-builder.html (2 patches) - Fallback providers synchronisés - pipeline-runner.html (3 patches) - UI améliorée résultats ### Enhancement Layers: - TechnicalLayer.js (1 patch) - defaultLLM: 'gpt-4o-mini' - StyleLayer.js (1 patch) - Type safety vocabulairePref - PatternBreakingCore.js (1 patch) - Mapping modifications - PatternBreakingLayers.js (1 patch) - LLM standardisé ### Validators & Tests: - QualityMetrics.js (1 patch) - callLLM('gpt-4o-mini') - PersonalityValidator.js (1 patch) - Provider gpt-4o-mini - AntiDetectionValidator.js - Synchronisé ### Documentation: - TODO.md (1 patch) - Section LiteLLM pour tracking coûts - CLAUDE.md - Documentation à jour ### Tools: - tools/analyze-skipped-exports.js (nouveau) - tools/apply-claude-exports.js (nouveau) - tools/apply-claude-exports-fuzzy.js (nouveau) ## 🎯 Changements principaux: - ✅ Standardisation LLM providers (openai → gpt-4o-mini, claude → claude-sonnet-4-5) - ✅ Lazy loading optimisé (ModeManager chargé à la demande) - ✅ SIGINT immediate exit (pas de graceful shutdown) - ✅ Type safety renforcé (conversions string explicites) - ✅ Instrumentation timing complète - ✅ Debug logging amélioré (console.log résultats pipeline) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
369 lines
10 KiB
JavaScript
369 lines
10 KiB
JavaScript
/**
|
||
* PipelineDefinition.js
|
||
*
|
||
* Schemas et validation pour les pipelines modulaires flexibles.
|
||
* Permet de définir des workflows custom avec n'importe quelle combinaison de modules.
|
||
*/
|
||
|
||
const { logSh } = require('../ErrorReporting');
|
||
const { getLLMProvidersList } = require('../LLMManager');
|
||
|
||
/**
|
||
* Providers LLM disponibles (source unique depuis LLMManager)
|
||
*/
|
||
const AVAILABLE_LLM_PROVIDERS = getLLMProvidersList();
|
||
|
||
/**
|
||
* Modules disponibles dans le pipeline
|
||
*/
|
||
const AVAILABLE_MODULES = {
|
||
generation: {
|
||
name: 'Generation',
|
||
description: 'Génération initiale du contenu',
|
||
modes: ['simple'],
|
||
defaultIntensity: 1.0,
|
||
defaultLLM: 'claude-sonnet-4-5',
|
||
parameters: {
|
||
llmProvider: { type: 'string', enum: AVAILABLE_LLM_PROVIDERS.map(p => p.id), default: 'claude-sonnet-4-5' }
|
||
}
|
||
},
|
||
selective: {
|
||
name: 'Selective Enhancement',
|
||
description: 'Amélioration sélective par couches',
|
||
modes: [
|
||
'lightEnhancement',
|
||
'standardEnhancement',
|
||
'fullEnhancement',
|
||
'personalityFocus',
|
||
'fluidityFocus',
|
||
'adaptive'
|
||
],
|
||
defaultIntensity: 1.0,
|
||
defaultLLM: 'gpt-4o-mini',
|
||
parameters: {
|
||
layers: { type: 'array', description: 'Couches spécifiques à appliquer' },
|
||
llmProvider: { type: 'string', enum: AVAILABLE_LLM_PROVIDERS.map(p => p.id), default: 'gpt-4o-mini' }
|
||
}
|
||
},
|
||
adversarial: {
|
||
name: 'Adversarial Generation',
|
||
description: 'Techniques anti-détection',
|
||
modes: ['none', 'light', 'standard', 'heavy', 'adaptive'],
|
||
defaultIntensity: 1.0,
|
||
defaultLLM: 'gemini-pro',
|
||
parameters: {
|
||
detector: { type: 'string', enum: ['general', 'gptZero', 'originality'], default: 'general' },
|
||
method: { type: 'string', enum: ['enhancement', 'regeneration', 'hybrid'], default: 'regeneration' },
|
||
llmProvider: { type: 'string', enum: AVAILABLE_LLM_PROVIDERS.map(p => p.id), default: 'gemini-pro' }
|
||
}
|
||
},
|
||
human: {
|
||
name: 'Human Simulation',
|
||
description: 'Simulation comportement humain',
|
||
modes: [
|
||
'none',
|
||
'lightSimulation',
|
||
'standardSimulation',
|
||
'heavySimulation',
|
||
'adaptiveSimulation',
|
||
'personalityFocus',
|
||
'temporalFocus'
|
||
],
|
||
defaultIntensity: 1.0,
|
||
defaultLLM: 'mistral-small',
|
||
parameters: {
|
||
fatigueLevel: { type: 'number', min: 0, max: 1, default: 0.5 },
|
||
errorRate: { type: 'number', min: 0, max: 1, default: 0.3 },
|
||
llmProvider: { type: 'string', enum: AVAILABLE_LLM_PROVIDERS.map(p => p.id), default: 'mistral-small' }
|
||
}
|
||
},
|
||
pattern: {
|
||
name: 'Pattern Breaking',
|
||
description: 'Cassage patterns LLM',
|
||
modes: [
|
||
'none',
|
||
'lightPatternBreaking',
|
||
'standardPatternBreaking',
|
||
'heavyPatternBreaking',
|
||
'adaptivePatternBreaking',
|
||
'syntaxFocus',
|
||
'connectorsFocus'
|
||
],
|
||
defaultIntensity: 1.0,
|
||
defaultLLM: 'deepseek-chat',
|
||
parameters: {
|
||
focus: { type: 'string', enum: ['syntax', 'connectors', 'both'], default: 'both' },
|
||
llmProvider: { type: 'string', enum: AVAILABLE_LLM_PROVIDERS.map(p => p.id), default: 'deepseek-chat' }
|
||
}
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Schema d'une étape de pipeline
|
||
*/
|
||
const STEP_SCHEMA = {
|
||
step: { type: 'number', required: true, description: 'Numéro séquentiel de l\'étape' },
|
||
module: { type: 'string', required: true, enum: Object.keys(AVAILABLE_MODULES), description: 'Module à exécuter' },
|
||
mode: { type: 'string', required: true, description: 'Mode du module' },
|
||
intensity: { type: 'number', required: false, min: 0.1, max: 2.0, default: 1.0, description: 'Intensité d\'application' },
|
||
parameters: { type: 'object', required: false, default: {}, description: 'Paramètres spécifiques au module' },
|
||
saveCheckpoint: { type: 'boolean', required: false, default: false, description: 'Sauvegarder checkpoint après cette étape' },
|
||
enabled: { type: 'boolean', required: false, default: true, description: 'Activer/désactiver l\'étape' }
|
||
};
|
||
|
||
/**
|
||
* Schema complet d'un pipeline
|
||
*/
|
||
const PIPELINE_SCHEMA = {
|
||
name: { type: 'string', required: true, minLength: 3, maxLength: 100 },
|
||
description: { type: 'string', required: false, maxLength: 500 },
|
||
pipeline: { type: 'array', required: true, minLength: 1, maxLength: 20 },
|
||
metadata: {
|
||
type: 'object',
|
||
required: false,
|
||
properties: {
|
||
author: { type: 'string' },
|
||
created: { type: 'string' },
|
||
version: { type: 'string' },
|
||
tags: { type: 'array' }
|
||
}
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Classe PipelineDefinition
|
||
*/
|
||
class PipelineDefinition {
|
||
constructor(definition = null) {
|
||
this.definition = definition;
|
||
}
|
||
|
||
/**
|
||
* Valide un pipeline complet
|
||
*/
|
||
static validate(pipeline) {
|
||
const errors = [];
|
||
|
||
// Validation schema principal
|
||
if (!pipeline.name || typeof pipeline.name !== 'string' || pipeline.name.length < 3) {
|
||
errors.push('Le nom du pipeline doit contenir au moins 3 caractères');
|
||
}
|
||
|
||
if (!Array.isArray(pipeline.pipeline) || pipeline.pipeline.length === 0) {
|
||
errors.push('Le pipeline doit contenir au moins une étape');
|
||
}
|
||
|
||
if (pipeline.pipeline && pipeline.pipeline.length > 20) {
|
||
errors.push('Le pipeline ne peut pas contenir plus de 20 étapes');
|
||
}
|
||
|
||
// Validation des étapes
|
||
if (Array.isArray(pipeline.pipeline)) {
|
||
pipeline.pipeline.forEach((step, index) => {
|
||
const stepErrors = PipelineDefinition.validateStep(step, index);
|
||
errors.push(...stepErrors);
|
||
});
|
||
|
||
// Vérifier séquence des steps
|
||
const steps = pipeline.pipeline.map(s => s.step).sort((a, b) => a - b);
|
||
for (let i = 0; i < steps.length; i++) {
|
||
if (steps[i] !== i + 1) {
|
||
errors.push(`Numérotation des étapes incorrecte: attendu ${i + 1}, trouvé ${steps[i]}`);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (errors.length > 0) {
|
||
logSh(`❌ Pipeline validation failed: ${errors.join(', ')}`, 'ERROR');
|
||
return { valid: false, errors };
|
||
}
|
||
|
||
logSh(`✅ Pipeline "${pipeline.name}" validé: ${pipeline.pipeline.length} étapes`, 'DEBUG');
|
||
return { valid: true, errors: [] };
|
||
}
|
||
|
||
/**
|
||
* Valide une étape individuelle
|
||
*/
|
||
static validateStep(step, index) {
|
||
const errors = [];
|
||
|
||
// Step number
|
||
if (typeof step.step !== 'number' || step.step < 1) {
|
||
errors.push(`Étape ${index}: 'step' doit être un nombre >= 1`);
|
||
}
|
||
|
||
// Module
|
||
if (!step.module || !AVAILABLE_MODULES[step.module]) {
|
||
errors.push(`Étape ${index}: module '${step.module}' inconnu. Disponibles: ${Object.keys(AVAILABLE_MODULES).join(', ')}`);
|
||
return errors; // Stop si module invalide
|
||
}
|
||
|
||
const moduleConfig = AVAILABLE_MODULES[step.module];
|
||
|
||
// Mode
|
||
if (!step.mode) {
|
||
errors.push(`Étape ${index}: 'mode' requis pour module ${step.module}`);
|
||
} else if (!moduleConfig.modes.includes(step.mode)) {
|
||
errors.push(`Étape ${index}: mode '${step.mode}' invalide pour ${step.module}. Disponibles: ${moduleConfig.modes.join(', ')}`);
|
||
}
|
||
|
||
// Intensity
|
||
if (step.intensity !== undefined) {
|
||
if (typeof step.intensity !== 'number' || step.intensity < 0.1 || step.intensity > 2.0) {
|
||
errors.push(`Étape ${index}: intensity doit être entre 0.1 et 2.0`);
|
||
}
|
||
}
|
||
|
||
// Parameters (validation basique)
|
||
if (step.parameters && typeof step.parameters !== 'object') {
|
||
errors.push(`Étape ${index}: parameters doit être un objet`);
|
||
}
|
||
|
||
return errors;
|
||
}
|
||
|
||
/**
|
||
* Crée une étape de pipeline valide
|
||
*/
|
||
static createStep(stepNumber, module, mode, options = {}) {
|
||
const moduleConfig = AVAILABLE_MODULES[module];
|
||
if (!moduleConfig) {
|
||
throw new Error(`Module inconnu: ${module}`);
|
||
}
|
||
|
||
if (!moduleConfig.modes.includes(mode)) {
|
||
throw new Error(`Mode ${mode} invalide pour module ${module}`);
|
||
}
|
||
|
||
return {
|
||
step: stepNumber,
|
||
module,
|
||
mode,
|
||
intensity: options.intensity ?? moduleConfig.defaultIntensity,
|
||
parameters: options.parameters ?? {},
|
||
saveCheckpoint: options.saveCheckpoint ?? false,
|
||
enabled: options.enabled ?? true
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Crée un pipeline vide
|
||
*/
|
||
static createEmpty(name, description = '') {
|
||
return {
|
||
name,
|
||
description,
|
||
pipeline: [],
|
||
metadata: {
|
||
author: 'system',
|
||
created: new Date().toISOString(),
|
||
version: '1.0',
|
||
tags: []
|
||
}
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Clone un pipeline
|
||
*/
|
||
static clone(pipeline, newName = null) {
|
||
const cloned = JSON.parse(JSON.stringify(pipeline));
|
||
if (newName) {
|
||
cloned.name = newName;
|
||
}
|
||
cloned.metadata = {
|
||
...cloned.metadata,
|
||
created: new Date().toISOString(),
|
||
clonedFrom: pipeline.name
|
||
};
|
||
return cloned;
|
||
}
|
||
|
||
/**
|
||
* Estime la durée d'un pipeline
|
||
*/
|
||
static estimateDuration(pipeline) {
|
||
// Durées moyennes par module (en secondes)
|
||
const DURATIONS = {
|
||
generation: 15,
|
||
selective: 20,
|
||
adversarial: 25,
|
||
human: 15,
|
||
pattern: 18
|
||
};
|
||
|
||
let totalSeconds = 0;
|
||
pipeline.pipeline.forEach(step => {
|
||
if (!step.enabled) return;
|
||
|
||
const baseDuration = DURATIONS[step.module] || 20;
|
||
const intensityFactor = step.intensity || 1.0;
|
||
totalSeconds += baseDuration * intensityFactor;
|
||
});
|
||
|
||
return {
|
||
seconds: Math.round(totalSeconds),
|
||
formatted: PipelineDefinition.formatDuration(totalSeconds)
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Formate une durée en secondes
|
||
*/
|
||
static formatDuration(seconds) {
|
||
if (seconds < 60) return `${seconds}s`;
|
||
const minutes = Math.floor(seconds / 60);
|
||
const secs = seconds % 60;
|
||
return `${minutes}m ${secs}s`;
|
||
}
|
||
|
||
/**
|
||
* Obtient les infos d'un module
|
||
*/
|
||
static getModuleInfo(moduleName) {
|
||
return AVAILABLE_MODULES[moduleName] || null;
|
||
}
|
||
|
||
/**
|
||
* Liste tous les modules disponibles
|
||
*/
|
||
static listModules() {
|
||
return Object.entries(AVAILABLE_MODULES).map(([key, config]) => ({
|
||
id: key,
|
||
...config
|
||
}));
|
||
}
|
||
|
||
/**
|
||
* Génère un résumé lisible du pipeline
|
||
*/
|
||
static getSummary(pipeline) {
|
||
const enabledSteps = pipeline.pipeline.filter(s => s.enabled !== false);
|
||
const moduleCount = {};
|
||
|
||
enabledSteps.forEach(step => {
|
||
moduleCount[step.module] = (moduleCount[step.module] || 0) + 1;
|
||
});
|
||
|
||
const summary = Object.entries(moduleCount)
|
||
.map(([module, count]) => `${module}×${count}`)
|
||
.join(' → ');
|
||
|
||
return {
|
||
totalSteps: enabledSteps.length,
|
||
summary,
|
||
duration: PipelineDefinition.estimateDuration(pipeline)
|
||
};
|
||
}
|
||
}
|
||
|
||
module.exports = {
|
||
PipelineDefinition,
|
||
AVAILABLE_MODULES,
|
||
AVAILABLE_LLM_PROVIDERS,
|
||
PIPELINE_SCHEMA,
|
||
STEP_SCHEMA
|
||
};
|