Now I need to modify `submitToAI()` to use `fetchWithTimeout` and trigger Round 2 when the checkbox is on. Let me find the AI API call and the response handling section:


Grep

fetchWithTimeout|Send to AI API|api_opus/api/query.php


9: * - Send to AI API with provider/model selection
1949:            fetchWithTimeout('../aiapi/api_opus/api/query.php', {
2142:            fetchWithTimeout('../aiapi/api_opus/api/query.php', {
2223:        function fetchWithTimeout(url, options, timeoutMs) {
2397:                const response = await fetch('../aiapi/api_opus/api/query.php?action=providers');
2831:                // Send to AI API
2832:                var response = await fetch('../aiapi/api_opus/api/query.php', {


Line 2831 is the one in `submitToAI()`. Let me read that section:


  2820→                for (var provider in modelsMap) {
  2821→                    requestBody['model_' + provider] = modelsMap[provider];
  2822→                }
  2823→
  2824→                // Show truncation notice if applicable
  2825→                if (wasTruncated) {
  2826→                    document.getElementById('loading-message').textContent = 'Content truncated to ' + finalTokens.toLocaleString() + ' tokens. Sending to ' + selectedProvidersList.length + ' AI(s)...';
  2827→                } else {
  2828→                    document.getElementById('loading-message').textContent = 'Sending ~' + finalTokens.toLocaleString() + ' tokens to ' + selectedProvidersList.length + ' AI provider(s)...';
  2829→                }
  2830→
  2831→                // Send to AI API
  2832→                var response = await fetch('../aiapi/api_opus/api/query.php', {
  2833→                    method: 'POST',
  2834→                    headers: { 'Content-Type': 'application/json' },
  2835→                    body: JSON.stringify(requestBody)
  2836→                });
  2837→
  2838→                if (!response.ok) {
  2839→                    var errText = '';
  2840→                    try { errText = await response.text(); } catch(e) {}
  2841→                    throw new Error('AI API returned HTTP ' + response.status + (errText ? ': ' + errText.substring(0, 200) : ''));
  2842→                }
  2843→
  2844→                var responseText = await response.text();
  2845→                var data;
  2846→                try {
  2847→                    data = JSON.parse(responseText);
  2848→                } catch (parseErr) {
  2849→                    throw new Error('AI API returned invalid JSON: ' + responseText.substring(0, 200));
  2850→                }
  2851→
  2852→                // Log response to debug file
  2853→                var responsePreview = '';
  2854→                if (data.responses) {
  2855→                    for (var rk in data.responses) {
  2856→                        if (data.responses[rk] && data.responses[rk].response) {
  2857→                            responsePreview = data.responses[rk].response.substring(0, 500);
  2858→                            break;
  2859→                        }
  2860→                    }
  2861→                }
  2862→                logAiDebug({
  2863→                    type: 'response',
  2864→                    thread_id: currentThreadId,
  2865→                    agent: selectedAgent,
  2866→                    providers: selectedProvidersList,
  2867→                    models: modelsMap,
  2868→                    estimated_tokens: finalTokens,
  2869→                    question: actualQuestion,
  2870→                    response: responsePreview
  2871→                });
  2872→
  2873→                console.log('=== AI RESPONSE LOG ===');
  2874→                console.log('Success:', data.success);
  2875→                console.log('Query ID:', data.query_id);
  2876→                console.log('Total Cost:', data.total_cost);
  2877→                console.log('=======================');
  2878→
  2879→                if (data.success) {
  2880→                    var firstSuccessfulProvider = null;
  2881→                    var firstSuccessfulResponse = null;
  2882→
  2883→                    // Save to MongoDB for each provider
  2884→                    for (var pi = 0; pi < selectedProvidersList.length; pi++) {
  2885→                        var prov = selectedProvidersList[pi];
  2886→                        var providerResponse = data.responses[prov + '_response'];
  2887→                        if (providerResponse && providerResponse.success) {
  2888→                            if (!firstSuccessfulProvider) {
  2889→                                firstSuccessfulProvider = prov;
  2890→                                firstSuccessfulResponse = providerResponse;
  2891→                            }
  2892→
  2893→                            // Save to MongoDB via our API
  2894→                            await saveAIResponse({
  2895→                                thread_ids: [currentThreadId].concat(allAdditionalThreads),
  2896→                                contact_id: primaryContactId,
  2897→                                question: actualQuestion,
  2898→                                context: context,
  2899→                                agent: selectedAgent,

                for (var provider in modelsMap) {
                    requestBody['model_' + provider] = modelsMap[provider];
                }

                // Show truncation notice if applicable
                if (wasTruncated) {
                    document.getElementById('loading-message').textContent = 'Content truncated to ' + finalTokens.toLocaleString() + ' tokens. Sending to ' + selectedProvidersList.length + ' AI(s)...';
                } else {
                    document.getElementById('loading-message').textContent = 'Sending ~' + finalTokens.toLocaleString() + ' tokens to ' + selectedProvidersList.length + ' AI provider(s)...';
                }

                // Send to AI API
                var response = await fetch('../aiapi/api_opus/api/query.php', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(requestBody)
                });

                if (!response.ok) {
                    var errText = '';
                    try { errText = await response.text(); } catch(e) {}
                    throw new Error('AI API returned HTTP ' + response.status + (errText ? ': ' + errText.substring(0, 200) : ''));
                }

                var responseText = await response.text();
                var data;
                try {
                    data = JSON.parse(responseText);
                } catch (parseErr) {
                    throw new Error('AI API returned invalid JSON: ' + responseText.substring(0, 200));
                }

                // Log response to debug file
                var responsePreview = '';
                if (data.responses) {
                    for (var rk in data.responses) {
                        if (data.responses[rk] && data.responses[rk].response) {
                            responsePreview = data.responses[rk].response.substring(0, 500);
                            break;
                        }
                    }
                }
                logAiDebug({
                    type: 'response',
                    thread_id: currentThreadId,
                    agent: selectedAgent,
                    providers: selectedProvidersList,
                    models: modelsMap,
                    estimated_tokens: finalTokens,
                    question: actualQuestion,
                    response: responsePreview
                });

                console.log('=== AI RESPONSE LOG ===');
                console.log('Success:', data.success);
                console.log('Query ID:', data.query_id);
                console.log('Total Cost:', data.total_cost);
                console.log('=======================');

                if (data.success) {
                    var firstSuccessfulProvider = null;
                    var firstSuccessfulResponse = null;

                    // Save to MongoDB for each provider
                    for (var pi = 0; pi < selectedProvidersList.length; pi++) {
                        var prov = selectedProvidersList[pi];
                        var providerResponse = data.responses[prov + '_response'];
                        if (providerResponse && providerResponse.success) {
                            if (!firstSuccessfulProvider) {
                                firstSuccessfulProvider = prov;
                                firstSuccessfulResponse = providerResponse;
                            }

                            // Save to MongoDB via our API
                            await saveAIResponse({
                                thread_ids: [currentThreadId].concat(allAdditionalThreads),
                                contact_id: primaryContactId,
                                question: actualQuestion,
                                context: context,
                                agent: selectedAgent,


  2898→                                context: context,
  2899→                                agent: selectedAgent,
  2900→                                content_mode: contentMode,
  2901→                                content_sent: fullContent,
  2902→                                content_length: fullContent.length,
  2903→                                estimated_tokens: finalTokens,
  2904→                                provider: prov,
  2905→                                model: modelsMap[prov],
  2906→                                query_id: data.query_id,
  2907→                                response: providerResponse,
  2908→                                total_cost: providerResponse.cost || 0,
  2909→                                all_providers: selectedProvidersList,
  2910→                                conversation_history_count: conversationHistory.length
  2911→                            });
  2912→                        }
  2913→                    }
  2914→
  2915→                    // ADD TO CONVERSATION HISTORY (first successful response)
  2916→                    if (firstSuccessfulProvider && firstSuccessfulResponse && firstSuccessfulResponse.response) {
  2917→                        addToConversation(
  2918→                            actualQuestion,
  2919→                            firstSuccessfulResponse.response,
  2920→                            firstSuccessfulProvider,
  2921→                            modelsMap[firstSuccessfulProvider],
  2922→                            context
  2923→                        );
  2924→                    }
  2925→
  2926→                    // Clear the question field for next question
  2927→                    document.getElementById('ai-question').value = '';
  2928→                    updateTokenEstimate();
  2929→
  2930→                    // Display response
  2931→                    displayAIResponse(data);
  2932→                } else {
  2933→                    alert('AI request failed: ' + (data.error || 'Unknown error'));
  2934→                }
  2935→            } catch (error) {
  2936→                console.error('AI request error:', error);
  2937→                alert('Error: ' + error.message);
  2938→            } finally {
  2939→                document.getElementById('loading-overlay').classList.remove('active');
  2940→                document.getElementById('submit-ai-btn').disabled = false;
  2941→            }
  2942→        }
  2943→
  2944→        // Save AI response to MongoDB
  2945→        async function saveAIResponse(responseData) {
  2946→            try {
  2947→                await fetch('api.php?action=save_ai_response', {
  2948→                    method: 'POST',
  2949→                    headers: { 'Content-Type': 'application/json' },
  2950→                    body: JSON.stringify(responseData)
  2951→                });
  2952→            } catch (error) {

                                context: context,
                                agent: selectedAgent,
                                content_mode: contentMode,
                                content_sent: fullContent,
                                content_length: fullContent.length,
                                estimated_tokens: finalTokens,
                                provider: prov,
                                model: modelsMap[prov],
                                query_id: data.query_id,
                                response: providerResponse,
                                total_cost: providerResponse.cost || 0,
                                all_providers: selectedProvidersList,
                                conversation_history_count: conversationHistory.length
                            });
                        }
                    }

                    // ADD TO CONVERSATION HISTORY (first successful response)
                    if (firstSuccessfulProvider && firstSuccessfulResponse && firstSuccessfulResponse.response) {
                        addToConversation(
                            actualQuestion,
                            firstSuccessfulResponse.response,
                            firstSuccessfulProvider,
                            modelsMap[firstSuccessfulProvider],
                            context
                        );
                    }

                    // Clear the question field for next question
                    document.getElementById('ai-question').value = '';
                    updateTokenEstimate();

                    // Display response
                    displayAIResponse(data);
                } else {
                    alert('AI request failed: ' + (data.error || 'Unknown error'));
                }
            } catch (error) {
                console.error('AI request error:', error);
                alert('Error: ' + error.message);
            } finally {
                document.getElementById('loading-overlay').classList.remove('active');
                document.getElementById('submit-ai-btn').disabled = false;
            }
        }

        // Save AI response to MongoDB
        async function saveAIResponse(responseData) {
            try {
                await fetch('api.php?action=save_ai_response', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(responseData)
                });
            } catch (error) {


Now replace the fetch call to use timeout and add Round 2 trigger after display:


Edit

                // Send to AI API
                var response = await fetch('../aiapi/api_opus/api/query.php', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(requestBody)
                });

                if (!response.ok) {
                    var errText = '';
                    try { errText = await response.text(); } catch(e) {}
                    throw new Error('AI API returned HTTP ' + response.status + (errText ? ': ' + errText.substring(0, 200) : ''));
                }

                var responseText = await response.text();
                var data;
                try {
                    data = JSON.parse(responseText);
                } catch (parseErr) {
                    throw new Error('AI API returned invalid JSON: ' + responseText.substring(0, 200));
                }

                // Send to AI API with timeout
                var timeoutSec = parseInt(document.getElementById('provider-timeout').value) || 120;
                var response = await fetchWithTimeout('../aiapi/api_opus/api/query.php', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(requestBody)
                }, timeoutSec * 1000);

                if (!response.ok) {
                    var errText = '';
                    try { errText = await response.text(); } catch(e) {}
                    throw new Error('AI API returned HTTP ' + response.status + (errText ? ': ' + errText.substring(0, 200) : ''));
                }

                var responseText = await response.text();
                var data;
                try {
                    data = JSON.parse(responseText);
                } catch (parseErr) {
                    throw new Error('AI API returned invalid JSON: ' + responseText.substring(0, 200));
                }