From bcc5e609ae05d3237b25332b97f8e8e273610f9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A4=95=E0=A4=BE=E0=A4=B0=E0=A4=A4=E0=A5=8B=E0=A4=AB?= =?UTF-8?q?=E0=A5=8D=E0=A4=AB=E0=A5=87=E0=A4=B2=E0=A4=B8=E0=A5=8D=E0=A4=95?= =?UTF-8?q?=E0=A5=8D=E0=A4=B0=E0=A4=BF=E0=A4=AA=E0=A5=8D=E0=A4=9F=E2=84=A2?= Date: Sun, 15 Dec 2024 11:46:52 +0100 Subject: [PATCH 1/4] copy over AgentExecutor and fix the imports --- .../nodes/agents/Agent/AgentExecutor.ts | 742 ++++++++++++++++++ 1 file changed, 742 insertions(+) create mode 100644 packages/@n8n/nodes-langchain/nodes/agents/Agent/AgentExecutor.ts diff --git a/packages/@n8n/nodes-langchain/nodes/agents/Agent/AgentExecutor.ts b/packages/@n8n/nodes-langchain/nodes/agents/Agent/AgentExecutor.ts new file mode 100644 index 0000000000000..bede03fb6ec88 --- /dev/null +++ b/packages/@n8n/nodes-langchain/nodes/agents/Agent/AgentExecutor.ts @@ -0,0 +1,742 @@ +import { + type StructuredToolInterface, + type ToolInterface, + ToolInputParsingException, + Tool, +} from '@langchain/core/tools'; +import { Runnable, type RunnableConfig, patchConfig } from '@langchain/core/runnables'; +import { AgentAction, AgentFinish, AgentStep } from '@langchain/core/agents'; +import { ChainValues } from '@langchain/core/utils/types'; +import { + CallbackManager, + CallbackManagerForChainRun, + Callbacks, +} from '@langchain/core/callbacks/manager'; +import { OutputParserException } from '@langchain/core/output_parsers'; +import { Serializable } from '@langchain/core/load/serializable'; +import { SerializedLLMChain } from 'langchain/dist/chains/serde'; +import { StoppingMethod } from 'langchain/dist/agents/types'; +import { + AgentRunnableSequence, + BaseMultiActionAgent, + BaseSingleActionAgent, + RunnableMultiActionAgent, + RunnableSingleActionAgent, + isRunnableAgent, +} from 'langchain/dist/agents/agent'; +import { BaseChain, ChainInputs } from 'langchain/dist/chains/base'; + +interface AgentExecutorIteratorInput { + agentExecutor: AgentExecutor; + inputs: Record; + config?: RunnableConfig; + /** @deprecated Use "config" */ + callbacks?: Callbacks; + /** @deprecated Use "config" */ + tags?: string[]; + /** @deprecated Use "config" */ + metadata?: Record; + runName?: string; + runManager?: CallbackManagerForChainRun; +} + +export class AgentExecutorIterator extends Serializable implements AgentExecutorIteratorInput { + lc_namespace = ['langchain', 'agents', 'executor_iterator']; + + agentExecutor: AgentExecutor; + + inputs: Record; + + config?: RunnableConfig; + + /** @deprecated Use "config" */ + callbacks?: Callbacks; + + /** @deprecated Use "config" */ + tags: string[] | undefined; + + /** @deprecated Use "config" */ + metadata: Record | undefined; + + /** @deprecated Use "config" */ + runName: string | undefined; + + private _finalOutputs: Record | undefined; + + get finalOutputs(): Record | undefined { + return this._finalOutputs; + } + + /** Intended to be used as a setter method, needs to be async. */ + async setFinalOutputs(value: Record | undefined) { + this._finalOutputs = undefined; + if (value) { + const preparedOutputs: Record = await this.agentExecutor.prepOutputs( + this.inputs, + value, + true, + ); + this._finalOutputs = preparedOutputs; + } + } + + runManager: CallbackManagerForChainRun | undefined; + + intermediateSteps: AgentStep[] = []; + + iterations = 0; + + get nameToToolMap(): Record { + const toolMap = this.agentExecutor.tools.map((tool) => ({ + [tool.name]: tool, + })); + return Object.assign({}, ...toolMap); + } + + constructor(fields: AgentExecutorIteratorInput) { + super(fields); + this.agentExecutor = fields.agentExecutor; + this.inputs = fields.inputs; + this.callbacks = fields.callbacks; + this.tags = fields.tags; + this.metadata = fields.metadata; + this.runName = fields.runName; + this.runManager = fields.runManager; + this.config = fields.config; + } + + /** + * Reset the iterator to its initial state, clearing intermediate steps, + * iterations, and the final output. + */ + reset(): void { + this.intermediateSteps = []; + this.iterations = 0; + this._finalOutputs = undefined; + } + + updateIterations(): void { + this.iterations += 1; + } + + async *streamIterator() { + this.reset(); + + // Loop to handle iteration + while (true) { + try { + if (this.iterations === 0) { + await this.onFirstStep(); + } + + const result = await this._callNext(); + yield result; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } catch (e: any) { + if ('message' in e && e.message.startsWith('Final outputs already reached: ')) { + if (!this.finalOutputs) { + throw e; + } + return this.finalOutputs; + } + if (this.runManager) { + await this.runManager.handleChainError(e); + } + throw e; + } + } + } + + /** + * Perform any necessary setup for the first step + * of the asynchronous iterator. + */ + async onFirstStep(): Promise { + if (this.iterations === 0) { + const callbackManager = await CallbackManager.configure( + this.callbacks ?? this.config?.callbacks, + this.agentExecutor.callbacks, + this.tags ?? this.config?.tags, + this.agentExecutor.tags, + this.metadata ?? this.config?.metadata, + this.agentExecutor.metadata, + { + verbose: this.agentExecutor.verbose, + }, + ); + this.runManager = await callbackManager?.handleChainStart( + this.agentExecutor.toJSON(), + this.inputs, + this.config?.runId, + undefined, + this.tags ?? this.config?.tags, + this.metadata ?? this.config?.metadata, + this.runName ?? this.config?.runName, + ); + if (this.config !== undefined) { + delete this.config.runId; + } + } + } + + /** + * Execute the next step in the chain using the + * AgentExecutor's _takeNextStep method. + */ + async _executeNextStep( + runManager?: CallbackManagerForChainRun, + ): Promise { + return this.agentExecutor._takeNextStep( + this.nameToToolMap, + this.inputs, + this.intermediateSteps, + runManager, + this.config, + ); + } + + /** + * Process the output of the next step, + * handling AgentFinish and tool return cases. + */ + async _processNextStepOutput( + nextStepOutput: AgentFinish | AgentStep[], + runManager?: CallbackManagerForChainRun, + ): Promise> { + if ('returnValues' in nextStepOutput) { + const output = await this.agentExecutor._return( + nextStepOutput as AgentFinish, + this.intermediateSteps, + runManager, + ); + if (this.runManager) { + await this.runManager.handleChainEnd(output); + } + await this.setFinalOutputs(output); + return output; + } + + this.intermediateSteps = this.intermediateSteps.concat(nextStepOutput as AgentStep[]); + + let output: Record = {}; + if (Array.isArray(nextStepOutput) && nextStepOutput.length === 1) { + const nextStep = nextStepOutput[0]; + const toolReturn = await this.agentExecutor._getToolReturn(nextStep); + if (toolReturn) { + output = await this.agentExecutor._return(toolReturn, this.intermediateSteps, runManager); + await this.runManager?.handleChainEnd(output); + await this.setFinalOutputs(output); + } + } + output = { intermediateSteps: nextStepOutput as AgentStep[] }; + return output; + } + + async _stop(): Promise> { + const output = await this.agentExecutor.agent.returnStoppedResponse( + this.agentExecutor.earlyStoppingMethod, + this.intermediateSteps, + this.inputs, + ); + const returnedOutput = await this.agentExecutor._return( + output, + this.intermediateSteps, + this.runManager, + ); + await this.setFinalOutputs(returnedOutput); + await this.runManager?.handleChainEnd(returnedOutput); + return returnedOutput; + } + + async _callNext(): Promise> { + // final output already reached: stopiteration (final output) + if (this.finalOutputs) { + throw new Error( + `Final outputs already reached: ${JSON.stringify(this.finalOutputs, null, 2)}`, + ); + } + // timeout/max iterations: stopiteration (stopped response) + if (!this.agentExecutor.shouldContinueGetter(this.iterations)) { + return this._stop(); + } + const nextStepOutput = await this._executeNextStep(this.runManager); + const output = await this._processNextStepOutput(nextStepOutput, this.runManager); + this.updateIterations(); + return output; + } +} + +type ExtractToolType = T extends { ToolType: infer ToolInterface } + ? ToolInterface + : StructuredToolInterface; + +/** + * Interface defining the structure of input data for creating an + * AgentExecutor. It extends ChainInputs and includes additional + * properties specific to agent execution. + */ +export interface AgentExecutorInput extends ChainInputs { + agent: + | BaseSingleActionAgent + | BaseMultiActionAgent + | Runnable; + tools: ExtractToolType[]; + returnIntermediateSteps?: boolean; + maxIterations?: number; + earlyStoppingMethod?: StoppingMethod; + handleParsingErrors?: + | boolean + | string + | ((e: OutputParserException | ToolInputParsingException) => string); + handleToolRuntimeErrors?: (e: Error) => string; +} + +// TODO: Type properly with { intermediateSteps?: AgentStep[] }; +export type AgentExecutorOutput = ChainValues; + +/** + * Tool that just returns the query. + * Used for exception tracking. + */ +export class ExceptionTool extends Tool { + name = '_Exception'; + + description = 'Exception tool'; + + async _call(query: string) { + return query; + } +} + +/** + * A chain managing an agent using tools. + * @augments BaseChain + * @example + * ```typescript + * + * const executor = AgentExecutor.fromAgentAndTools({ + * agent: async () => loadAgentFromLangchainHub(), + * tools: [new SerpAPI(), new Calculator()], + * returnIntermediateSteps: true, + * }); + * + * const result = await executor.invoke({ + * input: `Who is Olivia Wilde's boyfriend? What is his current age raised to the 0.23 power?`, + * }); + * + * ``` + */ +export class AgentExecutor extends BaseChain { + static lc_name() { + return 'AgentExecutor'; + } + + get lc_namespace() { + return ['langchain', 'agents', 'executor']; + } + + agent: BaseSingleActionAgent | BaseMultiActionAgent; + + tools: this['agent']['ToolType'][]; + + returnIntermediateSteps = false; + + maxIterations?: number = 15; + + earlyStoppingMethod: StoppingMethod = 'force'; + + // TODO: Update BaseChain implementation on breaking change to include this + returnOnlyOutputs = true; + + /** + * How to handle errors raised by the agent's output parser. + Defaults to `False`, which raises the error. + + If `true`, the error will be sent back to the LLM as an observation. + If a string, the string itself will be sent to the LLM as an observation. + If a callable function, the function will be called with the exception + as an argument, and the result of that function will be passed to the agent + as an observation. + */ + handleParsingErrors: + | boolean + | string + | ((e: OutputParserException | ToolInputParsingException) => string) = false; + + handleToolRuntimeErrors?: (e: Error) => string; + + get inputKeys() { + return this.agent.inputKeys; + } + + get outputKeys() { + return this.agent.returnValues; + } + + constructor(input: AgentExecutorInput) { + let agent: BaseSingleActionAgent | BaseMultiActionAgent; + let returnOnlyOutputs = true; + if (Runnable.isRunnable(input.agent)) { + if (AgentRunnableSequence.isAgentRunnableSequence(input.agent)) { + if (input.agent.singleAction) { + agent = new RunnableSingleActionAgent({ + runnable: input.agent, + streamRunnable: input.agent.streamRunnable, + }); + } else { + agent = new RunnableMultiActionAgent({ + runnable: input.agent, + streamRunnable: input.agent.streamRunnable, + }); + } + } else { + agent = new RunnableMultiActionAgent({ runnable: input.agent }); + } + // TODO: Update BaseChain implementation on breaking change + returnOnlyOutputs = false; + } else { + if (isRunnableAgent(input.agent)) { + returnOnlyOutputs = false; + } + agent = input.agent; + } + + super(input); + this.agent = agent; + this.tools = input.tools; + this.handleParsingErrors = input.handleParsingErrors ?? this.handleParsingErrors; + this.handleToolRuntimeErrors = input.handleToolRuntimeErrors; + this.returnOnlyOutputs = returnOnlyOutputs; + if (this.agent._agentActionType() === 'multi') { + for (const tool of this.tools) { + if (tool.returnDirect) { + throw new Error( + `Tool with return direct ${tool.name} not supported for multi-action agent.`, + ); + } + } + } + this.returnIntermediateSteps = input.returnIntermediateSteps ?? this.returnIntermediateSteps; + this.maxIterations = input.maxIterations ?? this.maxIterations; + this.earlyStoppingMethod = input.earlyStoppingMethod ?? this.earlyStoppingMethod; + } + + /** Create from agent and a list of tools. */ + static fromAgentAndTools(fields: AgentExecutorInput): AgentExecutor { + return new AgentExecutor(fields); + } + + get shouldContinueGetter() { + return this.shouldContinue.bind(this); + } + + /** + * Method that checks if the agent execution should continue based on the + * number of iterations. + * @param iterations The current number of iterations. + * @returns A boolean indicating whether the agent execution should continue. + */ + private shouldContinue(iterations: number): boolean { + return this.maxIterations === undefined || iterations < this.maxIterations; + } + + /** @ignore */ + async _call( + inputs: ChainValues, + runManager?: CallbackManagerForChainRun, + config?: RunnableConfig, + ): Promise { + const toolsByName = Object.fromEntries(this.tools.map((t) => [t.name.toLowerCase(), t])); + const steps: AgentStep[] = []; + let iterations = 0; + + const getOutput = async (finishStep: AgentFinish): Promise => { + const { returnValues } = finishStep; + const additional = await this.agent.prepareForOutput(returnValues, steps); + + await runManager?.handleAgentEnd(finishStep); + + let response; + + if (this.returnIntermediateSteps) { + response = { ...returnValues, intermediateSteps: steps, ...additional }; + } else { + response = { ...returnValues, ...additional }; + } + if (!this.returnOnlyOutputs) { + response = { ...inputs, ...response }; + } + return response; + }; + + while (this.shouldContinue(iterations)) { + let output; + try { + output = await this.agent.plan(steps, inputs, runManager?.getChild(), config); + } catch (e) { + // eslint-disable-next-line no-instanceof/no-instanceof + if (e instanceof OutputParserException) { + let observation; + let text = e.message; + if (this.handleParsingErrors === true) { + if (e.sendToLLM) { + observation = e.observation; + text = e.llmOutput ?? ''; + } else { + observation = 'Invalid or incomplete response'; + } + } else if (typeof this.handleParsingErrors === 'string') { + observation = this.handleParsingErrors; + } else if (typeof this.handleParsingErrors === 'function') { + observation = this.handleParsingErrors(e); + } else { + throw e; + } + output = { + tool: '_Exception', + toolInput: observation, + log: text, + } as AgentAction; + } else { + throw e; + } + } + // Check if the agent has finished + if ('returnValues' in output) { + return getOutput(output); + } + + let actions: AgentAction[]; + if (Array.isArray(output)) { + actions = output as AgentAction[]; + } else { + actions = [output as AgentAction]; + } + + const newSteps = await Promise.all( + actions.map(async (action) => { + await runManager?.handleAgentAction(action); + const tool = + action.tool === '_Exception' + ? new ExceptionTool() + : toolsByName[action.tool?.toLowerCase()]; + let observation; + try { + observation = tool + ? await tool.invoke( + action.toolInput, + patchConfig(config, { callbacks: runManager?.getChild() }), + ) + : `${action.tool} is not a valid tool, try another one.`; + if (typeof observation !== 'string') { + throw new Error('Received unsupported non-string response from tool call.'); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } catch (e: any) { + // eslint-disable-next-line no-instanceof/no-instanceof + if (e instanceof ToolInputParsingException) { + if (this.handleParsingErrors === true) { + observation = 'Invalid or incomplete tool input. Please try again.'; + } else if (typeof this.handleParsingErrors === 'string') { + observation = this.handleParsingErrors; + } else if (typeof this.handleParsingErrors === 'function') { + observation = this.handleParsingErrors(e); + } else { + throw e; + } + observation = await new ExceptionTool().call(observation, runManager?.getChild()); + return { action, observation: observation ?? '' }; + } else if (this.handleToolRuntimeErrors !== undefined) { + observation = this.handleToolRuntimeErrors(e); + } + } + + return { action, observation: observation ?? '' }; + }), + ); + + steps.push(...newSteps); + + const lastStep = steps[steps.length - 1]; + const lastTool = toolsByName[lastStep.action.tool?.toLowerCase()]; + + if (lastTool?.returnDirect) { + return getOutput({ + returnValues: { [this.agent.returnValues[0]]: lastStep.observation }, + log: '', + }); + } + + iterations += 1; + } + + const finish = await this.agent.returnStoppedResponse(this.earlyStoppingMethod, steps, inputs); + + return getOutput(finish); + } + + async _takeNextStep( + nameToolMap: Record, + inputs: ChainValues, + intermediateSteps: AgentStep[], + runManager?: CallbackManagerForChainRun, + config?: RunnableConfig, + ): Promise { + let output; + try { + output = await this.agent.plan(intermediateSteps, inputs, runManager?.getChild(), config); + } catch (e) { + // eslint-disable-next-line no-instanceof/no-instanceof + if (e instanceof OutputParserException) { + let observation; + let text = e.message; + if (this.handleParsingErrors === true) { + if (e.sendToLLM) { + observation = e.observation; + text = e.llmOutput ?? ''; + } else { + observation = 'Invalid or incomplete response'; + } + } else if (typeof this.handleParsingErrors === 'string') { + observation = this.handleParsingErrors; + } else if (typeof this.handleParsingErrors === 'function') { + observation = this.handleParsingErrors(e); + } else { + throw e; + } + output = { + tool: '_Exception', + toolInput: observation, + log: text, + } as AgentAction; + } else { + throw e; + } + } + + if ('returnValues' in output) { + return output; + } + + let actions: AgentAction[]; + if (Array.isArray(output)) { + actions = output as AgentAction[]; + } else { + actions = [output as AgentAction]; + } + + const result: AgentStep[] = []; + for (const agentAction of actions) { + let observation = ''; + if (runManager) { + await runManager?.handleAgentAction(agentAction); + } + if (agentAction.tool in nameToolMap) { + const tool = nameToolMap[agentAction.tool]; + try { + observation = await tool.call(agentAction.toolInput, runManager?.getChild()); + if (typeof observation !== 'string') { + throw new Error('Received unsupported non-string response from tool call.'); + } + } catch (e) { + // eslint-disable-next-line no-instanceof/no-instanceof + if (e instanceof ToolInputParsingException) { + if (this.handleParsingErrors === true) { + observation = 'Invalid or incomplete tool input. Please try again.'; + } else if (typeof this.handleParsingErrors === 'string') { + observation = this.handleParsingErrors; + } else if (typeof this.handleParsingErrors === 'function') { + observation = this.handleParsingErrors(e); + } else { + throw e; + } + observation = await new ExceptionTool().call(observation, runManager?.getChild()); + } + } + } else { + observation = `${ + agentAction.tool + } is not a valid tool, try another available tool: ${Object.keys(nameToolMap).join(', ')}`; + } + result.push({ + action: agentAction, + observation, + }); + } + return result; + } + + async _return( + output: AgentFinish, + intermediateSteps: AgentStep[], + runManager?: CallbackManagerForChainRun, + ): Promise { + if (runManager) { + await runManager.handleAgentEnd(output); + } + const finalOutput: Record = output.returnValues; + if (this.returnIntermediateSteps) { + finalOutput.intermediateSteps = intermediateSteps; + } + return finalOutput; + } + + async _getToolReturn(nextStepOutput: AgentStep): Promise { + const { action, observation } = nextStepOutput; + const nameToolMap = Object.fromEntries(this.tools.map((t) => [t.name.toLowerCase(), t])); + const [returnValueKey = 'output'] = this.agent.returnValues; + // Invalid tools won't be in the map, so we return False. + if (action.tool in nameToolMap) { + if (nameToolMap[action.tool].returnDirect) { + return { + returnValues: { [returnValueKey]: observation }, + log: '', + }; + } + } + return null; + } + + _returnStoppedResponse(earlyStoppingMethod: StoppingMethod) { + if (earlyStoppingMethod === 'force') { + return { + returnValues: { + output: 'Agent stopped due to iteration limit or time limit.', + }, + log: '', + } as AgentFinish; + } + throw new Error(`Got unsupported early_stopping_method: ${earlyStoppingMethod}`); + } + + async *_streamIterator( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + inputs: Record, + options?: Partial, + ): AsyncGenerator { + const agentExecutorIterator = new AgentExecutorIterator({ + inputs, + agentExecutor: this, + config: options, + // TODO: Deprecate these other parameters + metadata: options?.metadata, + tags: options?.tags, + callbacks: options?.callbacks, + }); + const iterator = agentExecutorIterator.streamIterator(); + for await (const step of iterator) { + if (!step) { + continue; + } + yield step; + } + } + + _chainType() { + return 'agent_executor' as const; + } + + serialize(): SerializedLLMChain { + throw new Error('Cannot serialize an AgentExecutor'); + } +} From 2aa575b68a21a29637408c13cfb03c6cb35581b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A4=95=E0=A4=BE=E0=A4=B0=E0=A4=A4=E0=A5=8B=E0=A4=AB?= =?UTF-8?q?=E0=A5=8D=E0=A4=AB=E0=A5=87=E0=A4=B2=E0=A4=B8=E0=A5=8D=E0=A4=95?= =?UTF-8?q?=E0=A5=8D=E0=A4=B0=E0=A4=BF=E0=A4=AA=E0=A5=8D=E0=A4=9F=E2=84=A2?= Date: Sun, 15 Dec 2024 11:50:35 +0100 Subject: [PATCH 2/4] format and lintfix --- .../nodes/agents/Agent/AgentExecutor.ts | 80 +++++++++---------- 1 file changed, 38 insertions(+), 42 deletions(-) diff --git a/packages/@n8n/nodes-langchain/nodes/agents/Agent/AgentExecutor.ts b/packages/@n8n/nodes-langchain/nodes/agents/Agent/AgentExecutor.ts index bede03fb6ec88..f2ea96f1b8726 100644 --- a/packages/@n8n/nodes-langchain/nodes/agents/Agent/AgentExecutor.ts +++ b/packages/@n8n/nodes-langchain/nodes/agents/Agent/AgentExecutor.ts @@ -1,30 +1,28 @@ +import type { AgentAction, AgentFinish, AgentStep } from '@langchain/core/agents'; +import type { CallbackManagerForChainRun, Callbacks } from '@langchain/core/callbacks/manager'; +import { CallbackManager } from '@langchain/core/callbacks/manager'; +import { Serializable } from '@langchain/core/load/serializable'; +import { OutputParserException } from '@langchain/core/output_parsers'; +import { Runnable, type RunnableConfig, patchConfig } from '@langchain/core/runnables'; import { type StructuredToolInterface, type ToolInterface, ToolInputParsingException, Tool, } from '@langchain/core/tools'; -import { Runnable, type RunnableConfig, patchConfig } from '@langchain/core/runnables'; -import { AgentAction, AgentFinish, AgentStep } from '@langchain/core/agents'; -import { ChainValues } from '@langchain/core/utils/types'; -import { - CallbackManager, - CallbackManagerForChainRun, - Callbacks, -} from '@langchain/core/callbacks/manager'; -import { OutputParserException } from '@langchain/core/output_parsers'; -import { Serializable } from '@langchain/core/load/serializable'; -import { SerializedLLMChain } from 'langchain/dist/chains/serde'; -import { StoppingMethod } from 'langchain/dist/agents/types'; +import type { ChainValues } from '@langchain/core/utils/types'; +import type { BaseMultiActionAgent, BaseSingleActionAgent } from 'langchain/dist/agents/agent'; import { AgentRunnableSequence, - BaseMultiActionAgent, - BaseSingleActionAgent, RunnableMultiActionAgent, RunnableSingleActionAgent, isRunnableAgent, } from 'langchain/dist/agents/agent'; -import { BaseChain, ChainInputs } from 'langchain/dist/chains/base'; +import type { StoppingMethod } from 'langchain/dist/agents/types'; +import type { ChainInputs } from 'langchain/dist/chains/base'; +import { BaseChain } from 'langchain/dist/chains/base'; +import type { SerializedLLMChain } from 'langchain/dist/chains/serde'; +import { ApplicationError } from 'n8n-workflow'; interface AgentExecutorIteratorInput { agentExecutor: AgentExecutor; @@ -153,7 +151,7 @@ export class AgentExecutorIterator extends Serializable implements AgentExecutor */ async onFirstStep(): Promise { if (this.iterations === 0) { - const callbackManager = await CallbackManager.configure( + const callbackManager = CallbackManager.configure( this.callbacks ?? this.config?.callbacks, this.agentExecutor.callbacks, this.tags ?? this.config?.tags, @@ -186,7 +184,7 @@ export class AgentExecutorIterator extends Serializable implements AgentExecutor async _executeNextStep( runManager?: CallbackManagerForChainRun, ): Promise { - return this.agentExecutor._takeNextStep( + return await this.agentExecutor._takeNextStep( this.nameToToolMap, this.inputs, this.intermediateSteps, @@ -205,7 +203,7 @@ export class AgentExecutorIterator extends Serializable implements AgentExecutor ): Promise> { if ('returnValues' in nextStepOutput) { const output = await this.agentExecutor._return( - nextStepOutput as AgentFinish, + nextStepOutput, this.intermediateSteps, runManager, ); @@ -216,7 +214,7 @@ export class AgentExecutorIterator extends Serializable implements AgentExecutor return output; } - this.intermediateSteps = this.intermediateSteps.concat(nextStepOutput as AgentStep[]); + this.intermediateSteps = this.intermediateSteps.concat(nextStepOutput); let output: Record = {}; if (Array.isArray(nextStepOutput) && nextStepOutput.length === 1) { @@ -228,7 +226,7 @@ export class AgentExecutorIterator extends Serializable implements AgentExecutor await this.setFinalOutputs(output); } } - output = { intermediateSteps: nextStepOutput as AgentStep[] }; + output = { intermediateSteps: nextStepOutput }; return output; } @@ -251,13 +249,13 @@ export class AgentExecutorIterator extends Serializable implements AgentExecutor async _callNext(): Promise> { // final output already reached: stopiteration (final output) if (this.finalOutputs) { - throw new Error( + throw new ApplicationError( `Final outputs already reached: ${JSON.stringify(this.finalOutputs, null, 2)}`, ); } // timeout/max iterations: stopiteration (stopped response) if (!this.agentExecutor.shouldContinueGetter(this.iterations)) { - return this._stop(); + return await this._stop(); } const nextStepOutput = await this._executeNextStep(this.runManager); const output = await this._processNextStepOutput(nextStepOutput, this.runManager); @@ -266,8 +264,8 @@ export class AgentExecutorIterator extends Serializable implements AgentExecutor } } -type ExtractToolType = T extends { ToolType: infer ToolInterface } - ? ToolInterface +type ExtractToolType = T extends { ToolType: infer IToolInterface } + ? IToolInterface : StructuredToolInterface; /** @@ -280,7 +278,7 @@ export interface AgentExecutorInput extends ChainInputs { | BaseSingleActionAgent | BaseMultiActionAgent | Runnable; - tools: ExtractToolType[]; + tools: Array>; returnIntermediateSteps?: boolean; maxIterations?: number; earlyStoppingMethod?: StoppingMethod; @@ -337,7 +335,7 @@ export class AgentExecutor extends BaseChain { agent: BaseSingleActionAgent | BaseMultiActionAgent; - tools: this['agent']['ToolType'][]; + tools: Array; returnIntermediateSteps = false; @@ -410,7 +408,7 @@ export class AgentExecutor extends BaseChain { if (this.agent._agentActionType() === 'multi') { for (const tool of this.tools) { if (tool.returnDirect) { - throw new Error( + throw new ApplicationError( `Tool with return direct ${tool.name} not supported for multi-action agent.`, ); } @@ -474,7 +472,6 @@ export class AgentExecutor extends BaseChain { try { output = await this.agent.plan(steps, inputs, runManager?.getChild(), config); } catch (e) { - // eslint-disable-next-line no-instanceof/no-instanceof if (e instanceof OutputParserException) { let observation; let text = e.message; @@ -503,14 +500,14 @@ export class AgentExecutor extends BaseChain { } // Check if the agent has finished if ('returnValues' in output) { - return getOutput(output); + return await getOutput(output); } let actions: AgentAction[]; if (Array.isArray(output)) { - actions = output as AgentAction[]; + actions = output; } else { - actions = [output as AgentAction]; + actions = [output]; } const newSteps = await Promise.all( @@ -529,11 +526,12 @@ export class AgentExecutor extends BaseChain { ) : `${action.tool} is not a valid tool, try another one.`; if (typeof observation !== 'string') { - throw new Error('Received unsupported non-string response from tool call.'); + throw new ApplicationError( + 'Received unsupported non-string response from tool call.', + ); } // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (e: any) { - // eslint-disable-next-line no-instanceof/no-instanceof if (e instanceof ToolInputParsingException) { if (this.handleParsingErrors === true) { observation = 'Invalid or incomplete tool input. Please try again.'; @@ -561,7 +559,7 @@ export class AgentExecutor extends BaseChain { const lastTool = toolsByName[lastStep.action.tool?.toLowerCase()]; if (lastTool?.returnDirect) { - return getOutput({ + return await getOutput({ returnValues: { [this.agent.returnValues[0]]: lastStep.observation }, log: '', }); @@ -572,7 +570,7 @@ export class AgentExecutor extends BaseChain { const finish = await this.agent.returnStoppedResponse(this.earlyStoppingMethod, steps, inputs); - return getOutput(finish); + return await getOutput(finish); } async _takeNextStep( @@ -586,7 +584,6 @@ export class AgentExecutor extends BaseChain { try { output = await this.agent.plan(intermediateSteps, inputs, runManager?.getChild(), config); } catch (e) { - // eslint-disable-next-line no-instanceof/no-instanceof if (e instanceof OutputParserException) { let observation; let text = e.message; @@ -620,9 +617,9 @@ export class AgentExecutor extends BaseChain { let actions: AgentAction[]; if (Array.isArray(output)) { - actions = output as AgentAction[]; + actions = output; } else { - actions = [output as AgentAction]; + actions = [output]; } const result: AgentStep[] = []; @@ -636,10 +633,9 @@ export class AgentExecutor extends BaseChain { try { observation = await tool.call(agentAction.toolInput, runManager?.getChild()); if (typeof observation !== 'string') { - throw new Error('Received unsupported non-string response from tool call.'); + throw new ApplicationError('Received unsupported non-string response from tool call.'); } } catch (e) { - // eslint-disable-next-line no-instanceof/no-instanceof if (e instanceof ToolInputParsingException) { if (this.handleParsingErrors === true) { observation = 'Invalid or incomplete tool input. Please try again.'; @@ -706,7 +702,7 @@ export class AgentExecutor extends BaseChain { log: '', } as AgentFinish; } - throw new Error(`Got unsupported early_stopping_method: ${earlyStoppingMethod}`); + throw new ApplicationError(`Got unsupported early_stopping_method: ${earlyStoppingMethod}`); } async *_streamIterator( @@ -737,6 +733,6 @@ export class AgentExecutor extends BaseChain { } serialize(): SerializedLLMChain { - throw new Error('Cannot serialize an AgentExecutor'); + throw new ApplicationError('Cannot serialize an AgentExecutor'); } } From cdeb35b81262712bf88833d1fe06cc71dd7b9542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A4=95=E0=A4=BE=E0=A4=B0=E0=A4=A4=E0=A5=8B=E0=A4=AB?= =?UTF-8?q?=E0=A5=8D=E0=A4=AB=E0=A5=87=E0=A4=B2=E0=A4=B8=E0=A5=8D=E0=A4=95?= =?UTF-8?q?=E0=A5=8D=E0=A4=B0=E0=A4=BF=E0=A4=AA=E0=A5=8D=E0=A4=9F=E2=84=A2?= Date: Mon, 16 Dec 2024 11:42:42 +0100 Subject: [PATCH 3/4] fix more imports, and patch langchain exports --- package.json | 1 + .../nodes/agents/Agent/AgentExecutor.ts | 10 ++-- patches/langchain@0.3.6.patch | 55 +++++++++++++++++++ pnpm-lock.yaml | 21 ++++--- 4 files changed, 72 insertions(+), 15 deletions(-) create mode 100644 patches/langchain@0.3.6.patch diff --git a/package.json b/package.json index 29be8d868af7f..f9fde8c3337b2 100644 --- a/package.json +++ b/package.json @@ -84,6 +84,7 @@ "ws": ">=8.17.1" }, "patchedDependencies": { + "langchain@0.3.6": "patches/langchain@0.3.6.patch", "typedi@0.10.0": "patches/typedi@0.10.0.patch", "pkce-challenge@3.0.0": "patches/pkce-challenge@3.0.0.patch", "pyodide@0.23.4": "patches/pyodide@0.23.4.patch", diff --git a/packages/@n8n/nodes-langchain/nodes/agents/Agent/AgentExecutor.ts b/packages/@n8n/nodes-langchain/nodes/agents/Agent/AgentExecutor.ts index f2ea96f1b8726..7966900a3946f 100644 --- a/packages/@n8n/nodes-langchain/nodes/agents/Agent/AgentExecutor.ts +++ b/packages/@n8n/nodes-langchain/nodes/agents/Agent/AgentExecutor.ts @@ -11,17 +11,15 @@ import { Tool, } from '@langchain/core/tools'; import type { ChainValues } from '@langchain/core/utils/types'; -import type { BaseMultiActionAgent, BaseSingleActionAgent } from 'langchain/dist/agents/agent'; +import type { BaseMultiActionAgent, BaseSingleActionAgent, StoppingMethod } from 'langchain/agents'; import { AgentRunnableSequence, RunnableMultiActionAgent, RunnableSingleActionAgent, isRunnableAgent, -} from 'langchain/dist/agents/agent'; -import type { StoppingMethod } from 'langchain/dist/agents/types'; -import type { ChainInputs } from 'langchain/dist/chains/base'; -import { BaseChain } from 'langchain/dist/chains/base'; -import type { SerializedLLMChain } from 'langchain/dist/chains/serde'; +} from 'langchain/agents'; +import type { ChainInputs, SerializedLLMChain } from 'langchain/chains'; +import { BaseChain } from 'langchain/chains'; import { ApplicationError } from 'n8n-workflow'; interface AgentExecutorIteratorInput { diff --git a/patches/langchain@0.3.6.patch b/patches/langchain@0.3.6.patch new file mode 100644 index 0000000000000..b1fef76242ef2 --- /dev/null +++ b/patches/langchain@0.3.6.patch @@ -0,0 +1,55 @@ +diff --git a/dist/agents/index.cjs b/dist/agents/index.cjs +index d7c4a2e371ddb587c1c8416f350c99c8649f090f..9fa1e7d50564b2becc0870d606f407ac60cdb3ae 100644 +--- a/dist/agents/index.cjs ++++ b/dist/agents/index.cjs +@@ -1,12 +1,17 @@ + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); +-exports.createReactAgent = exports.createXmlAgent = exports.XMLAgent = exports.createToolCallingAgent = exports.createOpenAIToolsAgent = exports.createOpenAIFunctionsAgent = exports.OpenAIAgent = exports.StructuredChatOutputParserWithRetries = exports.StructuredChatOutputParser = exports.createStructuredChatAgent = exports.StructuredChatAgent = exports.AgentActionOutputParser = exports.ZeroShotAgentOutputParser = exports.ZeroShotAgent = exports.initializeAgentExecutorWithOptions = exports.initializeAgentExecutor = exports.AgentExecutor = exports.ChatConversationalAgentOutputParserWithRetries = exports.ChatConversationalAgentOutputParser = exports.ChatConversationalAgent = exports.ChatAgentOutputParser = exports.ChatAgent = exports.Toolkit = exports.createVectorStoreRouterAgent = exports.createVectorStoreAgent = exports.createOpenApiAgent = exports.createJsonAgent = exports.VectorStoreToolkit = exports.VectorStoreRouterToolkit = exports.RequestsToolkit = exports.OpenApiToolkit = exports.JsonToolkit = exports.LLMSingleActionAgent = exports.RunnableAgent = exports.BaseMultiActionAgent = exports.BaseSingleActionAgent = exports.Agent = void 0; ++exports.createReactAgent = exports.createXmlAgent = exports.XMLAgent = exports.createToolCallingAgent = exports.createOpenAIToolsAgent = exports.createOpenAIFunctionsAgent = exports.OpenAIAgent = exports.StructuredChatOutputParserWithRetries = exports.StructuredChatOutputParser = exports.createStructuredChatAgent = exports.StructuredChatAgent = exports.AgentActionOutputParser = exports.ZeroShotAgentOutputParser = exports.ZeroShotAgent = exports.initializeAgentExecutorWithOptions = exports.initializeAgentExecutor = exports.AgentExecutor = exports.ChatConversationalAgentOutputParserWithRetries = exports.ChatConversationalAgentOutputParser = exports.ChatConversationalAgent = exports.ChatAgentOutputParser = exports.ChatAgent = exports.Toolkit = exports.createVectorStoreRouterAgent = exports.createVectorStoreAgent = exports.createOpenApiAgent = exports.createJsonAgent = exports.VectorStoreToolkit = exports.VectorStoreRouterToolkit = exports.RequestsToolkit = exports.OpenApiToolkit = exports.JsonToolkit = exports.LLMSingleActionAgent = exports.RunnableAgent = exports.BaseMultiActionAgent = exports.BaseSingleActionAgent = exports.Agent = exports.AgentRunnableSequence = exports.RunnableMultiActionAgent = exports.RunnableSingleActionAgent = exports.isRunnableAgent = void 0; + var agent_js_1 = require("./agent.cjs"); + Object.defineProperty(exports, "Agent", { enumerable: true, get: function () { return agent_js_1.Agent; } }); + Object.defineProperty(exports, "BaseSingleActionAgent", { enumerable: true, get: function () { return agent_js_1.BaseSingleActionAgent; } }); + Object.defineProperty(exports, "BaseMultiActionAgent", { enumerable: true, get: function () { return agent_js_1.BaseMultiActionAgent; } }); + Object.defineProperty(exports, "RunnableAgent", { enumerable: true, get: function () { return agent_js_1.RunnableAgent; } }); + Object.defineProperty(exports, "LLMSingleActionAgent", { enumerable: true, get: function () { return agent_js_1.LLMSingleActionAgent; } }); ++Object.defineProperty(exports, "AgentRunnableSequence", { enumerable: true, get: function () { return agent_js_1.AgentRunnableSequence; } }); ++Object.defineProperty(exports, "RunnableMultiActionAgent", { enumerable: true, get: function () { return agent_js_1.RunnableMultiActionAgent; } }); ++Object.defineProperty(exports, "RunnableSingleActionAgent", { enumerable: true, get: function () { return agent_js_1.RunnableSingleActionAgent; } }); ++Object.defineProperty(exports, "isRunnableAgent", { enumerable: true, get: function () { return agent_js_1.isRunnableAgent; } }); ++var index_js_1 = require("./toolkits/index.cjs"); + var index_js_1 = require("./toolkits/index.cjs"); + Object.defineProperty(exports, "JsonToolkit", { enumerable: true, get: function () { return index_js_1.JsonToolkit; } }); + Object.defineProperty(exports, "OpenApiToolkit", { enumerable: true, get: function () { return index_js_1.OpenApiToolkit; } }); +diff --git a/dist/agents/index.d.ts b/dist/agents/index.d.ts +index 05f874b2341e529f1f7b79d8ff227935a312d160..ba60c04331753c489dfe4a3378d143ddf130ff86 100644 +--- a/dist/agents/index.d.ts ++++ b/dist/agents/index.d.ts +@@ -1,4 +1,4 @@ +-export { Agent, type AgentArgs, BaseSingleActionAgent, BaseMultiActionAgent, RunnableAgent, LLMSingleActionAgent, type LLMSingleActionAgentInput, type OutputParserArgs, type AgentRunnableSequence, } from "./agent.js"; ++export { Agent, type AgentArgs, BaseSingleActionAgent, BaseMultiActionAgent, RunnableAgent, LLMSingleActionAgent, type LLMSingleActionAgentInput, type OutputParserArgs, AgentRunnableSequence, RunnableMultiActionAgent, RunnableSingleActionAgent, isRunnableAgent } from "./agent.js"; + export { JsonToolkit, OpenApiToolkit, RequestsToolkit, type VectorStoreInfo, VectorStoreRouterToolkit, VectorStoreToolkit, createJsonAgent, createOpenApiAgent, createVectorStoreAgent, createVectorStoreRouterAgent, } from "./toolkits/index.js"; + export { Toolkit } from "./toolkits/base.js"; + export { ChatAgent, type ChatAgentInput, type ChatCreatePromptArgs, } from "./chat/index.js"; +diff --git a/dist/agents/index.js b/dist/agents/index.js +index ca4a1ab41dabd8cf4f3874c24ad39a93279a6bd1..83cdb02f9b6c9be62af7389400ac6fe9b0f87a14 100644 +--- a/dist/agents/index.js ++++ b/dist/agents/index.js +@@ -1,4 +1,4 @@ +-export { Agent, BaseSingleActionAgent, BaseMultiActionAgent, RunnableAgent, LLMSingleActionAgent, } from "./agent.js"; ++export { Agent, BaseSingleActionAgent, BaseMultiActionAgent, RunnableAgent, LLMSingleActionAgent, AgentRunnableSequence, RunnableMultiActionAgent, RunnableSingleActionAgent, isRunnableAgent } from "./agent.js"; + export { JsonToolkit, OpenApiToolkit, RequestsToolkit, VectorStoreRouterToolkit, VectorStoreToolkit, createJsonAgent, createOpenApiAgent, createVectorStoreAgent, createVectorStoreRouterAgent, } from "./toolkits/index.js"; + export { Toolkit } from "./toolkits/base.js"; + export { ChatAgent, } from "./chat/index.js"; +diff --git a/schema/document.cjs b/schema/document.cjs +deleted file mode 100644 +index 18746fea69bdc22290c631c8534656d2490f9634..0000000000000000000000000000000000000000 +diff --git a/schema/document.d.cts b/schema/document.d.cts +deleted file mode 100644 +index d9c69889bdff03b3ecedc7c10283447d36a34f26..0000000000000000000000000000000000000000 +diff --git a/schema/document.d.ts b/schema/document.d.ts +deleted file mode 100644 +index d9c69889bdff03b3ecedc7c10283447d36a34f26..0000000000000000000000000000000000000000 +diff --git a/schema/document.js b/schema/document.js +deleted file mode 100644 +index d9c69889bdff03b3ecedc7c10283447d36a34f26..0000000000000000000000000000000000000000 diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e21c919dee7f9..cc4c6783fd4e0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -124,6 +124,9 @@ patchedDependencies: '@types/ws@8.5.4': hash: nbzuqaoyqbrfwipijj5qriqqju path: patches/@types__ws@8.5.4.patch + langchain@0.3.6: + hash: 7zttpgt447a63ax73cqbfl4o5u + path: patches/langchain@0.3.6.patch pkce-challenge@3.0.0: hash: dypouzb3lve7vncq25i5fuanki path: patches/pkce-challenge@3.0.0.patch @@ -428,7 +431,7 @@ importers: version: 3.666.0(@aws-sdk/client-sts@3.666.0) '@getzep/zep-cloud': specifier: 1.0.12 - version: 1.0.12(@langchain/core@0.3.19(openai@4.73.1(encoding@0.1.13)(zod@3.23.8)))(encoding@0.1.13)(langchain@0.3.6(e4rnrwhosnp2xiru36mqgdy2bu)) + version: 1.0.12(@langchain/core@0.3.19(openai@4.73.1(encoding@0.1.13)(zod@3.23.8)))(encoding@0.1.13)(langchain@0.3.6(patch_hash=7zttpgt447a63ax73cqbfl4o5u)(e4rnrwhosnp2xiru36mqgdy2bu)) '@getzep/zep-js': specifier: 0.9.0 version: 0.9.0 @@ -455,7 +458,7 @@ importers: version: 0.3.1(@aws-sdk/client-sso-oidc@3.666.0(@aws-sdk/client-sts@3.666.0))(@langchain/core@0.3.19(openai@4.73.1(encoding@0.1.13)(zod@3.23.8)))(encoding@0.1.13) '@langchain/community': specifier: 0.3.15 - version: 0.3.15(vc5hvyy27o4cmm4jplsptc2fqm) + version: 0.3.15(q275i25f3eipny32ftxrujomqi) '@langchain/core': specifier: 'catalog:' version: 0.3.19(openai@4.73.1(encoding@0.1.13)(zod@3.23.8)) @@ -542,7 +545,7 @@ importers: version: 23.0.1 langchain: specifier: 0.3.6 - version: 0.3.6(e4rnrwhosnp2xiru36mqgdy2bu) + version: 0.3.6(patch_hash=7zttpgt447a63ax73cqbfl4o5u)(e4rnrwhosnp2xiru36mqgdy2bu) lodash: specifier: 'catalog:' version: 4.17.21 @@ -15640,7 +15643,7 @@ snapshots: '@gar/promisify@1.1.3': optional: true - '@getzep/zep-cloud@1.0.12(@langchain/core@0.3.19(openai@4.73.1(encoding@0.1.13)(zod@3.23.8)))(encoding@0.1.13)(langchain@0.3.6(e4rnrwhosnp2xiru36mqgdy2bu))': + '@getzep/zep-cloud@1.0.12(@langchain/core@0.3.19(openai@4.73.1(encoding@0.1.13)(zod@3.23.8)))(encoding@0.1.13)(langchain@0.3.6(patch_hash=7zttpgt447a63ax73cqbfl4o5u)(e4rnrwhosnp2xiru36mqgdy2bu))': dependencies: form-data: 4.0.0 node-fetch: 2.7.0(encoding@0.1.13) @@ -15649,7 +15652,7 @@ snapshots: zod: 3.23.8 optionalDependencies: '@langchain/core': 0.3.19(openai@4.73.1(encoding@0.1.13)(zod@3.23.8)) - langchain: 0.3.6(e4rnrwhosnp2xiru36mqgdy2bu) + langchain: 0.3.6(patch_hash=7zttpgt447a63ax73cqbfl4o5u)(e4rnrwhosnp2xiru36mqgdy2bu) transitivePeerDependencies: - encoding @@ -16113,7 +16116,7 @@ snapshots: - aws-crt - encoding - '@langchain/community@0.3.15(vc5hvyy27o4cmm4jplsptc2fqm)': + '@langchain/community@0.3.15(q275i25f3eipny32ftxrujomqi)': dependencies: '@ibm-cloud/watsonx-ai': 1.1.2 '@langchain/core': 0.3.19(openai@4.73.1(encoding@0.1.13)(zod@3.23.8)) @@ -16123,7 +16126,7 @@ snapshots: flat: 5.0.2 ibm-cloud-sdk-core: 5.1.0 js-yaml: 4.1.0 - langchain: 0.3.6(e4rnrwhosnp2xiru36mqgdy2bu) + langchain: 0.3.6(patch_hash=7zttpgt447a63ax73cqbfl4o5u)(e4rnrwhosnp2xiru36mqgdy2bu) langsmith: 0.2.3(openai@4.73.1(encoding@0.1.13)(zod@3.23.8)) uuid: 10.0.0 zod: 3.23.8 @@ -16136,7 +16139,7 @@ snapshots: '@aws-sdk/client-s3': 3.666.0 '@aws-sdk/credential-provider-node': 3.666.0(@aws-sdk/client-sso-oidc@3.666.0(@aws-sdk/client-sts@3.666.0))(@aws-sdk/client-sts@3.666.0) '@azure/storage-blob': 12.18.0(encoding@0.1.13) - '@getzep/zep-cloud': 1.0.12(@langchain/core@0.3.19(openai@4.73.1(encoding@0.1.13)(zod@3.23.8)))(encoding@0.1.13)(langchain@0.3.6(e4rnrwhosnp2xiru36mqgdy2bu)) + '@getzep/zep-cloud': 1.0.12(@langchain/core@0.3.19(openai@4.73.1(encoding@0.1.13)(zod@3.23.8)))(encoding@0.1.13)(langchain@0.3.6(patch_hash=7zttpgt447a63ax73cqbfl4o5u)(e4rnrwhosnp2xiru36mqgdy2bu)) '@getzep/zep-js': 0.9.0 '@google-ai/generativelanguage': 2.6.0(encoding@0.1.13) '@google-cloud/storage': 7.12.1(encoding@0.1.13) @@ -23318,7 +23321,7 @@ snapshots: kuler@2.0.0: {} - langchain@0.3.6(e4rnrwhosnp2xiru36mqgdy2bu): + langchain@0.3.6(patch_hash=7zttpgt447a63ax73cqbfl4o5u)(e4rnrwhosnp2xiru36mqgdy2bu): dependencies: '@langchain/core': 0.3.19(openai@4.73.1(encoding@0.1.13)(zod@3.23.8)) '@langchain/openai': 0.3.14(@langchain/core@0.3.19(openai@4.73.1(encoding@0.1.13)(zod@3.23.8)))(encoding@0.1.13) From d6d3192a7c5bcdeed9f8fc543b8fbc721343b637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A4=95=E0=A4=BE=E0=A4=B0=E0=A4=A4=E0=A5=8B=E0=A4=AB?= =?UTF-8?q?=E0=A5=8D=E0=A4=AB=E0=A5=87=E0=A4=B2=E0=A4=B8=E0=A5=8D=E0=A4=95?= =?UTF-8?q?=E0=A5=8D=E0=A4=B0=E0=A4=BF=E0=A4=AA=E0=A5=8D=E0=A4=9F=E2=84=A2?= Date: Mon, 16 Dec 2024 11:45:38 +0100 Subject: [PATCH 4/4] use the forked AgentExecutor for all our agents --- .../nodes/agents/Agent/agents/OpenAiFunctionsAgent/execute.ts | 3 ++- .../nodes/agents/Agent/agents/ReActAgent/execute.ts | 3 ++- .../nodes/agents/Agent/agents/ToolsAgent/execute.ts | 3 ++- .../nodes/agents/OpenAiAssistant/OpenAiAssistant.node.ts | 2 +- .../vendors/OpenAi/actions/assistant/message.operation.ts | 2 +- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/OpenAiFunctionsAgent/execute.ts b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/OpenAiFunctionsAgent/execute.ts index 17a2d43590a10..5092f061e22d6 100644 --- a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/OpenAiFunctionsAgent/execute.ts +++ b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/OpenAiFunctionsAgent/execute.ts @@ -2,7 +2,7 @@ import type { BaseOutputParser } from '@langchain/core/output_parsers'; import { PromptTemplate } from '@langchain/core/prompts'; import { ChatOpenAI } from '@langchain/openai'; import type { AgentExecutorInput } from 'langchain/agents'; -import { AgentExecutor, OpenAIAgent } from 'langchain/agents'; +import { OpenAIAgent } from 'langchain/agents'; import { BufferMemory, type BaseChatMemory } from 'langchain/memory'; import { CombiningOutputParser } from 'langchain/output_parsers'; import { @@ -16,6 +16,7 @@ import { getConnectedTools, getPromptInputByType } from '@utils/helpers'; import { getOptionalOutputParsers } from '@utils/output_parsers/N8nOutputParser'; import { getTracingConfig } from '@utils/tracing'; +import { AgentExecutor } from '../../AgentExecutor'; import { extractParsedOutput } from '../utils'; export async function openAiFunctionsAgentExecute( diff --git a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ReActAgent/execute.ts b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ReActAgent/execute.ts index 4db35634d6c96..237b287e4ec27 100644 --- a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ReActAgent/execute.ts +++ b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ReActAgent/execute.ts @@ -2,7 +2,7 @@ import type { BaseLanguageModel } from '@langchain/core/language_models/base'; import type { BaseChatModel } from '@langchain/core/language_models/chat_models'; import type { BaseOutputParser } from '@langchain/core/output_parsers'; import { PromptTemplate } from '@langchain/core/prompts'; -import { AgentExecutor, ChatAgent, ZeroShotAgent } from 'langchain/agents'; +import { ChatAgent, ZeroShotAgent } from 'langchain/agents'; import { CombiningOutputParser } from 'langchain/output_parsers'; import { type IExecuteFunctions, @@ -16,6 +16,7 @@ import { getOptionalOutputParsers } from '@utils/output_parsers/N8nOutputParser' import { throwIfToolSchema } from '@utils/schemaParsing'; import { getTracingConfig } from '@utils/tracing'; +import { AgentExecutor } from '../../AgentExecutor'; import { checkForStructuredTools, extractParsedOutput } from '../utils'; export async function reActAgentAgentExecute( diff --git a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ToolsAgent/execute.ts b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ToolsAgent/execute.ts index b0e36d0d8b327..903a608911ec6 100644 --- a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ToolsAgent/execute.ts +++ b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ToolsAgent/execute.ts @@ -7,7 +7,7 @@ import { RunnableSequence } from '@langchain/core/runnables'; import type { Tool } from '@langchain/core/tools'; import { DynamicStructuredTool } from '@langchain/core/tools'; import type { AgentAction, AgentFinish } from 'langchain/agents'; -import { AgentExecutor, createToolCallingAgent } from 'langchain/agents'; +import { createToolCallingAgent } from 'langchain/agents'; import { omit } from 'lodash'; import { BINARY_ENCODING, jsonParse, NodeConnectionType, NodeOperationError } from 'n8n-workflow'; import type { IExecuteFunctions, INodeExecutionData } from 'n8n-workflow'; @@ -21,6 +21,7 @@ import { } from '@utils/output_parsers/N8nOutputParser'; import { SYSTEM_MESSAGE } from './prompt'; +import { AgentExecutor } from '../../AgentExecutor'; function getOutputParserSchema(outputParser: N8nOutputParser): ZodObject { const schema = diff --git a/packages/@n8n/nodes-langchain/nodes/agents/OpenAiAssistant/OpenAiAssistant.node.ts b/packages/@n8n/nodes-langchain/nodes/agents/OpenAiAssistant/OpenAiAssistant.node.ts index e44ad8f9d231d..f5cbe798ea68e 100644 --- a/packages/@n8n/nodes-langchain/nodes/agents/OpenAiAssistant/OpenAiAssistant.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/agents/OpenAiAssistant/OpenAiAssistant.node.ts @@ -1,4 +1,3 @@ -import { AgentExecutor } from 'langchain/agents'; import type { OpenAIToolType } from 'langchain/dist/experimental/openai_assistant/schema'; import { OpenAIAssistantRunnable } from 'langchain/experimental/openai_assistant'; import { NodeConnectionType, NodeOperationError } from 'n8n-workflow'; @@ -14,6 +13,7 @@ import { getConnectedTools } from '@utils/helpers'; import { getTracingConfig } from '@utils/tracing'; import { formatToOpenAIAssistantTool } from './utils'; +import { AgentExecutor } from '../Agent/AgentExecutor'; export class OpenAiAssistant implements INodeType { description: INodeTypeDescription = { diff --git a/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/assistant/message.operation.ts b/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/assistant/message.operation.ts index 977530cc830be..b6a449e4a7cfb 100644 --- a/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/assistant/message.operation.ts +++ b/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/assistant/message.operation.ts @@ -1,5 +1,4 @@ import type { BaseMessage } from '@langchain/core/messages'; -import { AgentExecutor } from 'langchain/agents'; import type { OpenAIToolType } from 'langchain/dist/experimental/openai_assistant/schema'; import { OpenAIAssistantRunnable } from 'langchain/experimental/openai_assistant'; import type { BufferWindowMemory } from 'langchain/memory'; @@ -22,6 +21,7 @@ import { promptTypeOptions } from '@utils/descriptions'; import { getConnectedTools } from '@utils/helpers'; import { getTracingConfig } from '@utils/tracing'; +import { AgentExecutor } from '../../../../agents/Agent/AgentExecutor'; import { formatToOpenAIAssistantTool } from '../../helpers/utils'; import { assistantRLC } from '../descriptions';