spb/vquant Public MIT
VibeQuant — AI-powered institutional-grade financial intelligence platform.
TypeScript 84.3%
Python 11.7%
JavaScript 1.6%
CSS 1.5%
HTML 0.7%
1/*2 * =============================================================================3 * VibeQuant (vquant) — AI-Powered Financial Intelligence Platform4 * -----------------------------------------------------------------------------5 * File: server/routes/validation.ts6 *7 * Author: Simon-Pierre Boucher8 * Contact: contact@spboucher.ai9 * Website: https://www.spboucher.ai10 * Demo: https://www.vquant.ai11 * License: MIT (see LICENSE)12 *13 * Copyright © 2026 Simon-Pierre Boucher. All rights reserved.14 * =============================================================================15 */1617import { z } from "zod";1819export const ALLOWED_MODELS = [20 'claude-fable-5', 'claude-opus-4-6', 'claude-opus-4-7', 'claude-opus-4-8', 'claude-sonnet-4-6', 'claude-haiku-4-5-20251001',21 'gpt-5.6-sol', 'gpt-5.6-terra', 'gpt-5.6-luna', 'gpt-5.5', 'gpt-5.4', 'gpt-5.2', 'gpt-5.1', 'gpt-5', 'gpt-5-mini', 'gpt-5-nano', 'gpt-4.1', 'gpt-4.1-mini',22 'gemini-3.5-flash', 'gemini-3.1-pro-preview', 'gemini-3-flash-preview', 'gemini-3.1-flash-lite',23] as const;24export const UNAVAILABLE_MODELS: readonly string[] = [];25export const DEFAULT_MODEL = 'claude-fable-5';26export type AllowedModel = typeof ALLOWED_MODELS[number];2728export const chatBodySchema = z.object({29 query: z.string().min(1, "Query is required").max(10000),30 history: z.array(z.object({31 question: z.string(),32 answer: z.string(),33 })).optional().default([]),34 sessionId: z.string().optional(),35 imageData: z.string().optional(),36 imageMimeType: z.string().optional(),37 model: z.enum(ALLOWED_MODELS).optional().default(DEFAULT_MODEL).transform(38 (m) => (UNAVAILABLE_MODELS.includes(m as typeof UNAVAILABLE_MODELS[number]) ? DEFAULT_MODEL : m)39 ),40});4142export const shareBodySchema = z.object({43 question: z.string().min(1, "Question is required"),44 answer: z.string().min(1, "Answer is required"),45 toolResults: z.unknown().optional(),46 sources: z.unknown().optional(),47 customPythonFigures: z.unknown().optional(),48});4950export const registerBodySchema = z.object({51 name: z.string().min(2, "Le nom doit contenir au moins 2 caracteres"),52});5354export const loginBodySchema = z.object({55 token: z.string().min(1, "Le token est requis"),56});5758export const heartbeatBodySchema = z.object({59 sessionId: z.string().min(1, "sessionId is required"),60 status: z.string().optional(),61 currentQuery: z.string().nullable().optional(),62 userId: z.string().nullable().optional(),63});64