const SYSTEM_PREFIX = `You are an email-classification assistant. Read the email below and the classification criterion provided by the user. `; const DEFAULT_CUSTOM_SYSTEM_PROMPT = "Determine whether the email satisfies the user's criterion."; const SYSTEM_SUFFIX = ` Return ONLY a JSON object on a single line of the form: {"match": true, "reason": ""} - if the email satisfies the criterion {"match": false, "reason": ""} - otherwise Do not add any other keys, text, or formatting.`; function extractLastJsonObject(text) { let last = null; let start = -1; let depth = 0; let inString = false; let escape = false; for (let i = 0; i < text.length; i += 1) { const ch = text[i]; if (inString) { if (escape) { escape = false; continue; } if (ch === "\\") { escape = true; continue; } if (ch === "\"") { inString = false; } continue; } if (ch === "\"") { inString = true; continue; } if (ch === "{") { if (depth === 0) { start = i; } depth += 1; continue; } if (ch === "}" && depth > 0) { depth -= 1; if (depth === 0 && start !== -1) { last = text.slice(start, i + 1); start = -1; } } } return last; } export const path = '/v1/chat/completions'; export function buildRequest(text, criterion, config) { const payload = { messages: [ { role: 'system', content: SYSTEM_PREFIX + (config.customSystemPrompt || DEFAULT_CUSTOM_SYSTEM_PROMPT) + SYSTEM_SUFFIX }, { role: 'user', content: `**Email Contents**\n\`\`\`\n${text}\n\`\`\`\nClassification Criterion: ${criterion}` } ], ...config.aiParams }; if (config.model) payload.model = config.model; return payload; } export function parseResponse(result) { const content = result?.choices?.[0]?.message?.content; if (typeof content !== 'string') throw new Error('Chat response missing text content.'); const candidate = extractLastJsonObject(content); if (!candidate) throw new Error('No JSON object found in AI response.'); const obj = JSON.parse(candidate); const matched = Object.hasOwn(obj, 'match') ? obj.match : obj.matched; if (typeof matched !== 'boolean') throw new Error('AI response missing valid match boolean.'); const reason = obj.reason ?? obj.reasoning ?? obj.explaination; return { matched, reason: typeof reason === 'string' ? reason : null, probability: null }; }