Skip to content

Commit 26e3fa2

Browse files
authored
Merge branch 'master' into python-3.14
2 parents 60b13f8 + 9dd494d commit 26e3fa2

47 files changed

Lines changed: 5589 additions & 758 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

MIGRATE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
Please see the following guides for migrating LangChain code:
44

5+
* Migrate to [LangChain v1.0](https://docs.langchain.com/oss/python/migrate/langchain-v1)
56
* Migrate to [LangChain v0.3](https://python.langchain.com/docs/versions/v0_3/)
67
* Migrate to [LangChain v0.2](https://python.langchain.com/docs/versions/v0_2/)
78
* Migrating from [LangChain 0.0.x Chains](https://python.langchain.com/docs/versions/migrating_chains/)

libs/core/langchain_core/language_models/chat_models.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1517,7 +1517,7 @@ def with_structured_output(
15171517
include_raw:
15181518
If `False` then only the parsed structured output is returned. If
15191519
an error occurs during model output parsing it will be raised. If `True`
1520-
then both the raw model response (a BaseMessage) and the parsed model
1520+
then both the raw model response (a `BaseMessage`) and the parsed model
15211521
response will be returned. If an error occurs during output parsing it
15221522
will be caught and returned as well. The final output is always a dict
15231523
with keys `'raw'`, `'parsed'`, and `'parsing_error'`.
@@ -1530,16 +1530,17 @@ def with_structured_output(
15301530
Returns:
15311531
A Runnable that takes same inputs as a `langchain_core.language_models.chat.BaseChatModel`.
15321532
1533-
If `include_raw` is False and `schema` is a Pydantic class, Runnable outputs
1534-
an instance of `schema` (i.e., a Pydantic object).
1533+
If `include_raw` is False and `schema` is a Pydantic class, Runnable outputs
1534+
an instance of `schema` (i.e., a Pydantic object).
15351535
1536-
Otherwise, if `include_raw` is False then Runnable outputs a dict.
1536+
Otherwise, if `include_raw` is False then Runnable outputs a dict.
15371537
1538-
If `include_raw` is True, then Runnable outputs a dict with keys:
1538+
If `include_raw` is True, then Runnable outputs a dict with keys:
15391539
1540-
- `'raw'`: BaseMessage
1541-
- `'parsed'`: None if there was a parsing error, otherwise the type depends on the `schema` as described above.
1542-
- `'parsing_error'`: BaseException | None
1540+
- `'raw'`: BaseMessage
1541+
- `'parsed'`: None if there was a parsing error, otherwise the type
1542+
depends on the `schema` as described above.
1543+
- `'parsing_error'`: BaseException | None
15431544
15441545
Example: Pydantic schema (include_raw=False):
15451546
```python
@@ -1620,7 +1621,7 @@ class AnswerWithJustification(BaseModel):
16201621
```
16211622
16221623
!!! warning "Behavior changed in 0.2.26"
1623-
Added support for TypedDict class.
1624+
Added support for TypedDict class.
16241625
16251626
""" # noqa: E501
16261627
_ = kwargs.pop("method", None)

libs/core/langchain_core/runnables/base.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -860,7 +860,7 @@ def batch(
860860
861861
The default implementation of batch works well for IO bound runnables.
862862
863-
Subclasses should override this method if they can batch more efficiently;
863+
Subclasses must override this method if they can batch more efficiently;
864864
e.g., if the underlying `Runnable` uses an API which supports a batch mode.
865865
866866
Args:
@@ -992,7 +992,7 @@ async def abatch(
992992
993993
The default implementation of `batch` works well for IO bound runnables.
994994
995-
Subclasses should override this method if they can batch more efficiently;
995+
Subclasses must override this method if they can batch more efficiently;
996996
e.g., if the underlying `Runnable` uses an API which supports a batch mode.
997997
998998
Args:
@@ -1112,7 +1112,7 @@ def stream(
11121112
) -> Iterator[Output]:
11131113
"""Default implementation of `stream`, which calls `invoke`.
11141114
1115-
Subclasses should override this method if they support streaming output.
1115+
Subclasses must override this method if they support streaming output.
11161116
11171117
Args:
11181118
input: The input to the `Runnable`.
@@ -1133,7 +1133,7 @@ async def astream(
11331133
) -> AsyncIterator[Output]:
11341134
"""Default implementation of `astream`, which calls `ainvoke`.
11351135
1136-
Subclasses should override this method if they support streaming output.
1136+
Subclasses must override this method if they support streaming output.
11371137
11381138
Args:
11391139
input: The input to the `Runnable`.
@@ -1497,7 +1497,7 @@ def transform(
14971497
14981498
Default implementation of transform, which buffers input and calls `astream`.
14991499
1500-
Subclasses should override this method if they can start producing output while
1500+
Subclasses must override this method if they can start producing output while
15011501
input is still being generated.
15021502
15031503
Args:
@@ -1542,7 +1542,7 @@ async def atransform(
15421542
15431543
Default implementation of atransform, which buffers input and calls `astream`.
15441544
1545-
Subclasses should override this method if they can start producing output while
1545+
Subclasses must override this method if they can start producing output while
15461546
input is still being generated.
15471547
15481548
Args:

libs/core/langchain_core/runnables/config.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,26 +75,26 @@ class RunnableConfig(TypedDict, total=False):
7575
max_concurrency: int | None
7676
"""
7777
Maximum number of parallel calls to make. If not provided, defaults to
78-
ThreadPoolExecutor's default.
78+
`ThreadPoolExecutor`'s default.
7979
"""
8080

8181
recursion_limit: int
8282
"""
83-
Maximum number of times a call can recurse. If not provided, defaults to 25.
83+
Maximum number of times a call can recurse. If not provided, defaults to `25`.
8484
"""
8585

8686
configurable: dict[str, Any]
8787
"""
88-
Runtime values for attributes previously made configurable on this Runnable,
89-
or sub-Runnables, through .configurable_fields() or .configurable_alternatives().
90-
Check .output_schema() for a description of the attributes that have been made
88+
Runtime values for attributes previously made configurable on this `Runnable`,
89+
or sub-Runnables, through `configurable_fields` or `configurable_alternatives`.
90+
Check `output_schema` for a description of the attributes that have been made
9191
configurable.
9292
"""
9393

9494
run_id: uuid.UUID | None
9595
"""
9696
Unique identifier for the tracer run for this call. If not provided, a new UUID
97-
will be generated.
97+
will be generated.
9898
"""
9999

100100

libs/core/langchain_core/tools/base.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1210,6 +1210,26 @@ class InjectedToolArg:
12101210
"""
12111211

12121212

1213+
class _DirectlyInjectedToolArg:
1214+
"""Annotation for tool arguments that are injected at runtime.
1215+
1216+
Injected via direct type annotation, rather than annotated metadata.
1217+
1218+
For example, ToolRuntime is a directly injected argument.
1219+
Note the direct annotation rather than the verbose alternative:
1220+
Annotated[ToolRuntime, InjectedRuntime]
1221+
```python
1222+
from langchain_core.tools import tool, ToolRuntime
1223+
1224+
1225+
@tool
1226+
def foo(x: int, runtime: ToolRuntime) -> str:
1227+
# use runtime.state, runtime.context, runtime.store, etc.
1228+
...
1229+
```
1230+
"""
1231+
1232+
12131233
class InjectedToolCallId(InjectedToolArg):
12141234
"""Annotation for injecting the tool call ID.
12151235
@@ -1237,6 +1257,24 @@ def foo(
12371257
"""
12381258

12391259

1260+
def _is_directly_injected_arg_type(type_: Any) -> bool:
1261+
"""Check if a type annotation indicates a directly injected argument.
1262+
1263+
This is currently only used for ToolRuntime.
1264+
Checks if either the annotation itself is a subclass of _DirectlyInjectedToolArg
1265+
or the origin of the annotation is a subclass of _DirectlyInjectedToolArg.
1266+
1267+
Ex: ToolRuntime or ToolRuntime[ContextT, StateT] would both return True.
1268+
"""
1269+
return (
1270+
isinstance(type_, type) and issubclass(type_, _DirectlyInjectedToolArg)
1271+
) or (
1272+
(origin := get_origin(type_)) is not None
1273+
and isinstance(origin, type)
1274+
and issubclass(origin, _DirectlyInjectedToolArg)
1275+
)
1276+
1277+
12401278
def _is_injected_arg_type(
12411279
type_: type | TypeVar, injected_type: type[InjectedToolArg] | None = None
12421280
) -> bool:
@@ -1249,7 +1287,15 @@ def _is_injected_arg_type(
12491287
Returns:
12501288
`True` if the type is an injected argument, `False` otherwise.
12511289
"""
1252-
injected_type = injected_type or InjectedToolArg
1290+
if injected_type is None:
1291+
# if no injected type is specified,
1292+
# check if the type is a directly injected argument
1293+
if _is_directly_injected_arg_type(type_):
1294+
return True
1295+
injected_type = InjectedToolArg
1296+
1297+
# if the type is an Annotated type, check if annotated metadata
1298+
# is an intance or subclass of the injected type
12531299
return any(
12541300
isinstance(arg, injected_type)
12551301
or (isinstance(arg, type) and issubclass(arg, injected_type))
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""langchain-core version information and utilities."""
22

3-
VERSION = "1.0.0rc1"
3+
VERSION = "1.0.0rc3"

libs/core/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ dependencies = [
1616
"pydantic>=2.7.4,<3.0.0",
1717
]
1818
name = "langchain-core"
19-
version = "1.0.0rc1"
19+
version = "1.0.0rc3"
2020
description = "Building applications with LLMs through composability"
2121
readme = "README.md"
2222

libs/core/uv.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""Main entrypoint into LangChain."""
22

3-
__version__ = "1.0.0a14"
3+
__version__ = "1.0.0rc2"

libs/langchain_v1/langchain/agents/factory.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
ModelRequest,
3232
ModelResponse,
3333
OmitFromSchema,
34-
PublicAgentState,
34+
_InputAgentState,
35+
_OutputAgentState,
3536
)
3637
from langchain.agents.structured_output import (
3738
AutoStrategy,
@@ -527,7 +528,7 @@ def create_agent( # noqa: PLR0915
527528
name: str | None = None,
528529
cache: BaseCache | None = None,
529530
) -> CompiledStateGraph[
530-
AgentState[ResponseT], ContextT, PublicAgentState[ResponseT], PublicAgentState[ResponseT]
531+
AgentState[ResponseT], ContextT, _InputAgentState, _OutputAgentState[ResponseT]
531532
]:
532533
"""Creates an agent graph that calls tools in a loop until a stopping condition is met.
533534
@@ -780,7 +781,7 @@ def check_weather(location: str) -> str:
780781

781782
# create graph, add nodes
782783
graph: StateGraph[
783-
AgentState[ResponseT], ContextT, PublicAgentState[ResponseT], PublicAgentState[ResponseT]
784+
AgentState[ResponseT], ContextT, _InputAgentState, _OutputAgentState[ResponseT]
784785
] = StateGraph(
785786
state_schema=resolved_state_schema,
786787
input_schema=input_schema,
@@ -1507,10 +1508,12 @@ def tools_to_model(state: dict[str, Any]) -> str | None:
15071508
last_ai_message, tool_messages = _fetch_last_ai_and_tool_messages(state["messages"])
15081509

15091510
# 1. Exit condition: All executed tools have return_direct=True
1510-
if all(
1511-
tool_node.tools_by_name[c["name"]].return_direct
1512-
for c in last_ai_message.tool_calls
1513-
if c["name"] in tool_node.tools_by_name
1511+
# Filter to only client-side tools (provider tools are not in tool_node)
1512+
client_side_tool_calls = [
1513+
c for c in last_ai_message.tool_calls if c["name"] in tool_node.tools_by_name
1514+
]
1515+
if client_side_tool_calls and all(
1516+
tool_node.tools_by_name[c["name"]].return_direct for c in client_side_tool_calls
15141517
):
15151518
return end_destination
15161519

@@ -1527,7 +1530,9 @@ def tools_to_model(state: dict[str, Any]) -> str | None:
15271530

15281531

15291532
def _add_middleware_edge(
1530-
graph: StateGraph[AgentState, ContextT, PublicAgentState, PublicAgentState],
1533+
graph: StateGraph[
1534+
AgentState[ResponseT], ContextT, _InputAgentState, _OutputAgentState[ResponseT]
1535+
],
15311536
*,
15321537
name: str,
15331538
default_destination: str,

0 commit comments

Comments
 (0)