UNPKG

lume-ai

Version:

A powerful yet simple library to build your own AI applications.

167 lines (145 loc) 5.14 kB
// =============================== // SECTION | IMPORTS // =============================== import { Custom } from '../genes/Custom' import { LLM, History, VectorDB, Gene, Tool } from '../interfaces' // =============================== // =============================== // SECTION | LUME // =============================== /** * The main service class for interacting with a Large Language Model (LLM) and managing conversation history. */ export class Lume { /** * The LLM instance used for generating responses. */ private llm: LLM /** * Optional history manager for storing and retrieving conversation history. */ private history: History | undefined /** * Optional vector database instance used for storing and retrieving embeddings. */ private vectorDB: VectorDB | undefined /** * Optional gene instance used for generating responses. */ private gene: Gene /** * Optional tools instance used for executing tools. */ private tools: Tool[] = [] /** * Constructs a new Lume service instance. * @param config - Configuration object containing the LLM instance and optional history manager. */ constructor(config: { llm: LLM history?: History vectorDB?: VectorDB gene?: Gene tools?: Tool[] }) { this.llm = config.llm this.history = config.history this.vectorDB = config.vectorDB this.gene = config.gene || new Custom() this.tools = config.tools || [] } /** * Sends a message to the LLM and returns its response. Optionally stores the message in history. * @param text - The user's input message. * @param options - Optional parameters including tags for categorizing the message. * @returns A promise that resolves to the LLM's response as a string. */ async chat(text: string, options?: { tags?: string[] }) { if (this.history) this.history.addMessage(options?.tags || [], { role: 'user', content: text, }) let results: string[] = [] if (this.vectorDB) { const embedding = await this.llm.getEmbedding(text) await this.vectorDB.add(text, embedding, options?.tags || []) results = await this.vectorDB.search(text, embedding, options?.tags || []) } const history = await this.history?.getMessages(options?.tags || []) const llmResponse = await this.llm.getResponse(text, { history: history?.reverse().slice(0, this.gene.maxHistory).reverse(), tags: options?.tags, vectorMatches: results, tools: this.tools, llmOptions: { systemPrompt: this.gene.generateSystemPrompt({ vectorMatches: results, }), model: this.gene.model, temperature: this.gene.temperature, maxTokens: (this.gene.maxTokens || 1000) + this.tools.reduce((acc, tool) => acc + tool.extraTokens, 0), topP: this.gene.topP, }, }) if (this.vectorDB) { const embedding = await this.llm.getEmbedding(llmResponse) await this.vectorDB.add(llmResponse, embedding, options?.tags || []) } return llmResponse } /** * Streams a response from the LLM as it is generated. Optionally stores the message in history and updates vectorDB. * @param text - The user's input message. * @param options - Optional parameters including tags for categorizing the message. * @returns An async generator yielding the LLM's response chunks as strings. */ async *chatStream(text: string, options?: { tags?: string[] }) { if (this.history) await this.history.addMessage(options?.tags || [], { role: 'user', content: text, }) let results: string[] = [] if (this.tools.length > 0) { throw new Error('Tools are not supported for streaming responses.') } if (this.vectorDB) { const embedding = await this.llm.getEmbedding(text) await this.vectorDB.add(text, embedding, options?.tags || []) results = await this.vectorDB.search(text, embedding, options?.tags || []) } const history = await this.history?.getMessages(options?.tags || []) if (!this.llm.streamResponse) { throw new Error('LLM does not support streaming responses.') } let fullResponse = '' for await (const chunk of this.llm.streamResponse(text, { history: history?.reverse().slice(0, this.gene.maxHistory).reverse(), tags: options?.tags, vectorMatches: results, tools: this.tools, llmOptions: { systemPrompt: this.gene.generateSystemPrompt({ vectorMatches: results, }), model: this.gene.model, temperature: this.gene.temperature, maxTokens: (this.gene.maxTokens || 1000) + this.tools.reduce((acc, tool) => acc + tool.extraTokens, 0), topP: this.gene.topP, }, })) { fullResponse += chunk yield chunk } if (this.vectorDB && fullResponse) { const embedding = await this.llm.getEmbedding(fullResponse) await this.vectorDB.add(fullResponse, embedding, options?.tags || []) } } } // ===============================