mirror of
https://github.com/FranP-code/inbox-negotiator.git
synced 2025-10-13 00:42:26 +00:00
feat: Enhance conversation history retrieval and logging for negotiation responses
This commit is contained in:
@@ -70,8 +70,33 @@ interface EmailResponseData {
|
|||||||
messageId?: string;
|
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
|
// AI-powered response analysis
|
||||||
async function analyzeEmailResponse(
|
async function analyzeEmailResponse(
|
||||||
|
supabaseClient: any,
|
||||||
debtId: string,
|
debtId: string,
|
||||||
fromEmail: string,
|
fromEmail: string,
|
||||||
subject: string,
|
subject: string,
|
||||||
@@ -91,12 +116,19 @@ async function analyzeEmailResponse(
|
|||||||
bodyLength: body.length,
|
bodyLength: body.length,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Get full conversation history for better context
|
||||||
|
const conversationHistory = await getConversationHistory(
|
||||||
|
supabaseClient,
|
||||||
|
debtId,
|
||||||
|
);
|
||||||
|
|
||||||
console.log({
|
console.log({
|
||||||
debtId,
|
debtId,
|
||||||
fromEmail,
|
fromEmail,
|
||||||
subject,
|
subject,
|
||||||
body,
|
body,
|
||||||
originalNegotiation,
|
originalNegotiation,
|
||||||
|
conversationHistoryLength: conversationHistory.length,
|
||||||
});
|
});
|
||||||
|
|
||||||
const system =
|
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.
|
- "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.
|
- "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 =
|
const prompt =
|
||||||
`Analyze the following email and extract the financial details and intent, populating the JSON object according to your system instructions.
|
`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}
|
From: ${fromEmail}
|
||||||
Subject: ${subject}
|
Subject: ${subject}
|
||||||
Body: ${body}
|
Body: ${body}
|
||||||
|
|
||||||
|
${conversationContext}
|
||||||
|
|
||||||
${
|
${
|
||||||
originalNegotiation
|
originalNegotiation
|
||||||
? `--- ORIGINAL CONTEXT FOR YOUR ANALYSIS ---
|
? `--- MOST RECENT NEGOTIATION CONTEXT ---
|
||||||
Our Negotiation Strategy: ${originalNegotiation.strategy}
|
Our Negotiation Strategy: ${originalNegotiation.strategy}
|
||||||
Our Proposed Amount: $${originalNegotiation.proposedAmount || "N/A"}
|
Our Proposed Amount: $${originalNegotiation.proposedAmount || "N/A"}
|
||||||
Our Proposed Terms: ${originalNegotiation.terms || "N/A"}
|
Our Proposed Terms: ${originalNegotiation.terms || "N/A"}
|
||||||
@@ -499,6 +572,7 @@ serve(async (req) => {
|
|||||||
|
|
||||||
// Analyze the response using AI
|
// Analyze the response using AI
|
||||||
const analysis = await analyzeEmailResponse(
|
const analysis = await analyzeEmailResponse(
|
||||||
|
supabaseClient,
|
||||||
debtId,
|
debtId,
|
||||||
fromEmail,
|
fromEmail,
|
||||||
subject,
|
subject,
|
||||||
@@ -554,8 +628,13 @@ serve(async (req) => {
|
|||||||
case "counter_offer":
|
case "counter_offer":
|
||||||
newStatus = "counter_negotiating";
|
newStatus = "counter_negotiating";
|
||||||
newNegotiationRound += 1;
|
newNegotiationRound += 1;
|
||||||
|
// More conservative auto-response logic for counter-offers
|
||||||
shouldAutoRespond = !analysis.requiresUserReview &&
|
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;
|
nextAction = analysis.suggestedNextAction;
|
||||||
break;
|
break;
|
||||||
case "request_info":
|
case "request_info":
|
||||||
@@ -678,10 +757,23 @@ serve(async (req) => {
|
|||||||
analysisConfidence: analysis.confidence,
|
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-response is recommended and confidence is high, trigger negotiation
|
||||||
if (
|
if (
|
||||||
|
AUTO_RESPONSES_ENABLED &&
|
||||||
shouldAutoRespond && analysis.confidence > 0.8 &&
|
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 {
|
try {
|
||||||
const negotiateUrl = `${
|
const negotiateUrl = `${
|
||||||
|
|||||||
@@ -544,20 +544,26 @@ async function processNegotiation(
|
|||||||
counterOfferContext,
|
counterOfferContext,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create conversation message for the AI-generated response
|
// Create conversation message only for auto-responses (counter-offers)
|
||||||
const messageType = counterOfferContext
|
// Regular negotiation generation doesn't create messages since they're not sent yet
|
||||||
? "counter_offer"
|
if (counterOfferContext) {
|
||||||
: "negotiation_sent";
|
await client.from("conversation_messages").insert({
|
||||||
await client.from("conversation_messages").insert({
|
debt_id: record.id,
|
||||||
debt_id: record.id,
|
message_type: "counter_offer",
|
||||||
message_type: messageType,
|
direction: "outbound",
|
||||||
direction: "outbound",
|
subject: emailResult.subject,
|
||||||
subject: emailResult.subject,
|
body: emailResult.body,
|
||||||
body: emailResult.body,
|
from_email: record.metadata?.toEmail || "user@example.com",
|
||||||
from_email: record.metadata?.toEmail || "user@example.com",
|
to_email: record.metadata?.fromEmail || record.vendor,
|
||||||
to_email: record.metadata?.fromEmail || record.vendor,
|
message_id: `auto-counter-${Date.now()}`,
|
||||||
message_id: `ai-generated-${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
|
// Update debt record with AI-generated content - using provided client
|
||||||
const { error: updateError } = await client
|
const { error: updateError } = await client
|
||||||
|
|||||||
@@ -403,13 +403,13 @@ Deno.serve(async (req) => {
|
|||||||
console.error("Error updating debt status:", updateError);
|
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({
|
await supabaseClient.from("conversation_messages").insert({
|
||||||
debt_id: debtId,
|
debt_id: debtId,
|
||||||
message_type: "negotiation_sent",
|
message_type: "negotiation_sent",
|
||||||
direction: "outbound",
|
direction: "outbound",
|
||||||
subject: subject,
|
subject: processedSubject, // Use processed subject with variables replaced
|
||||||
body: body,
|
body: processedBody, // Use processed body with variables replaced
|
||||||
from_email: fromEmail,
|
from_email: fromEmail,
|
||||||
to_email: toEmail,
|
to_email: toEmail,
|
||||||
message_id: emailResult.MessageID,
|
message_id: emailResult.MessageID,
|
||||||
|
|||||||
Reference in New Issue
Block a user