From ce1f6aa2247aa2736e9727b94061f628db5eface Mon Sep 17 00:00:00 2001 From: Noa Date: Sat, 30 Aug 2025 19:46:24 +0300 Subject: [PATCH 1/2] feat(Anthropic): Add native support for Anthropic system messages --- .../assistant/messages/anthropic_message.rb | 21 ++++++++-- .../messages/anthropic_message_spec.rb | 38 +++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/lib/langchain/assistant/messages/anthropic_message.rb b/lib/langchain/assistant/messages/anthropic_message.rb index 70f38209e..5ae3910b2 100644 --- a/lib/langchain/assistant/messages/anthropic_message.rb +++ b/lib/langchain/assistant/messages/anthropic_message.rb @@ -7,7 +7,8 @@ class AnthropicMessage < Base ROLES = [ "assistant", "user", - "tool_result" + "tool_result", + "system" ].freeze TOOL_ROLE = "tool_result" @@ -42,6 +43,8 @@ def initialize( def to_hash if assistant? assistant_hash + elsif system? + system_hash elsif tool? tool_hash elsif user? @@ -64,6 +67,16 @@ def assistant_hash } end + # Convert the message to an Anthropic API-compatible hash + # + # @return [Hash] The message as an Anthropic API-compatible hash, with the role as "system" + def system_hash + { + role: "system", + content: build_content_array + } + end + # Convert the message to an Anthropic API-compatible hash # # @return [Hash] The message as an Anthropic API-compatible hash, with the role as "user" @@ -125,9 +138,11 @@ def tool? role == "tool_result" end - # Anthropic does not implement system prompts + # Check if the message is a system message + # + # @return [Boolean] true/false whether this message is a system message def system? - false + role == "system" end # Check if the message came from an LLM diff --git a/spec/lib/langchain/assistant/messages/anthropic_message_spec.rb b/spec/lib/langchain/assistant/messages/anthropic_message_spec.rb index a1f04924e..266b54412 100644 --- a/spec/lib/langchain/assistant/messages/anthropic_message_spec.rb +++ b/spec/lib/langchain/assistant/messages/anthropic_message_spec.rb @@ -96,6 +96,32 @@ end end + context "when role is system" do + let(:role) { "system" } + + it "returns system_hash" do + message = described_class.new(role: role, content: "You are a helpful assistant.") + expect(message).to receive(:system_hash).and_call_original + expect(message.to_hash).to eq( + role: role, + content: [ + { + type: "text", + text: "You are a helpful assistant." + } + ] + ) + end + + it "returns system_hash without content" do + message = described_class.new(role: role, content: nil) + expect(message.to_hash).to eq( + role: role, + content: [] + ) + end + end + context "when role is tool_result" do let(:message) { described_class.new(role: "tool_result", content: "4.0", tool_call_id: "toolu_014eSx9oBA5DMe8gZqaqcJ3H") } @@ -153,4 +179,16 @@ end end end + + describe "#system?" do + it "returns true when role is system" do + message = described_class.new(role: "system", content: "You are a helpful assistant.") + expect(message.system?).to be true + end + + it "returns false when role is not system" do + message = described_class.new(role: "user", content: "Hello") + expect(message.system?).to be false + end + end end From 452ec0d8ad863c1f383c059a5ab4205233fa0cfb Mon Sep 17 00:00:00 2001 From: Noa Date: Sat, 30 Aug 2025 19:47:28 +0300 Subject: [PATCH 2/2] test(Anthropic): Update tests to expect correct behavior for system messages --- spec/lib/langchain/assistant/assistant_spec.rb | 6 +++++- spec/lib/langchain/assistant/llm/adapters/anthropic_spec.rb | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/spec/lib/langchain/assistant/assistant_spec.rb b/spec/lib/langchain/assistant/assistant_spec.rb index c7173cbc1..af7edfe70 100644 --- a/spec/lib/langchain/assistant/assistant_spec.rb +++ b/spec/lib/langchain/assistant/assistant_spec.rb @@ -1223,7 +1223,10 @@ before do allow(subject.llm).to receive(:chat) .with( - messages: [{role: "user", content: [{text: "Please calculate 2+2", type: "text"}]}], + messages: [ + {role: "system", content: [{text: instructions, type: "text"}]}, + {role: "user", content: [{text: "Please calculate 2+2", type: "text"}]} + ], tools: calculator.class.function_schemas.to_anthropic_format, tool_choice: {disable_parallel_tool_use: false, type: "auto"}, system: instructions @@ -1268,6 +1271,7 @@ allow(subject.llm).to receive(:chat) .with( messages: [ + {role: "system", content: [{text: instructions, type: "text"}]}, {role: "user", content: [{text: "Please calculate 2+2", type: "text"}]}, {role: "assistant", content: [ { diff --git a/spec/lib/langchain/assistant/llm/adapters/anthropic_spec.rb b/spec/lib/langchain/assistant/llm/adapters/anthropic_spec.rb index bcb7b603e..60bcaf77e 100644 --- a/spec/lib/langchain/assistant/llm/adapters/anthropic_spec.rb +++ b/spec/lib/langchain/assistant/llm/adapters/anthropic_spec.rb @@ -22,7 +22,7 @@ describe "#support_system_message?" do it "returns true" do - expect(subject.support_system_message?).to eq(false) + expect(subject.support_system_message?).to eq(true) end end