| @@ -71,14 +71,8 @@ | ||
| 71 | 71 | <strong>User Query:</strong> |
| 72 | 72 | <div id="last-query" class="query-display">Waiting for next query...</div> |
| 73 | 73 | </div> |
| 74 | 74 | <div class="mxchat-test-info"> |
| 75 | - <strong>Approved URLs for Citations:</strong> | |
| 76 | - <div class="mxchat-test-results approved-urls-container" id="approved-urls"> | |
| 77 | - <div class="no-data-message">No URL data yet</div> | |
| 78 | - </div> | |
| 79 | - </div> | |
| 80 | - <div class="mxchat-test-info"> | |
| 81 | 75 | <strong>Document Matches:</strong> |
| 82 | 76 | <div class="mxchat-test-results similarity-container" id="similarity-scores"> |
| 83 | 77 | <div class="no-data-message">No query data yet</div> |
| 84 | 78 | </div> |
| @@ -253,14 +247,10 @@ | ||
| 253 | 247 | this.log('📊 Chat data captured from response'); |
| 254 | 248 | |
| 255 | 249 | // Update query analysis section |
| 256 | 250 | this.updateLastQuery(testingData.query || 'No query', testingData.top_matches || []); |
| 251 | + this.updateTopMatches(testingData.top_matches || [], testingData.similarity_threshold || 0.75); | |
| 257 | 252 | |
| 258 | - // NEW: Update approved URLs | |
| 259 | - this.updateApprovedUrls(testingData.approved_urls || []); | |
| 260 | - | |
| 261 | - this.updateTopMatches(testingData.top_matches || [], testingData.similarity_threshold || 0.75, testingData.sources_used || 0, testingData.total_chunks_used || 0); | |
| 262 | - | |
| 263 | 253 | // NEW: Update action matches |
| 264 | 254 | this.updateActionMatches(testingData.action_matches || []); |
| 265 | 255 | |
| 266 | 256 | // Log additional info |
| @@ -270,24 +260,8 @@ | ||
| 270 | 260 | if (testingData.similarity_threshold) { |
| 271 | 261 | this.log(`🎯 Similarity Threshold: ${(testingData.similarity_threshold * 100)}%`); |
| 272 | 262 | } |
| 273 | 263 | |
| 274 | - // NEW: Log approved URLs count | |
| 275 | - if (testingData.approved_urls && testingData.approved_urls.length > 0) { | |
| 276 | - this.log(`🔗 Approved URLs for citations: ${testingData.approved_urls.length}`); | |
| 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 | - | |
| 290 | 264 | // Show summary in debug console |
| 291 | 265 | if (testingData.top_matches && testingData.top_matches.length > 0) { |
| 292 | 266 | const aboveThreshold = testingData.top_matches.filter(match => match.above_threshold).length; |
| 293 | 267 | const belowThreshold = testingData.top_matches.length - aboveThreshold; |
| @@ -312,50 +286,8 @@ | ||
| 312 | 286 | this.log('📝 No actions checked'); |
| 313 | 287 | } |
| 314 | 288 | } |
| 315 | 289 | |
| 316 | -updateApprovedUrls(approvedUrls) { | |
| 317 | - const urlsEl = this.panel.querySelector('#approved-urls'); | |
| 318 | - | |
| 319 | - // Safety check: ensure approvedUrls is an array | |
| 320 | - if (!approvedUrls || !Array.isArray(approvedUrls) || approvedUrls.length === 0) { | |
| 321 | - urlsEl.innerHTML = '<div class="no-data-message">No approved URLs (AI cannot cite links)</div>'; | |
| 322 | - return; | |
| 323 | - } | |
| 324 | - | |
| 325 | - let html = `<div class="urls-header"> | |
| 326 | - <strong>${approvedUrls.length} URL${approvedUrls.length !== 1 ? 's' : ''} approved for AI citations</strong> | |
| 327 | - </div>`; | |
| 328 | - | |
| 329 | - approvedUrls.forEach((url, index) => { | |
| 330 | - // Extract domain for display | |
| 331 | - let displayUrl = url; | |
| 332 | - try { | |
| 333 | - const urlObj = new URL(url); | |
| 334 | - displayUrl = urlObj.hostname + urlObj.pathname; | |
| 335 | - } catch (e) { | |
| 336 | - // Keep original if URL parsing fails | |
| 337 | - } | |
| 338 | - | |
| 339 | - html += ` | |
| 340 | - <div class="url-card"> | |
| 341 | - <div class="url-line"> | |
| 342 | - <span class="url-icon">🔗</span> | |
| 343 | - <a href="${url}" target="_blank" rel="noopener noreferrer" class="url-link" title="${url}"> | |
| 344 | - ${displayUrl} | |
| 345 | - </a> | |
| 346 | - </div> | |
| 347 | - </div> | |
| 348 | - `; | |
| 349 | - }); | |
| 350 | - | |
| 351 | - html += `<div class="urls-note"> | |
| 352 | - ℹ️ The AI can only cite these URLs. Any other URLs will be automatically removed from responses. | |
| 353 | - </div>`; | |
| 354 | - | |
| 355 | - urlsEl.innerHTML = html; | |
| 356 | -} | |
| 357 | - | |
| 358 | 290 | updateActionMatches(actionMatches) { |
| 359 | 291 | const actionsEl = this.panel.querySelector('#action-scores'); |
| 360 | 292 | |
| 361 | 293 | if (!actionMatches || actionMatches.length === 0) { |
| @@ -402,173 +334,60 @@ | ||
| 402 | 334 | |
| 403 | 335 | actionsEl.innerHTML = html; |
| 404 | 336 | } |
| 405 | 337 | |
| 406 | - updateTopMatches(topMatches, threshold, sourcesUsed = 0, totalChunksUsed = 0) { | |
| 338 | + updateTopMatches(topMatches, threshold) { | |
| 407 | 339 | const scoresEl = this.panel.querySelector('#similarity-scores'); |
| 408 | - | |
| 340 | + | |
| 409 | 341 | if (!topMatches || topMatches.length === 0) { |
| 410 | 342 | scoresEl.innerHTML = '<div class="no-data-message">No similarity data available</div>'; |
| 411 | 343 | return; |
| 412 | 344 | } |
| 413 | - | |
| 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 | - // Group matches by source URL | |
| 419 | - const groupedByUrl = {}; | |
| 420 | - topMatches.forEach((match) => { | |
| 421 | - const url = match.source_display || 'Unknown'; | |
| 422 | - if (!groupedByUrl[url]) { | |
| 423 | - groupedByUrl[url] = { | |
| 424 | - url: url, | |
| 425 | - isUrl: url.startsWith('http'), | |
| 426 | - bestScore: 0, | |
| 427 | - usedForContext: false, | |
| 428 | - totalChunks: match.total_chunks || 1, | |
| 429 | - matchedChunks: [], | |
| 430 | - isChunked: match.is_chunk || false, | |
| 431 | - bestFusedRank: Infinity, | |
| 432 | - viaSet: {} | |
| 433 | - }; | |
| 434 | - } | |
| 435 | - | |
| 436 | - // Track best score | |
| 437 | - if (match.similarity_percentage > groupedByUrl[url].bestScore) { | |
| 438 | - groupedByUrl[url].bestScore = match.similarity_percentage; | |
| 439 | - } | |
| 440 | - | |
| 441 | - // Track if any chunk was used for context | |
| 442 | - if (match.used_for_context) { | |
| 443 | - groupedByUrl[url].usedForContext = true; | |
| 444 | - } | |
| 445 | - | |
| 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 | - // Add chunk info | |
| 454 | - groupedByUrl[url].matchedChunks.push({ | |
| 455 | - chunkIndex: match.chunk_index, | |
| 456 | - score: match.similarity_percentage, | |
| 457 | - usedForContext: match.used_for_context, | |
| 458 | - aboveThreshold: match.above_threshold | |
| 459 | - }); | |
| 460 | - }); | |
| 461 | - | |
| 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 | - }); | |
| 469 | - | |
| 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`; | |
| 473 | - | |
| 345 | + | |
| 474 | 346 | 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> | |
| 347 | + <strong>Top ${topMatches.length} matches</strong> | |
| 477 | 348 | </div>`; |
| 478 | - | |
| 479 | - urlGroups.forEach((group, groupIndex) => { | |
| 480 | - const cardClass = group.usedForContext ? 'above-threshold' : 'below-threshold'; | |
| 481 | - const statusIcon = group.usedForContext ? '✓' : '✗'; | |
| 482 | - const contextLabel = group.usedForContext ? 'Used for AI context' : 'Not used'; | |
| 483 | - | |
| 484 | - // Build chunk summary | |
| 485 | - let chunkSummary = ''; | |
| 486 | - if (group.isChunked && group.totalChunks > 1) { | |
| 487 | - const usedChunkCount = group.matchedChunks.filter(c => c.usedForContext).length; | |
| 488 | - chunkSummary = `<span class="chunk-summary">${usedChunkCount}/${group.totalChunks} chunks matched</span>`; | |
| 349 | + | |
| 350 | + topMatches.forEach((match, index) => { | |
| 351 | + const isAboveThreshold = match.above_threshold; | |
| 352 | + const isUsedForContext = match.used_for_context; // Use the actual flag from PHP | |
| 353 | + const statusIcon = isAboveThreshold ? '✓' : '✗'; | |
| 354 | + | |
| 355 | + // Determine the correct label based on actual usage | |
| 356 | + let contextLabel; | |
| 357 | + if (isUsedForContext) { | |
| 358 | + contextLabel = 'Used for AI context'; | |
| 359 | + } else if (isAboveThreshold) { | |
| 360 | + contextLabel = 'Above threshold (not used)'; | |
| 361 | + } else { | |
| 362 | + contextLabel = 'Below threshold'; | |
| 489 | 363 | } |
| 490 | - | |
| 491 | - // Check if this entry has multiple matched chunks to show expand toggle | |
| 492 | - const hasMultipleChunks = group.matchedChunks.length > 1; | |
| 493 | - const expandToggle = hasMultipleChunks | |
| 494 | - ? `<span class="chunk-expand-toggle" data-group="${groupIndex}">▶ Show chunks</span>` | |
| 495 | - : ''; | |
| 496 | - | |
| 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 | - | |
| 364 | + | |
| 365 | + // Determine card styling - should be based on whether it was actually used | |
| 366 | + const cardClass = isUsedForContext ? 'above-threshold' : 'below-threshold'; | |
| 367 | + | |
| 507 | 368 | html += ` |
| 508 | 369 | <div class="match-card ${cardClass}"> |
| 509 | 370 | <div class="match-header"> |
| 510 | 371 | <div class="match-title"> |
| 511 | 372 | <span class="status-icon">${statusIcon}</span> |
| 512 | - <span class="similarity-score">${group.bestScore}%</span> | |
| 513 | - ${viaChip} | |
| 514 | - ${chunkSummary} | |
| 373 | + <span class="similarity-score">${match.similarity_percentage}%</span> | |
| 515 | 374 | </div> |
| 516 | 375 | <span class="context-label">${contextLabel}</span> |
| 517 | 376 | </div> |
| 518 | 377 | <div class="match-source"> |
| 519 | - ${group.isUrl ? | |
| 520 | - `<span class="source-icon link-icon">🔗</span> ${group.url}` : | |
| 521 | - `<span class="source-icon doc-icon">📄</span> ${group.url}` | |
| 378 | + ${match.source_display.startsWith('http') ? | |
| 379 | + `<span class="source-icon link-icon">🔗</span> ${match.source_display}` : | |
| 380 | + `<span class="source-icon doc-icon">📄</span> ${match.source_display}` | |
| 522 | 381 | } |
| 523 | 382 | </div> |
| 524 | - ${expandToggle} | |
| 525 | - ${hasMultipleChunks ? this.renderChunkDetails(group.matchedChunks, groupIndex) : ''} | |
| 526 | 383 | </div> |
| 527 | 384 | `; |
| 528 | 385 | }); |
| 529 | - | |
| 386 | + | |
| 530 | 387 | scoresEl.innerHTML = html; |
| 531 | - | |
| 532 | - // Add click handlers for expand toggles | |
| 533 | - scoresEl.querySelectorAll('.chunk-expand-toggle').forEach(toggle => { | |
| 534 | - toggle.addEventListener('click', (e) => { | |
| 535 | - const groupId = e.target.dataset.group; | |
| 536 | - const details = scoresEl.querySelector(`.chunk-details[data-group="${groupId}"]`); | |
| 537 | - if (details) { | |
| 538 | - const isExpanded = details.classList.toggle('expanded'); | |
| 539 | - e.target.textContent = isExpanded ? '▼ Hide chunks' : '▶ Show chunks'; | |
| 540 | - } | |
| 541 | - }); | |
| 542 | - }); | |
| 543 | 388 | } |
| 544 | 389 | |
| 545 | - renderChunkDetails(chunks, groupIndex) { | |
| 546 | - // Sort chunks by chunk index | |
| 547 | - const sortedChunks = [...chunks].sort((a, b) => (a.chunkIndex || 0) - (b.chunkIndex || 0)); | |
| 548 | - | |
| 549 | - let html = `<div class="chunk-details" data-group="${groupIndex}">`; | |
| 550 | - | |
| 551 | - sortedChunks.forEach(chunk => { | |
| 552 | - const chunkNum = (chunk.chunkIndex !== null && chunk.chunkIndex !== undefined) | |
| 553 | - ? chunk.chunkIndex + 1 | |
| 554 | - : '?'; | |
| 555 | - const statusClass = chunk.usedForContext ? 'chunk-used' : 'chunk-not-used'; | |
| 556 | - const statusIcon = chunk.usedForContext ? '✓' : '○'; | |
| 557 | - | |
| 558 | - html += ` | |
| 559 | - <div class="chunk-detail-row ${statusClass}"> | |
| 560 | - <span class="chunk-detail-icon">${statusIcon}</span> | |
| 561 | - <span class="chunk-detail-num">Chunk ${chunkNum}</span> | |
| 562 | - <span class="chunk-detail-score">${chunk.score}%</span> | |
| 563 | - </div> | |
| 564 | - `; | |
| 565 | - }); | |
| 566 | - | |
| 567 | - html += '</div>'; | |
| 568 | - return html; | |
| 569 | - } | |
| 570 | - | |
| 571 | 390 | updateLastQuery(query, topMatches) { |
| 572 | 391 | const queryEl = this.panel.querySelector('#last-query'); |
| 573 | 392 | queryEl.textContent = query; |
| 574 | 393 | |
| @@ -579,49 +398,28 @@ | ||
| 579 | 398 | }; |
| 580 | 399 | } |
| 581 | 400 | |
| 582 | 401 | 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 | - | |
| 402 | + // Get current session ID from cookie (most reliable) | |
| 403 | + const sessionId = this.getCookie('mxchat_session_id') || this.getCurrentSessionId(); | |
| 404 | + | |
| 596 | 405 | if (!sessionId) { |
| 597 | - this.log('No active session found'); | |
| 406 | + this.log('❌ No active session found'); | |
| 598 | 407 | return; |
| 599 | 408 | } |
| 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 | - | |
| 409 | + | |
| 410 | + this.log(`🔍 Current session ID: ${sessionId}`); | |
| 411 | + this.log('🧹 Starting fresh session...'); | |
| 412 | + | |
| 413 | + // Generate new session ID (using your existing format) | |
| 414 | + const newSessionId = 'mxchat_chat_' + Math.random().toString(36).substr(2, 9); | |
| 415 | + | |
| 416 | + // Clear the old cookie and set new one immediately | |
| 417 | + this.clearMxChatCookie(); | |
| 418 | + this.setChatSession(newSessionId); | |
| 419 | + | |
| 420 | + this.log(`🆕 New session ID: ${newSessionId}`); | |
| 421 | + | |
| 624 | 422 | // Call backend to clear old session data |
| 625 | 423 | fetch(mxchatTestData.ajaxUrl, { |
| 626 | 424 | method: 'POST', |
| 627 | 425 | headers: { |
| @@ -636,36 +434,35 @@ | ||
| 636 | 434 | }) |
| 637 | 435 | .then(response => response.json()) |
| 638 | 436 | .then(data => { |
| 639 | 437 | if (data.success) { |
| 640 | - this.log('Backend session cleared: ' + data.data.message); | |
| 641 | - | |
| 438 | + this.log('✅ Backend session cleared: ' + data.data.message); | |
| 439 | + | |
| 642 | 440 | // Update the session ID everywhere in the DOM |
| 643 | 441 | this.updateSessionIdEverywhere(newSessionId); |
| 644 | - | |
| 442 | + | |
| 645 | 443 | // Clear the chat UI |
| 646 | 444 | this.clearChatUI(); |
| 647 | - | |
| 445 | + | |
| 648 | 446 | // Show popular questions again |
| 649 | 447 | const popularQuestions = document.querySelector('#mxchat-popular-questions'); |
| 650 | 448 | if (popularQuestions) { |
| 651 | 449 | popularQuestions.style.display = 'block'; |
| 652 | 450 | } |
| 653 | - | |
| 451 | + | |
| 654 | 452 | // Clear testing data displays |
| 655 | 453 | this.updateLastQuery('New session started', []); |
| 656 | 454 | this.updateTopMatches([], 0); |
| 657 | - this.updateApprovedUrls([]); | |
| 658 | - | |
| 659 | - this.log('Fresh session started successfully'); | |
| 660 | - | |
| 455 | + | |
| 456 | + this.log('🎉 Fresh session started successfully'); | |
| 457 | + | |
| 661 | 458 | } else { |
| 662 | - this.log('Error clearing session: ' + (data.data?.message || 'Unknown error')); | |
| 459 | + this.log('❌ Error clearing session: ' + (data.data?.message || 'Unknown error')); | |
| 663 | 460 | } |
| 664 | 461 | }) |
| 665 | 462 | .catch(error => { |
| 666 | 463 | console.error('Error clearing chat session:', error); |
| 667 | - this.log('Connection error when clearing session'); | |
| 464 | + this.log('🔌 Connection error when clearing session'); | |
| 668 | 465 | }); |
| 669 | 466 | } |
| 670 | 467 | |
| 671 | 468 | // Helper function to get cookie (same as your existing one) |
| @@ -674,21 +471,19 @@ | ||
| 674 | 471 | let parts = value.split("; " + name + "="); |
| 675 | 472 | if (parts.length == 2) return parts.pop().split(";").shift(); |
| 676 | 473 | } |
| 677 | 474 | |
| 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'; | |
| 475 | + // Helper function to set session cookie (same as your existing one) | |
| 476 | + setChatSession(sessionId) { | |
| 477 | + // Set the cookie with a 24-hour expiration (86400 seconds) | |
| 478 | + document.cookie = "mxchat_session_id=" + sessionId + "; path=/; max-age=86400; SameSite=Lax"; | |
| 682 | 479 | } |
| 683 | 480 | |
| 684 | 481 | // 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'); | |
| 482 | + clearMxChatCookie() { | |
| 483 | + // Clear the cookie by setting it to expire in the past | |
| 484 | + document.cookie = "mxchat_session_id=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax"; | |
| 485 | + this.log('🍪 Session cookie cleared'); | |
| 691 | 486 | } |
| 692 | 487 | |
| 693 | 488 | updateSessionIdEverywhere(newSessionId) { |
| 694 | 489 | // Update global session ID variable if it exists |
| @@ -747,23 +542,9 @@ | ||
| 747 | 542 | } |
| 748 | 543 | } |
| 749 | 544 | |
| 750 | 545 | 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 | - } | |
| 546 | + // First try to get from cookie (most reliable) | |
| 766 | 547 | const cookieSessionId = this.getCookie('mxchat_session_id'); |
| 767 | 548 | if (cookieSessionId) { |
| 768 | 549 | return cookieSessionId; |
| 769 | 550 | } |
| @@ -824,63 +605,36 @@ | ||
| 824 | 605 | }); |
| 825 | 606 | } |
| 826 | 607 | |
| 827 | 608 | updateSystemPrompt() { |
| 828 | - const promptEl = this.panel.querySelector('#system-prompt'); | |
| 829 | - promptEl.textContent = 'Loading system prompt...'; | |
| 830 | - | |
| 831 | - fetch(mxchatTestData.ajaxUrl, { | |
| 832 | - method: 'POST', | |
| 833 | - headers: { | |
| 834 | - 'Content-Type': 'application/x-www-form-urlencoded', | |
| 835 | - }, | |
| 836 | - body: new URLSearchParams({ | |
| 837 | - action: 'mxchat_get_system_info', | |
| 838 | - nonce: mxchatTestData.nonce | |
| 609 | + const promptEl = this.panel.querySelector('#system-prompt'); | |
| 610 | + promptEl.textContent = 'Loading system prompt...'; | |
| 611 | + | |
| 612 | + fetch(mxchatTestData.ajaxUrl, { | |
| 613 | + method: 'POST', | |
| 614 | + headers: { | |
| 615 | + 'Content-Type': 'application/x-www-form-urlencoded', | |
| 616 | + }, | |
| 617 | + body: new URLSearchParams({ | |
| 618 | + action: 'mxchat_get_system_info', | |
| 619 | + nonce: mxchatTestData.nonce | |
| 620 | + }) | |
| 839 | 621 | }) |
| 840 | - }) | |
| 841 | - .then(response => response.json()) | |
| 842 | - .then(data => { | |
| 843 | - if (data.success) { | |
| 844 | - promptEl.textContent = data.data.system_prompt || 'No system prompt configured'; | |
| 845 | - | |
| 846 | - // Enhanced model display with OpenRouter support | |
| 847 | - if (data.data.is_openrouter) { | |
| 848 | - this.log(`🤖 Model: OpenRouter`); | |
| 849 | - this.log(` └─ Using: ${data.data.openrouter_model}`); | |
| 850 | - } else { | |
| 622 | + .then(response => response.json()) | |
| 623 | + .then(data => { | |
| 624 | + if (data.success) { | |
| 625 | + promptEl.textContent = data.data.system_prompt || 'No system prompt configured'; | |
| 851 | 626 | this.log(`🤖 Model: ${data.data.selected_model}`); |
| 852 | - } | |
| 853 | - | |
| 854 | - // Enhanced API status with OpenRouter | |
| 855 | - const apiStatus = data.data.api_status; | |
| 856 | - const configuredApis = Object.keys(apiStatus).filter(key => apiStatus[key]); | |
| 857 | - | |
| 858 | - if (configuredApis.length > 0) { | |
| 859 | - this.log(`🔑 Configured APIs: ${configuredApis.map(api => { | |
| 860 | - // Capitalize and format API names | |
| 861 | - if (api === 'openai') return 'OpenAI'; | |
| 862 | - if (api === 'xai') return 'X.AI'; | |
| 863 | - if (api === 'openrouter') return 'OpenRouter'; | |
| 864 | - return api.charAt(0).toUpperCase() + api.slice(1); | |
| 865 | - }).join(', ')}`); | |
| 627 | + this.log(`🔑 API Status: ${JSON.stringify(data.data.api_status)}`); | |
| 866 | 628 | } else { |
| 867 | - this.log(`⚠️ No API keys configured`); | |
| 629 | + promptEl.textContent = 'Error loading system prompt'; | |
| 868 | 630 | } |
| 869 | - | |
| 870 | - // Specific warning for OpenRouter if selected but no key | |
| 871 | - if (data.data.is_openrouter && !apiStatus.openrouter) { | |
| 872 | - this.log(`❌ WARNING: OpenRouter selected but no API key configured!`); | |
| 873 | - } | |
| 874 | - } else { | |
| 875 | - promptEl.textContent = 'Error loading system prompt'; | |
| 876 | - } | |
| 877 | - }) | |
| 878 | - .catch(error => { | |
| 879 | - console.error('Error fetching system info:', error); | |
| 880 | - promptEl.textContent = 'Connection error'; | |
| 881 | - }); | |
| 882 | -} | |
| 631 | + }) | |
| 632 | + .catch(error => { | |
| 633 | + console.error('Error fetching system info:', error); | |
| 634 | + promptEl.textContent = 'Connection error'; | |
| 635 | + }); | |
| 636 | + } | |
| 883 | 637 | |
| 884 | 638 | updateKnowledgeBaseStatus() { |
| 885 | 639 | const statusEl = this.panel.querySelector('#kb-status'); |
| 886 | 640 | statusEl.innerHTML = 'Checking...'; |