feat: Enhance conversation history retrieval and logging for negotiation responses

This commit is contained in:
2025-06-08 02:39:53 -03:00
parent 311ddbe5bd
commit 304b08f6bc
3 changed files with 120 additions and 22 deletions

View File

@@ -70,8 +70,33 @@ interface EmailResponseData {
messageId?: string;
}
// Retrieve full conversation history for context
async function getConversationHistory(
supabaseClient: any,
debtId: string,
) {
try {
const { data: messages, error } = await supabaseClient
.from("conversation_messages")
.select("*")
.eq("debt_id", debtId)
.order("created_at", { ascending: true });
if (error) {
console.error("Error fetching conversation history:", error);
return [];
}
return messages || [];
} catch (error) {
console.error("Error in getConversationHistory:", error);
return [];
}
}
// AI-powered response analysis
async function analyzeEmailResponse(
supabaseClient: any,
debtId: string,
fromEmail: string,
subject: string,
@@ -91,12 +116,19 @@ async function analyzeEmailResponse(
bodyLength: body.length,
});
// Get full conversation history for better context
const conversationHistory = await getConversationHistory(
supabaseClient,
debtId,
);
console.log({
debtId,
fromEmail,
subject,
body,
originalNegotiation,
conversationHistoryLength: conversationHistory.length,
});
const system =
@@ -141,19 +173,60 @@ Your entire output MUST be a single, valid JSON object. Do not include any markd
- "escalate_to_user": The response is hostile, contains legal threats, is complex, or requires a human decision.
- "mark_settled": The email confirms the debt is fully settled and no further action is needed.
7. **requiresUserReview**: Set to 'true' if intent is "unclear", sentiment is "negative", confidence is below 0.85, the email contains unusual legal language, or the "suggestedNextAction" is "escalate_to_user". Otherwise, set to 'false'.`;
7. **requiresUserReview**: Set to 'true' if intent is "unclear", sentiment is "negative", confidence is below 0.85, the email contains unusual legal language, the "suggestedNextAction" is "escalate_to_user", OR if the message is vague/lacks specific financial terms (e.g., "think of a better offer", "we need more", etc.). Only set to 'false' for clear, specific counter-offers with concrete terms.`;
// Build conversation history context
// const conversationContext = conversationHistory.length > 0
// ? `--- FULL CONVERSATION HISTORY ---
// ${
// conversationHistory.map((msg, index) =>
// `${
// index + 1
// }. ${msg.direction.toUpperCase()} - ${msg.message_type} (${
// new Date(msg.created_at).toLocaleDateString()
// })
// Subject: ${msg.subject || "N/A"}
// Body: ${msg.body.substring(0, 500)}${msg.body.length > 500 ? "..." : ""}
// ${msg.ai_analysis ? `AI Analysis: ${JSON.stringify(msg.ai_analysis)}` : ""}
// ---`
// ).join("\n")
// }
// `
// : "";
const conversationContext = conversationHistory.length > 0
? `--- FULL CONVERSATION HISTORY ---
${
conversationHistory.map((msg, index) =>
`${
index + 1
}. ${msg.direction.toUpperCase()} - ${msg.message_type} (${
new Date(msg.created_at).toLocaleDateString()
})
Subject: ${msg.subject || "N/A"}
Body: ${msg.body}
${msg.ai_analysis ? `AI Analysis: ${JSON.stringify(msg.ai_analysis)}` : ""}
---`
).join("\n")
}
`
: "";
const prompt =
`Analyze the following email and extract the financial details and intent, populating the JSON object according to your system instructions.
--- EMAIL TO ANALYZE ---
--- CURRENT EMAIL TO ANALYZE ---
From: ${fromEmail}
Subject: ${subject}
Body: ${body}
${conversationContext}
${
originalNegotiation
? `--- ORIGINAL CONTEXT FOR YOUR ANALYSIS ---
? `--- MOST RECENT NEGOTIATION CONTEXT ---
Our Negotiation Strategy: ${originalNegotiation.strategy}
Our Proposed Amount: $${originalNegotiation.proposedAmount || "N/A"}
Our Proposed Terms: ${originalNegotiation.terms || "N/A"}
@@ -499,6 +572,7 @@ serve(async (req) => {
// Analyze the response using AI
const analysis = await analyzeEmailResponse(
supabaseClient,
debtId,
fromEmail,
subject,
@@ -554,8 +628,13 @@ serve(async (req) => {
case "counter_offer":
newStatus = "counter_negotiating";
newNegotiationRound += 1;
// More conservative auto-response logic for counter-offers
shouldAutoRespond = !analysis.requiresUserReview &&
analysis.confidence > 0.8;
analysis.confidence > 0.9 && // Increased confidence threshold
analysis.extractedTerms && // Must have specific terms
(analysis.extractedTerms.proposedAmount ||
analysis.extractedTerms.paymentTerms) && // Must have concrete financial terms
body.length > 20; // Must be more than a vague message
nextAction = analysis.suggestedNextAction;
break;
case "request_info":
@@ -678,10 +757,23 @@ serve(async (req) => {
analysisConfidence: analysis.confidence,
});
// TEMPORARILY DISABLED: Auto-responses need more testing
// TODO: Re-enable after thorough testing and user preference settings
const AUTO_RESPONSES_ENABLED = true;
const conversationHistory = await getConversationHistory(
supabaseClient,
debtId,
);
console.log({
conversationHistoryLength: conversationHistory.length,
});
// If auto-response is recommended and confidence is high, trigger negotiation
if (
AUTO_RESPONSES_ENABLED &&
shouldAutoRespond && analysis.confidence > 0.8 &&
analysis.intent === "counter_offer"
analysis.intent === "counter_offer" &&
// the length of the conversation isn't bigger than 2 messages
conversationHistory.length <= 2
) {
try {
const negotiateUrl = `${

View File

@@ -544,20 +544,26 @@ async function processNegotiation(
counterOfferContext,
);
// Create conversation message for the AI-generated response
const messageType = counterOfferContext
? "counter_offer"
: "negotiation_sent";
await client.from("conversation_messages").insert({
debt_id: record.id,
message_type: messageType,
direction: "outbound",
subject: emailResult.subject,
body: emailResult.body,
from_email: record.metadata?.toEmail || "user@example.com",
to_email: record.metadata?.fromEmail || record.vendor,
message_id: `ai-generated-${Date.now()}`,
});
// Create conversation message only for auto-responses (counter-offers)
// Regular negotiation generation doesn't create messages since they're not sent yet
if (counterOfferContext) {
await client.from("conversation_messages").insert({
debt_id: record.id,
message_type: "counter_offer",
direction: "outbound",
subject: emailResult.subject,
body: emailResult.body,
from_email: record.metadata?.toEmail || "user@example.com",
to_email: record.metadata?.fromEmail || record.vendor,
message_id: `auto-counter-${Date.now()}`,
ai_analysis: {
strategy: emailResult.strategy,
confidence: emailResult.confidenceLevel,
projectedSavings: emailResult.projectedSavings,
isAutoGenerated: true,
},
});
}
// Update debt record with AI-generated content - using provided client
const { error: updateError } = await client

View File

@@ -403,13 +403,13 @@ Deno.serve(async (req) => {
console.error("Error updating debt status:", updateError);
}
// Record the sent email in conversation history
// Record the sent email in conversation history with processed content
await supabaseClient.from("conversation_messages").insert({
debt_id: debtId,
message_type: "negotiation_sent",
direction: "outbound",
subject: subject,
body: body,
subject: processedSubject, // Use processed subject with variables replaced
body: processedBody, // Use processed body with variables replaced
from_email: fromEmail,
to_email: toEmail,
message_id: emailResult.MessageID,