langchainrb 0.9.4 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 62c459d5dc2f716eaeb81697bdf45ad42ae168784d28ff8a80a89d1b3e14eadd
4
- data.tar.gz: 8bb1f94373c54619235cb24ea705179626e398d517739b93014a514283068468
3
+ metadata.gz: 81783847d8152dbcff9e1ea0b51afee5619fb863b1cf3bf2f66912a52e96e797
4
+ data.tar.gz: 877bf77b04771a9a898d478967a0df5ef8ab2d62371f7e71c67e76daf39cffb9
5
5
  SHA512:
6
- metadata.gz: 4b6bd3fb3a983458dd0ff83573e268c4ab8ae26fcffbab93826d3f3143a648b3fa2fcb9e93ba1139551cf8b6d8641da74ea78d098e42ecd672245ca41610c137
7
- data.tar.gz: a40d5bfb0301e7e9e4d66a708fc6bc048272da772bad21473f88be219caf139c86f8cbcf9ea73a3454642042872e796595518a75eb5e9ad3ba5288adf823bfc7
6
+ metadata.gz: 8a3c6e98399f8d76d10c0ccdd6af2650c77962662490a9541daf1bcb76f693c19637b8bdd140800dd920f116753178bdda7e7a2dd0649c9fdafaad837df3a3db
7
+ data.tar.gz: 8f0a18c9c3c25c2bea9041e5884aa2a29e79549fbbd73255f27bc2a6053e4524b4f3d0a4896d002291cf6f2b74c277462aa85d3933a2a3c4ab7499901d9aa89b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  ## [Unreleased]
2
- - `Langchain::LLM::Ollama` can now `#summarize`
2
+
3
+ ## [0.10.0]
4
+ - Delete `Langchain::Conversation` class
5
+
6
+ ## [0.9.5]
7
+ - Now using OpenAI's "text-embedding-3-small" model to generate embeddings
8
+ - Added `remove_texts(ids:)` method to Qdrant and Chroma
9
+ - Add Ruby 3.3 support
3
10
 
4
11
  ## [0.9.4]
5
12
  - New `Ollama#summarize()` method
@@ -17,7 +17,7 @@ module Langchain::LLM
17
17
  n: 1,
18
18
  temperature: 0.0,
19
19
  chat_completion_model_name: "gpt-3.5-turbo",
20
- embeddings_model_name: "text-embedding-ada-002"
20
+ embeddings_model_name: "text-embedding-3-small"
21
21
  }.freeze
22
22
 
23
23
  EMBEDDING_SIZES = {
@@ -53,7 +53,8 @@ module Langchain::LLM
53
53
  text:,
54
54
  model: defaults[:embeddings_model_name],
55
55
  encoding_format: nil,
56
- user: nil
56
+ user: nil,
57
+ dimensions: EMBEDDING_SIZES.fetch(model.to_sym, nil)
57
58
  )
58
59
  raise ArgumentError.new("text argument is required") if text.empty?
59
60
  raise ArgumentError.new("model argument is required") if model.empty?
@@ -61,12 +62,15 @@ module Langchain::LLM
61
62
 
62
63
  parameters = {
63
64
  input: text,
64
- model: model,
65
- dimensions: default_dimension
65
+ model: model
66
66
  }
67
67
  parameters[:encoding_format] = encoding_format if encoding_format
68
68
  parameters[:user] = user if user
69
69
 
70
+ if ["text-embedding-3-small", "text-embedding-3-large"].include?(model)
71
+ parameters[:dimensions] = EMBEDDING_SIZES[model.to_sym] if EMBEDDING_SIZES.key?(model.to_sym)
72
+ end
73
+
70
74
  validate_max_tokens(text, parameters[:model])
71
75
 
72
76
  response = with_api_error_handling do
@@ -1,4 +1,3 @@
1
- require "mail"
2
1
  require "uri"
3
2
 
4
3
  module Langchain
