Detect model replies that a provider cut off before they were complete.
LangChain has no normalized stop reason, so each provider's raw metadata is
read here. output_truncation classifies one message. EmptyTruncatedReplyMiddleware
turns an empty, truncated reply into a typed error, so the run fails visibly
instead of ending as a silent success with nothing to show. Subagent failures
become task-tool errors, while partial answers carry a warning to the parent.
Classify whether the provider stopped this message early.
Reads the raw provider metadata on response_metadata, so it also works on
the streamed chunk that carries the stop reason.
Return whether a message has reply text or a tool call to act on.
Reasoning alone does not count: the user still gets no answer.
Return a short, user-facing explanation of a truncation.
Why a provider stopped a reply early.
The model stopped before it gave any reply.
Subclasses ValueError so that the LangGraph server keeps the message when
it serializes the error for the client. Other exception types are redacted
to "An internal error occurred".
Fail the main run when the provider cut off a reply before any output.
Without this, a reply with no text, no tool calls, and a truncation stop reason ends the run as a success. The empty message is checkpointed and the UI shows nothing, so the app looks hung. Raising instead fails the model node, so the empty message is not saved and the client shows the error. A partial reply is left alone; the client warns about it.
This middleware never retries. It must wrap the retry middleware, so the error is not retried, and any recovery middleware that may still repair the reply.
Keep partial subagent answers and fail empty ones for the parent to handle.