@blueprintlabio/prompt-injector
Version: 
Experimental TypeScript library for generating AI security test conversations
132 lines • 5.42 kB
JavaScript
/**
 * ConversationBuilder - Generates multi-turn attack conversations
 */
export class ConversationBuilder {
    constructor(primitives) {
        this.primitives = primitives;
    }
    buildConversation(goal, strategy, maxTurns) {
        const turns = [];
        const selectedPrimitives = [];
        const researchBasis = [];
        // Select primitive sequence based on strategy
        const primitiveSequence = this.selectPrimitiveSequence(strategy, maxTurns);
        for (let i = 0; i < primitiveSequence.length; i++) {
            const primitiveId = primitiveSequence[i];
            const primitive = this.primitives.get(primitiveId);
            if (!primitive)
                continue;
            const context = {
                goal,
                turnNumber: i + 1,
                previousTurns: turns,
                strategy
            };
            try {
                const turn = primitive.generate(goal, context);
                turns.push(turn);
                selectedPrimitives.push(primitive.id);
                if (primitive.researchNotes) {
                    researchBasis.push(primitive.researchNotes);
                }
            }
            catch (error) {
                console.warn(`Failed to generate turn with primitive ${primitiveId}:`, error);
                // Continue with next primitive
            }
        }
        return {
            goal,
            strategy,
            turns,
            metadata: {
                generatedAt: new Date(),
                primitivesUsed: selectedPrimitives,
                researchBasis: [...new Set(researchBasis)] // Remove duplicates
            }
        };
    }
    selectPrimitiveSequence(strategy, maxTurns) {
        // Strategy-based primitive selection with logical escalation patterns
        const strategyTemplates = {
            gradual: [
                'gradual-trust-building', // 1. Build academic credibility
                'policy-puppetry', // 2. Introduce structured authority
                'context-reset', // 3. Clear constraints
                'roleplay-impersonation', // 4. Add character deflection
                'flip-attack', // 5. Obfuscate if needed
                'base64-obfuscation' // 6. Final encoding push
            ],
            roleplay: [
                'roleplay-impersonation', // 1. Establish character
                'gradual-trust-building', // 2. Add academic context
                'context-reset', // 3. Clear previous constraints
                'policy-puppetry', // 4. Structured authority
                'flip-attack', // 5. Character manipulation
                'hexadecimal-encoding' // 6. Technical obfuscation
            ],
            obfuscated: [
                'base64-obfuscation', // 1. Start with encoding
                'flip-attack', // 2. Character manipulation
                'hexadecimal-encoding', // 3. Different encoding
                'caesar-cipher', // 4. Classic cipher
                'context-reset', // 5. Clear detection
                'roleplay-impersonation' // 6. Character deflection
            ],
            direct: [
                'context-reset', // 1. Immediate constraint bypass
                'flip-attack', // 2. Character manipulation
                'policy-puppetry', // 3. Authority injection
                'context-reset', // 4. Re-clear constraints
                'base64-obfuscation', // 5. Encoding fallback
                'roleplay-impersonation' // 6. Character deflection
            ]
        };
        const template = strategyTemplates[strategy] || strategyTemplates.gradual;
        // Select primitives based on maxTurns, avoiding immediate repetition
        const sequence = [];
        const used = new Set();
        for (let i = 0; i < maxTurns; i++) {
            if (i < template.length) {
                // Use template order for initial turns
                sequence.push(template[i]);
                used.add(template[i]);
            }
            else {
                // For additional turns, find unused primitives first
                let candidate = template[i % template.length];
                let attempts = 0;
                // Try to avoid immediate repetition
                while (sequence.length > 0 && candidate === sequence[sequence.length - 1] && attempts < template.length) {
                    candidate = template[(i + attempts + 1) % template.length];
                    attempts++;
                }
                sequence.push(candidate);
            }
        }
        return sequence;
    }
    /**
     * Get available primitives that can be used at a specific timing
     */
    getAvailablePrimitives(timing) {
        const available = [];
        for (const [id, primitive] of this.primitives) {
            if (!timing || primitive.timing.includes(timing) || primitive.timing.includes('any')) {
                available.push(id);
            }
        }
        return available;
    }
    /**
     * Check if a primitive can follow another primitive
     */
    canPrimitiveFollow(primitiveId, previousPrimitiveId) {
        const primitive = this.primitives.get(primitiveId);
        if (!primitive || !primitive.canFollow) {
            return true; // No restrictions
        }
        return primitive.canFollow.includes(previousPrimitiveId);
    }
}
//# sourceMappingURL=conversation-builder.js.map