-
Notifications
You must be signed in to change notification settings - Fork 18.4k
Open
Labels
bugRelated to a bug, vulnerability, unexpected error with an existing featureRelated to a bug, vulnerability, unexpected error with an existing feature
Description
Checked other resources
- This is a bug, not a usage question. For questions, please use the LangChain Forum (https://forum.langchain.com/).
- I added a clear and descriptive title that summarizes this issue.
- I used the GitHub search to find a similar question and didn't find it.
- I am sure that this is a bug in LangChain rather than my code.
- The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).
- I read what a minimal reproducible example is (https://stackoverflow.com/help/minimal-reproducible-example).
- I posted a self-contained, minimal, reproducible example. A maintainer can copy it and run it AS IS.
Example Code
time_fmt = "%Y-%m-%d %H:%M:%S"
time_pattern = r"^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$"
class DataSoilDashboardQueryPayloadTimeShift(BaseModel):
shiftInterval: list[PositiveInt] = Field(description="Each element in the array represents a time offset relative to the query timestamp for individual time comparison analysis. If time comparison analysis dose not described, keep it **VOID**.",max_length=2,default=[])
timeUnit: Literal["DAY"] = Field(default="DAY",description="The unit of specific comparison time offset. This is the description about each value of unit:" +
"Unit **DAY** represents one day."
)
class DataSoilDashboardQueryPayloadQueryParamWhereFilter(BaseModel):
field: str = Field(description="The dimension **CODE** in the selected dimension list that requires enums filtering or pattern filtering.")
operator: Literal["IN", "NI", "LIKE", "NOT_LIKE"] = Field(description="Operators for enums filtering or pattern filtering. This is the description about each value of operator: " +
"The **IN** operator represents enums filtering and can be described as sql 'WHERE <dimension> IN <enums>'. " +
"The **NI** operator represents enums filtering and can be described as sql 'WHERE <dimension> NOT IN <enums>'. " +
"The **LIKE** operator represents pattern filtering and can be described as sql 'WHERE <dimension> LIKE %<pattern>%'. " +
"The **NOT_LIKE** operator represents pattern filtering and can be described as sql 'WHERE <dimension> NOT LIKE %<pattern>%'."
)
value: list[str] = Field(description="If for enums filtering, every element represents th practical enums of the dimension. Otherwise for pattern filtering, only **one** element is required and it represents a wildcard pattern.",min_length=1)
@field_validator("field")
def field_block(cls, v: str, info: ValidationInfo) -> str:
if v == "dt":
raise ValueError("Instruction: The time filtering should be described in 'time' field, not in the 'filters' field.")
return v
@field_validator("value")
def value_block(cls, v: Optional[list[str]], info: ValidationInfo) -> Optional[list[str]]:
if info.data["operator"] in {"LIKE", "NOT_LIKE"} and len(v) > 1:
raise ValueError("Instruction: For pattern filtering, the size of 'value' in 'where' must be **ONE**.")
return v
class DataSoilDashboardQueryPayloadQueryParamWhere(BaseModel):
time: list[Union[str, int]] = Field(
description="The target time range which is **left closed and right opened** for the query, **excluding** the comparison periods required for time comparison analysis. " +
f"The first element is start time, precise to second, a string formatted as **{time_fmt}**. The final time interval **include** this value. " +
f"The last element is end time, precise to second, a string formatted as **{time_fmt}**. The final time interval **exclude** this value.",
min_length=2,
max_length=2,
)
filters: list[DataSoilDashboardQueryPayloadQueryParamWhereFilter] = Field(description="Enums filtering or pattern filtering condition of dimension in the dimensions list. Metric's filtering and time's filtering is **forbidden**.")
relation: Literal["AND"] = Field(description="Boolean relationships between filters across multiple dimensions. This is the description about each value of relation: " +
"The **AND** represents boolean logic **and**."
)
@field_validator("time")
def value_block(cls, v: list[Union[int, str]], info: ValidationInfo) -> list[Union[int, str]]:
if isinstance(v[0], str) and not re.search(time_pattern, v[0]):
raise ValueError(f"Instruction: the start time of time range must be formatted as **{time_fmt}**")
if isinstance(v[1], str) and not re.search(time_pattern, v[1]):
raise ValueError(f"Instruction: the end time of time range must be formatted as **{time_fmt}**")
return v
class DataSoilDashboardQueryPayloadQueryParamOrderBy(BaseModel):
field: str = Field(description="The metric **CODE** in the selected metric list that requires metric sorting.")
direction: Literal["ASC", "DESC"] = Field(description="Sorting direction for specified metric. The **ASC** represents ascending order by metric values, while the **DESC** represents descending order by metric values.")
shift: int = Field(default=0)
limit: int = Field(description="The number of rows to return from the dataset after sorting by the designated metric.",default=50)
class DataSoilDashboardQueryPayloadQueryParamGroupBy(BaseModel):
field: str = Field(description="The dimension **CODE** in the selected dimension list for dimension grouping analysis.")
extendFields: list[str] = Field(default=[])
orderBy: Optional[DataSoilDashboardQueryPayloadQueryParamOrderBy] = Field(description="Sorting config for query results based on a specific **metric**. Dimension sorting is forbidden.",default=None)
class DataSoilDashboardQueryPayloadQueryParam(BaseModel):
queryType: Literal["DETAIL_TABLE"] = Field(description="This is the description about each value of queryType: " +
"The **DETAIL_TABLE** displays metrics grouped by each unique dimension combination where the levels of all grouped dimensions are the same."
)
interval: DashboardInterval = Field(description="The time granularity for time-based grouping analysis. This is the description about each value of granularity: " +
"The **BY_ONE_MINUTE** represents aggregating time at one-minute intervals. " +
"The **BY_FIVE_MINUTE** represents aggregating time at five-minute intervals. " +
"The **BY_HOUR** represents aggregating time at one-hour intervals. " +
"The **BY_DAY** represents aggregating time at one-day intervals. " +
"The **BY_WEEK** represents aggregating time at one-week intervals. " +
"The **BY_MONTH** represents aggregating time at one-month intervals. " +
"The **SUM** represents NOT aggregating time."
)
resultField: list[str] = Field(default=[])
where: DataSoilDashboardQueryPayloadQueryParamWhere = Field(description="Filtering condition for dimensions. Including target time range and enums filtering or pattern filtering for non-time dimensions.")
groupBy: list[DataSoilDashboardQueryPayloadQueryParamGroupBy] = Field(description="A list of dimensions grouping analysis info derived from the dimensions list. If these dimensions require roll-up, a sorting config for each dimension is also required, otherwise all sorting config should be **VOID**. The sorting config specifies the ordering of rolled-up dimensional data when the dimension is the lowest-level among all non-aggregated dimensions.")
orderBy: DataSoilDashboardQueryPayloadQueryParamOrderBy = Field(description="Sorting config for query results based on a specific **metric**. Dimension sorting is forbidden.")
heavyQuery: bool = Field(default=False)
@field_validator("groupBy")
def groupBy_block(cls, v: list[DataSoilDashboardQueryPayloadQueryParamGroupBy], info: ValidationInfo) -> list[DataSoilDashboardQueryPayloadQueryParamGroupBy]:
if "dt" in {e.field for e in v}:
if info.data["interval"] == "SUM":
raise ValueError("Instruction: the interval can not be **SUM** when **time-based grouping is required**.")
else:
if info.data["interval"] != "SUM":
raise ValueError("Instruction: the interval must be **SUM** when **time-based grouping is not required**.")
return v
class DataSoilDashboardQueryPayload(BaseModel):
model_config = ConfigDict(
frozen=False,
)
apiCode: str = Field(default="")
requestId: str = Field(default="")
applicationCode: str = Field(default="")
applicationToken: str = Field(default="")
debug: bool = Field(default=False)
timeShift: DataSoilDashboardQueryPayloadTimeShift = Field(description="Time comparison analysis config.",default=DataSoilDashboardQueryPayloadTimeShift())
dynamicQueryParam: DataSoilDashboardQueryPayloadQueryParam
forceFlush: bool = Field(default=False)
@tool(response_format="content_and_artifact")
def query_datasoil_data_tool(payload: DataSoilDashboardQueryPayload, state: Annotated[dict, InjectedState]) -> Tuple[str, dict]:
<any code>
generation_llm_with_tools = generation_llm.bind_tools(
tools=[DataSoilDashboardQueryPayload],
tool_choice=DataSoilDashboardQueryPayload.__name__,
)
generation_llm_with_tools.invoke([HumanMessage(content="any message")])
Error Message and Stack Trace (if applicable)
No response
Description
When a BaseChatModel binds a tool with input parameters defined by a nested Pydantic v2 model, the tool invocation fails to correctly recognize the Pydantic v2 schema. This results in the arg schema within AIMessage.tool_calls being arbitrarily generated.
System Info
ai-agent-common==1.0
aiohappyeyeballs==2.6.1
aiohttp==3.12.13
aiosignal==1.3.2
annotated-types==0.7.0
anyio==4.9.0
asttokens==3.0.0
async-timeout==5.0.1
atomic==0.7.3
attrs==25.3.0
backoff==2.2.1
beautifulsoup4==4.13.4
charset-normalizer==3.4.2
click==8.2.1
cloudpickle==3.1.1
cramjam==2.10.0
cryptography==44.0.3
dataclasses-json==0.6.7
decorator==5.2.1
distro==1.9.0
dnspython==2.7.0
docutils==0.21.2
exceptiongroup==1.3.0
executing==2.2.0
id==1.5.0
idna==3.10
importlib_metadata==8.7.0
IPy==1.1
ipython==9.4.0
ipython_pygments_lexers==1.1.1
jaraco.classes==3.4.0
keyring==25.6.0
langchain==0.3.26
langchain-community==0.3.27
langchain-core==0.3.71
langchain-openai==0.3.28
langchain-text-splitters==0.3.8
langgraph==0.5.4
langgraph-api==0.2.99
langgraph-checkpoint==2.1.1
langgraph-cli==0.3.5
langgraph-prebuilt==0.5.2
langgraph-runtime-inmem==0.6.1
langgraph-sdk==0.1.74
langserve==0.3.1
langsmith==0.4.8
markdown-it-py==3.0.0
marshmallow==3.26.1
matplotlib-inline==0.1.7
Pygments==2.19.2
PyJWT==2.10.1
python-dotenv==1.1.1
python-snappy==0.6.1
PyYAML==6.0.2
readme_renderer==44.0
regex==2024.11.6
rfc3986==2.0.0
rich==14.0.0
setuptools==80.9.0
six==1.17.0
sniffio==1.3.1
soupsieve==2.7
SQLAlchemy==2.0.41
tqdm==4.67.1
traitlets==5.14.3
truststore==0.10.1
twine==6.1.0
typing-inspect==0.9.0
typing-inspection==0.4.1
typing_extensions==4.14.0
urllib3==2.5.0
uvicorn==0.35.0
watchfiles==1.1.0
wcwidth==0.2.13
wrapt==1.17.2
xxhash==3.5.0
yarl==1.20.1
zipp==3.23.0
zstandard==0.23.0
```[ai-agent-common](https://pypi.python.org/pypi/ai-agent-common)==1.0
[aiohappyeyeballs](https://pypi.python.org/pypi/aiohappyeyeballs)==2.6.1
[aiohttp](https://pypi.python.org/pypi/aiohttp)==3.12.13
[aiosignal](https://pypi.python.org/pypi/aiosignal)==1.3.2
[annotated-types](https://pypi.python.org/pypi/annotated-types)==0.7.0
[anyio](https://pypi.python.org/pypi/anyio)==4.9.0
[asttokens](https://pypi.python.org/pypi/asttokens)==3.0.0
[async-timeout](https://pypi.python.org/pypi/async-timeout)==5.0.1
[atomic](https://pypi.python.org/pypi/atomic)==0.7.3
[attrs](https://pypi.python.org/pypi/attrs)==25.3.0
[backoff](https://pypi.python.org/pypi/backoff)==2.2.1
[beautifulsoup4](https://pypi.python.org/pypi/beautifulsoup4)==4.13.4
[charset-normalizer](https://pypi.python.org/pypi/charset-normalizer)==3.4.2
[click](https://pypi.python.org/pypi/click)==8.2.1
[cloudpickle](https://pypi.python.org/pypi/cloudpickle)==3.1.1
[cramjam](https://pypi.python.org/pypi/cramjam)==2.10.0
[cryptography](https://pypi.python.org/pypi/cryptography)==44.0.3
[dataclasses-json](https://pypi.python.org/pypi/dataclasses-json)==0.6.7
[decorator](https://pypi.python.org/pypi/decorator)==5.2.1
[distro](https://pypi.python.org/pypi/distro)==1.9.0
[dnspython](https://pypi.python.org/pypi/dnspython)==2.7.0
[docutils](https://pypi.python.org/pypi/docutils)==0.21.2
[exceptiongroup](https://pypi.python.org/pypi/exceptiongroup)==1.3.0
[executing](https://pypi.python.org/pypi/executing)==2.2.0
[id](https://pypi.python.org/pypi/id)==1.5.0
[idna](https://pypi.python.org/pypi/idna)==3.10
[importlib_metadata](https://pypi.python.org/pypi/importlib_metadata)==8.7.0
[IPy](https://pypi.python.org/pypi/IPy)==1.1
[ipython](https://pypi.python.org/pypi/ipython)==9.4.0
[ipython_pygments_lexers](https://pypi.python.org/pypi/ipython_pygments_lexers)==1.1.1
[jaraco.classes](https://pypi.python.org/pypi/jaraco.classes)==3.4.0
[keyring](https://pypi.python.org/pypi/keyring)==25.6.0
[langchain](https://pypi.python.org/pypi/langchain)==0.3.26
[langchain-community](https://pypi.python.org/pypi/langchain-community)==0.3.27
[langchain-core](https://pypi.python.org/pypi/langchain-core)==0.3.71
[langchain-openai](https://pypi.python.org/pypi/langchain-openai)==0.3.28
[langchain-text-splitters](https://pypi.python.org/pypi/langchain-text-splitters)==0.3.8
[langgraph](https://pypi.python.org/pypi/langgraph)==0.5.4
[langgraph-api](https://pypi.python.org/pypi/langgraph-api)==0.2.99
[langgraph-checkpoint](https://pypi.python.org/pypi/langgraph-checkpoint)==2.1.1
[langgraph-cli](https://pypi.python.org/pypi/langgraph-cli)==0.3.5
[langgraph-prebuilt](https://pypi.python.org/pypi/langgraph-prebuilt)==0.5.2
[langgraph-runtime-inmem](https://pypi.python.org/pypi/langgraph-runtime-inmem)==0.6.1
[langgraph-sdk](https://pypi.python.org/pypi/langgraph-sdk)==0.1.74
[langserve](https://pypi.python.org/pypi/langserve)==0.3.1
[langsmith](https://pypi.python.org/pypi/langsmith)==0.4.8
[markdown-it-py](https://pypi.python.org/pypi/markdown-it-py)==3.0.0
[marshmallow](https://pypi.python.org/pypi/marshmallow)==3.26.1
[matplotlib-inline](https://pypi.python.org/pypi/matplotlib-inline)==0.1.7
[Pygments](https://pypi.python.org/pypi/Pygments)==2.19.2
[PyJWT](https://pypi.python.org/pypi/PyJWT)==2.10.1
[python-dotenv](https://pypi.python.org/pypi/python-dotenv)==1.1.1
[python-snappy](https://pypi.python.org/pypi/python-snappy)==0.6.1
[PyYAML](https://pypi.python.org/pypi/PyYAML)==6.0.2
[readme_renderer](https://pypi.python.org/pypi/readme_renderer)==44.0
[regex](https://pypi.python.org/pypi/regex)==2024.11.6
[rfc3986](https://pypi.python.org/pypi/rfc3986)==2.0.0
[rich](https://pypi.python.org/pypi/rich)==14.0.0
[setuptools](https://pypi.python.org/pypi/setuptools)==80.9.0
[six](https://pypi.python.org/pypi/six)==1.17.0
[sniffio](https://pypi.python.org/pypi/sniffio)==1.3.1
[soupsieve](https://pypi.python.org/pypi/soupsieve)==2.7
[SQLAlchemy](https://pypi.python.org/pypi/SQLAlchemy)==2.0.41
[tqdm](https://pypi.python.org/pypi/tqdm)==4.67.1
[traitlets](https://pypi.python.org/pypi/traitlets)==5.14.3
[truststore](https://pypi.python.org/pypi/truststore)==0.10.1
[twine](https://pypi.python.org/pypi/twine)==6.1.0
[typing-inspect](https://pypi.python.org/pypi/typing-inspect)==0.9.0
[typing-inspection](https://pypi.python.org/pypi/typing-inspection)==0.4.1
[typing_extensions](https://pypi.python.org/pypi/typing_extensions)==4.14.0
[urllib3](https://pypi.python.org/pypi/urllib3)==2.5.0
[uvicorn](https://pypi.python.org/pypi/uvicorn)==0.35.0
[watchfiles](https://pypi.python.org/pypi/watchfiles)==1.1.0
[wcwidth](https://pypi.python.org/pypi/wcwidth)==0.2.13
[wrapt](https://pypi.python.org/pypi/wrapt)==1.17.2
[xxhash](https://pypi.python.org/pypi/xxhash)==3.5.0
[yarl](https://pypi.python.org/pypi/yarl)==1.20.1
[zipp](https://pypi.python.org/pypi/zipp)==3.23.0
[zstandard](https://pypi.python.org/pypi/zstandard)==0.23.0
Metadata
Metadata
Assignees
Labels
bugRelated to a bug, vulnerability, unexpected error with an existing featureRelated to a bug, vulnerability, unexpected error with an existing feature