* Produces a human-readable explanation of why no stored conversation matched * a given request. For each stored conversation it reports the first reason * matching failed, mirroring the logic in findAssistantIndexAfterPrefix.
( requestMessages: NormalizedMessage[], rawMessages: unknown[], storedData: NormalizedData | undefined, )
| 525 | * matching failed, mirroring the logic in {@link findAssistantIndexAfterPrefix}. |
| 526 | */ |
| 527 | function diagnoseMatchFailure( |
| 528 | requestMessages: NormalizedMessage[], |
| 529 | rawMessages: unknown[], |
| 530 | storedData: NormalizedData | undefined, |
| 531 | ): string { |
| 532 | const lines: string[] = []; |
| 533 | lines.push( |
| 534 | `Request has ${requestMessages.length} normalized messages (${rawMessages.length} raw).`, |
| 535 | ); |
| 536 | |
| 537 | if (!storedData || storedData.conversations.length === 0) { |
| 538 | lines.push("No stored conversations to match against."); |
| 539 | return lines.join("\n"); |
| 540 | } |
| 541 | |
| 542 | for (let c = 0; c < storedData.conversations.length; c++) { |
| 543 | const saved = storedData.conversations[c].messages; |
| 544 | |
| 545 | // Same check as findAssistantIndexAfterPrefix: request must be a strict prefix |
| 546 | if (requestMessages.length >= saved.length) { |
| 547 | lines.push( |
| 548 | `Conversation ${c} (${saved.length} messages): ` + |
| 549 | `skipped — request has ${requestMessages.length} messages, need fewer than ${saved.length}.`, |
| 550 | ); |
| 551 | continue; |
| 552 | } |
| 553 | |
| 554 | // Find the first message that doesn't match |
| 555 | let mismatchIndex = -1; |
| 556 | for (let i = 0; i < requestMessages.length; i++) { |
| 557 | if (JSON.stringify(requestMessages[i]) !== JSON.stringify(saved[i])) { |
| 558 | mismatchIndex = i; |
| 559 | break; |
| 560 | } |
| 561 | } |
| 562 | |
| 563 | if (mismatchIndex >= 0) { |
| 564 | const raw = |
| 565 | mismatchIndex < rawMessages.length |
| 566 | ? JSON.stringify(rawMessages[mismatchIndex]).slice(0, 300) |
| 567 | : "(no raw message)"; |
| 568 | lines.push( |
| 569 | `Conversation ${c} (${saved.length} messages): mismatch at message ${mismatchIndex}:`, |
| 570 | ` request: ${JSON.stringify(requestMessages[mismatchIndex]).slice(0, 200)}`, |
| 571 | ` saved: ${JSON.stringify(saved[mismatchIndex]).slice(0, 200)}`, |
| 572 | ` raw (pre-normalization): ${raw}`, |
| 573 | ); |
| 574 | } else { |
| 575 | // Prefix matched, but the next saved message isn't an assistant turn |
| 576 | const nextRole = |
| 577 | saved[requestMessages.length]?.role ?? "(end of conversation)"; |
| 578 | lines.push( |
| 579 | `Conversation ${c} (${saved.length} messages): ` + |
| 580 | `prefix matched, but next saved message is "${nextRole}" (need "assistant").`, |
| 581 | ); |
| 582 | } |
| 583 | } |
| 584 |
no test coverage detected
searching dependent graphs…