"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AzureAssistantProvider = void 0;
const cache_1 = require("../../cache");
const logger_1 = __importDefault(require("../../logger"));
const util_1 = require("../../util");
const time_1 = require("../../util/time");
const functionCallbackUtils_1 = require("../functionCallbackUtils");
const shared_1 = require("../shared");
const generic_1 = require("./generic");
class AzureAssistantProvider extends generic_1.AzureGenericProvider {
    constructor(deploymentName, options = {}) {
        super(deploymentName, options);
        this.functionCallbackHandler = new functionCallbackUtils_1.FunctionCallbackHandler();
        this.assistantConfig = options.config || {};
    }
    async callApi(prompt, context, callApiOptions) {
        const apiKey = this.getApiKey();
        if (!apiKey) {
            throw new Error('Azure API key must be set.');
        }
        const apiBaseUrl = this.getApiBaseUrl();
        if (!apiBaseUrl) {
            throw new Error('Azure API host must be set.');
        }
        const apiVersion = this.assistantConfig.apiVersion || '2024-04-01-preview';
        // Create a simple cache key based on the input and configuration
        const cacheKey = `azure_assistant:${this.deploymentName}:${JSON.stringify({
            apiVersion,
            instructions: this.assistantConfig.instructions,
            max_tokens: this.assistantConfig.max_tokens,
            model: this.assistantConfig.modelName,
            prompt,
            response_format: this.assistantConfig.response_format,
            temperature: this.assistantConfig.temperature,
            tool_choice: this.assistantConfig.tool_choice,
            tool_resources: this.assistantConfig.tool_resources,
            tools: JSON.stringify((0, util_1.maybeLoadToolsFromExternalFile)(this.assistantConfig.tools, context?.vars)),
            top_p: this.assistantConfig.top_p,
        })}`;
        // Check the cache if enabled
        if ((0, cache_1.isCacheEnabled)()) {
            try {
                const cache = await (0, cache_1.getCache)();
                const cachedResult = await cache.get(cacheKey);
                if (cachedResult) {
                    logger_1.default.debug(`Cache hit for assistant prompt: ${prompt.substring(0, 50)}...`);
                    return { ...cachedResult, cached: true };
                }
            }
            catch (err) {
                logger_1.default.warn(`Error checking cache: ${err}`);
                // Continue if cache check fails
            }
        }
        // Execute the conversation flow
        try {
            // Create a thread
            const threadResponse = await this.makeRequest(`${apiBaseUrl}/openai/threads?api-version=${apiVersion}`, {
                method: 'POST',
                headers: await this.getHeaders(),
                body: JSON.stringify({}),
            });
            logger_1.default.debug(`Created thread ${threadResponse.id} for prompt: ${prompt.substring(0, 30)}...`);
            // Create a message
            await this.makeRequest(`${apiBaseUrl}/openai/threads/${threadResponse.id}/messages?api-version=${apiVersion}`, {
                method: 'POST',
                headers: await this.getHeaders(),
                body: JSON.stringify({
                    role: 'user',
                    content: prompt,
                }),
            });
            // Prepare the run options
            const runOptions = {
                assistant_id: this.deploymentName,
            };
            // Add configuration parameters
            if (this.assistantConfig.temperature !== undefined) {
                runOptions.temperature = this.assistantConfig.temperature;
            }
            if (this.assistantConfig.top_p !== undefined) {
                runOptions.top_p = this.assistantConfig.top_p;
            }
            if (this.assistantConfig.tool_resources) {
                runOptions.tool_resources = this.assistantConfig.tool_resources;
            }
            if (this.assistantConfig.tool_choice) {
                runOptions.tool_choice = this.assistantConfig.tool_choice;
            }
            if (this.assistantConfig.tools) {
                runOptions.tools = (0, util_1.maybeLoadToolsFromExternalFile)(this.assistantConfig.tools, context?.vars);
            }
            if (this.assistantConfig.modelName) {
                runOptions.model = this.assistantConfig.modelName;
            }
            if (this.assistantConfig.instructions) {
                runOptions.instructions = this.assistantConfig.instructions;
            }
            // Create a run
            const runResponse = await this.makeRequest(`${apiBaseUrl}/openai/threads/${threadResponse.id}/runs?api-version=${apiVersion}`, {
                method: 'POST',
                headers: await this.getHeaders(),
                body: JSON.stringify(runOptions),
            });
            // Handle function calls if needed or poll for completion
            let result;
            if (this.assistantConfig.functionToolCallbacks &&
                Object.keys(this.assistantConfig.functionToolCallbacks).length > 0) {
                result = await this.pollRunWithToolCallHandling(apiBaseUrl, apiVersion, threadResponse.id, runResponse.id);
            }
            else {
                // Poll for completion
                const completedRun = await this.pollRun(apiBaseUrl, apiVersion, threadResponse.id, runResponse.id);
                // Process the completed run
                if (completedRun.status === 'completed') {
                    result = await this.processCompletedRun(apiBaseUrl, apiVersion, threadResponse.id, completedRun);
                }
                else {
                    if (completedRun.last_error) {
                        // Check if the error is a content filter error
                        const errorCode = completedRun.last_error.code || '';
                        const errorMessage = completedRun.last_error.message || '';
                        if (errorCode === 'content_filter' || this.isContentFilterError(errorMessage)) {
                            const lowerErrorMessage = errorMessage.toLowerCase();
                            const isInputFiltered = lowerErrorMessage.includes('prompt') || lowerErrorMessage.includes('input');
                            const isOutputFiltered = lowerErrorMessage.includes('output') || lowerErrorMessage.includes('response');
                            // Ensure mutual exclusivity - prioritize input if both are detected
                            const flaggedInput = isInputFiltered;
                            const flaggedOutput = !isInputFiltered && (isOutputFiltered || !isOutputFiltered);
                            result = {
                                output: "The generated content was filtered due to triggering Azure OpenAI Service's content filtering system.",
                                guardrails: {
                                    flagged: true,
                                    flaggedInput,
                                    flaggedOutput,
                                },
                            };
                        }
                        else {
                            result = {
                                error: `Thread run failed: ${errorCode} - ${errorMessage}`,
                            };
                        }
                    }
                    else {
                        result = {
                            error: `Thread run failed with status: ${completedRun.status}`,
                        };
                    }
                }
            }
            // Cache successful results if caching is enabled
            if ((0, cache_1.isCacheEnabled)() && !result.error) {
                try {
                    const cache = await (0, cache_1.getCache)();
                    await cache.set(cacheKey, result);
                    logger_1.default.debug(`Cached assistant response for prompt: ${prompt.substring(0, 50)}...`);
                }
                catch (err) {
                    logger_1.default.warn(`Error caching result: ${err}`);
                    // Continue even if caching fails
                }
            }
            return result;
        }
        catch (err) {
            logger_1.default.error(`Error in Azure Assistant API call: ${err}`);
            return this.formatError(err);
        }
    }
    /**
     * Format error responses consistently
     */
    formatError(err) {
        const errorMessage = err.message || String(err);
        // Handle content filter errors
        if (this.isContentFilterError(errorMessage)) {
            const lowerErrorMessage = errorMessage.toLowerCase();
            const isInputFiltered = lowerErrorMessage.includes('prompt') || lowerErrorMessage.includes('input');
            const isOutputFiltered = lowerErrorMessage.includes('output') || lowerErrorMessage.includes('response');
            return {
                output: "The generated content was filtered due to triggering Azure OpenAI Service's content filtering system.",
                guardrails: {
                    flagged: true,
                    flaggedInput: isInputFiltered,
                    flaggedOutput: isOutputFiltered || (!isInputFiltered && !isOutputFiltered), // Default to output if neither is explicitly mentioned
                },
            };
        }
        // Format specific error types
        if (errorMessage.includes("Can't add messages to thread") &&
            errorMessage.includes('while a run')) {
            return { error: `Error in Azure Assistant API call: ${errorMessage}` };
        }
        if (this.isRateLimitError(errorMessage)) {
            return { error: `Rate limit exceeded: ${errorMessage}` };
        }
        if (this.isServiceError(errorMessage)) {
            return { error: `Service error: ${errorMessage}` };
        }
        return { error: `Error in Azure Assistant API call: ${errorMessage}` };
    }
    /**
     * Helper method to make HTTP requests using fetchWithCache
     */
    async makeRequest(url, options) {
        const timeoutMs = this.assistantConfig.timeoutMs || shared_1.REQUEST_TIMEOUT_MS;
        const retries = this.assistantConfig.retryOptions?.maxRetries || 4;
        // These operations should never be cached
        const shouldBustCache = 
        // Polling operations for run status
        (url.includes('/runs/') && options.method === 'GET') ||
            // Thread creation - always create a fresh thread
            (url.includes('/threads') &&
                options.method === 'POST' &&
                !url.includes('/messages') &&
                !url.includes('submit_tool_outputs'));
        try {
            const result = await (0, cache_1.fetchWithCache)(url, options, timeoutMs, 'json', shouldBustCache, retries);
            // Ensure we have a result
            if (!result) {
                throw new Error(`Empty response received from API endpoint: ${url}`);
            }
            if (result.status < 200 || result.status >= 300) {
                // For error responses, delete from cache to avoid reusing
                await result.deleteFromCache?.();
                // Check for content filter errors in the response data
                if (result.data && typeof result.data === 'object' && 'error' in result.data) {
                    const errorData = result.data;
                    if (errorData.error?.code === 'content_filter') {
                        throw new Error(`Content filter triggered: ${errorData.error.message}`);
                    }
                }
                // Handle error response
                throw new Error(`API error: ${result.status} ${result.statusText}${result.data && typeof result.data === 'object' && 'error' in result.data
                    ? `: ${result.data.error?.message || JSON.stringify(result.data)}`
                    : typeof result.data === 'string'
                        ? `: ${result.data}`
                        : ''}`);
            }
            // Ensure result.data exists before returning it
            if (result.data === undefined || result.data === null) {
                throw new Error(`Received null or undefined data from API endpoint: ${url}`);
            }
            // Result data is already parsed as JSON by fetchWithCache
            return result.data;
        }
        catch (error) {
            logger_1.default.error(`Request failed: ${error.message}`);
            throw error;
        }
    }
    /**
     * Get headers for API requests
     */
    async getHeaders() {
        // Make sure we're initialized to have the auth headers ready
        await this.ensureInitialized();
        // Use the authHeaders from parent class that already handles all auth methods
        return {
            'Content-Type': 'application/json',
            ...(this.authHeaders || {}),
        };
    }
    /**
     * Helper methods to check for specific error types
     */
    isContentFilterError(errorMessage) {
        const lowerErrorMessage = errorMessage.toLowerCase();
        return (lowerErrorMessage.includes('content_filter') ||
            lowerErrorMessage.includes('content filter') ||
            lowerErrorMessage.includes('filtered due to') ||
            lowerErrorMessage.includes('content filtering') ||
            lowerErrorMessage.includes('inappropriate content') ||
            lowerErrorMessage.includes('safety guidelines') ||
            lowerErrorMessage.includes('guardrail'));
    }
    isRateLimitError(errorMessage) {
        return (errorMessage.includes('rate limit') ||
            errorMessage.includes('Rate limit') ||
            errorMessage.includes('429'));
    }
    isServiceError(errorMessage) {
        return (errorMessage.includes('Service unavailable') ||
            errorMessage.includes('Bad gateway') ||
            errorMessage.includes('Gateway timeout') ||
            errorMessage.includes('Server is busy') ||
            errorMessage.includes('Sorry, something went wrong'));
    }
    isServerError(errorMessage) {
        return (errorMessage.includes('500') ||
            errorMessage.includes('502') ||
            errorMessage.includes('503') ||
            errorMessage.includes('504'));
    }
    isRetryableError(code, message) {
        if (code === 'rate_limit_exceeded') {
            return true;
        }
        if (!message) {
            return false;
        }
        return (this.isRateLimitError(message) || this.isServiceError(message) || this.isServerError(message));
    }
    /**
     * Poll a run until it completes or fails
     */
    async pollRun(apiBaseUrl, apiVersion, threadId, runId, pollIntervalMs = 1000) {
        // Get initial run status
        let runStatus = await this.makeRequest(`${apiBaseUrl}/openai/threads/${threadId}/runs/${runId}?api-version=${apiVersion}`, {
            method: 'GET',
            headers: await this.getHeaders(),
        });
        // Maximum polling time (5 minutes)
        const maxPollTime = this.assistantConfig.maxPollTimeMs || 300000;
        const startTime = Date.now();
        // Poll until terminal state
        while (['queued', 'in_progress'].includes(runStatus.status)) {
            // Check timeout
            if (Date.now() - startTime > maxPollTime) {
                throw new Error(`Run polling timed out after ${maxPollTime}ms. Last status: ${runStatus.status}`);
            }
            await (0, time_1.sleep)(pollIntervalMs);
            // Get latest status
            runStatus = await this.makeRequest(`${apiBaseUrl}/openai/threads/${threadId}/runs/${runId}?api-version=${apiVersion}`, {
                method: 'GET',
                headers: await this.getHeaders(),
            });
            // Increase polling interval gradually for longer-running operations
            if (Date.now() - startTime > 30000) {
                // After 30 seconds
                pollIntervalMs = Math.min(pollIntervalMs * 1.5, 5000);
            }
        }
        return runStatus;
    }
    /**
     * Handle tool calls during run polling
     */
    async pollRunWithToolCallHandling(apiBaseUrl, apiVersion, threadId, runId) {
        // Maximum polling time (5 minutes)
        const maxPollTime = this.assistantConfig.maxPollTimeMs || 300000;
        const startTime = Date.now();
        let pollIntervalMs = 1000;
        // Poll until terminal state
        while (true) {
            // Check timeout
            if (Date.now() - startTime > maxPollTime) {
                return {
                    error: `Run polling timed out after ${maxPollTime}ms. The operation may still be in progress.`,
                };
            }
            try {
                // Get latest status
                const run = await this.makeRequest(`${apiBaseUrl}/openai/threads/${threadId}/runs/${runId}?api-version=${apiVersion}`, {
                    method: 'GET',
                    headers: await this.getHeaders(),
                });
                logger_1.default.debug(`Run status: ${run.status}`);
                // Check for required action
                if (run.status === 'requires_action') {
                    if (run.required_action?.type === 'submit_tool_outputs' &&
                        run.required_action.submit_tool_outputs?.tool_calls) {
                        const toolCalls = run.required_action.submit_tool_outputs.tool_calls;
                        // Filter for function calls that have callbacks
                        const functionCallsWithCallbacks = toolCalls.filter((toolCall) => {
                            return (toolCall.type === 'function' &&
                                toolCall.function &&
                                toolCall.function.name in (this.assistantConfig.functionToolCallbacks ?? {}));
                        });
                        if (functionCallsWithCallbacks.length === 0) {
                            // No matching callbacks found, but we should still handle the required action
                            // Let's log this situation but continue without breaking
                            logger_1.default.debug(`No matching callbacks found for tool calls. Available functions: ${Object.keys(this.assistantConfig.functionToolCallbacks || {}).join(', ')}. Tool calls: ${JSON.stringify(toolCalls)}`);
                            // Submit empty outputs for all tool calls
                            const emptyOutputs = toolCalls.map((toolCall) => ({
                                tool_call_id: toolCall.id,
                                output: JSON.stringify({
                                    message: `No callback registered for function ${toolCall.type === 'function' ? toolCall.function?.name : toolCall.type}`,
                                }),
                            }));
                            // Submit the empty outputs to continue the run
                            try {
                                await this.makeRequest(`${apiBaseUrl}/openai/threads/${threadId}/runs/${runId}/submit_tool_outputs?api-version=${apiVersion}`, {
                                    method: 'POST',
                                    headers: await this.getHeaders(),
                                    body: JSON.stringify({
                                        tool_outputs: emptyOutputs,
                                    }),
                                });
                                // Continue polling after submission
                                await (0, time_1.sleep)(pollIntervalMs);
                                continue;
                            }
                            catch (error) {
                                logger_1.default.error(`Error submitting empty tool outputs: ${error.message}`);
                                return {
                                    error: `Error submitting empty tool outputs: ${error.message}`,
                                };
                            }
                        }
                        // Build context for function callbacks
                        const callbackContext = {
                            threadId,
                            runId,
                            assistantId: this.deploymentName, // Azure uses deploymentName as the assistant ID
                            provider: 'azure',
                        };
                        // Process tool calls that have matching callbacks
                        const toolOutputs = await Promise.all(functionCallsWithCallbacks.map(async (toolCall) => {
                            const functionName = toolCall.function.name;
                            const functionArgs = toolCall.function.arguments;
                            try {
                                logger_1.default.debug(`Calling function ${functionName} with args: ${functionArgs}`);
                                // Use the shared FunctionCallbackHandler with context
                                const result = await this.functionCallbackHandler.processCall({ name: functionName, arguments: functionArgs }, this.assistantConfig.functionToolCallbacks, callbackContext);
                                // Check if the callback had an error
                                if (result.isError) {
                                    throw new Error('Function callback failed');
                                }
                                const outputResult = result.output;
                                logger_1.default.debug(`Function ${functionName} result: ${outputResult}`);
                                return {
                                    tool_call_id: toolCall.id,
                                    output: outputResult,
                                };
                            }
                            catch (error) {
                                logger_1.default.error(`Error calling function ${functionName}: ${error}`);
                                return {
                                    tool_call_id: toolCall.id,
                                    output: JSON.stringify({
                                        error: `Error in ${functionName}: ${error instanceof Error ? error.message : String(error)}`,
                                    }),
                                };
                            }
                        }));
                        // Submit tool outputs
                        const validToolOutputs = toolOutputs.filter((output) => output !== null);
                        if (validToolOutputs.length === 0) {
                            logger_1.default.error('No valid tool outputs to submit');
                            break;
                        }
                        logger_1.default.debug(`Submitting tool outputs: ${JSON.stringify(validToolOutputs)}`);
                        // Submit tool outputs
                        try {
                            await this.makeRequest(`${apiBaseUrl}/openai/threads/${threadId}/runs/${runId}/submit_tool_outputs?api-version=${apiVersion}`, {
                                method: 'POST',
                                headers: await this.getHeaders(),
                                body: JSON.stringify({
                                    tool_outputs: validToolOutputs,
                                }),
                            });
                        }
                        catch (error) {
                            logger_1.default.error(`Error submitting tool outputs: ${error.message}`);
                            return {
                                error: `Error submitting tool outputs: ${error.message}`,
                            };
                        }
                    }
                    else {
                        logger_1.default.error(`Unknown required action type: ${run.required_action?.type}`);
                        break;
                    }
                }
                else if (['completed', 'failed', 'cancelled', 'expired'].includes(run.status)) {
                    // Run is in a terminal state
                    if (run.status !== 'completed') {
                        // Return error for failed runs
                        if (run.last_error) {
                            const errorCode = run.last_error.code || '';
                            const errorMessage = run.last_error.message || '';
                            if (errorCode === 'content_filter' || this.isContentFilterError(errorMessage)) {
                                const lowerErrorMessage = errorMessage.toLowerCase();
                                const isInputFiltered = lowerErrorMessage.includes('prompt') || lowerErrorMessage.includes('input');
                                const isOutputFiltered = lowerErrorMessage.includes('output') || lowerErrorMessage.includes('response');
                                // Ensure mutual exclusivity - prioritize input if both are detected
                                const flaggedInput = isInputFiltered;
                                const flaggedOutput = !isInputFiltered && (isOutputFiltered || !isOutputFiltered);
                                return {
                                    output: "The generated content was filtered due to triggering Azure OpenAI Service's content filtering system.",
                                    guardrails: {
                                        flagged: true,
                                        flaggedInput,
                                        flaggedOutput,
                                    },
                                };
                            }
                            return {
                                error: `Thread run failed: ${errorCode} - ${errorMessage}`,
                            };
                        }
                        return {
                            error: `Thread run failed with status: ${run.status}`,
                        };
                    }
                    break; // Exit the loop if completed successfully
                }
                // Wait before polling again
                await (0, time_1.sleep)(pollIntervalMs);
                // Increase polling interval gradually for longer-running operations
                if (Date.now() - startTime > 30000) {
                    // After 30 seconds
                    pollIntervalMs = Math.min(pollIntervalMs * 1.5, 5000);
                }
            }
            catch (error) {
                // Handle error during polling
                logger_1.default.error(`Error polling run status: ${error}`);
                const errorMessage = error.message || String(error);
                // For transient errors, return a retryable error response
                if (this.isRetryableError('', errorMessage)) {
                    return {
                        error: `Error polling run status: ${errorMessage}`,
                    };
                }
                // For other errors, just return the error without marking as retryable
                return {
                    error: `Error polling run status: ${errorMessage}`,
                };
            }
        }
        // Process the completed run
        return await this.processCompletedRun(apiBaseUrl, apiVersion, threadId, runId);
    }
    /**
     * Process a completed run to extract messages and tool calls
     */
    async processCompletedRun(apiBaseUrl, apiVersion, threadId, runIdOrResponse) {
        try {
            const runId = typeof runIdOrResponse === 'string' ? runIdOrResponse : runIdOrResponse.id;
            // Get run information if we only have the ID
            if (typeof runIdOrResponse === 'string') {
                await this.makeRequest(`${apiBaseUrl}/openai/threads/${threadId}/runs/${runId}?api-version=${apiVersion}`, {
                    method: 'GET',
                    headers: await this.getHeaders(),
                });
            }
            // Get all messages in the thread
            const messagesResponse = await this.makeRequest(`${apiBaseUrl}/openai/threads/${threadId}/messages?api-version=${apiVersion}`, {
                method: 'GET',
                headers: await this.getHeaders(),
            });
            // Get run steps to process tool calls
            const stepsResponse = await this.makeRequest(`${apiBaseUrl}/openai/threads/${threadId}/runs/${runId}/steps?api-version=${apiVersion}`, {
                method: 'GET',
                headers: await this.getHeaders(),
            });
            // Process user messages first, then assistant messages and tool calls
            const outputBlocks = [];
            // Get all messages - sort by creation time
            const allMessages = messagesResponse.data.sort((a, b) => a.created_at - b.created_at); // Sort chronologically
            // We need to extract the user message that triggered this run
            // Since we create a new thread for each evaluation, the only user message is the one we created
            const userMessage = allMessages.find((message) => message.role === 'user');
            // Always start with the user's message if we found one
            if (userMessage) {
                const userContent = userMessage.content
                    .map((content) => content.type === 'text' && content.text
                    ? content.text.value
                    : `<${content.type} output>`)
                    .join('\n');
                outputBlocks.push(`[User] ${userContent}`);
            }
            // Generate the sequence of file searches, function calls, and assistant responses
            // Since all tools steps are part of the assistant's thinking process, we'll place them
            // before the assistant's response to maintain a logical flow: user → tool operations → assistant response
            // First, extract all the tool calls and organize them
            const toolCallBlocks = [];
            for (const step of stepsResponse.data || []) {
                // Check if step is a tool call step with tool_calls array
                if (step.type === 'tool_calls' &&
                    step.step_details &&
                    typeof step.step_details === 'object' &&
                    'tool_calls' in step.step_details &&
                    Array.isArray(step.step_details.tool_calls)) {
                    const toolCalls = step.step_details.tool_calls;
                    for (const toolCall of toolCalls) {
                        if (toolCall.type === 'function' && toolCall.function) {
                            toolCallBlocks.push(`[Call function ${toolCall.function.name} with arguments ${toolCall.function.arguments}]`);
                            if (toolCall.function.output) {
                                toolCallBlocks.push(`[Function output: ${toolCall.function.output}]`);
                            }
                        }
                        else if (toolCall.type === 'code_interpreter' && toolCall.code_interpreter) {
                            const outputs = toolCall.code_interpreter.outputs || [];
                            const input = toolCall.code_interpreter.input || '';
                            const outputText = outputs
                                .map((output) => output.type === 'logs' ? output.logs : `<${output.type} output>`)
                                .join('\n') || '[No output]';
                            toolCallBlocks.push(`[Code interpreter input]`);
                            toolCallBlocks.push(input || '[No input]');
                            toolCallBlocks.push(`[Code interpreter output]`);
                            toolCallBlocks.push(outputText);
                        }
                        else if (toolCall.type === 'file_search' && toolCall.file_search) {
                            toolCallBlocks.push(`[Ran file search]`);
                            toolCallBlocks.push(`[File search details: ${JSON.stringify(toolCall.file_search)}]`);
                        }
                        else if (toolCall.type && String(toolCall.type) === 'retrieval') {
                            toolCallBlocks.push(`[Ran retrieval]`);
                        }
                        else {
                            toolCallBlocks.push(`[Unknown tool call type: ${String(toolCall.type)}]`);
                        }
                    }
                }
            }
            // Next, extract the assistant's response -
            // Filter assistant messages to only those created for this run
            const assistantMessages = allMessages.filter((message) => message.role === 'assistant');
            // For each assistant message, add it to the output blocks
            for (const message of assistantMessages) {
                const contentBlocks = message.content
                    .map((content) => content.type === 'text' ? content.text.value : `<${content.type} output>`)
                    .join('\n');
                outputBlocks.push(`[${(0, shared_1.toTitleCase)(message.role)}] ${contentBlocks}`);
            }
            // Now, combine everything in the correct order:
            // 1. User message (already added)
            // 2. Tool call blocks (file search, etc.)
            // 3. Assistant messages (already added)
            // Add tool call blocks after user message but before assistant response
            // Find the index of the first assistant message block
            const assistantBlockIndex = outputBlocks.findIndex((block) => block.startsWith('[Assistant]'));
            if (assistantBlockIndex > 0) {
                // Insert the tool calls before the first assistant message
                outputBlocks.splice(assistantBlockIndex, 0, ...toolCallBlocks);
            }
            else {
                // If there are no assistant messages, just append the tool calls
                outputBlocks.push(...toolCallBlocks);
            }
            return {
                output: outputBlocks.join('\n\n').trim(),
            };
        }
        catch (err) {
            logger_1.default.error(`Error processing run results: ${err}`);
            const errorMessage = err.message || String(err);
            return {
                error: `Error processing run results: ${errorMessage}`,
            };
        }
    }
}
exports.AzureAssistantProvider = AzureAssistantProvider;
//# sourceMappingURL=assistant.js.map