@@ -1,41 +1,45 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Langchain::Tool
4
- class RubyCodeInterpreter < Base
5
- #
6
- # A tool that execute Ruby code in a sandboxed environment.
7
- #
8
- # Gem requirements:
9
- # gem "safe_ruby", "~> 1.0.4"
10
- #
11
- # Usage:
12
- # interpreter = Langchain::Tool::RubyCodeInterpreter.new
13
- #
14
- NAME = "ruby_code_interpreter"
15
- ANNOTATIONS_PATH = Langchain.root.join("./langchain/tool/#{NAME}/#{NAME}.json").to_path
3
+ # RubyCodeInterpreter does not work with Ruby 3.3;
4
+ # https://github.com/ukutaht/safe_ruby/issues/4
5
+ if RUBY_VERSION <= "3.2"
6
+ module Langchain::Tool
7
+ class RubyCodeInterpreter < Base
8
+ #
9
+ # A tool that execute Ruby code in a sandboxed environment.
10
+ #
11
+ # Gem requirements:
12
+ # gem "safe_ruby", "~> 1.0.4"
13
+ #
14
+ # Usage:
15
+ # interpreter = Langchain::Tool::RubyCodeInterpreter.new
16
+ #
17
+ NAME = "ruby_code_interpreter"
18
+ ANNOTATIONS_PATH = Langchain.root.join("./langchain/tool/#{NAME}/#{NAME}.json").to_path
16
19
 
17
- description <<~DESC
18
- A Ruby code interpreter. Use this to execute ruby expressions. Input should be a valid ruby expression. If you want to see the output of the tool, make sure to return a value.
19
- DESC
20
+ description <<~DESC
21
+ A Ruby code interpreter. Use this to execute ruby expressions. Input should be a valid ruby expression. If you want to see the output of the tool, make sure to return a value.
22
+ DESC
20
23
 
21
- def initialize(timeout: 30)
22
- depends_on "safe_ruby"
24
+ def initialize(timeout: 30)
25
+ depends_on "safe_ruby"
23
26
 
24
- @timeout = timeout
25
- end
27
+ @timeout = timeout
28
+ end
26
29
 
27
- # Executes Ruby code in a sandboxes environment.
28
- #
29
- # @param input [String] ruby code expression
30
- # @return [String] Answer
31
- def execute(input:)
32
- Langchain.logger.info("Executing \"#{input}\"", for: self.class)
30
+ # Executes Ruby code in a sandboxes environment.
31
+ #
32
+ # @param input [String] ruby code expression
33
+ # @return [String] Answer
34
+ def execute(input:)
35
+ Langchain.logger.info("Executing \"#{input}\"", for: self.class)
33
36
 
34
- safe_eval(input)
35
- end
37
+ safe_eval(input)
38
+ end
36
39
 
37
- def safe_eval(code)
38
- SafeRuby.eval(code, timeout: @timeout)
40
+ def safe_eval(code)
41
+ SafeRuby.eval(code, timeout: @timeout)
42
+ end
39
43
  end
40
44
  end
41
45
  end
@@ -124,6 +124,11 @@ module Langchain::Vectorsearch
124
124
  raise NotImplementedError, "#{self.class.name} does not support updating texts"
125
125
  end
126
126
 
127
+ # Method supported by Vectorsearch DB to delete a list of texts from the index
128
+ def remove_texts(...)
129
+ raise NotImplementedError, "#{self.class.name} does not support deleting texts"
130
+ end
131
+
127
132
  # Method supported by Vectorsearch DB to search for similar texts in the index
128
133
  def similarity_search(...)
129
134
  raise NotImplementedError, "#{self.class.name} does not support similarity search"
@@ -60,6 +60,13 @@ module Langchain::Vectorsearch
60
60
  collection.update(embeddings)
61
61
  end
62
62
 
63
+ # Remove a list of texts from the index
64
+ # @param ids [Array<String>] The list of ids to remove
65
+ # @return [Hash] The response from the server
66
+ def remove_texts(ids:)
67
+ collection.delete(ids)
68
+ end
69
+
63
70
  # Create the collection with the default schema
64
71
  # @return [::Chroma::Resources::Collection] Created collection
65
72
  def create_default_schema
@@ -75,6 +75,17 @@ module Langchain::Vectorsearch
75
75
  es_client.bulk(body: body)
76
76
  end
77
77
 
78
+ # Remove a list of texts from the index
79
+ # @param ids [Array<Integer>] The list of ids to delete
80
+ # @return [Elasticsearch::Response] from the Elasticsearch server
81
+ def remove_texts(ids: [])
82
+ body = ids.map do |id|
83
+ {delete: {_index: index_name, _id: id}}
84
+ end
85
+
86
+ es_client.bulk(body: body)
87
+ end
88
+
78
89
  # Create the index with the default schema
