Version: ruby_llm 1.15.0
Description
RubyLLM::Providers::Anthropic::Chat#build_system_content logs a warning whenever a chat has more than one :system-role message:
# lib/ruby_llm/providers/anthropic/chat.rb:34-39
if system_messages.length > 1
RubyLLM.logger.warn(
"Anthropic's Claude implementation only supports a single system message. " \
'Multiple system messages will be combined into one.'
)
end
The warning is misleading: Anthropic's system parameter accepts an array of text content blocks (each optionally with cache_control), and the gem already correctly serializes multiple system messages into that array via flat_map:
system_messages.flat_map do |msg|
content = msg.content
if content.is_a?(RubyLLM::Content::Raw)
content.value
else
Media.format_content(content)
end
end
So passing two :system messages via chat.with_instructions(a).with_instructions(b, append: true) produces a valid two-element system: [...] payload, with each block's cache_control preserved. The warning's claim that the gem is "combining them into one" is no longer accurate (and Anthropic's API has accepted multi-block system content for years).
Impact
Applications that intentionally split system content into separate blocks — e.g., a static prompt + a per-conversation context envelope — get spurious log spew on every request. In high-throughput agent settings, this floods logs.
Reproduction
chat = RubyLLM.chat(model: 'claude-sonnet-4-6')
chat.with_instructions("Static prompt.")
chat.with_instructions("Per-session context.", append: true)
chat.ask("Hello")
# Logs: "Anthropic's Claude implementation only supports a single system message. ..."
# Actual API payload:
# system: [
# { type: "text", text: "Static prompt." },
# { type: "text", text: "Per-session context." }
# ]
# — correctly multi-block.
Suggested fix
Remove the length > 1 warning block. Optional: replace it with a brief comment documenting that multi-block system content is supported and is forwarded faithfully to Anthropic's system array.
If there's appetite, also add a test asserting that given two :system messages the rendered Anthropic payload contains two distinct text blocks (and per-block cache_control is preserved through the round-trip).
References
Happy to PR the fix.
Version: ruby_llm 1.15.0
Description
RubyLLM::Providers::Anthropic::Chat#build_system_contentlogs a warning whenever a chat has more than one:system-role message:The warning is misleading: Anthropic's
systemparameter accepts an array of text content blocks (each optionally withcache_control), and the gem already correctly serializes multiple system messages into that array viaflat_map:So passing two
:systemmessages viachat.with_instructions(a).with_instructions(b, append: true)produces a valid two-elementsystem: [...]payload, with each block'scache_controlpreserved. The warning's claim that the gem is "combining them into one" is no longer accurate (and Anthropic's API has accepted multi-block system content for years).Impact
Applications that intentionally split system content into separate blocks — e.g., a static prompt + a per-conversation context envelope — get spurious log spew on every request. In high-throughput agent settings, this floods logs.
Reproduction
Suggested fix
Remove the
length > 1warning block. Optional: replace it with a brief comment documenting that multi-block system content is supported and is forwarded faithfully to Anthropic'ssystemarray.If there's appetite, also add a test asserting that given two
:systemmessages the rendered Anthropic payload contains two distinct text blocks (and per-blockcache_controlis preserved through the round-trip).References
systemaccepts a string or an array of text content blocks.cache_controlonsystemblocks: https://docs.anthropic.com/en/docs/build-with-claude/prompt-cachingsystemcontent has been supported since the prompt-caching launch in August 2024 (announcement: https://www.anthropic.com/news/prompt-caching).anthropic-sdk-pythonshipssystem: Union[str, Iterable[TextBlockParam]]natively.:systemmessages without warning — seelib/ruby_llm/providers/bedrock/chat.rb.Happy to PR the fix.