import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, Index, ManyToOne, JoinColumn, OneToMany, } from 'typeorm'; import { AIModel } from './model.entity'; export type ConversationStatus = 'active' | 'archived' | 'deleted'; export type MessageRole = 'system' | 'user' | 'assistant' | 'function'; export type FinishReason = 'stop' | 'length' | 'function_call' | 'content_filter'; @Entity({ name: 'conversations', schema: 'ai' }) export class AIConversation { @PrimaryGeneratedColumn('uuid') id: string; @Index() @Column({ name: 'tenant_id', type: 'uuid' }) tenantId: string; @Index() @Column({ name: 'user_id', type: 'uuid' }) userId: string; @Column({ name: 'title', type: 'varchar', length: 255, nullable: true }) title: string; @Column({ name: 'summary', type: 'text', nullable: true }) summary: string; @Column({ name: 'context_type', type: 'varchar', length: 50, nullable: true }) contextType: string; @Column({ name: 'context_data', type: 'jsonb', default: {} }) contextData: Record; @Column({ name: 'model_id', type: 'uuid', nullable: true }) modelId: string; @Column({ name: 'prompt_id', type: 'uuid', nullable: true }) promptId: string; @Index() @Column({ name: 'status', type: 'varchar', length: 20, default: 'active' }) status: ConversationStatus; @Column({ name: 'is_pinned', type: 'boolean', default: false }) isPinned: boolean; @Column({ name: 'message_count', type: 'int', default: 0 }) messageCount: number; @Column({ name: 'total_tokens', type: 'int', default: 0 }) totalTokens: number; @Column({ name: 'total_cost', type: 'decimal', precision: 10, scale: 4, default: 0 }) totalCost: number; @Column({ name: 'metadata', type: 'jsonb', default: {} }) metadata: Record; @Column({ name: 'tags', type: 'text', array: true, default: [] }) tags: string[]; @Column({ name: 'last_message_at', type: 'timestamptz', nullable: true }) lastMessageAt: Date; @CreateDateColumn({ name: 'created_at', type: 'timestamptz' }) createdAt: Date; @UpdateDateColumn({ name: 'updated_at', type: 'timestamptz' }) updatedAt: Date; @ManyToOne(() => AIModel, { onDelete: 'SET NULL' }) @JoinColumn({ name: 'model_id' }) model: AIModel; @OneToMany(() => AIMessage, (message) => message.conversation) messages: AIMessage[]; } @Entity({ name: 'messages', schema: 'ai' }) export class AIMessage { @PrimaryGeneratedColumn('uuid') id: string; @Index() @Column({ name: 'conversation_id', type: 'uuid' }) conversationId: string; @Index() @Column({ name: 'tenant_id', type: 'uuid' }) tenantId: string; @Column({ name: 'role', type: 'varchar', length: 20 }) role: MessageRole; @Column({ name: 'content', type: 'text' }) content: string; @Column({ name: 'function_name', type: 'varchar', length: 100, nullable: true }) functionName: string; @Column({ name: 'function_arguments', type: 'jsonb', nullable: true }) functionArguments: Record; @Column({ name: 'function_result', type: 'jsonb', nullable: true }) functionResult: Record; @Column({ name: 'model_id', type: 'uuid', nullable: true }) modelId: string; @Column({ name: 'model_response_id', type: 'varchar', length: 255, nullable: true }) modelResponseId: string; @Column({ name: 'prompt_tokens', type: 'int', nullable: true }) promptTokens: number; @Column({ name: 'completion_tokens', type: 'int', nullable: true }) completionTokens: number; @Column({ name: 'total_tokens', type: 'int', nullable: true }) totalTokens: number; @Column({ name: 'cost', type: 'decimal', precision: 10, scale: 6, nullable: true }) cost: number; @Column({ name: 'latency_ms', type: 'int', nullable: true }) latencyMs: number; @Column({ name: 'finish_reason', type: 'varchar', length: 30, nullable: true }) finishReason: FinishReason; @Column({ name: 'metadata', type: 'jsonb', default: {} }) metadata: Record; @Column({ name: 'feedback_rating', type: 'int', nullable: true }) feedbackRating: number; @Column({ name: 'feedback_text', type: 'text', nullable: true }) feedbackText: string; @Index() @CreateDateColumn({ name: 'created_at', type: 'timestamptz' }) createdAt: Date; @ManyToOne(() => AIConversation, (conversation) => conversation.messages, { onDelete: 'CASCADE' }) @JoinColumn({ name: 'conversation_id' }) conversation: AIConversation; @ManyToOne(() => AIModel, { onDelete: 'SET NULL' }) @JoinColumn({ name: 'model_id' }) model: AIModel; }