ReqLLM.Context (ReqLLM v1.19.0)

View Source

Context represents a conversation history as a collection of messages.

Provides canonical message constructor functions that can be imported for clean, readable message creation. Supports standard roles: :user, :assistant, :system, and :tool.

Example

import ReqLLM.Context

context = Context.new([
  system("You are a helpful assistant"),
  user("What's the weather like?"),
  assistant("I'll check that for you")
])

Context.validate!(context)

Redacting context on inspect

Set config :req_llm, redact_context: true to hide message contents from inspect/2 output. When enabled, only the message count is shown:

#Context<4 messages [REDACTED]>

This prevents sensitive prompts from leaking into logs or crash reports.

Summary

Types

Any input accepted by Context.normalize/2 as a prompt or messages parameter.

t()

Functions

Append a message to the context.

Appends one assistant tool-call message and its matched tool results.

Create an assistant message with optional tool calls and metadata.

Build an assistant message with a tool call.

Build an assistant message with multiple tool calls.

Create an assistant message with tool calls.

Build a message from role and content parts (metadata optional).

Concatenate two contexts.

Execute a list of tool calls and append their results to the context.

Merges the original context with a response to create an updated context.

Create a new Context from a list of messages (defaults to empty).

Normalize any "prompt-ish" input into a validated ReqLLM.Context.

Bang version of normalize/2 that raises on error.

Prepend a message to the context.

Create a system message with optional metadata.

Build a text-only message for the given role.

Return the underlying message list.

Create a tool result message with tool_call_id and content.

Create a tool result message with tool_call_id, name, and content.

Create a user message with optional metadata.

Validate context: ensures valid messages and tool message constraints.

Bang version of validate/1; raises ReqLLM.Error.Validation.Error on invalid context.

Build a message with text and an image URL for the given role.

Wrap a context with provider-specific tagged struct.

Types

prompt()

@type prompt() ::
  String.t()
  | ReqLLM.Message.t()
  | t()
  | map()
  | [String.t() | ReqLLM.Message.t() | t() | map()]

Any input accepted by Context.normalize/2 as a prompt or messages parameter.

Includes plain strings, single Message structs, Context structs, loose maps with :role/:content keys, and lists of any of those types.

t()

@type t() :: %ReqLLM.Context{messages: [any()], tools: [any()]}

Functions

append(ctx, msg)

@spec append(t(), ReqLLM.Message.t()) :: t()
@spec append(t(), [ReqLLM.Message.t()]) :: t()

Append a message to the context.

append_tool_exchange(context, source, results)

@spec append_tool_exchange(t(), ReqLLM.Message.t() | ReqLLM.Response.t(), [
  ReqLLM.Message.t()
]) ::
  {:ok, t()} | {:error, ReqLLM.Error.Validation.Error.t()}

Appends one assistant tool-call message and its matched tool results.

Accepts either the canonical assistant ReqLLM.Message or its ReqLLM.Response. Tool results must be canonical tool messages built with tool_result/2, tool_result/3, or tool_result_message/4.

The exchange is validated before the context changes. Results are matched by tool_call_id and appended in assistant call order, regardless of input order. A result without a name inherits the matched call name. Explicit result names must match.

Provider-executed builtins do not require local results. Provider-native calls remain explicit and require a matching result before continuation. The assistant and result messages otherwise retain their content, reasoning details, and metadata unchanged. This function never executes a tool or starts another model call.

If the context already ends with the exact assistant message, only the results are appended. This supports both the original input context and the response.context returned by generation functions.

Examples

results = [
  ReqLLM.Context.tool_result("call_1", "get_weather", "72°F and sunny")
]

{:ok, continued_context} =
  ReqLLM.Context.append_tool_exchange(input_context, response, results)

assistant(content \\ "", meta_or_opts \\ %{})

@spec assistant([ReqLLM.Message.ContentPart.t()] | String.t(), map() | keyword()) ::
  ReqLLM.Message.t()

Create an assistant message with optional tool calls and metadata.

Accepts a string or content parts list. Second argument can be a map (legacy) or keyword list with options including tool_calls.

