Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

langchain[patch]: Allow custom handling of tool runtime errors in legacy agent executor #6687

Merged
merged 1 commit into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions langchain/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -584,9 +584,9 @@
"prepack": "yarn build",
"release": "release-it --only-version --config .release-it.json",
"test": "NODE_OPTIONS=--experimental-vm-modules jest --testPathIgnorePatterns=\\.int\\.test.ts --testTimeout 30000 --maxWorkers=50%",
"test:watch": "yarn run build:deps && NODE_OPTIONS=--experimental-vm-modules jest --watch --testPathIgnorePatterns=\\.int\\.test.ts",
"test:integration": "yarn run build:deps && NODE_OPTIONS=--experimental-vm-modules jest --testPathPattern=\\.int\\.test.ts --testTimeout 100000 --maxWorkers=50%",
"test:single": "yarn run build:deps && NODE_OPTIONS=--experimental-vm-modules yarn run jest --config jest.config.cjs --testTimeout 100000",
"test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch --testPathIgnorePatterns=\\.int\\.test.ts",
"test:integration": "NODE_OPTIONS=--experimental-vm-modules jest --testPathPattern=\\.int\\.test.ts --testTimeout 100000 --maxWorkers=50%",
"test:single": "NODE_OPTIONS=--experimental-vm-modules yarn run jest --config jest.config.cjs --testTimeout 100000",
"format": "prettier --config .prettierrc --write \"src\"",
"format:check": "prettier --config .prettierrc --check \"src\""
},
Expand Down
9 changes: 8 additions & 1 deletion langchain/src/agents/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ export interface AgentExecutorInput extends ChainInputs {
| boolean
| string
| ((e: OutputParserException | ToolInputParsingException) => string);
handleToolRuntimeErrors?: (e: Error) => string;
}

// TODO: Type properly with { intermediateSteps?: AgentStep[] };
Expand Down Expand Up @@ -386,6 +387,8 @@ export class AgentExecutor extends BaseChain<ChainValues, AgentExecutorOutput> {
| ((e: OutputParserException | ToolInputParsingException) => string) =
false;

handleToolRuntimeErrors?: (e: Error) => string;

get inputKeys() {
return this.agent.inputKeys;
}
Expand Down Expand Up @@ -427,6 +430,7 @@ export class AgentExecutor extends BaseChain<ChainValues, AgentExecutorOutput> {
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) {
Expand Down Expand Up @@ -565,7 +569,8 @@ export class AgentExecutor extends BaseChain<ChainValues, AgentExecutorOutput> {
"Received unsupported non-string response from tool call."
);
}
} catch (e) {
// 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) {
Expand All @@ -583,6 +588,8 @@ export class AgentExecutor extends BaseChain<ChainValues, AgentExecutorOutput> {
runManager?.getChild()
);
return { action, observation: observation ?? "" };
} else if (this.handleToolRuntimeErrors !== undefined) {
observation = this.handleToolRuntimeErrors(e);
}
}

Expand Down
41 changes: 41 additions & 0 deletions langchain/src/agents/tests/create_openai_tools_agent.int.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import type { ChatPromptTemplate } from "@langchain/core/prompts";
import { RunnableLambda } from "@langchain/core/runnables";
import { LangChainTracer } from "@langchain/core/tracers/tracer_langchain";
import { AsyncLocalStorageProviderSingleton } from "@langchain/core/singletons";
import { tool } from "@langchain/core/tools";
import { z } from "zod";
import { AsyncLocalStorage } from "async_hooks";
import { TavilySearchResults } from "../../util/testing/tools/tavily_search.js";
import { pull } from "../../hub.js";
Expand Down Expand Up @@ -40,6 +42,45 @@ test("createOpenAIToolsAgent works", async () => {
expect(result.output.length).toBeGreaterThan(10);
});

test("createOpenAIToolsAgent handles errors", async () => {
const errorTools = [
tool(
async () => {
const error = new Error("Error getting search results");
throw error;
},
{
name: "search-results",
schema: z.object({
query: z.string(),
}),
description: "Searches the web",
}
),
];
const prompt = await pull<ChatPromptTemplate>("hwchase17/openai-tools-agent");
const llm = new ChatOpenAI({
modelName: "gpt-3.5-turbo-1106",
temperature: 0,
});
const agent = await createOpenAIToolsAgent({
llm,
tools: errorTools,
prompt,
});
const agentExecutor = new AgentExecutor({
agent,
tools: errorTools,
handleToolRuntimeErrors: (e) => {
throw e;
},
});
const input = "what is LangChain?";
await expect(agentExecutor.invoke({ input })).rejects.toThrowError(
"Error getting search results"
);
});

test.skip("createOpenAIToolsAgent tracing works when it is nested in a lambda", async () => {
AsyncLocalStorageProviderSingleton.initializeGlobalInstance(
new AsyncLocalStorage()
Expand Down
Loading