Skip to content

Commit 8e31a5d

Browse files
keenborder786mdrxy
andauthored
fix(core): Fix tool name check in name_dict for PydanticToolsParser (#33479)
- **Description:** The root cause of this issue is that when a user defines `model_config` in a `BaseModel`, the `{"type": <tool_name>}` value is derived from the title specified in `model_config` when the results are parsed [here](https://vscode.dev/github/keenborder786/langchain/blob/fix/tool_name_dict/libs/core/langchain_core/output_parsers/openai_tools.py#L199). However, [tool.__name__](https://vscode.dev/github/keenborder786/langchain/blob/fix/tool_name_dict/libs/core/langchain_core/output_parsers/openai_tools.py#L331) uses the class name (in uppercase) of the `BaseModel`, resulting in a `KeyError` when a custom title is provided in `model_config`. The Best Solution will be to use the title provided in `model_config` attribute if provided one since that is what `type` will be parsed to, if not then use `tool.__name__`. But need to make sure that this works only for Pydantic V2. - **Issue:** #27260 --------- Co-authored-by: Mason Daugherty <mason@langchain.dev>
1 parent ee630b4 commit 8e31a5d

File tree

2 files changed

+473
-2
lines changed

2 files changed

+473
-2
lines changed

libs/core/langchain_core/output_parsers/openai_tools.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@
1515
from langchain_core.output_parsers.transform import BaseCumulativeTransformOutputParser
1616
from langchain_core.outputs import ChatGeneration, Generation
1717
from langchain_core.utils.json import parse_partial_json
18-
from langchain_core.utils.pydantic import TypeBaseModel
18+
from langchain_core.utils.pydantic import (
19+
TypeBaseModel,
20+
is_pydantic_v1_subclass,
21+
is_pydantic_v2_subclass,
22+
)
1923

2024
logger = logging.getLogger(__name__)
2125

@@ -323,7 +327,15 @@ def parse_result(self, result: list[Generation], *, partial: bool = False) -> An
323327
return None if self.first_tool_only else []
324328

325329
json_results = [json_results] if self.first_tool_only else json_results
326-
name_dict = {tool.__name__: tool for tool in self.tools}
330+
name_dict_v2: dict[str, TypeBaseModel] = {
331+
tool.model_config.get("title") or tool.__name__: tool
332+
for tool in self.tools
333+
if is_pydantic_v2_subclass(tool)
334+
}
335+
name_dict_v1: dict[str, TypeBaseModel] = {
336+
tool.__name__: tool for tool in self.tools if is_pydantic_v1_subclass(tool)
337+
}
338+
name_dict: dict[str, TypeBaseModel] = {**name_dict_v2, **name_dict_v1}
327339
pydantic_objects = []
328340
for res in json_results:
329341
if not isinstance(res["args"], dict):

0 commit comments

Comments
 (0)