UNPKG

@llamaindex/core

Version:
969 lines (963 loc) 35.1 kB
import { wrapEventCaller } from '../../decorator/dist/index.js'; import { Settings } from '../../global/dist/index.js'; import { ChatMemoryBuffer, BaseMemory } from '../../memory/dist/index.js'; import { PromptMixin, defaultContextSystemPrompt } from '../../prompts/dist/index.js'; import { MetadataMode, EngineResponse } from '../../schema/dist/index.js'; import { streamConverter, streamReducer, extractText } from '../../utils/dist/index.js'; import { createMessageContent } from '../../response-synthesizers/dist/index.js'; class BaseChatEngine { } class DefaultContextGenerator extends PromptMixin { constructor(init){ super(); this.retriever = init.retriever; this.contextSystemPrompt = init?.contextSystemPrompt ?? defaultContextSystemPrompt; this.nodePostprocessors = init.nodePostprocessors || []; this.contextRole = init.contextRole ?? "system"; this.metadataMode = init.metadataMode ?? MetadataMode.NONE; } _getPromptModules() { return {}; } _getPrompts() { return { contextSystemPrompt: this.contextSystemPrompt }; } _updatePrompts(promptsDict) { if (promptsDict.contextSystemPrompt) { this.contextSystemPrompt = promptsDict.contextSystemPrompt; } } async applyNodePostprocessors(nodes, query) { let nodesWithScore = nodes; for (const postprocessor of this.nodePostprocessors){ nodesWithScore = await postprocessor.postprocessNodes(nodesWithScore, query); } return nodesWithScore; } async generate(message) { const sourceNodesWithScore = await this.retriever.retrieve({ query: message }); const nodes = await this.applyNodePostprocessors(sourceNodesWithScore, message); const content = await createMessageContent(this.contextSystemPrompt, nodes.map((r)=>r.node), undefined, this.metadataMode); return { message: { content, role: this.contextRole }, nodes }; } } function applyDecs2203RFactory$1() { function createAddInitializerMethod(initializers, decoratorFinishedRef) { return function addInitializer(initializer) { assertNotFinished(decoratorFinishedRef, "addInitializer"); assertCallable(initializer, "An initializer"); initializers.push(initializer); }; } function memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value) { var kindStr; switch(kind){ case 1: kindStr = "accessor"; break; case 2: kindStr = "method"; break; case 3: kindStr = "getter"; break; case 4: kindStr = "setter"; break; default: kindStr = "field"; } var ctx = { kind: kindStr, name: isPrivate ? "#" + name : name, static: isStatic, private: isPrivate, metadata: metadata }; var decoratorFinishedRef = { v: false }; ctx.addInitializer = createAddInitializerMethod(initializers, decoratorFinishedRef); var get, set; if (kind === 0) { if (isPrivate) { get = desc.get; set = desc.set; } else { get = function() { return this[name]; }; set = function(v) { this[name] = v; }; } } else if (kind === 2) { get = function() { return desc.value; }; } else { if (kind === 1 || kind === 3) { get = function() { return desc.get.call(this); }; } if (kind === 1 || kind === 4) { set = function(v) { desc.set.call(this, v); }; } } ctx.access = get && set ? { get: get, set: set } : get ? { get: get } : { set: set }; try { return dec(value, ctx); } finally{ decoratorFinishedRef.v = true; } } function assertNotFinished(decoratorFinishedRef, fnName) { if (decoratorFinishedRef.v) { throw new Error("attempted to call " + fnName + " after decoration was finished"); } } function assertCallable(fn, hint) { if (typeof fn !== "function") { throw new TypeError(hint + " must be a function"); } } function assertValidReturnValue(kind, value) { var type = typeof value; if (kind === 1) { if (type !== "object" || value === null) { throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0"); } if (value.get !== undefined) { assertCallable(value.get, "accessor.get"); } if (value.set !== undefined) { assertCallable(value.set, "accessor.set"); } if (value.init !== undefined) { assertCallable(value.init, "accessor.init"); } } else if (type !== "function") { var hint; if (kind === 0) { hint = "field"; } else if (kind === 10) { hint = "class"; } else { hint = "method"; } throw new TypeError(hint + " decorators must return a function or void 0"); } } function applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata) { var decs = decInfo[0]; var desc, init, value; if (isPrivate) { if (kind === 0 || kind === 1) { desc = { get: decInfo[3], set: decInfo[4] }; } else if (kind === 3) { desc = { get: decInfo[3] }; } else if (kind === 4) { desc = { set: decInfo[3] }; } else { desc = { value: decInfo[3] }; } } else if (kind !== 0) { desc = Object.getOwnPropertyDescriptor(base, name); } if (kind === 1) { value = { get: desc.get, set: desc.set }; } else if (kind === 2) { value = desc.value; } else if (kind === 3) { value = desc.get; } else if (kind === 4) { value = desc.set; } var newValue, get, set; if (typeof decs === "function") { newValue = memberDec(decs, name, desc, initializers, kind, isStatic, isPrivate, metadata, value); if (newValue !== void 0) { assertValidReturnValue(kind, newValue); if (kind === 0) { init = newValue; } else if (kind === 1) { init = newValue.init; get = newValue.get || value.get; set = newValue.set || value.set; value = { get: get, set: set }; } else { value = newValue; } } } else { for(var i = decs.length - 1; i >= 0; i--){ var dec = decs[i]; newValue = memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value); if (newValue !== void 0) { assertValidReturnValue(kind, newValue); var newInit; if (kind === 0) { newInit = newValue; } else if (kind === 1) { newInit = newValue.init; get = newValue.get || value.get; set = newValue.set || value.set; value = { get: get, set: set }; } else { value = newValue; } if (newInit !== void 0) { if (init === void 0) { init = newInit; } else if (typeof init === "function") { init = [ init, newInit ]; } else { init.push(newInit); } } } } } if (kind === 0 || kind === 1) { if (init === void 0) { init = function(instance, init) { return init; }; } else if (typeof init !== "function") { var ownInitializers = init; init = function(instance, init) { var value = init; for(var i = 0; i < ownInitializers.length; i++){ value = ownInitializers[i].call(instance, value); } return value; }; } else { var originalInitializer = init; init = function(instance, init) { return originalInitializer.call(instance, init); }; } ret.push(init); } if (kind !== 0) { if (kind === 1) { desc.get = value.get; desc.set = value.set; } else if (kind === 2) { desc.value = value; } else if (kind === 3) { desc.get = value; } else if (kind === 4) { desc.set = value; } if (isPrivate) { if (kind === 1) { ret.push(function(instance, args) { return value.get.call(instance, args); }); ret.push(function(instance, args) { return value.set.call(instance, args); }); } else if (kind === 2) { ret.push(value); } else { ret.push(function(instance, args) { return value.call(instance, args); }); } } else { Object.defineProperty(base, name, desc); } } } function applyMemberDecs(Class, decInfos, metadata) { var ret = []; var protoInitializers; var staticInitializers; var existingProtoNonFields = new Map(); var existingStaticNonFields = new Map(); for(var i = 0; i < decInfos.length; i++){ var decInfo = decInfos[i]; if (!Array.isArray(decInfo)) continue; var kind = decInfo[1]; var name = decInfo[2]; var isPrivate = decInfo.length > 3; var isStatic = kind >= 5; var base; var initializers; if (isStatic) { base = Class; kind = kind - 5; staticInitializers = staticInitializers || []; initializers = staticInitializers; } else { base = Class.prototype; protoInitializers = protoInitializers || []; initializers = protoInitializers; } if (kind !== 0 && !isPrivate) { var existingNonFields = isStatic ? existingStaticNonFields : existingProtoNonFields; var existingKind = existingNonFields.get(name) || 0; if (existingKind === true || existingKind === 3 && kind !== 4 || existingKind === 4 && kind !== 3) { throw new Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + name); } else if (!existingKind && kind > 2) { existingNonFields.set(name, kind); } else { existingNonFields.set(name, true); } } applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata); } pushInitializers(ret, protoInitializers); pushInitializers(ret, staticInitializers); return ret; } function pushInitializers(ret, initializers) { if (initializers) { ret.push(function(instance) { for(var i = 0; i < initializers.length; i++){ initializers[i].call(instance); } return instance; }); } } function applyClassDecs(targetClass, classDecs, metadata) { if (classDecs.length > 0) { var initializers = []; var newClass = targetClass; var name = targetClass.name; for(var i = classDecs.length - 1; i >= 0; i--){ var decoratorFinishedRef = { v: false }; try { var nextNewClass = classDecs[i](newClass, { kind: "class", name: name, addInitializer: createAddInitializerMethod(initializers, decoratorFinishedRef), metadata }); } finally{ decoratorFinishedRef.v = true; } if (nextNewClass !== undefined) { assertValidReturnValue(10, nextNewClass); newClass = nextNewClass; } } return [ defineMetadata(newClass, metadata), function() { for(var i = 0; i < initializers.length; i++){ initializers[i].call(newClass); } } ]; } } function defineMetadata(Class, metadata) { return Object.defineProperty(Class, Symbol.metadata || Symbol.for("Symbol.metadata"), { configurable: true, enumerable: true, value: metadata }); } return function applyDecs2203R(targetClass, memberDecs, classDecs, parentClass) { if (parentClass !== void 0) { var parentMetadata = parentClass[Symbol.metadata || Symbol.for("Symbol.metadata")]; } var metadata = Object.create(parentMetadata === void 0 ? null : parentMetadata); var e = applyMemberDecs(targetClass, memberDecs, metadata); if (!classDecs.length) defineMetadata(targetClass, metadata); return { e: e, get c () { return applyClassDecs(targetClass, classDecs, metadata); } }; }; } function _apply_decs_2203_r$1(targetClass, memberDecs, classDecs, parentClass) { return (_apply_decs_2203_r$1 = applyDecs2203RFactory$1())(targetClass, memberDecs, classDecs, parentClass); } var _initProto$1; /** * ContextChatEngine uses the Index to get the appropriate context for each query. * The context is stored in the system prompt, and the chat history is chunk, * allowing the appropriate context to be surfaced for each query. */ class ContextChatEngine extends PromptMixin { static{ ({ e: [_initProto$1] } = _apply_decs_2203_r$1(this, [ [ wrapEventCaller, 2, "chat" ] ], [])); } get chatHistory() { return this.memory.getMessages(); } constructor(init){ super(), _initProto$1(this); this.chatModel = init.chatModel ?? Settings.llm; this.memory = new ChatMemoryBuffer({ chatHistory: init?.chatHistory }); this.contextGenerator = new DefaultContextGenerator({ retriever: init.retriever, contextSystemPrompt: init?.contextSystemPrompt, nodePostprocessors: init?.nodePostprocessors, contextRole: init?.contextRole, metadataMode: MetadataMode.LLM }); this.systemPrompt = init.systemPrompt; } _getPrompts() { return { ...this.contextGenerator.getPrompts() }; } _updatePrompts(prompts) { this.contextGenerator.updatePrompts(prompts); } _getPromptModules() { return { contextGenerator: this.contextGenerator }; } async chat(params) { const { message, stream } = params; const chatHistory = params.chatHistory ? new ChatMemoryBuffer({ chatHistory: params.chatHistory instanceof BaseMemory ? await params.chatHistory.getMessages() : params.chatHistory }) : this.memory; const requestMessages = await this.prepareRequestMessages(message, chatHistory); if (stream) { const stream = await this.chatModel.chat({ messages: requestMessages.messages, stream: true, additionalChatOptions: params.chatOptions }); return streamConverter(streamReducer({ stream, initialValue: "", reducer: (accumulator, part)=>accumulator += part.delta, finished: (accumulator)=>{ chatHistory.put({ content: accumulator, role: "assistant" }); } }), (r)=>EngineResponse.fromChatResponseChunk(r, requestMessages.nodes)); } const response = await this.chatModel.chat({ messages: requestMessages.messages, additionalChatOptions: params.chatOptions }); chatHistory.put(response.message); return EngineResponse.fromChatResponse(response, requestMessages.nodes); } reset() { this.memory.reset(); } async prepareRequestMessages(message, chatHistory) { chatHistory.put({ content: message, role: "user" }); const textOnly = extractText(message); const context = await this.contextGenerator.generate(textOnly); const systemMessage = this.prependSystemPrompt(context.message); const messages = await chatHistory.getMessages([ systemMessage ]); return { nodes: context.nodes, messages }; } prependSystemPrompt(message) { if (!this.systemPrompt) return message; return { ...message, content: this.systemPrompt.trim() + "\n" + extractText(message.content) }; } } function applyDecs2203RFactory() { function createAddInitializerMethod(initializers, decoratorFinishedRef) { return function addInitializer(initializer) { assertNotFinished(decoratorFinishedRef, "addInitializer"); assertCallable(initializer, "An initializer"); initializers.push(initializer); }; } function memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value) { var kindStr; switch(kind){ case 1: kindStr = "accessor"; break; case 2: kindStr = "method"; break; case 3: kindStr = "getter"; break; case 4: kindStr = "setter"; break; default: kindStr = "field"; } var ctx = { kind: kindStr, name: isPrivate ? "#" + name : name, static: isStatic, private: isPrivate, metadata: metadata }; var decoratorFinishedRef = { v: false }; ctx.addInitializer = createAddInitializerMethod(initializers, decoratorFinishedRef); var get, set; if (kind === 0) { if (isPrivate) { get = desc.get; set = desc.set; } else { get = function() { return this[name]; }; set = function(v) { this[name] = v; }; } } else if (kind === 2) { get = function() { return desc.value; }; } else { if (kind === 1 || kind === 3) { get = function() { return desc.get.call(this); }; } if (kind === 1 || kind === 4) { set = function(v) { desc.set.call(this, v); }; } } ctx.access = get && set ? { get: get, set: set } : get ? { get: get } : { set: set }; try { return dec(value, ctx); } finally{ decoratorFinishedRef.v = true; } } function assertNotFinished(decoratorFinishedRef, fnName) { if (decoratorFinishedRef.v) { throw new Error("attempted to call " + fnName + " after decoration was finished"); } } function assertCallable(fn, hint) { if (typeof fn !== "function") { throw new TypeError(hint + " must be a function"); } } function assertValidReturnValue(kind, value) { var type = typeof value; if (kind === 1) { if (type !== "object" || value === null) { throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0"); } if (value.get !== undefined) { assertCallable(value.get, "accessor.get"); } if (value.set !== undefined) { assertCallable(value.set, "accessor.set"); } if (value.init !== undefined) { assertCallable(value.init, "accessor.init"); } } else if (type !== "function") { var hint; if (kind === 0) { hint = "field"; } else if (kind === 10) { hint = "class"; } else { hint = "method"; } throw new TypeError(hint + " decorators must return a function or void 0"); } } function applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata) { var decs = decInfo[0]; var desc, init, value; if (isPrivate) { if (kind === 0 || kind === 1) { desc = { get: decInfo[3], set: decInfo[4] }; } else if (kind === 3) { desc = { get: decInfo[3] }; } else if (kind === 4) { desc = { set: decInfo[3] }; } else { desc = { value: decInfo[3] }; } } else if (kind !== 0) { desc = Object.getOwnPropertyDescriptor(base, name); } if (kind === 1) { value = { get: desc.get, set: desc.set }; } else if (kind === 2) { value = desc.value; } else if (kind === 3) { value = desc.get; } else if (kind === 4) { value = desc.set; } var newValue, get, set; if (typeof decs === "function") { newValue = memberDec(decs, name, desc, initializers, kind, isStatic, isPrivate, metadata, value); if (newValue !== void 0) { assertValidReturnValue(kind, newValue); if (kind === 0) { init = newValue; } else if (kind === 1) { init = newValue.init; get = newValue.get || value.get; set = newValue.set || value.set; value = { get: get, set: set }; } else { value = newValue; } } } else { for(var i = decs.length - 1; i >= 0; i--){ var dec = decs[i]; newValue = memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value); if (newValue !== void 0) { assertValidReturnValue(kind, newValue); var newInit; if (kind === 0) { newInit = newValue; } else if (kind === 1) { newInit = newValue.init; get = newValue.get || value.get; set = newValue.set || value.set; value = { get: get, set: set }; } else { value = newValue; } if (newInit !== void 0) { if (init === void 0) { init = newInit; } else if (typeof init === "function") { init = [ init, newInit ]; } else { init.push(newInit); } } } } } if (kind === 0 || kind === 1) { if (init === void 0) { init = function(instance, init) { return init; }; } else if (typeof init !== "function") { var ownInitializers = init; init = function(instance, init) { var value = init; for(var i = 0; i < ownInitializers.length; i++){ value = ownInitializers[i].call(instance, value); } return value; }; } else { var originalInitializer = init; init = function(instance, init) { return originalInitializer.call(instance, init); }; } ret.push(init); } if (kind !== 0) { if (kind === 1) { desc.get = value.get; desc.set = value.set; } else if (kind === 2) { desc.value = value; } else if (kind === 3) { desc.get = value; } else if (kind === 4) { desc.set = value; } if (isPrivate) { if (kind === 1) { ret.push(function(instance, args) { return value.get.call(instance, args); }); ret.push(function(instance, args) { return value.set.call(instance, args); }); } else if (kind === 2) { ret.push(value); } else { ret.push(function(instance, args) { return value.call(instance, args); }); } } else { Object.defineProperty(base, name, desc); } } } function applyMemberDecs(Class, decInfos, metadata) { var ret = []; var protoInitializers; var staticInitializers; var existingProtoNonFields = new Map(); var existingStaticNonFields = new Map(); for(var i = 0; i < decInfos.length; i++){ var decInfo = decInfos[i]; if (!Array.isArray(decInfo)) continue; var kind = decInfo[1]; var name = decInfo[2]; var isPrivate = decInfo.length > 3; var isStatic = kind >= 5; var base; var initializers; if (isStatic) { base = Class; kind = kind - 5; staticInitializers = staticInitializers || []; initializers = staticInitializers; } else { base = Class.prototype; protoInitializers = protoInitializers || []; initializers = protoInitializers; } if (kind !== 0 && !isPrivate) { var existingNonFields = isStatic ? existingStaticNonFields : existingProtoNonFields; var existingKind = existingNonFields.get(name) || 0; if (existingKind === true || existingKind === 3 && kind !== 4 || existingKind === 4 && kind !== 3) { throw new Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + name); } else if (!existingKind && kind > 2) { existingNonFields.set(name, kind); } else { existingNonFields.set(name, true); } } applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata); } pushInitializers(ret, protoInitializers); pushInitializers(ret, staticInitializers); return ret; } function pushInitializers(ret, initializers) { if (initializers) { ret.push(function(instance) { for(var i = 0; i < initializers.length; i++){ initializers[i].call(instance); } return instance; }); } } function applyClassDecs(targetClass, classDecs, metadata) { if (classDecs.length > 0) { var initializers = []; var newClass = targetClass; var name = targetClass.name; for(var i = classDecs.length - 1; i >= 0; i--){ var decoratorFinishedRef = { v: false }; try { var nextNewClass = classDecs[i](newClass, { kind: "class", name: name, addInitializer: createAddInitializerMethod(initializers, decoratorFinishedRef), metadata }); } finally{ decoratorFinishedRef.v = true; } if (nextNewClass !== undefined) { assertValidReturnValue(10, nextNewClass); newClass = nextNewClass; } } return [ defineMetadata(newClass, metadata), function() { for(var i = 0; i < initializers.length; i++){ initializers[i].call(newClass); } } ]; } } function defineMetadata(Class, metadata) { return Object.defineProperty(Class, Symbol.metadata || Symbol.for("Symbol.metadata"), { configurable: true, enumerable: true, value: metadata }); } return function applyDecs2203R(targetClass, memberDecs, classDecs, parentClass) { if (parentClass !== void 0) { var parentMetadata = parentClass[Symbol.metadata || Symbol.for("Symbol.metadata")]; } var metadata = Object.create(parentMetadata === void 0 ? null : parentMetadata); var e = applyMemberDecs(targetClass, memberDecs, metadata); if (!classDecs.length) defineMetadata(targetClass, metadata); return { e: e, get c () { return applyClassDecs(targetClass, classDecs, metadata); } }; }; } function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) { return (_apply_decs_2203_r = applyDecs2203RFactory())(targetClass, memberDecs, classDecs, parentClass); } var _initProto; /** * SimpleChatEngine is the simplest possible chat engine. Useful for using your own custom prompts. */ class SimpleChatEngine { static{ ({ e: [_initProto] } = _apply_decs_2203_r(this, [ [ wrapEventCaller, 2, "chat" ] ], [])); } get chatHistory() { return this.memory.getMessages(); } constructor(init){ _initProto(this); this.llm = init?.llm ?? Settings.llm; this.memory = init?.memory ?? new ChatMemoryBuffer({ llm: this.llm }); } async chat(params) { const { message, stream } = params; const chatHistory = params.chatHistory ? new ChatMemoryBuffer({ llm: this.llm, chatHistory: params.chatHistory instanceof BaseMemory ? await params.chatHistory.getMessages() : params.chatHistory }) : this.memory; chatHistory.put({ content: message, role: "user" }); if (stream) { const stream = await this.llm.chat({ messages: await chatHistory.getMessages(), stream: true }); return streamConverter(streamReducer({ stream, initialValue: "", reducer: (accumulator, part)=>accumulator + part.delta, finished: (accumulator)=>{ chatHistory.put({ content: accumulator, role: "assistant" }); } }), EngineResponse.fromChatResponseChunk); } const response = await this.llm.chat({ stream: false, messages: await chatHistory.getMessages() }); chatHistory.put(response.message); return EngineResponse.fromChatResponse(response); } reset() { this.memory.reset(); } } export { BaseChatEngine, ContextChatEngine, DefaultContextGenerator, SimpleChatEngine };