79
90
  # @return [Elasticsearch::Response] Index creation
80
91
  def create_default_schema
@@ -64,6 +64,16 @@ module Langchain::Vectorsearch
64
64
  add_texts(texts: texts, ids: ids)
65
65
  end
66
66
 
67
+ # Remove a list of texts from the index
68
+ # @param ids [Array<Integer>] The ids to remove
69
+ # @return [Hash] The response from the server
70
+ def remove_texts(ids:)
71
+ client.points.delete(
72
+ collection_name: index_name,
73
+ points: ids
74
+ )
75
+ end
76
+
67
77
  # Get the default schema
68
78
  # @return [Hash] The response from the server
69
79
  def get_default_schema
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Langchain
4
- VERSION = "0.9.4"
4
+ VERSION = "0.10.0"
5
5
  end
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.9.4
4
+ version: 0.10.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-02-28 00:00:00.000000000 Z
11
+ date: 2024-03-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -698,12 +698,6 @@ files:
698
698
  - lib/langchain/chunker/sentence.rb
699
699
  - lib/langchain/chunker/text.rb
700
700
  - lib/langchain/contextual_logger.rb
701
- - lib/langchain/conversation.rb
702
- - lib/langchain/conversation/context.rb
703
- - lib/langchain/conversation/memory.rb
704
- - lib/langchain/conversation/message.rb
705
- - lib/langchain/conversation/prompt.rb
706
- - lib/langchain/conversation/response.rb
707
701
  - lib/langchain/data.rb
708
702
  - lib/langchain/dependency_helper.rb
709
703
  - lib/langchain/evals/ragas/answer_relevance.rb
@@ -819,7 +813,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
819
813
  - !ruby/object:Gem::Version
820
814
  version: '0'
821
815
  requirements: []
822
- rubygems_version: 3.4.1
816
+ rubygems_version: 3.5.3
823
817
  signing_key:
824
818
  specification_version: 4
