UNPKG

@langchain/core

Version:
108 lines (107 loc) 3.85 kB
import { deepCompareStrict } from "@cfworker/json-schema"; import { BaseOutputParser } from "./base.js"; import { isBaseMessage, isBaseMessageChunk, } from "../messages/base.js"; import { convertToChunk } from "../messages/utils.js"; import { GenerationChunk, ChatGenerationChunk, } from "../outputs.js"; /** * Class to parse the output of an LLM call that also allows streaming inputs. */ export class BaseTransformOutputParser extends BaseOutputParser { async *_transform(inputGenerator) { for await (const chunk of inputGenerator) { if (typeof chunk === "string") { yield this.parseResult([{ text: chunk }]); } else { yield this.parseResult([ { message: chunk, text: this._baseMessageToString(chunk), }, ]); } } } /** * Transforms an asynchronous generator of input into an asynchronous * generator of parsed output. * @param inputGenerator An asynchronous generator of input. * @param options A configuration object. * @returns An asynchronous generator of parsed output. */ async *transform(inputGenerator, options) { yield* this._transformStreamWithConfig(inputGenerator, this._transform.bind(this), { ...options, runType: "parser", }); } } /** * A base class for output parsers that can handle streaming input. It * extends the `BaseTransformOutputParser` class and provides a method for * converting parsed outputs into a diff format. */ export class BaseCumulativeTransformOutputParser extends BaseTransformOutputParser { constructor(fields) { super(fields); Object.defineProperty(this, "diff", { enumerable: true, configurable: true, writable: true, value: false }); this.diff = fields?.diff ?? this.diff; } async *_transform(inputGenerator) { let prevParsed; let accGen; for await (const chunk of inputGenerator) { if (typeof chunk !== "string" && typeof chunk.content !== "string") { throw new Error("Cannot handle non-string output."); } let chunkGen; if (isBaseMessageChunk(chunk)) { if (typeof chunk.content !== "string") { throw new Error("Cannot handle non-string message output."); } chunkGen = new ChatGenerationChunk({ message: chunk, text: chunk.content, }); } else if (isBaseMessage(chunk)) { if (typeof chunk.content !== "string") { throw new Error("Cannot handle non-string message output."); } chunkGen = new ChatGenerationChunk({ message: convertToChunk(chunk), text: chunk.content, }); } else { chunkGen = new GenerationChunk({ text: chunk }); } if (accGen === undefined) { accGen = chunkGen; } else { accGen = accGen.concat(chunkGen); } const parsed = await this.parsePartialResult([accGen]); if (parsed !== undefined && parsed !== null && !deepCompareStrict(parsed, prevParsed)) { if (this.diff) { yield this._diff(prevParsed, parsed); } else { yield parsed; } prevParsed = parsed; } } } getFormatInstructions() { return ""; } }