const CONFIG = { TRIAGE_API_URL: 'https://REPLACE_WITH_CLOUD_RUN_URL/api/triage', TRIAGE_API_KEY: 'REPLACE_WITH_TRIAGE_API_KEY', AUTO_SEND: false, MAX_THREADS_PER_RUN: 10, TRIAGED_LABEL: 'AI/Triaged', NEEDS_REVIEW_LABEL: 'AI/Needs-Review' }; function triageInboxAndReply() { const triagedLabel = getOrCreateLabel_(CONFIG.TRIAGED_LABEL); const reviewLabel = getOrCreateLabel_(CONFIG.NEEDS_REVIEW_LABEL); const query = 'in:inbox is:unread -label:"' + CONFIG.TRIAGED_LABEL + '"'; const threads = GmailApp.search(query, 0, CONFIG.MAX_THREADS_PER_RUN); for (const thread of threads) { try { const messages = thread.getMessages(); const message = messages[messages.length - 1]; const payload = { subject: message.getSubject() || '', sender: message.getFrom() || '', body: message.getPlainBody() || '' }; const triage = callTriageApi_(payload); const hasReplyAction = (triage.suggested_actions || []).indexOf('reply') !== -1; if (hasReplyAction && triage.suggested_reply) { if (CONFIG.AUTO_SEND) { message.reply(triage.suggested_reply); } else { message.createDraftReply(triage.suggested_reply); reviewLabel.addToThread(thread); } } applyActionLabels_(thread, triage.suggested_actions || []); triagedLabel.addToThread(thread); message.markRead(); } catch (error) { reviewLabel.addToThread(thread); Logger.log('Triage failed for thread ' + thread.getId() + ': ' + error); } } } function callTriageApi_(payload) { const response = UrlFetchApp.fetch(CONFIG.TRIAGE_API_URL, { method: 'post', contentType: 'application/json', headers: { 'x-api-key': CONFIG.TRIAGE_API_KEY }, payload: JSON.stringify(payload), muteHttpExceptions: true }); const code = response.getResponseCode(); if (code < 200 || code >= 300) { throw new Error('Triage API HTTP ' + code + ': ' + response.getContentText()); } return JSON.parse(response.getContentText()); } function applyActionLabels_(thread, actions) { const actionToLabel = { forward_to_it_sec: 'AI/Security', create_task: 'AI/Follow-Up', label_feedback: 'AI/Feedback', label_general: 'AI/General', move_to_junk: 'AI/Phishing', flag: 'AI/Important' }; for (const action of actions) { if (actionToLabel[action]) { getOrCreateLabel_(actionToLabel[action]).addToThread(thread); } } } function getOrCreateLabel_(name) { return GmailApp.getUserLabelByName(name) || GmailApp.createLabel(name); } function installTriageTrigger() { ScriptApp.getProjectTriggers().forEach(trigger => { if (trigger.getHandlerFunction() === 'triageInboxAndReply') { ScriptApp.deleteTrigger(trigger); } }); ScriptApp.newTrigger('triageInboxAndReply') .timeBased() .everyMinutes(5) .create(); }