class RubyLLM::Message
A Message is a single entry in a chat conversation: a user prompt, an assistant reply, a system instruction, or a tool result. Chat#ask returns the model’s reply as a Message, and Chat#messages holds the transcript as an array of them.
response = chat.ask "What is the capital of France?" response.role # => :assistant response.content # => "The capital of France is Paris." response.finish_reason # => :stop
A Message also carries everything else the provider returned: token usage (tokens), reasoning output (thinking), source citations (citations), and requested tool calls (tool_calls).
Constants
- ROLES
-
The valid message roles:
:system,:user,:assistant, and:tool.
Attributes
The files sent or returned with the message, as an array of Attachment objects.
The source citations as an array of Citation objects, normalized across providers.
The message text as a String. Empty for assistant messages that only request tool calls.
Why the model stopped: :stop, :max_tokens, :tool_calls, or :content_filter. Any other reason comes through as the provider spelled it, such as Anthropic’s :pause_turn.
The ID of the model that produced the message, nil on user messages.
The raw provider response: a Faraday::Response, or the result body Hash for messages retrieved from a Batch.
The role of the message: :system, :user, :assistant, or :tool.
The provider-executed tool steps in this response, as an array of ServerToolCall objects. Empty unless the chat enabled tools with Chat#with_server_tools and the model used one.
The model’s reasoning output as a Thinking object, or nil when the provider returned none.
The ID of the tool call this message answers. Set only on tool result messages.
The tool calls the assistant requested, as a Hash of ToolCall objects keyed by call ID, or nil.
Public Instance Methods
Source
# File lib/ruby_llm/message.rb, line 206 def cache_until_here @cache_until_here = true self end
Marks this message as an explicit prompt cache boundary. Providers with boundary controls use the conversation up to and including this message as the cacheable prefix. Returns self.
chat.add_message(role: :user, content: long_context).cache_until_here
Source
# File lib/ruby_llm/message.rb, line 213 def cache_until_here? @cache_until_here end
Returns true if the message carries an explicit prompt cache boundary, false otherwise.
Source
# File lib/ruby_llm/message.rb, line 174 def content_filtered? finish_reason == :content_filter end
Returns true if a provider safety filter stopped the response, false otherwise.
Source
# File lib/ruby_llm/message.rb, line 193 def cost(model: nil) return ruby_llm_usage_cost if model.nil? && ruby_llm_usage_entries.any? return @supplied_cost if model.nil? && @supplied_cost Cost.new(tokens:, model: model || model_info) end
Returns a Cost pricing this message’s token usage in US dollars. Uses recorded attempt costs, an explicitly supplied cost:, or pricing from model_info. An explicit model: overrides those costs for repricing.
response.cost.total
Source
# File lib/ruby_llm/message.rb, line 162 def max_tokens? finish_reason == :max_tokens end
Returns true if the response was cut off by a token limit, false otherwise.
Source
# File lib/ruby_llm/message.rb, line 243 def model_info return unless model @model_info ||= RubyLLM.models.find(model) rescue ModelNotFoundError nil end
Source
# File lib/ruby_llm/message.rb, line 119 def parsed return if content.nil? || content.empty? @parsed ||= JSON.parse(content) end
Returns content parsed as JSON, memoized after the first call. Useful for reading structured output responses.
response = chat.with_schema(PersonSchema).ask "Generate a person" response.parsed # => {"name" => "Alice", "age" => 30}
Source
# File lib/ruby_llm/message.rb, line 156 def stopped? finish_reason == :stop && !tool_call? end
Returns true if finish_reason indicates the model finished normally, false otherwise. A turn that stopped to call tools is reported by tool_call_stop? instead, whatever the provider named it.
Source
# File lib/ruby_llm/message.rb, line 221 def to_h { role: role, content: content, attachments: list_to_h(attachments), model: model, cost: @supplied_cost && cost.to_h, tool_calls: tool_calls&.transform_values(&:to_h), tool_call_id: tool_call_id, thinking: thinking&.text, thinking_signature: thinking&.signature, citations: list_to_h(citations), server_tool_calls: list_to_h(server_tool_calls), raw_content: raw_content, raw_reasoning: raw_reasoning, finish_reason: finish_reason, cache_until_here: cache_until_here? || nil }.merge(tokens.to_h).compact end
Returns a Hash of the message’s attributes, with token counts merged in as :input_tokens, :output_tokens, and related keys. Omits nil values and empty attachment and citation lists. Includes :cost only when supplied explicitly, preserving unknown costs on round-trip.
Source
# File lib/ruby_llm/message.rb, line 181 def tokens return @tokens if ruby_llm_usage_entries.empty? ruby_llm_usage_tokens end
Returns usage aggregated across every provider attempt that produced this message. Messages constructed by hand report the token counts they were built with.
Source
# File lib/ruby_llm/message.rb, line 132 def tool_call? !tool_calls.nil? && !tool_calls.empty? end
Returns true if the assistant requested one or more tool calls, false otherwise.
Source
# File lib/ruby_llm/message.rb, line 168 def tool_call_stop? finish_reason == :tool_calls || (tool_call? && finish_reason == :stop) end
Returns true if the model stopped to request tool calls, false otherwise.
Source
# File lib/ruby_llm/message.rb, line 138 def tool_result? !tool_call_id.nil? && !tool_call_id.empty? end
Returns true if the message carries the result of a tool call, false otherwise.
Source
# File lib/ruby_llm/message.rb, line 145 def tool_results return [] unless tool_call? && conversation conversation.messages.select do |message| message.tool_result? && tool_calls.key?(message.tool_call_id) end end
Returns the tool result messages answering this message’s tool calls, or an empty array when it made none. Mirrors the tool_results association on acts_as_message records.