Files
RedditBot/src/services/conversation-outcome-recorder.ts
T

54 lines
2.2 KiB
TypeScript

import type {
ConversationOutcomesRepository,
MessagesRepository,
SentMessageRecord,
SuccessfulMessagesRepository,
} from '../database/repositories.js';
import type { Logger } from '../utils/logger.js';
import { classifyConversationOutcome, type OutcomeContext, type ConversationOutcome } from './conversation-outcome.js';
export interface ConversationOutcomeDependencies {
messages: MessagesRepository;
successful: SuccessfulMessagesRepository;
outcomes: ConversationOutcomesRepository;
logger: Logger;
}
/** Canonical reply/outcome path shared by inbox and Matrix ingestion. */
export function recordConversationReply(
message: SentMessageRecord,
responseSnippet: string,
context: OutcomeContext,
deps: ConversationOutcomeDependencies,
): ConversationOutcome {
const outcome = classifyConversationOutcome(responseSnippet, context);
deps.messages.markGotResponse(message.id);
deps.outcomes.record(message.id, outcome, responseSnippet || null);
if (outcome === 'boundary') {
deps.outcomes.suppressRecipient(message.recipient, 'boundary');
}
const terminalNegative = outcome === 'boundary' || outcome === 'declined' || outcome === 'upsell';
if (terminalNegative || (context.authoritativeTranscript && (outcome !== 'engaged' || !context.learningEligible))) {
deps.successful.deleteBySentMessageId(message.id);
}
if (outcome === 'engaged' && context.learningEligible && !deps.successful.existsByMessage(message.message)) {
deps.successful.insert({
sentMessageId: message.id,
originalMessage: message.message,
imageAnalysis: message.postImageAnalysis ?? null,
postTitle: message.postTitle ?? null,
responseSnippet: responseSnippet || null,
subreddit: message.subreddit ?? null,
});
deps.logger.info(`Engaged response from u/${message.recipient}; stored for learning.`);
} else if (outcome !== 'engaged') {
deps.logger.info(`Response from u/${message.recipient} classified as ${outcome}; excluded from learning examples.`);
} else if (!context.learningEligible) {
deps.logger.info(`Response from u/${message.recipient} is not terminal; deferred from learning examples.`);
}
return outcome;
}