SIGN IN SIGN UP

feat: threading context through `create_agent` flows + middleware (#34978)

Closes https://github.com/langchain-ai/langchain/issues/33956

* Making `ModelRequest` generic on `ContextT` and `ResponseT` so that we
can thread type information through to `wrap_model_call`
* Making builtin middlewares generic on `ContextT` and `ResponseT` so
their context and response types can be inferred from the `create_agent`
signature

See new tests that verify backwards compatibility (for cases where folks
use custom middleware that wasn't parametrized).

This fixes:
1. Lack of access to context and response types in `wrap_model_call`
2. Lack of cohesion between middleware context + response types with
those specified in `create_agent`

See examples below:

### Type-safe context and response access

```python
class MyMiddleware(AgentMiddleware[AgentState[AnalysisResult], UserContext, AnalysisResult]):
    def wrap_model_call(
        self,
        request: ModelRequest[UserContext],
        handler: Callable[[ModelRequest[UserContext]], ModelResponse[AnalysisResult]],
    ) -> ModelResponse[AnalysisResult]:
        # ✅ Now type-safe: IDE knows user_id exists and is str
        user_id: str = request.runtime.context["user_id"]

        # ❌ mypy error: "session_id" doesn't exist on UserContext
        request.runtime.context["session_id"]

        response = handler(request)

        if response.structured_response is not None:
            # ✅ Now type-safe: IDE knows sentiment exists and is str
            sentiment: str = response.structured_response.sentiment

            # ❌ mypy error: "summary" doesn't exist on AnalysisResult
            response.structured_response.summary

        return response
```

### Mismatched middleware/schema caught at `create_agent`

```python
class SessionMiddleware(AgentMiddleware[AgentState[Any], SessionContext, Any]):
    ...

# ❌ mypy error: SessionMiddleware expects SessionContext, not UserContext
create_agent(
    model=model,
    middleware=[SessionMiddleware()],
    context_schema=UserContext,  # mismatch!
)

class AnalysisMiddleware(AgentMiddleware[AgentState[AnalysisResult], ContextT, AnalysisResult]):
    ...

# ❌ mypy error: AnalysisMiddleware expects AnalysisResult, not SummaryResult
create_agent(
    model=model,
    middleware=[AnalysisMiddleware()],
    response_format=SummaryResult,  # mismatch!
)
```
S
Sydney Runkle committed
dde2012b832c9d370a2ea76fd18a79624a182a4c
Parent: 032d01d
Committed by GitHub <[email protected]> on 2/5/2026, 12:41:27 PM