# Migrating off AgentExecutor

## What changes

- `AgentExecutor` + agent type strings -> `create_agent(model=..., tools=[...])`.
- Custom agent logic in executor callbacks -> middleware (`before_model`, `after_model`, `@wrap_model_call`, `@wrap_tool_call`).
- `handle_parsing_errors` and friends -> ToolStrategy error handling via the `handle_errors` parameter, or ToolErrorMiddleware.
- `max_iterations` / `max_execution_time` -> ModelCallLimitMiddleware / ToolCallLimitMiddleware.
- Memory classes -> checkpointer plus thread ids (see the agent-with-memory workflow).

## Order of work

1. Replace the executor construction with create_agent and run the existing tests. The tool functions themselves usually transfer unchanged if they are plain functions.
2. Move each customization to middleware one at a time, testing after each.
3. Delete the legacy imports. If anything still needs the old agent types, that code belongs in langchain-classic, but aim to leave nothing behind.

## Rules

- Do not run old and new agents side by side in production "just in case". Migrate, test, cut over.
- The old `prompt=` argument is now `system_prompt=` and takes a string. Callable prompts become `@dynamic_prompt` middleware.
- Structured output moves to `response_format=ToolStrategy(...)` or `ProviderStrategy(...)` from `langchain.agents.structured_output`.