UNPKG

@jackhua/mini-langchain

Version:

A lightweight TypeScript implementation of LangChain with cost optimization features

246 lines 8.12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SequentialChain = exports.SimpleSequentialChain = exports.BaseChain = void 0; /** * Base class for all chains */ class BaseChain { constructor(config) { this.callbacks = []; this.verbose = false; this.memory = config?.memory; this.callbacks = config?.callbacks || []; this.verbose = config?.verbose || false; } /** * Invoke the chain with automatic memory handling */ async invoke(inputs) { const allCallbacks = [...this.callbacks]; // Load memory variables let chainInputs = { ...inputs }; if (this.memory) { const memoryVariables = this.memory.loadMemoryVariables(inputs); chainInputs = { ...chainInputs, ...memoryVariables }; } // Handle callbacks await this.handleChainStart(chainInputs, allCallbacks); try { // Run the chain const outputs = await this.call(chainInputs, allCallbacks); // Save to memory if (this.memory) { await this.memory.saveContext(inputs, outputs); } await this.handleChainEnd(outputs, allCallbacks); return outputs; } catch (error) { await this.handleChainError(error, allCallbacks); throw error; } } /** * Run the chain with a single string input/output */ async run(text) { const inputKey = this.inputKeys[0]; const outputKey = this.outputKeys[0]; if (!inputKey || !outputKey) { throw new Error('Chain must have at least one input and output key to use run()'); } const result = await this.invoke({ [inputKey]: text }); return result[outputKey]; } /** * Batch run the chain */ async batch(inputs) { const results = []; for (const input of inputs) { const result = await this.invoke(input); results.push(result); } return results; } /** * Stream the chain output */ async *stream(inputs) { // Default implementation just yields the final result // Subclasses can override for true streaming const result = await this.invoke(inputs); yield result; } /** * Add a callback handler */ addCallback(callback) { this.callbacks.push(callback); } /** * Handle chain start callbacks */ async handleChainStart(inputs, callbacks) { for (const callback of callbacks) { if (callback.handleChainStart) { await callback.handleChainStart(this.constructor.name, inputs); } } } /** * Handle chain end callbacks */ async handleChainEnd(outputs, callbacks) { for (const callback of callbacks) { if (callback.handleChainEnd) { await callback.handleChainEnd(outputs); } } } /** * Handle chain error callbacks */ async handleChainError(error, callbacks) { for (const callback of callbacks) { if (callback.handleChainError) { await callback.handleChainError(error); } } } /** * Serialize the chain */ serialize() { return { _type: this.constructor.name, inputKeys: this.inputKeys, outputKeys: this.outputKeys }; } } exports.BaseChain = BaseChain; /** * Simple sequential chain that runs multiple chains in sequence */ class SimpleSequentialChain extends BaseChain { constructor(config) { super(config); this.chains = config.chains; this.inputKey = config.inputKey || 'input'; this.outputKey = config.outputKey || 'output'; this.validateChains(); } validateChains() { if (this.chains.length === 0) { throw new Error('SimpleSequentialChain must have at least one chain'); } // Validate that each chain has exactly one input and output for (const chain of this.chains) { if (chain.inputKeys.length !== 1 || chain.outputKeys.length !== 1) { throw new Error('All chains in SimpleSequentialChain must have exactly one input and output key'); } } } get inputKeys() { return [this.inputKey]; } get outputKeys() { return [this.outputKey]; } async call(inputs, callbacks) { let currentOutput = inputs[this.inputKey]; for (const chain of this.chains) { const chainInputKey = chain.inputKeys[0]; const chainOutputKey = chain.outputKeys[0]; const result = await chain.call({ [chainInputKey]: currentOutput }, callbacks); currentOutput = result[chainOutputKey]; } return { [this.outputKey]: currentOutput }; } } exports.SimpleSequentialChain = SimpleSequentialChain; /** * Sequential chain that can handle multiple inputs/outputs */ class SequentialChain extends BaseChain { constructor(config) { super(config); this.chains = config.chains; this._inputKeys = config.inputVariables; this._outputKeys = config.outputVariables; this.returnAll = config.returnAll || false; this.validateChains(); } validateChains() { if (this.chains.length === 0) { throw new Error('SequentialChain must have at least one chain'); } // Track all available variables const availableVariables = new Set(this._inputKeys); const allOutputVariables = new Set(); for (const chain of this.chains) { // Check that all input keys are available for (const inputKey of chain.inputKeys) { if (!availableVariables.has(inputKey)) { throw new Error(`Chain ${chain.constructor.name} requires input "${inputKey}" which is not available`); } } // Add output keys to available variables for (const outputKey of chain.outputKeys) { availableVariables.add(outputKey); allOutputVariables.add(outputKey); } } // Check that all output variables are produced if (!this.returnAll) { for (const outputVar of this._outputKeys) { if (!allOutputVariables.has(outputVar)) { throw new Error(`Output variable "${outputVar}" is not produced by any chain`); } } } } get inputKeys() { return this._inputKeys; } get outputKeys() { return this._outputKeys; } async call(inputs, callbacks) { const allVariables = { ...inputs }; for (const chain of this.chains) { // Prepare inputs for this chain const chainInputs = {}; for (const inputKey of chain.inputKeys) { if (inputKey in allVariables) { chainInputs[inputKey] = allVariables[inputKey]; } else { throw new Error(`Missing required input "${inputKey}" for chain ${chain.constructor.name}`); } } // Run the chain const outputs = await chain.call(chainInputs, callbacks); // Store outputs for (const [key, value] of Object.entries(outputs)) { allVariables[key] = value; } } // Return requested outputs const result = {}; if (this.returnAll) { return allVariables; } else { for (const outputKey of this._outputKeys) { if (outputKey in allVariables) { result[outputKey] = allVariables[outputKey]; } } return result; } } } exports.SequentialChain = SequentialChain; //# sourceMappingURL=base.js.map