LangChain.MessageDelta (LangChain v0.5.1)

Copy Markdown View Source

Models a "delta" message from a chat LLM. A delta is a small chunk, or piece of a much larger complete message. A series of deltas are used to construct the complete message.

Delta messages must be applied in order for them to be valid. Delta messages can be combined and transformed into a LangChain.Message once the final piece is received.

Roles

  • :unknown - The role data is missing for the delta.
  • :assistant - Responses coming back from the LLM.

Tool Usage

Tools can be used or called by the assistant (LLM). A tool call is also split across many message deltas and must be fully assembled before it can be executed.

Metadata

The metadata field is a map that can contain any additional information about the message delta. It is used to store token usage, model, and other LLM-specific information.

Content Fields

The content field may contain:

  • A string (for backward compatibility)
  • A LangChain.Message.ContentPart struct
  • An empty list [] that is received from some services like Anthropic, which is a signal that the content will be a list of content parts

The module uses two content-related fields:

  • content - The raw content received from the LLM. This can be either a string (for backward compatibility), a LangChain.Message.ContentPart struct, or a [] indicating it will be a list of content parts. This field is cleared (set to nil) after merging into merged_content.

  • merged_content - The accumulated list of ContentParts after merging deltas. This is the source of truth for the message content and is used when converting to a LangChain.Message. When merging deltas:

    • For string content, it's converted to a ContentPart of type :text
    • For ContentPart content, it's merged based on the index field
    • Multiple content parts can be maintained in the list to support multi-modal responses (text, images, audio) or separate thinking content from final text

Summary

Functions

Accumulates token usage from delta messages. Uses LangChain.TokenUsage.add/2 to combine the usage data from both deltas.

Safely adds tool call display information to a MessageDelta's metadata. Handles nil delta by creating a new one if needed.

Convert the MessageDelta's merged content to a string. Specify the type of content to convert so it can return just the text parts or thinking parts, etc. Defaults to :text.

Retrieves tool call display information from MessageDelta metadata. Returns empty list if none present.

Merge two MessageDelta structs. The first MessageDelta is the primary one that smaller deltas are merged into.

Merges a list of MessageDeltas into a single MessageDelta. The deltas are merged in order, with each delta being merged into the result of the previous merge.

Merges a list of MessageDeltas into an accumulated MessageDelta. This is useful for UI applications that accumulate deltas as they are received from a streaming LLM response.

Migrates a MessageDelta's string content to use LangChain.Message.ContentPart. This is for backward compatibility with models that don't yet support ContentPart streaming.

Create a new MessageDelta that represents a message chunk.

Create a new MessageDelta that represents a message chunk and return it or raise an error if invalid.

Convert the MessageDelta to a Message. Can only convert a fully complete MessageDelta.

Types

t()

@type t() :: %LangChain.MessageDelta{
  content: term(),
  index: term(),
  merged_content: term(),
  metadata: term(),
  role: term(),
  status: term(),
  tool_calls: term()
}

Functions

accumulate_token_usage(primary, delta_part)

@spec accumulate_token_usage(t(), t()) :: t()

Accumulates token usage from delta messages. Uses LangChain.TokenUsage.add/2 to combine the usage data from both deltas.

Example

iex> alias LangChain.TokenUsage
iex> alias LangChain.MessageDelta
iex> delta1 = %MessageDelta{
...>   metadata: %{
...>     usage: %TokenUsage{input: 10, output: 5}
...>   }
...> }
iex> delta2 = %MessageDelta{
...>   metadata: %{
...>     usage: %TokenUsage{input: 5, output: 15}
...>   }
...> }
iex> result = MessageDelta.accumulate_token_usage(delta1, delta2)
iex> result.metadata.usage.input
15
iex> result.metadata.usage.output
20

add_tool_display_info(delta, tool_info)

@spec add_tool_display_info(nil | t(), map()) :: t()

Safely adds tool call display information to a MessageDelta's metadata. Handles nil delta by creating a new one if needed.

Parameters

  • delta - MessageDelta struct or nil
  • tool_info - Map with :name, :call_id, :arguments, etc.

Returns

Updated MessageDelta with enriched metadata

Example

delta = MessageDelta.add_tool_display_info(nil, %{
  name: "write_file",
  call_id: "call_123",
  display_name: "Writing file..."
})

MessageDelta.get_tool_display_info(delta)
# => [%{name: "write_file", call_id: "call_123", ...}]

content_to_string(delta, type \\ :text)

@spec content_to_string(t(), type :: atom()) :: nil | String.t()

Convert the MessageDelta's merged content to a string. Specify the type of content to convert so it can return just the text parts or thinking parts, etc. Defaults to :text.

get_tool_display_info(delta)

@spec get_tool_display_info(nil | t()) :: [map()]

Retrieves tool call display information from MessageDelta metadata. Returns empty list if none present.

merge_delta(primary, delta_part)

@spec merge_delta(nil | t(), t()) :: t()

Merge two MessageDelta structs. The first MessageDelta is the primary one that smaller deltas are merged into.

The merging process:

  1. Migrates any string content to ContentParts for backward compatibility
  2. Merges the content into merged_content based on the index field
  3. Clears the content field (sets to nil) after merging
  4. Updates other fields (tool_calls, status, etc.)

Examples

iex> delta_1 =
...>   %LangChain.MessageDelta{
...>     content: nil,
...>     index: 0,
...>     tool_calls: [],
...>     role: :assistant,
...>     status: :incomplete
...>   }
iex> delta_2 =
...>   %LangChain.MessageDelta{
...>     content: "Hello",
...>     index: 0,
...>     tool_calls: [],
...>     role: :unknown,
...>     status: :incomplete
...>   }
iex> LangChain.MessageDelta.merge_delta(delta_1, delta_2)
%LangChain.MessageDelta{
  content: nil,
  merged_content: [%LangChain.Message.ContentPart{type: :text, content: "Hello"}],
  status: :incomplete,
  index: 0,
  role: :assistant,
  tool_calls: []
}

A set of deltas can be easily merged like this:

  MessageDelta.merge_deltas(list_of_delta_messages)

merge_deltas(deltas)

@spec merge_deltas([t()]) :: t()

Merges a list of MessageDeltas into a single MessageDelta. The deltas are merged in order, with each delta being merged into the result of the previous merge.

Examples

iex> deltas = [
...>   %LangChain.MessageDelta{content: "Hello", role: :assistant},
...>   %LangChain.MessageDelta{content: " world", role: :assistant},
...>   %LangChain.MessageDelta{content: "!", role: :assistant, status: :complete}
...> ]
iex> LangChain.MessageDelta.merge_deltas(deltas)
%LangChain.MessageDelta{
  content: nil,
  merged_content: [%LangChain.Message.ContentPart{type: :text, content: "Hello world!"}],
  status: :complete,
  role: :assistant
}

merge_deltas(accumulated_delta, deltas)

@spec merge_deltas(nil | t(), [t()]) :: t()

Merges a list of MessageDeltas into an accumulated MessageDelta. This is useful for UI applications that accumulate deltas as they are received from a streaming LLM response.

The first argument is the accumulated delta (or nil if no deltas have been processed yet). The second argument is a list of new deltas to merge in.

Examples

iex> accumulated = nil
iex> batch_1 = [
...>   %LangChain.MessageDelta{content: "Hello", role: :assistant},
...>   %LangChain.MessageDelta{content: " world", role: :assistant}
...> ]
iex> accumulated = LangChain.MessageDelta.merge_deltas(accumulated, batch_1)
iex> batch_2 = [
...>   %LangChain.MessageDelta{content: "!", role: :assistant, status: :complete}
...> ]
iex> result = LangChain.MessageDelta.merge_deltas(accumulated, batch_2)
iex> result
%LangChain.MessageDelta{
  content: nil,
  merged_content: [%LangChain.Message.ContentPart{type: :text, content: "Hello world!"}],
  status: :complete,
  role: :assistant
}

migrate_to_content_parts(delta)

@spec migrate_to_content_parts(t()) :: t()

Migrates a MessageDelta's string content to use LangChain.Message.ContentPart. This is for backward compatibility with models that don't yet support ContentPart streaming.

Examples

iex> delta = %LangChain.MessageDelta{content: "Hello world"}
iex> upgraded = migrate_to_content_parts(delta)
iex> upgraded.content
%LangChain.Message.ContentPart{type: :text, content: "Hello world"}

new(attrs \\ %{})

@spec new(attrs :: map()) :: {:ok, t()} | {:error, Ecto.Changeset.t()}

Create a new MessageDelta that represents a message chunk.

new!(attrs \\ %{})

@spec new!(attrs :: map()) :: t() | no_return()

Create a new MessageDelta that represents a message chunk and return it or raise an error if invalid.

to_message(delta)

@spec to_message(t()) :: {:ok, LangChain.Message.t()} | {:error, String.t()}

Convert the MessageDelta to a Message. Can only convert a fully complete MessageDelta.

This is assumed to be the result of merging all the received MessageDeltas. An error is returned if the status is :incomplete.

If the MessageDelta fails to convert to a LangChain.Message, an error is returned with the reason.