# RubyLLM::Chat < Object

---
# Includes:
Enumerable
---
A Chat is a conversation with an AI model. It holds the messages exchanged so far, the tools the model may call, and the settings applied to each request. RubyLLM.chat is the usual way to create one.

    chat = RubyLLM.chat
    chat.ask "What's the best way to learn Ruby?"

Configuration methods return `self`, so calls chain:

    chat = RubyLLM.chat(model: 'claude-sonnet-4-5')
    chat.with_instructions("Be terse.").with_tools(Weather)

#ask runs the agentic loop to completion, executing tool calls until the model produces a final answer. #ask_later, #generate, #run_tools, and #step expose the individual moves of that loop.

A Chat is Enumerable over its messages.
---
# Class methods:

    new

# Instance methods:

    add_message
    after_fallback
    after_message
    after_tool_result
    ask
    ask_later
    before_fallback
    before_message
    before_request
    before_tool_call
    cache_until_here!
    caching
    complete
    complete?
    concurrency
    cost
    each
    fallbacks
    generate
    headers
    messages
    messages=
    model
    provider
    provider_options
    render
    run_tools
    say
    schema
    step
    tools
    with_caching
    with_citations
    with_context
    with_fallbacks
    with_headers
    with_instructions
    with_max_output_tokens
    with_model
    with_provider_options
    with_schema
    with_temperature
    with_thinking
    with_tool_options
    with_tools
    without_caching
    without_citations
    without_context
    without_fallbacks
    without_headers
    without_instructions
    without_max_output_tokens
    without_provider_options
    without_schema
    without_temperature
    without_thinking
    without_tool_options
    without_tools

# Attributes:

    attr_reader caching
    attr_reader concurrency
    attr_reader fallbacks
    attr_reader headers
    attr_reader messages
    attr_reader model
    attr_reader provider
    attr_reader provider_options
    attr_reader schema
    attr_reader tools

# RubyLLM::Chat::new
### Implementation from Chat
---
    new(model: nil, provider: nil, protocol: nil, assume_model_exists: false, context: nil)

---

Creates a chat with `model:`, or with the configured default model when `model:` is `nil`. Most code calls RubyLLM.chat instead.

A model is identified by its name, an optional `provider:`, and an optional `protocol:`. Pass `provider:` to disambiguate models available from several providers, and `protocol:` to override the wire protocol the provider would otherwise pick for the model. With `assume_model_exists: true` the registry lookup is skipped, which requires `provider:`. Pass a Context as `context:` to use its configuration instead of the global one.

# RubyLLM::Chat#add_message
### Implementation from Chat
---
    add_message(message_or_attributes)

---

Appends a message to the conversation and returns it as a Message. Accepts a Message, an attribute Hash, or a record responding to `to_llm`.

    chat.add_message(role: :user, content: "What's the capital of France?")

# RubyLLM::Chat#after_fallback
### Implementation from Chat
---
    after_fallback(&)

---

Registers a callback that receives the Fallback attempt once it has succeeded or failed. Returns `self`.

# RubyLLM::Chat#after_message
### Implementation from Chat
---
    after_message(&)

---

Registers a callback that receives each assistant response and each tool result message once it has been appended. Returns `self`.

    chat.after_message { |message| puts message.content }

# RubyLLM::Chat#after_tool_result
### Implementation from Chat
---
    after_tool_result(&)

---

Registers a callback that receives each tool's result after execution. Returns `self`.

# RubyLLM::Chat#ask
### Implementation from Chat
---
    ask(message = nil, with: nil, &)

---

Adds `message` to the conversation as a user message and runs the agentic loop to completion, executing tool calls along the way. Returns the final assistant Message. Attach files with `with:`. A given block receives streamed Chunk objects as they arrive.

    chat.ask "What's the best way to learn Ruby?"
    chat.ask "What's in this image?", with: "ruby_conf.jpg"
    chat.ask "Analyze these files", with: ["diagram.png", "report.pdf"]
    chat.ask("Tell me a story") { |chunk| print chunk.content }

# RubyLLM::Chat#ask_later
### Implementation from Chat
---
    ask_later(message = nil, with: nil)

