Commit Graph

199 Commits

Author SHA1 Message Date
Sydney Runkle
28564ef94e release: core 1.0.2 and langchain 1.0.3 (#33736) 2025-10-29 15:30:17 -07:00
Christian Bromann
b62a9b57f3 fix(langchain_v1): removed unsed functions in tool_call_limit middleware (#33735)
These functions seem unused and can be removed.
2025-10-29 15:21:38 -07:00
Mason Daugherty
123e29dc26 style: more refs fixes (#33730) 2025-10-29 16:34:46 -04:00
Sydney Runkle
6a1dca113e chore: move ToolNode improvements back to langgraph (#33634)
Moving all `ToolNode` related improvements back to LangGraph and
importing them in LC!
pairing w/ https://github.com/langchain-ai/langgraph/pull/6321

this fixes a couple of things:
1. `InjectedState`, store etc will continue to work as expected no
matter where the import is from
2. `ToolRuntime` is now usable w/in langgraph, woohoo!
2025-10-29 11:44:23 -07:00
Sydney Runkle
8aea6dd23a feat: support structured output retry middleware (#33663)
* attach the latest `AIMessage` to all `StructuredOutputError`s so that
relevant middleware can use as desired
* raise `StructuredOutputError` from `ProviderStrategy` logic in case of
failed parsing (so that we can retry from middleware)
* added a test suite w/ example custom middleware that retries for tool
+ provider strategy

Long term, we could add our own opinionated structured output retry
middleware, but this at least unblocks folks who want to use custom
retry logic in the short term :)

```py
class StructuredOutputRetryMiddleware(AgentMiddleware):
    """Retries model calls when structured output parsing fails."""

    def __init__(self, max_retries: int) -> None:
        self.max_retries = max_retries

    def wrap_model_call(
        self, request: ModelRequest, handler: Callable[[ModelRequest], ModelResponse]
    ) -> ModelResponse:
        for attempt in range(self.max_retries + 1):
            try:
                return handler(request)
            except StructuredOutputError as exc:
                if attempt == self.max_retries:
                    raise

                ai_content = exc.ai_message.content
                error_message = (
                    f"Your previous response was:\n{ai_content}\n\n"
                    f"Error: {exc}. Please try again with a valid response."
                )
                request.messages.append(HumanMessage(content=error_message))
```
2025-10-29 08:41:44 -07:00
Mason Daugherty
b5e23e5823 fix(langchain_v1): correct ref url (#33715) 2025-10-28 23:29:19 -04:00
Mason Daugherty
e5e1d6c705 style: more refs work (#33707) 2025-10-28 14:43:28 -04:00
Mason Daugherty
62769a0dac feat(langchain): export UsageMetadata (#33692)
as well as `InputTokenDetails`, and `OutputTokenDetails` from
`langchain_core.messages`
2025-10-27 19:47:41 -04:00
ccurme
ef85161525 release(core): 1.0.1 (#33639) 2025-10-22 14:25:21 -04:00
Eugene Yurtsev
f8adbbc461 chore(langchain_v1): bump version from 1.0.1 to 1.0.2 (#33629)
Release 1.0.2
2025-10-21 17:05:51 -04:00
Eugene Yurtsev
17f0716d6c fix(langchain_v1): remove non llm controllable params from tool message on invocation failure (#33625)
The LLM shouldn't be seeing parameters it cannot control in the
ToolMessage error it gets when it invokes a tool with incorrect args.

This fixes the behavior within langchain to address immediate issue.

We may want to change the behavior in langchain_core as well to prevent
validation of injected arguments. But this would be done in a separate
change
2025-10-21 15:40:30 -04:00
Sydney Runkle
7d7a50d4cc release(langchain_v1): 1.0.1 (#33610) 2025-10-20 13:03:16 +00:00
Sydney Runkle
9319eecaba fix(langchain_v1): ToolRuntime default for args (#33606)
added some noqas, this is a quick patch to support a bug uncovered in
the quickstart, will resolve fully depending on where we centralize
ToolNode stuff.
2025-10-20 08:45:50 -04:00
Mason Daugherty
a47386f6dc style: more refs polishing (#33601) 2025-10-20 00:52:52 -04:00
Mason Daugherty
aaf88c157f docs(langchain): update reference documentation to note moved embeddings modules (#33600) 2025-10-19 20:10:25 -04:00
Mason Daugherty
1d056487c7 style(anthropic): use aliases for model names (#33590) 2025-10-17 21:40:22 +00:00
Mason Daugherty
64e6798a39 chore: update pyproject.toml url entries (#33587) 2025-10-17 17:16:55 -04:00
Sydney Runkle
4a65e827f7 release(langchain_v1): v1.0.0 (#33588)
waiting on langgraph bump
2025-10-17 16:49:07 -04:00
Sydney Runkle
35b89b8b10 fix: shell tool middleware (#33589)
the fact that this was broken showcases that we need significantly
better test coverage, this is literally the most minimalistic usage of
this middleware there could be 😿

will document these two gotchas better for custom middleware

```py
from langchain.agents.middleware.shell_tool import ShellToolMiddleware
from langchain.agents import create_agent

agent = create_agent(model="openai:gpt-4",middleware = [ShellToolMiddleware()])
agent.invoke({"messages":[{"role": "user", "content": "hi"}]})
```
2025-10-17 16:48:30 -04:00
Sydney Runkle
8fd54f13b5 feat(langchain_v1): Python 3.14 support (#33560)
Co-authored-by: Christophe Bornet <cbornet@hotmail.com>
2025-10-17 15:10:01 -04:00
ccurme
952fa8aa99 fix(langchain,langchain_v1): enable huggingface optional dep (#33586) 2025-10-17 18:42:53 +00:00
Sydney Runkle
9dd494ddcd fix(langchain): conditional tools -> end edge when all client side calls return direct (#33550)
mostly #33520 
also tacking on change to make sure we're only looking at client side
calls for the jump to end

---------

Co-authored-by: Nuno Campos <nuno@boringbits.io>
2025-10-17 02:35:47 +00:00
Sydney Runkle
2fa07b19f6 chore(langchain_v1): relax typing on input state (#33552)
so we don't get type errors when invoking w/ dict type (openai format)
messages

would love to have types for these eventually so we can get proper
checking

before
<img width="759" height="257" alt="Screenshot 2025-10-16 at 9 46 08 PM"
src="https://github.com/user-attachments/assets/aabe716f-6d8f-429d-ae47-31dd8617752d"
/>

after
<img width="751" height="228" alt="Screenshot 2025-10-16 at 9 51 09 PM"
src="https://github.com/user-attachments/assets/e74dcf12-874b-43ca-9d5b-5575ef8ced73"
/>
2025-10-16 22:35:28 -04:00
Nuno Campos
a022e3c14d feat(langchain_v1): Add ShellToolMiddleware and ClaudeBashToolMiddleware (#33527)
- Both middleware share the same implementation, the only difference is
one uses Claude's server-side tool definition, whereas the other one
uses a generic tool definition compatible with all models
- Implemented 3 execution policies (responsible for actually running the
shell process)
- HostExecutionPolicy runs the shell as subprocess, appropriate for
already sandboxed environments, eg when run inside a dedicated docker
container
- CodexSandboxExecutionPolicy runs the shell using the sandbox command
from the Codex CLI which implements sandboxing techniques for Linux and
Mac OS.
- DockerExecutionPolicy runs the shell inside a dedicated Docker
container for isolation.
- Implements all behaviours described in
https://docs.claude.com/en/docs/agents-and-tools/tool-use/bash-tool#handle-large-outputs
including timeouts, truncation, output redaction, etc

---------

Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
Co-authored-by: Sydney Runkle <sydneymarierunkle@gmail.com>
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
2025-10-16 22:32:11 -04:00
Eugene Yurtsev
e0e11423d9 feat(langchain): file-search middleware (#33551)
File search middleware from
https://github.com/langchain-ai/langchain/pull/33527
2025-10-16 21:52:18 -04:00
Sydney Runkle
3d288fd610 release: joint rcs for core + langchain (#33549) 2025-10-17 01:00:47 +00:00
Sydney Runkle
055cccde28 chore(langchain): allow injection of ToolRuntime and generic ToolRuntime[ContextT, StateT] (#33546)
Adds special private helper to allow direct injection of `ToolRuntime`
in tools, plus adding guards for generic annotations w/ `get_origin`.

Went w/ the private helper so that we didn't change behavior for other
injected types.
2025-10-16 20:55:19 -04:00
Eugene Yurtsev
90b68059f5 fix(langchain): revert conditional edge from tools to end (#33520) (#33539)
This is causing an issue with one of the middlewares
2025-10-16 17:19:26 -04:00
Sydney Runkle
c6b3f5b888 release(langchain): cut rc (#33534) 2025-10-16 19:55:38 +00:00
ccurme
aa78be574a release(core): 1.0.0rc2 (#33530) 2025-10-16 13:00:39 -04:00
Mason Daugherty
d0dd1b30d1 docs(langchain_v1): remove absent arg descriptions (#33529) 2025-10-16 12:25:18 -04:00
Sydney Runkle
e10d99b728 fix(langchain): conditional edge from tools to end (#33520) 2025-10-16 11:56:45 -04:00
Eugene Yurtsev
31718492c7 fix(langchain_v1): relax tool node validation to allow claude text editing tools (#33512)
Relax tool node validation to allow claude text editing tools
2025-10-16 14:56:41 +00:00
Sydney Runkle
2209878f48 chore(langchain): update state schema doc (#33524) 2025-10-16 10:40:54 -04:00
Sydney Runkle
dd77dbe3ab chore(langchain_v1): adding back state_schema to create_agent (#33519)
To make migration easier, things are more backwards compat

Very minimal footprint here

Will need to upgrade migration guide and other docs w/ this change
2025-10-16 10:12:34 -04:00
Sydney Runkle
551e86a517 chore(langchain): use runtime not tool_runtime for injected tool arg (#33522)
fast follow to https://github.com/langchain-ai/langchain/pull/33500
2025-10-16 13:53:54 +00:00
Eugene Yurtsev
8734c05f64 feat(langchain_v1): tool retry middleware (#33503)
Adds `ToolRetryMiddleware` to automatically retry failed tool calls with
configurable exponential backoff, exception filtering, and error
handling.

## Example

```python
from langchain.agents import create_agent
from langchain.agents.middleware import ToolRetryMiddleware
from langchain_openai import ChatOpenAI

# Retry up to 3 times with exponential backoff
retry = ToolRetryMiddleware(
    max_retries=3,
    initial_delay=1.0,
    backoff_factor=2.0,
)

agent = create_agent(
    model=ChatOpenAI(model="gpt-4"),
    tools=[search_tool, database_tool],
    middleware=[retry],
)

# Tool failures are automatically retried
result = agent.invoke({"messages": [{"role": "user", "content": "Search for AI news"}]})
```

For advanced usage with specific exception handling:

```python
from requests.exceptions import Timeout, HTTPError

def should_retry(exc: Exception) -> bool:
    # Only retry on 5xx errors or timeouts
    if isinstance(exc, HTTPError):
        return 500 <= exc.response.status_code < 600
    return isinstance(exc, Timeout)

retry = ToolRetryMiddleware(
    max_retries=4,
    retry_on=should_retry,
    tools=["search_database"],  # Only apply to specific tools
)
```
2025-10-16 09:47:43 -04:00
Sydney Runkle
0c8cbfb7de chore(langchain_v1): switch order of params in ToolRuntime (#33518)
To match `Runtime`
2025-10-16 12:09:05 +00:00
Sydney Runkle
89c3428d85 feat(langchain_v1): injected runtime (#33500)
Goal here is 2 fold

1. Improved devx for injecting args into tools
2. Support runtime injection for Python 3.10 async

One consequence of this PR is that `ToolNode` now expects `config`
available with `runtime`, which only happens in LangGraph execution
contexts. Hence the config patch for tests.

Are we ok reserving `tool_runtime`?

before, eek:
```py
from langchain.agents import create_agent
from langchain.tools import tool, InjectedState, InjectedStore
from langgraph.runtime import get_runtime
from typing_extensions import Annotated
from langgraph.store.base import BaseStore

@tool
def do_something(
    arg: int,
    state: Annotated[dict, InjectedState],
    store: Annotated[BaseStore, InjectedStore],
) -> None:
    """does something."""
    print(state)
    print(store)
    print(get_runtime().context)
    ...
```

after, woo!
```py
from langchain.agents import create_agent
from langchain.tools import tool, ToolRuntime

@tool
def do_something_better(
    arg: int,
    tool_runtime: ToolRuntime,
) -> None:
    """does something better."""
    print(tool_runtime.state)
    print(tool_runtime.store)
    print(tool_runtime.context)
    ...
```

```python
@dataclass
class ToolRuntime(InjectedToolArg, Generic[StateT, ContextT]):
    state: StateT
    context: ContextT
    config: RunnableConfig
    tool_call_id: str
    stream_writer: StreamWriter
    context: ContextT
    store: BaseStore | None
2025-10-16 07:41:09 -04:00
Mason Daugherty
707e96c541 style: more sweeping refs work (#33513) 2025-10-15 23:33:39 -04:00
Mason Daugherty
26e0a00c4c style: more work for refs (#33508)
Largely:
- Remove explicit `"Default is x"` since new refs show default inferred
from sig
- Inline code (useful for eventual parsing)
- Fix code block rendering (indentations)
2025-10-15 18:46:55 -04:00
Sydney Runkle
296994ebf0 release(langchain_v1): 1.0.0a15 (#33505) 2025-10-15 20:48:18 +00:00
Sydney Runkle
8f6851c349 fix(langchain_v1): keep state to relevant middlewares for tool/model call limits (#33493)
The one risk point that I can see here is that model + tool call
counting now occurs in the `after_model` hook which introduces order
dependency (what if you have HITL execute before this hook and we jump
early to `model`, for example).

This is something users can work around at the moment and we can
document. We could also introduce a priority concept to middleware.
2025-10-15 14:24:59 -04:00
ccurme
3bfd1f6d8a release(core): 1.0.0rc1 (#33497) 2025-10-15 13:02:35 -04:00
Mason Daugherty
79200cf3c2 docs: update package READMEs (#33488) 2025-10-15 10:49:35 -04:00
Eugene Yurtsev
99e0a60aab chore(langchain_v1): remove invocation request (#33482)
Remove ToolNode primitives from langchain
2025-10-14 15:07:30 -04:00
Eugene Yurtsev
d38729fbac feat(langchain_v1): add async implementations to wrap_model_call (#33467)
Add async implementations to wrap_model_call for prebuilt middleware
2025-10-14 17:39:38 +00:00
gsmini
ff0d21cfd5 fix(langchain_v1): can not import "wrap_tool_call" from agents.… (#33472)
fix can not import `wrap_tool_call` from ` langchain.agents.middleware
import `
```python

from langchain.agents import create_agent
from langchain.agents.middleware import wrap_tool_call # here !
from langchain_core.messages import ToolMessage

@wrap_tool_call
def handle_tool_errors(request, handler):
    """Handle tool execution errors with custom messages."""
    try:
        return handler(request)
    except Exception as e:
        # Return a custom error message to the model
        return ToolMessage(
            content=f"Tool error: Please check your input and try again. ({str(e)})",
            tool_call_id=request.tool_call["id"]
        )

agent = create_agent(
    model="openai:gpt-4o",
    tools=[search, calculate],
    middleware=[handle_tool_errors]
)
```
> example code from:
https://docs.langchain.com/oss/python/langchain/agents#tool-error-handling
2025-10-14 13:39:25 -04:00
Eugene Yurtsev
9140a7cb86 feat(langchain_v1): add override to model request and tool call request (#33465)
Add override to model request and tool call request
2025-10-14 10:31:46 -04:00
Mason Daugherty
9105573cb3 docs: create_agent style and clarify system_prompt (#33470) 2025-10-14 09:56:54 -04:00