pub enum AssistantBlock {
Text(TextContent),
Thinking(TextContent),
Reasoning(TextContent),
ReasoningDetails(ReasoningDetailsContent),
ToolCall(ToolCall),
}Expand description
Blocks an assistant message can carry.
§Channel separation contract
Thinking and Reasoning are two independent channels and the
loop must never mix them:
-
Thinkingis prompt-elicited tag-text. The model wraps reasoning inside<thought>...</thought>(or one of the synonym tags handled bycrate::ThinkingTagStreamFilter) inside its visible text stream. The bridge parses those tags out of the visible-text channel and stores the captured content here. On the next provider request it is rewoven into thecontentfield as a<thought>...</thought>tag — never as the wirereasoningfield. -
ReasoningandReasoningDetailsare provider-native reasoning. They arrive on a dedicated sideband (delta.reasoning/delta.reasoning_detailson the OpenRouter wire) and represent the provider’s own chain-of-thought tokens. On the next provider request they are replayed verbatim through the typedreasoning/reasoning_detailsfields — never wrapped in a<thought>...</thought>tag in thecontentfield.
The two processes are not interchangeable: tag-elicited scratch is
the model writing into its visible output by convention, and the
loop strips it before the user sees anything. Provider-native
reasoning is the upstream API delivering structured thinking
alongside the message. Conflating them risks (a) shipping the
model’s hidden scratch as if it were native reasoning (some
providers reject unknown content there or refuse to bill it as
cached input) and (b) leaking native reasoning into visible text
by way of <thought> rewrap (would round-trip native tokens
through the visible channel and double-count them).
The invariants are pinned by tests in
openrouter_request_tests.rs::channel_separation_invariants and
openrouter_stream::tests::stream_chunk_routing_invariants.
Variants§
Text(TextContent)
Thinking(TextContent)
Prompt-elicited hidden scratchpad. Captured from
<thought>...</thought> tags the model writes inside its
visible text stream; rewoven into the wire content field as
<thought>...</thought> on the next request. Never flows
into the wire reasoning field — see the type-level docs for
the channel-separation contract.
Reasoning(TextContent)
Provider-native reasoning (xAI Grok, OpenAI o-series, Anthropic
native thinking). Arrives on the dedicated delta.reasoning
sideband and replayed via the wire reasoning field. Never
wrapped in a <thought>...</thought> tag inside the content
field — see the type-level docs.
ReasoningDetails(ReasoningDetailsContent)
Native provider reasoning detail blocks (xAI’s
reasoning.encrypted envelopes, etc.). Replayed unmodified on
tool-continuation requests for reasoning models that rely on
signed/encrypted thinking continuity. Same channel contract as
Reasoning.
ToolCall(ToolCall)
Tool call request. Loop dispatches via the registry.
Trait Implementations§
Source§impl Clone for AssistantBlock
impl Clone for AssistantBlock
Source§fn clone(&self) -> AssistantBlock
fn clone(&self) -> AssistantBlock
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for AssistantBlock
impl Debug for AssistantBlock
Source§impl<'de> Deserialize<'de> for AssistantBlock
impl<'de> Deserialize<'de> for AssistantBlock
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl PartialEq for AssistantBlock
impl PartialEq for AssistantBlock
Source§fn eq(&self, other: &AssistantBlock) -> bool
fn eq(&self, other: &AssistantBlock) -> bool
self and other values to be equal, and is used by ==.