/**
 * CLI Prompt Builder
 * Prompt concatenation + multi-turn formatting helpers
 */
import { flattenOutputUnits } from './cli-output-converter.js';
/**
 * Extract clean AI output content from ConversationTurn
 * Prioritizes structured IR data, falls back to raw stdout
 *
 * This function performs noise filtering to extract only meaningful content
 * for use in prompt context, excluding progress updates, metadata, and system events.
 *
 * @param turn - Conversation turn containing output
 * @param options - Extraction options
 * @param options.includeThoughts - Whether to include AI reasoning/thinking in output (default: false)
 * @returns Clean output string suitable for prompt context
 *
 * @example
 * ```typescript
 * const cleanOutput = extractCleanOutput(turn, { includeThoughts: true });
 * // Returns: stdout + code + file_diff + thought (excludes: progress, metadata, system)
 * ```
 */
function extractCleanOutput(turn, options) {
    // Priority 1: Use structured IR if available (clean, noise-filtered)
    if (turn.output?.structured && turn.output.structured.length > 0) {
        const includeTypes = ['stdout', 'code', 'file_diff'];
        // Optionally include thought processes
        if (options?.includeThoughts) {
            includeTypes.push('thought');
        }
        return flattenOutputUnits(turn.output.structured, {
            includeTypes,
            excludeTypes: ['progress', 'metadata', 'system']
        });
    }
    // Priority 2: Use full output if available
    if (turn.output?.stdout_full) {
        return turn.output.stdout_full;
    }
    // Priority 3: Fall back to truncated stdout
    return turn.output?.stdout || '[No output]';
}
export function mergeConversations(conversations) {
    const mergedTurns = [];
    // Collect all turns with source tracking
    for (const conv of conversations) {
        for (const turn of conv.turns) {
            mergedTurns.push({
                ...turn,
                source_id: conv.id
            });
        }
    }
    // Sort by timestamp
    mergedTurns.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
    // Re-number turns
    mergedTurns.forEach((turn, idx) => {
        turn.turn = idx + 1;
    });
    // Calculate total duration
    const totalDuration = mergedTurns.reduce((sum, t) => sum + t.duration_ms, 0);
    return {
        mergedTurns,
        sourceConversations: conversations,
        totalDuration
    };
}
/**
 * Build prompt from merged conversations
 */
export function buildMergedPrompt(mergeResult, newPrompt, format = 'plain') {
    const concatenator = createPromptConcatenator({ format });
    // Set metadata for merged conversations
    concatenator.setMetadata('merged_sources', mergeResult.sourceConversations.map(c => c.id).join(', '));
    // Add all merged turns with source tracking
    for (const turn of mergeResult.mergedTurns) {
        concatenator.addFromConversationTurn(turn, turn.source_id);
    }
    return concatenator.build(newPrompt);
}
/**
 * PromptConcatenator - Dedicated class for building multi-turn prompts
 * Supports multiple output formats: plain text, YAML, JSON
 */
