PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 2.6.3
MxChat – AI Chatbot & Content Generation for WordPress v2.6.3
3.2.21 3.2.20 3.2.19 3.2.18 3.2.17 3.2.16 3.2.15 3.2.14 3.2.12 3.2.13 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 3.2.6 3.2.5 3.2.4 3.2.3 3.2.2 3.2.1 2.0.3 2.0.4 2.0.5 2.0.6 All 152 releases
← All changes | js/test-panel.js +45 -123 3.2.212.6.3 View file →
@@ -257,9 +257,9 @@
257 257
258 258 // NEW: Update approved URLs
259 259 this.updateApprovedUrls(testingData.approved_urls || []);
260 260
261 - this.updateTopMatches(testingData.top_matches || [], testingData.similarity_threshold || 0.75, testingData.sources_used || 0, testingData.total_chunks_used || 0);
261 + this.updateTopMatches(testingData.top_matches || [], testingData.similarity_threshold || 0.75);
262 262
263 263 // NEW: Update action matches
264 264 this.updateActionMatches(testingData.action_matches || []);
265 265
@@ -274,19 +274,8 @@
274 274 // NEW: Log approved URLs count
275 275 if (testingData.approved_urls && testingData.approved_urls.length > 0) {
276 276 this.log(`🔗 Approved URLs for citations: ${testingData.approved_urls.length}`);
277 277 }
278 -
279 - // 58f8b4: URL-guard outcome — stripping used to be completely silent,
280 - // which is why fabricated/stripped links were invisible from this panel.
281 - if (testingData.url_validation) {
282 - const uv = testingData.url_validation;
283 - if (uv.removed_count > 0) {
284 - this.log(`🚫 URL guard stripped ${uv.removed_count} unapproved link${uv.removed_count !== 1 ? 's' : ''}: ${(uv.removed_urls || []).join(', ')}`);
285 - } else if (uv.checked > 0) {
286 - this.log(`🔗 URL guard: all ${uv.checked} link${uv.checked !== 1 ? 's' : ''} in the answer approved (${uv.strict ? 'strict' : 'lenient'} mode)`);
287 - }
288 - }
289 278
290 279 // Show summary in debug console
291 280 if (testingData.top_matches && testingData.top_matches.length > 0) {
292 281 const aboveThreshold = testingData.top_matches.filter(match => match.above_threshold).length;
@@ -402,9 +391,9 @@
402 391
403 392 actionsEl.innerHTML = html;
404 393 }
405 394
406 - updateTopMatches(topMatches, threshold, sourcesUsed = 0, totalChunksUsed = 0) {
395 + updateTopMatches(topMatches, threshold) {
407 396 const scoresEl = this.panel.querySelector('#similarity-scores');
408 397
409 398 if (!topMatches || topMatches.length === 0) {
410 399 scoresEl.innerHTML = '<div class="no-data-message">No similarity data available</div>';
@@ -410,12 +399,8 @@
410 399 scoresEl.innerHTML = '<div class="no-data-message">No similarity data available</div>';
411 400 return;
412 401 }
413 402
414 - // Hybrid keyword boost (38ffa1): rows carry matched_via + fused_rank
415 - // when hybrid retrieval was on for this message.
416 - const hybridOn = topMatches.some(m => m.matched_via);
417 -
418 403 // Group matches by source URL
419 404 const groupedByUrl = {};
420 405 topMatches.forEach((match) => {
421 406 const url = match.source_display || 'Unknown';
@@ -426,11 +411,9 @@
426 411 bestScore: 0,
427 412 usedForContext: false,
428 413 totalChunks: match.total_chunks || 1,
429 414 matchedChunks: [],
430 - isChunked: match.is_chunk || false,
431 - bestFusedRank: Infinity,
432 - viaSet: {}
415 + isChunked: match.is_chunk || false
433 416 };
434 417 }
435 418
436 419 // Track best score
@@ -442,15 +425,8 @@
442 425 if (match.used_for_context) {
443 426 groupedByUrl[url].usedForContext = true;
444 427 }
445 428
446 - if (match.fused_rank && match.fused_rank < groupedByUrl[url].bestFusedRank) {
447 - groupedByUrl[url].bestFusedRank = match.fused_rank;
448 - }
449 - if (match.matched_via) {
450 - groupedByUrl[url].viaSet[match.matched_via] = true;
451 - }
452 -
453 429 // Add chunk info
454 430 groupedByUrl[url].matchedChunks.push({
455 431 chunkIndex: match.chunk_index,
456 432 score: match.similarity_percentage,
@@ -458,23 +434,17 @@
458 434 aboveThreshold: match.above_threshold
459 435 });
460 436 });
461 437
462 - // Convert to array: fused-rank order when hybrid is on, best cosine otherwise
463 - const urlGroups = Object.values(groupedByUrl).sort((a, b) => {
464 - if (hybridOn && a.bestFusedRank !== b.bestFusedRank) {
465 - return a.bestFusedRank - b.bestFusedRank;
466 - }
467 - return b.bestScore - a.bestScore;
468 - });
438 + // Convert to array and sort by best score
439 + const urlGroups = Object.values(groupedByUrl).sort((a, b) => b.bestScore - a.bestScore);
469 440
470 - // Use backend counts if available, otherwise fall back to frontend calculation
471 - const usedUrlCount = sourcesUsed > 0 ? sourcesUsed : urlGroups.filter(g => g.usedForContext).length;
472 - const chunksInfo = totalChunksUsed > 0 ? `${totalChunksUsed} chunks sent to AI` : `${topMatches.length} chunk matches`;
441 + // Count unique URLs used for context
442 + const usedUrlCount = urlGroups.filter(g => g.usedForContext).length;
473 443
474 444 let html = `<div class="matches-header">
475 - <strong>${usedUrlCount} source${usedUrlCount === 1 ? '' : 's'} used for AI context</strong>
476 - <span class="matches-subheader">(${chunksInfo})</span>
445 + <strong>${usedUrlCount} entr${usedUrlCount === 1 ? 'y' : 'ies'} used for AI context</strong>
446 + <span class="matches-subheader">(from ${topMatches.length} chunk matches)</span>
477 447 </div>`;
478 448
479 449 urlGroups.forEach((group, groupIndex) => {
480 450 const cardClass = group.usedForContext ? 'above-threshold' : 'below-threshold';
@@ -493,18 +463,8 @@
493 463 const expandToggle = hasMultipleChunks
494 464 ? `<span class="chunk-expand-toggle" data-group="${groupIndex}">▶ Show chunks</span>`
495 465 : '';
496 466
497 - let viaChip = '';
498 - if (hybridOn) {
499 - const vias = Object.keys(group.viaSet);
500 - if (vias.length) {
501 - const viaLabel = (vias.length > 1 || vias[0] === 'both') ? 'Both'
502 - : (vias[0] === 'keyword' ? 'Keyword' : 'Vector');
503 - viaChip = `<span class="mxch-rag-via-chip mxch-rag-via-${viaLabel.toLowerCase()}">${viaLabel}</span>`;
504 - }
505 - }
506 -
507 467 html += `
508 468 <div class="match-card ${cardClass}">
509 469 <div class="match-header">
510 470 <div class="match-title">
@@ -509,9 +469,8 @@
509 469 <div class="match-header">
510 470 <div class="match-title">
511 471 <span class="status-icon">${statusIcon}</span>
512 472 <span class="similarity-score">${group.bestScore}%</span>
513 - ${viaChip}
514 473 ${chunkSummary}
515 474 </div>
516 475 <span class="context-label">${contextLabel}</span>
517 476 </div>
@@ -579,49 +538,28 @@
579 538 };
580 539 }
581 540
582 541 clearChatSession() {
583 - // Determine the active bot ID from MxChatInstances
584 - let botId = 'default';
585 - if (typeof MxChatInstances !== 'undefined' && typeof MxChatInstances.getAllBotIds === 'function') {
586 - const botIds = MxChatInstances.getAllBotIds();
587 - if (botIds.length > 0) {
588 - botId = botIds[0];
589 - }
590 - }
591 -
592 - // Get current session ID using the correct bot-suffixed cookie name
593 - const cookieName = 'mxchat_session_id_' + botId;
594 - const sessionId = this.getCookie(cookieName) || this.getCookie('mxchat_session_id') || this.getCurrentSessionId();
595 -
542 + // Get current session ID from cookie (most reliable)
543 + const sessionId = this.getCookie('mxchat_session_id') || this.getCurrentSessionId();
544 +
596 545 if (!sessionId) {
597 - this.log('No active session found');
546 + this.log('❌ No active session found');
598 547 return;
599 548 }
600 -
601 - this.log('Current session ID: ' + sessionId);
602 - this.log('Starting fresh session...');
603 -
604 - // Use MxChatInstances.resetChatSession to properly reset in-memory state + cookie
605 - if (typeof MxChatInstances !== 'undefined' && typeof MxChatInstances.resetChatSession === 'function') {
606 - MxChatInstances.resetChatSession(botId);
607 - }
608 -
609 - // Get the new session ID that was just set by resetChatSession
610 - let newSessionId = '';
611 - if (typeof MxChatInstances !== 'undefined' && typeof MxChatInstances.getChatSession === 'function') {
612 - newSessionId = MxChatInstances.getChatSession(botId);
613 - }
614 -
615 - // Fallback if MxChatInstances wasn't available
616 - if (!newSessionId) {
617 - newSessionId = 'mxchat_chat_' + Math.random().toString(36).substr(2, 9);
618 - this.clearMxChatCookie(botId);
619 - this.setChatSession(newSessionId, botId);
620 - }
621 -
622 - this.log('New session ID: ' + newSessionId);
623 -
549 +
550 + this.log(`🔍 Current session ID: ${sessionId}`);
551 + this.log('🧹 Starting fresh session...');
552 +
553 + // Generate new session ID (using your existing format)
554 + const newSessionId = 'mxchat_chat_' + Math.random().toString(36).substr(2, 9);
555 +
556 + // Clear the old cookie and set new one immediately
557 + this.clearMxChatCookie();
558 + this.setChatSession(newSessionId);
559 +
560 + this.log(`🆕 New session ID: ${newSessionId}`);
561 +
624 562 // Call backend to clear old session data
625 563 fetch(mxchatTestData.ajaxUrl, {
626 564 method: 'POST',
627 565 headers: {
@@ -636,36 +574,36 @@
636 574 })
637 575 .then(response => response.json())
638 576 .then(data => {
639 577 if (data.success) {
640 - this.log('Backend session cleared: ' + data.data.message);
641 -
578 + this.log('✅ Backend session cleared: ' + data.data.message);
579 +
642 580 // Update the session ID everywhere in the DOM
643 581 this.updateSessionIdEverywhere(newSessionId);
644 -
582 +
645 583 // Clear the chat UI
646 584 this.clearChatUI();
647 -
585 +
648 586 // Show popular questions again
649 587 const popularQuestions = document.querySelector('#mxchat-popular-questions');
650 588 if (popularQuestions) {
651 589 popularQuestions.style.display = 'block';
652 590 }
653 -
591 +
654 592 // Clear testing data displays
655 593 this.updateLastQuery('New session started', []);
656 594 this.updateTopMatches([], 0);
657 595 this.updateApprovedUrls([]);
658 -
659 - this.log('Fresh session started successfully');
660 -
596 +
597 + this.log('🎉 Fresh session started successfully');
598 +
661 599 } else {
662 - this.log('Error clearing session: ' + (data.data?.message || 'Unknown error'));
600 + this.log('❌ Error clearing session: ' + (data.data?.message || 'Unknown error'));
663 601 }
664 602 })
665 603 .catch(error => {
666 604 console.error('Error clearing chat session:', error);
667 - this.log('Connection error when clearing session');
605 + this.log('🔌 Connection error when clearing session');
668 606 });
669 607 }
670 608
671 609 // Helper function to get cookie (same as your existing one)
@@ -674,21 +612,19 @@
674 612 let parts = value.split("; " + name + "=");
675 613 if (parts.length == 2) return parts.pop().split(";").shift();
676 614 }
677 615
678 - // Helper function to set session cookie (matches chat-script.js format)
679 - setChatSession(sessionId, botId) {
680 - botId = botId || 'default';
681 - document.cookie = 'mxchat_session_id_' + botId + '=' + sessionId + '; path=/; max-age=86400; SameSite=Lax';
616 + // Helper function to set session cookie (same as your existing one)
617 + setChatSession(sessionId) {
618 + // Set the cookie with a 24-hour expiration (86400 seconds)
619 + document.cookie = "mxchat_session_id=" + sessionId + "; path=/; max-age=86400; SameSite=Lax";
682 620 }
683 621
684 622 // Helper function to clear the MxChat session cookie
685 - clearMxChatCookie(botId) {
686 - botId = botId || 'default';
687 - // Clear both bot-suffixed and legacy cookie formats
688 - document.cookie = 'mxchat_session_id_' + botId + '=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax';
689 - document.cookie = 'mxchat_session_id=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax';
690 - this.log('Session cookie cleared');
623 + clearMxChatCookie() {
624 + // Clear the cookie by setting it to expire in the past
625 + document.cookie = "mxchat_session_id=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax";
626 + this.log('🍪 Session cookie cleared');
691 627 }
692 628
693 629 updateSessionIdEverywhere(newSessionId) {
694 630 // Update global session ID variable if it exists
@@ -747,23 +683,9 @@
747 683 }
748 684 }
749 685
750 686 getCurrentSessionId() {
751 - // Try MxChatInstances first (most reliable — matches chat-script.js)
752 - if (typeof MxChatInstances !== 'undefined' && typeof MxChatInstances.getChatSession === 'function') {
753 - const botIds = typeof MxChatInstances.getAllBotIds === 'function' ? MxChatInstances.getAllBotIds() : ['default'];
754 - const botId = botIds.length > 0 ? botIds[0] : 'default';
755 - const instanceSession = MxChatInstances.getChatSession(botId);
756 - if (instanceSession) {
757 - return instanceSession;
758 - }
759 - }
760 -
761 - // Try bot-suffixed cookie, then legacy cookie
762 - const botCookieId = this.getCookie('mxchat_session_id_default');
763 - if (botCookieId) {
764 - return botCookieId;
765 - }
687 + // First try to get from cookie (most reliable)
766 688 const cookieSessionId = this.getCookie('mxchat_session_id');
767 689 if (cookieSessionId) {
768 690 return cookieSessionId;
769 691 }