Fixes#38351
This PR fixes `create_agent` conditional edge routing when middleware
injects synthetic `ToolMessage` objects for already-satisfied tool
calls.
Previously, `_make_model_to_tools_edge` could return the model loop
entry destination, but that destination was not always included in
`model_to_tools_destinations`. This caused LangGraph to raise
`KeyError("model")`.
Changes:
* Include `loop_entry_node` in `model_to_tools_destinations`.
* Add a regression test covering synthetic `ToolMessage` injection
through `wrap_model_call` middleware using `ExtendedModelResponse` and
`Command(update={"messages": ...})`.
Test:
* `uv run --group test pytest
tests/unit_tests/agents/middleware/core/test_framework.py::test_create_agent_synthetic_tool_messages_reroute_to_model`
Result:
* Passed
---------
Co-authored-by: ccurme <26529506+ccurme@users.noreply.github.com>
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Raises the minimum `vcrpy` version from `>=8.0.0` to `>=8.2.0` in the
integration-test dependencies of `langchain-classic` and `langchain`,
aligning them with `langchain-openai` (`>=8.2.0`) and `langchain-tests`
(`>=8.2.1`), which already require newer versions.
Made by [Open
SWE](https://openswe.vercel.app/agents/cedc18ba-0856-5697-949e-3c6616845c60)
---------
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Closes#39977
---
Anyone reading the `ChatGroq.with_structured_output` reference sees the
`method` argument documented twice, and the two blocks disagree with
each other.
The first block is the current one. It lists three options and matches
how the sibling `langchain-openai` package documents the same argument.
The second block is older. It says the argument is `'function_calling'`
or `'json_mode'`, which stopped being true when `'json_schema'` support
was added. A reader who stops at the second block will not know
`'json_schema'` exists, and the duplicate key also breaks API reference
rendering.
This removes the stale block. The one thing it said that the surviving
block did not was the warning that `'json_mode'` does not support
streaming responses or stop sequences, so that warning moves up rather
than being dropped. Everything else in it was already covered above.
No behaviour changes, docstring only.
The added unit test asserts `method` appears once and that `json_schema`
is still described. It fails on the current `master` and passes with
this change.
---
Disclaimer: this contribution was prepared with the assistance of an AI
agent. I reviewed the change, verified the reproduction from the issue
against `master`, and ran the package unit tests and `ruff` locally
before opening it.
---------
Signed-off-by: Mason Daugherty <github@mdrxy.com>
Co-authored-by: Mason Daugherty <github@mdrxy.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Fixed Fireworks requests failing after switching from a model that
stores reasoning blocks in conversation history.
---
Users switching from an OpenAI Responses model to Fireworks could
receive a 400 because canonical `reasoning` blocks remained in
conversation history. `ChatFireworks` now drops those provider-specific
blocks before serializing Chat Completions requests, matching its
handling of other unsupported reasoning formats.
Made by [Open
SWE](https://openswe.vercel.app/agents/15bd8573-dbbf-55f8-8f22-d5295ec6de11)
---------
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Patch bump of `langchain` from 1.3.17 to 1.3.18 to prepare a release.
Picks up the `PIIMiddleware` redaction fix (#39894): message content
that is a list of content blocks was being flattened into the string
`repr` of the list during redaction, and redacted messages were losing
fields such as `additional_kwargs`.
Standard three-file bump — `__version__`, `pyproject.toml`, and the
`langchain` entry in `uv.lock`. Running `uv lock` locally also pulled in
unrelated dependency drift (upstream specifier changes and
environment-dependent marker lines), so that churn was reverted and only
the version line kept, matching prior release PRs.
---
*Written with the help of an AI agent (Claude Code).*
`PIIMiddleware` redacted message content via `str(message.content)`.
When `.content` is a list of content blocks rather than a plain string,
`str(...)` produces the `repr` of the list — so a redacted user message
was stored as the literal string:
```
"[{'type': 'text', 'text': 'my email is [REDACTED_EMAIL]'}]"
```
The PII itself was still detected and redacted; only the shape of the
message was destroyed. Anyone sending multimodal or provider-native
block content through an agent with `PIIMiddleware` had their messages
silently flattened into that repr before reaching the model.
`_process_content` now accepts either shape and walks content blocks,
redacting the text of each block in place and leaving non-text blocks
untouched. Plain-string content behaves exactly as before.
While fixing the call sites, this also drops the hand-rebuilding of
messages (`HumanMessage(content=..., id=..., name=...)`) in favor of
`model_copy`. The enumerated rebuild had been quietly discarding every
field it did not list — `additional_kwargs`, `response_metadata`, and so
on — on any message that contained PII.
## Release note
Fixed `PIIMiddleware` flattening list-of-content-blocks message content
into its string `repr` during redaction. Redaction now preserves the
original content shape, and no longer drops message fields such as
`additional_kwargs` on redacted messages.
---
*Written with the help of an AI agent (Claude Code).*
## Problem
`StructuredTool` cannot be dumped to JSON:
```python
@tool
def write_file(file_path: str, content: str) -> str:
"""Write content to the given path."""
return "ok"
write_file.model_dump(mode="json")
# PydanticSerializationError: Unable to serialize unknown type:
# <class 'pydantic._internal._model_construction.ModelMetaclass'>
```
`args_schema` holds a Pydantic model class, and `func` / `coroutine`
hold callables. None of them have a JSON form. Python-mode
`model_dump()` works; only the JSON modes raise.
This also costs tracing performance. The [LangSmith
SDK](https://github.com/langchain-ai/langsmith-sdk/blob/main/python/langsmith/_internal/_serde.py)
catches the error, dumps again in Python mode, and then sends every
class and function left in the result through its own `default` hook.
## Change
A `PlainSerializer(..., when_used="json-unless-none")` on the three
fields.
- `args_schema` dumps as its own JSON schema: `model_json_schema()` for
a Pydantic v2 class, `schema()` for a v1 one. A dict schema passes
through unchanged. A schema holding an arbitrary type has no JSON schema
at all, so it falls back to its repr instead of raising.
- `func` and `coroutine` dump as strings.
- Python-mode dumps are unchanged — still the live schema class and
callables.
- `exclude` / `include` / `exclude_none` keep working.
- Attached with `Annotated`, not `@field_serializer`. A field has only
one serializer slot, so `@field_serializer` would break any subclass
that declares its own serializer for the same field.
- Schema generation is cached per class. Pydantic does not memoize it,
and tracing would pay for it on every run.
## Result
The dump is JSON-native, and the schema it carries has the same shape a
dict `args_schema` already has, so it validates back into a working
tool.
Measured on the 8 filesystem tools of a deepagents agent, dumped through
the LangSmith serializer:
| | master | this PR |
|---|---|---|
| time per dump | 0.119 ms | **0.025 ms** |
| payload | 7,706 B | 12,213 B |
| objects reaching the SDK's `default` hook | 32 | 8 |
The payload grows because `args_schema` now carries the real schema
instead of `"<class ...>"`. Only the tool itself still enters the
`default` hook; the class and functions inside it no longer do. Without
the per-class cache the same dump takes 1.10 ms, so the cache is what
makes this a win rather than a regression.
## Why not on `BaseTool`
`args_schema` is declared there as well, so `Tool` and custom subclasses
hit the same error. But an `Annotated` serializer only applies where the
field is declared, and `StructuredTool` redeclares `args_schema` — it
would not inherit one from `BaseTool`.
## Tests
In `libs/core/tests/unit_tests/test_tools.py`: JSON round trip, Python
mode unchanged, dump options respected, dict `args_schema` preserved,
Pydantic v1 schema class, arbitrary-type fallback, and a subclass
declaring its own serializers for the same fields.
Fixes#39935
---
`gpt-5`, `gpt-5-mini`, `gpt-5-nano` and `gpt-5.1` no longer advertise a
reasoning effort level they reject, and the GPT-5 models advertise
`minimal` again.
The profile augmentations currently give all four models `["none",
"low", "medium", "high", "xhigh"]`. OpenAI's [GPT-5 model
page](https://developers.openai.com/api/docs/models/gpt-5) states that
effort supports "minimal, low, medium, and high", and the [GPT-5.1
page](https://developers.openai.com/api/docs/models/gpt-5.1) lists "none
(default), low, medium, and high". `xhigh` arrived later, with
GPT-5.1-Codex-Max.
A client that reads `profile["reasoning_effort_levels"]` to build its
settings therefore offers `xhigh` on models that reject it, and hides
`minimal`, which GPT-5 accepts. The corrected values match the
models.dev entries for the same models.
The `gpt-5.2` / `gpt-5.4` / `gpt-5.6` profiles are already correct and
are untouched. A few other entries (`gpt-5-pro`, `gpt-5.2-pro`,
`gpt-5.4-pro`, `gpt-5.2-chat-latest`) also differ from models.dev, but I
could not confirm those from OpenAI's own docs, so I left them alone.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Mason Daugherty <mason@langchain.dev>
Patch release of the `langchain` package (langchain_v1): `1.3.16` →
`1.3.17`.
Bumps `version` in `pyproject.toml`, `__version__` in
`langchain/__init__.py`, and the corresponding entry in `uv.lock`.
---
*Prepared with the assistance of an AI agent.*
Human-provided HITL rejection reasons now retain enough context for the
model to understand that the tool was rejected rather than executed.
Previously, a custom `RejectDecision.message` replaced all rejection
framing, while the bare-rejection fallback instructed the model not to
retry. `HumanInTheLoopMiddleware` now uses minimal user-rejection
context in both cases without prescribing future model behavior.
## Release note
Human-in-the-loop rejection results now identify the user rejection
without instructing the model whether to retry.
_Developed with AI-agent assistance._
Made by [Open
SWE](https://openswe.vercel.app/agents/3df8f29d-d7d4-5296-9369-26755096058d)
---------
Co-authored-by: Harrison Chase <11986836+hwchase17@users.noreply.github.com>
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Updates compatible minor and patch dependencies across `model-profiles`,
`standard-tests`, and `text-splitters`.
The `text-splitters` lockfile retains spaCy 3.8.13 because 3.8.15 cannot
install on Python 3.14, and retains ty 0.0.64 because 0.0.73 introduces
new diagnostics in existing NLTK and spaCy integrations. The compatible
pytest-socket, Ruff, NLTK, Transformers, and tiktoken updates remain
included.
Made by [Open
SWE](https://openswe.vercel.app/agents/0dfa86b3-bffc-58fa-b47a-d18f508e848f)
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: John Kennedy <65985482+jkennedyvz@users.noreply.github.com>
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Add a repository-wide `<corridor>` block to `AGENTS.md` requiring agents
to plan first and run Corridor `analyzePlan` before generating or
modifying code.
This mirrors langchain-ai/deepagents#5740. The tags are explicit and
balanced so Corridor-specific guidance remains scoped.
---
Validation: `git diff --check` and a tag-balance assertion.
---------
Co-authored-by: langsmith-fleet[bot] <langsmith-fleet[bot]@users.noreply.github.com>
Bumps the minor-and-patch group with 1 update in the /libs/langchain
directory: python.
Updates `python` from 3.11-slim-bookworm to 3.14-slim-bookworm
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [types-toml](https://github.com/python/typeshed) from
0.10.8.20260408 to 0.10.8.20260518.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/python/typeshed/commits">compare view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [types-pyyaml](https://github.com/python/typeshed) from
6.0.12.20260408 to 6.0.12.20260815.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/python/typeshed/commits">compare view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [types-requests](https://github.com/python/typeshed) from
2.33.0.20260518 to 2.33.0.20260712.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/python/typeshed/commits">compare view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
## Summary
- add monthly Dependabot coverage for the maintained
development-container Compose file
- add monthly Dependabot coverage for the LangChain development
Dockerfile
- keep major updates separate from minor and patch updates
## Test Plan
- parsed `.github/dependabot.yml` with Ruby `YAML.safe_load_file`
- ran `git diff --check`
- verified the staged diff contains only `.github/dependabot.yml`
This contribution was prepared with AI-agent assistance.
Co-authored-by: langsmith-fleet[bot] <langsmith-fleet[bot]@users.noreply.github.com>
Replace legacy sonar/sonar-pro examples in the ChatPerplexity docstring
with the Agent API pattern that 1.4.1 supports:
- use_responses_api=True with model_kwargs.preset + built-in web_search
tool
- explicit Agent API model IDs such as openai/gpt-5.6-sol
- pointer to the six current presets (fast, low, medium, high, xhigh,
wide-research) and to the Agent API models catalog
The rendered library docstring is what users see from IDEs and
help(ChatPerplexity), so this keeps it in sync with what 1.4.1 actually
routes to.
Fixes#39775