825
819
  summary: Build LLM-backed Ruby applications with Ruby's Langchain.rb
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Langchain
4
- class Conversation
5
- class Context < Message
6
- end
7
- end
8
- end
@@ -1,83 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Langchain
4
- class Conversation
5
- class Memory
6
- attr_reader :messages
7
-
8
- # The least number of tokens we want to be under the limit by
9
- TOKEN_LEEWAY = 20
10
-
11
- def initialize(llm:, messages: [], **options)
12
- warn "[DEPRECATION] `Langchain::Conversation::Memory` is deprecated. Please use `Langchain::Assistant` instead."
13
-
14
- @llm = llm
15
- @context = nil
16
- @summary = nil
17
- @messages = messages
18
- @strategy = options.delete(:strategy) || :truncate
19
- @options = options
20
- end
21
-
22
- def set_context(message)
23
- @context = message
24
- end
25
-
26
- def append_message(message)
27
- @messages.append(message)
28
- end
29
-
30
- def reduce_messages(exception)
31
- case @strategy
32
- when :truncate
33
- truncate_messages(exception)
34
- when :summarize
35
- summarize_messages
36
- else
37
- raise "Unknown strategy: #{@options[:strategy]}"
38
- end
39
- end
40
-
41
- def context
42
- return if @context.nil? && @summary.nil?
43
-
44
- Context.new([@context, @summary].compact.join("\n"))
45
- end
46
-
47
- private
48
-
49
- def truncate_messages(exception)
50
- raise exception if @messages.size == 1
51
-
52
- token_overflow = exception.token_overflow
53
-
54
- @messages = @messages.drop_while do |message|
55
- proceed = token_overflow > -TOKEN_LEEWAY
56
- token_overflow -= token_length(message.to_json, model_name, llm: @llm)
57
-
58
- proceed
59
- end
60
- end
61
-
62
- def summarize_messages
63
- history = [@summary, @messages.to_json].compact.join("\n")
64
- partitions = [history[0, history.size / 2], history[history.size / 2, history.size]]
65
-
66
- @summary = partitions.map { |messages| @llm.summarize(text: messages.to_json) }.join("\n")
67
-
68
- @messages = [@messages.last]
69
- end
70
-
71
- def partition_messages
72
- end
73
-
74
- def model_name
75
- @llm.class::DEFAULTS[:chat_completion_model_name]
76
- end
77
-
78
- def token_length(content, model_name, options)
79
- @llm.class::LENGTH_VALIDATOR.token_length(content, model_name, options)
80
- end
81
- end
82
- end
83
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Langchain
4
- class Conversation
5
- class Message
6
- attr_reader :content
7
-
8
- ROLE_MAPPING = {
9
- context: "system",
10
- prompt: "user",
11
- response: "assistant"
12
- }
13
-
14
- def initialize(content)
15
- warn "[DEPRECATION] `Langchain::Conversation::*` is deprecated. Please use `Langchain::Assistant` and `Langchain::Messages` classes instead."
16
-
17
- @content = content
18
- end
19
-
20
- def role
21
- ROLE_MAPPING[type]
22
- end
23
-
24
- def to_s
25
- content
26
- end
27
-
28
- def to_h
29
- {
30
- role: role,
31
- content: content
32
- }
33
- end
34
-
35
- def ==(other)
36
- to_json == other.to_json
37
- end
38
-
39
- def to_json(options = {})
40
- to_h.to_json
41
- end
42
-
43
- private
44
-
45
- def type
46
- self.class.to_s.split("::").last.downcase.to_sym
47
- end
48
- end
49
- end
50
- end
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Langchain
4
- class Conversation
5
- class Prompt < Message
6
- end
7
- end
8
- end
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Langchain
4
- class Conversation
5
- class Response < Message
6
- end
7
- end
8
- end
@@ -1,82 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Langchain
4
- #
5
- # A high-level API for running a conversation with an LLM.
6
- # Currently supports: OpenAI and Google PaLM LLMs.
7
- #
8
- # Usage:
9
- # llm = Langchain::LLM::OpenAI.new(api_key: "YOUR_API_KEY")
10
- # chat = Langchain::Conversation.new(llm: llm)
11
- # chat.set_context("You are a chatbot from the future")
12
- # chat.message("Tell me about future technologies")
13
- #
14
- # To stream the chat response:
15
- # chat = Langchain::Conversation.new(llm: llm) do |chunk|
16
- # print(chunk)
17
- # end
18
- #
19
- class Conversation
20
- attr_reader :options
21
-
22
- # Intialize Conversation with a LLM
23
- #
24
- # @param llm [Object] The LLM to use for the conversation
25
- # @param options [Hash] Options to pass to the LLM, like temperature, top_k, etc.
26
- # @return [Langchain::Conversation] The Langchain::Conversation instance
27
- def initialize(llm:, **options, &block)
28
- warn "[DEPRECATION] `Langchain::Conversation` is deprecated. Please use `Langchain::Assistant` instead."
29
-
30
- @llm = llm
31
- @context = nil
32
- @memory = ::Langchain::Conversation::Memory.new(
33
- llm: llm,
34
- messages: options.delete(:messages) || [],
35
- strategy: options.delete(:memory_strategy)
36
- )
37
- @options = options
38
- @block = block
39
- end
40
-
41
- # Set the context of the conversation. Usually used to set the model's persona.
42
- # @param message [String] The context of the conversation
43
- def set_context(message)
44
- @memory.set_context ::Langchain::Conversation::Context.new(message)
45
- end
46
-
47
- # Message the model with a prompt and return the response.
48
- # @param message [String] The prompt to message the model with
49
- # @return [Response] The response from the model
50
- def message(message)
51
- @memory.append_message ::Langchain::Conversation::Prompt.new(message)
52
- ai_message = ::Langchain::Conversation::Response.new(llm_response.chat_completion)
53
- @memory.append_message(ai_message)
54
- ai_message
55
- end
56
-
57
- # Messages from conversation memory
58
- # @return [Array<Prompt|Response>] The messages from the conversation memory
59
- def messages
60
- @memory.messages
61
- end
62
-
63
- # Context from conversation memory
64
- # @return [Context] Context from conversation memory
65
- def context
66
- @memory.context
67
- end
68
-
69
- private
70
-
71
- def llm_response
72
- message_history = messages.map(&:to_h)
73
- # Prepend the system message as context as the first message
74
- message_history.prepend({role: "system", content: @memory.context.to_s}) if @memory.context
75
-
76
- @llm.chat(messages: message_history, **@options, &@block)
77
- rescue Langchain::Utils::TokenLength::TokenLimitExceeded => exception
78
- @memory.reduce_messages(exception)
79
- retry
80
- end
81
- end
82
- end