Current section

Files

Jump to
langchain lib chains chain_callbacks.ex
Raw

lib/chains/chain_callbacks.ex

defmodule LangChain.Chains.ChainCallbacks do
@moduledoc """
Defines the callbacks fired by an LLMChain and LLM module.
A callback handler is a map that defines the specific callback event with a
function to execute for that event.
## Example
A sample configured callback handler that forwards received data to a specific
LiveView.
live_view_pid = self()
my_handlers = %{
on_llm_new_delta: fn _chain, new_deltas -> send(live_view_pid, {:received_delta, new_deltas}) end,
on_message_processed: fn _chain, new_message -> send(live_view_pid, {:received_message, new_message}) end,
on_error_message_created: fn _chain, new_message -> send(live_view_pid, {:received_message, new_message}) end
}
model = SomeLLM.new!(%{...})
chain =
%{llm: model}
|> LLMChain.new!()
|> LLMChain.add_callback(my_handlers)
"""
alias LangChain.Chains.LLMChain
alias LangChain.Function
alias LangChain.Message
alias LangChain.Message.ToolCall
alias LangChain.Message.ToolResult
alias LangChain.MessageDelta
alias LangChain.TokenUsage
@typedoc """
Executed when an LLM is streaming a response and a new MessageDelta (or token)
was received.
- `:index` is optionally present if the LLM supports sending `n` versions of a
response.
The return value is discarded.
"""
@type llm_new_delta :: (LLMChain.t(), [MessageDelta.t()] -> any())
@typedoc """
Executed when an LLM is not streaming and a full message was received.
The return value is discarded.
"""
@type llm_new_message :: (LLMChain.t(), Message.t() -> any())
@typedoc """
Executed when an LLM (typically a service) responds with rate limiting
information.
The specific rate limit information depends on the LLM. It returns a map with
all the available information included.
The return value is discarded.
"""
@type llm_ratelimit_info :: (LLMChain.t(), info :: %{String.t() => any()} -> any())
@typedoc """
Executed when an LLM response reports the token usage in a
`LangChain.TokenUsage` struct. The data returned depends on the LLM.
The return value is discarded.
"""
@type llm_token_usage :: (LLMChain.t(), TokenUsage.t() -> any())
@typedoc """
Executed when an LLM response is received through an HTTP response. The entire
set of raw response headers can be received and processed.
The return value is discarded.
## Example
A function declaration that matches the signature.
def handle_llm_response_headers(chain, response_headers) do
# This demonstrates how to send the response headers to a
# LiveView assuming the LiveView's pid was stored in the chain's
# custom_context.
send(chain.custom_context.live_view_pid, {:req_response_headers, response_headers})
IO.inspect(response_headers)
end
"""
@type llm_response_headers :: (LLMChain.t(), response_headers :: map() -> any())
@typedoc """
Executed when an LLMChain has completed processing a received assistant
message. This fires when a message is complete either after assembling
streaming deltas or when a full message is received when not streaming.
This is the best way to be notified when a message is "done" and should be
handled by the application.
The handler's return value is discarded.
"""
@type chain_message_processed :: (LLMChain.t(), Message.t() -> any())
@typedoc """
Executed when an LLMChain, in response to an error from the LLM, generates a
new, automated response message intended to be returned to the LLM.
"""
@type chain_error_message_created :: (LLMChain.t(), Message.t() -> any())
@typedoc """
Executed when processing a received message errors or fails. The erroring
message is included in the callback with the state of processing that was
completed before erroring.
The handler's return value is discarded.
"""
@type chain_message_processing_error :: (LLMChain.t(), Message.t() -> any())
@typedoc """
Executed when a tool call is identified during streaming, before execution begins.
This fires as soon as we have enough information to identify the tool (at minimum, the `name` field).
The tool call may be incomplete - `call_id` might not be available yet, and `arguments` may be partial.
This callback provides early notification for UI feedback like "Searching web..." while the LLM
is still streaming the complete tool call.
Timing:
- Fires: As soon as tool name is detected in streaming deltas
- Before: Tool arguments are fully received
- Before: Tool execution begins
Arguments:
- First: LLMChain.t() - Current chain state
- Second: ToolCall.t() - Tool call struct (may be incomplete, but has name)
- Third: Function.t() - Function definition (includes display_text)
The handler's return value is discarded.
## Example
callback_handler = %{
on_tool_call_identified: fn _chain, tool_call, func ->
IO.puts("Tool identified: \#{func.display_text || tool_call.name}")
end
}
"""
@type chain_tool_call_identified :: (LLMChain.t(), ToolCall.t(), Function.t() -> any())
@typedoc """
Executed when the chain begins executing a tool call.
This fires immediately before tool execution starts, allowing UIs to show
real-time feedback like "Searching the web..." or "Creating file...".
- First argument: LLMChain.t()
- Second argument: ToolCall struct being executed
- Third argument: Function struct for the tool (includes display_text)
The handler's return value is discarded.
"""
@type chain_tool_execution_started :: (LLMChain.t(), ToolCall.t(), Function.t() -> any())
@typedoc """
Executed when a single tool execution completes successfully.
Fires after individual tool execution, before results are aggregated.
Useful for showing per-tool success indicators.
- First argument: LLMChain.t()
- Second argument: ToolCall that was executed
- Third argument: ToolResult that was generated
The handler's return value is discarded.
"""
@type chain_tool_execution_completed :: (LLMChain.t(), ToolCall.t(), ToolResult.t() -> any())
@typedoc """
Executed when a single tool execution fails.
Fires when tool execution raises an exception or returns an error result.
- First argument: LLMChain.t()
- Second argument: ToolCall that failed
- Third argument: Error reason or exception
The handler's return value is discarded.
"""
@type chain_tool_execution_failed :: (LLMChain.t(), ToolCall.t(), term() -> any())
@typedoc """
Executed when the chain uses one or more tools and the resulting ToolResults
are generated as part of a tool response message.
The handler's return value is discarded.
"""
@type chain_tool_response_created :: (LLMChain.t(), Message.t() -> any())
@typedoc """
Executed when the chain failed multiple times used up the `max_retry_count`
resulting in the process aborting and returning an error.
The handler's return value is discarded.
"""
@type chain_retries_exceeded :: (LLMChain.t() -> any())
@typedoc """
The supported set of callbacks for an LLM module.
"""
@type chain_callback_handler :: %{
# model-level callbacks
optional(:on_llm_new_delta) => llm_new_delta(),
optional(:on_llm_new_message) => llm_new_message(),
optional(:on_llm_ratelimit_info) => llm_ratelimit_info(),
optional(:on_llm_token_usage) => llm_token_usage(),
optional(:on_llm_response_headers) => llm_response_headers(),
# Chain-level callbacks
optional(:on_message_processed) => chain_message_processed(),
optional(:on_message_processing_error) => chain_message_processing_error(),
optional(:on_error_message_created) => chain_error_message_created(),
optional(:on_tool_call_identified) => chain_tool_call_identified(),
optional(:on_tool_execution_started) => chain_tool_execution_started(),
optional(:on_tool_execution_completed) => chain_tool_execution_completed(),
optional(:on_tool_execution_failed) => chain_tool_execution_failed(),
optional(:on_tool_response_created) => chain_tool_response_created(),
optional(:on_retries_exceeded) => chain_retries_exceeded()
}
end