| const { createStartHandler } = require('~/app/clients/callbacks'); |
| const spendTokens = require('~/models/spendTokens'); |
| const { logger } = require('~/config'); |
|
|
| class RunManager { |
| constructor(fields) { |
| const { req, res, abortController, debug } = fields; |
| this.abortController = abortController; |
| this.user = req.user.id; |
| this.req = req; |
| this.res = res; |
| this.debug = debug; |
| this.runs = new Map(); |
| this.convos = new Map(); |
| } |
|
|
| addRun(runId, runData) { |
| if (!this.runs.has(runId)) { |
| this.runs.set(runId, runData); |
| if (runData.conversationId) { |
| this.convos.set(runData.conversationId, runId); |
| } |
| return runData; |
| } else { |
| const existingData = this.runs.get(runId); |
| const update = { ...existingData, ...runData }; |
| this.runs.set(runId, update); |
| if (update.conversationId) { |
| this.convos.set(update.conversationId, runId); |
| } |
| return update; |
| } |
| } |
|
|
| removeRun(runId) { |
| if (this.runs.has(runId)) { |
| this.runs.delete(runId); |
| } else { |
| logger.error(`[api/app/clients/llm/RunManager] Run with ID ${runId} does not exist.`); |
| } |
| } |
|
|
| getAllRuns() { |
| return Array.from(this.runs.values()); |
| } |
|
|
| getRunById(runId) { |
| return this.runs.get(runId); |
| } |
|
|
| getRunByConversationId(conversationId) { |
| const runId = this.convos.get(conversationId); |
| return { run: this.runs.get(runId), runId }; |
| } |
|
|
| createCallbacks(metadata) { |
| return [ |
| { |
| handleChatModelStart: createStartHandler({ ...metadata, manager: this }), |
| handleLLMEnd: async (output, runId, _parentRunId) => { |
| const { llmOutput, ..._output } = output; |
| logger.debug(`[RunManager] handleLLMEnd: ${JSON.stringify(metadata)}`, { |
| runId, |
| _parentRunId, |
| llmOutput, |
| }); |
|
|
| if (metadata.context !== 'title') { |
| logger.debug('[RunManager] handleLLMEnd:', { |
| output: _output, |
| }); |
| } |
|
|
| const { tokenUsage } = output.llmOutput; |
| const run = this.getRunById(runId); |
| this.removeRun(runId); |
|
|
| const txData = { |
| user: this.user, |
| model: run?.model ?? 'gpt-3.5-turbo', |
| ...metadata, |
| }; |
|
|
| await spendTokens(txData, tokenUsage); |
| }, |
| handleLLMError: async (err) => { |
| logger.error(`[RunManager] handleLLMError: ${JSON.stringify(metadata)}`, err); |
| if (metadata.context === 'title') { |
| return; |
| } else if (metadata.context === 'plugins') { |
| throw new Error(err); |
| } |
| const { conversationId } = metadata; |
| const { run } = this.getRunByConversationId(conversationId); |
| if (run && run.error) { |
| const { error } = run; |
| throw new Error(error); |
| } |
| }, |
| }, |
| ]; |
| } |
| } |
|
|
| module.exports = RunManager; |
|
|