feat: multi-provider AI support with per-provider model selection
- Add llm-factory.ts: unified LLM provider abstraction (Google/Claude/OpenAI) - Install @langchain/anthropic and @langchain/openai packages - resolveAiProvider picks active provider from DB settings (Claude > OpenAI > Google) - All AI graphs (reminder, new-patient, reschedule, internal-chat) now accept provider+model params - Add claudeAiModel, openAiModel, googleAiModel columns to ai_settings table - New PUT /api/ai/provider-model route to save selected model per provider - UI model dropdowns for Claude (Haiku/Sonnet/Opus), OpenAI (GPT-5.x series), Google (Gemini 2.5/3.x) - Google AI section also gets model selector alongside existing API key field Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -14,8 +14,10 @@
|
|||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@google/generative-ai": "^0.24.1",
|
"@google/generative-ai": "^0.24.1",
|
||||||
|
"@langchain/anthropic": "^1.4.0",
|
||||||
"@langchain/google-genai": "^2.1.30",
|
"@langchain/google-genai": "^2.1.30",
|
||||||
"@langchain/langgraph": "^1.2.9",
|
"@langchain/langgraph": "^1.2.9",
|
||||||
|
"@langchain/openai": "^1.4.7",
|
||||||
"archiver": "^7.0.1",
|
"archiver": "^7.0.1",
|
||||||
"axios": "^1.9.0",
|
"axios": "^1.9.0",
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
|
import { getLlm, type AiProvider } from "./llm-factory";
|
||||||
|
|
||||||
// ─── Intent types ─────────────────────────────────────────────────────────────
|
// ─── Intent types ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -92,7 +92,9 @@ export async function classifyInternalChat(
|
|||||||
message: string,
|
message: string,
|
||||||
apiKey: string,
|
apiKey: string,
|
||||||
extraSystemPrompt?: string,
|
extraSystemPrompt?: string,
|
||||||
history: { role: "user" | "assistant"; text: string }[] = []
|
history: { role: "user" | "assistant"; text: string }[] = [],
|
||||||
|
provider: AiProvider = "google",
|
||||||
|
model?: string
|
||||||
): Promise<ChatClassification> {
|
): Promise<ChatClassification> {
|
||||||
const fallback: ChatClassification = {
|
const fallback: ChatClassification = {
|
||||||
intent: "general",
|
intent: "general",
|
||||||
@@ -107,7 +109,7 @@ export async function classifyInternalChat(
|
|||||||
: BASE_SYSTEM_PROMPT;
|
: BASE_SYSTEM_PROMPT;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const llm = new ChatGoogleGenerativeAI({ model: "gemini-flash-latest", apiKey });
|
const llm = getLlm(provider, apiKey, model);
|
||||||
|
|
||||||
// Gemini requires conversation to start with a user turn — drop any leading assistant messages
|
// Gemini requires conversation to start with a user turn — drop any leading assistant messages
|
||||||
const trimmedHistory = history.slice(
|
const trimmedHistory = history.slice(
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
|
||||||
|
import { ChatAnthropic } from "@langchain/anthropic";
|
||||||
|
import { ChatOpenAI } from "@langchain/openai";
|
||||||
|
|
||||||
|
export type AiProvider = "google" | "claude" | "openai";
|
||||||
|
|
||||||
|
export function getLlm(provider: AiProvider, apiKey: string, model?: string) {
|
||||||
|
if (provider === "claude") {
|
||||||
|
return new ChatAnthropic({ model: model || "claude-haiku-4-5-20251001", apiKey });
|
||||||
|
}
|
||||||
|
if (provider === "openai") {
|
||||||
|
return new ChatOpenAI({ model: model || "gpt-4o-mini", apiKey });
|
||||||
|
}
|
||||||
|
return new ChatGoogleGenerativeAI({ model: model || "gemini-1.5-flash", apiKey });
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AiSettingsLike {
|
||||||
|
apiKey?: string | null;
|
||||||
|
claudeAiKey?: string | null;
|
||||||
|
claudeAiEnabled?: boolean | null;
|
||||||
|
claudeAiModel?: string | null;
|
||||||
|
openAiKey?: string | null;
|
||||||
|
openAiEnabled?: boolean | null;
|
||||||
|
openAiModel?: string | null;
|
||||||
|
googleAiModel?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveAiProvider(settings: AiSettingsLike): { provider: AiProvider; key: string; model: string } | null {
|
||||||
|
if (settings.claudeAiEnabled && settings.claudeAiKey?.trim()) {
|
||||||
|
return {
|
||||||
|
provider: "claude",
|
||||||
|
key: settings.claudeAiKey.trim(),
|
||||||
|
model: settings.claudeAiModel?.trim() || "claude-haiku-4-5-20251001",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (settings.openAiEnabled && settings.openAiKey?.trim()) {
|
||||||
|
return {
|
||||||
|
provider: "openai",
|
||||||
|
key: settings.openAiKey.trim(),
|
||||||
|
model: settings.openAiModel?.trim() || "gpt-5.2",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (settings.apiKey?.trim()) {
|
||||||
|
return {
|
||||||
|
provider: "google",
|
||||||
|
key: settings.apiKey.trim(),
|
||||||
|
model: settings.googleAiModel?.trim() || "gemini-2.5-flash",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { StateGraph, END, START, Annotation } from "@langchain/langgraph";
|
import { StateGraph, END, START, Annotation } from "@langchain/langgraph";
|
||||||
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
|
import { getLlm, type AiProvider } from "./llm-factory";
|
||||||
import type { ConversationStage } from "./aiHandoffStore";
|
import type { ConversationStage } from "./aiHandoffStore";
|
||||||
|
|
||||||
// ── Graph state ───────────────────────────────────────────────────────────────
|
// ── Graph state ───────────────────────────────────────────────────────────────
|
||||||
@@ -80,10 +80,12 @@ async function llmReply(
|
|||||||
system: string,
|
system: string,
|
||||||
userMsg: string,
|
userMsg: string,
|
||||||
fallback: string,
|
fallback: string,
|
||||||
apiKey: string
|
apiKey: string,
|
||||||
|
provider: AiProvider = "google",
|
||||||
|
model?: string
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
try {
|
try {
|
||||||
const llm = new ChatGoogleGenerativeAI({ model: "gemini-1.5-flash", apiKey });
|
const llm = getLlm(provider, apiKey, model);
|
||||||
const res = await llm.invoke([
|
const res = await llm.invoke([
|
||||||
{ role: "system", content: system },
|
{ role: "system", content: system },
|
||||||
{ role: "user", content: userMsg },
|
{ role: "user", content: userMsg },
|
||||||
@@ -192,6 +194,8 @@ function routeNode(state: GraphStateType): string {
|
|||||||
async function askNewOrExistingNode(state: GraphStateType, config: any) {
|
async function askNewOrExistingNode(state: GraphStateType, config: any) {
|
||||||
const lang = state.language || "English";
|
const lang = state.language || "English";
|
||||||
const apiKey: string | undefined = config?.configurable?.apiKey;
|
const apiKey: string | undefined = config?.configurable?.apiKey;
|
||||||
|
const provider: AiProvider = config?.configurable?.provider ?? "google";
|
||||||
|
const model: string | undefined = config?.configurable?.model;
|
||||||
|
|
||||||
const fallbacks: Record<string, string> = {
|
const fallbacks: Record<string, string> = {
|
||||||
English: "Are you a new patient or an existing patient?",
|
English: "Are you a new patient or an existing patient?",
|
||||||
@@ -208,7 +212,7 @@ async function askNewOrExistingNode(state: GraphStateType, config: any) {
|
|||||||
? await llmReply(
|
? await llmReply(
|
||||||
`You are a friendly dental office AI assistant. Ask the patient in ${lang} whether they are a new patient or an existing patient. One sentence, no formatting.`,
|
`You are a friendly dental office AI assistant. Ask the patient in ${lang} whether they are a new patient or an existing patient. One sentence, no formatting.`,
|
||||||
`Patient wants an appointment. Ask if new or existing.`,
|
`Patient wants an appointment. Ask if new or existing.`,
|
||||||
fallback, apiKey
|
fallback, apiKey, provider, model
|
||||||
)
|
)
|
||||||
: fallback;
|
: fallback;
|
||||||
|
|
||||||
@@ -218,6 +222,8 @@ async function askNewOrExistingNode(state: GraphStateType, config: any) {
|
|||||||
async function askNewPatientInsuranceNode(state: GraphStateType, config: any) {
|
async function askNewPatientInsuranceNode(state: GraphStateType, config: any) {
|
||||||
const lang = state.language || "English";
|
const lang = state.language || "English";
|
||||||
const apiKey: string | undefined = config?.configurable?.apiKey;
|
const apiKey: string | undefined = config?.configurable?.apiKey;
|
||||||
|
const provider: AiProvider = config?.configurable?.provider ?? "google";
|
||||||
|
const model: string | undefined = config?.configurable?.model;
|
||||||
|
|
||||||
const fallbacks: Record<string, string> = {
|
const fallbacks: Record<string, string> = {
|
||||||
English: "Do you have any dental insurance?",
|
English: "Do you have any dental insurance?",
|
||||||
@@ -234,7 +240,7 @@ async function askNewPatientInsuranceNode(state: GraphStateType, config: any) {
|
|||||||
? await llmReply(
|
? await llmReply(
|
||||||
`You are a friendly dental office AI assistant. Ask the new patient in ${lang} if they have dental insurance. One sentence, no formatting.`,
|
`You are a friendly dental office AI assistant. Ask the new patient in ${lang} if they have dental insurance. One sentence, no formatting.`,
|
||||||
`New patient confirmed. Ask about insurance.`,
|
`New patient confirmed. Ask about insurance.`,
|
||||||
fallback, apiKey
|
fallback, apiKey, provider, model
|
||||||
)
|
)
|
||||||
: fallback;
|
: fallback;
|
||||||
|
|
||||||
@@ -244,6 +250,8 @@ async function askNewPatientInsuranceNode(state: GraphStateType, config: any) {
|
|||||||
async function askInsuranceTypeNode(state: GraphStateType, config: any) {
|
async function askInsuranceTypeNode(state: GraphStateType, config: any) {
|
||||||
const lang = state.language || "English";
|
const lang = state.language || "English";
|
||||||
const apiKey: string | undefined = config?.configurable?.apiKey;
|
const apiKey: string | undefined = config?.configurable?.apiKey;
|
||||||
|
const provider: AiProvider = config?.configurable?.provider ?? "google";
|
||||||
|
const model: string | undefined = config?.configurable?.model;
|
||||||
|
|
||||||
const fallbacks: Record<string, string> = {
|
const fallbacks: Record<string, string> = {
|
||||||
English: "What kind of insurance do you have?",
|
English: "What kind of insurance do you have?",
|
||||||
@@ -260,7 +268,7 @@ async function askInsuranceTypeNode(state: GraphStateType, config: any) {
|
|||||||
? await llmReply(
|
? await llmReply(
|
||||||
`You are a friendly dental office AI assistant. The patient confirmed they have insurance. Ask them in ${lang} what kind of insurance they have. One sentence, no formatting.`,
|
`You are a friendly dental office AI assistant. The patient confirmed they have insurance. Ask them in ${lang} what kind of insurance they have. One sentence, no formatting.`,
|
||||||
`Patient has insurance. Ask what kind.`,
|
`Patient has insurance. Ask what kind.`,
|
||||||
fallback, apiKey
|
fallback, apiKey, provider, model
|
||||||
)
|
)
|
||||||
: fallback;
|
: fallback;
|
||||||
|
|
||||||
@@ -270,6 +278,8 @@ async function askInsuranceTypeNode(state: GraphStateType, config: any) {
|
|||||||
async function askMassHealthCheckConsentNode(state: GraphStateType, config: any) {
|
async function askMassHealthCheckConsentNode(state: GraphStateType, config: any) {
|
||||||
const lang = state.language || "English";
|
const lang = state.language || "English";
|
||||||
const apiKey: string | undefined = config?.configurable?.apiKey;
|
const apiKey: string | undefined = config?.configurable?.apiKey;
|
||||||
|
const provider: AiProvider = config?.configurable?.provider ?? "google";
|
||||||
|
const model: string | undefined = config?.configurable?.model;
|
||||||
|
|
||||||
const fallbacks: Record<string, string> = {
|
const fallbacks: Record<string, string> = {
|
||||||
English: "Do you want to check your MassHealth insurance now?",
|
English: "Do you want to check your MassHealth insurance now?",
|
||||||
@@ -286,7 +296,7 @@ async function askMassHealthCheckConsentNode(state: GraphStateType, config: any)
|
|||||||
? await llmReply(
|
? await llmReply(
|
||||||
`You are a friendly dental office AI assistant. The patient has MassHealth insurance. Ask them in ${lang} if they would like to check their MassHealth coverage right now. One sentence, no formatting.`,
|
`You are a friendly dental office AI assistant. The patient has MassHealth insurance. Ask them in ${lang} if they would like to check their MassHealth coverage right now. One sentence, no formatting.`,
|
||||||
`Patient has MassHealth. Ask if they want to check it now.`,
|
`Patient has MassHealth. Ask if they want to check it now.`,
|
||||||
fallback, apiKey
|
fallback, apiKey, provider, model
|
||||||
)
|
)
|
||||||
: fallback;
|
: fallback;
|
||||||
|
|
||||||
@@ -296,6 +306,8 @@ async function askMassHealthCheckConsentNode(state: GraphStateType, config: any)
|
|||||||
async function askMassHealthInfoNode(state: GraphStateType, config: any) {
|
async function askMassHealthInfoNode(state: GraphStateType, config: any) {
|
||||||
const lang = state.language || "English";
|
const lang = state.language || "English";
|
||||||
const apiKey: string | undefined = config?.configurable?.apiKey;
|
const apiKey: string | undefined = config?.configurable?.apiKey;
|
||||||
|
const provider: AiProvider = config?.configurable?.provider ?? "google";
|
||||||
|
const model: string | undefined = config?.configurable?.model;
|
||||||
|
|
||||||
const fallbacks: Record<string, string> = {
|
const fallbacks: Record<string, string> = {
|
||||||
English: "Please send me your MassHealth Member ID and date of birth so I can check your coverage.",
|
English: "Please send me your MassHealth Member ID and date of birth so I can check your coverage.",
|
||||||
@@ -312,7 +324,7 @@ async function askMassHealthInfoNode(state: GraphStateType, config: any) {
|
|||||||
? await llmReply(
|
? await llmReply(
|
||||||
`You are a friendly dental office AI assistant. The patient wants to check their MassHealth coverage. Ask them in ${lang} to provide their MassHealth Member ID and date of birth. 1-2 sentences, no formatting.`,
|
`You are a friendly dental office AI assistant. The patient wants to check their MassHealth coverage. Ask them in ${lang} to provide their MassHealth Member ID and date of birth. 1-2 sentences, no formatting.`,
|
||||||
`Patient agreed to MassHealth check. Ask for member ID and DOB.`,
|
`Patient agreed to MassHealth check. Ask for member ID and DOB.`,
|
||||||
fallback, apiKey
|
fallback, apiKey, provider, model
|
||||||
)
|
)
|
||||||
: fallback;
|
: fallback;
|
||||||
|
|
||||||
@@ -322,6 +334,8 @@ async function askMassHealthInfoNode(state: GraphStateType, config: any) {
|
|||||||
async function askExistingInsuranceNode(state: GraphStateType, config: any) {
|
async function askExistingInsuranceNode(state: GraphStateType, config: any) {
|
||||||
const lang = state.language || "English";
|
const lang = state.language || "English";
|
||||||
const apiKey: string | undefined = config?.configurable?.apiKey;
|
const apiKey: string | undefined = config?.configurable?.apiKey;
|
||||||
|
const provider: AiProvider = config?.configurable?.provider ?? "google";
|
||||||
|
const model: string | undefined = config?.configurable?.model;
|
||||||
|
|
||||||
const fallbacks: Record<string, string> = {
|
const fallbacks: Record<string, string> = {
|
||||||
English: "Got it — you are an existing patient! Do you still have the same insurance on file?",
|
English: "Got it — you are an existing patient! Do you still have the same insurance on file?",
|
||||||
@@ -338,7 +352,7 @@ async function askExistingInsuranceNode(state: GraphStateType, config: any) {
|
|||||||
? await llmReply(
|
? await llmReply(
|
||||||
`You are a friendly dental office AI assistant. The patient confirmed they are an existing patient. In ${lang}, acknowledge that they are an existing patient and then ask if they still have the same dental insurance on file. 1-2 sentences, no formatting.`,
|
`You are a friendly dental office AI assistant. The patient confirmed they are an existing patient. In ${lang}, acknowledge that they are an existing patient and then ask if they still have the same dental insurance on file. 1-2 sentences, no formatting.`,
|
||||||
`Existing patient confirmed. Acknowledge and ask about insurance.`,
|
`Existing patient confirmed. Acknowledge and ask about insurance.`,
|
||||||
fallback, apiKey
|
fallback, apiKey, provider, model
|
||||||
)
|
)
|
||||||
: fallback;
|
: fallback;
|
||||||
|
|
||||||
@@ -348,6 +362,8 @@ async function askExistingInsuranceNode(state: GraphStateType, config: any) {
|
|||||||
async function askAppointmentTimeNode(state: GraphStateType, config: any) {
|
async function askAppointmentTimeNode(state: GraphStateType, config: any) {
|
||||||
const lang = state.language || "English";
|
const lang = state.language || "English";
|
||||||
const apiKey: string | undefined = config?.configurable?.apiKey;
|
const apiKey: string | undefined = config?.configurable?.apiKey;
|
||||||
|
const provider: AiProvider = config?.configurable?.provider ?? "google";
|
||||||
|
const model: string | undefined = config?.configurable?.model;
|
||||||
|
|
||||||
const fallbacks: Record<string, string> = {
|
const fallbacks: Record<string, string> = {
|
||||||
English: "When would you like to come in for your appointment?",
|
English: "When would you like to come in for your appointment?",
|
||||||
@@ -364,7 +380,7 @@ async function askAppointmentTimeNode(state: GraphStateType, config: any) {
|
|||||||
? await llmReply(
|
? await llmReply(
|
||||||
`You are a friendly dental office AI assistant. Ask the patient in ${lang} what date and time they would prefer for their appointment. One sentence, no formatting.`,
|
`You are a friendly dental office AI assistant. Ask the patient in ${lang} what date and time they would prefer for their appointment. One sentence, no formatting.`,
|
||||||
`Ask when to schedule.`,
|
`Ask when to schedule.`,
|
||||||
fallback, apiKey
|
fallback, apiKey, provider, model
|
||||||
)
|
)
|
||||||
: fallback;
|
: fallback;
|
||||||
|
|
||||||
@@ -374,6 +390,8 @@ async function askAppointmentTimeNode(state: GraphStateType, config: any) {
|
|||||||
async function acknowledgeAppointmentTimeNode(state: GraphStateType, config: any) {
|
async function acknowledgeAppointmentTimeNode(state: GraphStateType, config: any) {
|
||||||
const lang = state.language || "English";
|
const lang = state.language || "English";
|
||||||
const apiKey: string | undefined = config?.configurable?.apiKey;
|
const apiKey: string | undefined = config?.configurable?.apiKey;
|
||||||
|
const provider: AiProvider = config?.configurable?.provider ?? "google";
|
||||||
|
const model: string | undefined = config?.configurable?.model;
|
||||||
|
|
||||||
const fallbacks: Record<string, string> = {
|
const fallbacks: Record<string, string> = {
|
||||||
English: "Thank you! Our office staff will confirm your appointment details shortly.",
|
English: "Thank you! Our office staff will confirm your appointment details shortly.",
|
||||||
@@ -390,7 +408,7 @@ async function acknowledgeAppointmentTimeNode(state: GraphStateType, config: any
|
|||||||
? await llmReply(
|
? await llmReply(
|
||||||
`You are a friendly dental office AI assistant. The patient stated their preferred appointment time. Acknowledge in ${lang} and tell them the office staff will confirm shortly. 1-2 sentences, no formatting.`,
|
`You are a friendly dental office AI assistant. The patient stated their preferred appointment time. Acknowledge in ${lang} and tell them the office staff will confirm shortly. 1-2 sentences, no formatting.`,
|
||||||
`Patient said: "${state.message}". Acknowledge.`,
|
`Patient said: "${state.message}". Acknowledge.`,
|
||||||
fallback, apiKey
|
fallback, apiKey, provider, model
|
||||||
)
|
)
|
||||||
: fallback;
|
: fallback;
|
||||||
|
|
||||||
@@ -400,6 +418,8 @@ async function acknowledgeAppointmentTimeNode(state: GraphStateType, config: any
|
|||||||
async function handleAppointmentPreferenceNode(state: GraphStateType, config: any) {
|
async function handleAppointmentPreferenceNode(state: GraphStateType, config: any) {
|
||||||
const lang = state.language || "English";
|
const lang = state.language || "English";
|
||||||
const apiKey: string | undefined = config?.configurable?.apiKey;
|
const apiKey: string | undefined = config?.configurable?.apiKey;
|
||||||
|
const provider: AiProvider = config?.configurable?.provider ?? "google";
|
||||||
|
const model: string | undefined = config?.configurable?.model;
|
||||||
|
|
||||||
const fallbacks: Record<string, string> = {
|
const fallbacks: Record<string, string> = {
|
||||||
English: "When would you like to come in? Are you looking for a routine check-up and teeth cleaning, or do you have a tooth problem or pain?",
|
English: "When would you like to come in? Are you looking for a routine check-up and teeth cleaning, or do you have a tooth problem or pain?",
|
||||||
@@ -416,7 +436,7 @@ async function handleAppointmentPreferenceNode(state: GraphStateType, config: an
|
|||||||
? await llmReply(
|
? await llmReply(
|
||||||
`You are a friendly dental office AI assistant. The patient's MassHealth is active. In ${lang}, ask when they would like to come in and whether they want a routine check-up and teeth cleaning, or if they have a dental problem or pain. 1-2 sentences, no formatting.`,
|
`You are a friendly dental office AI assistant. The patient's MassHealth is active. In ${lang}, ask when they would like to come in and whether they want a routine check-up and teeth cleaning, or if they have a dental problem or pain. 1-2 sentences, no formatting.`,
|
||||||
`MassHealth is active. Ask appointment preference.`,
|
`MassHealth is active. Ask appointment preference.`,
|
||||||
fallback, apiKey
|
fallback, apiKey, provider, model
|
||||||
)
|
)
|
||||||
: fallback;
|
: fallback;
|
||||||
|
|
||||||
@@ -426,6 +446,8 @@ async function handleAppointmentPreferenceNode(state: GraphStateType, config: an
|
|||||||
async function handleSelfPayNode(state: GraphStateType, config: any) {
|
async function handleSelfPayNode(state: GraphStateType, config: any) {
|
||||||
const lang = state.language || "English";
|
const lang = state.language || "English";
|
||||||
const apiKey: string | undefined = config?.configurable?.apiKey;
|
const apiKey: string | undefined = config?.configurable?.apiKey;
|
||||||
|
const provider: AiProvider = config?.configurable?.provider ?? "google";
|
||||||
|
const model: string | undefined = config?.configurable?.model;
|
||||||
const text = state.message.toLowerCase();
|
const text = state.message.toLowerCase();
|
||||||
|
|
||||||
const acceptsSelfPay = /yes|sure|ok|okay|yep|yeah|sí|si|claro|sim|confirmado|好的|نعم|wi|oke/i.test(text);
|
const acceptsSelfPay = /yes|sure|ok|okay|yep|yeah|sí|si|claro|sim|confirmado|好的|نعم|wi|oke/i.test(text);
|
||||||
@@ -479,6 +501,8 @@ async function handleSelfPayNode(state: GraphStateType, config: any) {
|
|||||||
async function askContactInfoNode(state: GraphStateType, config: any) {
|
async function askContactInfoNode(state: GraphStateType, config: any) {
|
||||||
const lang = state.language || "English";
|
const lang = state.language || "English";
|
||||||
const apiKey: string | undefined = config?.configurable?.apiKey;
|
const apiKey: string | undefined = config?.configurable?.apiKey;
|
||||||
|
const provider: AiProvider = config?.configurable?.provider ?? "google";
|
||||||
|
const model: string | undefined = config?.configurable?.model;
|
||||||
|
|
||||||
const fallbacks: Record<string, string> = {
|
const fallbacks: Record<string, string> = {
|
||||||
English: "Please leave your name and phone number. Our receptionist will contact you as soon as possible.",
|
English: "Please leave your name and phone number. Our receptionist will contact you as soon as possible.",
|
||||||
@@ -495,7 +519,7 @@ async function askContactInfoNode(state: GraphStateType, config: any) {
|
|||||||
? await llmReply(
|
? await llmReply(
|
||||||
`You are a friendly dental office AI assistant. The patient's MassHealth is inactive and they have no other insurance. In ${lang}, politely ask them to leave their name and phone number so the receptionist can contact them. 1-2 sentences, no formatting.`,
|
`You are a friendly dental office AI assistant. The patient's MassHealth is inactive and they have no other insurance. In ${lang}, politely ask them to leave their name and phone number so the receptionist can contact them. 1-2 sentences, no formatting.`,
|
||||||
`MassHealth inactive, no other insurance. Ask for name and phone.`,
|
`MassHealth inactive, no other insurance. Ask for name and phone.`,
|
||||||
fallback, apiKey
|
fallback, apiKey, provider, model
|
||||||
)
|
)
|
||||||
: fallback;
|
: fallback;
|
||||||
|
|
||||||
@@ -505,6 +529,8 @@ async function askContactInfoNode(state: GraphStateType, config: any) {
|
|||||||
async function acknowledgeContactInfoNode(state: GraphStateType, config: any) {
|
async function acknowledgeContactInfoNode(state: GraphStateType, config: any) {
|
||||||
const lang = state.language || "English";
|
const lang = state.language || "English";
|
||||||
const apiKey: string | undefined = config?.configurable?.apiKey;
|
const apiKey: string | undefined = config?.configurable?.apiKey;
|
||||||
|
const provider: AiProvider = config?.configurable?.provider ?? "google";
|
||||||
|
const model: string | undefined = config?.configurable?.model;
|
||||||
|
|
||||||
const fallbacks: Record<string, string> = {
|
const fallbacks: Record<string, string> = {
|
||||||
English: "Thank you! Our receptionist will reach out to you shortly.",
|
English: "Thank you! Our receptionist will reach out to you shortly.",
|
||||||
@@ -521,7 +547,7 @@ async function acknowledgeContactInfoNode(state: GraphStateType, config: any) {
|
|||||||
? await llmReply(
|
? await llmReply(
|
||||||
`You are a friendly dental office AI assistant. The patient has left their contact information. Thank them in ${lang} and let them know the receptionist will reach out soon. 1-2 sentences, no formatting.`,
|
`You are a friendly dental office AI assistant. The patient has left their contact information. Thank them in ${lang} and let them know the receptionist will reach out soon. 1-2 sentences, no formatting.`,
|
||||||
`Patient provided contact info. Acknowledge.`,
|
`Patient provided contact info. Acknowledge.`,
|
||||||
fallback, apiKey
|
fallback, apiKey, provider, model
|
||||||
)
|
)
|
||||||
: fallback;
|
: fallback;
|
||||||
|
|
||||||
@@ -588,11 +614,13 @@ export async function runNewPatientStep(
|
|||||||
stage: ConversationStage,
|
stage: ConversationStage,
|
||||||
language: string,
|
language: string,
|
||||||
apiKey: string,
|
apiKey: string,
|
||||||
generalFallback = ""
|
generalFallback = "",
|
||||||
|
provider: AiProvider = "google",
|
||||||
|
model?: string
|
||||||
): Promise<{ reply: string; nextStage: ConversationStage }> {
|
): Promise<{ reply: string; nextStage: ConversationStage }> {
|
||||||
const result = await graph.invoke(
|
const result = await graph.invoke(
|
||||||
{ message, stage, intent: "", reply: "", language, nextStage: "", generalFallback },
|
{ message, stage, intent: "", reply: "", language, nextStage: "", generalFallback },
|
||||||
{ configurable: { apiKey } }
|
{ configurable: { apiKey, provider, model } }
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
reply: result.reply || transferMsg(language),
|
reply: result.reply || transferMsg(language),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { StateGraph, END, START, Annotation } from "@langchain/langgraph";
|
import { StateGraph, END, START, Annotation } from "@langchain/langgraph";
|
||||||
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
|
import { getLlm, type AiProvider } from "./llm-factory";
|
||||||
|
|
||||||
const GraphState = Annotation.Root({
|
const GraphState = Annotation.Root({
|
||||||
message: Annotation<string>(),
|
message: Annotation<string>(),
|
||||||
@@ -95,7 +95,9 @@ async function confirmNode(state: GraphStateType, config: any) {
|
|||||||
if (!apiKey) return { reply: fallback };
|
if (!apiKey) return { reply: fallback };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const llm = new ChatGoogleGenerativeAI({ model: "gemini-1.5-flash", apiKey });
|
const provider: AiProvider = config?.configurable?.provider ?? "google";
|
||||||
|
const model: string | undefined = config?.configurable?.model;
|
||||||
|
const llm = getLlm(provider, apiKey, model);
|
||||||
const apptClause = appt ? ` Their appointment is on ${appt}.` : "";
|
const apptClause = appt ? ` Their appointment is on ${appt}.` : "";
|
||||||
const response = await llm.invoke([
|
const response = await llm.invoke([
|
||||||
{
|
{
|
||||||
@@ -134,7 +136,9 @@ async function rescheduleNode(state: GraphStateType, config: any) {
|
|||||||
if (!apiKey) return { reply: fallback };
|
if (!apiKey) return { reply: fallback };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const llm = new ChatGoogleGenerativeAI({ model: "gemini-1.5-flash", apiKey });
|
const provider: AiProvider = config?.configurable?.provider ?? "google";
|
||||||
|
const model: string | undefined = config?.configurable?.model;
|
||||||
|
const llm = getLlm(provider, apiKey, model);
|
||||||
const response = await llm.invoke([
|
const response = await llm.invoke([
|
||||||
{
|
{
|
||||||
role: "system",
|
role: "system",
|
||||||
@@ -160,7 +164,9 @@ async function otherNode(state: GraphStateType, config: any) {
|
|||||||
const fallback = NEW_APPT_FALLBACKS[lang] ?? NEW_APPT_FALLBACKS["English"]!;
|
const fallback = NEW_APPT_FALLBACKS[lang] ?? NEW_APPT_FALLBACKS["English"]!;
|
||||||
if (!apiKey) return { reply: fallback, intent: "wants_appointment" };
|
if (!apiKey) return { reply: fallback, intent: "wants_appointment" };
|
||||||
try {
|
try {
|
||||||
const llm = new ChatGoogleGenerativeAI({ model: "gemini-1.5-flash", apiKey });
|
const provider: AiProvider = config?.configurable?.provider ?? "google";
|
||||||
|
const model: string | undefined = config?.configurable?.model;
|
||||||
|
const llm = getLlm(provider, apiKey, model);
|
||||||
const response = await llm.invoke([
|
const response = await llm.invoke([
|
||||||
{
|
{
|
||||||
role: "system",
|
role: "system",
|
||||||
@@ -177,7 +183,9 @@ async function otherNode(state: GraphStateType, config: any) {
|
|||||||
const fallback = state.generalFallback || (GENERAL_FALLBACKS[lang] ?? GENERAL_FALLBACKS["English"]!);
|
const fallback = state.generalFallback || (GENERAL_FALLBACKS[lang] ?? GENERAL_FALLBACKS["English"]!);
|
||||||
if (!apiKey) return { reply: fallback };
|
if (!apiKey) return { reply: fallback };
|
||||||
try {
|
try {
|
||||||
const llm = new ChatGoogleGenerativeAI({ model: "gemini-1.5-flash", apiKey });
|
const provider: AiProvider = config?.configurable?.provider ?? "google";
|
||||||
|
const model: string | undefined = config?.configurable?.model;
|
||||||
|
const llm = getLlm(provider, apiKey, model);
|
||||||
const response = await llm.invoke([
|
const response = await llm.invoke([
|
||||||
{
|
{
|
||||||
role: "system",
|
role: "system",
|
||||||
@@ -215,11 +223,13 @@ export async function runReminderGraph(
|
|||||||
language = "English",
|
language = "English",
|
||||||
appointmentDatetime = "",
|
appointmentDatetime = "",
|
||||||
rescheduleGreeting = "",
|
rescheduleGreeting = "",
|
||||||
generalFallback = ""
|
generalFallback = "",
|
||||||
|
provider: AiProvider = "google",
|
||||||
|
model?: string
|
||||||
): Promise<{ reply: string | null; intent: string | null }> {
|
): Promise<{ reply: string | null; intent: string | null }> {
|
||||||
const result = await graph.invoke(
|
const result = await graph.invoke(
|
||||||
{ message: patientMessage, intent: "", reply: "", language, appointmentDatetime, rescheduleGreeting, generalFallback },
|
{ message: patientMessage, intent: "", reply: "", language, appointmentDatetime, rescheduleGreeting, generalFallback },
|
||||||
{ configurable: { apiKey } }
|
{ configurable: { apiKey, provider, model } }
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
reply: result.reply || null,
|
reply: result.reply || null,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
|
import { getLlm, type AiProvider } from "./llm-factory";
|
||||||
import { prisma as db } from "@repo/db/client";
|
import { prisma as db } from "@repo/db/client";
|
||||||
import { storage } from "../storage";
|
import { storage } from "../storage";
|
||||||
import {
|
import {
|
||||||
@@ -83,6 +83,8 @@ function messageHasTime(msg: string): boolean {
|
|||||||
export async function parseDateOnlyFromMessage(
|
export async function parseDateOnlyFromMessage(
|
||||||
message: string,
|
message: string,
|
||||||
apiKey: string,
|
apiKey: string,
|
||||||
|
provider: AiProvider = "google",
|
||||||
|
model?: string
|
||||||
): Promise<{ date: Date; dateLabel: string } | null> {
|
): Promise<{ date: Date; dateLabel: string } | null> {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const todayStr = now.toLocaleDateString("en-CA");
|
const todayStr = now.toLocaleDateString("en-CA");
|
||||||
@@ -106,9 +108,9 @@ export async function parseDateOnlyFromMessage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gemini fallback for "next Monday", "Tuesday", etc.
|
// LLM fallback for "next Monday", "Tuesday", etc.
|
||||||
try {
|
try {
|
||||||
const llm = new ChatGoogleGenerativeAI({ model: "gemini-1.5-flash", apiKey });
|
const llm = getLlm(provider, apiKey, model);
|
||||||
const res = await llm.invoke([
|
const res = await llm.invoke([
|
||||||
{
|
{
|
||||||
role: "system",
|
role: "system",
|
||||||
@@ -145,6 +147,8 @@ Return ONLY raw JSON: {"date":"YYYY-MM-DD"}
|
|||||||
async function parseDatetimeFromMessage(
|
async function parseDatetimeFromMessage(
|
||||||
message: string,
|
message: string,
|
||||||
apiKey: string,
|
apiKey: string,
|
||||||
|
provider: AiProvider = "google",
|
||||||
|
model?: string
|
||||||
): Promise<{ date: Date; startTime: string; displayLabel: string } | null> {
|
): Promise<{ date: Date; startTime: string; displayLabel: string } | null> {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const todayStr = now.toLocaleDateString("en-CA"); // YYYY-MM-DD local
|
const todayStr = now.toLocaleDateString("en-CA"); // YYYY-MM-DD local
|
||||||
@@ -188,9 +192,9 @@ async function parseDatetimeFromMessage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Step 2: fall back to Google AI for natural language ───────────────────
|
// ── Step 2: fall back to AI for natural language ───────────────────────────
|
||||||
try {
|
try {
|
||||||
const llm = new ChatGoogleGenerativeAI({ model: "gemini-1.5-flash", apiKey });
|
const llm = getLlm(provider, apiKey, model);
|
||||||
const res = await llm.invoke([
|
const res = await llm.invoke([
|
||||||
{
|
{
|
||||||
role: "system",
|
role: "system",
|
||||||
@@ -387,7 +391,7 @@ async function isSlotAvailable(
|
|||||||
|
|
||||||
// ── Time parsing (legacy) ─────────────────────────────────────────────────────
|
// ── Time parsing (legacy) ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
export async function parseTime(message: string, apiKey: string): Promise<string | null> {
|
export async function parseTime(message: string, apiKey: string, provider: AiProvider = "google", model?: string): Promise<string | null> {
|
||||||
const t = message.toLowerCase();
|
const t = message.toLowerCase();
|
||||||
if (/\bmorning\b|mañana|manhã|上午|صباح|maten/i.test(t)) return "09:00";
|
if (/\bmorning\b|mañana|manhã|上午|صباح|maten/i.test(t)) return "09:00";
|
||||||
if (/\bafternoon\b|tarde|après-midi|下午|مساء|aprèmidi/i.test(t)) return "13:00";
|
if (/\bafternoon\b|tarde|après-midi|下午|مساء|aprèmidi/i.test(t)) return "13:00";
|
||||||
@@ -402,7 +406,7 @@ export async function parseTime(message: string, apiKey: string): Promise<string
|
|||||||
}
|
}
|
||||||
if (clock) return clock[0]!;
|
if (clock) return clock[0]!;
|
||||||
try {
|
try {
|
||||||
const llm = new ChatGoogleGenerativeAI({ model: "gemini-1.5-flash", apiKey });
|
const llm = getLlm(provider, apiKey, model);
|
||||||
const res = await llm.invoke([
|
const res = await llm.invoke([
|
||||||
{ role: "system", content: 'Extract the time from the message. Return ONLY a 24-hour time in "HH:MM" format. If no time is mentioned, return "null".' },
|
{ role: "system", content: 'Extract the time from the message. Return ONLY a 24-hour time in "HH:MM" format. If no time is mentioned, return "null".' },
|
||||||
{ role: "user", content: message },
|
{ role: "user", content: message },
|
||||||
@@ -465,9 +469,9 @@ function prefersWednesday(t: string) { return /wednesday|miércoles|quarta|周
|
|||||||
|
|
||||||
// ── LLM helper ────────────────────────────────────────────────────────────────
|
// ── LLM helper ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
async function llmReply(system: string, user: string, fallback: string, apiKey: string): Promise<string> {
|
async function llmReply(system: string, user: string, fallback: string, apiKey: string, provider: AiProvider = "google", model?: string): Promise<string> {
|
||||||
try {
|
try {
|
||||||
const llm = new ChatGoogleGenerativeAI({ model: "gemini-1.5-flash", apiKey });
|
const llm = getLlm(provider, apiKey, model);
|
||||||
const res = await llm.invoke([
|
const res = await llm.invoke([
|
||||||
{ role: "system", content: system },
|
{ role: "system", content: system },
|
||||||
{ role: "user", content: user },
|
{ role: "user", content: user },
|
||||||
@@ -499,6 +503,8 @@ export async function runRescheduleStep(
|
|||||||
patientId: number,
|
patientId: number,
|
||||||
apiKey: string,
|
apiKey: string,
|
||||||
userId: number = 0,
|
userId: number = 0,
|
||||||
|
provider: AiProvider = "google",
|
||||||
|
model?: string
|
||||||
): Promise<{ reply: string; nextStage: ConversationStage }> {
|
): Promise<{ reply: string; nextStage: ConversationStage }> {
|
||||||
|
|
||||||
const lang = language || "English";
|
const lang = language || "English";
|
||||||
@@ -513,7 +519,7 @@ export async function runRescheduleStep(
|
|||||||
|
|
||||||
if (!hasTime) {
|
if (!hasTime) {
|
||||||
// Try to parse date only
|
// Try to parse date only
|
||||||
const parsedDate = await parseDateOnlyFromMessage(message, apiKey);
|
const parsedDate = await parseDateOnlyFromMessage(message, apiKey, provider, model);
|
||||||
if (!parsedDate) {
|
if (!parsedDate) {
|
||||||
const fallbacks: Record<string, string> = {
|
const fallbacks: Record<string, string> = {
|
||||||
English: "I didn't catch that. What day would you prefer? For example: 'Monday', 'next Tuesday', or '5/18'.",
|
English: "I didn't catch that. What day would you prefer? For example: 'Monday', 'next Tuesday', or '5/18'.",
|
||||||
@@ -559,13 +565,13 @@ export async function runRescheduleStep(
|
|||||||
`You are a friendly dental office assistant. The patient wants to reschedule to ${dateLabel} but hasn't given a time. Ask them in ${lang} what time they prefer on that day. 1 sentence, no formatting.`,
|
`You are a friendly dental office assistant. The patient wants to reschedule to ${dateLabel} but hasn't given a time. Ask them in ${lang} what time they prefer on that day. 1 sentence, no formatting.`,
|
||||||
`Patient wants ${dateLabel} but gave no time.`,
|
`Patient wants ${dateLabel} but gave no time.`,
|
||||||
fallbacks[lang] ?? fallbacks["English"]!,
|
fallbacks[lang] ?? fallbacks["English"]!,
|
||||||
apiKey,
|
apiKey, provider, model
|
||||||
);
|
);
|
||||||
return { reply: askTimeReply, nextStage: "asked_reschedule_time_for_date" };
|
return { reply: askTimeReply, nextStage: "asked_reschedule_time_for_date" };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Both date and time present — parse the full datetime
|
// Both date and time present — parse the full datetime
|
||||||
const parsed = await parseDatetimeFromMessage(message, apiKey);
|
const parsed = await parseDatetimeFromMessage(message, apiKey, provider, model);
|
||||||
if (!parsed) {
|
if (!parsed) {
|
||||||
const fallbacks: Record<string, string> = {
|
const fallbacks: Record<string, string> = {
|
||||||
English: "I didn't catch that. What day and time would you prefer? For example: 'Monday at 10am' or '5/18 at 2pm'.",
|
English: "I didn't catch that. What day and time would you prefer? For example: 'Monday at 10am' or '5/18 at 2pm'.",
|
||||||
@@ -613,7 +619,7 @@ export async function runRescheduleStep(
|
|||||||
`You are a friendly dental office AI assistant. The patient mentioned a date/time preference that you interpreted as "${displayLabel}". Ask them in ${lang} to confirm: "Do you mean ${displayLabel}?" 1 sentence, natural and friendly. No formatting.`,
|
`You are a friendly dental office AI assistant. The patient mentioned a date/time preference that you interpreted as "${displayLabel}". Ask them in ${lang} to confirm: "Do you mean ${displayLabel}?" 1 sentence, natural and friendly. No formatting.`,
|
||||||
`Patient said: "${message}"`,
|
`Patient said: "${message}"`,
|
||||||
fallbacks[lang] ?? fallbacks["English"]!,
|
fallbacks[lang] ?? fallbacks["English"]!,
|
||||||
apiKey,
|
apiKey, provider, model
|
||||||
);
|
);
|
||||||
return { reply: confirmReply, nextStage: "asked_reschedule_confirm_datetime" };
|
return { reply: confirmReply, nextStage: "asked_reschedule_confirm_datetime" };
|
||||||
}
|
}
|
||||||
@@ -636,7 +642,7 @@ export async function runRescheduleStep(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse the time from the patient's reply
|
// Parse the time from the patient's reply
|
||||||
const startTime = await parseTime(message, apiKey);
|
const startTime = await parseTime(message, apiKey, provider, model);
|
||||||
if (!startTime) {
|
if (!startTime) {
|
||||||
const fallbacks: Record<string, string> = {
|
const fallbacks: Record<string, string> = {
|
||||||
English: `I didn't catch the time. What time would you prefer on ${pending.dayLabel}? For example: '10am', '2pm', or '1:30pm'.`,
|
English: `I didn't catch the time. What time would you prefer on ${pending.dayLabel}? For example: '10am', '2pm', or '1:30pm'.`,
|
||||||
@@ -698,7 +704,7 @@ export async function runRescheduleStep(
|
|||||||
`You are a friendly dental office AI assistant. The patient wants ${fullLabel}. Ask them in ${lang} to confirm: "Do you mean ${fullLabel}?" 1 sentence, natural and friendly. No formatting.`,
|
`You are a friendly dental office AI assistant. The patient wants ${fullLabel}. Ask them in ${lang} to confirm: "Do you mean ${fullLabel}?" 1 sentence, natural and friendly. No formatting.`,
|
||||||
`Patient said: "${message}"`,
|
`Patient said: "${message}"`,
|
||||||
fallbacks[lang] ?? fallbacks["English"]!,
|
fallbacks[lang] ?? fallbacks["English"]!,
|
||||||
apiKey,
|
apiKey, provider, model
|
||||||
);
|
);
|
||||||
return { reply: confirmReply, nextStage: "asked_reschedule_confirm_datetime" };
|
return { reply: confirmReply, nextStage: "asked_reschedule_confirm_datetime" };
|
||||||
}
|
}
|
||||||
@@ -812,7 +818,7 @@ export async function runRescheduleStep(
|
|||||||
`You are a friendly dental office AI assistant. The patient's appointment has been successfully moved to ${displayLabel}. Write a warm confirmation message in ${lang}: tell them the appointment is moved to ${displayLabel}, and that our dental receptionist will confirm it with them tomorrow. 2 sentences max, no formatting.`,
|
`You are a friendly dental office AI assistant. The patient's appointment has been successfully moved to ${displayLabel}. Write a warm confirmation message in ${lang}: tell them the appointment is moved to ${displayLabel}, and that our dental receptionist will confirm it with them tomorrow. 2 sentences max, no formatting.`,
|
||||||
`Appointment rescheduled to ${displayLabel}.`,
|
`Appointment rescheduled to ${displayLabel}.`,
|
||||||
fallback,
|
fallback,
|
||||||
apiKey,
|
apiKey, provider, model
|
||||||
);
|
);
|
||||||
return { reply, nextStage: "done" };
|
return { reply, nextStage: "done" };
|
||||||
}
|
}
|
||||||
@@ -832,7 +838,7 @@ export async function runRescheduleStep(
|
|||||||
const fallback = fallbacks[lang] ?? fallbacks["English"]!;
|
const fallback = fallbacks[lang] ?? fallbacks["English"]!;
|
||||||
const reply = await llmReply(
|
const reply = await llmReply(
|
||||||
`You are a friendly dental office assistant. The patient does not want to reschedule. Write a warm, brief closing message in ${lang}. 1 sentence, no formatting.`,
|
`You are a friendly dental office assistant. The patient does not want to reschedule. Write a warm, brief closing message in ${lang}. 1 sentence, no formatting.`,
|
||||||
`Patient said: "${message}"`, fallback, apiKey,
|
`Patient said: "${message}"`, fallback, apiKey, provider, model
|
||||||
);
|
);
|
||||||
return { reply, nextStage: "done" };
|
return { reply, nextStage: "done" };
|
||||||
}
|
}
|
||||||
@@ -844,7 +850,7 @@ export async function runRescheduleStep(
|
|||||||
|
|
||||||
if (hasTime) {
|
if (hasTime) {
|
||||||
// Try to parse full datetime from the message
|
// Try to parse full datetime from the message
|
||||||
const parsed = await parseDatetimeFromMessage(message, apiKey);
|
const parsed = await parseDatetimeFromMessage(message, apiKey, provider, model);
|
||||||
if (parsed) {
|
if (parsed) {
|
||||||
const { date, startTime, displayLabel } = parsed;
|
const { date, startTime, displayLabel } = parsed;
|
||||||
const dayCheck = await isOfficeDayOpen(date, userId);
|
const dayCheck = await isOfficeDayOpen(date, userId);
|
||||||
@@ -873,14 +879,14 @@ export async function runRescheduleStep(
|
|||||||
};
|
};
|
||||||
const confirmReply = await llmReply(
|
const confirmReply = await llmReply(
|
||||||
`You are a friendly dental office AI assistant. The patient mentioned a date/time that you interpreted as "${displayLabel}". Ask them in ${lang} to confirm. 1 sentence, natural and friendly. No formatting.`,
|
`You are a friendly dental office AI assistant. The patient mentioned a date/time that you interpreted as "${displayLabel}". Ask them in ${lang} to confirm. 1 sentence, natural and friendly. No formatting.`,
|
||||||
`Patient said: "${message}"`, fallbacks[lang] ?? fallbacks["English"]!, apiKey,
|
`Patient said: "${message}"`, fallbacks[lang] ?? fallbacks["English"]!, apiKey, provider
|
||||||
);
|
);
|
||||||
return { reply: confirmReply, nextStage: "asked_reschedule_confirm_datetime" };
|
return { reply: confirmReply, nextStage: "asked_reschedule_confirm_datetime" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to parse a date-only from the message
|
// Try to parse a date-only from the message
|
||||||
const parsedDate = await parseDateOnlyFromMessage(message, apiKey);
|
const parsedDate = await parseDateOnlyFromMessage(message, apiKey, provider, model);
|
||||||
if (parsedDate) {
|
if (parsedDate) {
|
||||||
const { date, dateLabel } = parsedDate;
|
const { date, dateLabel } = parsedDate;
|
||||||
const dayCheck = await isOfficeDayOpen(date, userId);
|
const dayCheck = await isOfficeDayOpen(date, userId);
|
||||||
@@ -909,7 +915,7 @@ export async function runRescheduleStep(
|
|||||||
};
|
};
|
||||||
const askTimeReply = await llmReply(
|
const askTimeReply = await llmReply(
|
||||||
`You are a friendly dental office assistant. The patient wants ${dateLabel}. Ask them in ${lang} what time they prefer on that day. 1 sentence, no formatting.`,
|
`You are a friendly dental office assistant. The patient wants ${dateLabel}. Ask them in ${lang} what time they prefer on that day. 1 sentence, no formatting.`,
|
||||||
`Patient wants ${dateLabel} but gave no time.`, fallbacks[lang] ?? fallbacks["English"]!, apiKey,
|
`Patient wants ${dateLabel} but gave no time.`, fallbacks[lang] ?? fallbacks["English"]!, apiKey, provider
|
||||||
);
|
);
|
||||||
return { reply: askTimeReply, nextStage: "asked_reschedule_time_for_date" };
|
return { reply: askTimeReply, nextStage: "asked_reschedule_time_for_date" };
|
||||||
}
|
}
|
||||||
@@ -927,7 +933,7 @@ export async function runRescheduleStep(
|
|||||||
const fallback = fallbacks[lang] ?? fallbacks["English"]!;
|
const fallback = fallbacks[lang] ?? fallbacks["English"]!;
|
||||||
const reply = await llmReply(
|
const reply = await llmReply(
|
||||||
`You are a friendly dental office assistant. The patient wants to reschedule. Ask them in ${lang} what day and time they prefer. Give 1-2 examples like "Monday at 10am" or "next Tuesday afternoon". 1-2 sentences, no formatting.`,
|
`You are a friendly dental office assistant. The patient wants to reschedule. Ask them in ${lang} what day and time they prefer. Give 1-2 examples like "Monday at 10am" or "next Tuesday afternoon". 1-2 sentences, no formatting.`,
|
||||||
`Patient wants to reschedule.`, fallback, apiKey,
|
`Patient wants to reschedule.`, fallback, apiKey, provider, model
|
||||||
);
|
);
|
||||||
return { reply, nextStage: "asked_reschedule_datetime" };
|
return { reply, nextStage: "asked_reschedule_datetime" };
|
||||||
}
|
}
|
||||||
@@ -951,7 +957,7 @@ export async function runRescheduleStep(
|
|||||||
const fallback = fallbacks[lang] ?? fallbacks["English"]!;
|
const fallback = fallbacks[lang] ?? fallbacks["English"]!;
|
||||||
const reply = await llmReply(
|
const reply = await llmReply(
|
||||||
`You are a friendly dental office assistant. Ask the patient in ${lang} if they can come in tomorrow, ${tomorrow}. 1 sentence, no formatting.`,
|
`You are a friendly dental office assistant. Ask the patient in ${lang} if they can come in tomorrow, ${tomorrow}. 1 sentence, no formatting.`,
|
||||||
`Patient wants to reschedule ASAP.`, fallback, apiKey,
|
`Patient wants to reschedule ASAP.`, fallback, apiKey, provider, model
|
||||||
);
|
);
|
||||||
return { reply, nextStage: "asked_reschedule_asap" };
|
return { reply, nextStage: "asked_reschedule_asap" };
|
||||||
}
|
}
|
||||||
@@ -970,7 +976,7 @@ export async function runRescheduleStep(
|
|||||||
const fallback = fallbacks[lang] ?? fallbacks["English"]!;
|
const fallback = fallbacks[lang] ?? fallbacks["English"]!;
|
||||||
const reply = await llmReply(
|
const reply = await llmReply(
|
||||||
`You are a friendly dental office assistant. Offer next week's Monday (${mon}), Tuesday (${tue}), or Wednesday (${wed}) in ${lang}. 1-2 sentences, no formatting.`,
|
`You are a friendly dental office assistant. Offer next week's Monday (${mon}), Tuesday (${tue}), or Wednesday (${wed}) in ${lang}. 1-2 sentences, no formatting.`,
|
||||||
`Patient prefers next week.`, fallback, apiKey,
|
`Patient prefers next week.`, fallback, apiKey, provider, model
|
||||||
);
|
);
|
||||||
return { reply, nextStage: "asked_reschedule_next_week" };
|
return { reply, nextStage: "asked_reschedule_next_week" };
|
||||||
}
|
}
|
||||||
@@ -995,7 +1001,7 @@ export async function runRescheduleStep(
|
|||||||
const fallback = fallbacks[lang] ?? fallbacks["English"]!;
|
const fallback = fallbacks[lang] ?? fallbacks["English"]!;
|
||||||
const reply = await llmReply(
|
const reply = await llmReply(
|
||||||
`You are a friendly dental office assistant. The patient confirmed ${label}. Ask in ${lang} whether they prefer morning (9am-12pm) or afternoon (1pm-5pm). 1 sentence, no formatting.`,
|
`You are a friendly dental office assistant. The patient confirmed ${label}. Ask in ${lang} whether they prefer morning (9am-12pm) or afternoon (1pm-5pm). 1 sentence, no formatting.`,
|
||||||
`Patient confirmed tomorrow.`, fallback, apiKey,
|
`Patient confirmed tomorrow.`, fallback, apiKey, provider, model
|
||||||
);
|
);
|
||||||
return { reply, nextStage: "asked_reschedule_time" };
|
return { reply, nextStage: "asked_reschedule_time" };
|
||||||
}
|
}
|
||||||
@@ -1013,7 +1019,7 @@ export async function runRescheduleStep(
|
|||||||
const fallback = fallbacks[lang] ?? fallbacks["English"]!;
|
const fallback = fallbacks[lang] ?? fallbacks["English"]!;
|
||||||
const reply = await llmReply(
|
const reply = await llmReply(
|
||||||
`You are a friendly dental office assistant. The patient cannot come tomorrow. Offer next week: ${mon}, ${tue}, or ${wed} in ${lang}. 1-2 sentences, no formatting.`,
|
`You are a friendly dental office assistant. The patient cannot come tomorrow. Offer next week: ${mon}, ${tue}, or ${wed} in ${lang}. 1-2 sentences, no formatting.`,
|
||||||
`Patient can't come tomorrow.`, fallback, apiKey,
|
`Patient can't come tomorrow.`, fallback, apiKey, provider, model
|
||||||
);
|
);
|
||||||
return { reply, nextStage: "asked_reschedule_next_week" };
|
return { reply, nextStage: "asked_reschedule_next_week" };
|
||||||
}
|
}
|
||||||
@@ -1043,7 +1049,7 @@ export async function runRescheduleStep(
|
|||||||
const fallback = fallbacks[lang] ?? fallbacks["English"]!;
|
const fallback = fallbacks[lang] ?? fallbacks["English"]!;
|
||||||
const reply = await llmReply(
|
const reply = await llmReply(
|
||||||
`You are a friendly dental office assistant. The patient chose ${day}. Ask in ${lang} whether they prefer morning (9am-12pm) or afternoon (1pm-5pm). 1 sentence, no formatting.`,
|
`You are a friendly dental office assistant. The patient chose ${day}. Ask in ${lang} whether they prefer morning (9am-12pm) or afternoon (1pm-5pm). 1 sentence, no formatting.`,
|
||||||
`Patient chose ${day}.`, fallback, apiKey,
|
`Patient chose ${day}.`, fallback, apiKey, provider, model
|
||||||
);
|
);
|
||||||
return { reply, nextStage: "asked_reschedule_time" };
|
return { reply, nextStage: "asked_reschedule_time" };
|
||||||
}
|
}
|
||||||
@@ -1066,7 +1072,7 @@ export async function runRescheduleStep(
|
|||||||
const pending = getPendingReschedule(userId, patientId);
|
const pending = getPendingReschedule(userId, patientId);
|
||||||
if (!pending) return { reply: tx, nextStage: "done" };
|
if (!pending) return { reply: tx, nextStage: "done" };
|
||||||
|
|
||||||
const startTime = await parseTime(message, apiKey);
|
const startTime = await parseTime(message, apiKey, provider, model);
|
||||||
if (!startTime) {
|
if (!startTime) {
|
||||||
const fallbacks: Record<string, string> = {
|
const fallbacks: Record<string, string> = {
|
||||||
English: "I didn't catch the time. Would you prefer morning (9am–12pm) or afternoon (1pm–5pm)?",
|
English: "I didn't catch the time. Would you prefer morning (9am–12pm) or afternoon (1pm–5pm)?",
|
||||||
@@ -1101,7 +1107,7 @@ export async function runRescheduleStep(
|
|||||||
const fallback = `Your appointment has been moved to ${apptLabel}. Our dental receptionist will confirm it with you tomorrow.`;
|
const fallback = `Your appointment has been moved to ${apptLabel}. Our dental receptionist will confirm it with you tomorrow.`;
|
||||||
const reply = await llmReply(
|
const reply = await llmReply(
|
||||||
`You are a friendly dental office assistant. The patient's appointment has been rescheduled to ${apptLabel}. Confirm in ${lang}: say the appointment is moved to ${apptLabel} and that our dental receptionist will confirm it with them tomorrow. 2 sentences, no formatting.`,
|
`You are a friendly dental office assistant. The patient's appointment has been rescheduled to ${apptLabel}. Confirm in ${lang}: say the appointment is moved to ${apptLabel} and that our dental receptionist will confirm it with them tomorrow. 2 sentences, no formatting.`,
|
||||||
`Appointment moved to ${apptLabel}.`, fallback, apiKey,
|
`Appointment moved to ${apptLabel}.`, fallback, apiKey, provider, model
|
||||||
);
|
);
|
||||||
return { reply, nextStage: "done" };
|
return { reply, nextStage: "done" };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import express, { Request, Response } from "express";
|
|||||||
import { storage } from "../storage";
|
import { storage } from "../storage";
|
||||||
import { classifyInternalChat } from "../ai/internal-chat-graph";
|
import { classifyInternalChat } from "../ai/internal-chat-graph";
|
||||||
import { runInternalChatWorkflow } from "../ai/internal-chat-workflow";
|
import { runInternalChatWorkflow } from "../ai/internal-chat-workflow";
|
||||||
|
import { resolveAiProvider } from "../ai/llm-factory";
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@@ -20,8 +21,11 @@ router.get("/settings", async (req: Request, res: Response): Promise<any> => {
|
|||||||
aiEnabled: settings.aiEnabled ?? true,
|
aiEnabled: settings.aiEnabled ?? true,
|
||||||
openAiKey: settings.openAiKey ?? "",
|
openAiKey: settings.openAiKey ?? "",
|
||||||
openAiEnabled: settings.openAiEnabled ?? false,
|
openAiEnabled: settings.openAiEnabled ?? false,
|
||||||
|
openAiModel: settings.openAiModel ?? "gpt-5.2",
|
||||||
claudeAiKey: settings.claudeAiKey ?? "",
|
claudeAiKey: settings.claudeAiKey ?? "",
|
||||||
claudeAiEnabled: settings.claudeAiEnabled ?? false,
|
claudeAiEnabled: settings.claudeAiEnabled ?? false,
|
||||||
|
claudeAiModel: settings.claudeAiModel ?? "claude-haiku-4-5-20251001",
|
||||||
|
googleAiModel: settings.googleAiModel ?? "gemini-2.5-flash",
|
||||||
dentalMgmtKey: settings.dentalMgmtKey ?? "",
|
dentalMgmtKey: settings.dentalMgmtKey ?? "",
|
||||||
dentalMgmtEnabled: settings.dentalMgmtEnabled ?? false,
|
dentalMgmtEnabled: settings.dentalMgmtEnabled ?? false,
|
||||||
openPhoneReply: settings.openPhoneReply ?? false,
|
openPhoneReply: settings.openPhoneReply ?? false,
|
||||||
@@ -109,6 +113,27 @@ router.put("/provider-enabled", async (req: Request, res: Response): Promise<any
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// PUT /api/ai/provider-model
|
||||||
|
router.put("/provider-model", async (req: Request, res: Response): Promise<any> => {
|
||||||
|
try {
|
||||||
|
const userId = req.user?.id;
|
||||||
|
if (!userId) return res.status(401).json({ message: "Unauthorized" });
|
||||||
|
|
||||||
|
const { provider, model } = req.body;
|
||||||
|
if (!["claudeAi", "openAi", "googleAi"].includes(provider)) {
|
||||||
|
return res.status(400).json({ message: "Invalid provider" });
|
||||||
|
}
|
||||||
|
if (!model?.trim()) {
|
||||||
|
return res.status(400).json({ message: "model is required" });
|
||||||
|
}
|
||||||
|
|
||||||
|
await storage.setProviderModel(userId, provider, model.trim());
|
||||||
|
return res.status(200).json({ provider, model: model.trim() });
|
||||||
|
} catch (err) {
|
||||||
|
return res.status(500).json({ error: "Failed to save provider model", details: String(err) });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// GET /api/ai/advanced-settings
|
// GET /api/ai/advanced-settings
|
||||||
router.get("/advanced-settings", async (req: Request, res: Response): Promise<any> => {
|
router.get("/advanced-settings", async (req: Request, res: Response): Promise<any> => {
|
||||||
try {
|
try {
|
||||||
@@ -236,9 +261,10 @@ router.post("/internal-chat", async (req: Request, res: Response): Promise<any>
|
|||||||
if (!message?.trim()) return res.status(400).json({ message: "message is required" });
|
if (!message?.trim()) return res.status(400).json({ message: "message is required" });
|
||||||
|
|
||||||
const aiSettings = await storage.getAiSettings(userId);
|
const aiSettings = await storage.getAiSettings(userId);
|
||||||
if (!aiSettings?.apiKey) {
|
const activeAi = resolveAiProvider(aiSettings ?? {});
|
||||||
|
if (!activeAi) {
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
reply: "AI is not configured. Please add a Google AI API key in Settings.",
|
reply: "AI is not configured. Please add an API key in AI Settings.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,9 +275,11 @@ router.post("/internal-chat", async (req: Request, res: Response): Promise<any>
|
|||||||
|
|
||||||
const classification = await classifyInternalChat(
|
const classification = await classifyInternalChat(
|
||||||
message.trim(),
|
message.trim(),
|
||||||
aiSettings.apiKey,
|
activeAi.key,
|
||||||
extraSystemPrompt || undefined,
|
extraSystemPrompt || undefined,
|
||||||
Array.isArray(history) ? history : []
|
Array.isArray(history) ? history : [],
|
||||||
|
activeAi.provider,
|
||||||
|
activeAi.model
|
||||||
);
|
);
|
||||||
|
|
||||||
const response = await runInternalChatWorkflow(classification, userId, storage, customAliases);
|
const response = await runInternalChatWorkflow(classification, userId, storage, customAliases);
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
getOfficeHoursDisplay,
|
getOfficeHoursDisplay,
|
||||||
timeLabel,
|
timeLabel,
|
||||||
} from "../ai/reschedule-graph";
|
} from "../ai/reschedule-graph";
|
||||||
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
|
import { getLlm, resolveAiProvider } from "../ai/llm-factory";
|
||||||
import { runEligibilityProcessor } from "../queue/processors/eligibilityProcessor";
|
import { runEligibilityProcessor } from "../queue/processors/eligibilityProcessor";
|
||||||
import {
|
import {
|
||||||
getHandoff, getAfterHoursHandoff,
|
getHandoff, getAfterHoursHandoff,
|
||||||
@@ -109,7 +109,9 @@ function normalizeDob(raw: string): string {
|
|||||||
|
|
||||||
async function parseMassHealthInfo(
|
async function parseMassHealthInfo(
|
||||||
message: string,
|
message: string,
|
||||||
apiKey: string
|
apiKey: string,
|
||||||
|
provider: import("../ai/llm-factory").AiProvider = "google",
|
||||||
|
model?: string
|
||||||
): Promise<{ memberId: string | null; dob: string | null }> {
|
): Promise<{ memberId: string | null; dob: string | null }> {
|
||||||
// Regex: member IDs are typically 8-12 digits; DOB as MM/DD/YYYY or similar
|
// Regex: member IDs are typically 8-12 digits; DOB as MM/DD/YYYY or similar
|
||||||
const idMatch = message.match(/\b(\d{8,12})\b/);
|
const idMatch = message.match(/\b(\d{8,12})\b/);
|
||||||
@@ -123,7 +125,7 @@ async function parseMassHealthInfo(
|
|||||||
|
|
||||||
// Fall back to LLM structured extraction
|
// Fall back to LLM structured extraction
|
||||||
try {
|
try {
|
||||||
const llm = new ChatGoogleGenerativeAI({ model: "gemini-1.5-flash", apiKey });
|
const llm = getLlm(provider, apiKey, model);
|
||||||
const res = await llm.invoke([
|
const res = await llm.invoke([
|
||||||
{
|
{
|
||||||
role: "system",
|
role: "system",
|
||||||
@@ -332,7 +334,8 @@ router.post("/webhook/sms", async (req: Request, res: Response): Promise<any> =>
|
|||||||
|
|
||||||
// Fetch required context for this office
|
// Fetch required context for this office
|
||||||
const aiSettings = await storage.getAiSettings(userId);
|
const aiSettings = await storage.getAiSettings(userId);
|
||||||
if (!aiSettings?.apiKey) {
|
const activeAiU = resolveAiProvider(aiSettings ?? {});
|
||||||
|
if (!activeAiU) {
|
||||||
res.set("Content-Type", "text/xml");
|
res.set("Content-Type", "text/xml");
|
||||||
return res.send(empty());
|
return res.send(empty());
|
||||||
}
|
}
|
||||||
@@ -445,7 +448,7 @@ router.post("/webhook/sms", async (req: Request, res: Response): Promise<any> =>
|
|||||||
|
|
||||||
// ── Unknown: asked_appointment_time → parse date, check office hours ──
|
// ── Unknown: asked_appointment_time → parse date, check office hours ──
|
||||||
if (stage === "asked_appointment_time") {
|
if (stage === "asked_appointment_time") {
|
||||||
const parsedDate = await parseDateOnlyFromMessage(Body, aiSettings.apiKey);
|
const parsedDate = await parseDateOnlyFromMessage(Body, activeAiU.key, activeAiU.provider, activeAiU.model);
|
||||||
if (!parsedDate) {
|
if (!parsedDate) {
|
||||||
const msgs: Record<string, string> = {
|
const msgs: Record<string, string> = {
|
||||||
English: "I didn't catch that. What day would you prefer? For example: 'May 28', 'next Monday', or '5/28'.",
|
English: "I didn't catch that. What day would you prefer? For example: 'May 28', 'next Monday', or '5/28'.",
|
||||||
@@ -497,7 +500,7 @@ router.post("/webhook/sms", async (req: Request, res: Response): Promise<any> =>
|
|||||||
"asked_appointment_time",
|
"asked_appointment_time",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const startTime = await parseTime(Body, aiSettings.apiKey);
|
const startTime = await parseTime(Body, activeAiU.key, activeAiU.provider, activeAiU.model);
|
||||||
if (!startTime) {
|
if (!startTime) {
|
||||||
const msgs: Record<string, string> = {
|
const msgs: Record<string, string> = {
|
||||||
English: `I didn't catch the time. What time do you prefer on ${pendingApptDate.dateLabel}? For example: '10am' or '2pm'.`,
|
English: `I didn't catch the time. What time do you prefer on ${pendingApptDate.dateLabel}? For example: '10am' or '2pm'.`,
|
||||||
@@ -563,7 +566,7 @@ router.post("/webhook/sms", async (req: Request, res: Response): Promise<any> =>
|
|||||||
];
|
];
|
||||||
if (unknownNewPatientStages.includes(stage)) {
|
if (unknownNewPatientStages.includes(stage)) {
|
||||||
const { reply: aiReply, nextStage } = await runNewPatientStep(
|
const { reply: aiReply, nextStage } = await runNewPatientStep(
|
||||||
Body, stage, language, aiSettings.apiKey, chatTemplates.generalFallback
|
Body, stage, language, activeAiU.key, chatTemplates.generalFallback, activeAiU.provider, activeAiU.model
|
||||||
);
|
);
|
||||||
return replyUnknown(aiReply, nextStage);
|
return replyUnknown(aiReply, nextStage);
|
||||||
}
|
}
|
||||||
@@ -585,7 +588,8 @@ router.post("/webhook/sms", async (req: Request, res: Response): Promise<any> =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
const aiSettings = await storage.getAiSettings(patient.userId);
|
const aiSettings = await storage.getAiSettings(patient.userId);
|
||||||
if (!aiSettings?.apiKey) {
|
const activeAi = resolveAiProvider(aiSettings ?? {});
|
||||||
|
if (!activeAi) {
|
||||||
res.set("Content-Type", "text/xml");
|
res.set("Content-Type", "text/xml");
|
||||||
return res.send(empty());
|
return res.send(empty());
|
||||||
}
|
}
|
||||||
@@ -626,8 +630,8 @@ router.post("/webhook/sms", async (req: Request, res: Response): Promise<any> =>
|
|||||||
// Use Google AI (LangGraph) to read the patient's reply and classify yes/no
|
// Use Google AI (LangGraph) to read the patient's reply and classify yes/no
|
||||||
const apptDatetime = await getAppointmentDatetime(patient.id);
|
const apptDatetime = await getAppointmentDatetime(patient.id);
|
||||||
const { reply: intentReply, intent } = await runReminderGraph(
|
const { reply: intentReply, intent } = await runReminderGraph(
|
||||||
Body, aiSettings.apiKey, language, apptDatetime,
|
Body, activeAi.key, language, apptDatetime,
|
||||||
chatTemplates.rescheduleGreeting, chatTemplates.generalFallback
|
chatTemplates.rescheduleGreeting, chatTemplates.generalFallback, activeAi.provider, activeAi.model
|
||||||
);
|
);
|
||||||
|
|
||||||
if (intentReply) {
|
if (intentReply) {
|
||||||
@@ -652,7 +656,7 @@ router.post("/webhook/sms", async (req: Request, res: Response): Promise<any> =>
|
|||||||
/\b(monday|tuesday|wednesday|thursday|friday|saturday|sunday|tomorrow|next week)\b/i.test(Body);
|
/\b(monday|tuesday|wednesday|thursday|friday|saturday|sunday|tomorrow|next week)\b/i.test(Body);
|
||||||
if (hasDateInMessage) {
|
if (hasDateInMessage) {
|
||||||
const { reply: rescheduleReply, nextStage: rescheduleNextStage } = await runRescheduleStep(
|
const { reply: rescheduleReply, nextStage: rescheduleNextStage } = await runRescheduleStep(
|
||||||
Body, "asked_reschedule_datetime", language, patient.id, aiSettings.apiKey, patient.userId
|
Body, "asked_reschedule_datetime", language, patient.id, activeAi.key, patient.userId, activeAi.provider, activeAi.model
|
||||||
);
|
);
|
||||||
return reply(rescheduleReply, rescheduleNextStage);
|
return reply(rescheduleReply, rescheduleNextStage);
|
||||||
}
|
}
|
||||||
@@ -670,8 +674,8 @@ router.post("/webhook/sms", async (req: Request, res: Response): Promise<any> =>
|
|||||||
if (stage === "greeted") {
|
if (stage === "greeted") {
|
||||||
const apptDatetime = await getAppointmentDatetime(patient.id);
|
const apptDatetime = await getAppointmentDatetime(patient.id);
|
||||||
const { reply: aiReply, intent } = await runReminderGraph(
|
const { reply: aiReply, intent } = await runReminderGraph(
|
||||||
Body, aiSettings.apiKey, language, apptDatetime,
|
Body, activeAi.key, language, apptDatetime,
|
||||||
chatTemplates.rescheduleGreeting, chatTemplates.generalFallback
|
chatTemplates.rescheduleGreeting, chatTemplates.generalFallback, activeAi.provider, activeAi.model
|
||||||
);
|
);
|
||||||
if (aiReply) {
|
if (aiReply) {
|
||||||
let nextStage: ConversationStage;
|
let nextStage: ConversationStage;
|
||||||
@@ -686,7 +690,7 @@ router.post("/webhook/sms", async (req: Request, res: Response): Promise<any> =>
|
|||||||
/\b(monday|tuesday|wednesday|thursday|friday|saturday|sunday|tomorrow|next week)\b/i.test(Body);
|
/\b(monday|tuesday|wednesday|thursday|friday|saturday|sunday|tomorrow|next week)\b/i.test(Body);
|
||||||
if (hasDateInMessage) {
|
if (hasDateInMessage) {
|
||||||
const { reply: rescheduleReply, nextStage: rescheduleNextStage } = await runRescheduleStep(
|
const { reply: rescheduleReply, nextStage: rescheduleNextStage } = await runRescheduleStep(
|
||||||
Body, "asked_reschedule_datetime", language, patient.id, aiSettings.apiKey, patient.userId
|
Body, "asked_reschedule_datetime", language, patient.id, activeAi.key, patient.userId, activeAi.provider, activeAi.model
|
||||||
);
|
);
|
||||||
return reply(rescheduleReply, rescheduleNextStage);
|
return reply(rescheduleReply, rescheduleNextStage);
|
||||||
}
|
}
|
||||||
@@ -705,14 +709,14 @@ router.post("/webhook/sms", async (req: Request, res: Response): Promise<any> =>
|
|||||||
];
|
];
|
||||||
if (rescheduleStages.includes(stage)) {
|
if (rescheduleStages.includes(stage)) {
|
||||||
const { reply: aiReply, nextStage } = await runRescheduleStep(
|
const { reply: aiReply, nextStage } = await runRescheduleStep(
|
||||||
Body, stage, language, patient.id, aiSettings.apiKey, patient.userId
|
Body, stage, language, patient.id, activeAi.key, patient.userId, activeAi.provider, activeAi.model
|
||||||
);
|
);
|
||||||
return reply(aiReply, nextStage);
|
return reply(aiReply, nextStage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Stage: awaiting MassHealth member ID + DOB ────────────────────────
|
// ── Stage: awaiting MassHealth member ID + DOB ────────────────────────
|
||||||
if (stage === "awaiting_masshealth_info") {
|
if (stage === "awaiting_masshealth_info") {
|
||||||
const { memberId, dob } = await parseMassHealthInfo(Body, aiSettings.apiKey);
|
const { memberId, dob } = await parseMassHealthInfo(Body, activeAi.key, activeAi.provider, activeAi.model);
|
||||||
|
|
||||||
if (!memberId || !dob) {
|
if (!memberId || !dob) {
|
||||||
// Couldn't parse — ask again with a clearer format hint
|
// Couldn't parse — ask again with a clearer format hint
|
||||||
@@ -748,7 +752,7 @@ router.post("/webhook/sms", async (req: Request, res: Response): Promise<any> =>
|
|||||||
res.send(twimlReply(checkingMsg));
|
res.send(twimlReply(checkingMsg));
|
||||||
|
|
||||||
// Fire-and-forget: run check and send result SMS when complete
|
// Fire-and-forget: run check and send result SMS when complete
|
||||||
runMassHealthCheckAndNotify(patient, memberId, dob, aiSettings.apiKey).catch(() => {});
|
runMassHealthCheckAndNotify(patient, memberId, dob, activeAi.key).catch(() => {});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -797,7 +801,7 @@ router.post("/webhook/sms", async (req: Request, res: Response): Promise<any> =>
|
|||||||
|
|
||||||
// Fire-and-forget Selenium check; existing patient gets simpler result
|
// Fire-and-forget Selenium check; existing patient gets simpler result
|
||||||
runMassHealthCheckAndNotify(
|
runMassHealthCheckAndNotify(
|
||||||
patient, patientRecord.insuranceId, dobStr, aiSettings.apiKey, true
|
patient, patientRecord.insuranceId, dobStr, activeAi.key, true
|
||||||
).catch(() => {});
|
).catch(() => {});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -852,7 +856,7 @@ router.post("/webhook/sms", async (req: Request, res: Response): Promise<any> =>
|
|||||||
|
|
||||||
// ── Stage: asked_appointment_time → parse date, check office hours ───
|
// ── Stage: asked_appointment_time → parse date, check office hours ───
|
||||||
if (stage === "asked_appointment_time") {
|
if (stage === "asked_appointment_time") {
|
||||||
const parsedDate = await parseDateOnlyFromMessage(Body, aiSettings.apiKey);
|
const parsedDate = await parseDateOnlyFromMessage(Body, activeAi.key, activeAi.provider, activeAi.model);
|
||||||
if (!parsedDate) {
|
if (!parsedDate) {
|
||||||
const msgs: Record<string, string> = {
|
const msgs: Record<string, string> = {
|
||||||
English: "I didn't catch that. What day would you prefer? For example: 'May 28', 'next Monday', or '5/28'.",
|
English: "I didn't catch that. What day would you prefer? For example: 'May 28', 'next Monday', or '5/28'.",
|
||||||
@@ -899,7 +903,7 @@ router.post("/webhook/sms", async (req: Request, res: Response): Promise<any> =>
|
|||||||
if (!pending) {
|
if (!pending) {
|
||||||
return reply("I lost track of the date. What day would you prefer?", "asked_appointment_time");
|
return reply("I lost track of the date. What day would you prefer?", "asked_appointment_time");
|
||||||
}
|
}
|
||||||
const startTime = await parseTime(Body, aiSettings.apiKey);
|
const startTime = await parseTime(Body, activeAi.key, activeAi.provider, activeAi.model);
|
||||||
if (!startTime) {
|
if (!startTime) {
|
||||||
const msgs: Record<string, string> = {
|
const msgs: Record<string, string> = {
|
||||||
English: `I didn't catch the time. What time do you prefer on ${pending.dayLabel}? For example: '10am' or '2pm'.`,
|
English: `I didn't catch the time. What time do you prefer on ${pending.dayLabel}? For example: '10am' or '2pm'.`,
|
||||||
@@ -1002,7 +1006,7 @@ router.post("/webhook/sms", async (req: Request, res: Response): Promise<any> =>
|
|||||||
];
|
];
|
||||||
if (newPatientStages.includes(stage)) {
|
if (newPatientStages.includes(stage)) {
|
||||||
const { reply: aiReply, nextStage } = await runNewPatientStep(
|
const { reply: aiReply, nextStage } = await runNewPatientStep(
|
||||||
Body, stage, language, aiSettings.apiKey, chatTemplates.generalFallback
|
Body, stage, language, activeAi.key, chatTemplates.generalFallback, activeAi.provider, activeAi.model
|
||||||
);
|
);
|
||||||
return reply(aiReply, nextStage);
|
return reply(aiReply, nextStage);
|
||||||
}
|
}
|
||||||
@@ -1038,10 +1042,9 @@ router.post("/webhook/sms", async (req: Request, res: Response): Promise<any> =>
|
|||||||
: `Mèsi dèske ou chwazi nou! N'ap tann ou byento.`,
|
: `Mèsi dèske ou chwazi nou! N'ap tann ou byento.`,
|
||||||
};
|
};
|
||||||
const fallback = CLOSING[language] ?? CLOSING["English"]!;
|
const fallback = CLOSING[language] ?? CLOSING["English"]!;
|
||||||
if (aiSettings?.apiKey && apptDatetime) {
|
if (apptDatetime) {
|
||||||
try {
|
try {
|
||||||
const { ChatGoogleGenerativeAI } = await import("@langchain/google-genai");
|
const llm = getLlm(activeAi.provider, activeAi.key, activeAi.model);
|
||||||
const llm = new ChatGoogleGenerativeAI({ model: "gemini-1.5-flash", apiKey: aiSettings.apiKey });
|
|
||||||
const res = await llm.invoke([
|
const res = await llm.invoke([
|
||||||
{
|
{
|
||||||
role: "system",
|
role: "system",
|
||||||
|
|||||||
@@ -30,6 +30,15 @@ export const aiSettingsStorage = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async setProviderModel(userId: number, provider: "claudeAi" | "openAi" | "googleAi", model: string): Promise<void> {
|
||||||
|
const field = provider === "claudeAi" ? "claudeAiModel" : provider === "openAi" ? "openAiModel" : "googleAiModel";
|
||||||
|
await db.aiSettings.upsert({
|
||||||
|
where: { userId },
|
||||||
|
update: { [field]: model },
|
||||||
|
create: { userId, apiKey: "", [field]: model },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
async setProviderEnabled(userId: number, provider: "openAi" | "claudeAi" | "dentalMgmt", enabled: boolean): Promise<void> {
|
async setProviderEnabled(userId: number, provider: "openAi" | "claudeAi" | "dentalMgmt", enabled: boolean): Promise<void> {
|
||||||
const field = provider === "openAi" ? "openAiEnabled" : provider === "claudeAi" ? "claudeAiEnabled" : "dentalMgmtEnabled";
|
const field = provider === "openAi" ? "openAiEnabled" : provider === "claudeAi" ? "claudeAiEnabled" : "dentalMgmtEnabled";
|
||||||
await db.aiSettings.upsert({
|
await db.aiSettings.upsert({
|
||||||
|
|||||||
@@ -13,13 +13,17 @@ type AiSettings = {
|
|||||||
aiEnabled: boolean;
|
aiEnabled: boolean;
|
||||||
openAiKey: string;
|
openAiKey: string;
|
||||||
openAiEnabled: boolean;
|
openAiEnabled: boolean;
|
||||||
|
openAiModel: string;
|
||||||
claudeAiKey: string;
|
claudeAiKey: string;
|
||||||
claudeAiEnabled: boolean;
|
claudeAiEnabled: boolean;
|
||||||
|
claudeAiModel: string;
|
||||||
|
googleAiModel: string;
|
||||||
dentalMgmtKey: string;
|
dentalMgmtKey: string;
|
||||||
dentalMgmtEnabled: boolean;
|
dentalMgmtEnabled: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Provider = "openAi" | "claudeAi" | "dentalMgmt";
|
type Provider = "openAi" | "claudeAi" | "dentalMgmt";
|
||||||
|
type ModelProvider = "claudeAi" | "openAi" | "googleAi";
|
||||||
|
|
||||||
function ApiKeySection({
|
function ApiKeySection({
|
||||||
title,
|
title,
|
||||||
@@ -31,6 +35,9 @@ function ApiKeySection({
|
|||||||
onToggle,
|
onToggle,
|
||||||
isSaving,
|
isSaving,
|
||||||
isToggling,
|
isToggling,
|
||||||
|
modelOptions,
|
||||||
|
selectedModel,
|
||||||
|
onModelChange,
|
||||||
}: {
|
}: {
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
@@ -41,6 +48,9 @@ function ApiKeySection({
|
|||||||
onToggle: (enabled: boolean) => void;
|
onToggle: (enabled: boolean) => void;
|
||||||
isSaving: boolean;
|
isSaving: boolean;
|
||||||
isToggling: boolean;
|
isToggling: boolean;
|
||||||
|
modelOptions?: { value: string; label: string }[];
|
||||||
|
selectedModel?: string;
|
||||||
|
onModelChange?: (model: string) => void;
|
||||||
}) {
|
}) {
|
||||||
const [localKey, setLocalKey] = useState(apiKey);
|
const [localKey, setLocalKey] = useState(apiKey);
|
||||||
const [showKey, setShowKey] = useState(false);
|
const [showKey, setShowKey] = useState(false);
|
||||||
@@ -68,6 +78,21 @@ function ApiKeySection({
|
|||||||
|
|
||||||
<p className="text-sm text-gray-500">{description}</p>
|
<p className="text-sm text-gray-500">{description}</p>
|
||||||
|
|
||||||
|
{modelOptions && onModelChange && (
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium mb-1">Model</label>
|
||||||
|
<select
|
||||||
|
value={selectedModel}
|
||||||
|
onChange={(e) => onModelChange(e.target.value)}
|
||||||
|
className="p-2 border rounded w-full text-sm bg-white"
|
||||||
|
>
|
||||||
|
{modelOptions.map((opt) => (
|
||||||
|
<option key={opt.value} value={opt.value}>{opt.label}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium">API Key</label>
|
<label className="block text-sm font-medium">API Key</label>
|
||||||
<div className="relative mt-1">
|
<div className="relative mt-1">
|
||||||
@@ -168,6 +193,21 @@ export function AiSettingsCard() {
|
|||||||
onError: (err: any) => toast({ title: "Error", description: err?.message, variant: "destructive" }),
|
onError: (err: any) => toast({ title: "Error", description: err?.message, variant: "destructive" }),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Provider model change
|
||||||
|
const providerModelMutation = useMutation({
|
||||||
|
mutationFn: async ({ provider, model }: { provider: ModelProvider; model: string }) => {
|
||||||
|
const res = await apiRequest("PUT", "/api/ai/provider-model", { provider, model });
|
||||||
|
if (!res.ok) throw new Error((await res.json().catch(() => null))?.message || "Failed");
|
||||||
|
return { provider, model };
|
||||||
|
},
|
||||||
|
onSuccess: ({ provider, model }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["/api/ai/settings"] });
|
||||||
|
const names: Record<string, string> = { claudeAi: "Claude AI", openAi: "OpenAI" };
|
||||||
|
toast({ title: "Model updated", description: `${names[provider]} model set to ${model}.` });
|
||||||
|
},
|
||||||
|
onError: (err: any) => toast({ title: "Error", description: err?.message, variant: "destructive" }),
|
||||||
|
});
|
||||||
|
|
||||||
// Provider toggle
|
// Provider toggle
|
||||||
const providerToggleMutation = useMutation({
|
const providerToggleMutation = useMutation({
|
||||||
mutationFn: async ({ provider, enabled }: { provider: Provider; enabled: boolean }) => {
|
mutationFn: async ({ provider, enabled }: { provider: Provider; enabled: boolean }) => {
|
||||||
@@ -183,6 +223,28 @@ export function AiSettingsCard() {
|
|||||||
onError: (err: any) => toast({ title: "Error", description: err?.message, variant: "destructive" }),
|
onError: (err: any) => toast({ title: "Error", description: err?.message, variant: "destructive" }),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const CLAUDE_MODELS = [
|
||||||
|
{ value: "claude-haiku-4-5-20251001", label: "Claude Haiku 4.5 — Fast & affordable" },
|
||||||
|
{ value: "claude-sonnet-4-6", label: "Claude Sonnet 4.6 — Balanced" },
|
||||||
|
{ value: "claude-opus-4-8", label: "Claude Opus 4.8 — Most capable" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const OPENAI_MODELS = [
|
||||||
|
{ value: "gpt-5.2", label: "GPT-5.2 — Standard (recommended)" },
|
||||||
|
{ value: "gpt-5.2-pro", label: "GPT-5.2 Pro — Professional grade" },
|
||||||
|
{ value: "gpt-5.4", label: "GPT-5.4 — Previous gen, high quality" },
|
||||||
|
{ value: "gpt-5.4-pro", label: "GPT-5.4 Pro — Previous gen pro" },
|
||||||
|
{ value: "gpt-5.5", label: "GPT-5.5 — Flagship, complex tasks" },
|
||||||
|
{ value: "gpt-5.5-pro", label: "GPT-5.5 Pro — Flagship professional" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const GOOGLE_MODELS = [
|
||||||
|
{ value: "gemini-2.5-flash", label: "Gemini 2.5 Flash — Fast & balanced (recommended)" },
|
||||||
|
{ value: "gemini-2.5-pro", label: "Gemini 2.5 Pro — High capability, 1M context" },
|
||||||
|
{ value: "gemini-3.1-flash-lite", label: "Gemini 3.1 Flash Lite — Optimized for speed/cost" },
|
||||||
|
{ value: "gemini-3.5-flash", label: "Gemini 3.5 Flash — Latest frontier" },
|
||||||
|
];
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <Card><CardContent className="py-6"><p className="text-sm text-gray-400">Loading...</p></CardContent></Card>;
|
return <Card><CardContent className="py-6"><p className="text-sm text-gray-400">Loading...</p></CardContent></Card>;
|
||||||
}
|
}
|
||||||
@@ -214,6 +276,18 @@ export function AiSettingsCard() {
|
|||||||
<p className="text-sm text-gray-500">
|
<p className="text-sm text-gray-500">
|
||||||
Enter your Google AI Studio API key to enable AI-powered SMS replies.
|
Enter your Google AI Studio API key to enable AI-powered SMS replies.
|
||||||
</p>
|
</p>
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium mb-1">Model</label>
|
||||||
|
<select
|
||||||
|
value={settings?.googleAiModel ?? "gemini-2.5-flash"}
|
||||||
|
onChange={(e) => providerModelMutation.mutate({ provider: "googleAi", model: e.target.value })}
|
||||||
|
className="p-2 border rounded w-full text-sm bg-white"
|
||||||
|
>
|
||||||
|
{GOOGLE_MODELS.map((opt) => (
|
||||||
|
<option key={opt.value} value={opt.value}>{opt.label}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium">Google AI Studio API Key</label>
|
<label className="block text-sm font-medium">Google AI Studio API Key</label>
|
||||||
<div className="relative mt-1">
|
<div className="relative mt-1">
|
||||||
@@ -263,6 +337,9 @@ export function AiSettingsCard() {
|
|||||||
onToggle={(v) => providerToggleMutation.mutate({ provider: "openAi", enabled: v })}
|
onToggle={(v) => providerToggleMutation.mutate({ provider: "openAi", enabled: v })}
|
||||||
isSaving={providerKeyMutation.isPending && (providerKeyMutation.variables as any)?.provider === "openAi"}
|
isSaving={providerKeyMutation.isPending && (providerKeyMutation.variables as any)?.provider === "openAi"}
|
||||||
isToggling={providerToggleMutation.isPending && (providerToggleMutation.variables as any)?.provider === "openAi"}
|
isToggling={providerToggleMutation.isPending && (providerToggleMutation.variables as any)?.provider === "openAi"}
|
||||||
|
modelOptions={OPENAI_MODELS}
|
||||||
|
selectedModel={settings?.openAiModel ?? "gpt-4o-mini"}
|
||||||
|
onModelChange={(model) => providerModelMutation.mutate({ provider: "openAi", model })}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Separator />
|
<Separator />
|
||||||
@@ -278,6 +355,9 @@ export function AiSettingsCard() {
|
|||||||
onToggle={(v) => providerToggleMutation.mutate({ provider: "claudeAi", enabled: v })}
|
onToggle={(v) => providerToggleMutation.mutate({ provider: "claudeAi", enabled: v })}
|
||||||
isSaving={providerKeyMutation.isPending && (providerKeyMutation.variables as any)?.provider === "claudeAi"}
|
isSaving={providerKeyMutation.isPending && (providerKeyMutation.variables as any)?.provider === "claudeAi"}
|
||||||
isToggling={providerToggleMutation.isPending && (providerToggleMutation.variables as any)?.provider === "claudeAi"}
|
isToggling={providerToggleMutation.isPending && (providerToggleMutation.variables as any)?.provider === "claudeAi"}
|
||||||
|
modelOptions={CLAUDE_MODELS}
|
||||||
|
selectedModel={settings?.claudeAiModel ?? "claude-haiku-4-5-20251001"}
|
||||||
|
onModelChange={(model) => providerModelMutation.mutate({ provider: "claudeAi", model })}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Separator />
|
<Separator />
|
||||||
|
|||||||
Generated
+118
-43
@@ -38,8 +38,10 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@google/generative-ai": "^0.24.1",
|
"@google/generative-ai": "^0.24.1",
|
||||||
|
"@langchain/anthropic": "^1.4.0",
|
||||||
"@langchain/google-genai": "^2.1.30",
|
"@langchain/google-genai": "^2.1.30",
|
||||||
"@langchain/langgraph": "^1.2.9",
|
"@langchain/langgraph": "^1.2.9",
|
||||||
|
"@langchain/openai": "^1.4.7",
|
||||||
"archiver": "^7.0.1",
|
"archiver": "^7.0.1",
|
||||||
"axios": "^1.9.0",
|
"axios": "^1.9.0",
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
@@ -220,6 +222,27 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@anthropic-ai/sdk": {
|
||||||
|
"version": "0.95.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.95.2.tgz",
|
||||||
|
"integrity": "sha512-Egddwo3sheo1PzUrMkZnH6VkQYwS0h/b/i8vSK8Ta9M45UQipAMeDFH57dYuDAfXMEUUGeKw6CMlremgMZgrSQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"json-schema-to-ts": "^3.1.1",
|
||||||
|
"standardwebhooks": "^1.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"anthropic-ai-sdk": "bin/cli"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"zod": "^3.25.0 || ^4.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"zod": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
"version": "7.29.0",
|
"version": "7.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
|
||||||
@@ -1389,18 +1412,31 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@langchain/anthropic": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@langchain/anthropic/-/anthropic-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-rs1yVydrHjyiD31uChdCnKZpmDuKa0Bpz8Raiy9GvqnqmfXPMe0oOrap/2paE+NRSinDbtax8mMpP/yv8EbO1A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@anthropic-ai/sdk": "^0.95.1",
|
||||||
|
"zod": "^3.25.76 || ^4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@langchain/core": "^1.1.47"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@langchain/core": {
|
"node_modules/@langchain/core": {
|
||||||
"version": "1.1.44",
|
"version": "1.1.48",
|
||||||
"resolved": "https://registry.npmjs.org/@langchain/core/-/core-1.1.44.tgz",
|
"resolved": "https://registry.npmjs.org/@langchain/core/-/core-1.1.48.tgz",
|
||||||
"integrity": "sha512-RePW1IjGCHr9ua2vcby3aE8mOOz3EnwDZxMEGbNDT91kf14eqkJqxDXvaZFviGdcN9DTrxM5RPQNAHmwSm4tbg==",
|
"integrity": "sha512-fQU6Guyb1pwc2fEplmA8FPbKfOMAofjnyJzExevro0FxEiuGHE18Ov/ZHmT9trWCDTZRI9eW1VIc6aChxV8pAQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cfworker/json-schema": "^4.0.2",
|
"@cfworker/json-schema": "^4.0.2",
|
||||||
"@standard-schema/spec": "^1.1.0",
|
"@standard-schema/spec": "^1.1.0",
|
||||||
"ansi-styles": "^5.0.0",
|
|
||||||
"camelcase": "6",
|
|
||||||
"decamelize": "1.2.0",
|
|
||||||
"js-tiktoken": "^1.0.12",
|
"js-tiktoken": "^1.0.12",
|
||||||
"langsmith": ">=0.5.0 <1.0.0",
|
"langsmith": ">=0.5.0 <1.0.0",
|
||||||
"mustache": "^4.2.0",
|
"mustache": "^4.2.0",
|
||||||
@@ -1411,19 +1447,6 @@
|
|||||||
"node": ">=20"
|
"node": ">=20"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@langchain/core/node_modules/ansi-styles": {
|
|
||||||
"version": "5.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
|
|
||||||
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@langchain/google-genai": {
|
"node_modules/@langchain/google-genai": {
|
||||||
"version": "2.1.30",
|
"version": "2.1.30",
|
||||||
"resolved": "https://registry.npmjs.org/@langchain/google-genai/-/google-genai-2.1.30.tgz",
|
"resolved": "https://registry.npmjs.org/@langchain/google-genai/-/google-genai-2.1.30.tgz",
|
||||||
@@ -1590,6 +1613,23 @@
|
|||||||
"uuid": "dist/bin/uuid"
|
"uuid": "dist/bin/uuid"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@langchain/openai": {
|
||||||
|
"version": "1.4.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@langchain/openai/-/openai-1.4.7.tgz",
|
||||||
|
"integrity": "sha512-i1YLV4pWbGC6W8m0ZNpLObJuf1nyU4o8aWyX4AF9fHn7eM67HfIJWQ5n5XzcCpuSa41otrxA9jvH5XRKwI1qDA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"js-tiktoken": "^1.0.12",
|
||||||
|
"openai": "^6.37.0",
|
||||||
|
"zod": "^3.25.76 || ^4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@langchain/core": "^1.1.48"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@mapbox/node-pre-gyp": {
|
"node_modules/@mapbox/node-pre-gyp": {
|
||||||
"version": "1.0.11",
|
"version": "1.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz",
|
||||||
@@ -4312,6 +4352,12 @@
|
|||||||
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
|
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@stablelib/base64": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@standard-schema/spec": {
|
"node_modules/@standard-schema/spec": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
|
||||||
@@ -6230,19 +6276,6 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/camelcase": {
|
|
||||||
"version": "6.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
|
|
||||||
"integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/camelcase-css": {
|
"node_modules/camelcase-css": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
||||||
@@ -6914,16 +6947,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/decamelize": {
|
|
||||||
"version": "1.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
|
||||||
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/decimal.js": {
|
"node_modules/decimal.js": {
|
||||||
"version": "10.6.0",
|
"version": "10.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz",
|
||||||
@@ -7969,6 +7992,12 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/fast-sha256": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==",
|
||||||
|
"license": "Unlicense"
|
||||||
|
},
|
||||||
"node_modules/fast-uri": {
|
"node_modules/fast-uri": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
|
||||||
@@ -9051,7 +9080,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.21.tgz",
|
"resolved": "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.21.tgz",
|
||||||
"integrity": "sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g==",
|
"integrity": "sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"base64-js": "^1.5.1"
|
"base64-js": "^1.5.1"
|
||||||
}
|
}
|
||||||
@@ -9094,6 +9122,19 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/json-schema-to-ts": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.18.3",
|
||||||
|
"ts-algebra": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/json-schema-traverse": {
|
"node_modules/json-schema-traverse": {
|
||||||
"version": "0.4.1",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||||
@@ -10404,6 +10445,24 @@
|
|||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/openai": {
|
||||||
|
"version": "6.42.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/openai/-/openai-6.42.0.tgz",
|
||||||
|
"integrity": "sha512-1WFEt/uXMXOLhYRNkgJWo08Y2YNvNwpVU72K7ibrWgWpNOXd4VojXLbe6SQ4bLiUQ3Y8jz4IiyVkylJCL1DtZg==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"peerDependencies": {
|
||||||
|
"ws": "^8.18.0",
|
||||||
|
"zod": "^3.25 || ^4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"ws": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"zod": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/optionator": {
|
"node_modules/optionator": {
|
||||||
"version": "0.9.4",
|
"version": "0.9.4",
|
||||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
||||||
@@ -12895,6 +12954,16 @@
|
|||||||
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==",
|
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/standardwebhooks": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/standardwebhooks/-/standardwebhooks-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@stablelib/base64": "^1.0.0",
|
||||||
|
"fast-sha256": "^1.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/statuses": {
|
"node_modules/statuses": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
|
||||||
@@ -13465,6 +13534,12 @@
|
|||||||
"tree-kill": "cli.js"
|
"tree-kill": "cli.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ts-algebra": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/ts-api-utils": {
|
"node_modules/ts-api-utils": {
|
||||||
"version": "2.4.0",
|
"version": "2.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz",
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -441,6 +441,9 @@ exports.Prisma.AiSettingsScalarFieldEnum = {
|
|||||||
openAiEnabled: 'openAiEnabled',
|
openAiEnabled: 'openAiEnabled',
|
||||||
claudeAiKey: 'claudeAiKey',
|
claudeAiKey: 'claudeAiKey',
|
||||||
claudeAiEnabled: 'claudeAiEnabled',
|
claudeAiEnabled: 'claudeAiEnabled',
|
||||||
|
claudeAiModel: 'claudeAiModel',
|
||||||
|
openAiModel: 'openAiModel',
|
||||||
|
googleAiModel: 'googleAiModel',
|
||||||
dentalMgmtKey: 'dentalMgmtKey',
|
dentalMgmtKey: 'dentalMgmtKey',
|
||||||
dentalMgmtEnabled: 'dentalMgmtEnabled',
|
dentalMgmtEnabled: 'dentalMgmtEnabled',
|
||||||
afterHoursEnabled: 'afterHoursEnabled',
|
afterHoursEnabled: 'afterHoursEnabled',
|
||||||
|
|||||||
+100
-1
@@ -36467,6 +36467,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled: boolean | null
|
openAiEnabled: boolean | null
|
||||||
claudeAiKey: string | null
|
claudeAiKey: string | null
|
||||||
claudeAiEnabled: boolean | null
|
claudeAiEnabled: boolean | null
|
||||||
|
claudeAiModel: string | null
|
||||||
|
openAiModel: string | null
|
||||||
|
googleAiModel: string | null
|
||||||
dentalMgmtKey: string | null
|
dentalMgmtKey: string | null
|
||||||
dentalMgmtEnabled: boolean | null
|
dentalMgmtEnabled: boolean | null
|
||||||
afterHoursEnabled: boolean | null
|
afterHoursEnabled: boolean | null
|
||||||
@@ -36482,6 +36485,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled: boolean | null
|
openAiEnabled: boolean | null
|
||||||
claudeAiKey: string | null
|
claudeAiKey: string | null
|
||||||
claudeAiEnabled: boolean | null
|
claudeAiEnabled: boolean | null
|
||||||
|
claudeAiModel: string | null
|
||||||
|
openAiModel: string | null
|
||||||
|
googleAiModel: string | null
|
||||||
dentalMgmtKey: string | null
|
dentalMgmtKey: string | null
|
||||||
dentalMgmtEnabled: boolean | null
|
dentalMgmtEnabled: boolean | null
|
||||||
afterHoursEnabled: boolean | null
|
afterHoursEnabled: boolean | null
|
||||||
@@ -36497,6 +36503,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled: number
|
openAiEnabled: number
|
||||||
claudeAiKey: number
|
claudeAiKey: number
|
||||||
claudeAiEnabled: number
|
claudeAiEnabled: number
|
||||||
|
claudeAiModel: number
|
||||||
|
openAiModel: number
|
||||||
|
googleAiModel: number
|
||||||
dentalMgmtKey: number
|
dentalMgmtKey: number
|
||||||
dentalMgmtEnabled: number
|
dentalMgmtEnabled: number
|
||||||
afterHoursEnabled: number
|
afterHoursEnabled: number
|
||||||
@@ -36524,6 +36533,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: true
|
openAiEnabled?: true
|
||||||
claudeAiKey?: true
|
claudeAiKey?: true
|
||||||
claudeAiEnabled?: true
|
claudeAiEnabled?: true
|
||||||
|
claudeAiModel?: true
|
||||||
|
openAiModel?: true
|
||||||
|
googleAiModel?: true
|
||||||
dentalMgmtKey?: true
|
dentalMgmtKey?: true
|
||||||
dentalMgmtEnabled?: true
|
dentalMgmtEnabled?: true
|
||||||
afterHoursEnabled?: true
|
afterHoursEnabled?: true
|
||||||
@@ -36539,6 +36551,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: true
|
openAiEnabled?: true
|
||||||
claudeAiKey?: true
|
claudeAiKey?: true
|
||||||
claudeAiEnabled?: true
|
claudeAiEnabled?: true
|
||||||
|
claudeAiModel?: true
|
||||||
|
openAiModel?: true
|
||||||
|
googleAiModel?: true
|
||||||
dentalMgmtKey?: true
|
dentalMgmtKey?: true
|
||||||
dentalMgmtEnabled?: true
|
dentalMgmtEnabled?: true
|
||||||
afterHoursEnabled?: true
|
afterHoursEnabled?: true
|
||||||
@@ -36554,6 +36569,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: true
|
openAiEnabled?: true
|
||||||
claudeAiKey?: true
|
claudeAiKey?: true
|
||||||
claudeAiEnabled?: true
|
claudeAiEnabled?: true
|
||||||
|
claudeAiModel?: true
|
||||||
|
openAiModel?: true
|
||||||
|
googleAiModel?: true
|
||||||
dentalMgmtKey?: true
|
dentalMgmtKey?: true
|
||||||
dentalMgmtEnabled?: true
|
dentalMgmtEnabled?: true
|
||||||
afterHoursEnabled?: true
|
afterHoursEnabled?: true
|
||||||
@@ -36656,6 +36674,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled: boolean
|
openAiEnabled: boolean
|
||||||
claudeAiKey: string
|
claudeAiKey: string
|
||||||
claudeAiEnabled: boolean
|
claudeAiEnabled: boolean
|
||||||
|
claudeAiModel: string
|
||||||
|
openAiModel: string
|
||||||
|
googleAiModel: string
|
||||||
dentalMgmtKey: string
|
dentalMgmtKey: string
|
||||||
dentalMgmtEnabled: boolean
|
dentalMgmtEnabled: boolean
|
||||||
afterHoursEnabled: boolean
|
afterHoursEnabled: boolean
|
||||||
@@ -36690,6 +36711,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: boolean
|
openAiEnabled?: boolean
|
||||||
claudeAiKey?: boolean
|
claudeAiKey?: boolean
|
||||||
claudeAiEnabled?: boolean
|
claudeAiEnabled?: boolean
|
||||||
|
claudeAiModel?: boolean
|
||||||
|
openAiModel?: boolean
|
||||||
|
googleAiModel?: boolean
|
||||||
dentalMgmtKey?: boolean
|
dentalMgmtKey?: boolean
|
||||||
dentalMgmtEnabled?: boolean
|
dentalMgmtEnabled?: boolean
|
||||||
afterHoursEnabled?: boolean
|
afterHoursEnabled?: boolean
|
||||||
@@ -36706,6 +36730,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: boolean
|
openAiEnabled?: boolean
|
||||||
claudeAiKey?: boolean
|
claudeAiKey?: boolean
|
||||||
claudeAiEnabled?: boolean
|
claudeAiEnabled?: boolean
|
||||||
|
claudeAiModel?: boolean
|
||||||
|
openAiModel?: boolean
|
||||||
|
googleAiModel?: boolean
|
||||||
dentalMgmtKey?: boolean
|
dentalMgmtKey?: boolean
|
||||||
dentalMgmtEnabled?: boolean
|
dentalMgmtEnabled?: boolean
|
||||||
afterHoursEnabled?: boolean
|
afterHoursEnabled?: boolean
|
||||||
@@ -36722,6 +36749,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: boolean
|
openAiEnabled?: boolean
|
||||||
claudeAiKey?: boolean
|
claudeAiKey?: boolean
|
||||||
claudeAiEnabled?: boolean
|
claudeAiEnabled?: boolean
|
||||||
|
claudeAiModel?: boolean
|
||||||
|
openAiModel?: boolean
|
||||||
|
googleAiModel?: boolean
|
||||||
dentalMgmtKey?: boolean
|
dentalMgmtKey?: boolean
|
||||||
dentalMgmtEnabled?: boolean
|
dentalMgmtEnabled?: boolean
|
||||||
afterHoursEnabled?: boolean
|
afterHoursEnabled?: boolean
|
||||||
@@ -36738,13 +36768,16 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: boolean
|
openAiEnabled?: boolean
|
||||||
claudeAiKey?: boolean
|
claudeAiKey?: boolean
|
||||||
claudeAiEnabled?: boolean
|
claudeAiEnabled?: boolean
|
||||||
|
claudeAiModel?: boolean
|
||||||
|
openAiModel?: boolean
|
||||||
|
googleAiModel?: boolean
|
||||||
dentalMgmtKey?: boolean
|
dentalMgmtKey?: boolean
|
||||||
dentalMgmtEnabled?: boolean
|
dentalMgmtEnabled?: boolean
|
||||||
afterHoursEnabled?: boolean
|
afterHoursEnabled?: boolean
|
||||||
openPhoneReply?: boolean
|
openPhoneReply?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AiSettingsOmit<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = $Extensions.GetOmit<"id" | "userId" | "apiKey" | "aiEnabled" | "openAiKey" | "openAiEnabled" | "claudeAiKey" | "claudeAiEnabled" | "dentalMgmtKey" | "dentalMgmtEnabled" | "afterHoursEnabled" | "openPhoneReply", ExtArgs["result"]["aiSettings"]>
|
export type AiSettingsOmit<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = $Extensions.GetOmit<"id" | "userId" | "apiKey" | "aiEnabled" | "openAiKey" | "openAiEnabled" | "claudeAiKey" | "claudeAiEnabled" | "claudeAiModel" | "openAiModel" | "googleAiModel" | "dentalMgmtKey" | "dentalMgmtEnabled" | "afterHoursEnabled" | "openPhoneReply", ExtArgs["result"]["aiSettings"]>
|
||||||
export type AiSettingsInclude<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = {
|
export type AiSettingsInclude<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = {
|
||||||
user?: boolean | UserDefaultArgs<ExtArgs>
|
user?: boolean | UserDefaultArgs<ExtArgs>
|
||||||
}
|
}
|
||||||
@@ -36769,6 +36802,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled: boolean
|
openAiEnabled: boolean
|
||||||
claudeAiKey: string
|
claudeAiKey: string
|
||||||
claudeAiEnabled: boolean
|
claudeAiEnabled: boolean
|
||||||
|
claudeAiModel: string
|
||||||
|
openAiModel: string
|
||||||
|
googleAiModel: string
|
||||||
dentalMgmtKey: string
|
dentalMgmtKey: string
|
||||||
dentalMgmtEnabled: boolean
|
dentalMgmtEnabled: boolean
|
||||||
afterHoursEnabled: boolean
|
afterHoursEnabled: boolean
|
||||||
@@ -37205,6 +37241,9 @@ export namespace Prisma {
|
|||||||
readonly openAiEnabled: FieldRef<"AiSettings", 'Boolean'>
|
readonly openAiEnabled: FieldRef<"AiSettings", 'Boolean'>
|
||||||
readonly claudeAiKey: FieldRef<"AiSettings", 'String'>
|
readonly claudeAiKey: FieldRef<"AiSettings", 'String'>
|
||||||
readonly claudeAiEnabled: FieldRef<"AiSettings", 'Boolean'>
|
readonly claudeAiEnabled: FieldRef<"AiSettings", 'Boolean'>
|
||||||
|
readonly claudeAiModel: FieldRef<"AiSettings", 'String'>
|
||||||
|
readonly openAiModel: FieldRef<"AiSettings", 'String'>
|
||||||
|
readonly googleAiModel: FieldRef<"AiSettings", 'String'>
|
||||||
readonly dentalMgmtKey: FieldRef<"AiSettings", 'String'>
|
readonly dentalMgmtKey: FieldRef<"AiSettings", 'String'>
|
||||||
readonly dentalMgmtEnabled: FieldRef<"AiSettings", 'Boolean'>
|
readonly dentalMgmtEnabled: FieldRef<"AiSettings", 'Boolean'>
|
||||||
readonly afterHoursEnabled: FieldRef<"AiSettings", 'Boolean'>
|
readonly afterHoursEnabled: FieldRef<"AiSettings", 'Boolean'>
|
||||||
@@ -45818,6 +45857,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled: 'openAiEnabled',
|
openAiEnabled: 'openAiEnabled',
|
||||||
claudeAiKey: 'claudeAiKey',
|
claudeAiKey: 'claudeAiKey',
|
||||||
claudeAiEnabled: 'claudeAiEnabled',
|
claudeAiEnabled: 'claudeAiEnabled',
|
||||||
|
claudeAiModel: 'claudeAiModel',
|
||||||
|
openAiModel: 'openAiModel',
|
||||||
|
googleAiModel: 'googleAiModel',
|
||||||
dentalMgmtKey: 'dentalMgmtKey',
|
dentalMgmtKey: 'dentalMgmtKey',
|
||||||
dentalMgmtEnabled: 'dentalMgmtEnabled',
|
dentalMgmtEnabled: 'dentalMgmtEnabled',
|
||||||
afterHoursEnabled: 'afterHoursEnabled',
|
afterHoursEnabled: 'afterHoursEnabled',
|
||||||
@@ -48464,6 +48506,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: BoolFilter<"AiSettings"> | boolean
|
openAiEnabled?: BoolFilter<"AiSettings"> | boolean
|
||||||
claudeAiKey?: StringFilter<"AiSettings"> | string
|
claudeAiKey?: StringFilter<"AiSettings"> | string
|
||||||
claudeAiEnabled?: BoolFilter<"AiSettings"> | boolean
|
claudeAiEnabled?: BoolFilter<"AiSettings"> | boolean
|
||||||
|
claudeAiModel?: StringFilter<"AiSettings"> | string
|
||||||
|
openAiModel?: StringFilter<"AiSettings"> | string
|
||||||
|
googleAiModel?: StringFilter<"AiSettings"> | string
|
||||||
dentalMgmtKey?: StringFilter<"AiSettings"> | string
|
dentalMgmtKey?: StringFilter<"AiSettings"> | string
|
||||||
dentalMgmtEnabled?: BoolFilter<"AiSettings"> | boolean
|
dentalMgmtEnabled?: BoolFilter<"AiSettings"> | boolean
|
||||||
afterHoursEnabled?: BoolFilter<"AiSettings"> | boolean
|
afterHoursEnabled?: BoolFilter<"AiSettings"> | boolean
|
||||||
@@ -48480,6 +48525,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: SortOrder
|
openAiEnabled?: SortOrder
|
||||||
claudeAiKey?: SortOrder
|
claudeAiKey?: SortOrder
|
||||||
claudeAiEnabled?: SortOrder
|
claudeAiEnabled?: SortOrder
|
||||||
|
claudeAiModel?: SortOrder
|
||||||
|
openAiModel?: SortOrder
|
||||||
|
googleAiModel?: SortOrder
|
||||||
dentalMgmtKey?: SortOrder
|
dentalMgmtKey?: SortOrder
|
||||||
dentalMgmtEnabled?: SortOrder
|
dentalMgmtEnabled?: SortOrder
|
||||||
afterHoursEnabled?: SortOrder
|
afterHoursEnabled?: SortOrder
|
||||||
@@ -48499,6 +48547,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: BoolFilter<"AiSettings"> | boolean
|
openAiEnabled?: BoolFilter<"AiSettings"> | boolean
|
||||||
claudeAiKey?: StringFilter<"AiSettings"> | string
|
claudeAiKey?: StringFilter<"AiSettings"> | string
|
||||||
claudeAiEnabled?: BoolFilter<"AiSettings"> | boolean
|
claudeAiEnabled?: BoolFilter<"AiSettings"> | boolean
|
||||||
|
claudeAiModel?: StringFilter<"AiSettings"> | string
|
||||||
|
openAiModel?: StringFilter<"AiSettings"> | string
|
||||||
|
googleAiModel?: StringFilter<"AiSettings"> | string
|
||||||
dentalMgmtKey?: StringFilter<"AiSettings"> | string
|
dentalMgmtKey?: StringFilter<"AiSettings"> | string
|
||||||
dentalMgmtEnabled?: BoolFilter<"AiSettings"> | boolean
|
dentalMgmtEnabled?: BoolFilter<"AiSettings"> | boolean
|
||||||
afterHoursEnabled?: BoolFilter<"AiSettings"> | boolean
|
afterHoursEnabled?: BoolFilter<"AiSettings"> | boolean
|
||||||
@@ -48515,6 +48566,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: SortOrder
|
openAiEnabled?: SortOrder
|
||||||
claudeAiKey?: SortOrder
|
claudeAiKey?: SortOrder
|
||||||
claudeAiEnabled?: SortOrder
|
claudeAiEnabled?: SortOrder
|
||||||
|
claudeAiModel?: SortOrder
|
||||||
|
openAiModel?: SortOrder
|
||||||
|
googleAiModel?: SortOrder
|
||||||
dentalMgmtKey?: SortOrder
|
dentalMgmtKey?: SortOrder
|
||||||
dentalMgmtEnabled?: SortOrder
|
dentalMgmtEnabled?: SortOrder
|
||||||
afterHoursEnabled?: SortOrder
|
afterHoursEnabled?: SortOrder
|
||||||
@@ -48538,6 +48592,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: BoolWithAggregatesFilter<"AiSettings"> | boolean
|
openAiEnabled?: BoolWithAggregatesFilter<"AiSettings"> | boolean
|
||||||
claudeAiKey?: StringWithAggregatesFilter<"AiSettings"> | string
|
claudeAiKey?: StringWithAggregatesFilter<"AiSettings"> | string
|
||||||
claudeAiEnabled?: BoolWithAggregatesFilter<"AiSettings"> | boolean
|
claudeAiEnabled?: BoolWithAggregatesFilter<"AiSettings"> | boolean
|
||||||
|
claudeAiModel?: StringWithAggregatesFilter<"AiSettings"> | string
|
||||||
|
openAiModel?: StringWithAggregatesFilter<"AiSettings"> | string
|
||||||
|
googleAiModel?: StringWithAggregatesFilter<"AiSettings"> | string
|
||||||
dentalMgmtKey?: StringWithAggregatesFilter<"AiSettings"> | string
|
dentalMgmtKey?: StringWithAggregatesFilter<"AiSettings"> | string
|
||||||
dentalMgmtEnabled?: BoolWithAggregatesFilter<"AiSettings"> | boolean
|
dentalMgmtEnabled?: BoolWithAggregatesFilter<"AiSettings"> | boolean
|
||||||
afterHoursEnabled?: BoolWithAggregatesFilter<"AiSettings"> | boolean
|
afterHoursEnabled?: BoolWithAggregatesFilter<"AiSettings"> | boolean
|
||||||
@@ -51245,6 +51302,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: boolean
|
openAiEnabled?: boolean
|
||||||
claudeAiKey?: string
|
claudeAiKey?: string
|
||||||
claudeAiEnabled?: boolean
|
claudeAiEnabled?: boolean
|
||||||
|
claudeAiModel?: string
|
||||||
|
openAiModel?: string
|
||||||
|
googleAiModel?: string
|
||||||
dentalMgmtKey?: string
|
dentalMgmtKey?: string
|
||||||
dentalMgmtEnabled?: boolean
|
dentalMgmtEnabled?: boolean
|
||||||
afterHoursEnabled?: boolean
|
afterHoursEnabled?: boolean
|
||||||
@@ -51261,6 +51321,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: boolean
|
openAiEnabled?: boolean
|
||||||
claudeAiKey?: string
|
claudeAiKey?: string
|
||||||
claudeAiEnabled?: boolean
|
claudeAiEnabled?: boolean
|
||||||
|
claudeAiModel?: string
|
||||||
|
openAiModel?: string
|
||||||
|
googleAiModel?: string
|
||||||
dentalMgmtKey?: string
|
dentalMgmtKey?: string
|
||||||
dentalMgmtEnabled?: boolean
|
dentalMgmtEnabled?: boolean
|
||||||
afterHoursEnabled?: boolean
|
afterHoursEnabled?: boolean
|
||||||
@@ -51274,6 +51337,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
openAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
claudeAiKey?: StringFieldUpdateOperationsInput | string
|
claudeAiKey?: StringFieldUpdateOperationsInput | string
|
||||||
claudeAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
claudeAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
|
claudeAiModel?: StringFieldUpdateOperationsInput | string
|
||||||
|
openAiModel?: StringFieldUpdateOperationsInput | string
|
||||||
|
googleAiModel?: StringFieldUpdateOperationsInput | string
|
||||||
dentalMgmtKey?: StringFieldUpdateOperationsInput | string
|
dentalMgmtKey?: StringFieldUpdateOperationsInput | string
|
||||||
dentalMgmtEnabled?: BoolFieldUpdateOperationsInput | boolean
|
dentalMgmtEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
afterHoursEnabled?: BoolFieldUpdateOperationsInput | boolean
|
afterHoursEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
@@ -51290,6 +51356,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
openAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
claudeAiKey?: StringFieldUpdateOperationsInput | string
|
claudeAiKey?: StringFieldUpdateOperationsInput | string
|
||||||
claudeAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
claudeAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
|
claudeAiModel?: StringFieldUpdateOperationsInput | string
|
||||||
|
openAiModel?: StringFieldUpdateOperationsInput | string
|
||||||
|
googleAiModel?: StringFieldUpdateOperationsInput | string
|
||||||
dentalMgmtKey?: StringFieldUpdateOperationsInput | string
|
dentalMgmtKey?: StringFieldUpdateOperationsInput | string
|
||||||
dentalMgmtEnabled?: BoolFieldUpdateOperationsInput | boolean
|
dentalMgmtEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
afterHoursEnabled?: BoolFieldUpdateOperationsInput | boolean
|
afterHoursEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
@@ -51305,6 +51374,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: boolean
|
openAiEnabled?: boolean
|
||||||
claudeAiKey?: string
|
claudeAiKey?: string
|
||||||
claudeAiEnabled?: boolean
|
claudeAiEnabled?: boolean
|
||||||
|
claudeAiModel?: string
|
||||||
|
openAiModel?: string
|
||||||
|
googleAiModel?: string
|
||||||
dentalMgmtKey?: string
|
dentalMgmtKey?: string
|
||||||
dentalMgmtEnabled?: boolean
|
dentalMgmtEnabled?: boolean
|
||||||
afterHoursEnabled?: boolean
|
afterHoursEnabled?: boolean
|
||||||
@@ -51318,6 +51390,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
openAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
claudeAiKey?: StringFieldUpdateOperationsInput | string
|
claudeAiKey?: StringFieldUpdateOperationsInput | string
|
||||||
claudeAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
claudeAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
|
claudeAiModel?: StringFieldUpdateOperationsInput | string
|
||||||
|
openAiModel?: StringFieldUpdateOperationsInput | string
|
||||||
|
googleAiModel?: StringFieldUpdateOperationsInput | string
|
||||||
dentalMgmtKey?: StringFieldUpdateOperationsInput | string
|
dentalMgmtKey?: StringFieldUpdateOperationsInput | string
|
||||||
dentalMgmtEnabled?: BoolFieldUpdateOperationsInput | boolean
|
dentalMgmtEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
afterHoursEnabled?: BoolFieldUpdateOperationsInput | boolean
|
afterHoursEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
@@ -51333,6 +51408,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
openAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
claudeAiKey?: StringFieldUpdateOperationsInput | string
|
claudeAiKey?: StringFieldUpdateOperationsInput | string
|
||||||
claudeAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
claudeAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
|
claudeAiModel?: StringFieldUpdateOperationsInput | string
|
||||||
|
openAiModel?: StringFieldUpdateOperationsInput | string
|
||||||
|
googleAiModel?: StringFieldUpdateOperationsInput | string
|
||||||
dentalMgmtKey?: StringFieldUpdateOperationsInput | string
|
dentalMgmtKey?: StringFieldUpdateOperationsInput | string
|
||||||
dentalMgmtEnabled?: BoolFieldUpdateOperationsInput | boolean
|
dentalMgmtEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
afterHoursEnabled?: BoolFieldUpdateOperationsInput | boolean
|
afterHoursEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
@@ -53948,6 +54026,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: SortOrder
|
openAiEnabled?: SortOrder
|
||||||
claudeAiKey?: SortOrder
|
claudeAiKey?: SortOrder
|
||||||
claudeAiEnabled?: SortOrder
|
claudeAiEnabled?: SortOrder
|
||||||
|
claudeAiModel?: SortOrder
|
||||||
|
openAiModel?: SortOrder
|
||||||
|
googleAiModel?: SortOrder
|
||||||
dentalMgmtKey?: SortOrder
|
dentalMgmtKey?: SortOrder
|
||||||
dentalMgmtEnabled?: SortOrder
|
dentalMgmtEnabled?: SortOrder
|
||||||
afterHoursEnabled?: SortOrder
|
afterHoursEnabled?: SortOrder
|
||||||
@@ -53968,6 +54049,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: SortOrder
|
openAiEnabled?: SortOrder
|
||||||
claudeAiKey?: SortOrder
|
claudeAiKey?: SortOrder
|
||||||
claudeAiEnabled?: SortOrder
|
claudeAiEnabled?: SortOrder
|
||||||
|
claudeAiModel?: SortOrder
|
||||||
|
openAiModel?: SortOrder
|
||||||
|
googleAiModel?: SortOrder
|
||||||
dentalMgmtKey?: SortOrder
|
dentalMgmtKey?: SortOrder
|
||||||
dentalMgmtEnabled?: SortOrder
|
dentalMgmtEnabled?: SortOrder
|
||||||
afterHoursEnabled?: SortOrder
|
afterHoursEnabled?: SortOrder
|
||||||
@@ -53983,6 +54067,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: SortOrder
|
openAiEnabled?: SortOrder
|
||||||
claudeAiKey?: SortOrder
|
claudeAiKey?: SortOrder
|
||||||
claudeAiEnabled?: SortOrder
|
claudeAiEnabled?: SortOrder
|
||||||
|
claudeAiModel?: SortOrder
|
||||||
|
openAiModel?: SortOrder
|
||||||
|
googleAiModel?: SortOrder
|
||||||
dentalMgmtKey?: SortOrder
|
dentalMgmtKey?: SortOrder
|
||||||
dentalMgmtEnabled?: SortOrder
|
dentalMgmtEnabled?: SortOrder
|
||||||
afterHoursEnabled?: SortOrder
|
afterHoursEnabled?: SortOrder
|
||||||
@@ -58336,6 +58423,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: boolean
|
openAiEnabled?: boolean
|
||||||
claudeAiKey?: string
|
claudeAiKey?: string
|
||||||
claudeAiEnabled?: boolean
|
claudeAiEnabled?: boolean
|
||||||
|
claudeAiModel?: string
|
||||||
|
openAiModel?: string
|
||||||
|
googleAiModel?: string
|
||||||
dentalMgmtKey?: string
|
dentalMgmtKey?: string
|
||||||
dentalMgmtEnabled?: boolean
|
dentalMgmtEnabled?: boolean
|
||||||
afterHoursEnabled?: boolean
|
afterHoursEnabled?: boolean
|
||||||
@@ -58350,6 +58440,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: boolean
|
openAiEnabled?: boolean
|
||||||
claudeAiKey?: string
|
claudeAiKey?: string
|
||||||
claudeAiEnabled?: boolean
|
claudeAiEnabled?: boolean
|
||||||
|
claudeAiModel?: string
|
||||||
|
openAiModel?: string
|
||||||
|
googleAiModel?: string
|
||||||
dentalMgmtKey?: string
|
dentalMgmtKey?: string
|
||||||
dentalMgmtEnabled?: boolean
|
dentalMgmtEnabled?: boolean
|
||||||
afterHoursEnabled?: boolean
|
afterHoursEnabled?: boolean
|
||||||
@@ -58962,6 +59055,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
openAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
claudeAiKey?: StringFieldUpdateOperationsInput | string
|
claudeAiKey?: StringFieldUpdateOperationsInput | string
|
||||||
claudeAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
claudeAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
|
claudeAiModel?: StringFieldUpdateOperationsInput | string
|
||||||
|
openAiModel?: StringFieldUpdateOperationsInput | string
|
||||||
|
googleAiModel?: StringFieldUpdateOperationsInput | string
|
||||||
dentalMgmtKey?: StringFieldUpdateOperationsInput | string
|
dentalMgmtKey?: StringFieldUpdateOperationsInput | string
|
||||||
dentalMgmtEnabled?: BoolFieldUpdateOperationsInput | boolean
|
dentalMgmtEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
afterHoursEnabled?: BoolFieldUpdateOperationsInput | boolean
|
afterHoursEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
@@ -58976,6 +59072,9 @@ export namespace Prisma {
|
|||||||
openAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
openAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
claudeAiKey?: StringFieldUpdateOperationsInput | string
|
claudeAiKey?: StringFieldUpdateOperationsInput | string
|
||||||
claudeAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
claudeAiEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
|
claudeAiModel?: StringFieldUpdateOperationsInput | string
|
||||||
|
openAiModel?: StringFieldUpdateOperationsInput | string
|
||||||
|
googleAiModel?: StringFieldUpdateOperationsInput | string
|
||||||
dentalMgmtKey?: StringFieldUpdateOperationsInput | string
|
dentalMgmtKey?: StringFieldUpdateOperationsInput | string
|
||||||
dentalMgmtEnabled?: BoolFieldUpdateOperationsInput | boolean
|
dentalMgmtEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
afterHoursEnabled?: BoolFieldUpdateOperationsInput | boolean
|
afterHoursEnabled?: BoolFieldUpdateOperationsInput | boolean
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "prisma-client-5274dcc359e2ac7cb6d4e95a13b684de504baf5945107a0270a97148d1ad0620",
|
"name": "prisma-client-81ca44b9d3e5c16b41f6767b04f58e5bfe8927e8c0e21f3f03dff81c6db38733",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"types": "index.d.ts",
|
"types": "index.d.ts",
|
||||||
"browser": "default.js",
|
"browser": "default.js",
|
||||||
|
|||||||
@@ -609,6 +609,9 @@ model AiSettings {
|
|||||||
openAiEnabled Boolean @default(false)
|
openAiEnabled Boolean @default(false)
|
||||||
claudeAiKey String @default("")
|
claudeAiKey String @default("")
|
||||||
claudeAiEnabled Boolean @default(false)
|
claudeAiEnabled Boolean @default(false)
|
||||||
|
claudeAiModel String @default("claude-haiku-4-5-20251001")
|
||||||
|
openAiModel String @default("gpt-5.2")
|
||||||
|
googleAiModel String @default("gemini-2.5-flash")
|
||||||
dentalMgmtKey String @default("")
|
dentalMgmtKey String @default("")
|
||||||
dentalMgmtEnabled Boolean @default(false)
|
dentalMgmtEnabled Boolean @default(false)
|
||||||
afterHoursEnabled Boolean @default(true)
|
afterHoursEnabled Boolean @default(true)
|
||||||
|
|||||||
@@ -610,6 +610,9 @@ model AiSettings {
|
|||||||
openAiEnabled Boolean @default(false)
|
openAiEnabled Boolean @default(false)
|
||||||
claudeAiKey String @default("")
|
claudeAiKey String @default("")
|
||||||
claudeAiEnabled Boolean @default(false)
|
claudeAiEnabled Boolean @default(false)
|
||||||
|
claudeAiModel String @default("claude-haiku-4-5-20251001")
|
||||||
|
openAiModel String @default("gpt-5.2")
|
||||||
|
googleAiModel String @default("gemini-2.5-flash")
|
||||||
dentalMgmtKey String @default("")
|
dentalMgmtKey String @default("")
|
||||||
dentalMgmtEnabled Boolean @default(false)
|
dentalMgmtEnabled Boolean @default(false)
|
||||||
afterHoursEnabled Boolean @default(true)
|
afterHoursEnabled Boolean @default(true)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"version": "1.0",
|
"version": "1.0",
|
||||||
"generatorVersion": "1.0.0",
|
"generatorVersion": "1.0.0",
|
||||||
"generatedAt": "2026-06-06T02:32:44.464Z",
|
"generatedAt": "2026-06-06T04:01:46.483Z",
|
||||||
"outputPath": "/home/ff/Desktop/DentalManagementMH06/packages/db/shared",
|
"outputPath": "/home/ff/Desktop/DentalManagementMH06/packages/db/shared",
|
||||||
"files": [
|
"files": [
|
||||||
"schemas/enums/TransactionIsolationLevel.schema.ts",
|
"schemas/enums/TransactionIsolationLevel.schema.ts",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as z from 'zod';
|
import * as z from 'zod';
|
||||||
|
|
||||||
export const AiSettingsScalarFieldEnumSchema = z.enum(['id', 'userId', 'apiKey', 'aiEnabled', 'openAiKey', 'openAiEnabled', 'claudeAiKey', 'claudeAiEnabled', 'dentalMgmtKey', 'dentalMgmtEnabled', 'afterHoursEnabled', 'openPhoneReply'])
|
export const AiSettingsScalarFieldEnumSchema = z.enum(['id', 'userId', 'apiKey', 'aiEnabled', 'openAiKey', 'openAiEnabled', 'claudeAiKey', 'claudeAiEnabled', 'claudeAiModel', 'openAiModel', 'googleAiModel', 'dentalMgmtKey', 'dentalMgmtEnabled', 'afterHoursEnabled', 'openPhoneReply'])
|
||||||
|
|
||||||
export type AiSettingsScalarFieldEnum = z.infer<typeof AiSettingsScalarFieldEnumSchema>;
|
export type AiSettingsScalarFieldEnum = z.infer<typeof AiSettingsScalarFieldEnumSchema>;
|
||||||
@@ -18,6 +18,9 @@ export const AiSettingsFindFirstSelectSchema: z.ZodType<Prisma.AiSettingsSelect>
|
|||||||
openAiEnabled: z.boolean().optional(),
|
openAiEnabled: z.boolean().optional(),
|
||||||
claudeAiKey: z.boolean().optional(),
|
claudeAiKey: z.boolean().optional(),
|
||||||
claudeAiEnabled: z.boolean().optional(),
|
claudeAiEnabled: z.boolean().optional(),
|
||||||
|
claudeAiModel: z.boolean().optional(),
|
||||||
|
openAiModel: z.boolean().optional(),
|
||||||
|
googleAiModel: z.boolean().optional(),
|
||||||
dentalMgmtKey: z.boolean().optional(),
|
dentalMgmtKey: z.boolean().optional(),
|
||||||
dentalMgmtEnabled: z.boolean().optional(),
|
dentalMgmtEnabled: z.boolean().optional(),
|
||||||
afterHoursEnabled: z.boolean().optional(),
|
afterHoursEnabled: z.boolean().optional(),
|
||||||
@@ -34,6 +37,9 @@ export const AiSettingsFindFirstSelectZodSchema = z.object({
|
|||||||
openAiEnabled: z.boolean().optional(),
|
openAiEnabled: z.boolean().optional(),
|
||||||
claudeAiKey: z.boolean().optional(),
|
claudeAiKey: z.boolean().optional(),
|
||||||
claudeAiEnabled: z.boolean().optional(),
|
claudeAiEnabled: z.boolean().optional(),
|
||||||
|
claudeAiModel: z.boolean().optional(),
|
||||||
|
openAiModel: z.boolean().optional(),
|
||||||
|
googleAiModel: z.boolean().optional(),
|
||||||
dentalMgmtKey: z.boolean().optional(),
|
dentalMgmtKey: z.boolean().optional(),
|
||||||
dentalMgmtEnabled: z.boolean().optional(),
|
dentalMgmtEnabled: z.boolean().optional(),
|
||||||
afterHoursEnabled: z.boolean().optional(),
|
afterHoursEnabled: z.boolean().optional(),
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ export const AiSettingsFindFirstOrThrowSelectSchema: z.ZodType<Prisma.AiSettings
|
|||||||
openAiEnabled: z.boolean().optional(),
|
openAiEnabled: z.boolean().optional(),
|
||||||
claudeAiKey: z.boolean().optional(),
|
claudeAiKey: z.boolean().optional(),
|
||||||
claudeAiEnabled: z.boolean().optional(),
|
claudeAiEnabled: z.boolean().optional(),
|
||||||
|
claudeAiModel: z.boolean().optional(),
|
||||||
|
openAiModel: z.boolean().optional(),
|
||||||
|
googleAiModel: z.boolean().optional(),
|
||||||
dentalMgmtKey: z.boolean().optional(),
|
dentalMgmtKey: z.boolean().optional(),
|
||||||
dentalMgmtEnabled: z.boolean().optional(),
|
dentalMgmtEnabled: z.boolean().optional(),
|
||||||
afterHoursEnabled: z.boolean().optional(),
|
afterHoursEnabled: z.boolean().optional(),
|
||||||
@@ -34,6 +37,9 @@ export const AiSettingsFindFirstOrThrowSelectZodSchema = z.object({
|
|||||||
openAiEnabled: z.boolean().optional(),
|
openAiEnabled: z.boolean().optional(),
|
||||||
claudeAiKey: z.boolean().optional(),
|
claudeAiKey: z.boolean().optional(),
|
||||||
claudeAiEnabled: z.boolean().optional(),
|
claudeAiEnabled: z.boolean().optional(),
|
||||||
|
claudeAiModel: z.boolean().optional(),
|
||||||
|
openAiModel: z.boolean().optional(),
|
||||||
|
googleAiModel: z.boolean().optional(),
|
||||||
dentalMgmtKey: z.boolean().optional(),
|
dentalMgmtKey: z.boolean().optional(),
|
||||||
dentalMgmtEnabled: z.boolean().optional(),
|
dentalMgmtEnabled: z.boolean().optional(),
|
||||||
afterHoursEnabled: z.boolean().optional(),
|
afterHoursEnabled: z.boolean().optional(),
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ export const AiSettingsFindManySelectSchema: z.ZodType<Prisma.AiSettingsSelect>
|
|||||||
openAiEnabled: z.boolean().optional(),
|
openAiEnabled: z.boolean().optional(),
|
||||||
claudeAiKey: z.boolean().optional(),
|
claudeAiKey: z.boolean().optional(),
|
||||||
claudeAiEnabled: z.boolean().optional(),
|
claudeAiEnabled: z.boolean().optional(),
|
||||||
|
claudeAiModel: z.boolean().optional(),
|
||||||
|
openAiModel: z.boolean().optional(),
|
||||||
|
googleAiModel: z.boolean().optional(),
|
||||||
dentalMgmtKey: z.boolean().optional(),
|
dentalMgmtKey: z.boolean().optional(),
|
||||||
dentalMgmtEnabled: z.boolean().optional(),
|
dentalMgmtEnabled: z.boolean().optional(),
|
||||||
afterHoursEnabled: z.boolean().optional(),
|
afterHoursEnabled: z.boolean().optional(),
|
||||||
@@ -34,6 +37,9 @@ export const AiSettingsFindManySelectZodSchema = z.object({
|
|||||||
openAiEnabled: z.boolean().optional(),
|
openAiEnabled: z.boolean().optional(),
|
||||||
claudeAiKey: z.boolean().optional(),
|
claudeAiKey: z.boolean().optional(),
|
||||||
claudeAiEnabled: z.boolean().optional(),
|
claudeAiEnabled: z.boolean().optional(),
|
||||||
|
claudeAiModel: z.boolean().optional(),
|
||||||
|
openAiModel: z.boolean().optional(),
|
||||||
|
googleAiModel: z.boolean().optional(),
|
||||||
dentalMgmtKey: z.boolean().optional(),
|
dentalMgmtKey: z.boolean().optional(),
|
||||||
dentalMgmtEnabled: z.boolean().optional(),
|
dentalMgmtEnabled: z.boolean().optional(),
|
||||||
afterHoursEnabled: z.boolean().optional(),
|
afterHoursEnabled: z.boolean().optional(),
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ const makeSchema = () => z.object({
|
|||||||
openAiEnabled: z.literal(true).optional(),
|
openAiEnabled: z.literal(true).optional(),
|
||||||
claudeAiKey: z.literal(true).optional(),
|
claudeAiKey: z.literal(true).optional(),
|
||||||
claudeAiEnabled: z.literal(true).optional(),
|
claudeAiEnabled: z.literal(true).optional(),
|
||||||
|
claudeAiModel: z.literal(true).optional(),
|
||||||
|
openAiModel: z.literal(true).optional(),
|
||||||
|
googleAiModel: z.literal(true).optional(),
|
||||||
dentalMgmtKey: z.literal(true).optional(),
|
dentalMgmtKey: z.literal(true).optional(),
|
||||||
dentalMgmtEnabled: z.literal(true).optional(),
|
dentalMgmtEnabled: z.literal(true).optional(),
|
||||||
afterHoursEnabled: z.literal(true).optional(),
|
afterHoursEnabled: z.literal(true).optional(),
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ const makeSchema = () => z.object({
|
|||||||
openAiEnabled: SortOrderSchema.optional(),
|
openAiEnabled: SortOrderSchema.optional(),
|
||||||
claudeAiKey: SortOrderSchema.optional(),
|
claudeAiKey: SortOrderSchema.optional(),
|
||||||
claudeAiEnabled: SortOrderSchema.optional(),
|
claudeAiEnabled: SortOrderSchema.optional(),
|
||||||
|
claudeAiModel: SortOrderSchema.optional(),
|
||||||
|
openAiModel: SortOrderSchema.optional(),
|
||||||
|
googleAiModel: SortOrderSchema.optional(),
|
||||||
dentalMgmtKey: SortOrderSchema.optional(),
|
dentalMgmtKey: SortOrderSchema.optional(),
|
||||||
dentalMgmtEnabled: SortOrderSchema.optional(),
|
dentalMgmtEnabled: SortOrderSchema.optional(),
|
||||||
afterHoursEnabled: SortOrderSchema.optional(),
|
afterHoursEnabled: SortOrderSchema.optional(),
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ const makeSchema = () => z.object({
|
|||||||
openAiEnabled: z.boolean().optional(),
|
openAiEnabled: z.boolean().optional(),
|
||||||
claudeAiKey: z.string().optional(),
|
claudeAiKey: z.string().optional(),
|
||||||
claudeAiEnabled: z.boolean().optional(),
|
claudeAiEnabled: z.boolean().optional(),
|
||||||
|
claudeAiModel: z.string().optional(),
|
||||||
|
openAiModel: z.string().optional(),
|
||||||
|
googleAiModel: z.string().optional(),
|
||||||
dentalMgmtKey: z.string().optional(),
|
dentalMgmtKey: z.string().optional(),
|
||||||
dentalMgmtEnabled: z.boolean().optional(),
|
dentalMgmtEnabled: z.boolean().optional(),
|
||||||
afterHoursEnabled: z.boolean().optional(),
|
afterHoursEnabled: z.boolean().optional(),
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ const makeSchema = () => z.object({
|
|||||||
openAiEnabled: z.boolean().optional(),
|
openAiEnabled: z.boolean().optional(),
|
||||||
claudeAiKey: z.string().optional(),
|
claudeAiKey: z.string().optional(),
|
||||||
claudeAiEnabled: z.boolean().optional(),
|
claudeAiEnabled: z.boolean().optional(),
|
||||||
|
claudeAiModel: z.string().optional(),
|
||||||
|
openAiModel: z.string().optional(),
|
||||||
|
googleAiModel: z.string().optional(),
|
||||||
dentalMgmtKey: z.string().optional(),
|
dentalMgmtKey: z.string().optional(),
|
||||||
dentalMgmtEnabled: z.boolean().optional(),
|
dentalMgmtEnabled: z.boolean().optional(),
|
||||||
afterHoursEnabled: z.boolean().optional(),
|
afterHoursEnabled: z.boolean().optional(),
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ const makeSchema = () => z.object({
|
|||||||
openAiEnabled: z.boolean().optional(),
|
openAiEnabled: z.boolean().optional(),
|
||||||
claudeAiKey: z.string().optional(),
|
claudeAiKey: z.string().optional(),
|
||||||
claudeAiEnabled: z.boolean().optional(),
|
claudeAiEnabled: z.boolean().optional(),
|
||||||
|
claudeAiModel: z.string().optional(),
|
||||||
|
openAiModel: z.string().optional(),
|
||||||
|
googleAiModel: z.string().optional(),
|
||||||
dentalMgmtKey: z.string().optional(),
|
dentalMgmtKey: z.string().optional(),
|
||||||
dentalMgmtEnabled: z.boolean().optional(),
|
dentalMgmtEnabled: z.boolean().optional(),
|
||||||
afterHoursEnabled: z.boolean().optional(),
|
afterHoursEnabled: z.boolean().optional(),
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ const makeSchema = () => z.object({
|
|||||||
openAiEnabled: z.literal(true).optional(),
|
openAiEnabled: z.literal(true).optional(),
|
||||||
claudeAiKey: z.literal(true).optional(),
|
claudeAiKey: z.literal(true).optional(),
|
||||||
claudeAiEnabled: z.literal(true).optional(),
|
claudeAiEnabled: z.literal(true).optional(),
|
||||||
|
claudeAiModel: z.literal(true).optional(),
|
||||||
|
openAiModel: z.literal(true).optional(),
|
||||||
|
googleAiModel: z.literal(true).optional(),
|
||||||
dentalMgmtKey: z.literal(true).optional(),
|
dentalMgmtKey: z.literal(true).optional(),
|
||||||
dentalMgmtEnabled: z.literal(true).optional(),
|
dentalMgmtEnabled: z.literal(true).optional(),
|
||||||
afterHoursEnabled: z.literal(true).optional(),
|
afterHoursEnabled: z.literal(true).optional(),
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ const makeSchema = () => z.object({
|
|||||||
openAiEnabled: SortOrderSchema.optional(),
|
openAiEnabled: SortOrderSchema.optional(),
|
||||||
claudeAiKey: SortOrderSchema.optional(),
|
claudeAiKey: SortOrderSchema.optional(),
|
||||||
claudeAiEnabled: SortOrderSchema.optional(),
|
claudeAiEnabled: SortOrderSchema.optional(),
|
||||||
|
claudeAiModel: SortOrderSchema.optional(),
|
||||||
|
openAiModel: SortOrderSchema.optional(),
|
||||||
|
googleAiModel: SortOrderSchema.optional(),
|
||||||
dentalMgmtKey: SortOrderSchema.optional(),
|
dentalMgmtKey: SortOrderSchema.optional(),
|
||||||
dentalMgmtEnabled: SortOrderSchema.optional(),
|
dentalMgmtEnabled: SortOrderSchema.optional(),
|
||||||
afterHoursEnabled: SortOrderSchema.optional(),
|
afterHoursEnabled: SortOrderSchema.optional(),
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ const makeSchema = () => z.object({
|
|||||||
openAiEnabled: z.literal(true).optional(),
|
openAiEnabled: z.literal(true).optional(),
|
||||||
claudeAiKey: z.literal(true).optional(),
|
claudeAiKey: z.literal(true).optional(),
|
||||||
claudeAiEnabled: z.literal(true).optional(),
|
claudeAiEnabled: z.literal(true).optional(),
|
||||||
|
claudeAiModel: z.literal(true).optional(),
|
||||||
|
openAiModel: z.literal(true).optional(),
|
||||||
|
googleAiModel: z.literal(true).optional(),
|
||||||
dentalMgmtKey: z.literal(true).optional(),
|
dentalMgmtKey: z.literal(true).optional(),
|
||||||
dentalMgmtEnabled: z.literal(true).optional(),
|
dentalMgmtEnabled: z.literal(true).optional(),
|
||||||
afterHoursEnabled: z.literal(true).optional(),
|
afterHoursEnabled: z.literal(true).optional(),
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ const makeSchema = () => z.object({
|
|||||||
openAiEnabled: SortOrderSchema.optional(),
|
openAiEnabled: SortOrderSchema.optional(),
|
||||||
claudeAiKey: SortOrderSchema.optional(),
|
claudeAiKey: SortOrderSchema.optional(),
|
||||||
claudeAiEnabled: SortOrderSchema.optional(),
|
claudeAiEnabled: SortOrderSchema.optional(),
|
||||||
|
claudeAiModel: SortOrderSchema.optional(),
|
||||||
|
openAiModel: SortOrderSchema.optional(),
|
||||||
|
googleAiModel: SortOrderSchema.optional(),
|
||||||
dentalMgmtKey: SortOrderSchema.optional(),
|
dentalMgmtKey: SortOrderSchema.optional(),
|
||||||
dentalMgmtEnabled: SortOrderSchema.optional(),
|
dentalMgmtEnabled: SortOrderSchema.optional(),
|
||||||
afterHoursEnabled: SortOrderSchema.optional(),
|
afterHoursEnabled: SortOrderSchema.optional(),
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ const makeSchema = () => z.object({
|
|||||||
openAiEnabled: SortOrderSchema.optional(),
|
openAiEnabled: SortOrderSchema.optional(),
|
||||||
claudeAiKey: SortOrderSchema.optional(),
|
claudeAiKey: SortOrderSchema.optional(),
|
||||||
claudeAiEnabled: SortOrderSchema.optional(),
|
claudeAiEnabled: SortOrderSchema.optional(),
|
||||||
|
claudeAiModel: SortOrderSchema.optional(),
|
||||||
|
openAiModel: SortOrderSchema.optional(),
|
||||||
|
googleAiModel: SortOrderSchema.optional(),
|
||||||
dentalMgmtKey: SortOrderSchema.optional(),
|
dentalMgmtKey: SortOrderSchema.optional(),
|
||||||
dentalMgmtEnabled: SortOrderSchema.optional(),
|
dentalMgmtEnabled: SortOrderSchema.optional(),
|
||||||
afterHoursEnabled: SortOrderSchema.optional(),
|
afterHoursEnabled: SortOrderSchema.optional(),
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ const makeSchema = () => z.object({
|
|||||||
openAiEnabled: SortOrderSchema.optional(),
|
openAiEnabled: SortOrderSchema.optional(),
|
||||||
claudeAiKey: SortOrderSchema.optional(),
|
claudeAiKey: SortOrderSchema.optional(),
|
||||||
claudeAiEnabled: SortOrderSchema.optional(),
|
claudeAiEnabled: SortOrderSchema.optional(),
|
||||||
|
claudeAiModel: SortOrderSchema.optional(),
|
||||||
|
openAiModel: SortOrderSchema.optional(),
|
||||||
|
googleAiModel: SortOrderSchema.optional(),
|
||||||
dentalMgmtKey: SortOrderSchema.optional(),
|
dentalMgmtKey: SortOrderSchema.optional(),
|
||||||
dentalMgmtEnabled: SortOrderSchema.optional(),
|
dentalMgmtEnabled: SortOrderSchema.optional(),
|
||||||
afterHoursEnabled: SortOrderSchema.optional(),
|
afterHoursEnabled: SortOrderSchema.optional(),
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ const aisettingsscalarwherewithaggregatesinputSchema = z.object({
|
|||||||
openAiEnabled: z.union([z.lazy(() => BoolWithAggregatesFilterObjectSchema), z.boolean()]).optional(),
|
openAiEnabled: z.union([z.lazy(() => BoolWithAggregatesFilterObjectSchema), z.boolean()]).optional(),
|
||||||
claudeAiKey: z.union([z.lazy(() => StringWithAggregatesFilterObjectSchema), z.string()]).optional(),
|
claudeAiKey: z.union([z.lazy(() => StringWithAggregatesFilterObjectSchema), z.string()]).optional(),
|
||||||
claudeAiEnabled: z.union([z.lazy(() => BoolWithAggregatesFilterObjectSchema), z.boolean()]).optional(),
|
claudeAiEnabled: z.union([z.lazy(() => BoolWithAggregatesFilterObjectSchema), z.boolean()]).optional(),
|
||||||
|
claudeAiModel: z.union([z.lazy(() => StringWithAggregatesFilterObjectSchema), z.string()]).optional(),
|
||||||
|
openAiModel: z.union([z.lazy(() => StringWithAggregatesFilterObjectSchema), z.string()]).optional(),
|
||||||
|
googleAiModel: z.union([z.lazy(() => StringWithAggregatesFilterObjectSchema), z.string()]).optional(),
|
||||||
dentalMgmtKey: z.union([z.lazy(() => StringWithAggregatesFilterObjectSchema), z.string()]).optional(),
|
dentalMgmtKey: z.union([z.lazy(() => StringWithAggregatesFilterObjectSchema), z.string()]).optional(),
|
||||||
dentalMgmtEnabled: z.union([z.lazy(() => BoolWithAggregatesFilterObjectSchema), z.boolean()]).optional(),
|
dentalMgmtEnabled: z.union([z.lazy(() => BoolWithAggregatesFilterObjectSchema), z.boolean()]).optional(),
|
||||||
afterHoursEnabled: z.union([z.lazy(() => BoolWithAggregatesFilterObjectSchema), z.boolean()]).optional(),
|
afterHoursEnabled: z.union([z.lazy(() => BoolWithAggregatesFilterObjectSchema), z.boolean()]).optional(),
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ const makeSchema = () => z.object({
|
|||||||
openAiEnabled: z.boolean().optional(),
|
openAiEnabled: z.boolean().optional(),
|
||||||
claudeAiKey: z.boolean().optional(),
|
claudeAiKey: z.boolean().optional(),
|
||||||
claudeAiEnabled: z.boolean().optional(),
|
claudeAiEnabled: z.boolean().optional(),
|
||||||
|
claudeAiModel: z.boolean().optional(),
|
||||||
|
openAiModel: z.boolean().optional(),
|
||||||
|
googleAiModel: z.boolean().optional(),
|
||||||
dentalMgmtKey: z.boolean().optional(),
|
dentalMgmtKey: z.boolean().optional(),
|
||||||
dentalMgmtEnabled: z.boolean().optional(),
|
dentalMgmtEnabled: z.boolean().optional(),
|
||||||
afterHoursEnabled: z.boolean().optional(),
|
afterHoursEnabled: z.boolean().optional(),
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ const makeSchema = () => z.object({
|
|||||||
openAiEnabled: z.boolean().optional(),
|
openAiEnabled: z.boolean().optional(),
|
||||||
claudeAiKey: z.string().optional(),
|
claudeAiKey: z.string().optional(),
|
||||||
claudeAiEnabled: z.boolean().optional(),
|
claudeAiEnabled: z.boolean().optional(),
|
||||||
|
claudeAiModel: z.string().optional(),
|
||||||
|
openAiModel: z.string().optional(),
|
||||||
|
googleAiModel: z.string().optional(),
|
||||||
dentalMgmtKey: z.string().optional(),
|
dentalMgmtKey: z.string().optional(),
|
||||||
dentalMgmtEnabled: z.boolean().optional(),
|
dentalMgmtEnabled: z.boolean().optional(),
|
||||||
afterHoursEnabled: z.boolean().optional(),
|
afterHoursEnabled: z.boolean().optional(),
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ const makeSchema = () => z.object({
|
|||||||
openAiEnabled: z.boolean().optional(),
|
openAiEnabled: z.boolean().optional(),
|
||||||
claudeAiKey: z.string().optional(),
|
claudeAiKey: z.string().optional(),
|
||||||
claudeAiEnabled: z.boolean().optional(),
|
claudeAiEnabled: z.boolean().optional(),
|
||||||
|
claudeAiModel: z.string().optional(),
|
||||||
|
openAiModel: z.string().optional(),
|
||||||
|
googleAiModel: z.string().optional(),
|
||||||
dentalMgmtKey: z.string().optional(),
|
dentalMgmtKey: z.string().optional(),
|
||||||
dentalMgmtEnabled: z.boolean().optional(),
|
dentalMgmtEnabled: z.boolean().optional(),
|
||||||
afterHoursEnabled: z.boolean().optional(),
|
afterHoursEnabled: z.boolean().optional(),
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ const makeSchema = () => z.object({
|
|||||||
openAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
openAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
claudeAiKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
claudeAiKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
claudeAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
claudeAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
claudeAiModel: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
openAiModel: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
googleAiModel: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
dentalMgmtKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
dentalMgmtKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
dentalMgmtEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
dentalMgmtEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
afterHoursEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
afterHoursEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ const makeSchema = () => z.object({
|
|||||||
openAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
openAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
claudeAiKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
claudeAiKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
claudeAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
claudeAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
claudeAiModel: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
openAiModel: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
googleAiModel: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
dentalMgmtKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
dentalMgmtKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
dentalMgmtEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
dentalMgmtEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
afterHoursEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
afterHoursEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ const makeSchema = () => z.object({
|
|||||||
openAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
openAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
claudeAiKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
claudeAiKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
claudeAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
claudeAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
claudeAiModel: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
openAiModel: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
googleAiModel: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
dentalMgmtKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
dentalMgmtKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
dentalMgmtEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
dentalMgmtEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
afterHoursEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
afterHoursEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ const makeSchema = () => z.object({
|
|||||||
openAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
openAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
claudeAiKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
claudeAiKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
claudeAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
claudeAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
claudeAiModel: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
openAiModel: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
googleAiModel: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
dentalMgmtKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
dentalMgmtKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
dentalMgmtEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
dentalMgmtEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
afterHoursEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
afterHoursEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ const makeSchema = () => z.object({
|
|||||||
openAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
openAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
claudeAiKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
claudeAiKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
claudeAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
claudeAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
claudeAiModel: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
openAiModel: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
googleAiModel: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
dentalMgmtKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
dentalMgmtKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
dentalMgmtEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
dentalMgmtEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
afterHoursEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
afterHoursEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ const makeSchema = () => z.object({
|
|||||||
openAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
openAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
claudeAiKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
claudeAiKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
claudeAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
claudeAiEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
claudeAiModel: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
openAiModel: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
googleAiModel: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
dentalMgmtKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
dentalMgmtKey: z.union([z.string(), z.lazy(() => StringFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
dentalMgmtEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
dentalMgmtEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
afterHoursEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
afterHoursEnabled: z.union([z.boolean(), z.lazy(() => BoolFieldUpdateOperationsInputObjectSchema)]).optional(),
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ const aisettingswhereinputSchema = z.object({
|
|||||||
openAiEnabled: z.union([z.lazy(() => BoolFilterObjectSchema), z.boolean()]).optional(),
|
openAiEnabled: z.union([z.lazy(() => BoolFilterObjectSchema), z.boolean()]).optional(),
|
||||||
claudeAiKey: z.union([z.lazy(() => StringFilterObjectSchema), z.string()]).optional(),
|
claudeAiKey: z.union([z.lazy(() => StringFilterObjectSchema), z.string()]).optional(),
|
||||||
claudeAiEnabled: z.union([z.lazy(() => BoolFilterObjectSchema), z.boolean()]).optional(),
|
claudeAiEnabled: z.union([z.lazy(() => BoolFilterObjectSchema), z.boolean()]).optional(),
|
||||||
|
claudeAiModel: z.union([z.lazy(() => StringFilterObjectSchema), z.string()]).optional(),
|
||||||
|
openAiModel: z.union([z.lazy(() => StringFilterObjectSchema), z.string()]).optional(),
|
||||||
|
googleAiModel: z.union([z.lazy(() => StringFilterObjectSchema), z.string()]).optional(),
|
||||||
dentalMgmtKey: z.union([z.lazy(() => StringFilterObjectSchema), z.string()]).optional(),
|
dentalMgmtKey: z.union([z.lazy(() => StringFilterObjectSchema), z.string()]).optional(),
|
||||||
dentalMgmtEnabled: z.union([z.lazy(() => BoolFilterObjectSchema), z.boolean()]).optional(),
|
dentalMgmtEnabled: z.union([z.lazy(() => BoolFilterObjectSchema), z.boolean()]).optional(),
|
||||||
afterHoursEnabled: z.union([z.lazy(() => BoolFilterObjectSchema), z.boolean()]).optional(),
|
afterHoursEnabled: z.union([z.lazy(() => BoolFilterObjectSchema), z.boolean()]).optional(),
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ export const AiSettingsAggregateResultSchema = z.object({ _count: z.object({
|
|||||||
openAiEnabled: z.number(),
|
openAiEnabled: z.number(),
|
||||||
claudeAiKey: z.number(),
|
claudeAiKey: z.number(),
|
||||||
claudeAiEnabled: z.number(),
|
claudeAiEnabled: z.number(),
|
||||||
|
claudeAiModel: z.number(),
|
||||||
|
openAiModel: z.number(),
|
||||||
|
googleAiModel: z.number(),
|
||||||
dentalMgmtKey: z.number(),
|
dentalMgmtKey: z.number(),
|
||||||
dentalMgmtEnabled: z.number(),
|
dentalMgmtEnabled: z.number(),
|
||||||
afterHoursEnabled: z.number(),
|
afterHoursEnabled: z.number(),
|
||||||
@@ -28,6 +31,9 @@ export const AiSettingsAggregateResultSchema = z.object({ _count: z.object({
|
|||||||
apiKey: z.string().nullable(),
|
apiKey: z.string().nullable(),
|
||||||
openAiKey: z.string().nullable(),
|
openAiKey: z.string().nullable(),
|
||||||
claudeAiKey: z.string().nullable(),
|
claudeAiKey: z.string().nullable(),
|
||||||
|
claudeAiModel: z.string().nullable(),
|
||||||
|
openAiModel: z.string().nullable(),
|
||||||
|
googleAiModel: z.string().nullable(),
|
||||||
dentalMgmtKey: z.string().nullable()
|
dentalMgmtKey: z.string().nullable()
|
||||||
}).nullable().optional(),
|
}).nullable().optional(),
|
||||||
_max: z.object({
|
_max: z.object({
|
||||||
@@ -36,5 +42,8 @@ export const AiSettingsAggregateResultSchema = z.object({ _count: z.object({
|
|||||||
apiKey: z.string().nullable(),
|
apiKey: z.string().nullable(),
|
||||||
openAiKey: z.string().nullable(),
|
openAiKey: z.string().nullable(),
|
||||||
claudeAiKey: z.string().nullable(),
|
claudeAiKey: z.string().nullable(),
|
||||||
|
claudeAiModel: z.string().nullable(),
|
||||||
|
openAiModel: z.string().nullable(),
|
||||||
|
googleAiModel: z.string().nullable(),
|
||||||
dentalMgmtKey: z.string().nullable()
|
dentalMgmtKey: z.string().nullable()
|
||||||
}).nullable().optional()});
|
}).nullable().optional()});
|
||||||
@@ -8,6 +8,9 @@ export const AiSettingsCreateResultSchema = z.object({
|
|||||||
openAiEnabled: z.boolean(),
|
openAiEnabled: z.boolean(),
|
||||||
claudeAiKey: z.string(),
|
claudeAiKey: z.string(),
|
||||||
claudeAiEnabled: z.boolean(),
|
claudeAiEnabled: z.boolean(),
|
||||||
|
claudeAiModel: z.string(),
|
||||||
|
openAiModel: z.string(),
|
||||||
|
googleAiModel: z.string(),
|
||||||
dentalMgmtKey: z.string(),
|
dentalMgmtKey: z.string(),
|
||||||
dentalMgmtEnabled: z.boolean(),
|
dentalMgmtEnabled: z.boolean(),
|
||||||
afterHoursEnabled: z.boolean(),
|
afterHoursEnabled: z.boolean(),
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ export const AiSettingsDeleteResultSchema = z.nullable(z.object({
|
|||||||
openAiEnabled: z.boolean(),
|
openAiEnabled: z.boolean(),
|
||||||
claudeAiKey: z.string(),
|
claudeAiKey: z.string(),
|
||||||
claudeAiEnabled: z.boolean(),
|
claudeAiEnabled: z.boolean(),
|
||||||
|
claudeAiModel: z.string(),
|
||||||
|
openAiModel: z.string(),
|
||||||
|
googleAiModel: z.string(),
|
||||||
dentalMgmtKey: z.string(),
|
dentalMgmtKey: z.string(),
|
||||||
dentalMgmtEnabled: z.boolean(),
|
dentalMgmtEnabled: z.boolean(),
|
||||||
afterHoursEnabled: z.boolean(),
|
afterHoursEnabled: z.boolean(),
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ export const AiSettingsFindFirstResultSchema = z.nullable(z.object({
|
|||||||
openAiEnabled: z.boolean(),
|
openAiEnabled: z.boolean(),
|
||||||
claudeAiKey: z.string(),
|
claudeAiKey: z.string(),
|
||||||
claudeAiEnabled: z.boolean(),
|
claudeAiEnabled: z.boolean(),
|
||||||
|
claudeAiModel: z.string(),
|
||||||
|
openAiModel: z.string(),
|
||||||
|
googleAiModel: z.string(),
|
||||||
dentalMgmtKey: z.string(),
|
dentalMgmtKey: z.string(),
|
||||||
dentalMgmtEnabled: z.boolean(),
|
dentalMgmtEnabled: z.boolean(),
|
||||||
afterHoursEnabled: z.boolean(),
|
afterHoursEnabled: z.boolean(),
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ export const AiSettingsFindManyResultSchema = z.object({
|
|||||||
openAiEnabled: z.boolean(),
|
openAiEnabled: z.boolean(),
|
||||||
claudeAiKey: z.string(),
|
claudeAiKey: z.string(),
|
||||||
claudeAiEnabled: z.boolean(),
|
claudeAiEnabled: z.boolean(),
|
||||||
|
claudeAiModel: z.string(),
|
||||||
|
openAiModel: z.string(),
|
||||||
|
googleAiModel: z.string(),
|
||||||
dentalMgmtKey: z.string(),
|
dentalMgmtKey: z.string(),
|
||||||
dentalMgmtEnabled: z.boolean(),
|
dentalMgmtEnabled: z.boolean(),
|
||||||
afterHoursEnabled: z.boolean(),
|
afterHoursEnabled: z.boolean(),
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ export const AiSettingsFindUniqueResultSchema = z.nullable(z.object({
|
|||||||
openAiEnabled: z.boolean(),
|
openAiEnabled: z.boolean(),
|
||||||
claudeAiKey: z.string(),
|
claudeAiKey: z.string(),
|
||||||
claudeAiEnabled: z.boolean(),
|
claudeAiEnabled: z.boolean(),
|
||||||
|
claudeAiModel: z.string(),
|
||||||
|
openAiModel: z.string(),
|
||||||
|
googleAiModel: z.string(),
|
||||||
dentalMgmtKey: z.string(),
|
dentalMgmtKey: z.string(),
|
||||||
dentalMgmtEnabled: z.boolean(),
|
dentalMgmtEnabled: z.boolean(),
|
||||||
afterHoursEnabled: z.boolean(),
|
afterHoursEnabled: z.boolean(),
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ export const AiSettingsGroupByResultSchema = z.array(z.object({
|
|||||||
openAiEnabled: z.boolean(),
|
openAiEnabled: z.boolean(),
|
||||||
claudeAiKey: z.string(),
|
claudeAiKey: z.string(),
|
||||||
claudeAiEnabled: z.boolean(),
|
claudeAiEnabled: z.boolean(),
|
||||||
|
claudeAiModel: z.string(),
|
||||||
|
openAiModel: z.string(),
|
||||||
|
googleAiModel: z.string(),
|
||||||
dentalMgmtKey: z.string(),
|
dentalMgmtKey: z.string(),
|
||||||
dentalMgmtEnabled: z.boolean(),
|
dentalMgmtEnabled: z.boolean(),
|
||||||
afterHoursEnabled: z.boolean(),
|
afterHoursEnabled: z.boolean(),
|
||||||
@@ -21,6 +24,9 @@ export const AiSettingsGroupByResultSchema = z.array(z.object({
|
|||||||
openAiEnabled: z.number(),
|
openAiEnabled: z.number(),
|
||||||
claudeAiKey: z.number(),
|
claudeAiKey: z.number(),
|
||||||
claudeAiEnabled: z.number(),
|
claudeAiEnabled: z.number(),
|
||||||
|
claudeAiModel: z.number(),
|
||||||
|
openAiModel: z.number(),
|
||||||
|
googleAiModel: z.number(),
|
||||||
dentalMgmtKey: z.number(),
|
dentalMgmtKey: z.number(),
|
||||||
dentalMgmtEnabled: z.number(),
|
dentalMgmtEnabled: z.number(),
|
||||||
afterHoursEnabled: z.number(),
|
afterHoursEnabled: z.number(),
|
||||||
@@ -41,6 +47,9 @@ export const AiSettingsGroupByResultSchema = z.array(z.object({
|
|||||||
apiKey: z.string().nullable(),
|
apiKey: z.string().nullable(),
|
||||||
openAiKey: z.string().nullable(),
|
openAiKey: z.string().nullable(),
|
||||||
claudeAiKey: z.string().nullable(),
|
claudeAiKey: z.string().nullable(),
|
||||||
|
claudeAiModel: z.string().nullable(),
|
||||||
|
openAiModel: z.string().nullable(),
|
||||||
|
googleAiModel: z.string().nullable(),
|
||||||
dentalMgmtKey: z.string().nullable()
|
dentalMgmtKey: z.string().nullable()
|
||||||
}).nullable().optional(),
|
}).nullable().optional(),
|
||||||
_max: z.object({
|
_max: z.object({
|
||||||
@@ -49,6 +58,9 @@ export const AiSettingsGroupByResultSchema = z.array(z.object({
|
|||||||
apiKey: z.string().nullable(),
|
apiKey: z.string().nullable(),
|
||||||
openAiKey: z.string().nullable(),
|
openAiKey: z.string().nullable(),
|
||||||
claudeAiKey: z.string().nullable(),
|
claudeAiKey: z.string().nullable(),
|
||||||
|
claudeAiModel: z.string().nullable(),
|
||||||
|
openAiModel: z.string().nullable(),
|
||||||
|
googleAiModel: z.string().nullable(),
|
||||||
dentalMgmtKey: z.string().nullable()
|
dentalMgmtKey: z.string().nullable()
|
||||||
}).nullable().optional()
|
}).nullable().optional()
|
||||||
}));
|
}));
|
||||||
@@ -8,6 +8,9 @@ export const AiSettingsUpdateResultSchema = z.nullable(z.object({
|
|||||||
openAiEnabled: z.boolean(),
|
openAiEnabled: z.boolean(),
|
||||||
claudeAiKey: z.string(),
|
claudeAiKey: z.string(),
|
||||||
claudeAiEnabled: z.boolean(),
|
claudeAiEnabled: z.boolean(),
|
||||||
|
claudeAiModel: z.string(),
|
||||||
|
openAiModel: z.string(),
|
||||||
|
googleAiModel: z.string(),
|
||||||
dentalMgmtKey: z.string(),
|
dentalMgmtKey: z.string(),
|
||||||
dentalMgmtEnabled: z.boolean(),
|
dentalMgmtEnabled: z.boolean(),
|
||||||
afterHoursEnabled: z.boolean(),
|
afterHoursEnabled: z.boolean(),
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ export const AiSettingsUpsertResultSchema = z.object({
|
|||||||
openAiEnabled: z.boolean(),
|
openAiEnabled: z.boolean(),
|
||||||
claudeAiKey: z.string(),
|
claudeAiKey: z.string(),
|
||||||
claudeAiEnabled: z.boolean(),
|
claudeAiEnabled: z.boolean(),
|
||||||
|
claudeAiModel: z.string(),
|
||||||
|
openAiModel: z.string(),
|
||||||
|
googleAiModel: z.string(),
|
||||||
dentalMgmtKey: z.string(),
|
dentalMgmtKey: z.string(),
|
||||||
dentalMgmtEnabled: z.boolean(),
|
dentalMgmtEnabled: z.boolean(),
|
||||||
afterHoursEnabled: z.boolean(),
|
afterHoursEnabled: z.boolean(),
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ export const AiSettingsInputSchema = z.object({
|
|||||||
openAiEnabled: z.boolean(),
|
openAiEnabled: z.boolean(),
|
||||||
claudeAiKey: z.string(),
|
claudeAiKey: z.string(),
|
||||||
claudeAiEnabled: z.boolean(),
|
claudeAiEnabled: z.boolean(),
|
||||||
|
claudeAiModel: z.string(),
|
||||||
|
openAiModel: z.string(),
|
||||||
|
googleAiModel: z.string(),
|
||||||
dentalMgmtKey: z.string(),
|
dentalMgmtKey: z.string(),
|
||||||
dentalMgmtEnabled: z.boolean(),
|
dentalMgmtEnabled: z.boolean(),
|
||||||
afterHoursEnabled: z.boolean(),
|
afterHoursEnabled: z.boolean(),
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ export const AiSettingsModelSchema = z.object({
|
|||||||
openAiEnabled: z.boolean(),
|
openAiEnabled: z.boolean(),
|
||||||
claudeAiKey: z.string(),
|
claudeAiKey: z.string(),
|
||||||
claudeAiEnabled: z.boolean(),
|
claudeAiEnabled: z.boolean(),
|
||||||
|
claudeAiModel: z.string(),
|
||||||
|
openAiModel: z.string(),
|
||||||
|
googleAiModel: z.string(),
|
||||||
dentalMgmtKey: z.string(),
|
dentalMgmtKey: z.string(),
|
||||||
dentalMgmtEnabled: z.boolean(),
|
dentalMgmtEnabled: z.boolean(),
|
||||||
afterHoursEnabled: z.boolean(),
|
afterHoursEnabled: z.boolean(),
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ export const AiSettingsResultSchema = z.object({
|
|||||||
openAiEnabled: z.boolean(),
|
openAiEnabled: z.boolean(),
|
||||||
claudeAiKey: z.string(),
|
claudeAiKey: z.string(),
|
||||||
claudeAiEnabled: z.boolean(),
|
claudeAiEnabled: z.boolean(),
|
||||||
|
claudeAiModel: z.string(),
|
||||||
|
openAiModel: z.string(),
|
||||||
|
googleAiModel: z.string(),
|
||||||
dentalMgmtKey: z.string(),
|
dentalMgmtKey: z.string(),
|
||||||
dentalMgmtEnabled: z.boolean(),
|
dentalMgmtEnabled: z.boolean(),
|
||||||
afterHoursEnabled: z.boolean(),
|
afterHoursEnabled: z.boolean(),
|
||||||
|
|||||||
Reference in New Issue
Block a user