---

Stages `message` as a user message without requesting a completion, leaving the chat ready for #complete, a single #step, or a provider-side batch via RubyLLM.batch. Accepts attachments with `with:` like #ask. Returns `self`.

    chats = tickets.map { |t| RubyLLM.chat.ask_later(t.body) }
    RubyLLM.batch(chats)

# RubyLLM::Chat#before_fallback
### Implementation from Chat
---
    before_fallback(&)

---

Registers a callback that receives the Fallback attempt after the current model fails and before the fallback model is tried. Returns `self`.

# RubyLLM::Chat#before_message
### Implementation from Chat
---
    before_message(&)

---

Registers a callback that runs before each assistant response or tool result is appended to the conversation. Callbacks are additive: every registered block runs. Returns `self`.

# RubyLLM::Chat#before_request
### Implementation from Chat
---
    before_request(&)

---

Registers a callback that receives the fully rendered request payload before it is sent and may mutate it in place. Runs after all RubyLLM formatting and #with_provider_options merging. Returns `self`.

    chat.before_request { |payload| logger.debug payload }

# RubyLLM::Chat#before_tool_call
### Implementation from Chat
---
    before_tool_call(&)

---

Registers a callback that receives each ToolCall before the tool executes. Returns `self`.

    chat.before_tool_call { |tool_call| puts tool_call.name }

# RubyLLM::Chat#cache_until_here!
### Implementation from Chat
---
    cache_until_here!()

---

Marks the latest message as an explicit prompt cache boundary, asking the provider to cache everything up to this point. Returns `self`.

Raises ArgumentError if the chat has no messages.

# RubyLLM::Chat#complete
### Implementation from Chat
---
    complete(&)

---

Runs the agentic loop until #complete? is `true` and returns the last non-system Message. Used after #ask_later; #ask stages a message and calls #complete for you.

# RubyLLM::Chat#complete?
### Implementation from Chat
---
    complete?()

---

Returns whether the model owes this chat nothing more: nothing is staged, or the model answered without calling a tool.

# RubyLLM::Chat#cost
### Implementation from Chat
---
    cost()

---

Returns a Cost aggregating the cost of every message in the conversation, priced by each message's own model.

    chat.cost.total

# RubyLLM::Chat#each
### Implementation from Chat
---
    each(&)

---

Yields each Message in the conversation. Returns an Enumerator when no block is given. Chat includes Enumerable, so the usual collection methods are available.

# RubyLLM::Chat#generate
### Implementation from Chat
---
    generate(&)

---

Requests one completion from the model, appends the response to the conversation, and returns it as a Message. Honors the fallbacks configured with #with_fallbacks. A given block receives streamed Chunk objects. Tool calls in the response are not executed; that is #run_tools.

# RubyLLM::Chat#messages=
### Implementation from Chat
---
    messages=(new_messages)

---

Replaces the conversation with `new_messages`, coercing each element into a Message. Accepts Message objects, attribute Hashes, and records responding to `to_llm`.

# RubyLLM::Chat#render
### Implementation from Chat
---
    render()

---

Returns the request payload this chat would send to the provider for its next completion, with #before_request hooks applied. Useful for inspecting and testing request output.

# RubyLLM::Chat#run_tools
### Implementation from Chat
---
    run_tools()

---

Executes the tool calls pending in the latest response and appends their result messages, without asking the model to respond. Does nothing when no tool calls are pending. The chat is then ready for the next #generate, or the next batch round. Returns `self`.

# RubyLLM::Chat#say
### Implementation from Chat
---
    say(message = nil, with: nil, &)

---

