Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Document, Model } from 'mongoose';


export interface IGeneralSettings {
assistantName: string;
conversationStarter: string;
description: string;
promptSuggestions: string[];
updatedAt?: Date;
}


export interface IGeneralSettingsDocument extends IGeneralSettings, Document {
_id: string;
createdAt: Date;
updatedAt: Date;
}


export interface IGeneralSettingsModel extends Model<IGeneralSettingsDocument> {
getSettings(): Promise<IGeneralSettingsDocument | null>;
updateSettings(doc: Partial<IGeneralSettings>): Promise<IGeneralSettingsDocument>;
}


export const generalSettingsFields = {
assistantName: { type: String, default: '' },
conversationStarter: { type: String, default: '' },
description: { type: String, default: '' },
promptSuggestions: { type: [String], default: [] },
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Document } from 'mongoose';

export interface IRagInteraction {
question: string;
answer: string;
sourceDocuments?: string[];
userId: string;
orgId: string;
createdAt: Date;
modelUsed?: string;
responseTime?: number;
tokensUsed?: number;
confidenceScore?: number;
status: 'success' | 'error' | 'pending';
errorMessage?: string;
}

export interface IRagInteractionDocument extends IRagInteraction, Document {}

// Export the fields as a string
export const ragInteractionFields = `
question: String
answer: String
sourceDocuments: [String]
userId: String
orgId: String
createdAt: Date
modelUsed: String
responseTime: Float
tokensUsed: Float
confidenceScore: Float
status: String
errorMessage: String
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Document, Model } from "mongoose";

export interface ISystemPrompt {
prompt: string; // Remove orgId
updatedAt?: Date;
}

export interface ISystemPromptDocument extends ISystemPrompt, Document {
_id: string;
createdAt: Date;
updatedAt: Date;
}

export interface ISystemPromptModel extends Model<ISystemPromptDocument> {
getPrompt(): Promise<ISystemPromptDocument | null>; // Remove orgId parameter
updatePrompt(prompt: string): Promise<ISystemPromptDocument>; // Remove orgId parameter
}

export const systemPromptFields = {
prompt: { type: String, default: "" } // Remove orgId field
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Schema, model, Model } from "mongoose";
import {
IGeneralSettingsDocument,
IGeneralSettingsModel,
generalSettingsFields,
} from "../definitions/generalSettings";


export const GeneralSettingsSchema = new Schema<IGeneralSettingsDocument>(
generalSettingsFields,
{
timestamps: true,
collection: 'general_settings'
}
);


// Create the model with proper typing
export const GeneralSettingsModel = model<IGeneralSettingsDocument, IGeneralSettingsModel>(
"general_settings",
GeneralSettingsSchema
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// backend/core-api/src/modules/AIassistant/db/models/RagInteractions.ts
import { Schema, model, models, Document, Model } from 'mongoose';
import { field, stringField, numberField, dateField } from '../../utils/schemaField';
import { IRagInteraction } from '../definitions/ragInteractions';

export interface IRagInteractionDocument extends IRagInteraction, Document {}

export interface IRagInteractionModel extends Model<IRagInteractionDocument> {
getRagInteraction(_id: string): Promise<IRagInteractionDocument>;
}

export const ragInteractionSchema = new Schema({
question: stringField({ label: 'Question' }),
answer: stringField({ label: 'Answer' }),
sourceDocuments: field({
type: [String],
label: 'Source Documents',
optional: true
}),
userId: stringField({ label: 'User ID' }),
orgId: stringField({ label: 'Organization ID' }),
createdAt: dateField({
default: Date.now,
label: 'Created at',
immutable: true
}),
modelUsed: stringField({
label: 'Model Used',
optional: true
}),
responseTime: numberField({
label: 'Response Time (ms)',
optional: true,
min: 0
}),
tokensUsed: numberField({
label: 'Tokens Used',
optional: true,
min: 0
}),
confidenceScore: numberField({
label: 'Confidence Score',
optional: true,
min: 0,
max: 1
}),
status: stringField({
label: 'Status',
enum: ['success', 'error', 'pending'],
default: 'success'
}),
errorMessage: stringField({
label: 'Error Message',
optional: true
})
}, {
timestamps: true,
collection: 'rag_interactions'
});

// Add indexes for better query performance
ragInteractionSchema.index({ userId: 1, createdAt: -1 });
ragInteractionSchema.index({ orgId: 1 });
ragInteractionSchema.index({ status: 1 });

export const RagInteractions = models.RagInteractions ||
model<IRagInteractionDocument, IRagInteractionModel>('rag_interactions', ragInteractionSchema);
39 changes: 39 additions & 0 deletions backend/core-api/src/modules/AIassistant/db/models/SystemPrompt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Schema, model, Model } from "mongoose";
import {
ISystemPromptDocument,
ISystemPromptModel,
systemPromptFields,
} from "../definitions/systemPrompt";

export const SystemPromptSchema = new Schema<ISystemPromptDocument>(
systemPromptFields,
{
timestamps: true,
collection: 'system_prompts'
}
);

SystemPromptSchema.statics.getPrompt = function () {
return this.findOne().exec();
};

SystemPromptSchema.statics.updatePrompt = async function (prompt: string) {
const updated = await this.findOneAndUpdate(
{},
{
prompt,
updatedAt: new Date()
},
{
new: true,
upsert: true
}
).exec();

return updated;
};

export const SystemPromptModel = model<ISystemPromptDocument, ISystemPromptModel>(
"system_prompt",
SystemPromptSchema
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { IModels } from '~/connectionResolvers';
import { GeneralSettingsModel } from './GeneralSettings';
import { IGeneralSettingsDocument, IGeneralSettingsModel } from '../definitions/generalSettings';


export const loadGeneralSettingsClass = (models: IModels) => {
class GeneralSettings {
// Example static method
public static async getSettings(): Promise<IGeneralSettingsDocument | null> {
return models.GeneralSettings.findOne({});
}


// You can add more static methods here
}


// Attach class methods to the existing model's schema
GeneralSettingsModel.schema.loadClass(GeneralSettings);


return GeneralSettingsModel;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { IModels } from '~/connectionResolvers';
import { ragInteractionSchema } from './RagInteractions';
import { IRagInteractionDocument, IRagInteraction } from '../definitions/ragInteractions';

export const loadRagInteractionClass = (models: IModels) => {
class RagInteraction {
public static async getRagInteraction(_id: string) {
const ragInteraction = await models.RagInteractions.findOne({ _id });

if (!ragInteraction) {
throw new Error('RagInteraction not found');
}

return ragInteraction;
}
}

ragInteractionSchema.loadClass(RagInteraction);
return ragInteractionSchema;
};
17 changes: 17 additions & 0 deletions backend/core-api/src/modules/AIassistant/docker-compose.dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
version: '3.8'

services:
rag-service:
build: ./rag-service
ports:
- "8000:8000"
env_file:
- ./rag-service/.env
volumes:
- ./rag-service/src:/app/src
restart: unless-stopped
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}
- EMBEDDING_MODEL=${EMBEDDING_MODEL}
- LLM_MODEL=${LLM_MODEL}
- ALLOWED_ORIGINS=http://localhost:3000,http://localhost:3001
37 changes: 37 additions & 0 deletions backend/core-api/src/modules/AIassistant/general.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Router, Request, Response } from "express";
const router: Router = Router();

// in-memory store
let generalSettings = {
assistantName: "Sparkles AI",
conversationStarter: "How can I help you today?",
description:
"Get quick answers and insights about your customers and sales pipeline.",
promptSuggestions: [
"Summarize the last 10 conversations from Team Inbox",
"List all open leads assigned to me",
"Answer customer FAQs quickly",
],
};
Comment on lines +4 to +15
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Inconsistency: In-memory store contradicts database infrastructure.

The AI summary and related files indicate that database models (IGeneralSettings, GeneralSettings Mongoose model, loadGeneralSettingsClass.ts) were added for persistent storage, but this implementation uses an in-memory store that will lose data on restart.

Either:

  1. Use the database models mentioned in the summary
  2. Update the documentation to clarify this is intentionally ephemeral

Run this script to verify if database models exist:

#!/bin/bash
# Check for GeneralSettings database models
echo "=== Searching for GeneralSettings models ==="
fd -t f 'generalSettings.ts' backend/core-api
fd -t f 'GeneralSettings.ts' backend/core-api

echo ""
echo "=== Check model definitions ==="
rg -n "IGeneralSettings" backend/core-api -C 3
🤖 Prompt for AI Agents
In backend/core-api/src/modules/AIassistant/general.ts around lines 4 to 15, the
current in-memory generalSettings object conflicts with the newly-added
persistent database models (IGeneralSettings / GeneralSettings Mongoose model);
either wired persistence must be used or docs must state the store is ephemeral.
Fix by removing the hardcoded in-memory store and instead import and use the
GeneralSettings model: on module initialization load the settings document (or
create with defaults if missing), use that document for reads/updates, and
persist changes through Mongoose calls; alternatively, if ephemeral behavior is
intentional, update the module/file header and project documentation to
explicitly state this is an in-memory ephemeral store and reference the existing
database model files so the discrepancy is clear.


// ✅ GET route (fixed)
router.get("/ai-assistant/general/:orgId", (req: Request, res: Response) => {
res.json(generalSettings);
});

// ✅ POST route (already in your file, just make sure it updates generalSettings)
router.post("/ai-assistant/general/:orgId", (req: Request, res: Response) => {
const { assistantName, conversationStarter, description, promptSuggestions } =
req.body;

generalSettings = {
assistantName,
conversationStarter,
description,
promptSuggestions,
};

res.json({ success: true, settings: generalSettings });
});

export default router;
27 changes: 27 additions & 0 deletions backend/core-api/src/modules/AIassistant/graphql/generalSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { generalSettingsFields } from "../db/definitions/generalSettings";

export const generaltypes = () => [
`
type GeneralSettings {
_id: String!
${generalSettingsFields}
updatedAt: String
}

input GeneralSettingsInput {
assistantName: String
conversationStarter: String
description: String
promptSuggestions: [String]
}

extend type Query {
getGeneralSettings: GeneralSettings
}


extend type Mutation {
updateGeneralSettings(input: GeneralSettingsInput!): GeneralSettings
}
`
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { IGeneralSettingsDocument } from "../../db/definitions/generalSettings";
import { GeneralSettingsModel } from "../../db/models/GeneralSettings";




export interface GeneralSettingsMutationResolvers {
updateGeneralSettings: (
_parent: any,
args: { input: Partial<IGeneralSettingsDocument> }
) => Promise<IGeneralSettingsDocument>;
}




export const generalMutations: GeneralSettingsMutationResolvers = {
updateGeneralSettings: async (
_parent: any,
{ input }: { input: Partial<IGeneralSettingsDocument> }
): Promise<IGeneralSettingsDocument> => {
const existingSettings = await GeneralSettingsModel.findOne().exec();




if (existingSettings) {
Object.assign(existingSettings, input, { updatedAt: new Date() });
return await existingSettings.save();
} else {
const newSettings = new GeneralSettingsModel({
...input,
updatedAt: new Date(),
});
return await newSettings.save();
}
},
};
Loading
Loading