// src/models/ai-provider.ts // Copyright (C) 2025 DTP Technologies, LLC // All Rights Reserved import { Schema, Document, model } from "mongoose"; export type ApiType = "ollama" | "openai"; /** * Normalised capability flags stored with each model record. These are * populated during model refresh from provider-specific metadata and drive * slot-based filtering in the UI (e.g. only canCallTools models for Agent). */ export interface IAiModelSettings { temperature?: number; topP?: number; topK?: number; numCtx?: number; } export interface IAiModelCapabilities { /** Model supports structured function / tool calling via the API. */ canCallTools: boolean; /** Model accepts image inputs (multimodal / vision). */ hasVision: boolean; /** Model can produce vector embeddings (required for the Vector slot). */ hasEmbedding: boolean; /** Model has an explicit reasoning / thinking phase (e.g. o1, QwQ). */ hasThinking: boolean; /** Model is instruction-tuned / chat-tuned (as opposed to a base model). */ isInstructTuned: boolean; } export const AiModelCapabilitiesSchema = new Schema( { canCallTools: { type: Boolean, default: false }, hasVision: { type: Boolean, default: false }, hasEmbedding: { type: Boolean, default: false }, hasThinking: { type: Boolean, default: false }, isInstructTuned: { type: Boolean, default: false }, }, { _id: false }, ); export interface IAiModel { id: string; name: string; /** * Raw parameter count in billions (float). Use parameterLabel for display. */ parameterCount?: number; /** * Human-readable parameter size label sourced directly from the provider, * e.g. "7b", "70b", "3.8b". */ parameterLabel?: string; contextWindow?: number; capabilities: IAiModelCapabilities; settings?: IAiModelSettings; } export const AiModelSettingsSchema = new Schema( { temperature: { type: Number }, topP: { type: Number }, topK: { type: Number }, numCtx: { type: Number }, }, { _id: false }, ); export const AiModelSchema = new Schema( { id: { type: String, required: true }, name: { type: String, required: true }, parameterCount: { type: Number }, parameterLabel: { type: String }, contextWindow: { type: Number }, capabilities: { type: AiModelCapabilitiesSchema, default: () => ({ canCallTools: false, hasVision: false, hasEmbedding: false, hasThinking: false, isInstructTuned: false, }), }, settings: { type: AiModelSettingsSchema, default: undefined, }, }, { _id: false }, ); export interface IAiProvider extends Document { name: string; apiType: ApiType; baseUrl: string; apiKey: string; enabled: boolean; models: IAiModel[]; lastModelRefresh: Date; } export const AiProviderSchema = new Schema({ name: { type: String, required: true }, apiType: { type: String, enum: ["ollama", "openai"], required: true }, baseUrl: { type: String, required: true }, apiKey: { type: String, required: true, select: false }, enabled: { type: Boolean, default: true, required: true }, models: { type: [AiModelSchema], default: [], required: true }, lastModelRefresh: { type: Date, default: Date.now }, }); AiProviderSchema.index({ name: 1 }, { unique: true }); export const AiProvider = model("AiProvider", AiProviderSchema); export default AiProvider; // Note: Index synchronization is now handled during application startup // to ensure the database connection is established first. // See src/lib/db.ts for the syncDatabaseIndexes function.