From b6b597fddaf13b12747a07e57e33b2200e7db24f Mon Sep 17 00:00:00 2001 From: saridsa2 Date: Mon, 13 Apr 2026 14:52:30 +0530 Subject: [PATCH] fix: clinicId on all appointment paths + startedAt on call records - AI chat book_appointment tool: accepts optional clinicId - Widget booking: passes clinicId from request - LiveKit agent: passes clinicId from doctor context if available - Dispose endpoint: sets startedAt/endedAt on outbound call records (computed from durationSec). Fixes null timestamps in call history. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/ai/ai-chat.controller.ts | 8 +++++--- src/livekit-agent/agent.ts | 1 + src/ozonetel/ozonetel-agent.controller.ts | 9 ++++++++- src/widget/widget.service.ts | 1 + src/widget/widget.types.ts | 1 + 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/ai/ai-chat.controller.ts b/src/ai/ai-chat.controller.ts index e2a9d9f..5972dd6 100644 --- a/src/ai/ai-chat.controller.ts +++ b/src/ai/ai-chat.controller.ts @@ -380,17 +380,18 @@ export class AiChatController { }), book_appointment: tool({ - description: 'Book an appointment for a patient. Collect patient name, phone, department, doctor, preferred date/time, and reason before calling this.', + description: 'Book an appointment for a patient. Collect patient name, phone, department, doctor, clinic/branch, preferred date/time, and reason before calling this.', inputSchema: z.object({ patientName: z.string().describe('Full name of the patient'), phoneNumber: z.string().describe('Patient phone number'), department: z.string().describe('Department for the appointment'), doctorName: z.string().describe('Doctor name'), + clinicId: z.string().optional().describe('Clinic/branch ID — get from lookup_doctor results'), scheduledAt: z.string().describe('Date and time in ISO format (e.g. 2026-04-01T10:00:00)'), reason: z.string().describe('Reason for visit'), }), - execute: async ({ patientName, phoneNumber, department, doctorName, scheduledAt, reason }) => { - this.logger.log(`[TOOL] book_appointment: ${patientName} | ${phoneNumber} | ${department} | ${doctorName} | ${scheduledAt}`); + execute: async ({ patientName, phoneNumber, department, doctorName, clinicId, scheduledAt, reason }) => { + this.logger.log(`[TOOL] book_appointment: ${patientName} | ${phoneNumber} | ${department} | ${doctorName} | clinic=${clinicId ?? 'none'} | ${scheduledAt}`); try { const result = await platformService.queryWithAuth( `mutation($data: AppointmentCreateInput!) { createAppointment(data: $data) { id } }`, @@ -402,6 +403,7 @@ export class AiChatController { doctorName, department, reasonForVisit: reason, + ...(clinicId ? { clinicId } : {}), }, }, auth, diff --git a/src/livekit-agent/agent.ts b/src/livekit-agent/agent.ts index d62ce5f..f357a38 100644 --- a/src/livekit-agent/agent.ts +++ b/src/livekit-agent/agent.ts @@ -128,6 +128,7 @@ const bookAppointment = llm.tool({ doctorName: doctor?.name ?? doctorName ?? 'To be assigned', department, reasonForVisit: reason, + ...((doctor as any)?.clinicId ? { clinicId: (doctor as any).clinicId } : {}), }, }, ); diff --git a/src/ozonetel/ozonetel-agent.controller.ts b/src/ozonetel/ozonetel-agent.controller.ts index 8a89bff..df443d0 100644 --- a/src/ozonetel/ozonetel-agent.controller.ts +++ b/src/ozonetel/ozonetel-agent.controller.ts @@ -147,14 +147,21 @@ export class OzonetelAgentController { // only place that creates the call record for outbound dials. if (body.direction === 'OUTBOUND' && body.callerPhone) { try { + const durationSec = body.durationSec ?? 0; + const endedAt = new Date().toISOString(); + const startedAt = durationSec > 0 + ? new Date(Date.now() - durationSec * 1000).toISOString() + : endedAt; const callData: Record = { name: `Outbound — ${body.callerPhone}`, direction: 'OUTBOUND', callStatus: 'COMPLETED', callerNumber: { primaryPhoneNumber: `+91${body.callerPhone.replace(/^\+?91/, '')}` }, agentName: agentId, - durationSec: body.durationSec ?? 0, + durationSec, disposition: body.disposition, + startedAt, + endedAt, }; if (body.leadId) callData.leadId = body.leadId; diff --git a/src/widget/widget.service.ts b/src/widget/widget.service.ts index 53434ad..b3c79a2 100644 --- a/src/widget/widget.service.ts +++ b/src/widget/widget.service.ts @@ -204,6 +204,7 @@ export class WidgetService { department: req.departmentId, reasonForVisit: req.chiefComplaint ?? '', patientId, + ...(req.clinicId ? { clinicId: req.clinicId } : {}), } }, this.auth, ); diff --git a/src/widget/widget.types.ts b/src/widget/widget.types.ts index 602ee90..5d3b364 100644 --- a/src/widget/widget.types.ts +++ b/src/widget/widget.types.ts @@ -15,6 +15,7 @@ export type WidgetInitResponse = { export type WidgetBookRequest = { departmentId: string; doctorId: string; + clinicId?: string; scheduledAt: string; patientName: string; patientPhone: string;