import { defineLogicFunction } from 'twenty-sdk/define'; import { LOGIC_FUNCTION_CONSTANTS, OBJECT_UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers'; import { aiReviewContractCore } from 'src/logic-functions/handlers/ai-review-contract'; import { extractBody, extractDatabaseEventRecordId, normalizeRecordId, } from 'src/logic-functions/utils/route-input'; import { type AiReviewInput, type AiReviewOutcome } from 'src/types/logic-function-io'; const handler = (input: unknown): Promise => { // Serves two triggers: the DATABASE_EVENT (contract.updated on status) and the // HTTP route / manual exec ({ recordId } body). const recordId = extractDatabaseEventRecordId(input) ?? normalizeRecordId(extractBody(input as never)?.recordId); if (recordId === undefined) { return Promise.resolve({ success: false, recordId: '', llmConfigured: false, message: 'Missing recordId.', }); } return aiReviewContractCore({ input: { recordId } }); }; export default defineLogicFunction({ universalIdentifier: LOGIC_FUNCTION_CONSTANTS.aiReview.universalIdentifier, name: 'ai-review', description: "Reviews a Contract's attached PDF with an LLM, writes structured findings and a payment-mismatch flag, and advances status to pending manager approval.", timeoutSeconds: 120, handler, // Runs automatically whenever a Contract's status changes — the handler only // proceeds when it is PENDING_AI_REVIEW — so the review fires no matter how the // contract got there (Submit command or a manual status change). databaseEventTriggerSettings: { eventName: 'contract.updated', updatedFields: ['status'], }, httpRouteTriggerSettings: { path: LOGIC_FUNCTION_CONSTANTS.aiReview.path, httpMethod: 'POST', isAuthRequired: true, }, workflowActionTriggerSettings: { label: 'AI review contract', icon: 'IconSparkles', inputSchema: [ { type: 'object', properties: { recordId: { type: 'record', objectUniversalIdentifier: OBJECT_UNIVERSAL_IDENTIFIERS.contract, label: 'Contract', }, }, }, ], outputSchema: [ { type: 'object', properties: { success: { type: 'boolean', label: 'Success' }, recordId: { type: 'string', label: 'Record Id' }, status: { type: 'string', label: 'Status' }, paymentMismatch: { type: 'string', label: 'Payment Mismatch' }, llmConfigured: { type: 'boolean', label: 'LLM Configured' }, message: { type: 'string', label: 'Message' }, }, }, ], }, });