AssistantMessage

org.llm4s.llmconnect.model.AssistantMessage
See theAssistantMessage companion object
@Stable
final case class AssistantMessage extends Message

A response from the LLM, optionally containing text, tool-call requests, or both, and the reasoning the model produced before them.

content always returns a non-null String; it returns "" when the LLM response contains only tool calls and no accompanying text (contentOpt is None). Code that displays assistant output should check for an empty string rather than null-guarding.

A well-formed AssistantMessage must satisfy at least one of:

  • contentOpt.exists(_.trim.nonEmpty) — the LLM produced text.
  • toolCalls.nonEmpty — the LLM requested one or more tool invocations.

Thinking alone does not make a message well-formed.

Construct one with the companion apply and change it with the with* setters.

'''Sealed thinking.''' A signed ThinkingBlock.Text, a ThinkingBlock.Redacted or a ThinkingBlock.Opaque block is valid only in the conversation the provider produced it in. Anthropic signs a thinking block over everything sent before it - the system prompt, the tools and every earlier message - and rejects it once any of those changes; Bedrock documents its reasoning signature as a hash of all the messages in the conversation. Both also reject a block sent beside content or tool calls other than the ones it came with. Two rules keep llm4s from sending a signed turn that no longer holds:

  • '''Its own message.''' withContent and withToolCalls, given a value different from the current one, '''unseal''' the thinking: they drop redacted and opaque blocks, the signatures of text blocks and the binding, keeping the reasoning text.
  • '''Everything before it.''' The client that receives sealed thinking records, in thinkingBinding, a fingerprint of the request it answered and of who answered it: the provider and model, the system messages, the tools, the response format and every earlier message. When the message is sent again, the client replays its sealed thinking only if it is calling that provider and model and the conversation before it still has that fingerprint, and sends it unsealed otherwise - so a signature is never sent to a provider or model that did not produce it. So pruning, compression, summarisation, an edit or an insertion anywhere earlier in the history - by any code, through any API - unseals every later turn, without the code that made the change having to know about thinking.

Unsealed thinking keeps its text, which Anthropic and Bedrock leave out of the request and the other providers still receive. Earlier turns whose history is unchanged keep their sealed thinking, as Anthropic recommends: the blocks it accepts back are an unbroken run of the original sequence, and these rules never leave a gap, because unsealing one turn changes the history of every later one. To keep signed thinking, leave the message and everything before it as they are; to replace it deliberately, use withThinking.

Value parameters

contentOpt

Text portion of the response; None when the model produced only tool calls.

thinking

The model's reasoning, as the provider returned it; empty when there was none or the provider does not report it. Clients put it here so that it stays in the conversation history, and send it back where their provider accepts it (see ThinkingBlock).

thinkingBinding

A fingerprint of the request the sealed thinking was produced for, set by the client that received it; None when the thinking is not sealed or was not bound. Opaque. Sealed thinking without a binding matching the conversation before the message is not replayed (see "Sealed thinking" above).

toolCalls

Tool invocations requested by the model; each carries an id that must be matched by a subsequent ToolMessage.

Attributes

Companion
object
Graph
Supertypes
trait Serializable
trait Product
trait Equals
trait Message
class Object
trait Matchable
class Any
Show all

Members list

Value members

Concrete methods

def content: String
def hasSealedThinking: Boolean

Whether the thinking is sealed: it holds a signed text block or a redacted block, valid only with this exact content and these tool calls, after the history it was produced after (see "Sealed thinking" above).

Whether the thinking is sealed: it holds a signed text block or a redacted block, valid only with this exact content and these tool calls, after the history it was produced after (see "Sealed thinking" above).

Attributes

def hasThinking: Boolean

Whether the message carries any thinking, text or redacted.

Whether the message carries any thinking, text or redacted.

Attributes

def hasToolCalls: Boolean
def thinkingText: Option[String]

The text of the thinking blocks, concatenated; None when there is none.

The text of the thinking blocks, concatenated; None when there is none.

Attributes

override def toString: String

Returns a string representation of the object.

Returns a string representation of the object.

The default representation is platform dependent.

Attributes

Returns

a string representation of the object.

Definition Classes
Message -> Any
override def validate: Result[Message]

Validates that this message satisfies its role-specific content constraints.

Validates that this message satisfies its role-specific content constraints.

Returns Left(ValidationError) when content is blank; AssistantMessage additionally requires at least one of content or toolCalls to be present.

Attributes

Definition Classes
def withContent(content: String): AssistantMessage

Sets the content; a changed content unseals the thinking (see "Sealed thinking" above).

Sets the content; a changed content unseals the thinking (see "Sealed thinking" above).

Attributes

def withContent(content: Option[String]): AssistantMessage

Sets the content; a changed content unseals the thinking (see "Sealed thinking" above).

Sets the content; a changed content unseals the thinking (see "Sealed thinking" above).

Attributes

Replaces the thinking, sealed or not, as given, and clears the binding: sealed thinking set here is not replayed until a client binds it (see "Sealed thinking" above).

Replaces the thinking, sealed or not, as given, and clears the binding: sealed thinking set here is not replayed until a client binds it (see "Sealed thinking" above).

Attributes

def withThinking(text: String): AssistantMessage

Sets the thinking to text as one unsigned ThinkingBlock.Text, or to none when it is empty.

Sets the thinking to text as one unsigned ThinkingBlock.Text, or to none when it is empty.

Attributes

def withToolCalls(toolCalls: Seq[ToolCall]): AssistantMessage

Sets the tool calls; changed tool calls unseal the thinking (see "Sealed thinking" above).

Sets the tool calls; changed tool calls unseal the thinking (see "Sealed thinking" above).

Attributes

Inherited methods

def productElementNames: Iterator[String]

Attributes

Inherited from:
Product
def productIterator: Iterator[Any]

Attributes

Inherited from:
Product

Concrete fields