Skip to content

Commit 0a27073

Browse files
Introduce support_system_message? method (#824)
* Introduce #support_system_message? in LLM adapter Definition of whether the adapter supports system message stays in adapter. That makes an assistant class unchangeable when new adapter would be introduced. * Add specs * Cleanup * fix linter --------- Co-authored-by: Karol Bajko <[email protected]>
1 parent d17719c commit 0a27073

File tree

15 files changed

+152
-16
lines changed

15 files changed

+152
-16
lines changed

lib/langchain/assistant.rb

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,13 @@ def initialize(
4848
self.messages = messages
4949
@tools = tools
5050
self.tool_choice = tool_choice
51-
@instructions = instructions
51+
self.instructions = instructions
5252
@block = block
5353
@state = :ready
5454

5555
@total_prompt_tokens = 0
5656
@total_completion_tokens = 0
5757
@total_tokens = 0
58-
59-
# The first message in the messages array should be the system instructions
60-
# For Google Gemini, and Anthropic system instructions are added to the `system:` param in the `chat` method
61-
initialize_instructions
6258
end
6359

6460
# Add a user message to the messages array
@@ -184,12 +180,9 @@ def clear_messages!
184180
def instructions=(new_instructions)
185181
@instructions = new_instructions
186182

187-
# This only needs to be done that support Message#@role="system"
188-
if !llm.is_a?(Langchain::LLM::GoogleGemini) &&
189-
!llm.is_a?(Langchain::LLM::GoogleVertexAI) &&
190-
!llm.is_a?(Langchain::LLM::Anthropic)
183+
if @llm_adapter.support_system_message?
191184
# Find message with role: "system" in messages and delete it from the messages array
192-
replace_system_message!(content: new_instructions)
185+
replace_system_message!(content: new_instructions) if @instructions
193186
end
194187
end
195188

@@ -323,12 +316,6 @@ def execute_tools
323316
:failed
324317
end
325318

326-
def initialize_instructions
327-
if llm.is_a?(Langchain::LLM::OpenAI) || llm.is_a?(Langchain::LLM::MistralAI)
328-
self.instructions = @instructions if @instructions
329-
end
330-
end
331-
332319
# Call to the LLM#chat() method
333320
#
334321
# @return [Langchain::LLM::BaseResponse] The LLM response object

lib/langchain/assistant/llm/adapters/anthropic.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ def tool_role
7070
Messages::AnthropicMessage::TOOL_ROLE
7171
end
7272

73+
def support_system_message?
74+
Messages::AnthropicMessage::ROLES.include?("system")
75+
end
76+
7377
private
7478

7579
def build_tool_choice(choice)

lib/langchain/assistant/llm/adapters/base.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ def build_message(role:, content: nil, image_url: nil, tool_calls: [], tool_call
3636
raise NotImplementedError, "Subclasses must implement build_message"
3737
end
3838

39+
# Does this adapter accept messages with role="system"?
40+
#
41+
# @return [Boolean] Whether the adapter supports system messages
42+
def support_system_message?
43+
raise NotImplementedError, "Subclasses must implement support_system_message?"
44+
end
45+
3946
# Role name used to return the tool output
4047
#
4148
# @return [String] The tool role

lib/langchain/assistant/llm/adapters/google_gemini.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ def tool_role
7070
Messages::GoogleGeminiMessage::TOOL_ROLE
7171
end
7272

73+
def support_system_message?
74+
Messages::GoogleGeminiMessage::ROLES.include?("system")
75+
end
76+
7377
private
7478

7579
def build_tool_config(choice)

lib/langchain/assistant/llm/adapters/mistral_ai.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ def tool_role
7272
Messages::MistralAIMessage::TOOL_ROLE
7373
end
7474

75+
def support_system_message?
76+
Messages::MistralAIMessage::ROLES.include?("system")
77+
end
78+
7579
private
7680

7781
def build_tool_choice(choice)

lib/langchain/assistant/llm/adapters/ollama.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ def tool_role
6868
Messages::OllamaMessage::TOOL_ROLE
6969
end
7070

71+
def support_system_message?
72+
Messages::OllamaMessage::ROLES.include?("system")
73+
end
74+
7175
private
7276

7377
def build_tools(tools)

lib/langchain/assistant/llm/adapters/openai.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ def tool_role
7272
Messages::OpenAIMessage::TOOL_ROLE
7373
end
7474

75+
def support_system_message?
76+
Messages::OpenAIMessage::ROLES.include?("system")
77+
end
78+
7579
private
7680

7781
def build_tool_choice(choice)

spec/langchain/assistant/assistant_spec.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,7 @@
472472
describe "#instructions=" do
473473
it "resets instructions" do
474474
subject.instructions = "New instructions"
475+
expect(subject.messages.first.role).to eq("system")
475476
expect(subject.messages.first.content).to eq("New instructions")
476477
expect(subject.instructions).to eq("New instructions")
477478
end
@@ -829,6 +830,7 @@
829830
describe "#instructions=" do
830831
it "resets instructions" do
831832
subject.instructions = "New instructions"
833+
expect(subject.messages.first.role).to eq("system")
832834
expect(subject.messages.first.content).to eq("New instructions")
833835
expect(subject.instructions).to eq("New instructions")
834836
end

spec/langchain/assistant/llm/adapters/.keep

Whitespace-only changes.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe Langchain::Assistant::LLM::Adapters::Anthropic do
4+
let(:adapter) { described_class.new }
5+
6+
describe "#support_system_message?" do
7+
it "returns true" do
8+
expect(adapter.support_system_message?).to eq(false)
9+
end
10+
end
11+
12+
describe "#tool_role" do
13+
it "returns 'tool'" do
14+
expect(adapter.tool_role).to eq("tool_result")
15+
end
16+
end
17+
end

0 commit comments

Comments
 (0)