Commit Graph

240 Commits

Author SHA1 Message Date
Chester Curme
27160cd1fe support async on_error 2026-07-10 11:14:33 -04:00
Chester Curme
ebc0107633 x 2026-07-10 10:26:18 -04:00
ccurme
fca0a977a6 fix(langchain): propagate interrupts through ToolRetryMiddleware (#38722) 2026-07-08 11:16:42 -04:00
Yashodip More
a586e9044c fix(langchain): avoid shared process-group kill in shell middleware (#36359)
Fixes #36358

---

**Summary**
This PR fixes a process termination safety bug in ShellToolMiddleware
where cleanup could kill the caller process group when
create_process_group is False.

**Why this change**
When the shell child is started without a dedicated process group, it
can share the parent group. The existing cleanup path used group kill
unconditionally, which could terminate unrelated processes including the
caller. This is a high-impact availability risk.

**What changed**

Updated shell session kill logic to use group kill only when the child
is in a different process group than the caller.
Added safe fallback to child-only kill when both share the same process
group.
Added regression tests for both scenarios:
Shared process group: no group kill, child-only kill.
Dedicated process group: existing group kill behavior is preserved.

**Validation**

Targeted new tests passed.
Full shell tool unit test file passed.

AI assistance disclosure
This contribution was prepared with assistance from an AI coding agent.
I reviewed, validated, and finalized the proposed changes and test
coverage before submission.

**Areas for careful review**

Process-group detection behavior on Linux and other POSIX environments.
Any implications for existing timeout and shutdown flows in shell
middleware.
Whether additional integration-level coverage is desirable for process
cleanup behavior.

---------

Co-authored-by: Mason Daugherty <github@mdrxy.com>
2026-07-05 23:51:57 -04:00
Hunter Lovell
4cdd47b253 fix(langchain): sanitize anthropic cache markers on fallback retries (#37867)
## Summary

Fixes #33709.

When `AnthropicPromptCachingMiddleware` runs before
`ModelFallbackMiddleware`, Anthropic-specific `cache_control` markers
can leak into fallback attempts targeting non-Anthropic models. This
change makes fallback retries sanitize those markers only on non-primary
attempts, preserving primary-call behavior and avoiding API changes.

Related: langchain-ai/deepagentsjs#551.

## Changes

### libs/langchain_v1

- Added a private fallback sanitizer in `model_fallback.py` to remove
Anthropic `cache_control` markers from fallback requests.
- Sanitization covers `model_settings`, system/content message blocks,
and tool payloads (`BaseTool.extras` plus dict-style tools/extras).
- Applied sanitization in both sync and async fallback retry paths
(`wrap_model_call` and `awrap_model_call`) while leaving the primary
attempt unchanged.

### libs/langchain_v1 tests

- Added sync and async regression tests in `test_model_fallback.py` that
simulate primary failure and assert fallback calls only succeed when
cache markers are stripped.
- Verified non-cache settings (for example `temperature` and `top_p`)
are preserved on fallback.
- Preserved existing fallback behavior coverage (ordering, exhaustion,
and error propagation).

## Compatibility with `BedrockPromptCachingMiddleware`

The sanitizer also covers `BedrockPromptCachingMiddleware`, which
injects `cache_control` into `model_settings` only. Bedrock-specific
markers (`cachePoint` blocks, content-block `cache_control`) are applied
by the chat model classes at API-call time and never appear in the
`ModelRequest`, so no additional handling is needed.

---------

Co-authored-by: Mason Daugherty <mason@langchain.dev>
Co-authored-by: Mason Daugherty <github@mdrxy.com>
2026-07-05 00:27:29 -04:00
Christophe Bornet
f912638334 style: fix some ruff preview rules in langchain_v1 and standard-tests (#38657) 2026-07-04 22:22:24 -04:00
Christophe Bornet
64177b6fc5 chore(langchain): add types in agent middleware tests (#38188)
Co-authored-by: Mason Daugherty <github@mdrxy.com>
Co-authored-by: Mason Daugherty <mason@langchain.dev>
2026-06-23 00:18:11 -04:00
ccurme
9ef324c9ab fix(langchain,openai): only set strict=True on tools for OpenAI-compatible models in ProviderStrategy (#38370)
When using `ProviderStrategy`, `create_agent` unnecessarily sets
`strict=True` on tools for all providers. This is only needed for OpenAI
/ chat completions. Here we unset `strict`. For OpenAI:
1. We set it in `BaseChatOpenAI.bind_tools` (as a convenience to users
calling `model.bind_tools` directly)
2. We (redundantly) special-case OpenAI in the `create_agent` factory
logic so that things will not break for users who upgrade `langchain`
but not `langchain-openai`.

Note: payloads for OpenAI are tested here and appear unchanged:
https://github.com/langchain-ai/langchain/blob/master/libs/langchain_v1/tests/unit_tests/agents/test_response_format_integration.py

Quick test:
```python
from langchain.agents import create_agent
from langchain.agents.structured_output import ProviderStrategy
from pydantic import BaseModel

class Weather(BaseModel):
    temperature: float
    condition: str

def weather_tool(location: str) -> str:
    """Get the weather at a location."""
    return "Sunny and 75 degrees F."

for model in [
    "anthropic:claude-sonnet-4-6",
    "openai:gpt-5.4",
    "google_genai:gemini-3.5-flash",
]:

    agent = create_agent(
        model=model,
        tools=[weather_tool],
        response_format=ProviderStrategy(Weather),
    )
    
    result = agent.invoke({
        "messages": [{"role": "user", "content": "What's the weather in SF?"}]
    })
    
    print(result["structured_response"])
```
2026-06-22 18:11:55 -04:00
Nishitha M
15c38c8555 fix(langchain): switch summary format (#38171)
Part of https://github.com/langchain-ai/deepagents/issues/2873

---

`SummarizationMiddleware` now serializes the history passed to the
summarizer with XML formatting so URL-backed multimodal content remains
available in the prompt. The existing behavior avoided dumping raw
message metadata into the token budget, but the prefix serialization
path omitted image/audio/video URL blocks before the summary model saw
them.

## Changes

- Update `SummarizationMiddleware._create_summary` and
`SummarizationMiddleware._acreate_summary` to call
`get_buffer_string(..., format="xml")` for trimmed conversation history
- Preserve URL-backed multimodal blocks in the summary prompt while
still avoiding raw message metadata expansion
- Add sync and async unit coverage with a prompt-capturing chat model to
assert image URLs survive summarization input serialization

---------

Co-authored-by: Mason Daugherty <mason@langchain.dev>
Co-authored-by: Mason Daugherty <github@mdrxy.com>
2026-06-18 13:34:42 -04:00
Mason Daugherty
ae1c9418b5 fix(langchain): detect provider strategy for dated gpt-5.2/gpt-5.4 snapshots (#38222)
Closes #38220

---

Users calling `create_agent(..., response_format=<schema>)` with an
OpenAI model pinned to a dated snapshot (e.g. `gpt-5.4-2026-03-05`) were
silently downgraded from native structured output (`ProviderStrategy`)
to tool-calling (`ToolStrategy`). This changes runtime behavior: extra
tool-call traces, different token usage, and no provider-side schema
enforcement.

The cause is in `_supports_provider_strategy`'s fallback patterns: the
`gpt-5.2` and `gpt-5.4` base patterns terminated with `($|[/:])`, which
— unlike their sibling families — rejected a trailing `-`, so OpenAI's
`-YYYY-MM-DD` dated-snapshot suffix matched none of the patterns. The
base patterns were deliberately strict to keep
`gpt-5.2-pro`/`gpt-5.4-pro` blocked, so rather than allowing any
trailing `-` (which would re-admit those `-pro` variants) this change
adds an optional dated-snapshot group `(-\d{4}-\d{2}-\d{2})?`. Dated
snapshots now resolve to `ProviderStrategy` while `-pro` variants stay
blocked.

Made by [Open
SWE](https://openswe.vercel.app/agents/c5ebcb29-8ce5-dda0-73f6-198e49f0c36c)

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-06-17 16:29:08 -04:00
Christophe Bornet
5d044cd326 chore(langchain): improve typing in tests (#38163)
Co-authored-by: Mason Daugherty <github@mdrxy.com>
Co-authored-by: Mason Daugherty <mason@langchain.dev>
2026-06-15 19:02:22 -04:00
Nick Hollon
dcaf7795a3 fix(langchain,anthropic): confine file-search results and tighten anthropic allowed_prefixes (#38106) 2026-06-12 12:47:23 -04:00
Mason Daugherty
5d20596d73 style(core,langchain,langchain-classic,partners): replace double backticks in docstrings (#38095)
Standardizes inline code markup in Python docstrings and comments by
replacing Sphinx-style double backticks with single-backtick Markdown.
The cleanup keeps existing code fences intact while aligning inline
references with the repo's docstring convention.

## Changes
- Converted inline code references in core prompt-loading docs and
LangSmith tracer comments, including `..`, `allow_dangerous_paths`, and
inheritable metadata keys.
- Normalized agent-related docstrings and comments around
`wrap_model_call`, `ExtendedModelResponse`, `Command`,
`create_structured_chat_agent`, and `DockerExecutionPolicy`.
- Updated partner package docstrings for inline references such as
`json_schema`, `ToolCall`, `apply_patch_call_output`, OpenRouter content
block keys, and Perplexity tool-call serialization.
- Cleaned test and helper docstrings that referenced command separators,
fake `resource` modules, stream event names, and xdist rate-limit
environment variables.
2026-06-12 00:17:26 -04:00
Christophe Bornet
d5f7d33f88 chore(langchain): add overloads to create_agent (#34309)
This way mypy can infer the return type when `ResponseT` is not passed.

---------

Co-authored-by: Mason Daugherty <61371264+mdrxy@users.noreply.github.com>
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Mason Daugherty <mason@langchain.dev>
Co-authored-by: Mason Daugherty <github@mdrxy.com>
2026-06-11 01:12:20 -04:00
Mason Daugherty
6b9e22dbbc fix(langchain): tighten structured output model fallbacks (#38042)
Provider-native structured output fallback detection now uses bounded
model-name patterns instead of broad substring checks, reducing false
positives for unrelated model IDs. The model examples and test fixtures
across OpenAI/OpenRouter-facing code were refreshed around current
OpenAI model families while preserving shipped defaults.

## Changes
- Tightened `FALLBACK_MODELS_WITH_STRUCTURED_OUTPUT` from loose string
fragments to regex patterns, with `_supports_provider_strategy` matching
full model-name segments instead of arbitrary substrings.
- Expanded structured-output fallback coverage for newer OpenAI,
Anthropic, and xAI/Grok model families, including `gpt-5.x`, newer
Claude 4/5-style names, and `grok-build`.
- Reused `_attempt_infer_model_provider` in provider tool search routing
so `_provider_from_model_name` follows the same provider inference
behavior as `init_chat_model`.
- Suppressed irrelevant provider-inference deprecation warnings during
provider tool search registry lookup.
- Refreshed OpenAI, Azure OpenAI, OpenRouter, core metadata, and example
model references from older fixtures like `gpt-4`, `gpt-4o`, `o1`, and
`o4-mini` to current test/profile models such as `gpt-5.5`,
`gpt-5-nano`, and `gpt-4.1-mini`.
- Removed outdated OpenAI test assumptions around legacy `o1` behavior
and narrowed legacy structured-output checks to explicitly legacy model
names.
2026-06-10 21:18:14 -04:00
Christophe Bornet
3eee4002d9 refactor(langchain): refactor test_create_agent_tool_validation (#34443)
Simplify test for `create_agent` errors.
* Remove duplicate tests
* Test sync and async with common logic

---------

Co-authored-by: Mason Daugherty <github@mdrxy.com>
2026-06-10 14:42:46 -04:00
Christophe Bornet
7ffe092657 style(langchain): add ruff rules ARG (#34435)
In this order:
* used `@override` when overriding a parent method.
* prefixed param with `_` when the param could be renamed.
* used `*_args, **_kwargs` when it was not possible to rename (eg:
protocol)
* used `_ = some_variable` when the variable name is inspected (in
tools)

---------

Co-authored-by: Mason Daugherty <github@mdrxy.com>
Co-authored-by: Mason Daugherty <mason@langchain.dev>
2026-06-10 14:12:38 -04:00
Alexander Olsen
92ee772761 feat(langchain): add ProviderToolSearchMiddleware (#37969)
[Docs](https://github.com/langchain-ai/docs/pull/4355)

Adds `ProviderToolSearchMiddleware` to let agents defer selected tools
behind OpenAI/Anthropic provider-native tool search while preserving
existing `extras={"defer_loading": True}` behavior. The middleware
validates searchable tool names, injects the provider search tool only
when a tool is deferred, and rejects unsupported providers up front.

Made by [Open SWE](https://openswe.vercel.app)

---------

Co-authored-by: Alexander Olsen <13665641+aolsenjazz@users.noreply.github.com>
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Mason Daugherty <github@mdrxy.com>
Co-authored-by: Mason Daugherty <mason@langchain.dev>
2026-06-10 14:03:28 -04:00
Mason Daugherty
77bbf8ba39 test(langchain): mark legacy trigger view for 2.0 removal (#38002)
`SummarizationMiddleware._trigger_conditions` is now explicitly marked
as a temporary compatibility view for private consumers. The regression
test is tied to the package major version so the 2.0 release path fails
loudly until the legacy attr and test are removed.
2026-06-09 21:15:36 -04:00
Mason Daugherty
8c5b36c851 fix(langchain): preserve summarization trigger compatibility (#38000)
`SummarizationMiddleware` now uses `_trigger_clauses` as the canonical
internal representation for AND/OR trigger evaluation while keeping
`_trigger_conditions` as a tuple-shaped compatibility view. This keeps
the new dict-style `TriggerClause` behavior intact without breaking
private consumers that still inspect the old tuple-normalized trigger
state.

## Changes
- Added `_trigger_clauses` as the source of truth for summarization
trigger evaluation, profile requirement checks, and compound AND clause
handling.
- Restored `_trigger_conditions` as a legacy compatibility projection
for tuple-expressible triggers, so tuple and single-key dict triggers
remain visible in the previous private shape.
- Avoided misrepresenting compound `TriggerClause` inputs like
`{"tokens": 1000, "messages": 5}` as independent OR-style tuple
conditions.
2026-06-09 20:49:15 -04:00
James
05fe08201c feat(langchain): port AND-capable trigger conditions to SummarizationMiddleware (#34576)
Closes #34442

[Docs](https://github.com/langchain-ai/docs/pull/4377)

---

Add parity with LangChain.js trigger semantics for Python
`SummarizationMiddleware`. `trigger` can now express AND conditions
within a single dict-style `TriggerClause` while preserving the existing
tuple and list-of-tuples behavior.

A simple user story: a support agent is helping debug an issue over a
long conversation. One tool call may return a large log snippet, briefly
pushing the token count over a limit, but the conversation is still only
a few messages long and the recent context is valuable. Separately, the
user may send many short follow-up messages that increase message count
without using much context.

With `trigger={"tokens": 4000, "messages": 10}`, both thresholds must be
met at the same time: at least 4,000 tokens and at least 10 messages.
This means 5,000 tokens across only 3 messages does not summarize, and
20 short messages totaling only 1,000 tokens does not summarize either.
Summarization waits until the conversation is large enough by both
measures, making it less likely to discard useful recent context too
early.

## Changes

- Add `TriggerClause` support so `trigger={"tokens": 4000, "messages":
10}` only summarizes when all configured thresholds are met
- Export `TriggerClause` from `langchain.agents.middleware` so users can
import and annotate dict-style trigger clauses from the public
middleware entrypoint
- Normalize tuple and mapping trigger inputs through
`_normalize_trigger`, preserving existing `ContextSize` tuple semantics
as single-condition clauses
- Defensively copy mutable trigger list and dict inputs during
initialization so caller-side mutations do not change the middleware's
stored public configuration after construction
- Keep list inputs as OR semantics across clauses, including mixed lists
like `[{"tokens": 4000, "messages": 10}, ("messages", 50)]`
- Update `_should_summarize` to evaluate AND within each clause and OR
across clauses for `tokens`, `messages`, and `fraction`
- Update the docs and API link map so `TriggerClause` resolves in the
Python middleware docs
- Preserve tuple-trigger compatibility while allowing message-based
`keep` configurations to summarize at least one message when a trigger
fires near the cutoff boundary

AI assistance was used to help draft and refine this contribution.

---------

Co-authored-by: Mason Daugherty <mason@langchain.dev>
Co-authored-by: Mason Daugherty <github@mdrxy.com>
2026-06-09 19:30:39 -04:00
open-swe[bot]
17d1c274c4 fix(langchain): improve HITL rejection guidance (#37859)
Improves the default `reject` `ToolMessage` so models see that the human
denied the action, the tool was not executed, and the same call should
not be retried unless the user asks. Also documents that clients can
provide a custom `reject` message for domain-specific guidance.

[Docs](https://github.com/langchain-ai/docs/pull/4269)

_Opened collaboratively by Mason Daugherty and open-swe._

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Mason Daugherty <61371264+mdrxy@users.noreply.github.com>
Co-authored-by: Mason Daugherty <github@mdrxy.com>
2026-06-02 15:59:50 -04:00
Nick Hollon
dfca7f4424 feat(langchain): project subagent runs onto typed run.subagents channel (#37739) 2026-06-01 16:28:09 -04:00
Sydney Runkle
36be77b0f1 feat(langchain): add interrupt_mode and when predicate to HumanInTheLoopMiddleware (#37579)
Adds an optional `when` predicate to `InterruptOnConfig`, allowing
dynamic per-tool-call control over whether a HITL interrupt fires.

---

**`when` predicate in `InterruptOnConfig`**

```python
class InterruptOnConfig(TypedDict):
    allowed_decisions: list[DecisionType]
    description: NotRequired[str | _DescriptionFactory]
    args_schema: NotRequired[dict[str, Any]]
    when: NotRequired[Callable[[ToolCallRequest], bool]]  # new
```

When provided, `when` is called before adding a tool call to the batch
interrupt. If it returns `False`, the call is auto-approved and
excluded. If it returns `True` (or `when` is absent), existing behaviour
is unchanged.

The predicate receives a `ToolCallRequest` with:
- `tool_call` — the raw tool call dict (name, args, id)
- `tool` — `None` (no `BaseTool` instance is available at the
`after_model` stage)
- `state` — current agent state
- `runtime` — a `ToolRuntime` constructed from the node-level `Runtime`,
with `tool_call_id` populated

Example:

```python
HumanInTheLoopMiddleware(
    interrupt_on={
        "delete_file": InterruptOnConfig(
            allowed_decisions=["approve", "reject"],
            when=lambda req: req.tool_call["args"].get("path", "").startswith("/etc"),
        )
    }
)
```

This change is fully backwards-compatible — `when` is `NotRequired` and
existing configs without it behave identically.

> This PR was developed with AI-agent assistance.
2026-06-01 16:05:35 -04:00
Nick Hollon
d08245f70d feat(langchain): redact streamed PII in flight on PIIMiddleware (#37616)
`PIIMiddleware` previously scrubbed detected PII only at the state level
via its `after_model` / `before_model` hooks. Consumers reading the live
stream — `astream_events(version="v3")` or `run.messages` /
`run.tool_calls` / `run.values` — saw the raw model text, the raw
tool-call args, the raw tool outputs, and the raw state snapshots until
the run finished and the canonical conversation history was written.
This change registers a stream transformer ahead of
`MessagesTransformer` that redacts every wire surface of an agent run.

The transformer holds a sliding lookback buffer (default 128 characters)
per `(run_id, content-block index)` so PII patterns that straddle delta
boundaries are caught before the safe prefix is released downstream.
Anything older than the lookback is run through the configured detector
and emitted; the trailing tail stays buffered until a later delta
extends it past the cap or the block finishes. `_finalize_block` always
re-runs detection over the full block snapshot so the finalized content
lands fully redacted even when the in-flight buffer never released a
tail (short responses, or PII arriving in the final delta).

The `block` strategy is now supported on the streaming path via a
buffering mode that withholds every delta until the block resolves —
clean blocks release the full text at finalize, PII-bearing blocks zero
the wire and let `after_model` / `apply_to_tool_results` raise
`PIIDetectionError` on the original state message. Activation is gated
on `apply_to_output=True`, matching the existing post-hoc semantics. The
middleware's transformer factory is cloned by `StreamMux._make_child`
into every subgraph scope, so attaching `PIIMiddleware` at the outer
agent also redacts streamed deltas from sub-agents invoked inside tools.

## Tool-call and tools-channel coverage

The transformer covers every wire surface of an agent run, not just AI
message text:

- **Streamed AI text deltas** (`content-block-delta` of type
`text-delta`) — lookback machinery, redacted in place.
- **Streamed tool-call args** (`content-block-delta` with
`tool_call_chunk` / `server_tool_call_chunk` fields) — each delta
carries the full cumulative args string; detection runs on the field
directly and redacts in place. Verified empirically against
`_compat_bridge.py` and the consumer-side
`_merge_block_delta_into_store` snapshot-replace semantics.
- **Finalized tool-call blocks** (`content-block-finish` with
`tool_call` / `server_tool_call` / `invalid_tool_call`) — `args` dict
walked recursively and each string leaf redacted.
- **Tool execution events on the `tools` channel** —
`tool-started.input`, `tool-output-delta`, `tool-finished.output`,
`tool-error.message` all run through detection. String deltas use the
same lookback machinery as text-deltas keyed by `tool_call_id`;
structured payloads walk recursively.
- **State snapshots on the `values` channel** — message lists are walked
and each message's `.content` is redacted on a fresh copy. Graph state
itself stays intact for the state-level enforcer
(`apply_to_tool_results` via `before_model`) to act on independently.
- **Legacy `(BaseMessage, metadata)` payloads** on the `messages`
channel (Python 3.10 path, where `langgraph`'s `ASYNCIO_ACCEPTS_CONTEXT
= sys.version_info >= (3, 11)` falls back to a code path that doesn't
propagate the streaming callback into the chat model) — `.content` and
`AIMessage.tool_calls[*].args` are scrubbed. For `block`, the event's
`data` tuple is replaced with an empty-content copy so the original
message stays in state for `after_model` to raise on.

## Worth a careful look

- `_PIIStreamTransformer._mutate_text_delta` — lookback partition.
Anything older than `lookback` characters is released after redaction;
the tail stays buffered. Bulletproof against whitespace-permissive
detectors (notably `credit_card`, whose regex matches across spaces).
- `_PIIStreamTransformer._mutate_tool_call_chunk_delta` — direct
in-place redaction of the cumulative args string. No buffer; the wire
shape is cumulative-snapshot, the consumer-side merge is
replace-not-append.
- `_PIIStreamTransformer._mutate_legacy_payload` — the dual path:
mutate-in-place for non-`block` (idempotent with `after_model`),
replace-with-empty-copy for `block` (keeps original in graph state for
`after_model` to raise on).
- `_PIIStreamTransformer._redact_value` — the recursive walker.
`BaseMessage` branch returns a fresh `.content`-redacted copy via
`model_copy(update=...)` — never mutates in place — so tool-output
payloads that wrap a `ToolMessage` and message lists in state snapshots
flow through cleanly.
- The new `transformers` attribute on `PIIMiddleware`: this is what
makes `create_agent` pick the factory up. Multiple `PIIMiddleware`
instances each register one transformer; ordering is preserved within
the `before_builtins` lane.

## Compatibility

Bumps `langgraph` to `>=1.2.1` for the `before_builtins` opt-in on
`StreamTransformer`.
2026-05-22 17:27:02 -04:00
Nick Hollon
1aa4496fb4 feat(langchain): register stream transformers on middleware (#37591)
Adds a `transformers` attribute to `AgentMiddleware` so middleware can
declare scope-aware `StreamTransformer` factories alongside their
`tools` and lifecycle hooks. `create_agent` merges middleware-registered
factories with any caller-supplied ones at compile time.

## API

```python
class MyMiddleware(AgentMiddleware):
    transformers = (MyTransformer,)  # factory: (scope,) -> StreamTransformer
```

When the agent compiles, the final transformer order on the run mux is:

1. Built-in ``ToolCallTransformer``
2. Middleware-registered factories, in middleware order
3. Caller-supplied ``transformers=`` from ``create_agent``

This ordering keeps the built-in tool-call projection in front of any
consumer transformers and gives caller-supplied entries the final word.
2026-05-21 12:08:54 -04:00
Blut-agent
d328d84b78 fix(langchain): sort glob_search results by mtime (newest first) (#37462)
Closes #37369

---

The `glob_search` tool in `FilesystemFileSearchMiddleware` documents
that
results are "sorted by modification time (most recently modified
first)",
but the implementation was returning files in the arbitrary order
provided
by `Path.glob()`.

This change adds a sort by modification timestamp (`modified_at`), in
descending order, immediately before extracting the file paths for the
return value. No public API changes.

---------

Co-authored-by: Mason Daugherty <github@mdrxy.com>
2026-05-16 18:09:53 -07:00
ccurme
36c381b149 fix(langchain): alias Bedrock providers in summarization token check (#37453) 2026-05-15 14:08:31 -04:00
Nick Hollon
da380bccf8 chore(infra): merge v1.4 into master (#37350) 2026-05-11 11:39:25 -07:00
ccurme
9c48a120b9 revert: feat(langchain): ls_agent_type tag on create_agent calls (#37249) 2026-05-08 09:24:11 -04:00
Sydney Runkle
ba56ac6f03 feat(langchain): add respond decision to HITL middleware (#37095)
Extends `HumanInTheLoopMiddleware` with a new `respond` decision type
for "ask user" style tools — tools whose real implementation is the
human's response. The interrupt is raised with the tool call as usual;
the resume payload becomes the body of a synthetic `ToolMessage` with
`status="success"`, and the tool itself is not executed.

This complements `reject` (which produces a synthetic `ToolMessage` with
`status="error"`) by enabling the symmetric success path: a reviewer can
answer on the tool's behalf without invoking it.

## Changes

- New `RespondDecision` `TypedDict` with a required `message: str`
field; added to the `Decision` union.
- `"respond"` added to the `DecisionType` literal.
- `_process_decision` handles `"respond"` by emitting a `ToolMessage`
with `status="success"` and preserving the original tool call on the
`AIMessage` so provider-required tool-call/tool-message pairing is
maintained.
- The `True` shortcut in `interrupt_on` now expands to `["approve",
"edit", "reject", "respond"]`, so existing callers that opted into "all
decisions" pick up the new capability without code changes. The `reject`
decision already permits a reviewer to inject arbitrary `ToolMessage`
content, so `respond` extends the same trust model — not a new
capability class.

## Example

```python
from langchain.agents.middleware import HumanInTheLoopMiddleware

middleware = HumanInTheLoopMiddleware(
    interrupt_on={"ask_user": {"allowed_decisions": ["respond"]}}
)
# Resume payload: {"decisions": [{"type": "respond", "message": "blue"}]}
# → synthetic ToolMessage(content="blue", status="success") for `ask_user`.
```

---

*Implementation drafted with AI-agent assistance.*

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 14:55:03 -04:00
Jacob Lee
ee95ad6907 feat(langchain): ls_agent_type tag on create_agent calls (#36774) 2026-04-17 15:39:22 -07:00
Eugene Yurtsev
c87cd04927 release(core): release 1.3.0 (#36851)
xRelease 1.3.0
2026-04-17 14:42:01 +00:00
Eugene Yurtsev
8f5c800f41 test(langchain): test cache hit/miss on lru (#36659)
add quick test
2026-04-13 10:13:21 -04:00
Eugene Yurtsev
1ca47a5411 perf(langchain): add another init test with middleware (#36644)
add another init test with middleware
2026-04-10 11:20:23 -04:00
Eugene Yurtsev
af4d711a2f chore(core): reduce streaming metadata / perf (#36588)
- looking into reducing streaming metadata / perfm

---------

Co-authored-by: William Fu-Hinthorn <13333726+hinthornw@users.noreply.github.com>
2026-04-10 10:47:54 -04:00
Eugene Yurtsev
f0c5a28fa0 perf(langchain): add benchmark command (#36641)
add benchmark in Makefile
2026-04-09 16:05:17 -04:00
Eugene Yurtsev
4e55c555ad test(langchain): cover runtime recursion limit override in create_agent (#36376)
Extends the existing unit test for to verify that a per-invoke override
is visible inside the tool runtime config. This keeps the coverage in
the existing fake-model end-to-end test and exercises both the default
config path and the override path in one place.

Created with [Deep Agents
CLI](https://docs.langchain.com/oss/python/deepagents/cli/overview)
using gpt-5.4 (provider: openai).
2026-03-30 12:47:02 -04:00
Eugene Yurtsev
c7a677bba5 chore(langchain): add async implementation to todolist and test (#36313)
add async func as well
2026-03-27 15:38:38 -04:00
Mason Daugherty
2f64d80cc6 fix(core,model-profiles): add missing ModelProfile fields, warn on schema drift (#36129)
PR #35788 added 7 new fields to the `langchain-profiles` CLI output
(`name`, `status`, `release_date`, `last_updated`, `open_weights`,
`attachment`, `temperature`) but didn't update `ModelProfile` in
`langchain-core`. Partner packages like `langchain-aws` that set
`extra="forbid"` on their Pydantic models hit `extra_forbidden`
validation errors when Pydantic encountered undeclared TypedDict keys at
construction time. This adds the missing fields, makes `ModelProfile`
forward-compatible, provides a base-class hook so partners can stop
duplicating model-profile validator boilerplate, migrates all in-repo
partners to the new hook, and adds runtime + CI-time warnings for schema
drift.

## Changes

### `langchain-core`
- Add `__pydantic_config__ = ConfigDict(extra="allow")` to
`ModelProfile` so unknown profile keys pass Pydantic validation even on
models with `extra="forbid"` — forward-compatibility for when the CLI
schema evolves ahead of core
- Declare the 7 missing fields on `ModelProfile`: `name`, `status`,
`release_date`, `last_updated`, `open_weights` (metadata) and
`attachment`, `temperature` (capabilities)
- Add `_warn_unknown_profile_keys()` in `model_profile.py` — emits a
`UserWarning` when a profile dict contains keys not in `ModelProfile`,
suggesting a core upgrade. Wrapped in a bare `except` so introspection
failures never crash model construction
- Add `BaseChatModel._resolve_model_profile()` hook that returns `None`
by default. Partners can override this single method instead of
redefining the full `_set_model_profile` validator — the base validator
calls it automatically
- Add `BaseChatModel._check_profile_keys` as a separate
`model_validator` that calls `_warn_unknown_profile_keys`. Uses a
distinct method name so partner overrides of `_set_model_profile` don't
inadvertently suppress the check

### `langchain-profiles` CLI
- Add `_warn_undeclared_profile_keys()` to the CLI (`cli.py`), called
after merging augmentations in `refresh()` — warns at profile-generation
time (not just runtime) when emitted keys aren't declared in
`ModelProfile`. Gracefully skips if `langchain-core` isn't installed
- Add guard test
`test_model_data_to_profile_keys_subset_of_model_profile` in
model-profiles — feeds a fully-populated model dict to
`_model_data_to_profile()` and asserts every emitted key exists in
`ModelProfile.__annotations__`. CI fails before any release if someone
adds a CLI field without updating the TypedDict

### Partner packages
- Migrate all 10 in-repo partners to the `_resolve_model_profile()`
hook, replacing duplicated `@model_validator` / `_set_model_profile`
overrides: anthropic, deepseek, fireworks, groq, huggingface, mistralai,
openai (base + azure), openrouter, perplexity, xai
- Anthropic retains custom logic (context-1m beta → `max_input_tokens`
override); all others reduce to a one-liner
- Add `pr_lint.yml` scope for the new `model-profiles` package
2026-03-23 00:44:27 -04:00
Giulio Leone
9e4a6013be fix(openai): add type: message to Responses API input items (#35693) 2026-03-15 12:43:16 -04:00
Giulio Leone
46fdade7e6 fix(langchain): normalize custom detector output to prevent KeyError in hash/mask strategies (#35651) 2026-03-08 15:07:36 -04:00
Mason Daugherty
bed4d2686a chore(langchain): switch refs from gemini-3 to gemini-3.1 (#35535) 2026-03-03 10:36:33 -05:00
Théo Deschamps
83f81d65af fix(langchain): allow Gemini 3 models to use ProviderStrategy with tools (#34464) 2026-02-18 21:14:16 -05:00
ccurme
8f1bc0d3ae feat(openai): support automatic server-side compaction (#35212) 2026-02-17 10:48:52 -05:00
Mason Daugherty
65c224a3da chore(core): raise more descriptive model error in init_chat_model (#35167) 2026-02-11 11:09:06 -05:00
dependabot[bot]
de05838fca chore(deps): bump the langchain-deps group across 3 directories with 40 updates (#35129)
Bumps the langchain-deps group with 10 updates in the /libs/core
directory:

| Package | From | To |
| --- | --- | --- |
| [langsmith](https://github.com/langchain-ai/langsmith-sdk) | `0.6.0` |
`0.7.1` |
| [tenacity](https://github.com/jd/tenacity) | `9.1.2` | `9.1.4` |
| [packaging](https://github.com/pypa/packaging) | `25.0` | `26.0` |
| [uuid-utils](https://github.com/aminalaee/uuid-utils) | `0.12.0` |
`0.14.0` |
| [ruff](https://github.com/astral-sh/ruff) | `0.14.11` | `0.15.0` |
| [types-requests](https://github.com/typeshed-internal/stub_uploader) |
`2.31.0.6` | `2.32.4.20260107` |
| [setuptools](https://github.com/pypa/setuptools) | `78.1.1` | `82.0.0`
|
| [pytest](https://github.com/pytest-dev/pytest) | `8.4.2` | `9.0.2` |
| [pytest-watcher](https://github.com/olzhasar/pytest-watcher) | `0.4.3`
| `0.6.3` |
| [pytest-codspeed](https://github.com/CodSpeedHQ/pytest-codspeed) |
`4.2.0` | `4.3.0` |

Bumps the langchain-deps group with 31 updates in the /libs/langchain
directory:

| Package | From | To |
| --- | --- | --- |
| [langsmith](https://github.com/langchain-ai/langsmith-sdk) | `0.4.31`
| `0.7.1` |
| [packaging](https://github.com/pypa/packaging) | `25.0` | `26.0` |
| [pydantic](https://github.com/pydantic/pydantic) | `2.12.1` | `2.12.5`
|
| [ruff](https://github.com/astral-sh/ruff) | `0.14.11` | `0.15.0` |
| [types-requests](https://github.com/typeshed-internal/stub_uploader) |
`2.31.0.6` | `2.32.4.20260107` |
| [setuptools](https://github.com/pypa/setuptools) | `80.9.0` | `82.0.0`
|
| [pytest](https://github.com/pytest-dev/pytest) | `8.4.2` | `9.0.2` |
| [pytest-watcher](https://github.com/olzhasar/pytest-watcher) | `0.4.3`
| `0.6.3` |
| [numpy](https://github.com/numpy/numpy) | `1.26.4` | `2.2.6` |
| [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) | `2.0.43` |
`2.0.46` |
| [langchain-anthropic](https://github.com/langchain-ai/langchain) |
`0.0.1.post1` | `1.3.2` |
|
[langchain-google-vertexai](https://github.com/langchain-ai/langchain-google)
| `2.1.2` | `3.2.2` |
|
[langchain-google-genai](https://github.com/langchain-ai/langchain-google)
| `2.1.12` | `4.2.0` |
| [langchain-fireworks](https://github.com/langchain-ai/langchain) |
`1.0.0a1` | `1.1.0` |
| [langchain-ollama](https://github.com/langchain-ai/langchain) |
`1.0.0a1` | `1.0.1` |
| [langchain-mistralai](https://github.com/langchain-ai/langchain) |
`0.2.12` | `1.1.1` |
| [langchain-huggingface](https://github.com/langchain-ai/langchain) |
`1.0.0` | `1.2.0` |
| [langchain-groq](https://github.com/langchain-ai/langchain) |
`1.0.0a1` | `1.1.2` |
| [langchain-aws](https://github.com/langchain-ai/langchain-aws) |
`1.0.0a1` | `1.2.3` |
| [langchain-deepseek](https://github.com/langchain-ai/langchain) |
`1.0.0a1` | `1.0.1` |
| [langchain-xai](https://github.com/langchain-ai/langchain) | `1.0.0a1`
| `1.2.2` |
| [langchain-perplexity](https://github.com/langchain-ai/langchain) |
`1.0.0a1` | `1.1.0` |
| [pytest-cov](https://github.com/pytest-dev/pytest-cov) | `4.1.0` |
`7.0.0` |
| [lark](https://github.com/lark-parser/lark) | `1.3.0` | `1.3.1` |
| [wrapt](https://github.com/GrahamDumpleton/wrapt) | `1.17.3` | `2.1.1`
|
| [python-dotenv](https://github.com/theskumar/python-dotenv) | `1.1.1`
| `1.2.1` |
| langchainhub | `0.1.18` | `0.1.21` |
| [mypy-protobuf](https://github.com/nipunn1313/mypy-protobuf) | `3.6.0`
| `5.0.0` |
| [types-pytz](https://github.com/typeshed-internal/stub_uploader) |
`2023.4.0.20240130` | `2025.2.0.20251108` |
| [fastapi](https://github.com/fastapi/fastapi) | `0.128.0` | `0.128.6`
|
| [playwright](https://github.com/microsoft/playwright-python) |
`1.55.0` | `1.58.0` |

Bumps the langchain-deps group with 17 updates in the /libs/langchain_v1
directory:

| Package | From | To |
| --- | --- | --- |
| [pydantic](https://github.com/pydantic/pydantic) | `2.12.4` | `2.12.5`
|
| [ruff](https://github.com/astral-sh/ruff) | `0.14.11` | `0.15.0` |
| [pytest](https://github.com/pytest-dev/pytest) | `8.4.2` | `9.0.2` |
| [pytest-watcher](https://github.com/olzhasar/pytest-watcher) | `0.4.3`
| `0.6.3` |
|
[langchain-google-vertexai](https://github.com/langchain-ai/langchain-google)
| `3.0.3` | `3.2.2` |
|
[langchain-google-genai](https://github.com/langchain-ai/langchain-google)
| `3.0.3` | `4.2.0` |
| [langchain-fireworks](https://github.com/langchain-ai/langchain) |
`1.0.0` | `1.1.0` |
| [langchain-ollama](https://github.com/langchain-ai/langchain) |
`1.0.0` | `1.0.1` |
| [langchain-mistralai](https://github.com/langchain-ai/langchain) |
`1.0.1` | `1.1.1` |
| [langchain-huggingface](https://github.com/langchain-ai/langchain) |
`1.0.1` | `1.2.0` |
| [langchain-groq](https://github.com/langchain-ai/langchain) | `1.0.1`
| `1.1.2` |
| [langchain-aws](https://github.com/langchain-ai/langchain-aws) |
`1.0.0` | `1.2.3` |
| [langchain-xai](https://github.com/langchain-ai/langchain) | `1.0.0` |
`1.2.2` |
| [langchain-perplexity](https://github.com/langchain-ai/langchain) |
`1.0.0` | `1.1.0` |
| [wrapt](https://github.com/GrahamDumpleton/wrapt) | `1.17.3` | `2.1.1`
|
| [langgraph](https://github.com/langchain-ai/langgraph) | `1.0.7` |
`1.0.8` |
| [langchain-azure-ai](https://github.com/langchain-ai/langchain-azure)
| `1.0.3` | `1.0.4` |


Updates `langsmith` from 0.6.0 to 0.7.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/langchain-ai/langsmith-sdk/releases">langsmith's
releases</a>.</em></p>
<blockquote>
<h2>v0.7.1</h2>
<h2>What's Changed</h2>
<ul>
<li>release(js): 0.5.0 by <a
href="https://github.com/jacoblee93"><code>@​jacoblee93</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2381">langchain-ai/langsmith-sdk#2381</a></li>
<li>fix(ci): Convert JS release workflow to use OIDC by <a
href="https://github.com/jacoblee93"><code>@​jacoblee93</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2383">langchain-ai/langsmith-sdk#2383</a></li>
<li>feat(js): run evaluations as examples complete by <a
href="https://github.com/bees"><code>@​bees</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2349">langchain-ai/langsmith-sdk#2349</a></li>
<li>fix(js): Restore default concurrency behavior for JS eval runner by
<a href="https://github.com/jacoblee93"><code>@​jacoblee93</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2385">langchain-ai/langsmith-sdk#2385</a></li>
<li>fix(js,py): Adds backcompat for old prompt cache API by <a
href="https://github.com/jacoblee93"><code>@​jacoblee93</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2386">langchain-ai/langsmith-sdk#2386</a></li>
<li>fix(js): Add system message visibility to Anthropic wrapper traces
by <a href="https://github.com/veeceey"><code>@​veeceey</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2375">langchain-ai/langsmith-sdk#2375</a></li>
<li>release(py): 0.7.1 by <a
href="https://github.com/jacoblee93"><code>@​jacoblee93</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2388">langchain-ai/langsmith-sdk#2388</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/veeceey"><code>@​veeceey</code></a> made
their first contribution in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2375">langchain-ai/langsmith-sdk#2375</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.7.0...v0.7.1">https://github.com/langchain-ai/langsmith-sdk/compare/v0.7.0...v0.7.1</a></p>
<h2>v0.7.0</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(deps): bump form-data from 4.0.3 to 4.0.5 in /js by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2282">langchain-ai/langsmith-sdk#2282</a></li>
<li>chore(deps-dev): bump langchain from 0.3.29 to 0.3.37 in /js by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2283">langchain-ai/langsmith-sdk#2283</a></li>
<li>chore(deps): bump vite from 6.3.5 to 6.4.1 in /js by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2284">langchain-ai/langsmith-sdk#2284</a></li>
<li>chore:deps by <a
href="https://github.com/jkennedyvz"><code>@​jkennedyvz</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2356">langchain-ai/langsmith-sdk#2356</a></li>
<li>chore(deps): bump python-multipart from 0.0.21 to 0.0.22 in /python
by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2351">langchain-ai/langsmith-sdk#2351</a></li>
<li>chore(deps): bump protobuf from 6.33.2 to 6.33.5 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2352">langchain-ai/langsmith-sdk#2352</a></li>
<li>chore(deps): bump pyasn1 from 0.6.1 to 0.6.2 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2353">langchain-ai/langsmith-sdk#2353</a></li>
<li>chore(deps-dev): bump esbuild from 0.20.2 to 0.25.0 in
/js/internal/environment_tests/test-exports-esbuild in the npm_and_yarn
group across 1 directory by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2354">langchain-ai/langsmith-sdk#2354</a></li>
<li>chore(deps): bump jws from 4.0.0 to 4.0.1 in /js by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2355">langchain-ai/langsmith-sdk#2355</a></li>
<li>chore(deps): bump actions/setup-node from 3 to 6 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2357">langchain-ai/langsmith-sdk#2357</a></li>
<li>chore(deps): bump actions/github-script from 6 to 8 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2358">langchain-ai/langsmith-sdk#2358</a></li>
<li>chore(deps): bump actions/checkout from 2 to 6 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2359">langchain-ai/langsmith-sdk#2359</a></li>
<li>chore(deps): bump astral-sh/setup-uv from 6 to 7 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2360">langchain-ai/langsmith-sdk#2360</a></li>
<li>chore(deps): bump actions/cache from 4 to 5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2361">langchain-ai/langsmith-sdk#2361</a></li>
<li>chore(deps-dev): bump ty from 0.0.10 to 0.0.15 in /python in the
py-minor-and-patch group by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2362">langchain-ai/langsmith-sdk#2362</a></li>
<li>chore(deps): update httpx requirement from &lt;0.28.0,&gt;=0.23.0 to
&gt;=0.23.0,&lt;0.29.0 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2363">langchain-ai/langsmith-sdk#2363</a></li>
<li>chore(deps-dev): bump eslint-plugin-prettier from 4.2.1 to 4.2.5 in
/js by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2366">langchain-ai/langsmith-sdk#2366</a></li>
<li>chore(deps-dev): bump babel-jest from 29.7.0 to 30.2.0 in /js by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2365">langchain-ai/langsmith-sdk#2365</a></li>
<li>chore: adding workflow perms by <a
href="https://github.com/jkennedyvz"><code>@​jkennedyvz</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2367">langchain-ai/langsmith-sdk#2367</a></li>
<li>fix: esbuild CVE dependabot 78 by <a
href="https://github.com/jkennedyvz"><code>@​jkennedyvz</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2369">langchain-ai/langsmith-sdk#2369</a></li>
<li>fix(deps): resolve glob CLI command injection (CVE-2025-64756) by <a
href="https://github.com/jkennedyvz"><code>@​jkennedyvz</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2368">langchain-ai/langsmith-sdk#2368</a></li>
<li>fix(deps): resolve js-yaml prototype pollution vulnerability by <a
href="https://github.com/jkennedyvz"><code>@​jkennedyvz</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2370">langchain-ai/langsmith-sdk#2370</a></li>
<li>chore(deps): bump the js-minor-and-patch group in /js with 20
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2364">langchain-ai/langsmith-sdk#2364</a></li>
<li>chore: rm unused fn by <a
href="https://github.com/hinthornw"><code>@​hinthornw</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2346">langchain-ai/langsmith-sdk#2346</a></li>
<li>feat(py,js): Use global singleton for prompt cache, enable by
default by <a
href="https://github.com/jacoblee93"><code>@​jacoblee93</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2371">langchain-ai/langsmith-sdk#2371</a></li>
<li>chore: Support jwt auth in replicas by <a
href="https://github.com/hinthornw"><code>@​hinthornw</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2293">langchain-ai/langsmith-sdk#2293</a></li>
<li>release(py): 0.7.0 by <a
href="https://github.com/jacoblee93"><code>@​jacoblee93</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2382">langchain-ai/langsmith-sdk#2382</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/jkennedyvz"><code>@​jkennedyvz</code></a> made
their first contribution in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/2356">langchain-ai/langsmith-sdk#2356</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.6.9...v0.7.0">https://github.com/langchain-ai/langsmith-sdk/compare/v0.6.9...v0.7.0</a></p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="ff55b58836"><code>ff55b58</code></a>
release(py): 0.7.1 (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/2388">#2388</a>)</li>
<li><a
href="c41e3fbc85"><code>c41e3fb</code></a>
fix(js): Add system message visibility to Anthropic wrapper traces (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/2375">#2375</a>)</li>
<li><a
href="ffc3769a46"><code>ffc3769</code></a>
fix(js,py): Adds backcompat for old prompt cache API (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/2386">#2386</a>)</li>
<li><a
href="de02f1deab"><code>de02f1d</code></a>
fix(js): Restore default concurrency behavior for JS eval runner (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/2385">#2385</a>)</li>
<li><a
href="2083f3b149"><code>2083f3b</code></a>
feat(js): run evaluations as examples complete (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/2349">#2349</a>)</li>
<li><a
href="c231c07b34"><code>c231c07</code></a>
fix(ci): Convert JS release workflow to use OIDC (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/2383">#2383</a>)</li>
<li><a
href="9587a467a3"><code>9587a46</code></a>
release(js): 0.5.0 (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/2381">#2381</a>)</li>
<li><a
href="c9f9c9b49d"><code>c9f9c9b</code></a>
release(py): 0.7.0 (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/2382">#2382</a>)</li>
<li><a
href="0fbbc113bc"><code>0fbbc11</code></a>
chore: Support jwt auth in replicas (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/2293">#2293</a>)</li>
<li><a
href="024cd6cbed"><code>024cd6c</code></a>
feat(py,js): Use global singleton for prompt cache, enable by default
(<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/2371">#2371</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.6.0...v0.7.1">compare
view</a></li>
</ul>
</details>
<br />

Updates `tenacity` from 9.1.2 to 9.1.4
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/jd/tenacity/releases">tenacity's
releases</a>.</em></p>
<blockquote>
<h2>9.1.4</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix <code>retry()</code> annotations with async <code>sleep=</code>
function by <a
href="https://github.com/Zac-HD"><code>@​Zac-HD</code></a> in <a
href="https://redirect.github.com/jd/tenacity/pull/555">jd/tenacity#555</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/jd/tenacity/compare/9.1.3...9.1.4">https://github.com/jd/tenacity/compare/9.1.3...9.1.4</a></p>
<h2>9.1.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Apply formatting to num seconds in before_sleep_log by <a
href="https://github.com/aguinane"><code>@​aguinane</code></a> in <a
href="https://redirect.github.com/jd/tenacity/pull/489">jd/tenacity#489</a></li>
<li>Support Python 3.14 by <a
href="https://github.com/sandrobonazzola"><code>@​sandrobonazzola</code></a>
in <a
href="https://redirect.github.com/jd/tenacity/pull/528">jd/tenacity#528</a></li>
<li>Typing: Accept non-standard logger in helpers logging something by
<a href="https://github.com/k4nar"><code>@​k4nar</code></a> in <a
href="https://redirect.github.com/jd/tenacity/pull/540">jd/tenacity#540</a></li>
<li>feat(wait): add <code>wait_exception</code> strategy by <a
href="https://github.com/capitan-davide"><code>@​capitan-davide</code></a>
in <a
href="https://redirect.github.com/jd/tenacity/pull/541">jd/tenacity#541</a></li>
<li>docs: fix syntax error in wait_chain docstring example by <a
href="https://github.com/VedantMadane"><code>@​VedantMadane</code></a>
in <a
href="https://redirect.github.com/jd/tenacity/pull/548">jd/tenacity#548</a></li>
<li>chore: drop Python 3.9 support (EOL) by <a
href="https://github.com/Zac-HD"><code>@​Zac-HD</code></a> in <a
href="https://redirect.github.com/jd/tenacity/pull/552">jd/tenacity#552</a></li>
<li>Support async sleep for sync fn-to-retry by <a
href="https://github.com/Zac-HD"><code>@​Zac-HD</code></a> in <a
href="https://redirect.github.com/jd/tenacity/pull/551">jd/tenacity#551</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/aguinane"><code>@​aguinane</code></a>
made their first contribution in <a
href="https://redirect.github.com/jd/tenacity/pull/489">jd/tenacity#489</a></li>
<li><a
href="https://github.com/sandrobonazzola"><code>@​sandrobonazzola</code></a>
made their first contribution in <a
href="https://redirect.github.com/jd/tenacity/pull/528">jd/tenacity#528</a></li>
<li><a href="https://github.com/k4nar"><code>@​k4nar</code></a> made
their first contribution in <a
href="https://redirect.github.com/jd/tenacity/pull/540">jd/tenacity#540</a></li>
<li><a
href="https://github.com/capitan-davide"><code>@​capitan-davide</code></a>
made their first contribution in <a
href="https://redirect.github.com/jd/tenacity/pull/541">jd/tenacity#541</a></li>
<li><a
href="https://github.com/VedantMadane"><code>@​VedantMadane</code></a>
made their first contribution in <a
href="https://redirect.github.com/jd/tenacity/pull/548">jd/tenacity#548</a></li>
<li><a href="https://github.com/Zac-HD"><code>@​Zac-HD</code></a> made
their first contribution in <a
href="https://redirect.github.com/jd/tenacity/pull/552">jd/tenacity#552</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/jd/tenacity/compare/9.1.2...9.1.3">https://github.com/jd/tenacity/compare/9.1.2...9.1.3</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="d4e868d6b8"><code>d4e868d</code></a>
Fix <code>retry()</code> annotations with async <code>sleep=</code>
function (<a
href="https://redirect.github.com/jd/tenacity/issues/555">#555</a>)</li>
<li><a
href="24415ebbca"><code>24415eb</code></a>
support async sleep for sync fn (<a
href="https://redirect.github.com/jd/tenacity/issues/551">#551</a>)</li>
<li><a
href="3bf33b4409"><code>3bf33b4</code></a>
chore: drop Python 3.9 support (EOL) (<a
href="https://redirect.github.com/jd/tenacity/issues/552">#552</a>)</li>
<li><a
href="7027da31d2"><code>7027da3</code></a>
chore(deps): bump the github-actions group with 2 updates (<a
href="https://redirect.github.com/jd/tenacity/issues/550">#550</a>)</li>
<li><a
href="21ae7d0cc2"><code>21ae7d0</code></a>
docs: fix syntax error in wait_chain docstring example (<a
href="https://redirect.github.com/jd/tenacity/issues/548">#548</a>)</li>
<li><a
href="ef12c9ed1d"><code>ef12c9e</code></a>
chore(deps): bump actions/checkout in the github-actions group (<a
href="https://redirect.github.com/jd/tenacity/issues/547">#547</a>)</li>
<li><a
href="c35a4b341e"><code>c35a4b3</code></a>
chore(deps): bump the github-actions group with 2 updates (<a
href="https://redirect.github.com/jd/tenacity/issues/545">#545</a>)</li>
<li><a
href="e792bbaf0c"><code>e792bba</code></a>
ci: fix mypy (<a
href="https://redirect.github.com/jd/tenacity/issues/546">#546</a>)</li>
<li><a
href="0f55245b8d"><code>0f55245</code></a>
ci: remove reno requirements (<a
href="https://redirect.github.com/jd/tenacity/issues/542">#542</a>)</li>
<li><a
href="815c34fec2"><code>815c34f</code></a>
feat(wait): add <code>wait_exception</code> strategy (<a
href="https://redirect.github.com/jd/tenacity/issues/541">#541</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/jd/tenacity/compare/9.1.2...9.1.4">compare
view</a></li>
</ul>
</details>
<br />

Updates `packaging` from 25.0 to 26.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/pypa/packaging/releases">packaging's
releases</a>.</em></p>
<blockquote>
<h2>26.0</h2>
<p>Read about the performance improvements here: <a
href="https://iscinumpy.dev/post/packaging-faster">https://iscinumpy.dev/post/packaging-faster</a>.</p>
<h2>What's Changed</h2>
<p>Features:</p>
<ul>
<li>PEP 751: support pylock by <a
href="https://github.com/sbidoul"><code>@​sbidoul</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/900">pypa/packaging#900</a></li>
<li>PEP 794: import name metadata by <a
href="https://github.com/brettcannon"><code>@​brettcannon</code></a> in
<a
href="https://redirect.github.com/pypa/packaging/pull/948">pypa/packaging#948</a></li>
<li>Support writing metadata by <a
href="https://github.com/henryiii"><code>@​henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/846">pypa/packaging#846</a></li>
<li>Support <code>__replace__</code> for <code>Version</code> by <a
href="https://github.com/henryiii"><code>@​henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/1003">pypa/packaging#1003</a></li>
<li>Support positional pattern matching for <code>Version</code> and
<code>Specifier</code> by <a
href="https://github.com/henryiii"><code>@​henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/1004">pypa/packaging#1004</a></li>
</ul>
<p>Behavior adaptations:</p>
<ul>
<li>PEP 440 handling of prereleases for <code>Specifier.contains</code>,
<code>SpecifierSet.contains</code>, and <code>SpecifierSet.filter</code>
by <a
href="https://github.com/notatallshaw"><code>@​notatallshaw</code></a>
in <a
href="https://redirect.github.com/pypa/packaging/pull/897">pypa/packaging#897</a></li>
<li>Handle PEP 440 edge case in <code>SpecifierSet.filter</code> by <a
href="https://github.com/notatallshaw"><code>@​notatallshaw</code></a>
in <a
href="https://redirect.github.com/pypa/packaging/pull/942">pypa/packaging#942</a></li>
<li>Adjust arbitrary equality intersection preservation in
<code>SpecifierSet</code> by <a
href="https://github.com/notatallshaw"><code>@​notatallshaw</code></a>
in <a
href="https://redirect.github.com/pypa/packaging/pull/951">pypa/packaging#951</a></li>
<li>Return <code>False</code> instead of raising for
<code>.contains</code> with invalid version by <a
href="https://github.com/Liam-DeVoe"><code>@​Liam-DeVoe</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/932">pypa/packaging#932</a></li>
<li>Support arbitrary equality on arbitrary strings for
<code>Specifier</code> and <code>SpecifierSet</code>'s
<code>filter</code> and <code>contains</code> method. by <a
href="https://github.com/notatallshaw"><code>@​notatallshaw</code></a>
in <a
href="https://redirect.github.com/pypa/packaging/pull/954">pypa/packaging#954</a></li>
<li>Only try to parse as <code>Version</code> on certain marker keys,
return <code>False</code> on unequal ordered comparsions by <a
href="https://github.com/JP-Ellis"><code>@​JP-Ellis</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/939">pypa/packaging#939</a></li>
</ul>
<p>Fixes:</p>
<ul>
<li>Update <code>_hash</code> when unpickling <code>Tag()</code> by <a
href="https://github.com/dholth"><code>@​dholth</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/860">pypa/packaging#860</a></li>
<li>Correct comment and simplify implicit prerelease handling in
<code>Specifier.prereleases</code> by <a
href="https://github.com/notatallshaw"><code>@​notatallshaw</code></a>
in <a
href="https://redirect.github.com/pypa/packaging/pull/896">pypa/packaging#896</a></li>
<li>Use explicit <code>_GLibCVersion</code> <code>NamedTuple</code> in
<code>_manylinux</code> by <a
href="https://github.com/cthoyt"><code>@​cthoyt</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/868">pypa/packaging#868</a></li>
<li>Detect invalid license expressions containing <code>()</code> by <a
href="https://github.com/bwoodsend"><code>@​bwoodsend</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/879">pypa/packaging#879</a></li>
<li>Correct regex for metadata <code>'name'</code> format by <a
href="https://github.com/di"><code>@​di</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/925">pypa/packaging#925</a></li>
<li>Improve the message around expecting a semicolon by <a
href="https://github.com/pradyunsg"><code>@​pradyunsg</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/833">pypa/packaging#833</a></li>
<li>Support nested parens in license expressions by <a
href="https://github.com/Liam-DeVoe"><code>@​Liam-DeVoe</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/931">pypa/packaging#931</a></li>
<li>Add space before at symbol in <code>Requirements</code> string by <a
href="https://github.com/henryiii"><code>@​henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/953">pypa/packaging#953</a></li>
<li>A root logger use found by ruff LOG, use <code>packaging</code>
logger instead by <a
href="https://github.com/henryiii"><code>@​henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/965">pypa/packaging#965</a></li>
<li>Better support for subclassing <code>Marker</code> and
<code>Requirement</code> by <a
href="https://github.com/henryiii"><code>@​henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/1022">pypa/packaging#1022</a></li>
<li>Normalize all extras, not just if it comes first by <a
href="https://github.com/henryiii"><code>@​henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/1024">pypa/packaging#1024</a></li>
<li>Don't produce a broken repr if <code>Marker</code> fails to
construct by <a
href="https://github.com/henryiii"><code>@​henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/1033">pypa/packaging#1033</a></li>
</ul>
<p>Performance:</p>
<ul>
<li>Avoid recompiling regexes in the tokenizer for a 3x speedup by <a
href="https://github.com/hauntsaninja"><code>@​hauntsaninja</code></a>
in <a
href="https://redirect.github.com/pypa/packaging/pull/1019">pypa/packaging#1019</a></li>
<li>Improve performance in <code>_manylinux.py</code> by <a
href="https://github.com/cthoyt"><code>@​cthoyt</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/869">pypa/packaging#869</a></li>
<li>Minor cleanups to <code>Version</code> by <a
href="https://github.com/bearomorphism"><code>@​bearomorphism</code></a>
in <a
href="https://redirect.github.com/pypa/packaging/pull/913">pypa/packaging#913</a></li>
<li>Skip redundant creation of <code>Version</code>s in specifier
comparison by <a
href="https://github.com/notatallshaw"><code>@​notatallshaw</code></a>
in <a
href="https://redirect.github.com/pypa/packaging/pull/986">pypa/packaging#986</a></li>
<li>Cache <code>Specifier</code>'s Version by <a
href="https://github.com/notatallshaw"><code>@​notatallshaw</code></a>
in <a
href="https://redirect.github.com/pypa/packaging/pull/985">pypa/packaging#985</a></li>
<li>Make <code>Version</code> a little faster by <a
href="https://github.com/henryiii"><code>@​henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/987">pypa/packaging#987</a></li>
<li>Minor <code>Version</code> regex cleanup by <a
href="https://github.com/henryiii"><code>@​henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/990">pypa/packaging#990</a></li>
<li>Faster regex on Python 3.11.5+ by <a
href="https://github.com/henryiii"><code>@​henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/988">pypa/packaging#988</a>
and <a
href="https://redirect.github.com/pypa/packaging/pull/1055">pypa/packaging#1055</a></li>
<li>Lazily calculate <code>_key</code> in <code>Version</code> by <a
href="https://github.com/notatallshaw"><code>@​notatallshaw</code></a>
in <a
href="https://redirect.github.com/pypa/packaging/pull/989">pypa/packaging#989</a>
and regression for <code>packaging_legacy</code> fixed by <a
href="https://github.com/henryiii"><code>@​henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/1048">pypa/packaging#1048</a></li>
<li>Faster <code>canonicalize_version</code> by <a
href="https://github.com/henryiii"><code>@​henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/993">pypa/packaging#993</a></li>
<li>Use <code>fullmatch</code> in a couple more places by <a
href="https://github.com/henryiii"><code>@​henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/992">pypa/packaging#992</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/pypa/packaging/blob/main/CHANGELOG.rst">packaging's
changelog</a>.</em></p>
<blockquote>
<p>26.0 - 2026-01-20</p>
<pre><code>
Features:
<ul>
<li>PEP 751: support pylock (:pull:<code>900</code>)</li>
<li>PEP 794: import name metadata (:pull:<code>948</code>)</li>
<li>Support for writing metadata to a file (:pull:<code>846</code>)</li>
<li>Support <code>__replace__</code> on Version
(:pull:<code>1003</code>)</li>
<li>Support positional pattern matching for <code>Version</code> and
<code>SpecifierSet</code> (:pull:<code>1004</code>)</li>
</ul>
<p>Behavior adaptations:</p>
<ul>
<li>PEP 440 handling of prereleases for <code>Specifier.contains</code>,
<code>SpecifierSet.contains</code>, and <code>SpecifierSet.filter</code>
(:pull:<code>897</code>)</li>
<li>Handle PEP 440 edge case in <code>SpecifierSet.filter</code>
(:pull:<code>942</code>)</li>
<li>Adjust arbitrary equality intersection preservation in
<code>SpecifierSet</code> (:pull:<code>951</code>)</li>
<li>Return <code>False</code> instead of raising for
<code>.contains</code> with invalid version
(:pull:<code>932</code>)</li>
<li>Support arbitrary equality on arbitrary strings for
<code>Specifier</code> and <code>SpecifierSet</code>'s
<code>filter</code> and <code>contains</code> method.
(:pull:<code>954</code>)</li>
<li>Only try to parse as <code>Version</code> on certain marker keys,
return <code>False</code> on unequal ordered comparisons
(:pull:<code>939</code>)</li>
</ul>
<p>Fixes:</p>
<ul>
<li>Update <code>_hash</code> when unpickling <code>Tag()</code>
(:pull:<code>860</code>)</li>
<li>Correct comment and simplify implicit prerelease handling in
<code>Specifier.prereleases</code> (:pull:<code>896</code>)</li>
<li>Use explicit <code>_GLibCVersion</code> <code>NamedTuple</code> in
<code>_manylinux</code> (:pull:<code>868</code>)</li>
<li>Detect invalid license expressions containing <code>()</code>
(:pull:<code>879</code>)</li>
<li>Correct regex for metadata <code>'name'</code> format
(:pull:<code>925</code>)</li>
<li>Improve the message around expecting a semicolon
(:pull:<code>833</code>)</li>
<li>Support nested parens in license expressions
(:pull:<code>931</code>)</li>
<li>Add space before at symbol in <code>Requirements</code> string
(:pull:<code>953</code>)</li>
<li>A root logger use found, use a <code>packaging</code> logger instead
(:pull:<code>965</code>)</li>
<li>Better support for subclassing <code>Marker</code> and
<code>Requirement</code> (:pull:<code>1022</code>)</li>
<li>Normalize all extras, not just if it comes first
(:pull:<code>1024</code>)</li>
<li>Don't produce a broken repr if <code>Marker</code> fails to
construct (:pull:<code>1033</code>)</li>
</ul>
<p>Performance:</p>
<ul>
<li>Avoid recompiling regexes in the tokenizer for a 3x speedup
(:pull:<code>1019</code>)</li>
<li>Improve performance in <code>_manylinux.py</code>
(:pull:<code>869</code>)</li>
<li>Minor cleanups to <code>Version</code> (:pull:<code>913</code>)</li>
<li>Skip redundant creation of <code>Version</code>'s in specifier
comparison (:pull:<code>986</code>)</li>
<li>Cache the <code>Specifier</code>'s <code>Version</code>
(:pull:<code>985</code>)</li>
<li>Make <code>Version</code> a little faster
(:pull:<code>987</code>)</li>
<li>Minor <code>Version</code> regex cleanup
(:pull:<code>990</code>)</li>
<li>Faster regex on Python 3.11.5+ for <code>Version</code>
(:pull:<code>988</code>, :pull:<code>1055</code>)</li>
<li>Lazily calculate <code>_key</code> in <code>Version</code>
(:pull:<code>989</code>, :pull:<code>1048</code>)</li>
<li>Faster <code>canonicalize_version</code>
(:pull:<code>993</code>)</li>
<li>Use <code>re.fullmatch</code> in a couple more places
(:pull:<code>992</code>, :pull:<code>1029</code>)</li>
<li>Use <code>map</code> instead of generator
(:pull:<code>996</code>)</li>
<li>Deprecate <code>._version</code> (<code>_Version</code>, a
<code>NamedTuple</code>) (:pull:<code>995</code>,
:pull:<code>1062</code>)<br />
&lt;/tr&gt;&lt;/table&gt;<br />
</code></pre></li>
</ul>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="3b77a26f5a"><code>3b77a26</code></a>
Bump for release</li>
<li><a
href="31371cce59"><code>31371cc</code></a>
docs: prepare for 26.0 final (<a
href="https://redirect.github.com/pypa/packaging/issues/1063">#1063</a>)</li>
<li><a
href="9627a8821f"><code>9627a88</code></a>
perf: dual replace (<a
href="https://redirect.github.com/pypa/packaging/issues/1064">#1064</a>)</li>
<li><a
href="d5398b8bc1"><code>d5398b8</code></a>
fix: restore ._version as a compat shim (<a
href="https://redirect.github.com/pypa/packaging/issues/1062">#1062</a>)</li>
<li><a
href="3a7b600a12"><code>3a7b600</code></a>
Bump for development</li>
<li><a
href="d4eefdccf9"><code>d4eefdc</code></a>
Bump for release</li>
<li><a
href="46189124fb"><code>4618912</code></a>
docs: prepare for 26.0rc3 (<a
href="https://redirect.github.com/pypa/packaging/issues/1060">#1060</a>)</li>
<li><a
href="0cf1b41b4b"><code>0cf1b41</code></a>
ci: test on first public release of CPythons (<a
href="https://redirect.github.com/pypa/packaging/issues/1056">#1056</a>)</li>
<li><a
href="716beb1c0a"><code>716beb1</code></a>
perf: 10% faster stripping zeros (<a
href="https://redirect.github.com/pypa/packaging/issues/1058">#1058</a>)</li>
<li><a
href="350a230670"><code>350a230</code></a>
fix: support CPython 3.11.0-3.11.4 and older PyPy3.11 (<a
href="https://redirect.github.com/pypa/packaging/issues/1055">#1055</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/pypa/packaging/compare/25.0...26.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `uuid-utils` from 0.12.0 to 0.14.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/aminalaee/uuid-utils/releases">uuid-utils's
releases</a>.</em></p>
<blockquote>
<h2>0.14.0</h2>
<h3>Added</h3>
<ul>
<li>Call reseed RNG in fork process in <a
href="https://redirect.github.com/aminalaee/uuid-utils/pull/108">aminalaee/uuid-utils#108</a></li>
<li>Change <code>getnode</code> to be compatible with stdlib <a
href="https://redirect.github.com/aminalaee/uuid-utils/pull/113">aminalaee/uuid-utils#113</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/aminalaee/uuid-utils/compare/0.13.0...0.14.0">https://github.com/aminalaee/uuid-utils/compare/0.13.0...0.14.0</a></p>
<h2>0.13.0</h2>
<h3>Added</h3>
<ul>
<li>add <code>NIL</code> and <code>MAX</code> UUID by <a
href="https://github.com/aminalaee"><code>@​aminalaee</code></a> in <a
href="https://redirect.github.com/aminalaee/uuid-utils/pull/107">aminalaee/uuid-utils#107</a></li>
</ul>
<h3>Fixed</h3>
<ul>
<li>remove duplicate pyo3 features by <a
href="https://github.com/chirizxc"><code>@​chirizxc</code></a> in <a
href="https://redirect.github.com/aminalaee/uuid-utils/pull/96">aminalaee/uuid-utils#96</a></li>
<li>bump <code>uuid</code> by <a
href="https://github.com/chirizxc"><code>@​chirizxc</code></a> in <a
href="https://redirect.github.com/aminalaee/uuid-utils/pull/98">aminalaee/uuid-utils#98</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/aminalaee/uuid-utils/compare/0.12.0...0.13.0">https://github.com/aminalaee/uuid-utils/compare/0.12.0...0.13.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="c555f9887c"><code>c555f98</code></a>
Version 0.14.0 (<a
href="https://redirect.github.com/aminalaee/uuid-utils/issues/114">#114</a>)</li>
<li><a
href="842cc6140e"><code>842cc61</code></a>
Change <code>getnode</code> to be compatible with python (<a
href="https://redirect.github.com/aminalaee/uuid-utils/issues/113">#113</a>)</li>
<li><a
href="1294ee9691"><code>1294ee9</code></a>
Use PyPI trusted publisher with uv (<a
href="https://redirect.github.com/aminalaee/uuid-utils/issues/112">#112</a>)</li>
<li><a
href="5fd983919b"><code>5fd9839</code></a>
Call reseed in fork process (<a
href="https://redirect.github.com/aminalaee/uuid-utils/issues/108">#108</a>)</li>
<li><a
href="51ed31d6b4"><code>51ed31d</code></a>
chore: cleanup (<a
href="https://redirect.github.com/aminalaee/uuid-utils/issues/111">#111</a>)</li>
<li><a
href="3072e53b6f"><code>3072e53</code></a>
chore: docs and benchmarks</li>
<li><a
href="152f8c617b"><code>152f8c6</code></a>
add third-party tests github action (<a
href="https://redirect.github.com/aminalaee/uuid-utils/issues/110">#110</a>)</li>
<li><a
href="10def287dd"><code>10def28</code></a>
Version 0.13.0 (<a
href="https://redirect.github.com/aminalaee/uuid-utils/issues/109">#109</a>)</li>
<li><a
href="ed464fabe4"><code>ed464fa</code></a>
update typehints</li>
<li><a
href="4467139f3b"><code>4467139</code></a>
update docs and classifiers</li>
<li>Additional commits viewable in <a
href="https://github.com/aminalaee/uuid-utils/compare/0.12.0...0.14.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `ruff` from 0.14.11 to 0.15.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.15.0</h2>
<h2>Release Notes</h2>
<p>Released on 2026-02-03.</p>
<p>Check out the <a href="https://astral.sh/blog/ruff-v0.15.0">blog
post</a> for a migration guide and overview of the changes!</p>
<h3>Breaking changes</h3>
<ul>
<li>
<p>Ruff now formats your code according to the 2026 style guide. See the
formatter section below or in the blog post for a detailed list of
changes.</p>
</li>
<li>
<p>The linter now supports block suppression comments. For example, to
suppress <code>N803</code> for all parameters in this function:</p>
<pre lang="python"><code># ruff: disable[N803]
def foo(
    legacyArg1,
    legacyArg2,
    legacyArg3,
    legacyArg4,
): ...
# ruff: enable[N803]
</code></pre>
<p>See the <a
href="https://docs.astral.sh/ruff/linter/#block-level">documentation</a>
for more details.</p>
</li>
<li>
<p>The <code>ruff:alpine</code> Docker image is now based on Alpine 3.23
(up from 3.21).</p>
</li>
<li>
<p>The <code>ruff:debian</code> and <code>ruff:debian-slim</code> Docker
images are now based on Debian 13 &quot;Trixie&quot; instead of Debian
12 &quot;Bookworm.&quot;</p>
</li>
<li>
<p>Binaries for the <code>ppc64</code> (64-bit big-endian PowerPC)
architecture are no longer included in our releases. It should still be
possible to build Ruff manually for this platform, if needed.</p>
</li>
<li>
<p>Ruff now resolves all <code>extend</code>ed configuration files
before falling back on a default Python version.</p>
</li>
</ul>
<h3>Stabilization</h3>
<p>The following rules have been stabilized and are no longer in
preview:</p>
<ul>
<li><a
href="https://docs.astral.sh/ruff/rules/blocking-http-call-httpx-in-async-function"><code>blocking-http-call-httpx-in-async-function</code></a>
(<code>ASYNC212</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/blocking-path-method-in-async-function"><code>blocking-path-method-in-async-function</code></a>
(<code>ASYNC240</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/blocking-input-in-async-function"><code>blocking-input-in-async-function</code></a>
(<code>ASYNC250</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/map-without-explicit-strict"><code>map-without-explicit-strict</code></a>
(<code>B912</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/if-exp-instead-of-or-operator"><code>if-exp-instead-of-or-operator</code></a>
(<code>FURB110</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/single-item-membership-test"><code>single-item-membership-test</code></a>
(<code>FURB171</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/missing-maxsplit-arg"><code>missing-maxsplit-arg</code></a>
(<code>PLC0207</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/unnecessary-lambda"><code>unnecessary-lambda</code></a>
(<code>PLW0108</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/unnecessary-empty-iterable-within-deque-call"><code>unnecessary-empty-iterable-within-deque-call</code></a>
(<code>RUF037</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/in-empty-collection"><code>in-empty-collection</code></a>
(<code>RUF060</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/legacy-form-pytest-raises"><code>legacy-form-pytest-raises</code></a>
(<code>RUF061</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/non-octal-permissions"><code>non-octal-permissions</code></a>
(<code>RUF064</code>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.15.0</h2>
<p>Released on 2026-02-03.</p>
<p>Check out the <a href="https://astral.sh/blog/ruff-v0.15.0">blog
post</a> for a migration
guide and overview of the changes!</p>
<h3>Breaking changes</h3>
<ul>
<li>
<p>Ruff now formats your code according to the 2026 style guide. See the
formatter section below or in the blog post for a detailed list of
changes.</p>
</li>
<li>
<p>The linter now supports block suppression comments. For example, to
suppress <code>N803</code> for all parameters in this function:</p>
<pre lang="python"><code># ruff: disable[N803]
def foo(
    legacyArg1,
    legacyArg2,
    legacyArg3,
    legacyArg4,
): ...
# ruff: enable[N803]
</code></pre>
<p>See the <a
href="https://docs.astral.sh/ruff/linter/#block-level">documentation</a>
for more details.</p>
</li>
<li>
<p>The <code>ruff:alpine</code> Docker image is now based on Alpine 3.23
(up from 3.21).</p>
</li>
<li>
<p>The <code>ruff:debian</code> and <code>ruff:debian-slim</code> Docker
images are now based on Debian 13 &quot;Trixie&quot; instead of Debian
12 &quot;Bookworm.&quot;</p>
</li>
<li>
<p>Binaries for the <code>ppc64</code> (64-bit big-endian PowerPC)
architecture are no longer included in our releases. It should still be
possible to build Ruff manually for this platform, if needed.</p>
</li>
<li>
<p>Ruff now resolves all <code>extend</code>ed configuration files
before falling back on a default Python version.</p>
</li>
</ul>
<h3>Stabilization</h3>
<p>The following rules have been stabilized and are no longer in
preview:</p>
<ul>
<li><a
href="https://docs.astral.sh/ruff/rules/blocking-http-call-httpx-in-async-function"><code>blocking-http-call-httpx-in-async-function</code></a>
(<code>ASYNC212</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/blocking-path-method-in-async-function"><code>blocking-path-method-in-async-function</code></a>
(<code>ASYNC240</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/blocking-input-in-async-function"><code>blocking-input-in-async-function</code></a>
(<code>ASYNC250</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/map-without-explicit-strict"><code>map-without-explicit-strict</code></a>
(<code>B912</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/if-exp-instead-of-or-operator"><code>if-exp-instead-of-or-operator</code></a>
(<code>FURB110</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/single-item-membership-test"><code>single-item-membership-test</code></a>
(<code>FURB171</code>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="ce5f7b6127"><code>ce5f7b6</code></a>
Bump 0.15.0 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/23055">#23055</a>)</li>
<li><a
href="b4e40f539c"><code>b4e40f5</code></a>
[ty] Fix <code>__contains__</code> to respect descriptors (<a
href="https://redirect.github.com/astral-sh/ruff/issues/23056">#23056</a>)</li>
<li><a
href="848cb72dc1"><code>848cb72</code></a>
[ty] Fix narrowing of nonlocal variables with conditional assignments
(<a
href="https://redirect.github.com/astral-sh/ruff/issues/22966">#22966</a>)</li>
<li><a
href="da7f33af22"><code>da7f33a</code></a>
[ty] Add a diagnostic for <code>Final</code> without assignment (<a
href="https://redirect.github.com/astral-sh/ruff/issues/23001">#23001</a>)</li>
<li><a
href="e65f9a6b03"><code>e65f9a6</code></a>
Document markdown formatting feature (<a
href="https://redirect.github.com/astral-sh/ruff/issues/22990">#22990</a>)</li>
<li><a
href="c0c1b985c9"><code>c0c1b98</code></a>
Format markdown code blocks with line-by-line regex parse (<a
href="https://redirect.github.com/astral-sh/ruff/issues/22996">#22996</a>)</li>
<li><a
href="9f8f3e196b"><code>9f8f3e1</code></a>
Allow positional-only params with defaults in method overrides (<a
href="https://redirect.github.com/astral-sh/ruff/issues/23037">#23037</a>)</li>
<li><a
href="ef83810e11"><code>ef83810</code></a>
[ty] ecosystem-analyzer: Support bare git repositories (<a
href="https://redirect.github.com/astral-sh/ruff/issues/23054">#23054</a>)</li>
<li><a
href="54dfee4cb8"><code>54dfee4</code></a>
Customize where the <code>fix_title</code> sub-diagnostic appears (<a
href="https://redirect.github.com/astral-sh/ruff/issues/23044">#23044</a>)</li>
<li><a
href="b53460799b"><code>b534607</code></a>
2026 Ruff Formatter Style (<a
href="https://redirect.github.com/astral-sh/ruff/issues/22735">#22735</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.14.11...0.15.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `types-requests` from 2.31.0.6 to 2.32.4.20260107
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/typeshed-internal/stub_uploader/commits">compare
view</a></li>
</ul>
</details>
<br />

Updates `setuptools` from 78.1.1 to 82.0.0
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/pypa/setuptools/blob/main/NEWS.rst">setuptools's
changelog</a>.</em></p>
<blockquote>
<h1>v82.0.0</h1>
<h2>Deprecations and Removals</h2>
<ul>
<li><code>pkg_resources</code> has been removed from Setuptools. Most
common uses of <code>pkg_resources</code> have been superseded by the
<code>importlib.resources
&lt;https://docs.python.org/3/library/importlib.resources.html&gt;</code>_
and <code>importlib.metadata
&lt;https://docs.python.org/3/library/importlib.metadata.html&gt;</code>_
projects. Projects and environments relying on
<code>pkg_resources</code> for namespace packages or other behavior
should depend on older versions of <code>setuptools</code>. (<a
href="https://redirect.github.com/pypa/setuptools/issues/3085">#3085</a>)</li>
</ul>
<h1>v81.0.0</h1>
<h2>Deprecations and Removals</h2>
<ul>
<li>Removed support for the --dry-run parameter to setup.py. This one
feature by its nature threads through lots of core and ancillary
functionality, adding complexity and friction. Removal of this parameter
will help decouple the compiler functionality from distutils and thus
the eventual full integration of distutils. These changes do affect some
class and function signatures, so any derivative functionality may
require some compatibility shims to support their expected interface.
Please report any issues to the Setuptools project for investigation.
(<a
href="https://redirect.github.com/pypa/setuptools/issues/4872">#4872</a>)</li>
</ul>
<h1>v80.10.2</h1>
<h2>Bugfixes</h2>
<ul>
<li>Update vendored dependencies. (<a
href="https://redirect.github.com/pypa/setuptools/issues/5159">#5159</a>)</li>
</ul>
<h2>Misc</h2>
<ul>
<li><a
href="https://redirect.github.com/pypa/setuptools/issues/5115">#5115</a>,
<a
href="https://redirect.github.com/pypa/setuptools/issues/5128">#5128</a></li>
</ul>
<h1>v80.10.1</h1>
<h2>Misc</h2>
<ul>
<li><a
href="https://redirect.github.com/pypa/setuptools/issues/5152">#5152</a></li>
</ul>
<h1>v80.10.0</h1>
<h2>Features</h2>
<ul>
<li>Remove post-release tags on setuptools' own build. (<a
href="https://redirect.github.com/pypa/setuptools/issues/4530">#4530</a>)</li>
<li>Refreshed vendored dependencies. (<a
href="https://redirect.github.com/pypa/setuptools/issues/5139">#5139</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="03f3615362"><code>03f3615</code></a>
Bump version: 81.0.0 → 82.0.0</li>
<li><a
href="530d11498a"><code>530d114</code></a>
Merge pull request <a
href="https://redirect.github.com/pypa/setuptools/issues/5007">#5007</a>
from pypa/feature/remove-more-pkg_resources</li>
<li><a
href="11efe9f552"><code>11efe9f</code></a>
Merge branch 'maint/75.3'</li>
<li><a
href="118f129dd0"><code>118f129</code></a>
Bump version: 75.3.3 → 75.3.4</li>
<li><a
href="90561ffde1"><code>90561ff</code></a>
Merge pull request <a
href="https://redirect.github.com/pypa/setuptools/issues/5150">#5150</a>
from UladzimirTrehubenka/backport_cve_47273</li>
<li><a
href="4595034db8"><code>4595034</code></a>
Add news fragment.</li>
<li><a
href="fc008006fc"><code>fc00800</code></a>
Merge pull request <a
href="https://redirect.github.com/pypa/setuptools/issues/5171">#5171</a>
from cclauss/ruff-v0.15.0</li>
<li><a
href="127e561362"><code>127e561</code></a>
Remove tests reliant on pkg_resources, rather than xfailing them.</li>
<li><a
href="64bc21e10b"><code>64bc21e</code></a>
Reference the superseding libraries.</li>
<li><a
href="cf1ff459ea"><code>cf1ff45</code></a>
Merge branch 'main' into debt/pbr-without-pkg_resources</li>
<li>Additional commits viewable in <a
href="https://github.com/pypa/setuptools/compare/v78.1.1...v82.0.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `pytest` from 8.4.2 to 9.0.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/pytest-dev/pytest/releases">pytest's
releases</a>.</em></p>
<blockquote>
<h2>9.0.2</h2>
<h1>pytest 9.0.2 (2025-12-06)</h1>
<h2>Bug fixes</h2>
<ul>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13896">#13896</a>:
The terminal progress feature added in pytest 9.0.0 has been disabled by
default, except on Windows, due to compatibility issues with some
terminal emulators.</p>
<p>You may enable it again by passing <code>-p terminalprogress</code>.
We may enable it by default again once compatibility improves in the
future.</p>
<p>Additionally, when the environment variable <code>TERM</code> is
<code>dumb</code>, the escape codes are no longer emitted, even if the
plugin is enabled.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13904">#13904</a>:
Fixed the TOML type of the <code>tmp_path_retention_count</code>
settings in the API reference from number to string.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13946">#13946</a>:
The private <code>config.inicfg</code> attribute was changed in a
breaking manner in pytest 9.0.0.
Due to its usage in the ecosystem, it is now restored to working order
using a compatibility shim.
It will be deprecated in pytest 9.1 and removed in pytest 10.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13965">#13965</a>:
Fixed quadratic-time behavior when handling <code>unittest</code>
subtests in Python 3.10.</p>
</li>
</ul>
<h2>Improved documentation</h2>
<ul>
<li><a
href="https://redirect.github.com/pytest-dev/pytest/issues/4492">#4492</a>:
The API Reference now contains cross-reference-able documentation of
<code>pytest's command-line flags
&lt;command-line-flags&gt;</code>.</li>
</ul>
<h2>9.0.1</h2>
<h1>pytest 9.0.1 (2025-11-12)</h1>
<h2>Bug fixes</h2>
<ul>
<li><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13895">#13895</a>:
Restore support for skipping tests via <code>raise
unittest.SkipTest</code>.</li>
<li><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13896">#13896</a>:
The terminal progress plugin added in pytest 9.0 is now automatically
disabled when iTerm2 is detected, it generated desktop notifications
instead of the desired functionality.</li>
<li><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13904">#13904</a>:
Fixed the TOML type of the verbosity settings in the API reference from
number to string.</li>
<li><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13910">#13910</a>:
Fixed <!-- raw HTML omitted -->UserWarning: Do not expect
file_or_dir<!-- raw HTML omitted --> on some earlier Python 3.12 and
3.13 point versions.</li>
</ul>
<h2>Packaging updates and notes for downstreams</h2>
<ul>
<li><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13933">#13933</a>:
The tox configuration has been adjusted to make sure the desired
version string can be passed into its <code>package_env</code> through
the <code>SETUPTOOLS_SCM_PRETEND_VERSION_FOR_PYTEST</code> environment
variable as a part of the release process -- by
<code>webknjaz</code>.</li>
</ul>
<h2>Contributor-facing changes</h2>
<ul>
<li><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13891">#13891</a>,
<a
href="https://redirect.github.com/pytest-dev/pytest/issues/13942">#13942</a>:
The CI/CD part of the release automation is now capable of
creating GitHub Releases without having a Git checkout on
disk -- by <code>bluetech</code> and <code>webknjaz</code>.</li>
<li><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13933">#13933</a>:
The tox configuration has been adjusted to make sure the desired
version string can be passed into its <code>package_env</code> through
the <code>SETUPTOOLS_SCM_PRETEND_VERSION_FOR_PYTEST</code> environment
variable as a part of the release process -- by
<code>webknjaz</code>.</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="3d10b5148e"><code>3d10b51</code></a>
Prepare release version 9.0.2</li>
<li><a
href="188750b725"><code>188750b</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14030">#14030</a>
from pytest-dev/patchback/backports/9.0.x/1e4b01d1f...</li>
<li><a
href="b7d7bef90c"><code>b7d7bef</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14014">#14014</a>
from bluetech/compat-note</li>
<li><a
href="bd08e85ac7"><code>bd08e85</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14013">#14013</a>
from pytest-dev/patchback/backports/9.0.x/922b60377...</li>
<li><a
href="bc78386299"><code>bc78386</code></a>
Add CLI options reference documentation (<a
href="https://redirect.github.com/pytest-dev/pytest/issues/13930">#13930</a>)</li>
<li><a
href="5a4e398ce8"><code>5a4e398</code></a>
Fix docs typo (<a
href="https://redirect.github.com/pytest-dev/pytest/issues/14005">#14005</a>)
(<a
href="https://redirect.github.com/pytest-dev/pytest/issues/14008">#14008</a>)</li>
<li><a
href="d7ae6df394"><code>d7ae6df</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14006">#14006</a>
from pytest-dev/maintenance/update-plugin-list-tmpl...</li>
<li><a
href="556f6a22e1"><code>556f6a2</code></a>
pre-commit: fix rst-lint after new release (<a
href="https://redirect.github.com/pytest-dev/pytest/issues/13999">#13999</a>)
(<a
href="https://redirect.github.com/pytest-dev/pytest/issues/14001">#14001</a>)</li>
<li><a
href="c60fbe63a2"><code>c60fbe6</code></a>
Fix quadratic-time behavior when handling <code>unittest</code> subtests
in Python 3.10 ...</li>
<li><a
href="73d9b01118"><code>73d9b01</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/13995">#13995</a>
from nicoddemus/patchback/backports/9.0.x/1b5200c0f...</li>
<li>Additional commits viewable in <a
href="https://github.com/pytest-dev/pytest/compare/8.4.2...9.0.2">compare
view</a></li>
</ul>
</details>
<br />

Updates `syrupy` from 4.9.1 to 5.1.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/syrupy-project/syrupy/releases">syrupy's
releases</a>.</em></p>
<blockquote>
<h2>v5.1.0</h2>
<h1><a
href="https://github.com/syrupy-project/syrupy/compare/v5.0.0...v5.1.0">5.1.0</a>
(2026-01-25)</h1>
<h3>Features</h3>
<ul>
<li>add serializer plugin system; plugins for data models (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1062">#1062</a>)
(<a
href="df9bc8f6b3">df9bc8f</a>)</li>
</ul>
<h2>v5.0.0</h2>
<h2>Syrupy 5.0.0</h2>
<p><em>(2025-09-28)</em></p>
<p>This release introduces new features, bug fixes, and a major license
change. It also includes several <strong>breaking changes</strong>, so
please review those carefully before upgrading.</p>
<hr />
<h3>New Features </h3>
<ul>
<li><strong>Add <code>--snapshot-dirname</code> option:</strong> A new
option, <code>--snapshot-dirname</code>, is now available to change the
default directory snapshots are stored in. ([<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/810">#81...

_Description has been truncated_

---------

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: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 23:49:11 -08:00
ccurme
0040e1a8aa fix(langchain): fix token counting on partial message sequences (#35101) 2026-02-09 15:27:17 -05:00
Mason Daugherty
ce5f73e07c refactor(langchain): rename _SUPPORTED_PROVIDERS -> _BUILTIN_PROVIDERS (#35100) 2026-02-09 15:26:01 -05:00
Sydney Runkle
8767a462ca feat: support state updates from wrap_model_call with command(s) (#35033)
Alternative to https://github.com/langchain-ai/langchain/pull/35024.
Paving the way for summarization in `wrap_model_call` (which requires
state updates).

---

Add `ExtendedModelResponse` dataclass that allows `wrap_model_call`
middleware to return a `Command` alongside the model response for
additional state updates.

```py
@dataclass
class ExtendedModelResponse(Generic[ResponseT]):
    model_response: ModelResponse[ResponseT]
    command: Command
```

## Motivation

Previously, `wrap_model_call` middleware could only return a
`ModelResponse` or `AIMessage` — there was no way to inject additional
state updates (e.g. custom state fields) from the model call middleware
layer. `ExtendedModelResponse` fills this gap by accepting an optional
`Command`.

This feature is needed by the summarization middleware, which needs to
track summarization trigger points calculated during `wrap_model_call`.

## Why `Command` instead of a plain `state_update` dict?

We chose `Command` rather than the raw `state_update: dict` approach
from the earlier iteration because `Command` is the established
LangGraph primitive for state updates from nodes. Using `Command` means:

- State updates flow through the graph's reducers (e.g. `add_messages`)
rather than being merged as raw dicts. This makes messages updates
additive alongside the model response instead of replacing them.
- Consistency with `wrap_tool_call`, which already returns `Command`.
- Future-proof: as `Command` gains new capabilities (e.g. `goto`,
`send`), middleware can leverage them without API changes.

## Why keep `model_response` separate instead of using `Command`
directly?

The model node needs to distinguish the model's actual response
(messages + structured output) from supplementary middleware state
updates. If middleware returned only a `Command`, there would be no
clean way to extract the `ModelResponse` for structured output handling,
response validation, and the core model-to-tools routing logic. Keeping
`model_response` explicit preserves a clear boundary between "what the
model said" and "what middleware wants to update."

Also, in order to avoid breaking, the `handler` passed to
`wrap_tool_call` needs to always return a `ModelResponse`. There's no
easy way to preserve this if we pump it into a `Command`.

One nice thing about having this `ExtendedModelResponse` structure is
that it's extensible if we want to add more metadata in the future.

## Composition

When multiple middleware layers return `ExtendedModelResponse`, their
commands compose naturally:

- **Inner commands propagate outward:** At composition boundaries,
`ExtendedModelResponse` is unwrapped to its underlying `ModelResponse`
so outer middleware always sees a plain `ModelResponse` from
`handler()`. The inner command is captured and accumulated.
- **Commands are applied through reducers:** Each `Command` becomes a
separate state update applied through the graph's reducers. For
messages, this means they're additive (via `add_messages`), not
replacing.
- **Outer wins on conflicts:** For non-reducer state fields, commands
are applied inner-first then outer, so the outermost middleware's value
takes precedence on conflicting keys.
- **Retry-safe:** When outer middleware retries by calling `handler()`
again, accumulated inner commands are cleared and re-collected from the
fresh call.

```python
class Outer(AgentMiddleware):
    def wrap_model_call(self, request, handler):
        response = handler(request)  # sees ModelResponse, not ExtendedModelResponse
        return ExtendedModelResponse(
            model_response=response,
            command=Command(update={"outer_key": "val"}),
        )

class Inner(AgentMiddleware):
    def wrap_model_call(self, request, handler):
        response = handler(request)
        return ExtendedModelResponse(
            model_response=response,
            command=Command(update={"inner_key": "val"}),
        )

# Final state merges both commands: {"inner_key": "val", "outer_key": "val"}
```

## Backwards compatibility

Fully backwards compatible. The `ModelCallResult` type alias is widened
from `ModelResponse | AIMessage` to `ModelResponse | AIMessage |
ExtendedModelResponse`, but existing middleware returning
`ModelResponse` or `AIMessage` continues to work identically.

## Internals

- `model_node` / `amodel_node` now return `list[Command]` instead of
`dict[str, Any]`
- `_build_commands` converts the model response + accumulated middleware
commands into a list of `Command` objects for LangGraph
- `_ComposedExtendedModelResponse` is the internal type that accumulates
commands across layers during composition
2026-02-06 07:28:04 -05:00