(This method is an alias for RubyLLM::Chat#ask.)

Adds `message` to the conversation as a user message and runs the agentic loop to completion, executing tool calls along the way. Returns the final assistant Message. Attach files with `with:`. A given block receives streamed Chunk objects as they arrive.

    chat.ask "What's the best way to learn Ruby?"
    chat.ask "What's in this image?", with: "ruby_conf.jpg"
    chat.ask "Analyze these files", with: ["diagram.png", "report.pdf"]
    chat.ask("Tell me a story") { |chunk| print chunk.content }

# RubyLLM::Chat#step
### Implementation from Chat
---
    step(&)

---

Advances the conversation by one move: runs the pending tool calls if the model asked for them, otherwise generates the next response. Returns `nil` once there is nothing left to do.

# RubyLLM::Chat#with_caching
### Implementation from Chat
---
    with_caching(options = {})

---

Enables provider prompt caching. With no arguments the provider's default behavior applies; options such as `ttl:` are passed through to providers that support them. Returns `self`.

    chat.with_caching
    chat.with_caching(ttl: "1h")

# RubyLLM::Chat#with_citations
### Implementation from Chat
---
    with_citations()

---

Enables document citations, so the model backs its claims with quotes from attached files. Returns `self`.

    chat.with_citations
    response = chat.ask "Who created Ruby?", with: "facts.txt"
    response.citations.each { |citation| puts citation.cited_text }

# RubyLLM::Chat#with_context
### Implementation from Chat
---
    with_context(context)

---

Rebinds the chat to `context`, a Context built with RubyLLM.context, so subsequent requests use its configuration. Returns `self`.

# RubyLLM::Chat#with_fallbacks
### Implementation from Chat
---
    with_fallbacks(*models, on: Fallback::DEFAULT_ERRORS)

---

Sets fallback models to try, in order, when generation fails. `on:` selects the error classes that trigger a fallback; the default covers transient provider and network errors. Returns `self`.

    chat.with_fallbacks("gpt-4.1-mini", "claude-haiku-4-5")

# RubyLLM::Chat#with_headers
### Implementation from Chat
---
    with_headers(headers)

---

Sets extra HTTP headers sent with completion requests, replacing any previously set headers. Returns `self`.

    chat.with_headers('anthropic-beta' => 'fine-grained-tool-streaming-2025-05-14')

# RubyLLM::Chat#with_instructions
### Implementation from Chat
---
    with_instructions(instructions, append: false)

---

Sets the system instructions for the conversation, replacing any existing system messages. With `append: true` the instructions are added alongside the existing ones. Returns `self`.

    chat.with_instructions "You are a helpful Ruby tutor."
    chat.with_instructions "Use exactly one short paragraph.", append: true

# RubyLLM::Chat#with_max_output_tokens
### Implementation from Chat
---
    with_max_output_tokens(max_output_tokens)

---

Caps the number of tokens the model may generate, mapping to each provider's request field (`max_tokens`, `max_output_tokens`, `maxOutputTokens`, and so on). Returns `self`.

    chat.with_max_output_tokens(1000)

# RubyLLM::Chat#with_model
### Implementation from Chat
---
    with_model(model_id, provider: nil, protocol: nil, assume_model_exists: false)

---

Switches the chat to `model_id` and its provider. Pass `provider:` to disambiguate, and `assume_model_exists: true` to skip registry validation for custom or private models. Pass `nil` to return to the configured default model. Returns `self`.

`protocol:` overrides the wire protocol the provider would pick for the model, such as `:responses` or `:chat_completions` for OpenAI. It stays `nil` by default, meaning the provider chooses the protocol for each request. A bare #with_model resets the override to `nil`, just as it re-resolves the provider from the model.

Raises ModelNotFoundError if `model_id` is not in the registry and `assume_model_exists:` is false.

    chat.with_model('claude-sonnet-4-5')
    chat.with_model('gpt-5.4', protocol: :chat_completions)

# RubyLLM::Chat#with_provider_options
### Implementation from Chat
---
    with_provider_options(provider_options)

---

Sets options in the provider's request vocabulary, merged into the request payload as-is and overriding RubyLLM's defaults. Replaces any previously set provider options. Returns `self`.

    chat.with_provider_options(max_output_tokens: 200)

# RubyLLM::Chat#with_schema
### Implementation from Chat
---
    with_schema(schema)

---

Sets the schema for structured output. Accepts a JSON Schema Hash, a RubyLLM::Schema class or instance, or any object responding to `to_json_schema`. Returns `self`.

    class PersonSchema < RubyLLM::Schema
      string :name
      integer :age
    end

    chat.with_schema(PersonSchema)
    response = chat.ask("Generate a person named Alice who is 30 years old")
    response.parsed # => {"name" => "Alice", "age" => 30}

# RubyLLM::Chat#with_temperature
### Implementation from Chat
---
    with_temperature(temperature)

---

Sets the sampling temperature for subsequent requests. Returns `self`.

    chat.with_temperature(0.2)

# RubyLLM::Chat#with_thinking
### Implementation from Chat
---
    with_thinking(*args, effort: nil, budget: nil)

---

Configures extended thinking for models that support it, with `effort:` (`:low`, `:medium`, `:high`, or `:none`) and/or `budget:` (a token count). Returns `self`.

Raises ArgumentError unless `effort:` or `budget:` is given.

    chat.with_thinking(effort: :high, budget: 8000)
    chat.with_thinking(budget: 10_000)

# RubyLLM::Chat#with_tool_options
### Implementation from Chat
---
    with_tool_options(choice: nil, calls: nil, concurrency: nil)

---

Configures how the model uses the registered tools. `choice:` constrains tool use to `:auto`, `:none`, `:required`, a tool name, or a Tool class. `calls:` limits how many tool calls one response may contain (`:many` or `:one`). `concurrency:` runs tool calls concurrently: `true` or `:threads` for threads, `:fibers` for fibers. A `nil` option is left unchanged. Returns `self`.

    chat.with_tools(Weather, Search).with_tool_options(choice: :required)
    chat.with_tool_options(calls: :one, concurrency: :threads)

# RubyLLM::Chat#with_tools
### Implementation from Chat
---
    with_tools(*tools)

---

Registers `tools`, each a Tool class or instance, for the model to call. Configure how the model uses them with #with_tool_options. Returns `self`.

    chat.with_tools(Weather, Search)
    chat.with_tools(Weather).with_tool_options(choice: :required)

To replace the registered tools, clear them first with #without_tools.

    chat.without_tools.with_tools(NewTool)

# RubyLLM::Chat#without_caching
### Implementation from Chat
---
    without_caching()

---

Disables prompt caching. Returns `self`.

# RubyLLM::Chat#without_citations
### Implementation from Chat
---
    without_citations()

---

Disables document citations. Returns `self`.

# RubyLLM::Chat#without_context
### Implementation from Chat
---
    without_context()

---

Removes the Context, returning the chat to the global RubyLLM.config. Returns `self`.

# RubyLLM::Chat#without_fallbacks
### Implementation from Chat
---
    without_fallbacks()

---

Removes all fallback models and restores the default fallback error classes. Returns `self`.

# RubyLLM::Chat#without_headers
### Implementation from Chat
---
    without_headers()

---

Removes all extra HTTP headers. Returns `self`.

# RubyLLM::Chat#without_instructions
### Implementation from Chat
---
    without_instructions()

---

Removes all system instructions from the conversation. Returns `self`.

# RubyLLM::Chat#without_max_output_tokens
### Implementation from Chat
---
    without_max_output_tokens()

---

Removes the output token limit, letting the provider use its default. Returns `self`.

# RubyLLM::Chat#without_provider_options
### Implementation from Chat
---
    without_provider_options()

---

Removes all provider request options. Returns `self`.

# RubyLLM::Chat#without_schema
### Implementation from Chat
---
    without_schema()

---

Removes the structured output schema, returning the chat to plain text responses. Returns `self`.

# RubyLLM::Chat#without_temperature
### Implementation from Chat
---
    without_temperature()

---

Removes the temperature override, returning the chat to the model's default sampling behavior. Returns `self`.

# RubyLLM::Chat#without_thinking
### Implementation from Chat
---
    without_thinking()

---

Clears the thinking configuration, returning to the model's default behavior. Returns `self`.

# RubyLLM::Chat#without_tool_options
### Implementation from Chat
---
    without_tool_options()

---

Resets the options set with #with_tool_options: `choice:` and `calls:` return to unset, `concurrency:` to the configured default. Returns `self`.

# RubyLLM::Chat#without_tools
### Implementation from Chat
---
    without_tools()

---

Removes all registered tools, leaving the options set with #with_tool_options unchanged. Returns `self`.
