langchainrb 0.17.1 → 0.18.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +5 -0
- data/lib/langchain/{assistants → assistant}/llm/adapter.rb +1 -1
- data/lib/langchain/assistant/llm/adapters/anthropic.rb +105 -0
- data/lib/langchain/assistant/llm/adapters/base.rb +63 -0
- data/lib/langchain/{assistants → assistant}/llm/adapters/google_gemini.rb +43 -3
- data/lib/langchain/{assistants → assistant}/llm/adapters/mistral_ai.rb +39 -2
- data/lib/langchain/assistant/llm/adapters/ollama.rb +94 -0
- data/lib/langchain/{assistants → assistant}/llm/adapters/openai.rb +38 -2
- data/lib/langchain/assistant/messages/anthropic_message.rb +77 -0
- data/lib/langchain/assistant/messages/base.rb +56 -0
- data/lib/langchain/assistant/messages/google_gemini_message.rb +92 -0
- data/lib/langchain/assistant/messages/mistral_ai_message.rb +98 -0
- data/lib/langchain/assistant/messages/ollama_message.rb +76 -0
- data/lib/langchain/assistant/messages/openai_message.rb +105 -0
- data/lib/langchain/{assistants/assistant.rb → assistant.rb} +26 -49
- data/lib/langchain/llm/ai21.rb +1 -1
- data/lib/langchain/llm/anthropic.rb +59 -4
- data/lib/langchain/llm/aws_bedrock.rb +6 -7
- data/lib/langchain/llm/azure.rb +1 -1
- data/lib/langchain/llm/hugging_face.rb +1 -1
- data/lib/langchain/llm/ollama.rb +0 -1
- data/lib/langchain/llm/openai.rb +2 -2
- data/lib/langchain/llm/parameters/chat.rb +1 -0
- data/lib/langchain/llm/replicate.rb +2 -10
- data/lib/langchain/version.rb +1 -1
- data/lib/langchain.rb +1 -14
- metadata +16 -16
- data/lib/langchain/assistants/llm/adapters/_base.rb +0 -21
- data/lib/langchain/assistants/llm/adapters/anthropic.rb +0 -62
- data/lib/langchain/assistants/llm/adapters/ollama.rb +0 -57
- data/lib/langchain/assistants/messages/anthropic_message.rb +0 -75
- data/lib/langchain/assistants/messages/base.rb +0 -54
- data/lib/langchain/assistants/messages/google_gemini_message.rb +0 -90
- data/lib/langchain/assistants/messages/mistral_ai_message.rb +0 -96
- data/lib/langchain/assistants/messages/ollama_message.rb +0 -74
- data/lib/langchain/assistants/messages/openai_message.rb +0 -103
@@ -7,12 +7,13 @@ module Langchain::LLM
|
|
7
7
|
# gem 'aws-sdk-bedrockruntime', '~> 1.1'
|
8
8
|
#
|
9
9
|
# Usage:
|
10
|
-
#
|
10
|
+
# llm = Langchain::LLM::AwsBedrock.new(llm_options: {})
|
11
11
|
#
|
12
12
|
class AwsBedrock < Base
|
13
13
|
DEFAULTS = {
|
14
|
+
chat_completion_model_name: "anthropic.claude-v2",
|
14
15
|
completion_model_name: "anthropic.claude-v2",
|
15
|
-
|
16
|
+
embeddings_model_name: "amazon.titan-embed-text-v1",
|
16
17
|
max_tokens_to_sample: 300,
|
17
18
|
temperature: 1,
|
18
19
|
top_k: 250,
|
@@ -52,13 +53,11 @@ module Langchain::LLM
|
|
52
53
|
SUPPORTED_CHAT_COMPLETION_PROVIDERS = %i[anthropic].freeze
|
53
54
|
SUPPORTED_EMBEDDING_PROVIDERS = %i[amazon cohere].freeze
|
54
55
|
|
55
|
-
def initialize(
|
56
|
+
def initialize(aws_client_options: {}, default_options: {})
|
56
57
|
depends_on "aws-sdk-bedrockruntime", req: "aws-sdk-bedrockruntime"
|
57
58
|
|
58
59
|
@client = ::Aws::BedrockRuntime::Client.new(**aws_client_options)
|
59
60
|
@defaults = DEFAULTS.merge(default_options)
|
60
|
-
.merge(completion_model_name: completion_model)
|
61
|
-
.merge(embedding_model_name: embedding_model)
|
62
61
|
|
63
62
|
chat_parameters.update(
|
64
63
|
model: {default: @defaults[:chat_completion_model_name]},
|
@@ -85,7 +84,7 @@ module Langchain::LLM
|
|
85
84
|
parameters = compose_embedding_parameters params.merge(text:)
|
86
85
|
|
87
86
|
response = client.invoke_model({
|
88
|
-
model_id: @defaults[:
|
87
|
+
model_id: @defaults[:embeddings_model_name],
|
89
88
|
body: parameters.to_json,
|
90
89
|
content_type: "application/json",
|
91
90
|
accept: "application/json"
|
@@ -180,7 +179,7 @@ module Langchain::LLM
|
|
180
179
|
end
|
181
180
|
|
182
181
|
def embedding_provider
|
183
|
-
@defaults[:
|
182
|
+
@defaults[:embeddings_model_name].split(".").first.to_sym
|
184
183
|
end
|
185
184
|
|
186
185
|
def wrap_prompt(prompt)
|
data/lib/langchain/llm/azure.rb
CHANGED
@@ -7,7 +7,7 @@ module Langchain::LLM
|
|
7
7
|
# gem "ruby-openai", "~> 6.3.0"
|
8
8
|
#
|
9
9
|
# Usage:
|
10
|
-
#
|
10
|
+
# llm = Langchain::LLM::Azure.new(api_key:, llm_options: {}, embedding_deployment_url: chat_deployment_url:)
|
11
11
|
#
|
12
12
|
class Azure < OpenAI
|
13
13
|
attr_reader :embed_client
|
@@ -8,7 +8,7 @@ module Langchain::LLM
|
|
8
8
|
# gem "hugging-face", "~> 0.3.4"
|
9
9
|
#
|
10
10
|
# Usage:
|
11
|
-
#
|
11
|
+
# llm = Langchain::LLM::HuggingFace.new(api_key: ENV["HUGGING_FACE_API_KEY"])
|
12
12
|
#
|
13
13
|
class HuggingFace < Base
|
14
14
|
DEFAULTS = {
|
data/lib/langchain/llm/ollama.rb
CHANGED
data/lib/langchain/llm/openai.rb
CHANGED
@@ -7,7 +7,7 @@ module Langchain::LLM
|
|
7
7
|
# gem "ruby-openai", "~> 6.3.0"
|
8
8
|
#
|
9
9
|
# Usage:
|
10
|
-
#
|
10
|
+
# llm = Langchain::LLM::OpenAI.new(
|
11
11
|
# api_key: ENV["OPENAI_API_KEY"],
|
12
12
|
# llm_options: {}, # Available options: https://github.com/alexrudall/ruby-openai/blob/main/lib/openai/client.rb#L5-L13
|
13
13
|
# default_options: {}
|
@@ -100,7 +100,7 @@ module Langchain::LLM
|
|
100
100
|
# @param params [Hash] The parameters to pass to the `chat()` method
|
101
101
|
# @return [Langchain::LLM::OpenAIResponse] Response object
|
102
102
|
def complete(prompt:, **params)
|
103
|
-
warn "DEPRECATED: `Langchain::LLM::OpenAI#complete` is deprecated, and will be removed in the next major version. Use `Langchain::LLM::OpenAI#chat` instead."
|
103
|
+
Langchain.logger.warn "DEPRECATED: `Langchain::LLM::OpenAI#complete` is deprecated, and will be removed in the next major version. Use `Langchain::LLM::OpenAI#chat` instead."
|
104
104
|
|
105
105
|
if params[:stop_sequences]
|
106
106
|
params[:stop] = params.delete(:stop_sequences)
|
@@ -7,16 +7,8 @@ module Langchain::LLM
|
|
7
7
|
# Gem requirements:
|
8
8
|
# gem "replicate-ruby", "~> 0.2.2"
|
9
9
|
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
# Or pass it to be used by a vector search DB:
|
14
|
-
# chroma = Langchain::Vectorsearch::Chroma.new(
|
15
|
-
# url: ENV["CHROMA_URL"],
|
16
|
-
# index_name: "...",
|
17
|
-
# llm: replicate
|
18
|
-
# )
|
19
|
-
#
|
10
|
+
# Usage:
|
11
|
+
# llm = Langchain::LLM::Replicate.new(api_key: ENV["REPLICATE_API_KEY"])
|
20
12
|
class Replicate < Base
|
21
13
|
DEFAULTS = {
|
22
14
|
# TODO: Figure out how to send the temperature to the API
|
data/lib/langchain/version.rb
CHANGED
data/lib/langchain.rb
CHANGED
@@ -22,25 +22,12 @@ loader.inflector.inflect(
|
|
22
22
|
"mistral_ai_response" => "MistralAIResponse",
|
23
23
|
"mistral_ai_message" => "MistralAIMessage",
|
24
24
|
"openai" => "OpenAI",
|
25
|
-
"openai_validator" => "OpenAIValidator",
|
26
25
|
"openai_response" => "OpenAIResponse",
|
27
26
|
"openai_message" => "OpenAIMessage",
|
28
27
|
"pdf" => "PDF"
|
29
28
|
)
|
29
|
+
|
30
30
|
loader.collapse("#{__dir__}/langchain/llm/response")
|
31
|
-
loader.collapse("#{__dir__}/langchain/assistants")
|
32
|
-
|
33
|
-
loader.collapse("#{__dir__}/langchain/tool/calculator")
|
34
|
-
loader.collapse("#{__dir__}/langchain/tool/database")
|
35
|
-
loader.collapse("#{__dir__}/langchain/tool/docs_tool")
|
36
|
-
loader.collapse("#{__dir__}/langchain/tool/file_system")
|
37
|
-
loader.collapse("#{__dir__}/langchain/tool/google_search")
|
38
|
-
loader.collapse("#{__dir__}/langchain/tool/ruby_code_interpreter")
|
39
|
-
loader.collapse("#{__dir__}/langchain/tool/news_retriever")
|
40
|
-
loader.collapse("#{__dir__}/langchain/tool/tavily")
|
41
|
-
loader.collapse("#{__dir__}/langchain/tool/vectorsearch")
|
42
|
-
loader.collapse("#{__dir__}/langchain/tool/weather")
|
43
|
-
loader.collapse("#{__dir__}/langchain/tool/wikipedia")
|
44
31
|
|
45
32
|
# RubyCodeInterpreter does not work with Ruby 3.3;
|
46
33
|
# https://github.com/ukutaht/safe_ruby/issues/4
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: langchainrb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.18.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrei Bondarev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-10-
|
11
|
+
date: 2024-10-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: baran
|
@@ -637,20 +637,20 @@ files:
|
|
637
637
|
- LICENSE.txt
|
638
638
|
- README.md
|
639
639
|
- lib/langchain.rb
|
640
|
-
- lib/langchain/
|
641
|
-
- lib/langchain/
|
642
|
-
- lib/langchain/
|
643
|
-
- lib/langchain/
|
644
|
-
- lib/langchain/
|
645
|
-
- lib/langchain/
|
646
|
-
- lib/langchain/
|
647
|
-
- lib/langchain/
|
648
|
-
- lib/langchain/
|
649
|
-
- lib/langchain/
|
650
|
-
- lib/langchain/
|
651
|
-
- lib/langchain/
|
652
|
-
- lib/langchain/
|
653
|
-
- lib/langchain/
|
640
|
+
- lib/langchain/assistant.rb
|
641
|
+
- lib/langchain/assistant/llm/adapter.rb
|
642
|
+
- lib/langchain/assistant/llm/adapters/anthropic.rb
|
643
|
+
- lib/langchain/assistant/llm/adapters/base.rb
|
644
|
+
- lib/langchain/assistant/llm/adapters/google_gemini.rb
|
645
|
+
- lib/langchain/assistant/llm/adapters/mistral_ai.rb
|
646
|
+
- lib/langchain/assistant/llm/adapters/ollama.rb
|
647
|
+
- lib/langchain/assistant/llm/adapters/openai.rb
|
648
|
+
- lib/langchain/assistant/messages/anthropic_message.rb
|
649
|
+
- lib/langchain/assistant/messages/base.rb
|
650
|
+
- lib/langchain/assistant/messages/google_gemini_message.rb
|
651
|
+
- lib/langchain/assistant/messages/mistral_ai_message.rb
|
652
|
+
- lib/langchain/assistant/messages/ollama_message.rb
|
653
|
+
- lib/langchain/assistant/messages/openai_message.rb
|
654
654
|
- lib/langchain/chunk.rb
|
655
655
|
- lib/langchain/chunker/base.rb
|
656
656
|
- lib/langchain/chunker/markdown.rb
|
@@ -1,21 +0,0 @@
|
|
1
|
-
module Langchain
|
2
|
-
class Assistant
|
3
|
-
module LLM
|
4
|
-
module Adapters
|
5
|
-
class Base
|
6
|
-
def build_chat_params(tools:, instructions:, messages:, tool_choice:)
|
7
|
-
raise NotImplementedError, "Subclasses must implement build_chat_params"
|
8
|
-
end
|
9
|
-
|
10
|
-
def extract_tool_call_args(tool_call:)
|
11
|
-
raise NotImplementedError, "Subclasses must implement extract_tool_call_args"
|
12
|
-
end
|
13
|
-
|
14
|
-
def build_message(role:, content: nil, image_url: nil, tool_calls: [], tool_call_id: nil)
|
15
|
-
raise NotImplementedError, "Subclasses must implement build_message"
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,62 +0,0 @@
|
|
1
|
-
module Langchain
|
2
|
-
class Assistant
|
3
|
-
module LLM
|
4
|
-
module Adapters
|
5
|
-
class Anthropic < Base
|
6
|
-
def build_chat_params(tools:, instructions:, messages:, tool_choice:)
|
7
|
-
params = {messages: messages}
|
8
|
-
if tools.any?
|
9
|
-
params[:tools] = build_tools(tools)
|
10
|
-
params[:tool_choice] = build_tool_choice(tool_choice)
|
11
|
-
end
|
12
|
-
params[:system] = instructions if instructions
|
13
|
-
params
|
14
|
-
end
|
15
|
-
|
16
|
-
def build_message(role:, content: nil, image_url: nil, tool_calls: [], tool_call_id: nil)
|
17
|
-
warn "Image URL is not supported by Anthropic currently" if image_url
|
18
|
-
|
19
|
-
Langchain::Messages::AnthropicMessage.new(role: role, content: content, tool_calls: tool_calls, tool_call_id: tool_call_id)
|
20
|
-
end
|
21
|
-
|
22
|
-
# Extract the tool call information from the Anthropic tool call hash
|
23
|
-
#
|
24
|
-
# @param tool_call [Hash] The tool call hash, format: {"type"=>"tool_use", "id"=>"toolu_01TjusbFApEbwKPRWTRwzadR", "name"=>"news_retriever__get_top_headlines", "input"=>{"country"=>"us", "page_size"=>10}}], "stop_reason"=>"tool_use"}
|
25
|
-
# @return [Array] The tool call information
|
26
|
-
def extract_tool_call_args(tool_call:)
|
27
|
-
tool_call_id = tool_call.dig("id")
|
28
|
-
function_name = tool_call.dig("name")
|
29
|
-
tool_name, method_name = function_name.split("__")
|
30
|
-
tool_arguments = tool_call.dig("input").transform_keys(&:to_sym)
|
31
|
-
[tool_call_id, tool_name, method_name, tool_arguments]
|
32
|
-
end
|
33
|
-
|
34
|
-
def build_tools(tools)
|
35
|
-
tools.map { |tool| tool.class.function_schemas.to_anthropic_format }.flatten
|
36
|
-
end
|
37
|
-
|
38
|
-
def allowed_tool_choices
|
39
|
-
["auto", "any"]
|
40
|
-
end
|
41
|
-
|
42
|
-
def available_tool_names(tools)
|
43
|
-
build_tools(tools).map { |tool| tool.dig(:name) }
|
44
|
-
end
|
45
|
-
|
46
|
-
private
|
47
|
-
|
48
|
-
def build_tool_choice(choice)
|
49
|
-
case choice
|
50
|
-
when "auto"
|
51
|
-
{type: "auto"}
|
52
|
-
when "any"
|
53
|
-
{type: "any"}
|
54
|
-
else
|
55
|
-
{type: "tool", name: choice}
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
module Langchain
|
2
|
-
class Assistant
|
3
|
-
module LLM
|
4
|
-
module Adapters
|
5
|
-
class Ollama < Base
|
6
|
-
def build_chat_params(tools:, instructions:, messages:, tool_choice:)
|
7
|
-
params = {messages: messages}
|
8
|
-
if tools.any?
|
9
|
-
params[:tools] = build_tools(tools)
|
10
|
-
end
|
11
|
-
params
|
12
|
-
end
|
13
|
-
|
14
|
-
def build_message(role:, content: nil, image_url: nil, tool_calls: [], tool_call_id: nil)
|
15
|
-
warn "Image URL is not supported by Ollama currently" if image_url
|
16
|
-
|
17
|
-
Langchain::Messages::OllamaMessage.new(role: role, content: content, tool_calls: tool_calls, tool_call_id: tool_call_id)
|
18
|
-
end
|
19
|
-
|
20
|
-
# Extract the tool call information from the OpenAI tool call hash
|
21
|
-
#
|
22
|
-
# @param tool_call [Hash] The tool call hash
|
23
|
-
# @return [Array] The tool call information
|
24
|
-
def extract_tool_call_args(tool_call:)
|
25
|
-
tool_call_id = tool_call.dig("id")
|
26
|
-
|
27
|
-
function_name = tool_call.dig("function", "name")
|
28
|
-
tool_name, method_name = function_name.split("__")
|
29
|
-
|
30
|
-
tool_arguments = tool_call.dig("function", "arguments")
|
31
|
-
tool_arguments = if tool_arguments.is_a?(Hash)
|
32
|
-
Langchain::Utils::HashTransformer.symbolize_keys(tool_arguments)
|
33
|
-
else
|
34
|
-
JSON.parse(tool_arguments, symbolize_names: true)
|
35
|
-
end
|
36
|
-
|
37
|
-
[tool_call_id, tool_name, method_name, tool_arguments]
|
38
|
-
end
|
39
|
-
|
40
|
-
def available_tool_names(tools)
|
41
|
-
build_tools(tools).map { |tool| tool.dig(:function, :name) }
|
42
|
-
end
|
43
|
-
|
44
|
-
def allowed_tool_choices
|
45
|
-
["auto", "none"]
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
def build_tools(tools)
|
51
|
-
tools.map { |tool| tool.class.function_schemas.to_openai_format }.flatten
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
@@ -1,75 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Langchain
|
4
|
-
module Messages
|
5
|
-
class AnthropicMessage < Base
|
6
|
-
ROLES = [
|
7
|
-
"assistant",
|
8
|
-
"user",
|
9
|
-
"tool_result"
|
10
|
-
].freeze
|
11
|
-
|
12
|
-
TOOL_ROLE = "tool_result"
|
13
|
-
|
14
|
-
def initialize(role:, content: nil, tool_calls: [], tool_call_id: nil)
|
15
|
-
raise ArgumentError, "Role must be one of #{ROLES.join(", ")}" unless ROLES.include?(role)
|
16
|
-
raise ArgumentError, "Tool calls must be an array of hashes" unless tool_calls.is_a?(Array) && tool_calls.all? { |tool_call| tool_call.is_a?(Hash) }
|
17
|
-
|
18
|
-
@role = role
|
19
|
-
# Some Tools return content as a JSON hence `.to_s`
|
20
|
-
@content = content.to_s
|
21
|
-
@tool_calls = tool_calls
|
22
|
-
@tool_call_id = tool_call_id
|
23
|
-
end
|
24
|
-
|
25
|
-
# Convert the message to an Anthropic API-compatible hash
|
26
|
-
#
|
27
|
-
# @return [Hash] The message as an Anthropic API-compatible hash
|
28
|
-
def to_hash
|
29
|
-
{}.tap do |h|
|
30
|
-
h[:role] = tool? ? "user" : role
|
31
|
-
|
32
|
-
h[:content] = if tool?
|
33
|
-
[
|
34
|
-
{
|
35
|
-
type: "tool_result",
|
36
|
-
tool_use_id: tool_call_id,
|
37
|
-
content: content
|
38
|
-
}
|
39
|
-
]
|
40
|
-
elsif tool_calls.any?
|
41
|
-
tool_calls
|
42
|
-
else
|
43
|
-
content
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
# Check if the message is a tool call
|
49
|
-
#
|
50
|
-
# @return [Boolean] true/false whether this message is a tool call
|
51
|
-
def tool?
|
52
|
-
role == "tool_result"
|
53
|
-
end
|
54
|
-
|
55
|
-
# Anthropic does not implement system prompts
|
56
|
-
def system?
|
57
|
-
false
|
58
|
-
end
|
59
|
-
|
60
|
-
# Check if the message came from an LLM
|
61
|
-
#
|
62
|
-
# @return [Boolean] true/false whether this message was produced by an LLM
|
63
|
-
def assistant?
|
64
|
-
role == "assistant"
|
65
|
-
end
|
66
|
-
|
67
|
-
# Check if the message came from an LLM
|
68
|
-
#
|
69
|
-
# @return [Boolean] true/false whether this message was produced by an LLM
|
70
|
-
def llm?
|
71
|
-
assistant?
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
@@ -1,54 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Langchain
|
4
|
-
module Messages
|
5
|
-
class Base
|
6
|
-
attr_reader :role,
|
7
|
-
:content,
|
8
|
-
:image_url,
|
9
|
-
:tool_calls,
|
10
|
-
:tool_call_id
|
11
|
-
|
12
|
-
# Check if the message came from a user
|
13
|
-
#
|
14
|
-
# @return [Boolean] true/false whether the message came from a user
|
15
|
-
def user?
|
16
|
-
role == "user"
|
17
|
-
end
|
18
|
-
|
19
|
-
# Check if the message came from an LLM
|
20
|
-
#
|
21
|
-
# @raise NotImplementedError if the subclass does not implement this method
|
22
|
-
def llm?
|
23
|
-
raise NotImplementedError, "Class #{self.class.name} must implement the method 'llm?'"
|
24
|
-
end
|
25
|
-
|
26
|
-
# Check if the message is a tool call
|
27
|
-
#
|
28
|
-
# @raise NotImplementedError if the subclass does not implement this method
|
29
|
-
def tool?
|
30
|
-
raise NotImplementedError, "Class #{self.class.name} must implement the method 'tool?'"
|
31
|
-
end
|
32
|
-
|
33
|
-
# Check if the message is a system prompt
|
34
|
-
#
|
35
|
-
# @raise NotImplementedError if the subclass does not implement this method
|
36
|
-
def system?
|
37
|
-
raise NotImplementedError, "Class #{self.class.name} must implement the method 'system?'"
|
38
|
-
end
|
39
|
-
|
40
|
-
# Returns the standardized role symbol based on the specific role methods
|
41
|
-
#
|
42
|
-
# @return [Symbol] the standardized role symbol (:system, :llm, :tool, :user, or :unknown)
|
43
|
-
def standard_role
|
44
|
-
return :user if user?
|
45
|
-
return :llm if llm?
|
46
|
-
return :tool if tool?
|
47
|
-
return :system if system?
|
48
|
-
|
49
|
-
# TODO: Should we return :unknown or raise an error?
|
50
|
-
:unknown
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
@@ -1,90 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Langchain
|
4
|
-
module Messages
|
5
|
-
class GoogleGeminiMessage < Base
|
6
|
-
# Google Gemini uses the following roles:
|
7
|
-
ROLES = [
|
8
|
-
"user",
|
9
|
-
"model",
|
10
|
-
"function"
|
11
|
-
].freeze
|
12
|
-
|
13
|
-
TOOL_ROLE = "function"
|
14
|
-
|
15
|
-
# Initialize a new Google Gemini message
|
16
|
-
#
|
17
|
-
# @param [String] The role of the message
|
18
|
-
# @param [String] The content of the message
|
19
|
-
# @param [Array<Hash>] The tool calls made in the message
|
20
|
-
# @param [String] The ID of the tool call
|
21
|
-
def initialize(role:, content: nil, tool_calls: [], tool_call_id: nil)
|
22
|
-
raise ArgumentError, "Role must be one of #{ROLES.join(", ")}" unless ROLES.include?(role)
|
23
|
-
raise ArgumentError, "Tool calls must be an array of hashes" unless tool_calls.is_a?(Array) && tool_calls.all? { |tool_call| tool_call.is_a?(Hash) }
|
24
|
-
|
25
|
-
@role = role
|
26
|
-
# Some Tools return content as a JSON hence `.to_s`
|
27
|
-
@content = content.to_s
|
28
|
-
@tool_calls = tool_calls
|
29
|
-
@tool_call_id = tool_call_id
|
30
|
-
end
|
31
|
-
|
32
|
-
# Check if the message came from an LLM
|
33
|
-
#
|
34
|
-
# @return [Boolean] true/false whether this message was produced by an LLM
|
35
|
-
def llm?
|
36
|
-
model?
|
37
|
-
end
|
38
|
-
|
39
|
-
# Convert the message to a Google Gemini API-compatible hash
|
40
|
-
#
|
41
|
-
# @return [Hash] The message as a Google Gemini API-compatible hash
|
42
|
-
def to_hash
|
43
|
-
{}.tap do |h|
|
44
|
-
h[:role] = role
|
45
|
-
h[:parts] = if function?
|
46
|
-
[{
|
47
|
-
functionResponse: {
|
48
|
-
name: tool_call_id,
|
49
|
-
response: {
|
50
|
-
name: tool_call_id,
|
51
|
-
content: content
|
52
|
-
}
|
53
|
-
}
|
54
|
-
}]
|
55
|
-
elsif tool_calls.any?
|
56
|
-
tool_calls
|
57
|
-
else
|
58
|
-
[{text: content}]
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
# Google Gemini does not implement system prompts
|
64
|
-
def system?
|
65
|
-
false
|
66
|
-
end
|
67
|
-
|
68
|
-
# Check if the message is a tool call
|
69
|
-
#
|
70
|
-
# @return [Boolean] true/false whether this message is a tool call
|
71
|
-
def tool?
|
72
|
-
function?
|
73
|
-
end
|
74
|
-
|
75
|
-
# Check if the message is a tool call
|
76
|
-
#
|
77
|
-
# @return [Boolean] true/false whether this message is a tool call
|
78
|
-
def function?
|
79
|
-
role == "function"
|
80
|
-
end
|
81
|
-
|
82
|
-
# Check if the message came from an LLM
|
83
|
-
#
|
84
|
-
# @return [Boolean] true/false whether this message was produced by an LLM
|
85
|
-
def model?
|
86
|
-
role == "model"
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
@@ -1,96 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Langchain
|
4
|
-
module Messages
|
5
|
-
class MistralAIMessage < Base
|
6
|
-
# MistralAI uses the following roles:
|
7
|
-
ROLES = [
|
8
|
-
"system",
|
9
|
-
"assistant",
|
10
|
-
"user",
|
11
|
-
"tool"
|
12
|
-
].freeze
|
13
|
-
|
14
|
-
TOOL_ROLE = "tool"
|
15
|
-
|
16
|
-
# Initialize a new MistralAI message
|
17
|
-
#
|
18
|
-
# @param role [String] The role of the message
|
19
|
-
# @param content [String] The content of the message
|
20
|
-
# @param image_url [String] The URL of the image
|
21
|
-
# @param tool_calls [Array<Hash>] The tool calls made in the message
|
22
|
-
# @param tool_call_id [String] The ID of the tool call
|
23
|
-
def initialize(role:, content: nil, image_url: nil, tool_calls: [], tool_call_id: nil) # TODO: Implement image_file: reference (https://platform.openai.com/docs/api-reference/messages/object#messages/object-content)
|
24
|
-
raise ArgumentError, "Role must be one of #{ROLES.join(", ")}" unless ROLES.include?(role)
|
25
|
-
raise ArgumentError, "Tool calls must be an array of hashes" unless tool_calls.is_a?(Array) && tool_calls.all? { |tool_call| tool_call.is_a?(Hash) }
|
26
|
-
|
27
|
-
@role = role
|
28
|
-
# Some Tools return content as a JSON hence `.to_s`
|
29
|
-
@content = content.to_s
|
30
|
-
# Make sure you're using the Pixtral model if you want to send image_url
|
31
|
-
@image_url = image_url
|
32
|
-
@tool_calls = tool_calls
|
33
|
-
@tool_call_id = tool_call_id
|
34
|
-
end
|
35
|
-
|
36
|
-
# Check if the message came from an LLM
|
37
|
-
#
|
38
|
-
# @return [Boolean] true/false whether this message was produced by an LLM
|
39
|
-
def llm?
|
40
|
-
assistant?
|
41
|
-
end
|
42
|
-
|
43
|
-
# Convert the message to an MistralAI API-compatible hash
|
44
|
-
#
|
45
|
-
# @return [Hash] The message as an MistralAI API-compatible hash
|
46
|
-
def to_hash
|
47
|
-
{}.tap do |h|
|
48
|
-
h[:role] = role
|
49
|
-
|
50
|
-
if tool_calls.any?
|
51
|
-
h[:tool_calls] = tool_calls
|
52
|
-
else
|
53
|
-
h[:tool_call_id] = tool_call_id if tool_call_id
|
54
|
-
|
55
|
-
h[:content] = []
|
56
|
-
|
57
|
-
if content && !content.empty?
|
58
|
-
h[:content] << {
|
59
|
-
type: "text",
|
60
|
-
text: content
|
61
|
-
}
|
62
|
-
end
|
63
|
-
|
64
|
-
if image_url
|
65
|
-
h[:content] << {
|
66
|
-
type: "image_url",
|
67
|
-
image_url: image_url
|
68
|
-
}
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
# Check if the message came from an LLM
|
75
|
-
#
|
76
|
-
# @return [Boolean] true/false whether this message was produced by an LLM
|
77
|
-
def assistant?
|
78
|
-
role == "assistant"
|
79
|
-
end
|
80
|
-
|
81
|
-
# Check if the message are system instructions
|
82
|
-
#
|
83
|
-
# @return [Boolean] true/false whether this message are system instructions
|
84
|
-
def system?
|
85
|
-
role == "system"
|
86
|
-
end
|
87
|
-
|
88
|
-
# Check if the message is a tool call
|
89
|
-
#
|
90
|
-
# @return [Boolean] true/false whether this message is a tool call
|
91
|
-
def tool?
|
92
|
-
role == "tool"
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|