Options

  • :tool_calls - List of tool calls (ToolCall structs, tuples, or maps)
  • :metadata - Map of metadata to attach to the message (default: %{})

Examples

assistant("Hello")
assistant("", tool_calls: [ToolCall.new("id", "get_weather", ~s({"location":"SF"}))])
assistant("Let me check", tool_calls: [{"get_weather", %{location: "SF"}}])
assistant([ContentPart.text("Hi")], metadata: %{})

assistant_tool_call(name, input, opts \\ [])

This function is deprecated. Use assistant("", tool_calls: [{name, input}]) instead.
@spec assistant_tool_call(String.t(), term(), keyword()) :: ReqLLM.Message.t()

Build an assistant message with a tool call.

assistant_tool_calls(calls, meta \\ %{})

This function is deprecated. Use assistant("", tool_calls: [...]) instead.
@spec assistant_tool_calls(
  [%{id: String.t(), name: String.t(), input: term()}],
  map()
) ::
  ReqLLM.Message.t()

Build an assistant message with multiple tool calls.

assistant_with_tools(tool_calls, text \\ nil)

This function is deprecated. Use assistant(content, tool_calls: [...]) instead.
@spec assistant_with_tools([ReqLLM.ToolCall.t()], String.t() | nil) ::
  ReqLLM.Message.t()

Create an assistant message with tool calls.

build(role, content, meta \\ %{})

Build a message from role and content parts (metadata optional).

concat(ctx, other)

@spec concat(t(), t()) :: t()

Concatenate two contexts.

execute_and_append_tools(context, tool_calls, available_tools)

@spec execute_and_append_tools(t(), [map()], [ReqLLM.Tool.t()]) :: t()

Execute a list of tool calls and append their results to the context.

Takes a list of tool call maps (with :id, :name, :arguments keys) and a list of available tools, executes each call, and appends the results as tool messages. Tool callbacks may return plain text, structured data, content parts, or a ReqLLM.ToolResult.

Parameters

  • context - The context to append results to
  • tool_calls - List of tool call maps with :id, :name, :arguments
  • available_tools - List of ReqLLM.Tool structs to execute against

Returns

Updated context with tool result messages appended.

Examples

tool_calls = [%{id: "call_1", name: "calculator", arguments: %{"operation" => "add", "a" => 2, "b" => 3}}]
context = Context.execute_and_append_tools(context, tool_calls, tools)

merge_response(context, response, opts \\ [])

@spec merge_response(t(), ReqLLM.Response.t(), keyword()) :: ReqLLM.Response.t()

Merges the original context with a response to create an updated context.

Takes a context and a response, then creates a new context containing the original messages plus the assistant response message.

Parameters

  • context - Original ReqLLM.Context
  • response - ReqLLM.Response containing the assistant message

Returns

  • Updated response with merged context

Examples

context = ReqLLM.Context.new([user("Hello")])
response = %ReqLLM.Response{message: assistant("Hi there!")}
updated_response = ReqLLM.Context.merge_response(context, response)
# response.context now contains both user and assistant messages

new(list \\ [])

@spec new([ReqLLM.Message.t()]) :: t()

Create a new Context from a list of messages (defaults to empty).

normalize(prompt, opts \\ [])

@spec normalize(
  String.t()
  | ReqLLM.Message.t()
  | t()
  | map()
  | [String.t() | ReqLLM.Message.t() | t() | map()],
  keyword()
) :: {:ok, t()} | {:error, term()}

Normalize any "prompt-ish" input into a validated ReqLLM.Context.

Accepts various input types and converts them to a proper Context struct:

  • String: converts to user message
  • Message struct: wraps in Context
  • Context struct: passes through
  • List: processes each item and creates Context from all messages
  • Loose maps: converts to Message if they have role/content keys

Options

  • :system_prompt - String to add as system message if none exists
  • :validate - Boolean to run validation (default: true)
  • :convert_loose - Boolean to allow loose maps with role/content (default: true)

Examples

