Skip to content

Conversation

sydney-runkle
Copy link
Collaborator

@sydney-runkle sydney-runkle commented Sep 5, 2025

Overview

Adding new AgentMiddleware primitive that supports before_model, after_model, and prepare_model_request hooks.

This is very exciting! It makes our create_agent prebuilt much more extensible + capable. Still in alpha and subject to change.

This is different than the initial implementation in that it:

  • Fills in gaps w/ missing features, for ex -- new structured output, optionality of tools + system prompt, sync and async model requests, provider builtin tools
  • Exposes private state extensions for middleware, enabling things like model call tracking, etc
  • Middleware can register tools
  • Uses a TypedDict for AgentState -- dataclass subclassing is tricky w/ required values + required decorators
  • Addition of model_settings to ModelRequest so that we can pass through things to bind (like cache kwargs for anthropic middleware)

TODOs

top prio

  • add middleware support to existing agent
  • top prio middlewares
    • summarization node
    • HITL
    • prompt caching

other ones

  • model call limits
  • tool calling limits
  • usage (requires output state)

secondary prio

  • improve typing for state updates from middleware (not working right now w/ simple AgentUpdate and AgentJump, at least in Python)
  • add support for public state (input / output modifications via pregel channel mods) -- to be tackled in another PR
  • testing!

docs

See langchain-ai/docs#390

  • high level docs about middleware
  • summarization node
  • HITL
  • prompt caching

open questions

Lots of open questions right now, many of them inlined as comments for the short term, will catalog some more significant ones here.

Copy link

vercel bot commented Sep 5, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
langchain Ready Ready Preview Comment Sep 8, 2025 1:18am

Copy link

codspeed-hq bot commented Sep 5, 2025

CodSpeed WallTime Performance Report

Merging #32828 will not alter performance

Comparing sr/new-agent (a6a4b0d) with master (bc91a48)

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

Summary

✅ 13 untouched benchmarks

Copy link

codspeed-hq bot commented Sep 5, 2025

CodSpeed Instrumentation Performance Report

Merging #32828 will not alter performance

Comparing sr/new-agent (522f99d) with master (bc91a48)

Summary

✅ 14 untouched benchmarks

@sydney-runkle sydney-runkle marked this pull request as draft September 5, 2025 14:17
@sydney-runkle sydney-runkle added the codspeed-ignore ⚠️ Shouldn't be regularly used! Bypasses Codspeed performance checks label Sep 5, 2025
@mdrxy mdrxy added the langchain Related to the package `langchain` label Sep 5, 2025
@mdrxy mdrxy added this to the v1 milestone Sep 5, 2025
messages = state["messages"]
self._ensure_message_ids(messages)

total_tokens = self.token_counter(messages)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want to cache this or something? recomputing kind of annoying?

hwchase17 and others added 3 commits September 6, 2025 13:11
…32837)

Main change here is the removal of `AgentJump`.

Typing things as `AgentJump` doesn't really make sense, given that we
often want to perform an agent jump **and** update the state of the
graph, potentially including updates to state extensions from a given
middleware.

For example, previously we had:

```py
def after_model(state: AgentState) -> AgentUpdate | AgentJump | None:
    ...
```

But what if my middleware adds a `model_calls` attribute? `AgentJump`
has no way of inheriting that newly defined state, but I still might
want to do something like:

```py
def after_model(state: AgentState) -> AgentUpdate | AgentJump | None:
    return {'model_calls': X, 'jump_to': '__end__'}
```

Then the return type `AgentUpdate | AgentJump | None` doesn't represent
the return value.

There's no great way to type partial state updates yet, hence we use
`dict[str, Any]`. This is a Python limitation.

I've removed the conditional logic for signature parsing on `AgentJump`
and we just always add conditional edges for middleware nodes now.

Other things:
* adding docstrings + other linting fixes (sort of a general cleanup of
this module).
* removing tool calling / model calling limits as those applications
aren't fully fleshed out / we want to just publish these 3 middlewares
first.
@sydney-runkle sydney-runkle changed the title wip: port over new agent w/ middleware feat(langchain): middleware support in create_agent Sep 7, 2025
@sydney-runkle sydney-runkle marked this pull request as ready for review September 8, 2025 01:03
@sydney-runkle sydney-runkle enabled auto-merge (squash) September 8, 2025 01:09
@sydney-runkle sydney-runkle merged commit 6e2f46d into master Sep 8, 2025
36 checks passed
@sydney-runkle sydney-runkle deleted the sr/new-agent branch September 8, 2025 01:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
codspeed-ignore ⚠️ Shouldn't be regularly used! Bypasses Codspeed performance checks langchain Related to the package `langchain`
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants