diff --git a/crates/openplotva-dialog/src/leak_guard.rs b/crates/openplotva-dialog/src/leak_guard.rs index 6457bd22..f512c85b 100644 --- a/crates/openplotva-dialog/src/leak_guard.rs +++ b/crates/openplotva-dialog/src/leak_guard.rs @@ -213,7 +213,9 @@ impl ReplyLeakGuard { .history .iter() .filter(|entry| entry.shingles.iter().any(|s| reply_shingles.contains(s))) - .count(); + .filter_map(|entry| entry.exact) + .collect::>() + .len(); echoed >= MIN_ECHOED_HISTORY_ENTRIES } @@ -660,6 +662,36 @@ mod tests { ); } + #[test] + fn repeated_history_entry_does_not_make_one_quote_a_transcript_dump() { + let source = "Our team decided to move the weekly meeting from Tuesday to Thursday morning"; + let guard = ReplyLeakGuard::builder() + .history_entry("Ada", source) + .history_entry("Ada", source) + .history_entry("Ben", &source.to_uppercase()) + .build(); + assert_eq!( + guard.detect("The phrase ‘move the weekly meeting from Tuesday to Thursday morning’ describes a schedule change."), + None + ); + assert_eq!(guard.detect(source), Some(DialogLeak::Transcript)); + assert_eq!( + guard.detect("Ada: agreed\nBen: agreed"), + Some(DialogLeak::Transcript) + ); + let guard = ReplyLeakGuard::builder() + .history_entry("Ada", source) + .history_entry( + "Ben", + "The meeting room on the second floor is unavailable during the renovation", + ) + .build(); + assert_eq!( + guard.detect("move the weekly meeting from Tuesday to Thursday morning\nThe meeting room on the second floor is unavailable"), + Some(DialogLeak::Transcript) + ); + } + #[test] fn transcript_echo_is_transcript_leak() { let guard = guard(); diff --git a/crates/openplotva-llm/src/aifarm.rs b/crates/openplotva-llm/src/aifarm.rs index 67d55be8..726812c8 100644 --- a/crates/openplotva-llm/src/aifarm.rs +++ b/crates/openplotva-llm/src/aifarm.rs @@ -8255,6 +8255,41 @@ mod tests { ); } + #[test] + fn reply_leak_guard_allows_one_quote_from_the_current_history_message() { + let mut input = base_input(); + input.message.id = 11; + input.message.text = + "Our team decided to move the weekly meeting from Tuesday to Thursday morning".into(); + input.history.push(HistoryMessage { + role: ROLE_USER.into(), + kind: MESSAGE_KIND_TEXT.into(), + name: input.user.full_name.clone(), + text: input.message.text.clone(), + message_id: input.message.id, + ..Default::default() + }); + let messages = + build_initial_messages_with_tool_prompt(&input, &input.history, ToolPromptMode::Native) + .expect("messages"); + let guard = reply_leak_guard(&messages, &input); + let answer = "‘move the weekly meeting from Tuesday to Thursday morning’ describes a schedule change."; + let completion = |content: &str| json!({"choices":[{"message":{"content":content}}]}); + assert_eq!( + extract_final_answer_for_provider(&completion(answer), PROVIDER_AIFARM, &guard) + .expect("a quote is allowed"), + answer + ); + assert!( + extract_final_answer_for_provider( + &completion(&input.message.text), + PROVIDER_AIFARM, + &guard + ) + .is_err() + ); + } + #[test] fn reply_leak_guard_rejects_prompt_and_transcript_copies() { let mut input = base_input();