# String to user message
Context.normalize("Hello")
#=> {:ok, %Context{messages: [%Message{role: :user, content: [%ContentPart{text: "Hello"}]}]}}

# Add system prompt
Context.normalize("Hello", system_prompt: "You are helpful")
#=> {:ok, %Context{messages: [%Message{role: :system}, %Message{role: :user}]}}

# List of mixed types
Context.normalize([%Message{role: :system}, "Hello"])

normalize!(prompt, opts \\ [])

@spec normalize!(
  String.t()
  | ReqLLM.Message.t()
  | t()
  | map()
  | [String.t() | ReqLLM.Message.t() | t() | map()],
  keyword()
) :: t()

Bang version of normalize/2 that raises on error.

prepend(ctx, msg)

@spec prepend(t(), ReqLLM.Message.t()) :: t()

Prepend a message to the context.

schema()

system(content, meta_or_opts \\ %{})

Create a system message with optional metadata.

Accepts a string or content parts list. Second argument can be a map (legacy) or keyword list with options.

Options

  • :metadata - Map of metadata to attach to the message (default: %{})

Examples

system("You are helpful")
system("You are helpful", %{version: 1})
system("You are helpful", metadata: %{version: 1})

text(role, content, meta \\ %{})

@spec text(atom(), String.t(), map()) :: ReqLLM.Message.t()

Build a text-only message for the given role.

to_list(context)

@spec to_list(t()) :: [ReqLLM.Message.t()]

Return the underlying message list.

tool_result(tool_call_id, result)

Create a tool result message with tool_call_id and content.

Accepts plain text, content parts, or a ReqLLM.ToolResult for structured and multi-part outputs.

tool_result(tool_call_id, name, result)

Create a tool result message with tool_call_id, name, and content.

Accepts plain text, content parts, or a ReqLLM.ToolResult for structured and multi-part outputs.

tool_result_message(tool_name, tool_call_id, output, meta \\ %{})

@spec tool_result_message(String.t() | nil, String.t(), term(), map()) ::
  ReqLLM.Message.t()

Build a tool result message.

The model-visible contract lives in the message content. When output is a non-text value, ReqLLM encodes it into a JSON text content part and also preserves the original value in metadata for provider adapters and local tooling.

Prefer putting canonical success/failure semantics in the content body, for example:

%{ok: true, result: %{temp_f: 72}}
%{ok: false, error: %{type: :timeout, message: "Tool timed out"}}

Metadata is supplementary and should not be the only place a model-facing tool result is represented.

user(content, meta_or_opts \\ %{})

Create a user message with optional metadata.

Accepts a string or content parts list. Second argument can be a map (legacy) or keyword list with options.

Options

  • :metadata - Map of metadata to attach to the message (default: %{})

Examples

user("Hello")
user("Hello", %{source: "api"})
user("Hello", metadata: %{source: "api"})
user([ContentPart.text("Hello")], metadata: %{})

validate(context)

@spec validate(t()) :: {:ok, t()} | {:error, String.t()}

Validate context: ensures valid messages and tool message constraints.

validate!(context)

@spec validate!(t()) :: t()

Bang version of validate/1; raises ReqLLM.Error.Validation.Error on invalid context.

with_image(role, text, url, meta \\ %{})

@spec with_image(atom(), String.t(), String.t(), map()) :: ReqLLM.Message.t()

Build a message with text and an image URL for the given role.

wrap(ctx, model)

@spec wrap(t(), LLMDB.Model.t()) :: term()

Wrap a context with provider-specific tagged struct.

Takes a ReqLLM.Context and ReqLLM.Model and wraps the context in the appropriate provider-specific struct for encoding/decoding.

Parameters

  • context - A ReqLLM.Context to wrap
  • model - A ReqLLM.Model indicating the provider

Returns

  • Provider-specific tagged struct ready for encoding

Examples

context = ReqLLM.Context.new([ReqLLM.Context.user("Hello")])
model = ReqLLM.model("anthropic:claude-3-haiku-20240307")
tagged = ReqLLM.Context.wrap(context, model)
#=> %ReqLLM.Providers.Anthropic.Context{context: context}