Harden conversation replies and prioritize newest candidates
This commit is contained in:
1 parent
f98c5c732d
commit
b8e4a1bb88
23 files changed
+598
-113
No files matched your search
@@ -1,5 +1,6 @@
|
||||
import { createHash } from 'node:crypto';
|
||||
import { isSafeOutboundMessage } from './outbound-message-safety.js';
|
||||
import { containsMediaRequest, detectConversationBoundaries } from './conversation-boundaries.js';
|
||||
|
||||
export interface ConversationMessage {
|
||||
sender: string;
|
||||
@@ -38,7 +39,7 @@ export interface ConversationState {
|
||||
|
||||
export const LEGACY_AUTOMATED_CONVERSATION_TURNS = 3;
|
||||
export const DEFAULT_HYBRID_RAPPORT_TURNS = 3;
|
||||
export const CONVERSATION_POLICY_VERSION = 2;
|
||||
export const CONVERSATION_POLICY_VERSION = 3;
|
||||
export type ConversationPolicyMode = 'legacy' | 'r4r' | 'r4r-media' | 'manual';
|
||||
export type HybridConversationPhase = 'rapport' | 'media-ask' | 'post-media-ask';
|
||||
|
||||
@@ -103,11 +104,6 @@ export function buildConversationState(messages: ConversationMessage[]): Convers
|
||||
.filter((message) => !message.isSelf)
|
||||
.map((message) => message.text)
|
||||
.join('\n');
|
||||
const ownText = messages
|
||||
.filter((message) => message.isSelf)
|
||||
.map((message) => message.text)
|
||||
.join('\n');
|
||||
|
||||
const ageMatch = firstSelfMessage.match(/\b(3[0-5])\s*[mM]\b/);
|
||||
const persona: ConversationPersona = {
|
||||
age: ageMatch ? Number(ageMatch[1]) : EMPTY_PERSONA.age,
|
||||
@@ -115,20 +111,14 @@ export function buildConversationState(messages: ConversationMessage[]): Convers
|
||||
relationshipStatus: /\bmarried\b|\bwife\b/i.test(firstSelfMessage) ? 'married' : EMPTY_PERSONA.relationshipStatus,
|
||||
};
|
||||
|
||||
const boundaries: string[] = [];
|
||||
if (/\b(no|not)\b[^.\n]{0,50}\b(pic|pics|photo|photos|selfie|selfies|video|videos|nudes?)\b|\bdon't send\b[^.\n]{0,30}\b(pic|photo|video|nudes?)\b/i.test(theirText)) {
|
||||
boundaries.push('does not want to send photos or videos');
|
||||
}
|
||||
if (/\bstop\b|\bleave me alone\b|\bnot interested\b/i.test(theirText)) {
|
||||
boundaries.push('does not want further sexual escalation');
|
||||
}
|
||||
const boundaries = detectConversationBoundaries(messages);
|
||||
|
||||
const topics = extractTopics(theirText);
|
||||
return {
|
||||
persona,
|
||||
boundaries,
|
||||
sellerDetected: false,
|
||||
askedForMedia: /\b(send|show|share)\b[^.\n]{0,40}\b(pic|pics|photo|photos|selfie|selfies|video|videos|nudes?)\b/i.test(ownText),
|
||||
askedForMedia: messages.some((message) => message.isSelf && containsMediaRequest(message.text)),
|
||||
topics,
|
||||
automation: createConversationAutomationState(),
|
||||
};
|
||||
@@ -214,14 +204,13 @@ export function isSafeConversationReply(message: string): boolean {
|
||||
/** R4R automation may converse and flirt, but it must never solicit sexual media. */
|
||||
export function isSafeR4RReply(message: string): boolean {
|
||||
if (!isSafeConversationReply(message)) return false;
|
||||
return !/\b(send|show|share|swap|trade|drop|give|dm)\b[^.!?\n]{0,60}\b(pic|pics|photo|photos|selfie|selfies|video|videos|nude|nudes|content)\b/i.test(message)
|
||||
&& !/\b(can|could|would|will) you\b[^.!?\n]{0,60}\b(pic|pics|photo|photos|selfie|selfies|video|videos|nude|nudes)\b/i.test(message);
|
||||
return !containsMediaRequest(message);
|
||||
}
|
||||
|
||||
/** The hybrid policy gets one optional, non-explicit image request after rapport. */
|
||||
export function isSafeHybridMediaAsk(message: string): boolean {
|
||||
if (!isSafeConversationReply(message)) return false;
|
||||
if (!/\b(pic|pics|photo|photos|selfie|selfies|video|videos)\b/i.test(message)) return false;
|
||||
if (!containsMediaRequest(message)) return false;
|
||||
if (/\b(nude|nudes|naked|explicit|nsfw|sexy pic|sexual)\b/i.test(message)) return false;
|
||||
return !/\b(must|prove|dare|owe|have to|need to)\b/i.test(message);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user