export class PromptConcatenator {
    turns = [];
    options;
    metadata = {};
    constructor(options = {}) {
        this.options = {
            format: options.format || 'plain',
            includeMetadata: options.includeMetadata ?? true,
            includeTurnMarkers: options.includeTurnMarkers ?? true,
            maxOutputLength: options.maxOutputLength || 8192
        };
    }
    /**
     * Set metadata for the conversation
     */
    setMetadata(key, value) {
        this.metadata[key] = value;
        return this;
    }
    /**
     * Add a user turn
     */
    addUserTurn(content, options = {}) {
        this.turns.push({
            turn: this.turns.length + 1,
            role: 'user',
            content,
            ...options
        });
        return this;
    }
    /**
     * Add an assistant turn
     */
    addAssistantTurn(content, options = {}) {
        // Truncate output if needed
        const truncatedContent = content.length > this.options.maxOutputLength
            ? content.substring(0, this.options.maxOutputLength) + '\n... [truncated]'
            : content;
        this.turns.push({
            turn: this.turns.length + 1,
            role: 'assistant',
            content: truncatedContent,
            ...options
        });
        return this;
    }
    /**
     * Add a conversation turn from ConversationTurn
     */
    addFromConversationTurn(turn, sourceId) {
        this.addUserTurn(turn.prompt, {
            turn: turn.turn * 2 - 1,
            timestamp: turn.timestamp,
            source_id: sourceId
        });
        // Use extractCleanOutput to get noise-filtered content
        const cleanOutput = extractCleanOutput(turn);
        this.addAssistantTurn(cleanOutput, {
            turn: turn.turn * 2,
            timestamp: turn.timestamp,
            status: turn.status,
            duration_ms: turn.duration_ms,
            source_id: sourceId
        });
        return this;
    }
    /**
     * Load turns from an existing conversation
     */
    loadConversation(conversation) {
        for (const turn of conversation.turns) {
            this.addFromConversationTurn(turn);
        }
        return this;
    }
    /**
     * Build the final prompt in plain text format
     */
    buildPlainText(newPrompt) {
        const parts = [];
        // Metadata section
        if (this.options.includeMetadata && Object.keys(this.metadata).length > 0) {
            parts.push('=== CONTEXT ===');
            for (const [key, value] of Object.entries(this.metadata)) {
                parts.push(`${key}: ${String(value)}`);
            }
            parts.push('');
        }
        // Conversation history
        if (this.turns.length > 0) {
            parts.push('=== CONVERSATION HISTORY ===');
            parts.push('');
            let currentTurn = 0;
            for (let i = 0; i < this.turns.length; i += 2) {
                currentTurn++;
                const userTurn = this.turns[i];
                const assistantTurn = this.turns[i + 1];
                if (this.options.includeTurnMarkers) {
                    const sourceMarker = userTurn.source_id ? ` [${userTurn.source_id}]` : '';
                    parts.push(`--- Turn ${currentTurn}${sourceMarker} ---`);
                }
                parts.push('USER:');
                parts.push(userTurn.content);
                parts.push('');
                if (assistantTurn) {
                    parts.push('ASSISTANT:');
                    parts.push(assistantTurn.content);
                    parts.push('');
                }
            }
        }
        // New request
        parts.push('=== NEW REQUEST ===');
        parts.push('');
        parts.push(newPrompt);
        return parts.join('\n');
    }
    /**
     * Build the final prompt in YAML format
     */
    buildYaml(newPrompt) {
        const yamlLines = [];
        // Metadata
        if (this.options.includeMetadata && Object.keys(this.metadata).length > 0) {
            yamlLines.push('context:');
            for (const [key, value] of Object.entries(this.metadata)) {
                yamlLines.push(`  ${key}: ${this.yamlValue(value)}`);
            }
            yamlLines.push('');
        }
        // Conversation history
        if (this.turns.length > 0) {
            yamlLines.push('conversation:');
            let currentTurn = 0;
            for (let i = 0; i < this.turns.length; i += 2) {
                currentTurn++;
                const userTurn = this.turns[i];
                const assistantTurn = this.turns[i + 1];
                yamlLines.push(`  - turn: ${currentTurn}`);
                if (userTurn.source_id) {
                    yamlLines.push(`    source: ${userTurn.source_id}`);
                }
                if (userTurn.timestamp) {
                    yamlLines.push(`    timestamp: ${userTurn.timestamp}`);
                }
                // User message
                yamlLines.push('    user: |');
                const userLines = userTurn.content.split('\n');
                for (const line of userLines) {
                    yamlLines.push(`      ${line}`);
                }
                // Assistant message
                if (assistantTurn) {
                    if (assistantTurn.status) {
                        yamlLines.push(`    status: ${assistantTurn.status}`);
                    }
                    if (assistantTurn.duration_ms) {
                        yamlLines.push(`    duration_ms: ${assistantTurn.duration_ms}`);
                    }
                    yamlLines.push('    assistant: |');
                    const assistantLines = assistantTurn.content.split('\n');
                    for (const line of assistantLines) {
                        yamlLines.push(`      ${line}`);
                    }
                }
                yamlLines.push('');
            }
        }
        // New request
        yamlLines.push('new_request: |');
        const requestLines = newPrompt.split('\n');
        for (const line of requestLines) {
            yamlLines.push(`  ${line}`);
        }
        return yamlLines.join('\n');
    }
    /**
     * Build the final prompt in JSON format
     */
    buildJson(newPrompt) {
        const data = {};
        // Metadata
        if (this.options.includeMetadata && Object.keys(this.metadata).length > 0) {
            data.context = this.metadata;
        }
        // Conversation history
        if (this.turns.length > 0) {
            const conversation = [];
            for (let i = 0; i < this.turns.length; i += 2) {
                const userTurn = this.turns[i];
                const assistantTurn = this.turns[i + 1];
                const turnData = {
                    turn: Math.ceil((i + 1) / 2),
                    user: userTurn.content
                };
                if (userTurn.source_id)
                    turnData.source = userTurn.source_id;
                if (userTurn.timestamp)
                    turnData.timestamp = userTurn.timestamp;
                if (assistantTurn) {
                    turnData.assistant = assistantTurn.content;
                    if (assistantTurn.status)
                        turnData.status = assistantTurn.status;
                    if (assistantTurn.duration_ms)
                        turnData.duration_ms = assistantTurn.duration_ms;
                }
                conversation.push(turnData);
            }
            data.conversation = conversation;
        }
        data.new_request = newPrompt;
        return JSON.stringify(data, null, 2);
    }
    /**
     * Helper to format YAML values
     */
    yamlValue(value) {
        if (typeof value === 'string') {
            // Quote strings that might be interpreted as other types
            if (/[:\[\]{}#&*!|>'"@`]/.test(value) || value === '') {
                return `"${value.replace(/"/g, '\\"')}"`;
            }
            return value;
        }
        if (typeof value === 'number' || typeof value === 'boolean') {
            return String(value);
        }
        if (value === null || value === undefined) {
            return 'null';
        }
        return JSON.stringify(value);
    }
    /**
     * Build the final prompt string
     */
    build(newPrompt) {
        switch (this.options.format) {
            case 'yaml':
                return this.buildYaml(newPrompt);
            case 'json':
                return this.buildJson(newPrompt);
            case 'plain':
            default:
                return this.buildPlainText(newPrompt);
        }
    }
    /**
     * Reset the concatenator for reuse
     */
    reset() {
        this.turns = [];
        this.metadata = {};
        return this;
    }
}
/**
 * Create a prompt concatenator with specified options
 */
export function createPromptConcatenator(options) {
    return new PromptConcatenator(options);
}
/**
 * Quick helper to build a multi-turn prompt in any format
 */
export function buildPrompt(conversation, newPrompt, format = 'plain') {
    return createPromptConcatenator({ format })
        .loadConversation(conversation)
        .build(newPrompt);
}
/**
 * Build multi-turn prompt with full conversation history
 * Uses the PromptConcatenator with plain text format by default
 */
export function buildMultiTurnPrompt(conversation, newPrompt, format = 'plain') {
    return buildPrompt(conversation, newPrompt, format);
}
//# sourceMappingURL=cli-prompt-builder.js.map