feat: enhance new-patient AI chat flow with full scheduling and eligibility

- Add 3-message intro (self-intro → empathetic ack → new/existing question) via single TwiML response to guarantee delivery order
- Detect reschedule intent from first message; look up existing appointment date
- New patient flow: ask insurance type → MassHealth consent → member ID + DOB → Selenium eligibility check
- Post-eligibility: active → ask appointment date/time with office-hours validation; inactive → ask other insurance or collect contact info
- Date/time collection mirrors reschedule flow: check office day open, ask time, validate against office hours
- Auto-create appointment in schedule for known patients on confirmation; use first available staff member
- Add openPhoneReply toggle (Settings → AI Chat) to respond to any number at any time
- Add 5-minute inactivity timeout: reset conversation to initial stage and clear pending state
- Normalize MassHealth DOB to zero-padded MM/DD/YYYY before Selenium submission
- Expand isExistingPatient classifier to recognize "old patient", "old", "previous", "prior"
- Existing patient confirmation message now acknowledges patient type before asking about insurance

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gitead
2026-05-15 00:00:56 -04:00
parent c1f55778ca
commit c71624f7e7
53 changed files with 1078 additions and 124 deletions

File diff suppressed because one or more lines are too long

View File

@@ -423,7 +423,8 @@ exports.Prisma.AiSettingsScalarFieldEnum = {
id: 'id',
userId: 'userId',
apiKey: 'apiKey',
afterHoursEnabled: 'afterHoursEnabled'
afterHoursEnabled: 'afterHoursEnabled',
openPhoneReply: 'openPhoneReply'
};
exports.Prisma.OfficeHoursScalarFieldEnum = {

View File

@@ -34731,6 +34731,7 @@ export namespace Prisma {
userId: number | null
apiKey: string | null
afterHoursEnabled: boolean | null
openPhoneReply: boolean | null
}
export type AiSettingsMaxAggregateOutputType = {
@@ -34738,6 +34739,7 @@ export namespace Prisma {
userId: number | null
apiKey: string | null
afterHoursEnabled: boolean | null
openPhoneReply: boolean | null
}
export type AiSettingsCountAggregateOutputType = {
@@ -34745,6 +34747,7 @@ export namespace Prisma {
userId: number
apiKey: number
afterHoursEnabled: number
openPhoneReply: number
_all: number
}
@@ -34764,6 +34767,7 @@ export namespace Prisma {
userId?: true
apiKey?: true
afterHoursEnabled?: true
openPhoneReply?: true
}
export type AiSettingsMaxAggregateInputType = {
@@ -34771,6 +34775,7 @@ export namespace Prisma {
userId?: true
apiKey?: true
afterHoursEnabled?: true
openPhoneReply?: true
}
export type AiSettingsCountAggregateInputType = {
@@ -34778,6 +34783,7 @@ export namespace Prisma {
userId?: true
apiKey?: true
afterHoursEnabled?: true
openPhoneReply?: true
_all?: true
}
@@ -34872,6 +34878,7 @@ export namespace Prisma {
userId: number
apiKey: string
afterHoursEnabled: boolean
openPhoneReply: boolean
_count: AiSettingsCountAggregateOutputType | null
_avg: AiSettingsAvgAggregateOutputType | null
_sum: AiSettingsSumAggregateOutputType | null
@@ -34898,6 +34905,7 @@ export namespace Prisma {
userId?: boolean
apiKey?: boolean
afterHoursEnabled?: boolean
openPhoneReply?: boolean
user?: boolean | UserDefaultArgs<ExtArgs>
}, ExtArgs["result"]["aiSettings"]>
@@ -34906,6 +34914,7 @@ export namespace Prisma {
userId?: boolean
apiKey?: boolean
afterHoursEnabled?: boolean
openPhoneReply?: boolean
user?: boolean | UserDefaultArgs<ExtArgs>
}, ExtArgs["result"]["aiSettings"]>
@@ -34914,6 +34923,7 @@ export namespace Prisma {
userId?: boolean
apiKey?: boolean
afterHoursEnabled?: boolean
openPhoneReply?: boolean
user?: boolean | UserDefaultArgs<ExtArgs>
}, ExtArgs["result"]["aiSettings"]>
@@ -34922,9 +34932,10 @@ export namespace Prisma {
userId?: boolean
apiKey?: boolean
afterHoursEnabled?: boolean
openPhoneReply?: boolean
}
export type AiSettingsOmit<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = $Extensions.GetOmit<"id" | "userId" | "apiKey" | "afterHoursEnabled", ExtArgs["result"]["aiSettings"]>
export type AiSettingsOmit<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = $Extensions.GetOmit<"id" | "userId" | "apiKey" | "afterHoursEnabled" | "openPhoneReply", ExtArgs["result"]["aiSettings"]>
export type AiSettingsInclude<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = {
user?: boolean | UserDefaultArgs<ExtArgs>
}
@@ -34945,6 +34956,7 @@ export namespace Prisma {
userId: number
apiKey: string
afterHoursEnabled: boolean
openPhoneReply: boolean
}, ExtArgs["result"]["aiSettings"]>
composites: {}
}
@@ -35373,6 +35385,7 @@ export namespace Prisma {
readonly userId: FieldRef<"AiSettings", 'Int'>
readonly apiKey: FieldRef<"AiSettings", 'String'>
readonly afterHoursEnabled: FieldRef<"AiSettings", 'Boolean'>
readonly openPhoneReply: FieldRef<"AiSettings", 'Boolean'>
}
@@ -41715,7 +41728,8 @@ export namespace Prisma {
id: 'id',
userId: 'userId',
apiKey: 'apiKey',
afterHoursEnabled: 'afterHoursEnabled'
afterHoursEnabled: 'afterHoursEnabled',
openPhoneReply: 'openPhoneReply'
};
export type AiSettingsScalarFieldEnum = (typeof AiSettingsScalarFieldEnum)[keyof typeof AiSettingsScalarFieldEnum]
@@ -44229,6 +44243,7 @@ export namespace Prisma {
userId?: IntFilter<"AiSettings"> | number
apiKey?: StringFilter<"AiSettings"> | string
afterHoursEnabled?: BoolFilter<"AiSettings"> | boolean
openPhoneReply?: BoolFilter<"AiSettings"> | boolean
user?: XOR<UserScalarRelationFilter, UserWhereInput>
}
@@ -44237,6 +44252,7 @@ export namespace Prisma {
userId?: SortOrder
apiKey?: SortOrder
afterHoursEnabled?: SortOrder
openPhoneReply?: SortOrder
user?: UserOrderByWithRelationInput
}
@@ -44248,6 +44264,7 @@ export namespace Prisma {
NOT?: AiSettingsWhereInput | AiSettingsWhereInput[]
apiKey?: StringFilter<"AiSettings"> | string
afterHoursEnabled?: BoolFilter<"AiSettings"> | boolean
openPhoneReply?: BoolFilter<"AiSettings"> | boolean
user?: XOR<UserScalarRelationFilter, UserWhereInput>
}, "id" | "userId">
@@ -44256,6 +44273,7 @@ export namespace Prisma {
userId?: SortOrder
apiKey?: SortOrder
afterHoursEnabled?: SortOrder
openPhoneReply?: SortOrder
_count?: AiSettingsCountOrderByAggregateInput
_avg?: AiSettingsAvgOrderByAggregateInput
_max?: AiSettingsMaxOrderByAggregateInput
@@ -44271,6 +44289,7 @@ export namespace Prisma {
userId?: IntWithAggregatesFilter<"AiSettings"> | number
apiKey?: StringWithAggregatesFilter<"AiSettings"> | string
afterHoursEnabled?: BoolWithAggregatesFilter<"AiSettings"> | boolean
openPhoneReply?: BoolWithAggregatesFilter<"AiSettings"> | boolean
}
export type OfficeHoursWhereInput = {
@@ -46744,6 +46763,7 @@ export namespace Prisma {
export type AiSettingsCreateInput = {
apiKey: string
afterHoursEnabled?: boolean
openPhoneReply?: boolean
user: UserCreateNestedOneWithoutAiSettingsInput
}
@@ -46752,11 +46772,13 @@ export namespace Prisma {
userId: number
apiKey: string
afterHoursEnabled?: boolean
openPhoneReply?: boolean
}
export type AiSettingsUpdateInput = {
apiKey?: StringFieldUpdateOperationsInput | string
afterHoursEnabled?: BoolFieldUpdateOperationsInput | boolean
openPhoneReply?: BoolFieldUpdateOperationsInput | boolean
user?: UserUpdateOneRequiredWithoutAiSettingsNestedInput
}
@@ -46765,6 +46787,7 @@ export namespace Prisma {
userId?: IntFieldUpdateOperationsInput | number
apiKey?: StringFieldUpdateOperationsInput | string
afterHoursEnabled?: BoolFieldUpdateOperationsInput | boolean
openPhoneReply?: BoolFieldUpdateOperationsInput | boolean
}
export type AiSettingsCreateManyInput = {
@@ -46772,11 +46795,13 @@ export namespace Prisma {
userId: number
apiKey: string
afterHoursEnabled?: boolean
openPhoneReply?: boolean
}
export type AiSettingsUpdateManyMutationInput = {
apiKey?: StringFieldUpdateOperationsInput | string
afterHoursEnabled?: BoolFieldUpdateOperationsInput | boolean
openPhoneReply?: BoolFieldUpdateOperationsInput | boolean
}
export type AiSettingsUncheckedUpdateManyInput = {
@@ -46784,6 +46809,7 @@ export namespace Prisma {
userId?: IntFieldUpdateOperationsInput | number
apiKey?: StringFieldUpdateOperationsInput | string
afterHoursEnabled?: BoolFieldUpdateOperationsInput | boolean
openPhoneReply?: BoolFieldUpdateOperationsInput | boolean
}
export type OfficeHoursCreateInput = {
@@ -49191,6 +49217,7 @@ export namespace Prisma {
userId?: SortOrder
apiKey?: SortOrder
afterHoursEnabled?: SortOrder
openPhoneReply?: SortOrder
}
export type AiSettingsAvgOrderByAggregateInput = {
@@ -49203,6 +49230,7 @@ export namespace Prisma {
userId?: SortOrder
apiKey?: SortOrder
afterHoursEnabled?: SortOrder
openPhoneReply?: SortOrder
}
export type AiSettingsMinOrderByAggregateInput = {
@@ -49210,6 +49238,7 @@ export namespace Prisma {
userId?: SortOrder
apiKey?: SortOrder
afterHoursEnabled?: SortOrder
openPhoneReply?: SortOrder
}
export type AiSettingsSumOrderByAggregateInput = {
@@ -53081,12 +53110,14 @@ export namespace Prisma {
export type AiSettingsCreateWithoutUserInput = {
apiKey: string
afterHoursEnabled?: boolean
openPhoneReply?: boolean
}
export type AiSettingsUncheckedCreateWithoutUserInput = {
id?: number
apiKey: string
afterHoursEnabled?: boolean
openPhoneReply?: boolean
}
export type AiSettingsCreateOrConnectWithoutUserInput = {
@@ -53659,12 +53690,14 @@ export namespace Prisma {
export type AiSettingsUpdateWithoutUserInput = {
apiKey?: StringFieldUpdateOperationsInput | string
afterHoursEnabled?: BoolFieldUpdateOperationsInput | boolean
openPhoneReply?: BoolFieldUpdateOperationsInput | boolean
}
export type AiSettingsUncheckedUpdateWithoutUserInput = {
id?: IntFieldUpdateOperationsInput | number
apiKey?: StringFieldUpdateOperationsInput | string
afterHoursEnabled?: BoolFieldUpdateOperationsInput | boolean
openPhoneReply?: BoolFieldUpdateOperationsInput | boolean
}
export type OfficeHoursUpsertWithoutUserInput = {

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,5 @@
{
"name": "prisma-client-7ab23aa0435ee62d1543cc6f3f10f1fac4ea741f94efe006ada0cea03090a0c9",
"name": "prisma-client-f058d09dfd4869ea5203c66c2370bac837d95f1a5aaea0632641bf080a04b5d8",
"main": "index.js",
"types": "index.d.ts",
"browser": "default.js",

View File

@@ -579,6 +579,7 @@ model AiSettings {
userId Int @unique
apiKey String
afterHoursEnabled Boolean @default(true)
openPhoneReply Boolean @default(false)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)